@orangecheck/agent-vercel 0.1.0 → 0.1.1
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/dist/index.d.mts +3 -13
- package/dist/index.d.ts +3 -13
- package/dist/index.js +6 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/index.ts +14 -65
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DelegationEnvelope } from '@orangecheck/agent-core';
|
|
2
2
|
import { SignerRef, ActionEnvelope } from '@orangecheck/agent-signer';
|
|
3
|
+
import { ConsoleClient, PostActionResult } from '@orangecheck/agent-console-client';
|
|
4
|
+
export { ConsoleClient, PostActionResult, postActionToConsole } from '@orangecheck/agent-console-client';
|
|
3
5
|
|
|
4
6
|
interface VercelToolCall {
|
|
5
7
|
callId: string;
|
|
@@ -39,17 +41,5 @@ interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
|
|
|
39
41
|
}>;
|
|
40
42
|
}
|
|
41
43
|
declare function ocTool<TArgs extends Record<string, unknown>, TResult>(input: OcToolInput<TArgs, TResult>): OcToolWrapped<TArgs, TResult>;
|
|
42
|
-
interface ConsoleClient {
|
|
43
|
-
baseUrl?: string;
|
|
44
|
-
apiToken: string;
|
|
45
|
-
projectId: string;
|
|
46
|
-
fetch?: typeof fetch;
|
|
47
|
-
}
|
|
48
|
-
interface PostActionResult {
|
|
49
|
-
id: string;
|
|
50
|
-
project_id: string;
|
|
51
|
-
delegation_id: string;
|
|
52
|
-
}
|
|
53
|
-
declare function postActionToConsole(action: ActionEnvelope, client: ConsoleClient): Promise<PostActionResult>;
|
|
54
44
|
|
|
55
|
-
export { type AgentContext, type
|
|
45
|
+
export { type AgentContext, type OcToolInput, type OcToolWrapped, type StampToolCallInput, type VercelToolCall, canonicalizeToolCall, ocTool, stampToolCall, toolCallActionId, toolCallHash };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DelegationEnvelope } from '@orangecheck/agent-core';
|
|
2
2
|
import { SignerRef, ActionEnvelope } from '@orangecheck/agent-signer';
|
|
3
|
+
import { ConsoleClient, PostActionResult } from '@orangecheck/agent-console-client';
|
|
4
|
+
export { ConsoleClient, PostActionResult, postActionToConsole } from '@orangecheck/agent-console-client';
|
|
3
5
|
|
|
4
6
|
interface VercelToolCall {
|
|
5
7
|
callId: string;
|
|
@@ -39,17 +41,5 @@ interface OcToolWrapped<TArgs extends Record<string, unknown>, TResult> {
|
|
|
39
41
|
}>;
|
|
40
42
|
}
|
|
41
43
|
declare function ocTool<TArgs extends Record<string, unknown>, TResult>(input: OcToolInput<TArgs, TResult>): OcToolWrapped<TArgs, TResult>;
|
|
42
|
-
interface ConsoleClient {
|
|
43
|
-
baseUrl?: string;
|
|
44
|
-
apiToken: string;
|
|
45
|
-
projectId: string;
|
|
46
|
-
fetch?: typeof fetch;
|
|
47
|
-
}
|
|
48
|
-
interface PostActionResult {
|
|
49
|
-
id: string;
|
|
50
|
-
project_id: string;
|
|
51
|
-
delegation_id: string;
|
|
52
|
-
}
|
|
53
|
-
declare function postActionToConsole(action: ActionEnvelope, client: ConsoleClient): Promise<PostActionResult>;
|
|
54
44
|
|
|
55
|
-
export { type AgentContext, type
|
|
45
|
+
export { type AgentContext, type OcToolInput, type OcToolWrapped, type StampToolCallInput, type VercelToolCall, canonicalizeToolCall, ocTool, stampToolCall, toolCallActionId, toolCallHash };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var sha256 = require('@noble/hashes/sha256');
|
|
4
4
|
var agentCore = require('@orangecheck/agent-core');
|
|
5
5
|
var agentSigner = require('@orangecheck/agent-signer');
|
|
6
|
+
var agentConsoleClient = require('@orangecheck/agent-console-client');
|
|
6
7
|
|
|
7
8
|
// src/index.ts
|
|
8
9
|
function canonicalizeToolCall(c) {
|
|
@@ -67,7 +68,7 @@ function ocTool(input) {
|
|
|
67
68
|
let posted = null;
|
|
68
69
|
if (ctx.console) {
|
|
69
70
|
try {
|
|
70
|
-
posted = await postActionToConsole(action, ctx.console);
|
|
71
|
+
posted = await agentConsoleClient.postActionToConsole(action, ctx.console);
|
|
71
72
|
} catch (err) {
|
|
72
73
|
console.error("[oc-agent-vercel] postActionToConsole failed:", err);
|
|
73
74
|
}
|
|
@@ -76,45 +77,13 @@ function ocTool(input) {
|
|
|
76
77
|
}
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
|
-
async function postActionToConsole(action, client) {
|
|
80
|
-
const baseUrl = client.baseUrl ?? "https://console.ochk.io";
|
|
81
|
-
const f = client.fetch ?? fetch;
|
|
82
|
-
const body = {
|
|
83
|
-
project_id: client.projectId,
|
|
84
|
-
delegation_id: action.delegation_id,
|
|
85
|
-
agent_address: action.signer.address,
|
|
86
|
-
scope_exercised: action.scope_exercised,
|
|
87
|
-
content_hash: action.content.hash,
|
|
88
|
-
content_length: action.content.length,
|
|
89
|
-
content_mime: action.content.mime,
|
|
90
|
-
signed_at: action.signed_at,
|
|
91
|
-
signature: action.sig.value,
|
|
92
|
-
id: action.id
|
|
93
|
-
};
|
|
94
|
-
const r = await f(`${baseUrl}/api/actions`, {
|
|
95
|
-
method: "POST",
|
|
96
|
-
headers: {
|
|
97
|
-
"Content-Type": "application/json",
|
|
98
|
-
Authorization: `Bearer ${client.apiToken}`
|
|
99
|
-
},
|
|
100
|
-
body: JSON.stringify(body)
|
|
101
|
-
});
|
|
102
|
-
if (!r.ok) {
|
|
103
|
-
let reason = `http_${r.status}`;
|
|
104
|
-
try {
|
|
105
|
-
const j2 = await r.json();
|
|
106
|
-
if (j2.reason) reason = j2.reason;
|
|
107
|
-
} catch {
|
|
108
|
-
}
|
|
109
|
-
throw new Error(`postActionToConsole failed: ${reason}`);
|
|
110
|
-
}
|
|
111
|
-
const j = await r.json();
|
|
112
|
-
return j.action;
|
|
113
|
-
}
|
|
114
80
|
|
|
81
|
+
Object.defineProperty(exports, "postActionToConsole", {
|
|
82
|
+
enumerable: true,
|
|
83
|
+
get: function () { return agentConsoleClient.postActionToConsole; }
|
|
84
|
+
});
|
|
115
85
|
exports.canonicalizeToolCall = canonicalizeToolCall;
|
|
116
86
|
exports.ocTool = ocTool;
|
|
117
|
-
exports.postActionToConsole = postActionToConsole;
|
|
118
87
|
exports.stampToolCall = stampToolCall;
|
|
119
88
|
exports.toolCallActionId = toolCallActionId;
|
|
120
89
|
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","_post"],"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';\nimport {\n postActionToConsole as _post,\n type ConsoleClient,\n type PostActionResult,\n} from '@orangecheck/agent-console-client';\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 _post(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 — re-export from the shared client. The local OcTool\n// surface above references ConsoleClient + PostActionResult, so we also\n// pull them into module scope (re-exporting alone doesn't expose the names).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport {\n postActionToConsole,\n type ConsoleClient,\n type PostActionResult,\n} from '@orangecheck/agent-console-client';\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { sha256 } from '@noble/hashes/sha256';
|
|
2
2
|
import { canonicalize, hexEncode, computeActionId, parseScope, isSubScope } from '@orangecheck/agent-core';
|
|
3
3
|
import { signAsAgent } from '@orangecheck/agent-signer';
|
|
4
|
+
import { postActionToConsole } from '@orangecheck/agent-console-client';
|
|
5
|
+
export { postActionToConsole } from '@orangecheck/agent-console-client';
|
|
4
6
|
|
|
5
7
|
// src/index.ts
|
|
6
8
|
function canonicalizeToolCall(c) {
|
|
@@ -74,42 +76,7 @@ function ocTool(input) {
|
|
|
74
76
|
}
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
|
-
async function postActionToConsole(action, client) {
|
|
78
|
-
const baseUrl = client.baseUrl ?? "https://console.ochk.io";
|
|
79
|
-
const f = client.fetch ?? fetch;
|
|
80
|
-
const body = {
|
|
81
|
-
project_id: client.projectId,
|
|
82
|
-
delegation_id: action.delegation_id,
|
|
83
|
-
agent_address: action.signer.address,
|
|
84
|
-
scope_exercised: action.scope_exercised,
|
|
85
|
-
content_hash: action.content.hash,
|
|
86
|
-
content_length: action.content.length,
|
|
87
|
-
content_mime: action.content.mime,
|
|
88
|
-
signed_at: action.signed_at,
|
|
89
|
-
signature: action.sig.value,
|
|
90
|
-
id: action.id
|
|
91
|
-
};
|
|
92
|
-
const r = await f(`${baseUrl}/api/actions`, {
|
|
93
|
-
method: "POST",
|
|
94
|
-
headers: {
|
|
95
|
-
"Content-Type": "application/json",
|
|
96
|
-
Authorization: `Bearer ${client.apiToken}`
|
|
97
|
-
},
|
|
98
|
-
body: JSON.stringify(body)
|
|
99
|
-
});
|
|
100
|
-
if (!r.ok) {
|
|
101
|
-
let reason = `http_${r.status}`;
|
|
102
|
-
try {
|
|
103
|
-
const j2 = await r.json();
|
|
104
|
-
if (j2.reason) reason = j2.reason;
|
|
105
|
-
} catch {
|
|
106
|
-
}
|
|
107
|
-
throw new Error(`postActionToConsole failed: ${reason}`);
|
|
108
|
-
}
|
|
109
|
-
const j = await r.json();
|
|
110
|
-
return j.action;
|
|
111
|
-
}
|
|
112
79
|
|
|
113
|
-
export { canonicalizeToolCall, ocTool,
|
|
80
|
+
export { canonicalizeToolCall, ocTool, stampToolCall, toolCallActionId, toolCallHash };
|
|
114
81
|
//# sourceMappingURL=index.mjs.map
|
|
115
82
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,OAAA,EAAS;AACb,QAAA,IAAI;AACA,UAAA,MAAA,GAAS,MAAM,mBAAA,CAAoB,MAAA,EAAQ,GAAA,CAAI,OAAO,CAAA;AAAA,QAC1D,SAAS,GAAA,EAAK;AAEV,UAAA,OAAA,CAAQ,KAAA,CAAM,iDAAiD,GAAG,CAAA;AAAA,QACtE;AAAA,MACJ;AACA,MAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO;AAAA,IACpC;AAAA,GACJ;AACJ;AA8BA,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,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,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","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":["_post"],"mappings":";;;;;;;AAmEO,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,OAAA,EAAS;AACb,QAAA,IAAI;AACA,UAAA,MAAA,GAAS,MAAMA,mBAAA,CAAM,MAAA,EAAQ,GAAA,CAAI,OAAO,CAAA;AAAA,QAC5C,SAAS,GAAA,EAAK;AAEV,UAAA,OAAA,CAAQ,KAAA,CAAM,iDAAiD,GAAG,CAAA;AAAA,QACtE;AAAA,MACJ;AACA,MAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO;AAAA,IACpC;AAAA,GACJ;AACJ","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';\nimport {\n postActionToConsole as _post,\n type ConsoleClient,\n type PostActionResult,\n} from '@orangecheck/agent-console-client';\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 _post(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 — re-export from the shared client. The local OcTool\n// surface above references ConsoleClient + PostActionResult, so we also\n// pull them into module scope (re-exporting alone doesn't expose the names).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport {\n postActionToConsole,\n type ConsoleClient,\n type PostActionResult,\n} from '@orangecheck/agent-console-client';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangecheck/agent-vercel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
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",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@noble/hashes": "^1.5.0",
|
|
54
|
+
"@orangecheck/agent-console-client": "0.1.0",
|
|
54
55
|
"@orangecheck/agent-core": "^0.3.0",
|
|
55
56
|
"@orangecheck/agent-signer": "^0.1.0"
|
|
56
57
|
},
|
package/src/index.ts
CHANGED
|
@@ -36,6 +36,11 @@ import {
|
|
|
36
36
|
type ActionEnvelope,
|
|
37
37
|
type SignerRef,
|
|
38
38
|
} from '@orangecheck/agent-signer';
|
|
39
|
+
import {
|
|
40
|
+
postActionToConsole as _post,
|
|
41
|
+
type ConsoleClient,
|
|
42
|
+
type PostActionResult,
|
|
43
|
+
} from '@orangecheck/agent-console-client';
|
|
39
44
|
|
|
40
45
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
41
46
|
// Canonicalization of a tool call
|
|
@@ -218,7 +223,7 @@ export function ocTool<TArgs extends Record<string, unknown>, TResult>(
|
|
|
218
223
|
let posted: PostActionResult | null = null;
|
|
219
224
|
if (ctx.console) {
|
|
220
225
|
try {
|
|
221
|
-
posted = await
|
|
226
|
+
posted = await _post(action, ctx.console);
|
|
222
227
|
} catch (err) {
|
|
223
228
|
// eslint-disable-next-line no-console
|
|
224
229
|
console.error('[oc-agent-vercel] postActionToConsole failed:', err);
|
|
@@ -230,69 +235,13 @@ export function ocTool<TArgs extends Record<string, unknown>, TResult>(
|
|
|
230
235
|
}
|
|
231
236
|
|
|
232
237
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
233
|
-
// Console integration
|
|
238
|
+
// Console integration — re-export from the shared client. The local OcTool
|
|
239
|
+
// surface above references ConsoleClient + PostActionResult, so we also
|
|
240
|
+
// pull them into module scope (re-exporting alone doesn't expose the names).
|
|
234
241
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
235
242
|
|
|
236
|
-
export
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
/** Project the action belongs to (proj_*). */
|
|
242
|
-
projectId: string;
|
|
243
|
-
/** Optional fetch override for runtimes that need it. */
|
|
244
|
-
fetch?: typeof fetch;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export interface PostActionResult {
|
|
248
|
-
id: string;
|
|
249
|
-
project_id: string;
|
|
250
|
-
delegation_id: string;
|
|
251
|
-
}
|
|
252
|
-
|
|
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-
|
|
256
|
-
* delegation, persists, fans out to Nostr (kind 30084), submits to
|
|
257
|
-
* OC Stamp, and triggers any subscribed webhooks. Throws on non-2xx
|
|
258
|
-
* with the server's reason string.
|
|
259
|
-
*/
|
|
260
|
-
export async function postActionToConsole(
|
|
261
|
-
action: ActionEnvelope,
|
|
262
|
-
client: ConsoleClient
|
|
263
|
-
): Promise<PostActionResult> {
|
|
264
|
-
const baseUrl = client.baseUrl ?? 'https://console.ochk.io';
|
|
265
|
-
const f = client.fetch ?? fetch;
|
|
266
|
-
const body = {
|
|
267
|
-
project_id: client.projectId,
|
|
268
|
-
delegation_id: action.delegation_id,
|
|
269
|
-
agent_address: action.signer.address,
|
|
270
|
-
scope_exercised: action.scope_exercised,
|
|
271
|
-
content_hash: action.content.hash,
|
|
272
|
-
content_length: action.content.length,
|
|
273
|
-
content_mime: action.content.mime,
|
|
274
|
-
signed_at: action.signed_at,
|
|
275
|
-
signature: action.sig.value,
|
|
276
|
-
id: action.id,
|
|
277
|
-
};
|
|
278
|
-
const r = await f(`${baseUrl}/api/actions`, {
|
|
279
|
-
method: 'POST',
|
|
280
|
-
headers: {
|
|
281
|
-
'Content-Type': 'application/json',
|
|
282
|
-
Authorization: `Bearer ${client.apiToken}`,
|
|
283
|
-
},
|
|
284
|
-
body: JSON.stringify(body),
|
|
285
|
-
});
|
|
286
|
-
if (!r.ok) {
|
|
287
|
-
let reason = `http_${r.status}`;
|
|
288
|
-
try {
|
|
289
|
-
const j = (await r.json()) as { reason?: string };
|
|
290
|
-
if (j.reason) reason = j.reason;
|
|
291
|
-
} catch {
|
|
292
|
-
// body wasn't json
|
|
293
|
-
}
|
|
294
|
-
throw new Error(`postActionToConsole failed: ${reason}`);
|
|
295
|
-
}
|
|
296
|
-
const j = (await r.json()) as { ok: true; action: PostActionResult };
|
|
297
|
-
return j.action;
|
|
298
|
-
}
|
|
243
|
+
export {
|
|
244
|
+
postActionToConsole,
|
|
245
|
+
type ConsoleClient,
|
|
246
|
+
type PostActionResult,
|
|
247
|
+
} from '@orangecheck/agent-console-client';
|