@orangecheck/agent-vercel 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -91,4 +91,4 @@ MIT.
91
91
  - [oc-agent-protocol](https://github.com/orangecheck/oc-agent-protocol) — normative wire format.
92
92
  - [@orangecheck/agent-core](https://www.npmjs.com/package/@orangecheck/agent-core) — verifier library.
93
93
  - [@orangecheck/agent-mcp](https://www.npmjs.com/package/@orangecheck/agent-mcp) / [-anthropic](https://www.npmjs.com/package/@orangecheck/agent-anthropic) / [-openai](https://www.npmjs.com/package/@orangecheck/agent-openai) — sibling adapters.
94
- - [console.ochk.io/integrations/vercel-ai](https://console.ochk.io/integrations/vercel-ai) — managed-tier story.
94
+ - [fleet.ochk.io/integrations/vercel-ai](https://fleet.ochk.io/integrations/vercel-ai) — managed-tier story.
package/dist/index.d.mts CHANGED
@@ -31,7 +31,7 @@ interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
31
31
  description?: string;
32
32
  execute: (args: TArgs, ctx: AgentContext & {
33
33
  callId: string;
34
- console?: ConsoleClient;
34
+ fleet?: FleetClient;
35
35
  }) => Promise<{
36
36
  result: TResult;
37
37
  action: ActionEnvelope;
@@ -39,7 +39,7 @@ interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
39
39
  }>;
40
40
  }
41
41
  declare function ocTool<TArgs extends Record<string, unknown>, TResult>(input: OcToolInput<TArgs, TResult>): OcToolWrapped<TArgs, TResult>;
42
- interface ConsoleClient {
42
+ interface FleetClient {
43
43
  baseUrl?: string;
44
44
  apiToken: string;
45
45
  projectId: string;
@@ -50,6 +50,6 @@ interface PostActionResult {
50
50
  project_id: string;
51
51
  delegation_id: string;
52
52
  }
53
- declare function postActionToConsole(action: ActionEnvelope, client: ConsoleClient): Promise<PostActionResult>;
53
+ declare function postActionToFleet(action: ActionEnvelope, client: FleetClient): Promise<PostActionResult>;
54
54
 
55
- export { type AgentContext, type ConsoleClient, type OcToolInput, type OcToolWrapped, type PostActionResult, type StampToolCallInput, type VercelToolCall, canonicalizeToolCall, ocTool, postActionToConsole, stampToolCall, toolCallActionId, toolCallHash };
55
+ export { type AgentContext, type FleetClient, type OcToolInput, type OcToolWrapped, type PostActionResult, type StampToolCallInput, type VercelToolCall, canonicalizeToolCall, ocTool, postActionToFleet, stampToolCall, toolCallActionId, toolCallHash };
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
31
31
  description?: string;
32
32
  execute: (args: TArgs, ctx: AgentContext & {
33
33
  callId: string;
34
- console?: ConsoleClient;
34
+ fleet?: FleetClient;
35
35
  }) => Promise<{
36
36
  result: TResult;
37
37
  action: ActionEnvelope;
@@ -39,7 +39,7 @@ interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
39
39
  }>;
40
40
  }
41
41
  declare function ocTool<TArgs extends Record<string, unknown>, TResult>(input: OcToolInput<TArgs, TResult>): OcToolWrapped<TArgs, TResult>;
42
- interface ConsoleClient {
42
+ interface FleetClient {
43
43
  baseUrl?: string;
44
44
  apiToken: string;
45
45
  projectId: string;
@@ -50,6 +50,6 @@ interface PostActionResult {
50
50
  project_id: string;
51
51
  delegation_id: string;
52
52
  }
53
- declare function postActionToConsole(action: ActionEnvelope, client: ConsoleClient): Promise<PostActionResult>;
53
+ declare function postActionToFleet(action: ActionEnvelope, client: FleetClient): Promise<PostActionResult>;
54
54
 
55
- export { type AgentContext, type ConsoleClient, type OcToolInput, type OcToolWrapped, type PostActionResult, type StampToolCallInput, type VercelToolCall, canonicalizeToolCall, ocTool, postActionToConsole, stampToolCall, toolCallActionId, toolCallHash };
55
+ export { type AgentContext, type FleetClient, type OcToolInput, type OcToolWrapped, type PostActionResult, type StampToolCallInput, type VercelToolCall, canonicalizeToolCall, ocTool, postActionToFleet, stampToolCall, toolCallActionId, toolCallHash };
package/dist/index.js CHANGED
@@ -65,19 +65,19 @@ function ocTool(input) {
65
65
  });
66
66
  const result = await input.execute(args);
67
67
  let posted = null;
68
- if (ctx.console) {
68
+ if (ctx.fleet) {
69
69
  try {
70
- posted = await postActionToConsole(action, ctx.console);
70
+ posted = await postActionToFleet(action, ctx.fleet);
71
71
  } catch (err) {
72
- console.error("[oc-agent-vercel] postActionToConsole failed:", err);
72
+ console.error("[oc-agent-vercel] postActionToFleet failed:", err);
73
73
  }
74
74
  }
75
75
  return { result, action, posted };
76
76
  }
77
77
  };
78
78
  }
79
- async function postActionToConsole(action, client) {
80
- const baseUrl = client.baseUrl ?? "https://console.ochk.io";
79
+ async function postActionToFleet(action, client) {
80
+ const baseUrl = client.baseUrl ?? "https://fleet.ochk.io";
81
81
  const f = client.fetch ?? fetch;
82
82
  const body = {
83
83
  project_id: client.projectId,
@@ -106,7 +106,7 @@ async function postActionToConsole(action, client) {
106
106
  if (j2.reason) reason = j2.reason;
107
107
  } catch {
108
108
  }
109
- throw new Error(`postActionToConsole failed: ${reason}`);
109
+ throw new Error(`postActionToFleet failed: ${reason}`);
110
110
  }
111
111
  const j = await r.json();
112
112
  return j.action;
@@ -114,7 +114,7 @@ async function postActionToConsole(action, client) {
114
114
 
115
115
  exports.canonicalizeToolCall = canonicalizeToolCall;
116
116
  exports.ocTool = ocTool;
117
- exports.postActionToConsole = postActionToConsole;
117
+ exports.postActionToFleet = postActionToFleet;
118
118
  exports.stampToolCall = stampToolCall;
119
119
  exports.toolCallActionId = toolCallActionId;
120
120
  exports.toolCallHash = toolCallHash;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["canonicalize","hexEncode","sha256","computeActionId","parseScope","isSubScope","signAsAgent","j"],"mappings":"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","file":"index.js","sourcesContent":["// @orangecheck/agent-vercel — wrap Vercel AI SDK `tool()` invocations in\n// OC Agent action envelopes.\n//\n// Provider-agnostic: the AI SDK is the abstraction layer. Whatever model\n// you use underneath (Anthropic, OpenAI, Cohere, …) the tool primitive is\n// the same {description, parameters, execute} shape. This adapter wraps\n// `execute` so every successful call produces a signed agent-action\n// envelope citing the active delegation.\n//\n// Two integration shapes:\n//\n// 1. ocTool({verb, parameters, execute})\n// A drop-in replacement for `tool()`. The wrapped execute runs the\n// scope check, signs the canonical (verb, args, callId) tuple,\n// then runs your real handler.\n//\n// 2. stampToolCall(input)\n// Lower-level stamping helper for cases where you have your own\n// tool-execution loop and want to emit envelopes manually.\n//\n// The agent + delegation are passed via a per-request context object\n// (or threaded through closures) — we don't depend on AsyncLocalStorage\n// to keep edge-runtime compatibility maximal.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalize,\n computeActionId,\n hexEncode,\n isSubScope,\n parseScope,\n type DelegationEnvelope,\n} from '@orangecheck/agent-core';\nimport {\n signAsAgent,\n type ActionEnvelope,\n type SignerRef,\n} from '@orangecheck/agent-signer';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Canonicalization of a tool call\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface VercelToolCall {\n /** Unique id assigned by the AI SDK for this tool invocation. */\n callId: string;\n /** Tool verb / name — passed in via ocTool() or set per-call by your wrapper. */\n verb: string;\n /** JSON-serializable arguments produced by the model. */\n args: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for a Vercel AI SDK tool call.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"args\": <canonical JSON of args>,\n * \"call_id\": <callId>,\n * \"verb\": <verb>\n * }\n */\nexport function canonicalizeToolCall(c: VercelToolCall): Uint8Array {\n const canon = {\n args: c.args,\n call_id: c.callId,\n verb: c.verb,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolCallHash(c: VercelToolCall): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolCall(c)));\n}\n\nexport function toolCallActionId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n c: VercelToolCall\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolCallHash(c),\n content_length: canonicalizeToolCall(c).byteLength,\n content_mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamping primitive\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AgentContext {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n}\n\nexport interface StampToolCallInput extends AgentContext {\n call: VercelToolCall;\n /** Defaults to `vercel:tool(verb=<verb>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\nexport async function stampToolCall(input: StampToolCallInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `vercel:tool(verb=${input.call.verb})`;\n\n const granted = (input.delegation.scopes ?? []).map(parseScope);\n const exercisedParsed = parseScope(scopeExercised);\n if (!granted.some((g) => isSubScope(exercisedParsed, g))) {\n throw new Error(\n `stampToolCall: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolCall(input.call);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolCallHash(input.call), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ocTool — drop-in tool() replacement\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface OcToolInput<TArgs extends Record<string, unknown>, TResult> {\n /** OC Agent verb under which this tool is exercised. */\n verb: string;\n /** Pass-through to AI SDK's `tool()` — the JSON Schema for inputs. */\n parameters?: unknown;\n /** Pass-through description shown to the model. */\n description?: string;\n /** Your real handler. Returns whatever the tool returns. */\n execute: (args: TArgs) => Promise<TResult>;\n}\n\nexport interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {\n verb: string;\n parameters?: unknown;\n description?: string;\n /**\n * The execute fn the AI SDK calls. Receives args + a callId (the AI\n * SDK passes its own callId through — adapter glue passes it via\n * context). Optional `console` field on the context tells the\n * wrapper to fire-and-forget POST the stamped action to console.\n * ochk.io/api/actions after the underlying execute() returns.\n */\n execute: (\n args: TArgs,\n ctx: AgentContext & { callId: string; console?: ConsoleClient }\n ) => Promise<{\n result: TResult;\n action: ActionEnvelope;\n posted: PostActionResult | null;\n }>;\n}\n\n/**\n * Wrap a tool() definition so its execute path is scope-checked and\n * envelope-emitting. The exact glue depends on which AI-SDK release you're\n * on — the typical pattern is:\n *\n * const tools = {\n * 'invoice.create': tool({\n * description: '…',\n * parameters: schema,\n * execute: async (args, { toolCallId }) => {\n * const { result, action } = await invoiceCreate.execute(args, {\n * agent, delegation, callId: toolCallId,\n * });\n * await yourAuditPipeline.append(action);\n * return result;\n * },\n * }),\n * };\n *\n * const invoiceCreate = ocTool({\n * verb: 'invoice.create',\n * parameters: schema,\n * execute: async (args) => myInvoiceCreateImpl(args),\n * });\n *\n * The `ocTool` value is provider/SDK-agnostic — bring your own glue around\n * it. v1 of the adapter intentionally does not import `ai` so it works on\n * any release.\n */\nexport function ocTool<TArgs extends Record<string, unknown>, TResult>(\n input: OcToolInput<TArgs, TResult>\n): OcToolWrapped<TArgs, TResult> {\n return {\n verb: input.verb,\n parameters: input.parameters,\n description: input.description,\n execute: async (args, ctx) => {\n const call: VercelToolCall = {\n callId: ctx.callId,\n verb: input.verb,\n args,\n };\n const action = await stampToolCall({\n agent: ctx.agent,\n delegation: ctx.delegation,\n call,\n });\n const result = await input.execute(args);\n let posted: PostActionResult | null = null;\n if (ctx.console) {\n try {\n posted = await postActionToConsole(action, ctx.console);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[oc-agent-vercel] postActionToConsole failed:', err);\n }\n }\n return { result, action, posted };\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Console integration: POST stamped actions to console.ochk.io/api/actions\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ConsoleClient {\n /** Defaults to https://console.ochk.io. */\n baseUrl?: string;\n /** Bearer token from /settings § 03 (`ock_<hex>`). */\n apiToken: string;\n /** Project the action belongs to (proj_*). */\n projectId: string;\n /** Optional fetch override for runtimes that need it. */\n fetch?: typeof fetch;\n}\n\nexport interface PostActionResult {\n id: string;\n project_id: string;\n delegation_id: string;\n}\n\n/**\n * POST a stamped action envelope to console.ochk.io/api/actions. The\n * console re-derives the action id, validates agent-must-match-\n * delegation, persists, fans out to Nostr (kind 30084), submits to\n * OC Stamp, and triggers any subscribed webhooks. Throws on non-2xx\n * with the server's reason string.\n */\nexport async function postActionToConsole(\n action: ActionEnvelope,\n client: ConsoleClient\n): Promise<PostActionResult> {\n const baseUrl = client.baseUrl ?? 'https://console.ochk.io';\n const f = client.fetch ?? fetch;\n const body = {\n project_id: client.projectId,\n delegation_id: action.delegation_id,\n agent_address: action.signer.address,\n scope_exercised: action.scope_exercised,\n content_hash: action.content.hash,\n content_length: action.content.length,\n content_mime: action.content.mime,\n signed_at: action.signed_at,\n signature: action.sig.value,\n id: action.id,\n };\n const r = await f(`${baseUrl}/api/actions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${client.apiToken}`,\n },\n body: JSON.stringify(body),\n });\n if (!r.ok) {\n let reason = `http_${r.status}`;\n try {\n const j = (await r.json()) as { reason?: string };\n if (j.reason) reason = j.reason;\n } catch {\n // body wasn't json\n }\n throw new Error(`postActionToConsole failed: ${reason}`);\n }\n const j = (await r.json()) as { ok: true; action: PostActionResult };\n return j.action;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["canonicalize","hexEncode","sha256","computeActionId","parseScope","isSubScope","signAsAgent","j"],"mappings":"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","file":"index.js","sourcesContent":["// @orangecheck/agent-vercel — wrap Vercel AI SDK `tool()` invocations in\n// OC Agent action envelopes.\n//\n// Provider-agnostic: the AI SDK is the abstraction layer. Whatever model\n// you use underneath (Anthropic, OpenAI, Cohere, …) the tool primitive is\n// the same {description, parameters, execute} shape. This adapter wraps\n// `execute` so every successful call produces a signed agent-action\n// envelope citing the active delegation.\n//\n// Two integration shapes:\n//\n// 1. ocTool({verb, parameters, execute})\n// A drop-in replacement for `tool()`. The wrapped execute runs the\n// scope check, signs the canonical (verb, args, callId) tuple,\n// then runs your real handler.\n//\n// 2. stampToolCall(input)\n// Lower-level stamping helper for cases where you have your own\n// tool-execution loop and want to emit envelopes manually.\n//\n// The agent + delegation are passed via a per-request context object\n// (or threaded through closures) — we don't depend on AsyncLocalStorage\n// to keep edge-runtime compatibility maximal.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalize,\n computeActionId,\n hexEncode,\n isSubScope,\n parseScope,\n type DelegationEnvelope,\n} from '@orangecheck/agent-core';\nimport {\n signAsAgent,\n type ActionEnvelope,\n type SignerRef,\n} from '@orangecheck/agent-signer';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Canonicalization of a tool call\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface VercelToolCall {\n /** Unique id assigned by the AI SDK for this tool invocation. */\n callId: string;\n /** Tool verb / name — passed in via ocTool() or set per-call by your wrapper. */\n verb: string;\n /** JSON-serializable arguments produced by the model. */\n args: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for a Vercel AI SDK tool call.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"args\": <canonical JSON of args>,\n * \"call_id\": <callId>,\n * \"verb\": <verb>\n * }\n */\nexport function canonicalizeToolCall(c: VercelToolCall): Uint8Array {\n const canon = {\n args: c.args,\n call_id: c.callId,\n verb: c.verb,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolCallHash(c: VercelToolCall): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolCall(c)));\n}\n\nexport function toolCallActionId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n c: VercelToolCall\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolCallHash(c),\n content_length: canonicalizeToolCall(c).byteLength,\n content_mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamping primitive\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AgentContext {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n}\n\nexport interface StampToolCallInput extends AgentContext {\n call: VercelToolCall;\n /** Defaults to `vercel:tool(verb=<verb>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\nexport async function stampToolCall(input: StampToolCallInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `vercel:tool(verb=${input.call.verb})`;\n\n const granted = (input.delegation.scopes ?? []).map(parseScope);\n const exercisedParsed = parseScope(scopeExercised);\n if (!granted.some((g) => isSubScope(exercisedParsed, g))) {\n throw new Error(\n `stampToolCall: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolCall(input.call);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolCallHash(input.call), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ocTool — drop-in tool() replacement\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface OcToolInput<TArgs extends Record<string, unknown>, TResult> {\n /** OC Agent verb under which this tool is exercised. */\n verb: string;\n /** Pass-through to AI SDK's `tool()` — the JSON Schema for inputs. */\n parameters?: unknown;\n /** Pass-through description shown to the model. */\n description?: string;\n /** Your real handler. Returns whatever the tool returns. */\n execute: (args: TArgs) => Promise<TResult>;\n}\n\nexport interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {\n verb: string;\n parameters?: unknown;\n description?: string;\n /**\n * The execute fn the AI SDK calls. Receives args + a callId (the AI\n * SDK passes its own callId through — adapter glue passes it via\n * context). Optional `fleet` field on the context tells the\n * wrapper to fire-and-forget POST the stamped action to fleet.\n * ochk.io/api/actions after the underlying execute() returns.\n */\n execute: (\n args: TArgs,\n ctx: AgentContext & { callId: string; fleet?: FleetClient }\n ) => Promise<{\n result: TResult;\n action: ActionEnvelope;\n posted: PostActionResult | null;\n }>;\n}\n\n/**\n * Wrap a tool() definition so its execute path is scope-checked and\n * envelope-emitting. The exact glue depends on which AI-SDK release you're\n * on — the typical pattern is:\n *\n * const tools = {\n * 'invoice.create': tool({\n * description: '…',\n * parameters: schema,\n * execute: async (args, { toolCallId }) => {\n * const { result, action } = await invoiceCreate.execute(args, {\n * agent, delegation, callId: toolCallId,\n * });\n * await yourAuditPipeline.append(action);\n * return result;\n * },\n * }),\n * };\n *\n * const invoiceCreate = ocTool({\n * verb: 'invoice.create',\n * parameters: schema,\n * execute: async (args) => myInvoiceCreateImpl(args),\n * });\n *\n * The `ocTool` value is provider/SDK-agnostic — bring your own glue around\n * it. v1 of the adapter intentionally does not import `ai` so it works on\n * any release.\n */\nexport function ocTool<TArgs extends Record<string, unknown>, TResult>(\n input: OcToolInput<TArgs, TResult>\n): OcToolWrapped<TArgs, TResult> {\n return {\n verb: input.verb,\n parameters: input.parameters,\n description: input.description,\n execute: async (args, ctx) => {\n const call: VercelToolCall = {\n callId: ctx.callId,\n verb: input.verb,\n args,\n };\n const action = await stampToolCall({\n agent: ctx.agent,\n delegation: ctx.delegation,\n call,\n });\n const result = await input.execute(args);\n let posted: PostActionResult | null = null;\n if (ctx.fleet) {\n try {\n posted = await postActionToFleet(action, ctx.fleet);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[oc-agent-vercel] postActionToFleet failed:', err);\n }\n }\n return { result, action, posted };\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Fleet integration: POST stamped actions to fleet.ochk.io/api/actions\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface FleetClient {\n /** Defaults to https://fleet.ochk.io. */\n baseUrl?: string;\n /** Bearer token from /settings § 03 (`ock_<hex>`). */\n apiToken: string;\n /** Project the action belongs to (proj_*). */\n projectId: string;\n /** Optional fetch override for runtimes that need it. */\n fetch?: typeof fetch;\n}\n\nexport interface PostActionResult {\n id: string;\n project_id: string;\n delegation_id: string;\n}\n\n/**\n * POST a stamped action envelope to fleet.ochk.io/api/actions. The\n * fleet re-derives the action id, validates agent-must-match-\n * delegation, persists, fans out to Nostr (kind 30084), submits to\n * OC Stamp, and triggers any subscribed webhooks. Throws on non-2xx\n * with the server's reason string.\n */\nexport async function postActionToFleet(\n action: ActionEnvelope,\n client: FleetClient\n): Promise<PostActionResult> {\n const baseUrl = client.baseUrl ?? 'https://fleet.ochk.io';\n const f = client.fetch ?? fetch;\n const body = {\n project_id: client.projectId,\n delegation_id: action.delegation_id,\n agent_address: action.signer.address,\n scope_exercised: action.scope_exercised,\n content_hash: action.content.hash,\n content_length: action.content.length,\n content_mime: action.content.mime,\n signed_at: action.signed_at,\n signature: action.sig.value,\n id: action.id,\n };\n const r = await f(`${baseUrl}/api/actions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${client.apiToken}`,\n },\n body: JSON.stringify(body),\n });\n if (!r.ok) {\n let reason = `http_${r.status}`;\n try {\n const j = (await r.json()) as { reason?: string };\n if (j.reason) reason = j.reason;\n } catch {\n // body wasn't json\n }\n throw new Error(`postActionToFleet failed: ${reason}`);\n }\n const j = (await r.json()) as { ok: true; action: PostActionResult };\n return j.action;\n}\n"]}
package/dist/index.mjs CHANGED
@@ -63,19 +63,19 @@ function ocTool(input) {
63
63
  });
64
64
  const result = await input.execute(args);
65
65
  let posted = null;
66
- if (ctx.console) {
66
+ if (ctx.fleet) {
67
67
  try {
68
- posted = await postActionToConsole(action, ctx.console);
68
+ posted = await postActionToFleet(action, ctx.fleet);
69
69
  } catch (err) {
70
- console.error("[oc-agent-vercel] postActionToConsole failed:", err);
70
+ console.error("[oc-agent-vercel] postActionToFleet failed:", err);
71
71
  }
72
72
  }
73
73
  return { result, action, posted };
74
74
  }
75
75
  };
76
76
  }
77
- async function postActionToConsole(action, client) {
78
- const baseUrl = client.baseUrl ?? "https://console.ochk.io";
77
+ async function postActionToFleet(action, client) {
78
+ const baseUrl = client.baseUrl ?? "https://fleet.ochk.io";
79
79
  const f = client.fetch ?? fetch;
80
80
  const body = {
81
81
  project_id: client.projectId,
@@ -104,12 +104,12 @@ async function postActionToConsole(action, client) {
104
104
  if (j2.reason) reason = j2.reason;
105
105
  } catch {
106
106
  }
107
- throw new Error(`postActionToConsole failed: ${reason}`);
107
+ throw new Error(`postActionToFleet failed: ${reason}`);
108
108
  }
109
109
  const j = await r.json();
110
110
  return j.action;
111
111
  }
112
112
 
113
- export { canonicalizeToolCall, ocTool, postActionToConsole, stampToolCall, toolCallActionId, toolCallHash };
113
+ export { canonicalizeToolCall, ocTool, postActionToFleet, stampToolCall, toolCallActionId, toolCallHash };
114
114
  //# sourceMappingURL=index.mjs.map
115
115
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["j"],"mappings":"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","file":"index.mjs","sourcesContent":["// @orangecheck/agent-vercel — wrap Vercel AI SDK `tool()` invocations in\n// OC Agent action envelopes.\n//\n// Provider-agnostic: the AI SDK is the abstraction layer. Whatever model\n// you use underneath (Anthropic, OpenAI, Cohere, …) the tool primitive is\n// the same {description, parameters, execute} shape. This adapter wraps\n// `execute` so every successful call produces a signed agent-action\n// envelope citing the active delegation.\n//\n// Two integration shapes:\n//\n// 1. ocTool({verb, parameters, execute})\n// A drop-in replacement for `tool()`. The wrapped execute runs the\n// scope check, signs the canonical (verb, args, callId) tuple,\n// then runs your real handler.\n//\n// 2. stampToolCall(input)\n// Lower-level stamping helper for cases where you have your own\n// tool-execution loop and want to emit envelopes manually.\n//\n// The agent + delegation are passed via a per-request context object\n// (or threaded through closures) — we don't depend on AsyncLocalStorage\n// to keep edge-runtime compatibility maximal.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalize,\n computeActionId,\n hexEncode,\n isSubScope,\n parseScope,\n type DelegationEnvelope,\n} from '@orangecheck/agent-core';\nimport {\n signAsAgent,\n type ActionEnvelope,\n type SignerRef,\n} from '@orangecheck/agent-signer';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Canonicalization of a tool call\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface VercelToolCall {\n /** Unique id assigned by the AI SDK for this tool invocation. */\n callId: string;\n /** Tool verb / name — passed in via ocTool() or set per-call by your wrapper. */\n verb: string;\n /** JSON-serializable arguments produced by the model. */\n args: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for a Vercel AI SDK tool call.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"args\": <canonical JSON of args>,\n * \"call_id\": <callId>,\n * \"verb\": <verb>\n * }\n */\nexport function canonicalizeToolCall(c: VercelToolCall): Uint8Array {\n const canon = {\n args: c.args,\n call_id: c.callId,\n verb: c.verb,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolCallHash(c: VercelToolCall): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolCall(c)));\n}\n\nexport function toolCallActionId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n c: VercelToolCall\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolCallHash(c),\n content_length: canonicalizeToolCall(c).byteLength,\n content_mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamping primitive\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AgentContext {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n}\n\nexport interface StampToolCallInput extends AgentContext {\n call: VercelToolCall;\n /** Defaults to `vercel:tool(verb=<verb>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\nexport async function stampToolCall(input: StampToolCallInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `vercel:tool(verb=${input.call.verb})`;\n\n const granted = (input.delegation.scopes ?? []).map(parseScope);\n const exercisedParsed = parseScope(scopeExercised);\n if (!granted.some((g) => isSubScope(exercisedParsed, g))) {\n throw new Error(\n `stampToolCall: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolCall(input.call);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolCallHash(input.call), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ocTool — drop-in tool() replacement\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface OcToolInput<TArgs extends Record<string, unknown>, TResult> {\n /** OC Agent verb under which this tool is exercised. */\n verb: string;\n /** Pass-through to AI SDK's `tool()` — the JSON Schema for inputs. */\n parameters?: unknown;\n /** Pass-through description shown to the model. */\n description?: string;\n /** Your real handler. Returns whatever the tool returns. */\n execute: (args: TArgs) => Promise<TResult>;\n}\n\nexport interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {\n verb: string;\n parameters?: unknown;\n description?: string;\n /**\n * The execute fn the AI SDK calls. Receives args + a callId (the AI\n * SDK passes its own callId through — adapter glue passes it via\n * context). Optional `console` field on the context tells the\n * wrapper to fire-and-forget POST the stamped action to console.\n * ochk.io/api/actions after the underlying execute() returns.\n */\n execute: (\n args: TArgs,\n ctx: AgentContext & { callId: string; console?: ConsoleClient }\n ) => Promise<{\n result: TResult;\n action: ActionEnvelope;\n posted: PostActionResult | null;\n }>;\n}\n\n/**\n * Wrap a tool() definition so its execute path is scope-checked and\n * envelope-emitting. The exact glue depends on which AI-SDK release you're\n * on — the typical pattern is:\n *\n * const tools = {\n * 'invoice.create': tool({\n * description: '…',\n * parameters: schema,\n * execute: async (args, { toolCallId }) => {\n * const { result, action } = await invoiceCreate.execute(args, {\n * agent, delegation, callId: toolCallId,\n * });\n * await yourAuditPipeline.append(action);\n * return result;\n * },\n * }),\n * };\n *\n * const invoiceCreate = ocTool({\n * verb: 'invoice.create',\n * parameters: schema,\n * execute: async (args) => myInvoiceCreateImpl(args),\n * });\n *\n * The `ocTool` value is provider/SDK-agnostic — bring your own glue around\n * it. v1 of the adapter intentionally does not import `ai` so it works on\n * any release.\n */\nexport function ocTool<TArgs extends Record<string, unknown>, TResult>(\n input: OcToolInput<TArgs, TResult>\n): OcToolWrapped<TArgs, TResult> {\n return {\n verb: input.verb,\n parameters: input.parameters,\n description: input.description,\n execute: async (args, ctx) => {\n const call: VercelToolCall = {\n callId: ctx.callId,\n verb: input.verb,\n args,\n };\n const action = await stampToolCall({\n agent: ctx.agent,\n delegation: ctx.delegation,\n call,\n });\n const result = await input.execute(args);\n let posted: PostActionResult | null = null;\n if (ctx.console) {\n try {\n posted = await postActionToConsole(action, ctx.console);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[oc-agent-vercel] postActionToConsole failed:', err);\n }\n }\n return { result, action, posted };\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Console integration: POST stamped actions to console.ochk.io/api/actions\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ConsoleClient {\n /** Defaults to https://console.ochk.io. */\n baseUrl?: string;\n /** Bearer token from /settings § 03 (`ock_<hex>`). */\n apiToken: string;\n /** Project the action belongs to (proj_*). */\n projectId: string;\n /** Optional fetch override for runtimes that need it. */\n fetch?: typeof fetch;\n}\n\nexport interface PostActionResult {\n id: string;\n project_id: string;\n delegation_id: string;\n}\n\n/**\n * POST a stamped action envelope to console.ochk.io/api/actions. The\n * console re-derives the action id, validates agent-must-match-\n * delegation, persists, fans out to Nostr (kind 30084), submits to\n * OC Stamp, and triggers any subscribed webhooks. Throws on non-2xx\n * with the server's reason string.\n */\nexport async function postActionToConsole(\n action: ActionEnvelope,\n client: ConsoleClient\n): Promise<PostActionResult> {\n const baseUrl = client.baseUrl ?? 'https://console.ochk.io';\n const f = client.fetch ?? fetch;\n const body = {\n project_id: client.projectId,\n delegation_id: action.delegation_id,\n agent_address: action.signer.address,\n scope_exercised: action.scope_exercised,\n content_hash: action.content.hash,\n content_length: action.content.length,\n content_mime: action.content.mime,\n signed_at: action.signed_at,\n signature: action.sig.value,\n id: action.id,\n };\n const r = await f(`${baseUrl}/api/actions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${client.apiToken}`,\n },\n body: JSON.stringify(body),\n });\n if (!r.ok) {\n let reason = `http_${r.status}`;\n try {\n const j = (await r.json()) as { reason?: string };\n if (j.reason) reason = j.reason;\n } catch {\n // body wasn't json\n }\n throw new Error(`postActionToConsole failed: ${reason}`);\n }\n const j = (await r.json()) as { ok: true; action: PostActionResult };\n return j.action;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["j"],"mappings":";;;;;AA8DO,SAAS,qBAAqB,CAAA,EAA+B;AAChE,EAAA,MAAM,KAAA,GAAQ;AAAA,IACV,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,SAAS,CAAA,CAAE,MAAA;AAAA,IACX,MAAM,CAAA,CAAE;AAAA,GACZ;AACA,EAAA,MAAM,GAAA,GAAM,aAAa,KAAsD,CAAA;AAC/E,EAAA,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,MAAM,IAAI,CAAA;AAC9C;AAEO,SAAS,aAAa,CAAA,EAA2B;AACpD,EAAA,OAAO,YAAY,SAAA,CAAU,MAAA,CAAO,oBAAA,CAAqB,CAAC,CAAC,CAAC,CAAA;AAChE;AAEO,SAAS,gBAAA,CACZ,YAAA,EACA,QAAA,EACA,YAAA,EACA,gBACA,CAAA,EACM;AACN,EAAA,OAAO,eAAA,CAAgB;AAAA,IACnB,OAAA,EAAS,YAAA;AAAA,IACT,YAAA,EAAc,aAAa,CAAC,CAAA;AAAA,IAC5B,cAAA,EAAgB,oBAAA,CAAqB,CAAC,CAAA,CAAE,UAAA;AAAA,IACxC,YAAA,EAAc,gDAAA;AAAA,IACd,SAAA,EAAW,QAAA;AAAA,IACX,aAAA,EAAe,YAAA;AAAA,IACf,eAAA,EAAiB;AAAA,GACpB,CAAA;AACL;AAkBA,eAAsB,cAAc,KAAA,EAAoD;AACpF,EAAA,MAAM,iBACF,KAAA,CAAM,cAAA,IAAkB,CAAA,iBAAA,EAAoB,KAAA,CAAM,KAAK,IAAI,CAAA,CAAA,CAAA;AAE/D,EAAA,MAAM,WAAW,KAAA,CAAM,UAAA,CAAW,UAAU,EAAC,EAAG,IAAI,UAAU,CAAA;AAC9D,EAAA,MAAM,eAAA,GAAkB,WAAW,cAAc,CAAA;AACjD,EAAA,IAAI,CAAC,QAAQ,IAAA,CAAK,CAAC,MAAM,UAAA,CAAW,eAAA,EAAiB,CAAC,CAAC,CAAA,EAAG;AACtD,IAAA,MAAM,IAAI,KAAA;AAAA,MACN,mCAAmC,cAAc,CAAA,yCAAA;AAAA,KACrD;AAAA,EACJ;AAEA,EAAA,MAAM,KAAA,GAAQ,oBAAA,CAAqB,KAAA,CAAM,IAAI,CAAA;AAC7C,EAAA,OAAO,WAAA,CAAY;AAAA,IACf,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,OAAA,EAAS,EAAE,IAAA,EAAM,YAAA,CAAa,MAAM,IAAI,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,UAAA,EAAW;AAAA,IACpE,IAAA,EAAM,gDAAA;AAAA,IACN,cAAA;AAAA,IACA,UAAU,KAAA,CAAM;AAAA,GACnB,CAAA;AACL;AAmEO,SAAS,OACZ,KAAA,EAC6B;AAC7B,EAAA,OAAO;AAAA,IACH,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,OAAA,EAAS,OAAO,IAAA,EAAM,GAAA,KAAQ;AAC1B,MAAA,MAAM,IAAA,GAAuB;AAAA,QACzB,QAAQ,GAAA,CAAI,MAAA;AAAA,QACZ,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ;AAAA,OACJ;AACA,MAAA,MAAM,MAAA,GAAS,MAAM,aAAA,CAAc;AAAA,QAC/B,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,YAAY,GAAA,CAAI,UAAA;AAAA,QAChB;AAAA,OACH,CAAA;AACD,MAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AACvC,MAAA,IAAI,MAAA,GAAkC,IAAA;AACtC,MAAA,IAAI,IAAI,KAAA,EAAO;AACX,QAAA,IAAI;AACA,UAAA,MAAA,GAAS,MAAM,iBAAA,CAAkB,MAAA,EAAQ,GAAA,CAAI,KAAK,CAAA;AAAA,QACtD,SAAS,GAAA,EAAK;AAEV,UAAA,OAAA,CAAQ,KAAA,CAAM,+CAA+C,GAAG,CAAA;AAAA,QACpE;AAAA,MACJ;AACA,MAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO;AAAA,IACpC;AAAA,GACJ;AACJ;AA8BA,eAAsB,iBAAA,CAClB,QACA,MAAA,EACyB;AACzB,EAAA,MAAM,OAAA,GAAU,OAAO,OAAA,IAAW,uBAAA;AAClC,EAAA,MAAM,CAAA,GAAI,OAAO,KAAA,IAAS,KAAA;AAC1B,EAAA,MAAM,IAAA,GAAO;AAAA,IACT,YAAY,MAAA,CAAO,SAAA;AAAA,IACnB,eAAe,MAAA,CAAO,aAAA;AAAA,IACtB,aAAA,EAAe,OAAO,MAAA,CAAO,OAAA;AAAA,IAC7B,iBAAiB,MAAA,CAAO,eAAA;AAAA,IACxB,YAAA,EAAc,OAAO,OAAA,CAAQ,IAAA;AAAA,IAC7B,cAAA,EAAgB,OAAO,OAAA,CAAQ,MAAA;AAAA,IAC/B,YAAA,EAAc,OAAO,OAAA,CAAQ,IAAA;AAAA,IAC7B,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,SAAA,EAAW,OAAO,GAAA,CAAI,KAAA;AAAA,IACtB,IAAI,MAAA,CAAO;AAAA,GACf;AACA,EAAA,MAAM,CAAA,GAAI,MAAM,CAAA,CAAE,CAAA,EAAG,OAAO,CAAA,YAAA,CAAA,EAAgB;AAAA,IACxC,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACL,cAAA,EAAgB,kBAAA;AAAA,MAChB,aAAA,EAAe,CAAA,OAAA,EAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,KAC5C;AAAA,IACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,GAC5B,CAAA;AACD,EAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACP,IAAA,IAAI,MAAA,GAAS,CAAA,KAAA,EAAQ,CAAA,CAAE,MAAM,CAAA,CAAA;AAC7B,IAAA,IAAI;AACA,MAAA,MAAMA,EAAAA,GAAK,MAAM,CAAA,CAAE,IAAA,EAAK;AACxB,MAAA,IAAIA,EAAAA,CAAE,MAAA,EAAQ,MAAA,GAASA,EAAAA,CAAE,MAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,MAAM,CAAA,CAAE,CAAA;AAAA,EACzD;AACA,EAAA,MAAM,CAAA,GAAK,MAAM,CAAA,CAAE,IAAA,EAAK;AACxB,EAAA,OAAO,CAAA,CAAE,MAAA;AACb","file":"index.mjs","sourcesContent":["// @orangecheck/agent-vercel — wrap Vercel AI SDK `tool()` invocations in\n// OC Agent action envelopes.\n//\n// Provider-agnostic: the AI SDK is the abstraction layer. Whatever model\n// you use underneath (Anthropic, OpenAI, Cohere, …) the tool primitive is\n// the same {description, parameters, execute} shape. This adapter wraps\n// `execute` so every successful call produces a signed agent-action\n// envelope citing the active delegation.\n//\n// Two integration shapes:\n//\n// 1. ocTool({verb, parameters, execute})\n// A drop-in replacement for `tool()`. The wrapped execute runs the\n// scope check, signs the canonical (verb, args, callId) tuple,\n// then runs your real handler.\n//\n// 2. stampToolCall(input)\n// Lower-level stamping helper for cases where you have your own\n// tool-execution loop and want to emit envelopes manually.\n//\n// The agent + delegation are passed via a per-request context object\n// (or threaded through closures) — we don't depend on AsyncLocalStorage\n// to keep edge-runtime compatibility maximal.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalize,\n computeActionId,\n hexEncode,\n isSubScope,\n parseScope,\n type DelegationEnvelope,\n} from '@orangecheck/agent-core';\nimport {\n signAsAgent,\n type ActionEnvelope,\n type SignerRef,\n} from '@orangecheck/agent-signer';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Canonicalization of a tool call\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface VercelToolCall {\n /** Unique id assigned by the AI SDK for this tool invocation. */\n callId: string;\n /** Tool verb / name — passed in via ocTool() or set per-call by your wrapper. */\n verb: string;\n /** JSON-serializable arguments produced by the model. */\n args: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for a Vercel AI SDK tool call.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"args\": <canonical JSON of args>,\n * \"call_id\": <callId>,\n * \"verb\": <verb>\n * }\n */\nexport function canonicalizeToolCall(c: VercelToolCall): Uint8Array {\n const canon = {\n args: c.args,\n call_id: c.callId,\n verb: c.verb,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolCallHash(c: VercelToolCall): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolCall(c)));\n}\n\nexport function toolCallActionId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n c: VercelToolCall\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolCallHash(c),\n content_length: canonicalizeToolCall(c).byteLength,\n content_mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamping primitive\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AgentContext {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n}\n\nexport interface StampToolCallInput extends AgentContext {\n call: VercelToolCall;\n /** Defaults to `vercel:tool(verb=<verb>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\nexport async function stampToolCall(input: StampToolCallInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `vercel:tool(verb=${input.call.verb})`;\n\n const granted = (input.delegation.scopes ?? []).map(parseScope);\n const exercisedParsed = parseScope(scopeExercised);\n if (!granted.some((g) => isSubScope(exercisedParsed, g))) {\n throw new Error(\n `stampToolCall: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolCall(input.call);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolCallHash(input.call), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.vercel-tool-call+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ocTool — drop-in tool() replacement\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface OcToolInput<TArgs extends Record<string, unknown>, TResult> {\n /** OC Agent verb under which this tool is exercised. */\n verb: string;\n /** Pass-through to AI SDK's `tool()` — the JSON Schema for inputs. */\n parameters?: unknown;\n /** Pass-through description shown to the model. */\n description?: string;\n /** Your real handler. Returns whatever the tool returns. */\n execute: (args: TArgs) => Promise<TResult>;\n}\n\nexport interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {\n verb: string;\n parameters?: unknown;\n description?: string;\n /**\n * The execute fn the AI SDK calls. Receives args + a callId (the AI\n * SDK passes its own callId through — adapter glue passes it via\n * context). Optional `fleet` field on the context tells the\n * wrapper to fire-and-forget POST the stamped action to fleet.\n * ochk.io/api/actions after the underlying execute() returns.\n */\n execute: (\n args: TArgs,\n ctx: AgentContext & { callId: string; fleet?: FleetClient }\n ) => Promise<{\n result: TResult;\n action: ActionEnvelope;\n posted: PostActionResult | null;\n }>;\n}\n\n/**\n * Wrap a tool() definition so its execute path is scope-checked and\n * envelope-emitting. The exact glue depends on which AI-SDK release you're\n * on — the typical pattern is:\n *\n * const tools = {\n * 'invoice.create': tool({\n * description: '…',\n * parameters: schema,\n * execute: async (args, { toolCallId }) => {\n * const { result, action } = await invoiceCreate.execute(args, {\n * agent, delegation, callId: toolCallId,\n * });\n * await yourAuditPipeline.append(action);\n * return result;\n * },\n * }),\n * };\n *\n * const invoiceCreate = ocTool({\n * verb: 'invoice.create',\n * parameters: schema,\n * execute: async (args) => myInvoiceCreateImpl(args),\n * });\n *\n * The `ocTool` value is provider/SDK-agnostic — bring your own glue around\n * it. v1 of the adapter intentionally does not import `ai` so it works on\n * any release.\n */\nexport function ocTool<TArgs extends Record<string, unknown>, TResult>(\n input: OcToolInput<TArgs, TResult>\n): OcToolWrapped<TArgs, TResult> {\n return {\n verb: input.verb,\n parameters: input.parameters,\n description: input.description,\n execute: async (args, ctx) => {\n const call: VercelToolCall = {\n callId: ctx.callId,\n verb: input.verb,\n args,\n };\n const action = await stampToolCall({\n agent: ctx.agent,\n delegation: ctx.delegation,\n call,\n });\n const result = await input.execute(args);\n let posted: PostActionResult | null = null;\n if (ctx.fleet) {\n try {\n posted = await postActionToFleet(action, ctx.fleet);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[oc-agent-vercel] postActionToFleet failed:', err);\n }\n }\n return { result, action, posted };\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Fleet integration: POST stamped actions to fleet.ochk.io/api/actions\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface FleetClient {\n /** Defaults to https://fleet.ochk.io. */\n baseUrl?: string;\n /** Bearer token from /settings § 03 (`ock_<hex>`). */\n apiToken: string;\n /** Project the action belongs to (proj_*). */\n projectId: string;\n /** Optional fetch override for runtimes that need it. */\n fetch?: typeof fetch;\n}\n\nexport interface PostActionResult {\n id: string;\n project_id: string;\n delegation_id: string;\n}\n\n/**\n * POST a stamped action envelope to fleet.ochk.io/api/actions. The\n * fleet re-derives the action id, validates agent-must-match-\n * delegation, persists, fans out to Nostr (kind 30084), submits to\n * OC Stamp, and triggers any subscribed webhooks. Throws on non-2xx\n * with the server's reason string.\n */\nexport async function postActionToFleet(\n action: ActionEnvelope,\n client: FleetClient\n): Promise<PostActionResult> {\n const baseUrl = client.baseUrl ?? 'https://fleet.ochk.io';\n const f = client.fetch ?? fetch;\n const body = {\n project_id: client.projectId,\n delegation_id: action.delegation_id,\n agent_address: action.signer.address,\n scope_exercised: action.scope_exercised,\n content_hash: action.content.hash,\n content_length: action.content.length,\n content_mime: action.content.mime,\n signed_at: action.signed_at,\n signature: action.sig.value,\n id: action.id,\n };\n const r = await f(`${baseUrl}/api/actions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${client.apiToken}`,\n },\n body: JSON.stringify(body),\n });\n if (!r.ok) {\n let reason = `http_${r.status}`;\n try {\n const j = (await r.json()) as { reason?: string };\n if (j.reason) reason = j.reason;\n } catch {\n // body wasn't json\n }\n throw new Error(`postActionToFleet failed: ${reason}`);\n }\n const j = (await r.json()) as { ok: true; action: PostActionResult };\n return j.action;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orangecheck/agent-vercel",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Wrap Vercel AI SDK tool() invocations with OC Agent scope enforcement and emit a signed agent-action envelope per tool execution. Provider-agnostic — works under Anthropic, OpenAI, Cohere, etc.",
5
5
  "keywords": [
6
6
  "bitcoin",
package/src/index.ts CHANGED
@@ -153,13 +153,13 @@ export interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
153
153
  /**
154
154
  * The execute fn the AI SDK calls. Receives args + a callId (the AI
155
155
  * SDK passes its own callId through — adapter glue passes it via
156
- * context). Optional `console` field on the context tells the
157
- * wrapper to fire-and-forget POST the stamped action to console.
156
+ * context). Optional `fleet` field on the context tells the
157
+ * wrapper to fire-and-forget POST the stamped action to fleet.
158
158
  * ochk.io/api/actions after the underlying execute() returns.
159
159
  */
160
160
  execute: (
161
161
  args: TArgs,
162
- ctx: AgentContext & { callId: string; console?: ConsoleClient }
162
+ ctx: AgentContext & { callId: string; fleet?: FleetClient }
163
163
  ) => Promise<{
164
164
  result: TResult;
165
165
  action: ActionEnvelope;
@@ -216,12 +216,12 @@ export function ocTool<TArgs extends Record<string, unknown>, TResult>(
216
216
  });
217
217
  const result = await input.execute(args);
218
218
  let posted: PostActionResult | null = null;
219
- if (ctx.console) {
219
+ if (ctx.fleet) {
220
220
  try {
221
- posted = await postActionToConsole(action, ctx.console);
221
+ posted = await postActionToFleet(action, ctx.fleet);
222
222
  } catch (err) {
223
223
  // eslint-disable-next-line no-console
224
- console.error('[oc-agent-vercel] postActionToConsole failed:', err);
224
+ console.error('[oc-agent-vercel] postActionToFleet failed:', err);
225
225
  }
226
226
  }
227
227
  return { result, action, posted };
@@ -230,11 +230,11 @@ export function ocTool<TArgs extends Record<string, unknown>, TResult>(
230
230
  }
231
231
 
232
232
  // ─────────────────────────────────────────────────────────────────────────────
233
- // Console integration: POST stamped actions to console.ochk.io/api/actions
233
+ // Fleet integration: POST stamped actions to fleet.ochk.io/api/actions
234
234
  // ─────────────────────────────────────────────────────────────────────────────
235
235
 
236
- export interface ConsoleClient {
237
- /** Defaults to https://console.ochk.io. */
236
+ export interface FleetClient {
237
+ /** Defaults to https://fleet.ochk.io. */
238
238
  baseUrl?: string;
239
239
  /** Bearer token from /settings § 03 (`ock_<hex>`). */
240
240
  apiToken: string;
@@ -251,17 +251,17 @@ export interface PostActionResult {
251
251
  }
252
252
 
253
253
  /**
254
- * POST a stamped action envelope to console.ochk.io/api/actions. The
255
- * console re-derives the action id, validates agent-must-match-
254
+ * POST a stamped action envelope to fleet.ochk.io/api/actions. The
255
+ * fleet re-derives the action id, validates agent-must-match-
256
256
  * delegation, persists, fans out to Nostr (kind 30084), submits to
257
257
  * OC Stamp, and triggers any subscribed webhooks. Throws on non-2xx
258
258
  * with the server's reason string.
259
259
  */
260
- export async function postActionToConsole(
260
+ export async function postActionToFleet(
261
261
  action: ActionEnvelope,
262
- client: ConsoleClient
262
+ client: FleetClient
263
263
  ): Promise<PostActionResult> {
264
- const baseUrl = client.baseUrl ?? 'https://console.ochk.io';
264
+ const baseUrl = client.baseUrl ?? 'https://fleet.ochk.io';
265
265
  const f = client.fetch ?? fetch;
266
266
  const body = {
267
267
  project_id: client.projectId,
@@ -291,7 +291,7 @@ export async function postActionToConsole(
291
291
  } catch {
292
292
  // body wasn't json
293
293
  }
294
- throw new Error(`postActionToConsole failed: ${reason}`);
294
+ throw new Error(`postActionToFleet failed: ${reason}`);
295
295
  }
296
296
  const j = (await r.json()) as { ok: true; action: PostActionResult };
297
297
  return j.action;