@tangle-network/agent-integrations 0.34.0 → 0.35.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
|
@@ -165,6 +165,9 @@ OAuth credentials.
|
|
|
165
165
|
| `runIntegrationHealthchecks` | Checks connection status, registry executability, scope shape, and optional live provider tests. |
|
|
166
166
|
| `receiveIntegrationWebhook` | Verifies inbound webhooks, dedupes provider events, and dispatches normalized trigger events. |
|
|
167
167
|
| `buildIntegrationBridgeEnvironment` | Encodes scoped sandbox capabilities for sandbox processes or executor-style CLIs. |
|
|
168
|
+
| `mintDelegatedToolToken` / `verifyDelegatedToolToken` | Signed-claims bearer (workspace + tool allow-list + TTL) for an external agent that calls back into the product's tools mid-session. |
|
|
169
|
+
| `issueDelegatedToolLease` | Standardized lease (token + allow-list + expiry + callback URL) the product hands to its external agent. |
|
|
170
|
+
| `handleDelegatedToolCall` / `handleDelegatedToolRequest` | Transport-agnostic JSON-RPC 2.0 callback handler with fail-closed gates (token fresh, tool allow-listed, integration connected) via product-supplied seams. |
|
|
168
171
|
| `createTangleIntegrationsClient` | Tiny generated-app/sandbox client for platform `/v1/integrations/invoke`. |
|
|
169
172
|
| `inferIntegrationManifestFromTools` / `validateIntegrationManifest` | Deterministic manifest helpers for Builder and platform APIs. |
|
|
170
173
|
| `renderConsentSummary` / `renderApprovalCopy` | User-facing consent and approval copy from manifests/actions. |
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Short-lived, workspace-scoped bearer for the delegated-tool bridge.
|
|
3
|
+
*
|
|
4
|
+
* An external stateful agent — a voice caller, a long-running autonomous worker
|
|
5
|
+
* — is handed one of these tokens and calls BACK into the product's tools
|
|
6
|
+
* mid-session. The token names exactly which workspace and which tool names the
|
|
7
|
+
* external agent may reach, and it EXPIRES, so a leaked lease stops working once
|
|
8
|
+
* the session window closes. The product's connector credentials never leave the
|
|
9
|
+
* product; the external agent only ever holds this opaque token and reaches the
|
|
10
|
+
* product's callback endpoint (see {@link handleDelegatedToolCall}).
|
|
11
|
+
*
|
|
12
|
+
* This is a SIGNED-CLAIMS envelope, distinct from an identity capability token
|
|
13
|
+
* (`HMAC(secret, "user:<id>")`, verified against a known id). Here the verifier
|
|
14
|
+
* RECOVERS the claims (workspaceId, allowedTools, expiresAt) from the token
|
|
15
|
+
* itself, so the bridge endpoint needs no prior knowledge of the lease.
|
|
16
|
+
*
|
|
17
|
+
* Crypto: WebCrypto HMAC-SHA256, base64url, constant-time compare. Runs on
|
|
18
|
+
* Cloudflare Workers, Node, and the browser with no Node `crypto` dependency —
|
|
19
|
+
* matching the sibling capability-token primitive. Fail-closed: with no secret,
|
|
20
|
+
* mint returns `undefined` and verify returns `null`, so the bridge is simply
|
|
21
|
+
* absent rather than silently unauthenticated.
|
|
22
|
+
*/
|
|
23
|
+
interface DelegatedToolClaims {
|
|
24
|
+
workspaceId: string;
|
|
25
|
+
allowedTools: string[];
|
|
26
|
+
/** Epoch milliseconds at which the token stops verifying. */
|
|
27
|
+
expiresAt: number;
|
|
28
|
+
}
|
|
29
|
+
interface MintDelegatedToolTokenInput {
|
|
30
|
+
workspaceId: string;
|
|
31
|
+
allowedTools: string[];
|
|
32
|
+
ttlSeconds: number;
|
|
33
|
+
/** Shared HMAC secret. When absent, mint returns `undefined` (fail-closed). */
|
|
34
|
+
secret?: string;
|
|
35
|
+
/** Token prefix (namespaces the credential; lets verify reject foreign tokens
|
|
36
|
+
* cheaply). Default `dtt_`. */
|
|
37
|
+
prefix?: string;
|
|
38
|
+
/** Override the clock (epoch ms) — for tests. Defaults to `Date.now()`. */
|
|
39
|
+
now?: number;
|
|
40
|
+
}
|
|
41
|
+
interface VerifyDelegatedToolTokenOptions {
|
|
42
|
+
secret?: string;
|
|
43
|
+
prefix?: string;
|
|
44
|
+
now?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Mint a delegated-tool token carrying signed claims, or `undefined` when no
|
|
48
|
+
* secret is configured (fail-closed — the caller refuses to issue a lease rather
|
|
49
|
+
* than hand out an unauthenticated one).
|
|
50
|
+
*/
|
|
51
|
+
declare function mintDelegatedToolToken(input: MintDelegatedToolTokenInput): Promise<string | undefined>;
|
|
52
|
+
/**
|
|
53
|
+
* Verify a delegated-tool token and recover its claims. Returns `null` (never
|
|
54
|
+
* throws) for an unconfigured secret, a wrong prefix, a malformed or forged
|
|
55
|
+
* token, or an expired one.
|
|
56
|
+
*/
|
|
57
|
+
declare function verifyDelegatedToolToken(token: string, opts: VerifyDelegatedToolTokenOptions): Promise<DelegatedToolClaims | null>;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Transport-agnostic JSON-RPC 2.0 callback handler for the delegated-tool
|
|
61
|
+
* bridge — the endpoint an EXTERNAL stateful agent calls back into mid-session,
|
|
62
|
+
* authorized by the bearer minted via {@link mintDelegatedToolToken}.
|
|
63
|
+
*
|
|
64
|
+
* The product supplies three seams; the handler bakes in no domain assumptions
|
|
65
|
+
* (no voice/phony/calendar specifics):
|
|
66
|
+
*
|
|
67
|
+
* - `verifyToken(bearer)` → claims | null — recover & validate the lease
|
|
68
|
+
* (fresh, signed). Usually {@link verifyDelegatedToolToken} bound to a secret.
|
|
69
|
+
* - `resolveTool(workspaceId, name)` → invocable | null — the product's tool
|
|
70
|
+
* registry. `null` means "this workspace cannot reach that tool right now".
|
|
71
|
+
* - `isIntegrationConnected(workspaceId, tool)` → boolean — the live
|
|
72
|
+
* connectivity gate; a stale token naming a since-disconnected integration
|
|
73
|
+
* resolves but fails this check.
|
|
74
|
+
*
|
|
75
|
+
* FAIL-CLOSED, in order, for `tools/call`: (1) bearer verifies, (2) tool is in
|
|
76
|
+
* the lease allow-list, (3) tool resolves for the workspace, (4) the backing
|
|
77
|
+
* integration is connected. Any miss returns a JSON-RPC error and the invocable
|
|
78
|
+
* is never touched.
|
|
79
|
+
*
|
|
80
|
+
* `tools/list` is advisory: it returns the intersection of the allow-list with
|
|
81
|
+
* what currently resolves + is connected, omitting (never erroring) the rest.
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
interface DelegatedToolDescriptor {
|
|
85
|
+
/** Wire name the external agent calls by. */
|
|
86
|
+
name: string;
|
|
87
|
+
description?: string;
|
|
88
|
+
/** JSON Schema for the tool arguments. Defaults to `{ type: 'object' }`. */
|
|
89
|
+
inputSchema?: unknown;
|
|
90
|
+
}
|
|
91
|
+
interface ResolvedDelegatedTool extends DelegatedToolDescriptor {
|
|
92
|
+
/**
|
|
93
|
+
* Invoke the tool with the JSON-RPC `arguments`. Returns the JSON-RPC `result`
|
|
94
|
+
* payload on success. Throw {@link DelegatedToolInvocationError} to surface a
|
|
95
|
+
* structured JSON-RPC error (code + data); any other throw becomes -32000.
|
|
96
|
+
*/
|
|
97
|
+
invoke(args: Record<string, unknown>): Promise<unknown>;
|
|
98
|
+
}
|
|
99
|
+
/** Throw from `resolveTool().invoke` to control the JSON-RPC error envelope. */
|
|
100
|
+
declare class DelegatedToolInvocationError extends Error {
|
|
101
|
+
readonly code: number;
|
|
102
|
+
readonly data?: unknown;
|
|
103
|
+
constructor(message: string, options?: {
|
|
104
|
+
code?: number;
|
|
105
|
+
data?: unknown;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
interface DelegatedToolCallSeams {
|
|
109
|
+
/** Recover lease claims from a raw bearer string, or `null` to reject. */
|
|
110
|
+
verifyToken(bearer: string): Promise<DelegatedToolClaims | null> | DelegatedToolClaims | null;
|
|
111
|
+
/** The product's tool registry. `null` ⇒ not reachable for this workspace. */
|
|
112
|
+
resolveTool(workspaceId: string, name: string): Promise<ResolvedDelegatedTool | null> | ResolvedDelegatedTool | null;
|
|
113
|
+
/** Live connectivity gate for the integration backing `tool`. */
|
|
114
|
+
isIntegrationConnected(workspaceId: string, tool: ResolvedDelegatedTool): Promise<boolean> | boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Optional advertised name/version for the JSON-RPC `initialize` handshake.
|
|
117
|
+
* Defaults to `{ name: 'delegated-tools', version: '1' }`.
|
|
118
|
+
*/
|
|
119
|
+
serverInfo?: {
|
|
120
|
+
name: string;
|
|
121
|
+
version: string;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
interface JsonRpcRequest {
|
|
125
|
+
jsonrpc?: unknown;
|
|
126
|
+
id?: unknown;
|
|
127
|
+
method?: unknown;
|
|
128
|
+
params?: unknown;
|
|
129
|
+
}
|
|
130
|
+
interface JsonRpcResponse {
|
|
131
|
+
jsonrpc: '2.0';
|
|
132
|
+
id: string | number | null;
|
|
133
|
+
result?: unknown;
|
|
134
|
+
error?: {
|
|
135
|
+
code: number;
|
|
136
|
+
message: string;
|
|
137
|
+
data?: unknown;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Handle one JSON-RPC call. Accepts a parsed body + the raw `authorization`
|
|
142
|
+
* header value. Returns the JSON-RPC response object (the transport wrapper —
|
|
143
|
+
* {@link handleDelegatedToolRequest} — turns it into an HTTP `Response`).
|
|
144
|
+
*/
|
|
145
|
+
declare function handleDelegatedToolCall(body: JsonRpcRequest, authorization: string | null | undefined, seams: DelegatedToolCallSeams): Promise<JsonRpcResponse>;
|
|
146
|
+
/**
|
|
147
|
+
* HTTP transport wrapper around {@link handleDelegatedToolCall}: parses the
|
|
148
|
+
* request, enforces POST, maps the JSON-RPC response to a `Response`. Unauthorized
|
|
149
|
+
* is the only non-200 status (401) so an unauthenticated probe can't distinguish
|
|
150
|
+
* methods; every authenticated JSON-RPC error rides a 200 per the JSON-RPC contract.
|
|
151
|
+
*/
|
|
152
|
+
declare function handleDelegatedToolRequest(request: Request, seams: DelegatedToolCallSeams): Promise<Response>;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Standardized lease payload the product hands to its external agent.
|
|
156
|
+
*
|
|
157
|
+
* The product resolves which tools a workspace may delegate right now, mints a
|
|
158
|
+
* scoped token over exactly those names ({@link mintDelegatedToolToken}), and
|
|
159
|
+
* packages the result as a lease. The external agent (or the broker that builds
|
|
160
|
+
* its session) reads `callbackUrl` + `token` to reach the product's
|
|
161
|
+
* {@link handleDelegatedToolRequest} endpoint mid-session.
|
|
162
|
+
*
|
|
163
|
+
* Standardizing the shape here means every caller's lease looks the same on the
|
|
164
|
+
* wire regardless of the external runtime (voice broker, autonomous worker).
|
|
165
|
+
*/
|
|
166
|
+
interface IssueDelegatedToolLeaseInput {
|
|
167
|
+
workspaceId: string;
|
|
168
|
+
allowedTools: string[];
|
|
169
|
+
ttlSeconds: number;
|
|
170
|
+
/** Shared HMAC secret for the token. Absent ⇒ lease cannot be issued. */
|
|
171
|
+
secret?: string;
|
|
172
|
+
/** Token prefix; forwarded to {@link mintDelegatedToolToken}. */
|
|
173
|
+
prefix?: string;
|
|
174
|
+
/** Endpoint the external agent calls back into. Echoed onto the lease. */
|
|
175
|
+
callbackUrl?: string;
|
|
176
|
+
/** Override the clock (epoch ms) — for tests. */
|
|
177
|
+
now?: number;
|
|
178
|
+
}
|
|
179
|
+
interface DelegatedToolLease {
|
|
180
|
+
token: string;
|
|
181
|
+
allowedTools: string[];
|
|
182
|
+
/** Epoch milliseconds at which the lease (and its token) expires. */
|
|
183
|
+
expiresAt: number;
|
|
184
|
+
callbackUrl?: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Issue a delegated-tool lease, or `null` when no secret is configured
|
|
188
|
+
* (fail-closed — the product refuses to hand out an unauthenticated lease).
|
|
189
|
+
* Pass an already-filtered `allowedTools`: this helper signs whatever it is
|
|
190
|
+
* given, so the product MUST intersect against what the workspace can delegate
|
|
191
|
+
* before calling.
|
|
192
|
+
*/
|
|
193
|
+
declare function issueDelegatedToolLease(input: IssueDelegatedToolLeaseInput): Promise<DelegatedToolLease | null>;
|
|
194
|
+
|
|
195
|
+
export { type DelegatedToolCallSeams, type DelegatedToolClaims, type DelegatedToolDescriptor, DelegatedToolInvocationError, type DelegatedToolLease, type IssueDelegatedToolLeaseInput, type JsonRpcRequest, type JsonRpcResponse, type MintDelegatedToolTokenInput, type ResolvedDelegatedTool, type VerifyDelegatedToolTokenOptions, handleDelegatedToolCall, handleDelegatedToolRequest, issueDelegatedToolLease, mintDelegatedToolToken, verifyDelegatedToolToken };
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import "../chunk-PZ5AY32C.js";
|
|
2
|
+
|
|
3
|
+
// src/delegated-tools/token.ts
|
|
4
|
+
var DEFAULT_PREFIX = "dtt_";
|
|
5
|
+
function base64urlEncode(input) {
|
|
6
|
+
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
7
|
+
let binary = "";
|
|
8
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
9
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
10
|
+
}
|
|
11
|
+
function base64urlDecodeToString(input) {
|
|
12
|
+
try {
|
|
13
|
+
const padded = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
14
|
+
const binary = atob(padded);
|
|
15
|
+
const bytes = new Uint8Array(binary.length);
|
|
16
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
17
|
+
return new TextDecoder().decode(bytes);
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function sign(payload, secret) {
|
|
23
|
+
const enc = new TextEncoder();
|
|
24
|
+
const key = await crypto.subtle.importKey("raw", enc.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
25
|
+
const sig = await crypto.subtle.sign("HMAC", key, enc.encode(payload));
|
|
26
|
+
return base64urlEncode(new Uint8Array(sig));
|
|
27
|
+
}
|
|
28
|
+
function timingSafeEqual(a, b) {
|
|
29
|
+
if (a.length !== b.length) return false;
|
|
30
|
+
let diff = 0;
|
|
31
|
+
for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
32
|
+
return diff === 0;
|
|
33
|
+
}
|
|
34
|
+
async function mintDelegatedToolToken(input) {
|
|
35
|
+
const secret = input.secret?.trim();
|
|
36
|
+
if (!secret) return void 0;
|
|
37
|
+
const prefix = input.prefix ?? DEFAULT_PREFIX;
|
|
38
|
+
const now = input.now ?? Date.now();
|
|
39
|
+
const claims = {
|
|
40
|
+
workspaceId: input.workspaceId,
|
|
41
|
+
allowedTools: input.allowedTools,
|
|
42
|
+
expiresAt: now + input.ttlSeconds * 1e3
|
|
43
|
+
};
|
|
44
|
+
const payload = base64urlEncode(JSON.stringify(claims));
|
|
45
|
+
const signature = await sign(payload, secret);
|
|
46
|
+
return `${prefix}${payload}.${signature}`;
|
|
47
|
+
}
|
|
48
|
+
async function verifyDelegatedToolToken(token, opts) {
|
|
49
|
+
const secret = opts.secret?.trim();
|
|
50
|
+
const prefix = opts.prefix ?? DEFAULT_PREFIX;
|
|
51
|
+
if (!secret || !token.startsWith(prefix)) return null;
|
|
52
|
+
const body = token.slice(prefix.length);
|
|
53
|
+
const dot = body.indexOf(".");
|
|
54
|
+
if (dot <= 0) return null;
|
|
55
|
+
const payload = body.slice(0, dot);
|
|
56
|
+
const signature = body.slice(dot + 1);
|
|
57
|
+
if (!payload || !signature) return null;
|
|
58
|
+
const expected = await sign(payload, secret);
|
|
59
|
+
if (!timingSafeEqual(signature, expected)) return null;
|
|
60
|
+
const json = base64urlDecodeToString(payload);
|
|
61
|
+
if (json === null) return null;
|
|
62
|
+
let claims;
|
|
63
|
+
try {
|
|
64
|
+
claims = JSON.parse(json);
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (!claims || typeof claims !== "object") return null;
|
|
69
|
+
const record = claims;
|
|
70
|
+
if (typeof record.workspaceId !== "string" || !record.workspaceId) return null;
|
|
71
|
+
if (typeof record.expiresAt !== "number" || !Number.isFinite(record.expiresAt)) return null;
|
|
72
|
+
if (!Array.isArray(record.allowedTools) || !record.allowedTools.every((tool) => typeof tool === "string")) return null;
|
|
73
|
+
const now = opts.now ?? Date.now();
|
|
74
|
+
if (record.expiresAt <= now) return null;
|
|
75
|
+
return {
|
|
76
|
+
workspaceId: record.workspaceId,
|
|
77
|
+
allowedTools: record.allowedTools,
|
|
78
|
+
expiresAt: record.expiresAt
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/delegated-tools/handler.ts
|
|
83
|
+
var DelegatedToolInvocationError = class extends Error {
|
|
84
|
+
code;
|
|
85
|
+
data;
|
|
86
|
+
constructor(message, options = {}) {
|
|
87
|
+
super(message);
|
|
88
|
+
this.name = "DelegatedToolInvocationError";
|
|
89
|
+
this.code = options.code ?? -32e3;
|
|
90
|
+
this.data = options.data;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var PROTOCOL_VERSION = "2024-11-05";
|
|
94
|
+
function normalizeId(id) {
|
|
95
|
+
return typeof id === "string" || typeof id === "number" ? id : null;
|
|
96
|
+
}
|
|
97
|
+
function rpcResult(id, result) {
|
|
98
|
+
return { jsonrpc: "2.0", id: normalizeId(id), result };
|
|
99
|
+
}
|
|
100
|
+
function rpcError(id, code, message, data) {
|
|
101
|
+
return {
|
|
102
|
+
jsonrpc: "2.0",
|
|
103
|
+
id: normalizeId(id),
|
|
104
|
+
error: data === void 0 ? { code, message } : { code, message, data }
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function extractBearer(authorization) {
|
|
108
|
+
return authorization?.match(/^Bearer\s+(.+)$/i)?.[1];
|
|
109
|
+
}
|
|
110
|
+
async function handleDelegatedToolCall(body, authorization, seams) {
|
|
111
|
+
const id = body.id ?? null;
|
|
112
|
+
const method = typeof body.method === "string" ? body.method : "";
|
|
113
|
+
const bearer = extractBearer(authorization);
|
|
114
|
+
const claims = bearer ? await seams.verifyToken(bearer) : null;
|
|
115
|
+
if (!claims) return rpcError(id, -32001, "Unauthorized");
|
|
116
|
+
if (method === "initialize") {
|
|
117
|
+
const info = seams.serverInfo ?? { name: "delegated-tools", version: "1" };
|
|
118
|
+
return rpcResult(id, {
|
|
119
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
120
|
+
capabilities: { tools: {} },
|
|
121
|
+
serverInfo: info
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (method === "tools/list") {
|
|
125
|
+
const tools = [];
|
|
126
|
+
for (const name of claims.allowedTools) {
|
|
127
|
+
const tool = await seams.resolveTool(claims.workspaceId, name);
|
|
128
|
+
if (!tool) continue;
|
|
129
|
+
if (!await seams.isIntegrationConnected(claims.workspaceId, tool)) continue;
|
|
130
|
+
tools.push({
|
|
131
|
+
name: tool.name,
|
|
132
|
+
description: tool.description,
|
|
133
|
+
inputSchema: tool.inputSchema ?? { type: "object" }
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return rpcResult(id, { tools });
|
|
137
|
+
}
|
|
138
|
+
if (method === "tools/call") {
|
|
139
|
+
const params = body.params ?? {};
|
|
140
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
141
|
+
const args = params.arguments && typeof params.arguments === "object" && !Array.isArray(params.arguments) ? params.arguments : {};
|
|
142
|
+
if (!name) return rpcError(id, -32602, "Missing tool name");
|
|
143
|
+
if (!claims.allowedTools.includes(name)) {
|
|
144
|
+
return rpcError(id, -32602, `Tool not delegated to this session: ${name}`);
|
|
145
|
+
}
|
|
146
|
+
const tool = await seams.resolveTool(claims.workspaceId, name);
|
|
147
|
+
if (!tool) return rpcError(id, -32602, `Tool not available for workspace: ${name}`);
|
|
148
|
+
if (!await seams.isIntegrationConnected(claims.workspaceId, tool)) {
|
|
149
|
+
return rpcError(id, -32602, `Integration not connected for tool: ${name}`);
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const result = await tool.invoke(args);
|
|
153
|
+
return rpcResult(id, result);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (err instanceof DelegatedToolInvocationError) {
|
|
156
|
+
return rpcError(id, err.code, err.message, err.data);
|
|
157
|
+
}
|
|
158
|
+
return rpcError(id, -32e3, err instanceof Error ? err.message : "Tool invocation failed");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return rpcError(id, -32601, `Method not found: ${method || "(none)"}`);
|
|
162
|
+
}
|
|
163
|
+
async function handleDelegatedToolRequest(request, seams) {
|
|
164
|
+
if (request.method !== "POST") {
|
|
165
|
+
return Response.json({ error: "Method not allowed" }, { status: 405 });
|
|
166
|
+
}
|
|
167
|
+
let body;
|
|
168
|
+
try {
|
|
169
|
+
body = await request.json();
|
|
170
|
+
} catch {
|
|
171
|
+
return Response.json(rpcError(null, -32700, "Parse error"));
|
|
172
|
+
}
|
|
173
|
+
const response = await handleDelegatedToolCall(body, request.headers.get("authorization"), seams);
|
|
174
|
+
if (response.error?.code === -32001) {
|
|
175
|
+
return Response.json(response, { status: 401 });
|
|
176
|
+
}
|
|
177
|
+
return Response.json(response);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/delegated-tools/lease.ts
|
|
181
|
+
async function issueDelegatedToolLease(input) {
|
|
182
|
+
const now = input.now ?? Date.now();
|
|
183
|
+
const token = await mintDelegatedToolToken({
|
|
184
|
+
workspaceId: input.workspaceId,
|
|
185
|
+
allowedTools: input.allowedTools,
|
|
186
|
+
ttlSeconds: input.ttlSeconds,
|
|
187
|
+
secret: input.secret,
|
|
188
|
+
prefix: input.prefix,
|
|
189
|
+
now
|
|
190
|
+
});
|
|
191
|
+
if (!token) return null;
|
|
192
|
+
return {
|
|
193
|
+
token,
|
|
194
|
+
allowedTools: input.allowedTools,
|
|
195
|
+
expiresAt: now + input.ttlSeconds * 1e3,
|
|
196
|
+
callbackUrl: input.callbackUrl
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
export {
|
|
200
|
+
DelegatedToolInvocationError,
|
|
201
|
+
handleDelegatedToolCall,
|
|
202
|
+
handleDelegatedToolRequest,
|
|
203
|
+
issueDelegatedToolLease,
|
|
204
|
+
mintDelegatedToolToken,
|
|
205
|
+
verifyDelegatedToolToken
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/delegated-tools/token.ts","../../src/delegated-tools/handler.ts","../../src/delegated-tools/lease.ts"],"sourcesContent":["/**\n * Short-lived, workspace-scoped bearer for the delegated-tool bridge.\n *\n * An external stateful agent — a voice caller, a long-running autonomous worker\n * — is handed one of these tokens and calls BACK into the product's tools\n * mid-session. The token names exactly which workspace and which tool names the\n * external agent may reach, and it EXPIRES, so a leaked lease stops working once\n * the session window closes. The product's connector credentials never leave the\n * product; the external agent only ever holds this opaque token and reaches the\n * product's callback endpoint (see {@link handleDelegatedToolCall}).\n *\n * This is a SIGNED-CLAIMS envelope, distinct from an identity capability token\n * (`HMAC(secret, \"user:<id>\")`, verified against a known id). Here the verifier\n * RECOVERS the claims (workspaceId, allowedTools, expiresAt) from the token\n * itself, so the bridge endpoint needs no prior knowledge of the lease.\n *\n * Crypto: WebCrypto HMAC-SHA256, base64url, constant-time compare. Runs on\n * Cloudflare Workers, Node, and the browser with no Node `crypto` dependency —\n * matching the sibling capability-token primitive. Fail-closed: with no secret,\n * mint returns `undefined` and verify returns `null`, so the bridge is simply\n * absent rather than silently unauthenticated.\n */\n\nconst DEFAULT_PREFIX = 'dtt_'\n\nexport interface DelegatedToolClaims {\n workspaceId: string\n allowedTools: string[]\n /** Epoch milliseconds at which the token stops verifying. */\n expiresAt: number\n}\n\nexport interface MintDelegatedToolTokenInput {\n workspaceId: string\n allowedTools: string[]\n ttlSeconds: number\n /** Shared HMAC secret. When absent, mint returns `undefined` (fail-closed). */\n secret?: string\n /** Token prefix (namespaces the credential; lets verify reject foreign tokens\n * cheaply). Default `dtt_`. */\n prefix?: string\n /** Override the clock (epoch ms) — for tests. Defaults to `Date.now()`. */\n now?: number\n}\n\nexport interface VerifyDelegatedToolTokenOptions {\n secret?: string\n prefix?: string\n now?: number\n}\n\nfunction base64urlEncode(input: string | Uint8Array): string {\n const bytes = typeof input === 'string' ? new TextEncoder().encode(input) : input\n let binary = ''\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction base64urlDecodeToString(input: string): string | null {\n try {\n const padded = input.replace(/-/g, '+').replace(/_/g, '/')\n const binary = atob(padded)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n return new TextDecoder().decode(bytes)\n } catch {\n return null\n }\n}\n\nasync function sign(payload: string, secret: string): Promise<string> {\n const enc = new TextEncoder()\n const key = await crypto.subtle.importKey('raw', enc.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'])\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(payload))\n return base64urlEncode(new Uint8Array(sig))\n}\n\n/** Length-independent-leak-free compare for two same-charset strings. */\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false\n let diff = 0\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i)\n return diff === 0\n}\n\n/**\n * Mint a delegated-tool token carrying signed claims, or `undefined` when no\n * secret is configured (fail-closed — the caller refuses to issue a lease rather\n * than hand out an unauthenticated one).\n */\nexport async function mintDelegatedToolToken(input: MintDelegatedToolTokenInput): Promise<string | undefined> {\n const secret = input.secret?.trim()\n if (!secret) return undefined\n const prefix = input.prefix ?? DEFAULT_PREFIX\n const now = input.now ?? Date.now()\n const claims: DelegatedToolClaims = {\n workspaceId: input.workspaceId,\n allowedTools: input.allowedTools,\n expiresAt: now + input.ttlSeconds * 1000,\n }\n const payload = base64urlEncode(JSON.stringify(claims))\n const signature = await sign(payload, secret)\n return `${prefix}${payload}.${signature}`\n}\n\n/**\n * Verify a delegated-tool token and recover its claims. Returns `null` (never\n * throws) for an unconfigured secret, a wrong prefix, a malformed or forged\n * token, or an expired one.\n */\nexport async function verifyDelegatedToolToken(\n token: string,\n opts: VerifyDelegatedToolTokenOptions,\n): Promise<DelegatedToolClaims | null> {\n const secret = opts.secret?.trim()\n const prefix = opts.prefix ?? DEFAULT_PREFIX\n if (!secret || !token.startsWith(prefix)) return null\n const body = token.slice(prefix.length)\n const dot = body.indexOf('.')\n if (dot <= 0) return null\n const payload = body.slice(0, dot)\n const signature = body.slice(dot + 1)\n if (!payload || !signature) return null\n\n const expected = await sign(payload, secret)\n if (!timingSafeEqual(signature, expected)) return null\n\n const json = base64urlDecodeToString(payload)\n if (json === null) return null\n\n let claims: unknown\n try {\n claims = JSON.parse(json)\n } catch {\n return null\n }\n if (!claims || typeof claims !== 'object') return null\n const record = claims as Record<string, unknown>\n if (typeof record.workspaceId !== 'string' || !record.workspaceId) return null\n if (typeof record.expiresAt !== 'number' || !Number.isFinite(record.expiresAt)) return null\n if (!Array.isArray(record.allowedTools) || !record.allowedTools.every((tool) => typeof tool === 'string')) return null\n\n const now = opts.now ?? Date.now()\n if (record.expiresAt <= now) return null\n\n return {\n workspaceId: record.workspaceId,\n allowedTools: record.allowedTools as string[],\n expiresAt: record.expiresAt,\n }\n}\n","/**\n * Transport-agnostic JSON-RPC 2.0 callback handler for the delegated-tool\n * bridge — the endpoint an EXTERNAL stateful agent calls back into mid-session,\n * authorized by the bearer minted via {@link mintDelegatedToolToken}.\n *\n * The product supplies three seams; the handler bakes in no domain assumptions\n * (no voice/phony/calendar specifics):\n *\n * - `verifyToken(bearer)` → claims | null — recover & validate the lease\n * (fresh, signed). Usually {@link verifyDelegatedToolToken} bound to a secret.\n * - `resolveTool(workspaceId, name)` → invocable | null — the product's tool\n * registry. `null` means \"this workspace cannot reach that tool right now\".\n * - `isIntegrationConnected(workspaceId, tool)` → boolean — the live\n * connectivity gate; a stale token naming a since-disconnected integration\n * resolves but fails this check.\n *\n * FAIL-CLOSED, in order, for `tools/call`: (1) bearer verifies, (2) tool is in\n * the lease allow-list, (3) tool resolves for the workspace, (4) the backing\n * integration is connected. Any miss returns a JSON-RPC error and the invocable\n * is never touched.\n *\n * `tools/list` is advisory: it returns the intersection of the allow-list with\n * what currently resolves + is connected, omitting (never erroring) the rest.\n */\n\nimport type { DelegatedToolClaims } from './token.js'\n\nexport interface DelegatedToolDescriptor {\n /** Wire name the external agent calls by. */\n name: string\n description?: string\n /** JSON Schema for the tool arguments. Defaults to `{ type: 'object' }`. */\n inputSchema?: unknown\n}\n\nexport interface ResolvedDelegatedTool extends DelegatedToolDescriptor {\n /**\n * Invoke the tool with the JSON-RPC `arguments`. Returns the JSON-RPC `result`\n * payload on success. Throw {@link DelegatedToolInvocationError} to surface a\n * structured JSON-RPC error (code + data); any other throw becomes -32000.\n */\n invoke(args: Record<string, unknown>): Promise<unknown>\n}\n\n/** Throw from `resolveTool().invoke` to control the JSON-RPC error envelope. */\nexport class DelegatedToolInvocationError extends Error {\n readonly code: number\n readonly data?: unknown\n constructor(message: string, options: { code?: number; data?: unknown } = {}) {\n super(message)\n this.name = 'DelegatedToolInvocationError'\n this.code = options.code ?? -32000\n this.data = options.data\n }\n}\n\nexport interface DelegatedToolCallSeams {\n /** Recover lease claims from a raw bearer string, or `null` to reject. */\n verifyToken(bearer: string): Promise<DelegatedToolClaims | null> | DelegatedToolClaims | null\n /** The product's tool registry. `null` ⇒ not reachable for this workspace. */\n resolveTool(\n workspaceId: string,\n name: string,\n ): Promise<ResolvedDelegatedTool | null> | ResolvedDelegatedTool | null\n /** Live connectivity gate for the integration backing `tool`. */\n isIntegrationConnected(\n workspaceId: string,\n tool: ResolvedDelegatedTool,\n ): Promise<boolean> | boolean\n /**\n * Optional advertised name/version for the JSON-RPC `initialize` handshake.\n * Defaults to `{ name: 'delegated-tools', version: '1' }`.\n */\n serverInfo?: { name: string; version: string }\n}\n\nexport interface JsonRpcRequest {\n jsonrpc?: unknown\n id?: unknown\n method?: unknown\n params?: unknown\n}\n\nexport interface JsonRpcResponse {\n jsonrpc: '2.0'\n id: string | number | null\n result?: unknown\n error?: { code: number; message: string; data?: unknown }\n}\n\nconst PROTOCOL_VERSION = '2024-11-05'\n\nfunction normalizeId(id: unknown): string | number | null {\n return typeof id === 'string' || typeof id === 'number' ? id : null\n}\n\nfunction rpcResult(id: unknown, result: unknown): JsonRpcResponse {\n return { jsonrpc: '2.0', id: normalizeId(id), result }\n}\n\nfunction rpcError(id: unknown, code: number, message: string, data?: unknown): JsonRpcResponse {\n return {\n jsonrpc: '2.0',\n id: normalizeId(id),\n error: data === undefined ? { code, message } : { code, message, data },\n }\n}\n\nfunction extractBearer(authorization: string | null | undefined): string | undefined {\n return authorization?.match(/^Bearer\\s+(.+)$/i)?.[1]\n}\n\n/**\n * Handle one JSON-RPC call. Accepts a parsed body + the raw `authorization`\n * header value. Returns the JSON-RPC response object (the transport wrapper —\n * {@link handleDelegatedToolRequest} — turns it into an HTTP `Response`).\n */\nexport async function handleDelegatedToolCall(\n body: JsonRpcRequest,\n authorization: string | null | undefined,\n seams: DelegatedToolCallSeams,\n): Promise<JsonRpcResponse> {\n const id = body.id ?? null\n const method = typeof body.method === 'string' ? body.method : ''\n\n const bearer = extractBearer(authorization)\n const claims = bearer ? await seams.verifyToken(bearer) : null\n if (!claims) return rpcError(id, -32001, 'Unauthorized')\n\n if (method === 'initialize') {\n const info = seams.serverInfo ?? { name: 'delegated-tools', version: '1' }\n return rpcResult(id, {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: { tools: {} },\n serverInfo: info,\n })\n }\n\n if (method === 'tools/list') {\n const tools: DelegatedToolDescriptor[] = []\n for (const name of claims.allowedTools) {\n const tool = await seams.resolveTool(claims.workspaceId, name)\n if (!tool) continue\n if (!(await seams.isIntegrationConnected(claims.workspaceId, tool))) continue\n tools.push({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema ?? { type: 'object' },\n })\n }\n return rpcResult(id, { tools })\n }\n\n if (method === 'tools/call') {\n const params = (body.params ?? {}) as { name?: unknown; arguments?: unknown }\n const name = typeof params.name === 'string' ? params.name : ''\n const args =\n params.arguments && typeof params.arguments === 'object' && !Array.isArray(params.arguments)\n ? (params.arguments as Record<string, unknown>)\n : {}\n\n if (!name) return rpcError(id, -32602, 'Missing tool name')\n if (!claims.allowedTools.includes(name)) {\n return rpcError(id, -32602, `Tool not delegated to this session: ${name}`)\n }\n const tool = await seams.resolveTool(claims.workspaceId, name)\n if (!tool) return rpcError(id, -32602, `Tool not available for workspace: ${name}`)\n if (!(await seams.isIntegrationConnected(claims.workspaceId, tool))) {\n return rpcError(id, -32602, `Integration not connected for tool: ${name}`)\n }\n\n try {\n const result = await tool.invoke(args)\n return rpcResult(id, result)\n } catch (err) {\n if (err instanceof DelegatedToolInvocationError) {\n return rpcError(id, err.code, err.message, err.data)\n }\n return rpcError(id, -32000, err instanceof Error ? err.message : 'Tool invocation failed')\n }\n }\n\n return rpcError(id, -32601, `Method not found: ${method || '(none)'}`)\n}\n\n/**\n * HTTP transport wrapper around {@link handleDelegatedToolCall}: parses the\n * request, enforces POST, maps the JSON-RPC response to a `Response`. Unauthorized\n * is the only non-200 status (401) so an unauthenticated probe can't distinguish\n * methods; every authenticated JSON-RPC error rides a 200 per the JSON-RPC contract.\n */\nexport async function handleDelegatedToolRequest(\n request: Request,\n seams: DelegatedToolCallSeams,\n): Promise<Response> {\n if (request.method !== 'POST') {\n return Response.json({ error: 'Method not allowed' }, { status: 405 })\n }\n\n let body: JsonRpcRequest\n try {\n body = (await request.json()) as JsonRpcRequest\n } catch {\n return Response.json(rpcError(null, -32700, 'Parse error'))\n }\n\n const response = await handleDelegatedToolCall(body, request.headers.get('authorization'), seams)\n if (response.error?.code === -32001) {\n return Response.json(response, { status: 401 })\n }\n return Response.json(response)\n}\n","/**\n * Standardized lease payload the product hands to its external agent.\n *\n * The product resolves which tools a workspace may delegate right now, mints a\n * scoped token over exactly those names ({@link mintDelegatedToolToken}), and\n * packages the result as a lease. The external agent (or the broker that builds\n * its session) reads `callbackUrl` + `token` to reach the product's\n * {@link handleDelegatedToolRequest} endpoint mid-session.\n *\n * Standardizing the shape here means every caller's lease looks the same on the\n * wire regardless of the external runtime (voice broker, autonomous worker).\n */\n\nimport { mintDelegatedToolToken } from './token.js'\n\nexport interface IssueDelegatedToolLeaseInput {\n workspaceId: string\n allowedTools: string[]\n ttlSeconds: number\n /** Shared HMAC secret for the token. Absent ⇒ lease cannot be issued. */\n secret?: string\n /** Token prefix; forwarded to {@link mintDelegatedToolToken}. */\n prefix?: string\n /** Endpoint the external agent calls back into. Echoed onto the lease. */\n callbackUrl?: string\n /** Override the clock (epoch ms) — for tests. */\n now?: number\n}\n\nexport interface DelegatedToolLease {\n token: string\n allowedTools: string[]\n /** Epoch milliseconds at which the lease (and its token) expires. */\n expiresAt: number\n callbackUrl?: string\n}\n\n/**\n * Issue a delegated-tool lease, or `null` when no secret is configured\n * (fail-closed — the product refuses to hand out an unauthenticated lease).\n * Pass an already-filtered `allowedTools`: this helper signs whatever it is\n * given, so the product MUST intersect against what the workspace can delegate\n * before calling.\n */\nexport async function issueDelegatedToolLease(\n input: IssueDelegatedToolLeaseInput,\n): Promise<DelegatedToolLease | null> {\n const now = input.now ?? Date.now()\n const token = await mintDelegatedToolToken({\n workspaceId: input.workspaceId,\n allowedTools: input.allowedTools,\n ttlSeconds: input.ttlSeconds,\n secret: input.secret,\n prefix: input.prefix,\n now,\n })\n if (!token) return null\n return {\n token,\n allowedTools: input.allowedTools,\n expiresAt: now + input.ttlSeconds * 1000,\n callbackUrl: input.callbackUrl,\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-integrations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Vendor-neutral integration contracts and runtime helpers for sandbox and agent apps.",
|
|
5
5
|
"homepage": "https://github.com/tangle-network/agent-integrations#readme",
|
|
6
6
|
"repository": {
|
|
@@ -54,6 +54,11 @@
|
|
|
54
54
|
"import": "./dist/webhooks/index.js",
|
|
55
55
|
"default": "./dist/webhooks/index.js"
|
|
56
56
|
},
|
|
57
|
+
"./delegated-tools": {
|
|
58
|
+
"types": "./dist/delegated-tools/index.d.ts",
|
|
59
|
+
"import": "./dist/delegated-tools/index.js",
|
|
60
|
+
"default": "./dist/delegated-tools/index.js"
|
|
61
|
+
},
|
|
57
62
|
"./registry": {
|
|
58
63
|
"types": "./dist/registry.d.ts",
|
|
59
64
|
"import": "./dist/registry.js",
|