@l33t/agentlayer-sdk

The same contract packaged twice: a typed agent-side client and a studio-side Express middleware for AgentLayer — async tasks, SSE observation, MCP discovery, idempotency, HMAC, human checkpoints and attributed artifacts.

v0.1.0zero runtime depsNode 18+ESM + CJS + .d.tsMIT

Install

npm i @l33t/agentlayer-sdk

Live staging: https://agentportal.l33tpro.com (REST /api/* + MCP /mcp). Full reference in the package README.

Agent side — play a game through AgentLayer

import { AgentLayerClient } from "@l33t/agentlayer-sdk/agent";

const agent = new AgentLayerClient({
  baseUrl: "https://agentportal.l33tpro.com",
  auth: { apiKey: "sk_live_…" },
});

await agent.connect();                                    // handshake
const tools = await agent.discoverTools("demonic-gauntlet"); // MCP tools/list

const task = await agent.submitTask("demonic-gauntlet", {
  skill: "farm_zone",
  params: { zone: "circle_1", stop_when_gold_below: 5000 },
  agentId: "claude-desktop-1",
  // payment: { max_amount: 1.5, currency: "USD" },       // optional mandate
});

const sub = agent.observeTask(task, (evt) => {            // SSE, read-only
  console.log(evt.eventType, evt.data);                   // auto-resume w/ Last-Event-ID
});
await sub.terminal();
sub.close();

await agent.submitInput(task.gameId, task.taskId, { input: { choice: "potion" } }); // checkpoint
const artifact = await agent.getArtifact(task.gameId, task.taskId);                 // attributed result

Studio side — expose server-authoritative actions

import express from "express";
import { z } from "zod";
import { createAgentLayerMiddleware } from "@l33t/agentlayer-sdk/studio";

const al = createAgentLayerMiddleware({
  game: "demonic-gauntlet",
  secretKey: process.env.AL_SECRET_KEY,        // sk_live_… server only
  handlers: {
    farm_zone: {
      params: z.object({ zone: z.string(), stop_when_gold_below: z.number().optional() }),
      scope: "game:action",
      rate: "60/hour",
      implement: async (params, ctx) => {
        const r = await game.simulateFarm(params, ctx.checkpointState);
        if (r.hp < 20) return { status: "input-required", reason: "hp_below_threshold",
                                options: ["potion","flee","abort"], checkpointState: r };
        return { status: "completed", artifact: { xp: r.xp, gold: r.gold } };
      },
    },
  },
  onCheckpoint: async (evt) => ({ default: "abort", timeout: "30m" }),
});

app.use("/agentlayer", al.router());

The router serves POST /actions/:action (HMAC: signature + timestamp + nonce anti-replay), /.well-known/agent.json (A2A Agent Card) and /.well-known/agentplay.json (MCP-flavored gaming discovery) — all generated from your handler registry. zod validation, timeout isolation, checkpoint policy and artifact envelopes included.

Wire protocol (v1)

EndpointPurpose
POST /api/games/:gameId/taskssubmit task → 201 {task} · idempotent replay → 200 {task, idempotent_replay}
GET /api/games/:gameId/tasks/:taskIdstate + events + artifact
GET /api/games/:gameId/tasks/:taskId/eventsSSE with Last-Event-ID replay · terminal done
POST /api/games/:gameId/tasks/:taskId/inputanswer an input-required checkpoint
GET /api/games/:gameId/artifactsattributed artifacts
POST /mcpJSON-RPC 2.0: initialize · tools/list · tools/call (sk_live_ gated)

Lifecycle: queued → working → (input-required ⇄ queued) → completed | failed. :gameId is the game UUID; slugs are for discovery.

Status

✔ 53/53 tests · ✔ E2E against live staging (register → game → key → MCP discovery → task → SSE → artifact) — see examples/e2e-against-staging.md in the repo.