@orangecheck/agent-anthropic 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
@@ -94,4 +94,4 @@ MIT.
94
94
  - [@orangecheck/agent-core](https://www.npmjs.com/package/@orangecheck/agent-core) — verifier library.
95
95
  - [@orangecheck/agent-mcp](https://www.npmjs.com/package/@orangecheck/agent-mcp) — same pattern, for MCP.
96
96
  - [@orangecheck/agent-openai](https://www.npmjs.com/package/@orangecheck/agent-openai) — same pattern, for OpenAI Responses + Chat Completions.
97
- - [console.ochk.io/integrations/anthropic](https://console.ochk.io/integrations/anthropic) — the managed-tier story this slots into.
97
+ - [fleet.ochk.io/integrations/anthropic](https://fleet.ochk.io/integrations/anthropic) — the managed-tier story this slots into.
package/dist/index.d.mts CHANGED
@@ -25,7 +25,7 @@ interface InvokeWithStampResult<T> {
25
25
  action: ActionEnvelope;
26
26
  }
27
27
  declare function invokeWithStamp<T>(input: InvokeWithStampInput<T>): Promise<InvokeWithStampResult<T>>;
28
- interface ConsoleClient {
28
+ interface FleetClient {
29
29
  baseUrl?: string;
30
30
  apiToken: string;
31
31
  projectId: string;
@@ -36,13 +36,13 @@ interface PostActionResult {
36
36
  project_id: string;
37
37
  delegation_id: string;
38
38
  }
39
- declare function postActionToConsole(action: ActionEnvelope, client: ConsoleClient): Promise<PostActionResult>;
39
+ declare function postActionToFleet(action: ActionEnvelope, client: FleetClient): Promise<PostActionResult>;
40
40
  interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {
41
- console?: ConsoleClient;
41
+ fleet?: FleetClient;
42
42
  }
43
43
  interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {
44
44
  posted: PostActionResult | null;
45
45
  }
46
46
  declare function invokeWithStampAndPost<T>(input: InvokeWithStampAndPostInput<T>): Promise<InvokeWithStampAndPostResult<T>>;
47
47
 
48
- export { type AnthropicToolUse, type ConsoleClient, type InvokeWithStampAndPostInput, type InvokeWithStampAndPostResult, type InvokeWithStampInput, type InvokeWithStampResult, type PostActionResult, type StampToolUseInput, canonicalizeToolUse, invokeWithStamp, invokeWithStampAndPost, postActionToConsole, stampToolUse, toolUseHash, toolUseId };
48
+ export { type AnthropicToolUse, type FleetClient, type InvokeWithStampAndPostInput, type InvokeWithStampAndPostResult, type InvokeWithStampInput, type InvokeWithStampResult, type PostActionResult, type StampToolUseInput, canonicalizeToolUse, invokeWithStamp, invokeWithStampAndPost, postActionToFleet, stampToolUse, toolUseHash, toolUseId };
package/dist/index.d.ts CHANGED
@@ -25,7 +25,7 @@ interface InvokeWithStampResult<T> {
25
25
  action: ActionEnvelope;
26
26
  }
27
27
  declare function invokeWithStamp<T>(input: InvokeWithStampInput<T>): Promise<InvokeWithStampResult<T>>;
28
- interface ConsoleClient {
28
+ interface FleetClient {
29
29
  baseUrl?: string;
30
30
  apiToken: string;
31
31
  projectId: string;
@@ -36,13 +36,13 @@ interface PostActionResult {
36
36
  project_id: string;
37
37
  delegation_id: string;
38
38
  }
39
- declare function postActionToConsole(action: ActionEnvelope, client: ConsoleClient): Promise<PostActionResult>;
39
+ declare function postActionToFleet(action: ActionEnvelope, client: FleetClient): Promise<PostActionResult>;
40
40
  interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {
41
- console?: ConsoleClient;
41
+ fleet?: FleetClient;
42
42
  }
43
43
  interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {
44
44
  posted: PostActionResult | null;
45
45
  }
46
46
  declare function invokeWithStampAndPost<T>(input: InvokeWithStampAndPostInput<T>): Promise<InvokeWithStampAndPostResult<T>>;
47
47
 
48
- export { type AnthropicToolUse, type ConsoleClient, type InvokeWithStampAndPostInput, type InvokeWithStampAndPostResult, type InvokeWithStampInput, type InvokeWithStampResult, type PostActionResult, type StampToolUseInput, canonicalizeToolUse, invokeWithStamp, invokeWithStampAndPost, postActionToConsole, stampToolUse, toolUseHash, toolUseId };
48
+ export { type AnthropicToolUse, type FleetClient, type InvokeWithStampAndPostInput, type InvokeWithStampAndPostResult, type InvokeWithStampInput, type InvokeWithStampResult, type PostActionResult, type StampToolUseInput, canonicalizeToolUse, invokeWithStamp, invokeWithStampAndPost, postActionToFleet, stampToolUse, toolUseHash, toolUseId };
package/dist/index.js CHANGED
@@ -52,8 +52,8 @@ async function invokeWithStamp(input) {
52
52
  const result = await input.call(input.toolUse);
53
53
  return { result, action };
54
54
  }
55
- async function postActionToConsole(action, client) {
56
- const baseUrl = client.baseUrl ?? "https://console.ochk.io";
55
+ async function postActionToFleet(action, client) {
56
+ const baseUrl = client.baseUrl ?? "https://fleet.ochk.io";
57
57
  const f = client.fetch ?? fetch;
58
58
  const body = {
59
59
  project_id: client.projectId,
@@ -82,7 +82,7 @@ async function postActionToConsole(action, client) {
82
82
  if (j2.reason) reason = j2.reason;
83
83
  } catch {
84
84
  }
85
- throw new Error(`postActionToConsole failed: ${reason}`);
85
+ throw new Error(`postActionToFleet failed: ${reason}`);
86
86
  }
87
87
  const j = await r.json();
88
88
  return j.action;
@@ -90,11 +90,11 @@ async function postActionToConsole(action, client) {
90
90
  async function invokeWithStampAndPost(input) {
91
91
  const { result, action } = await invokeWithStamp(input);
92
92
  let posted = null;
93
- if (input.console) {
93
+ if (input.fleet) {
94
94
  try {
95
- posted = await postActionToConsole(action, input.console);
95
+ posted = await postActionToFleet(action, input.fleet);
96
96
  } catch (err) {
97
- console.error("[oc-agent-anthropic] postActionToConsole failed:", err);
97
+ console.error("[oc-agent-anthropic] postActionToFleet failed:", err);
98
98
  }
99
99
  }
100
100
  return { result, action, posted };
@@ -103,7 +103,7 @@ async function invokeWithStampAndPost(input) {
103
103
  exports.canonicalizeToolUse = canonicalizeToolUse;
104
104
  exports.invokeWithStamp = invokeWithStamp;
105
105
  exports.invokeWithStampAndPost = invokeWithStampAndPost;
106
- exports.postActionToConsole = postActionToConsole;
106
+ exports.postActionToFleet = postActionToFleet;
107
107
  exports.stampToolUse = stampToolUse;
108
108
  exports.toolUseHash = toolUseHash;
109
109
  exports.toolUseId = toolUseId;
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":";;;;;;;AAgDO,SAAS,oBAAoB,CAAA,EAAiC;AACjE,EAAA,MAAM,KAAA,GAAQ;AAAA,IACV,IAAI,CAAA,CAAE,EAAA;AAAA,IACN,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,MAAM,CAAA,CAAE;AAAA,GACZ;AACA,EAAA,MAAM,GAAA,GAAMA,uBAAa,KAAsD,CAAA;AAC/E,EAAA,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,MAAM,IAAI,CAAA;AAC9C;AAEO,SAAS,YAAY,CAAA,EAA6B;AACrD,EAAA,OAAO,YAAYC,mBAAA,CAAUC,aAAA,CAAO,mBAAA,CAAoB,CAAC,CAAC,CAAC,CAAA;AAC/D;AAEO,SAAS,SAAA,CACZ,YAAA,EACA,QAAA,EACA,YAAA,EACA,gBACA,CAAA,EACM;AACN,EAAA,OAAOC,yBAAA,CAAgB;AAAA,IACnB,OAAA,EAAS,YAAA;AAAA,IACT,YAAA,EAAc,YAAY,CAAC,CAAA;AAAA,IAC3B,cAAA,EAAgB,mBAAA,CAAoB,CAAC,CAAA,CAAE,UAAA;AAAA,IACvC,YAAA,EAAc,kDAAA;AAAA,IACd,SAAA,EAAW,QAAA;AAAA,IACX,aAAA,EAAe,YAAA;AAAA,IACf,eAAA,EAAiB;AAAA,GACpB,CAAA;AACL;AAmBA,eAAsB,aAAa,KAAA,EAAmD;AAClF,EAAA,MAAM,iBACF,KAAA,CAAM,cAAA,IAAkB,CAAA,oBAAA,EAAuB,KAAA,CAAM,QAAQ,IAAI,CAAA,CAAA,CAAA;AAErE,EAAA,MAAM,WAAW,KAAA,CAAM,UAAA,CAAW,UAAU,EAAC,EAAG,IAAIC,oBAAU,CAAA;AAC9D,EAAA,MAAM,eAAA,GAAkBA,qBAAW,cAAc,CAAA;AACjD,EAAA,IAAI,CAAC,QAAQ,IAAA,CAAK,CAAC,MAAMC,oBAAA,CAAW,eAAA,EAAiB,CAAC,CAAC,CAAA,EAAG;AACtD,IAAA,MAAM,IAAI,KAAA;AAAA,MACN,kCAAkC,cAAc,CAAA,yCAAA;AAAA,KACpD;AAAA,EACJ;AAEA,EAAA,MAAM,KAAA,GAAQ,mBAAA,CAAoB,KAAA,CAAM,OAAO,CAAA;AAC/C,EAAA,OAAOC,uBAAA,CAAY;AAAA,IACf,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,OAAA,EAAS,EAAE,IAAA,EAAM,WAAA,CAAY,MAAM,OAAO,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,UAAA,EAAW;AAAA,IACtE,IAAA,EAAM,kDAAA;AAAA,IACN,cAAA;AAAA,IACA,UAAU,KAAA,CAAM;AAAA,GACnB,CAAA;AACL;AAsBA,eAAsB,gBAClB,KAAA,EACiC;AACjC,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,KAAK,CAAA;AACvC,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,IAAA,CAAK,MAAM,OAAO,CAAA;AAC7C,EAAA,OAAO,EAAE,QAAQ,MAAA,EAAO;AAC5B;AAoCA,eAAsB,mBAAA,CAClB,QACA,MAAA,EACyB;AACzB,EAAA,MAAM,OAAA,GAAU,OAAO,OAAA,IAAW,yBAAA;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,MAAMC,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,4BAAA,EAA+B,MAAM,CAAA,CAAE,CAAA;AAAA,EAC3D;AACA,EAAA,MAAM,CAAA,GAAK,MAAM,CAAA,CAAE,IAAA,EAAK;AACxB,EAAA,OAAO,CAAA,CAAE,MAAA;AACb;AAsBA,eAAsB,uBAClB,KAAA,EACwC;AACxC,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAM,gBAAgB,KAAK,CAAA;AACtD,EAAA,IAAI,MAAA,GAAkC,IAAA;AACtC,EAAA,IAAI,MAAM,OAAA,EAAS;AACf,IAAA,IAAI;AACA,MAAA,MAAA,GAAS,MAAM,mBAAA,CAAoB,MAAA,EAAQ,KAAA,CAAM,OAAO,CAAA;AAAA,IAC5D,SAAS,GAAA,EAAK;AAKV,MAAA,OAAA,CAAQ,KAAA,CAAM,oDAAoD,GAAG,CAAA;AAAA,IACzE;AAAA,EACJ;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO;AACpC","file":"index.js","sourcesContent":["// @orangecheck/agent-anthropic — wrap Anthropic Tool Use invocations in\n// OC Agent action envelopes.\n//\n// Anthropic's Messages API surfaces tool calls as `tool_use` content\n// blocks: { type: 'tool_use', id, name, input }. This module canonicalizes\n// each tool_use, hashes it, and produces an agent-action envelope binding\n// the BIP-322-authenticated agent to the (tool_name, input) tuple — at a\n// scope of `anthropic:tool(name=<tool>)`.\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 an Anthropic tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AnthropicToolUse {\n /** The `id` Anthropic assigns to this tool_use block (passed back as tool_use_id on result). */\n id: string;\n /** The tool name registered in your `tools` array on messages.create. */\n name: string;\n /** The model's structured input for this tool — JSON-serializable. */\n input: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for an Anthropic tool_use. The bytes are what\n * the agent-action envelope's `content.hash` is a SHA-256 of.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"id\": <tool_use_id>,\n * \"input\": <canonical JSON of input>,\n * \"name\": <tool name>\n * }\n */\nexport function canonicalizeToolUse(t: AnthropicToolUse): Uint8Array {\n const canon = {\n id: t.id,\n input: t.input,\n name: t.name,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolUseHash(t: AnthropicToolUse): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolUse(t)));\n}\n\nexport function toolUseId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n t: AnthropicToolUse\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolUseHash(t),\n content_length: canonicalizeToolUse(t).byteLength,\n content_mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamped tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface StampToolUseInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n toolUse: AnthropicToolUse;\n /** Defaults to `anthropic:tool(name=<tool>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\n/**\n * Stamp an Anthropic tool_use without executing it. Useful for pre-\n * authorization flows or batch stamping.\n */\nexport async function stampToolUse(input: StampToolUseInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `anthropic:tool(name=${input.toolUse.name})`;\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 `stampToolUse: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolUse(input.toolUse);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolUseHash(input.toolUse), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// invokeWithStamp — call the tool AND produce the stamp around it\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface InvokeWithStampInput<T> extends StampToolUseInput {\n /** Your handler that actually runs the tool. Returns whatever the tool returns. */\n call: (toolUse: AnthropicToolUse) => Promise<T>;\n}\n\nexport interface InvokeWithStampResult<T> {\n result: T;\n action: ActionEnvelope;\n}\n\n/**\n * Stamp the tool_use first, then execute the handler. The stamped envelope\n * is returned alongside the result so the caller can ship them together —\n * e.g. as a side-channel to an audit log, or as the `_oc_agent` metadata on\n * the tool_result content block back to Claude.\n */\nexport async function invokeWithStamp<T>(\n input: InvokeWithStampInput<T>\n): Promise<InvokeWithStampResult<T>> {\n const action = await stampToolUse(input);\n const result = await input.call(input.toolUse);\n return { result, action };\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 (Node 18 LTS w/o global fetch, etc). */\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's /api/actions\n * registry. The console:\n * - re-derives the action id from canonical inputs and rejects on\n * mismatch (tamper defense)\n * - validates that the agent address matches the parent delegation's\n * agent (forgery defense)\n * - persists, fans out to Nostr (kind 30084), submits to OC Stamp,\n * and triggers any subscribed webhooks (action.registered)\n *\n * Returns the registered action's id + project_id + delegation_id.\n * Throws on non-2xx 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; keep the http_<n> reason\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\nexport interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {\n /** Console credentials. If absent, behaves like invokeWithStamp (no posting). */\n console?: ConsoleClient;\n}\n\nexport interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {\n /** Set when console is configured AND the POST succeeded. null otherwise. */\n posted: PostActionResult | null;\n}\n\n/**\n * Convenience: stamp the tool_use, execute the handler, AND post the\n * stamped envelope to console. Three roundtrips → one call. If `console`\n * is omitted, this is identical to invokeWithStamp + posted=null.\n *\n * The post happens AFTER the call so a failing post doesn't prevent the\n * tool from running. If you need pre-authorization (the post must\n * succeed before the call runs), use stampToolUse + postActionToConsole\n * + your call() in that order.\n */\nexport async function invokeWithStampAndPost<T>(\n input: InvokeWithStampAndPostInput<T>\n): Promise<InvokeWithStampAndPostResult<T>> {\n const { result, action } = await invokeWithStamp(input);\n let posted: PostActionResult | null = null;\n if (input.console) {\n try {\n posted = await postActionToConsole(action, input.console);\n } catch (err) {\n // Best-effort post — surfacing the error here would force\n // every caller to handle \"tool ran fine but post failed\",\n // which is rarely what they want. Log and continue.\n // eslint-disable-next-line no-console\n console.error('[oc-agent-anthropic] postActionToConsole failed:', err);\n }\n }\n return { result, action, posted };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["canonicalize","hexEncode","sha256","computeActionId","parseScope","isSubScope","signAsAgent","j"],"mappings":";;;;;;;AAgDO,SAAS,oBAAoB,CAAA,EAAiC;AACjE,EAAA,MAAM,KAAA,GAAQ;AAAA,IACV,IAAI,CAAA,CAAE,EAAA;AAAA,IACN,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,MAAM,CAAA,CAAE;AAAA,GACZ;AACA,EAAA,MAAM,GAAA,GAAMA,uBAAa,KAAsD,CAAA;AAC/E,EAAA,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,MAAM,IAAI,CAAA;AAC9C;AAEO,SAAS,YAAY,CAAA,EAA6B;AACrD,EAAA,OAAO,YAAYC,mBAAA,CAAUC,aAAA,CAAO,mBAAA,CAAoB,CAAC,CAAC,CAAC,CAAA;AAC/D;AAEO,SAAS,SAAA,CACZ,YAAA,EACA,QAAA,EACA,YAAA,EACA,gBACA,CAAA,EACM;AACN,EAAA,OAAOC,yBAAA,CAAgB;AAAA,IACnB,OAAA,EAAS,YAAA;AAAA,IACT,YAAA,EAAc,YAAY,CAAC,CAAA;AAAA,IAC3B,cAAA,EAAgB,mBAAA,CAAoB,CAAC,CAAA,CAAE,UAAA;AAAA,IACvC,YAAA,EAAc,kDAAA;AAAA,IACd,SAAA,EAAW,QAAA;AAAA,IACX,aAAA,EAAe,YAAA;AAAA,IACf,eAAA,EAAiB;AAAA,GACpB,CAAA;AACL;AAmBA,eAAsB,aAAa,KAAA,EAAmD;AAClF,EAAA,MAAM,iBACF,KAAA,CAAM,cAAA,IAAkB,CAAA,oBAAA,EAAuB,KAAA,CAAM,QAAQ,IAAI,CAAA,CAAA,CAAA;AAErE,EAAA,MAAM,WAAW,KAAA,CAAM,UAAA,CAAW,UAAU,EAAC,EAAG,IAAIC,oBAAU,CAAA;AAC9D,EAAA,MAAM,eAAA,GAAkBA,qBAAW,cAAc,CAAA;AACjD,EAAA,IAAI,CAAC,QAAQ,IAAA,CAAK,CAAC,MAAMC,oBAAA,CAAW,eAAA,EAAiB,CAAC,CAAC,CAAA,EAAG;AACtD,IAAA,MAAM,IAAI,KAAA;AAAA,MACN,kCAAkC,cAAc,CAAA,yCAAA;AAAA,KACpD;AAAA,EACJ;AAEA,EAAA,MAAM,KAAA,GAAQ,mBAAA,CAAoB,KAAA,CAAM,OAAO,CAAA;AAC/C,EAAA,OAAOC,uBAAA,CAAY;AAAA,IACf,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,OAAA,EAAS,EAAE,IAAA,EAAM,WAAA,CAAY,MAAM,OAAO,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,UAAA,EAAW;AAAA,IACtE,IAAA,EAAM,kDAAA;AAAA,IACN,cAAA;AAAA,IACA,UAAU,KAAA,CAAM;AAAA,GACnB,CAAA;AACL;AAsBA,eAAsB,gBAClB,KAAA,EACiC;AACjC,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,KAAK,CAAA;AACvC,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,IAAA,CAAK,MAAM,OAAO,CAAA;AAC7C,EAAA,OAAO,EAAE,QAAQ,MAAA,EAAO;AAC5B;AAoCA,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,MAAMC,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;AAsBA,eAAsB,uBAClB,KAAA,EACwC;AACxC,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAM,gBAAgB,KAAK,CAAA;AACtD,EAAA,IAAI,MAAA,GAAkC,IAAA;AACtC,EAAA,IAAI,MAAM,KAAA,EAAO;AACb,IAAA,IAAI;AACA,MAAA,MAAA,GAAS,MAAM,iBAAA,CAAkB,MAAA,EAAQ,KAAA,CAAM,KAAK,CAAA;AAAA,IACxD,SAAS,GAAA,EAAK;AAKV,MAAA,OAAA,CAAQ,KAAA,CAAM,kDAAkD,GAAG,CAAA;AAAA,IACvE;AAAA,EACJ;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO;AACpC","file":"index.js","sourcesContent":["// @orangecheck/agent-anthropic — wrap Anthropic Tool Use invocations in\n// OC Agent action envelopes.\n//\n// Anthropic's Messages API surfaces tool calls as `tool_use` content\n// blocks: { type: 'tool_use', id, name, input }. This module canonicalizes\n// each tool_use, hashes it, and produces an agent-action envelope binding\n// the BIP-322-authenticated agent to the (tool_name, input) tuple — at a\n// scope of `anthropic:tool(name=<tool>)`.\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 an Anthropic tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AnthropicToolUse {\n /** The `id` Anthropic assigns to this tool_use block (passed back as tool_use_id on result). */\n id: string;\n /** The tool name registered in your `tools` array on messages.create. */\n name: string;\n /** The model's structured input for this tool — JSON-serializable. */\n input: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for an Anthropic tool_use. The bytes are what\n * the agent-action envelope's `content.hash` is a SHA-256 of.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"id\": <tool_use_id>,\n * \"input\": <canonical JSON of input>,\n * \"name\": <tool name>\n * }\n */\nexport function canonicalizeToolUse(t: AnthropicToolUse): Uint8Array {\n const canon = {\n id: t.id,\n input: t.input,\n name: t.name,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolUseHash(t: AnthropicToolUse): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolUse(t)));\n}\n\nexport function toolUseId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n t: AnthropicToolUse\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolUseHash(t),\n content_length: canonicalizeToolUse(t).byteLength,\n content_mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamped tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface StampToolUseInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n toolUse: AnthropicToolUse;\n /** Defaults to `anthropic:tool(name=<tool>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\n/**\n * Stamp an Anthropic tool_use without executing it. Useful for pre-\n * authorization flows or batch stamping.\n */\nexport async function stampToolUse(input: StampToolUseInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `anthropic:tool(name=${input.toolUse.name})`;\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 `stampToolUse: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolUse(input.toolUse);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolUseHash(input.toolUse), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// invokeWithStamp — call the tool AND produce the stamp around it\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface InvokeWithStampInput<T> extends StampToolUseInput {\n /** Your handler that actually runs the tool. Returns whatever the tool returns. */\n call: (toolUse: AnthropicToolUse) => Promise<T>;\n}\n\nexport interface InvokeWithStampResult<T> {\n result: T;\n action: ActionEnvelope;\n}\n\n/**\n * Stamp the tool_use first, then execute the handler. The stamped envelope\n * is returned alongside the result so the caller can ship them together —\n * e.g. as a side-channel to an audit log, or as the `_oc_agent` metadata on\n * the tool_result content block back to Claude.\n */\nexport async function invokeWithStamp<T>(\n input: InvokeWithStampInput<T>\n): Promise<InvokeWithStampResult<T>> {\n const action = await stampToolUse(input);\n const result = await input.call(input.toolUse);\n return { result, action };\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 (Node 18 LTS w/o global fetch, etc). */\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's /api/actions\n * registry. The fleet:\n * - re-derives the action id from canonical inputs and rejects on\n * mismatch (tamper defense)\n * - validates that the agent address matches the parent delegation's\n * agent (forgery defense)\n * - persists, fans out to Nostr (kind 30084), submits to OC Stamp,\n * and triggers any subscribed webhooks (action.registered)\n *\n * Returns the registered action's id + project_id + delegation_id.\n * Throws on non-2xx 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; keep the http_<n> reason\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\nexport interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {\n /** Fleet credentials. If absent, behaves like invokeWithStamp (no posting). */\n fleet?: FleetClient;\n}\n\nexport interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {\n /** Set when fleet is configured AND the POST succeeded. null otherwise. */\n posted: PostActionResult | null;\n}\n\n/**\n * Convenience: stamp the tool_use, execute the handler, AND post the\n * stamped envelope to fleet. Three roundtrips → one call. If `fleet`\n * is omitted, this is identical to invokeWithStamp + posted=null.\n *\n * The post happens AFTER the call so a failing post doesn't prevent the\n * tool from running. If you need pre-authorization (the post must\n * succeed before the call runs), use stampToolUse + postActionToFleet\n * + your call() in that order.\n */\nexport async function invokeWithStampAndPost<T>(\n input: InvokeWithStampAndPostInput<T>\n): Promise<InvokeWithStampAndPostResult<T>> {\n const { result, action } = await invokeWithStamp(input);\n let posted: PostActionResult | null = null;\n if (input.fleet) {\n try {\n posted = await postActionToFleet(action, input.fleet);\n } catch (err) {\n // Best-effort post — surfacing the error here would force\n // every caller to handle \"tool ran fine but post failed\",\n // which is rarely what they want. Log and continue.\n // eslint-disable-next-line no-console\n console.error('[oc-agent-anthropic] postActionToFleet failed:', err);\n }\n }\n return { result, action, posted };\n}\n"]}
package/dist/index.mjs CHANGED
@@ -50,8 +50,8 @@ async function invokeWithStamp(input) {
50
50
  const result = await input.call(input.toolUse);
51
51
  return { result, action };
52
52
  }
53
- async function postActionToConsole(action, client) {
54
- const baseUrl = client.baseUrl ?? "https://console.ochk.io";
53
+ async function postActionToFleet(action, client) {
54
+ const baseUrl = client.baseUrl ?? "https://fleet.ochk.io";
55
55
  const f = client.fetch ?? fetch;
56
56
  const body = {
57
57
  project_id: client.projectId,
@@ -80,7 +80,7 @@ async function postActionToConsole(action, client) {
80
80
  if (j2.reason) reason = j2.reason;
81
81
  } catch {
82
82
  }
83
- throw new Error(`postActionToConsole failed: ${reason}`);
83
+ throw new Error(`postActionToFleet failed: ${reason}`);
84
84
  }
85
85
  const j = await r.json();
86
86
  return j.action;
@@ -88,16 +88,16 @@ async function postActionToConsole(action, client) {
88
88
  async function invokeWithStampAndPost(input) {
89
89
  const { result, action } = await invokeWithStamp(input);
90
90
  let posted = null;
91
- if (input.console) {
91
+ if (input.fleet) {
92
92
  try {
93
- posted = await postActionToConsole(action, input.console);
93
+ posted = await postActionToFleet(action, input.fleet);
94
94
  } catch (err) {
95
- console.error("[oc-agent-anthropic] postActionToConsole failed:", err);
95
+ console.error("[oc-agent-anthropic] postActionToFleet failed:", err);
96
96
  }
97
97
  }
98
98
  return { result, action, posted };
99
99
  }
100
100
 
101
- export { canonicalizeToolUse, invokeWithStamp, invokeWithStampAndPost, postActionToConsole, stampToolUse, toolUseHash, toolUseId };
101
+ export { canonicalizeToolUse, invokeWithStamp, invokeWithStampAndPost, postActionToFleet, stampToolUse, toolUseHash, toolUseId };
102
102
  //# sourceMappingURL=index.mjs.map
103
103
  //# 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-anthropic — wrap Anthropic Tool Use invocations in\n// OC Agent action envelopes.\n//\n// Anthropic's Messages API surfaces tool calls as `tool_use` content\n// blocks: { type: 'tool_use', id, name, input }. This module canonicalizes\n// each tool_use, hashes it, and produces an agent-action envelope binding\n// the BIP-322-authenticated agent to the (tool_name, input) tuple — at a\n// scope of `anthropic:tool(name=<tool>)`.\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 an Anthropic tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AnthropicToolUse {\n /** The `id` Anthropic assigns to this tool_use block (passed back as tool_use_id on result). */\n id: string;\n /** The tool name registered in your `tools` array on messages.create. */\n name: string;\n /** The model's structured input for this tool — JSON-serializable. */\n input: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for an Anthropic tool_use. The bytes are what\n * the agent-action envelope's `content.hash` is a SHA-256 of.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"id\": <tool_use_id>,\n * \"input\": <canonical JSON of input>,\n * \"name\": <tool name>\n * }\n */\nexport function canonicalizeToolUse(t: AnthropicToolUse): Uint8Array {\n const canon = {\n id: t.id,\n input: t.input,\n name: t.name,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolUseHash(t: AnthropicToolUse): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolUse(t)));\n}\n\nexport function toolUseId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n t: AnthropicToolUse\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolUseHash(t),\n content_length: canonicalizeToolUse(t).byteLength,\n content_mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamped tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface StampToolUseInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n toolUse: AnthropicToolUse;\n /** Defaults to `anthropic:tool(name=<tool>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\n/**\n * Stamp an Anthropic tool_use without executing it. Useful for pre-\n * authorization flows or batch stamping.\n */\nexport async function stampToolUse(input: StampToolUseInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `anthropic:tool(name=${input.toolUse.name})`;\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 `stampToolUse: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolUse(input.toolUse);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolUseHash(input.toolUse), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// invokeWithStamp — call the tool AND produce the stamp around it\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface InvokeWithStampInput<T> extends StampToolUseInput {\n /** Your handler that actually runs the tool. Returns whatever the tool returns. */\n call: (toolUse: AnthropicToolUse) => Promise<T>;\n}\n\nexport interface InvokeWithStampResult<T> {\n result: T;\n action: ActionEnvelope;\n}\n\n/**\n * Stamp the tool_use first, then execute the handler. The stamped envelope\n * is returned alongside the result so the caller can ship them together —\n * e.g. as a side-channel to an audit log, or as the `_oc_agent` metadata on\n * the tool_result content block back to Claude.\n */\nexport async function invokeWithStamp<T>(\n input: InvokeWithStampInput<T>\n): Promise<InvokeWithStampResult<T>> {\n const action = await stampToolUse(input);\n const result = await input.call(input.toolUse);\n return { result, action };\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 (Node 18 LTS w/o global fetch, etc). */\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's /api/actions\n * registry. The console:\n * - re-derives the action id from canonical inputs and rejects on\n * mismatch (tamper defense)\n * - validates that the agent address matches the parent delegation's\n * agent (forgery defense)\n * - persists, fans out to Nostr (kind 30084), submits to OC Stamp,\n * and triggers any subscribed webhooks (action.registered)\n *\n * Returns the registered action's id + project_id + delegation_id.\n * Throws on non-2xx 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; keep the http_<n> reason\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\nexport interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {\n /** Console credentials. If absent, behaves like invokeWithStamp (no posting). */\n console?: ConsoleClient;\n}\n\nexport interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {\n /** Set when console is configured AND the POST succeeded. null otherwise. */\n posted: PostActionResult | null;\n}\n\n/**\n * Convenience: stamp the tool_use, execute the handler, AND post the\n * stamped envelope to console. Three roundtrips → one call. If `console`\n * is omitted, this is identical to invokeWithStamp + posted=null.\n *\n * The post happens AFTER the call so a failing post doesn't prevent the\n * tool from running. If you need pre-authorization (the post must\n * succeed before the call runs), use stampToolUse + postActionToConsole\n * + your call() in that order.\n */\nexport async function invokeWithStampAndPost<T>(\n input: InvokeWithStampAndPostInput<T>\n): Promise<InvokeWithStampAndPostResult<T>> {\n const { result, action } = await invokeWithStamp(input);\n let posted: PostActionResult | null = null;\n if (input.console) {\n try {\n posted = await postActionToConsole(action, input.console);\n } catch (err) {\n // Best-effort post — surfacing the error here would force\n // every caller to handle \"tool ran fine but post failed\",\n // which is rarely what they want. Log and continue.\n // eslint-disable-next-line no-console\n console.error('[oc-agent-anthropic] postActionToConsole failed:', err);\n }\n }\n return { result, action, posted };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["j"],"mappings":"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","file":"index.mjs","sourcesContent":["// @orangecheck/agent-anthropic — wrap Anthropic Tool Use invocations in\n// OC Agent action envelopes.\n//\n// Anthropic's Messages API surfaces tool calls as `tool_use` content\n// blocks: { type: 'tool_use', id, name, input }. This module canonicalizes\n// each tool_use, hashes it, and produces an agent-action envelope binding\n// the BIP-322-authenticated agent to the (tool_name, input) tuple — at a\n// scope of `anthropic:tool(name=<tool>)`.\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 an Anthropic tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface AnthropicToolUse {\n /** The `id` Anthropic assigns to this tool_use block (passed back as tool_use_id on result). */\n id: string;\n /** The tool name registered in your `tools` array on messages.create. */\n name: string;\n /** The model's structured input for this tool — JSON-serializable. */\n input: Record<string, unknown>;\n}\n\n/**\n * Produce the canonical bytes for an Anthropic tool_use. The bytes are what\n * the agent-action envelope's `content.hash` is a SHA-256 of.\n *\n * Shape (RFC 8785 canonical JSON, then trailing LF):\n * {\n * \"id\": <tool_use_id>,\n * \"input\": <canonical JSON of input>,\n * \"name\": <tool name>\n * }\n */\nexport function canonicalizeToolUse(t: AnthropicToolUse): Uint8Array {\n const canon = {\n id: t.id,\n input: t.input,\n name: t.name,\n };\n const str = canonicalize(canon as unknown as Parameters<typeof canonicalize>[0]);\n return new TextEncoder().encode(str + '\\n');\n}\n\nexport function toolUseHash(t: AnthropicToolUse): string {\n return 'sha256:' + hexEncode(sha256(canonicalizeToolUse(t)));\n}\n\nexport function toolUseId(\n agentAddress: string,\n signedAt: string,\n delegationId: string,\n scopeExercised: string,\n t: AnthropicToolUse\n): string {\n return computeActionId({\n address: agentAddress,\n content_hash: toolUseHash(t),\n content_length: canonicalizeToolUse(t).byteLength,\n content_mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n signed_at: signedAt,\n delegation_id: delegationId,\n scope_exercised: scopeExercised,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stamped tool_use\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface StampToolUseInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n toolUse: AnthropicToolUse;\n /** Defaults to `anthropic:tool(name=<tool>)` — the tightest admissible sub-scope. */\n scopeExercised?: string;\n signedAt?: Date;\n}\n\n/**\n * Stamp an Anthropic tool_use without executing it. Useful for pre-\n * authorization flows or batch stamping.\n */\nexport async function stampToolUse(input: StampToolUseInput): Promise<ActionEnvelope> {\n const scopeExercised =\n input.scopeExercised ?? `anthropic:tool(name=${input.toolUse.name})`;\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 `stampToolUse: scope_exercised (${scopeExercised}) is not a sub-scope of any granted scope`\n );\n }\n\n const bytes = canonicalizeToolUse(input.toolUse);\n return signAsAgent({\n agent: input.agent,\n delegation: input.delegation as never,\n content: { hash: toolUseHash(input.toolUse), length: bytes.byteLength },\n mime: 'application/vnd.oc-agent.anthropic-tool-use+json',\n scopeExercised,\n signedAt: input.signedAt,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// invokeWithStamp — call the tool AND produce the stamp around it\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface InvokeWithStampInput<T> extends StampToolUseInput {\n /** Your handler that actually runs the tool. Returns whatever the tool returns. */\n call: (toolUse: AnthropicToolUse) => Promise<T>;\n}\n\nexport interface InvokeWithStampResult<T> {\n result: T;\n action: ActionEnvelope;\n}\n\n/**\n * Stamp the tool_use first, then execute the handler. The stamped envelope\n * is returned alongside the result so the caller can ship them together —\n * e.g. as a side-channel to an audit log, or as the `_oc_agent` metadata on\n * the tool_result content block back to Claude.\n */\nexport async function invokeWithStamp<T>(\n input: InvokeWithStampInput<T>\n): Promise<InvokeWithStampResult<T>> {\n const action = await stampToolUse(input);\n const result = await input.call(input.toolUse);\n return { result, action };\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 (Node 18 LTS w/o global fetch, etc). */\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's /api/actions\n * registry. The fleet:\n * - re-derives the action id from canonical inputs and rejects on\n * mismatch (tamper defense)\n * - validates that the agent address matches the parent delegation's\n * agent (forgery defense)\n * - persists, fans out to Nostr (kind 30084), submits to OC Stamp,\n * and triggers any subscribed webhooks (action.registered)\n *\n * Returns the registered action's id + project_id + delegation_id.\n * Throws on non-2xx 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; keep the http_<n> reason\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\nexport interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {\n /** Fleet credentials. If absent, behaves like invokeWithStamp (no posting). */\n fleet?: FleetClient;\n}\n\nexport interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {\n /** Set when fleet is configured AND the POST succeeded. null otherwise. */\n posted: PostActionResult | null;\n}\n\n/**\n * Convenience: stamp the tool_use, execute the handler, AND post the\n * stamped envelope to fleet. Three roundtrips → one call. If `fleet`\n * is omitted, this is identical to invokeWithStamp + posted=null.\n *\n * The post happens AFTER the call so a failing post doesn't prevent the\n * tool from running. If you need pre-authorization (the post must\n * succeed before the call runs), use stampToolUse + postActionToFleet\n * + your call() in that order.\n */\nexport async function invokeWithStampAndPost<T>(\n input: InvokeWithStampAndPostInput<T>\n): Promise<InvokeWithStampAndPostResult<T>> {\n const { result, action } = await invokeWithStamp(input);\n let posted: PostActionResult | null = null;\n if (input.fleet) {\n try {\n posted = await postActionToFleet(action, input.fleet);\n } catch (err) {\n // Best-effort post — surfacing the error here would force\n // every caller to handle \"tool ran fine but post failed\",\n // which is rarely what they want. Log and continue.\n // eslint-disable-next-line no-console\n console.error('[oc-agent-anthropic] postActionToFleet failed:', err);\n }\n }\n return { result, action, posted };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orangecheck/agent-anthropic",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Wrap Anthropic Tool Use (Claude tool_use blocks) with OC Agent scope enforcement and emit a signed agent-action envelope per tool execution.",
5
5
  "keywords": [
6
6
  "bitcoin",
package/src/index.test.ts CHANGED
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
2
2
 
3
3
  import {
4
4
  canonicalizeToolUse,
5
- postActionToConsole,
5
+ postActionToFleet,
6
6
  toolUseHash,
7
7
  } from './index.js';
8
8
  import type { ActionEnvelope } from '@orangecheck/agent-signer';
@@ -49,7 +49,7 @@ describe('canonicalizeToolUse', () => {
49
49
  });
50
50
  });
51
51
 
52
- describe('postActionToConsole', () => {
52
+ describe('postActionToFleet', () => {
53
53
  const fakeAction: ActionEnvelope = {
54
54
  v: 1,
55
55
  kind: 'agent-action',
@@ -69,7 +69,7 @@ describe('postActionToConsole', () => {
69
69
 
70
70
  it('POSTs to /api/actions with Bearer auth + the action body fields', async () => {
71
71
  const fakeFetch = vi.fn(async (url: string | URL, init?: RequestInit) => {
72
- expect(String(url)).toBe('https://console.example/api/actions');
72
+ expect(String(url)).toBe('https://fleet.example/api/actions');
73
73
  const headers = init!.headers as Record<string, string>;
74
74
  expect(headers.Authorization).toBe('Bearer ock_xxxx');
75
75
  expect(headers['Content-Type']).toBe('application/json');
@@ -93,10 +93,10 @@ describe('postActionToConsole', () => {
93
93
  { status: 201, headers: { 'Content-Type': 'application/json' } }
94
94
  );
95
95
  });
96
- const result = await postActionToConsole(fakeAction, {
96
+ const result = await postActionToFleet(fakeAction, {
97
97
  apiToken: 'ock_xxxx',
98
98
  projectId: 'proj_test',
99
- baseUrl: 'https://console.example',
99
+ baseUrl: 'https://fleet.example',
100
100
  fetch: fakeFetch as unknown as typeof fetch,
101
101
  });
102
102
  expect(result.id).toBe(fakeAction.id);
@@ -112,10 +112,10 @@ describe('postActionToConsole', () => {
112
112
  })
113
113
  );
114
114
  await expect(
115
- postActionToConsole(fakeAction, {
115
+ postActionToFleet(fakeAction, {
116
116
  apiToken: 'ock_xxxx',
117
117
  projectId: 'proj_test',
118
- baseUrl: 'https://console.example',
118
+ baseUrl: 'https://fleet.example',
119
119
  fetch: fakeFetch as unknown as typeof fetch,
120
120
  })
121
121
  ).rejects.toThrow(/agent_must_match_delegation/);
@@ -126,18 +126,18 @@ describe('postActionToConsole', () => {
126
126
  new Response('upstream error', { status: 502, headers: { 'Content-Type': 'text/plain' } })
127
127
  );
128
128
  await expect(
129
- postActionToConsole(fakeAction, {
129
+ postActionToFleet(fakeAction, {
130
130
  apiToken: 'ock_xxxx',
131
131
  projectId: 'proj_test',
132
- baseUrl: 'https://console.example',
132
+ baseUrl: 'https://fleet.example',
133
133
  fetch: fakeFetch as unknown as typeof fetch,
134
134
  })
135
135
  ).rejects.toThrow(/http_502/);
136
136
  });
137
137
 
138
- it('defaults to https://console.ochk.io when baseUrl is omitted', async () => {
138
+ it('defaults to https://fleet.ochk.io when baseUrl is omitted', async () => {
139
139
  const fakeFetch = vi.fn(async (url: string | URL) => {
140
- expect(String(url)).toBe('https://console.ochk.io/api/actions');
140
+ expect(String(url)).toBe('https://fleet.ochk.io/api/actions');
141
141
  return new Response(
142
142
  JSON.stringify({
143
143
  ok: true,
@@ -150,7 +150,7 @@ describe('postActionToConsole', () => {
150
150
  { status: 201, headers: { 'Content-Type': 'application/json' } }
151
151
  );
152
152
  });
153
- await postActionToConsole(fakeAction, {
153
+ await postActionToFleet(fakeAction, {
154
154
  apiToken: 'ock_xxxx',
155
155
  projectId: 'proj_test',
156
156
  fetch: fakeFetch as unknown as typeof fetch,
package/src/index.ts CHANGED
@@ -147,11 +147,11 @@ export async function invokeWithStamp<T>(
147
147
  }
148
148
 
149
149
  // ─────────────────────────────────────────────────────────────────────────────
150
- // Console integration: POST stamped actions to console.ochk.io/api/actions
150
+ // Fleet integration: POST stamped actions to fleet.ochk.io/api/actions
151
151
  // ─────────────────────────────────────────────────────────────────────────────
152
152
 
153
- export interface ConsoleClient {
154
- /** Defaults to https://console.ochk.io. */
153
+ export interface FleetClient {
154
+ /** Defaults to https://fleet.ochk.io. */
155
155
  baseUrl?: string;
156
156
  /** Bearer token from /settings § 03 (`ock_<hex>`). */
157
157
  apiToken: string;
@@ -168,8 +168,8 @@ export interface PostActionResult {
168
168
  }
169
169
 
170
170
  /**
171
- * POST a stamped action envelope to console.ochk.io's /api/actions
172
- * registry. The console:
171
+ * POST a stamped action envelope to fleet.ochk.io's /api/actions
172
+ * registry. The fleet:
173
173
  * - re-derives the action id from canonical inputs and rejects on
174
174
  * mismatch (tamper defense)
175
175
  * - validates that the agent address matches the parent delegation's
@@ -180,11 +180,11 @@ export interface PostActionResult {
180
180
  * Returns the registered action's id + project_id + delegation_id.
181
181
  * Throws on non-2xx with the server's reason string.
182
182
  */
183
- export async function postActionToConsole(
183
+ export async function postActionToFleet(
184
184
  action: ActionEnvelope,
185
- client: ConsoleClient
185
+ client: FleetClient
186
186
  ): Promise<PostActionResult> {
187
- const baseUrl = client.baseUrl ?? 'https://console.ochk.io';
187
+ const baseUrl = client.baseUrl ?? 'https://fleet.ochk.io';
188
188
  const f = client.fetch ?? fetch;
189
189
  const body = {
190
190
  project_id: client.projectId,
@@ -214,30 +214,30 @@ export async function postActionToConsole(
214
214
  } catch {
215
215
  // body wasn't json; keep the http_<n> reason
216
216
  }
217
- throw new Error(`postActionToConsole failed: ${reason}`);
217
+ throw new Error(`postActionToFleet failed: ${reason}`);
218
218
  }
219
219
  const j = (await r.json()) as { ok: true; action: PostActionResult };
220
220
  return j.action;
221
221
  }
222
222
 
223
223
  export interface InvokeWithStampAndPostInput<T> extends InvokeWithStampInput<T> {
224
- /** Console credentials. If absent, behaves like invokeWithStamp (no posting). */
225
- console?: ConsoleClient;
224
+ /** Fleet credentials. If absent, behaves like invokeWithStamp (no posting). */
225
+ fleet?: FleetClient;
226
226
  }
227
227
 
228
228
  export interface InvokeWithStampAndPostResult<T> extends InvokeWithStampResult<T> {
229
- /** Set when console is configured AND the POST succeeded. null otherwise. */
229
+ /** Set when fleet is configured AND the POST succeeded. null otherwise. */
230
230
  posted: PostActionResult | null;
231
231
  }
232
232
 
233
233
  /**
234
234
  * Convenience: stamp the tool_use, execute the handler, AND post the
235
- * stamped envelope to console. Three roundtrips → one call. If `console`
235
+ * stamped envelope to fleet. Three roundtrips → one call. If `fleet`
236
236
  * is omitted, this is identical to invokeWithStamp + posted=null.
237
237
  *
238
238
  * The post happens AFTER the call so a failing post doesn't prevent the
239
239
  * tool from running. If you need pre-authorization (the post must
240
- * succeed before the call runs), use stampToolUse + postActionToConsole
240
+ * succeed before the call runs), use stampToolUse + postActionToFleet
241
241
  * + your call() in that order.
242
242
  */
243
243
  export async function invokeWithStampAndPost<T>(
@@ -245,15 +245,15 @@ export async function invokeWithStampAndPost<T>(
245
245
  ): Promise<InvokeWithStampAndPostResult<T>> {
246
246
  const { result, action } = await invokeWithStamp(input);
247
247
  let posted: PostActionResult | null = null;
248
- if (input.console) {
248
+ if (input.fleet) {
249
249
  try {
250
- posted = await postActionToConsole(action, input.console);
250
+ posted = await postActionToFleet(action, input.fleet);
251
251
  } catch (err) {
252
252
  // Best-effort post — surfacing the error here would force
253
253
  // every caller to handle "tool ran fine but post failed",
254
254
  // which is rarely what they want. Log and continue.
255
255
  // eslint-disable-next-line no-console
256
- console.error('[oc-agent-anthropic] postActionToConsole failed:', err);
256
+ console.error('[oc-agent-anthropic] postActionToFleet failed:', err);
257
257
  }
258
258
  }
259
259
  return { result, action, posted };