@tangle-network/agent-app 0.49.32 → 0.49.33
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.
|
@@ -37,22 +37,15 @@ export interface ParsedIntegrationAction {
|
|
|
37
37
|
* elsewhere instead of misrouting them to the hub.
|
|
38
38
|
*/
|
|
39
39
|
export declare function resolveIntegrationAction(toolName: string): ParsedIntegrationAction | undefined;
|
|
40
|
-
/**
|
|
41
|
-
* credentials, resolves the connection from the bearer principal, evaluates
|
|
42
|
-
* per-action policy (read → allow, write/destructive → approval), and runs the
|
|
43
|
-
* action server-side. Never throws on a policy block — a gated write is a
|
|
44
|
-
* normal `succeeded: false` outcome. */
|
|
40
|
+
/** Product outcome adapter over the published Hub transport. Never grants approval. */
|
|
45
41
|
export declare class HubExecClient {
|
|
46
|
-
private readonly
|
|
47
|
-
private readonly bearer;
|
|
48
|
-
private readonly fetchImpl;
|
|
42
|
+
private readonly hub;
|
|
49
43
|
constructor(options: HubExecClientOptions);
|
|
50
44
|
exec(input: {
|
|
51
45
|
path: string;
|
|
52
46
|
actionInput?: unknown;
|
|
53
47
|
connectionId?: string;
|
|
54
48
|
}): Promise<HubExecResult>;
|
|
55
|
-
private readEnvelope;
|
|
56
49
|
}
|
|
57
50
|
/** Define input parameters for invoking a hub tool with user ID, tool name, and optional arguments */
|
|
58
51
|
export interface HubInvokeInput {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/integrations/index.ts
|
|
2
|
+
import { HubClient, HubSdkError } from "@tangle-network/hub-sdk";
|
|
2
3
|
import { parseIntegrationToolName } from "@tangle-network/agent-integrations/catalog";
|
|
3
4
|
function resolveIntegrationAction(toolName) {
|
|
4
5
|
let parsed;
|
|
@@ -11,43 +12,26 @@ function resolveIntegrationAction(toolName) {
|
|
|
11
12
|
return { ...parsed, path: `${parsed.providerId}.${parsed.connectorId}.${parsed.actionId}` };
|
|
12
13
|
}
|
|
13
14
|
var HubExecClient = class {
|
|
14
|
-
|
|
15
|
-
bearer;
|
|
16
|
-
fetchImpl;
|
|
15
|
+
hub;
|
|
17
16
|
constructor(options) {
|
|
18
17
|
if (!options.baseUrl) throw new Error("HubExecClient: baseUrl is required");
|
|
19
18
|
if (!options.bearer) throw new Error("HubExecClient: bearer is required");
|
|
20
|
-
this.
|
|
21
|
-
this.bearer = options.bearer;
|
|
22
|
-
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
19
|
+
this.hub = new HubClient({ baseUrl: options.baseUrl, apiKey: options.bearer, fetch: options.fetchImpl });
|
|
23
20
|
}
|
|
24
21
|
async exec(input) {
|
|
25
|
-
const response = await this.fetchImpl(`${this.baseUrl}/v1/hub/exec`, {
|
|
26
|
-
method: "POST",
|
|
27
|
-
headers: { Authorization: `Bearer ${this.bearer}`, "Content-Type": "application/json", Accept: "application/json" },
|
|
28
|
-
body: JSON.stringify({ path: input.path, input: input.actionInput, connectionId: input.connectionId })
|
|
29
|
-
});
|
|
30
|
-
const envelope = await this.readEnvelope(response);
|
|
31
|
-
if (response.ok && envelope.success) return { succeeded: true, result: envelope.data?.result };
|
|
32
|
-
return {
|
|
33
|
-
succeeded: false,
|
|
34
|
-
code: envelope.error?.code ?? `HUB_HTTP_${response.status}`,
|
|
35
|
-
message: envelope.error?.message ?? `Hub /exec returned ${response.status}`,
|
|
36
|
-
approval: envelope.error?.details?.approval
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
async readEnvelope(response) {
|
|
40
|
-
const text = await response.text();
|
|
41
|
-
if (!text) return { success: false, error: { code: `HUB_HTTP_${response.status}`, message: `Hub returned ${response.status} with no body` } };
|
|
42
22
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
23
|
+
const result = await this.hub.tools.invoke(input.path, input.actionInput, { connectionId: input.connectionId });
|
|
24
|
+
return { succeeded: true, result: result.result };
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (!(error instanceof HubSdkError)) throw error;
|
|
27
|
+
const details = error.details;
|
|
28
|
+
const approval = details && typeof details === "object" && "approval" in details ? details.approval : void 0;
|
|
29
|
+
return { succeeded: false, code: error.code, message: error.message, ...approval !== void 0 ? { approval } : {} };
|
|
46
30
|
}
|
|
47
31
|
}
|
|
48
32
|
};
|
|
49
33
|
async function invokeIntegrationHub(input, deps) {
|
|
50
|
-
const env = deps.env ?? process
|
|
34
|
+
const env = deps.env ?? globalThis.process?.env ?? {};
|
|
51
35
|
const baseUrl = deps.baseUrl ?? env.TANGLE_PLATFORM_URL?.trim();
|
|
52
36
|
if (!baseUrl) return { status: 500, body: { error: "TANGLE_PLATFORM_URL is not configured" } };
|
|
53
37
|
const action = resolveIntegrationAction(input.toolName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/integrations/index.ts"],"sourcesContent":["/**\n * Integration-hub WIRING — the agent→hub invocation path every Tangle agent app\n * forks. The integration ENGINE (catalog, connectors, OAuth, policy) is\n * `@tangle-network/agent-integrations` (a peer dependency); this module is the\n * thin app-side wiring on top: a typed client over the platform hub's\n * `POST /v1/hub/exec`, MCP-tool-name → hub-action-path resolution, and the\n * per-turn invoke flow the `integration_invoke` tool calls.\n *\n * The product supplies its own catalog (which connectors it uses) and its own\n * per-user api-key resolver (the `apiKeyResolver` seam) — this module owns\n * neither credentials nor the action catalog.\n */\nimport { parseIntegrationToolName } from '@tangle-network/agent-integrations/catalog'\n\n/** `{ success: false }` codes the hub returns on `/exec`. */\nexport type HubExecErrorCode =\n | 'HUB_APPROVAL_REQUIRED'\n | 'HUB_POLICY_DENIED'\n | 'HUB_CONNECTION_MISSING'\n | 'HUB_CONNECTION_REVOKED'\n | 'HUB_CONFIG_MISSING'\n | 'HUB_NOT_FOUND'\n | string\n\n/** Outcome of a hub `/exec` call. Callers MUST inspect `succeeded` before\n * reading `result` — a denied or approval-gated write resolves with\n * `succeeded: false` and a populated `code`, never a thrown silent failure. */\nexport type HubExecResult =\n | { succeeded: true; result: unknown }\n | { succeeded: false; code: HubExecErrorCode; message: string; approval?: unknown }\n\n/** Define configuration options for initializing a Hub execution client */\nexport interface HubExecClientOptions {\n /** Platform base URL (e.g. `TANGLE_PLATFORM_URL`). */\n baseUrl: string\n /** Calling user's Tangle API key — the hub principal bearer. */\n bearer: string\n /** Test seam. Defaults to global `fetch`. */\n fetchImpl?: typeof fetch\n}\n\n/** The provider/connector/action a hub action path addresses, plus the dotted\n * `path` the hub `/exec` endpoint expects. */\nexport interface ParsedIntegrationAction {\n providerId: string\n connectorId: string\n actionId: string\n /** `provider.connector.action`. */\n path: string\n}\n\n/**\n * Resolve an MCP tool name (the opaque `int_…` catalog name the agent calls)\n * into the dotted hub action path. Returns `undefined` when the name is not a\n * catalog integration tool, so the chat loop routes non-integration calls\n * elsewhere instead of misrouting them to the hub.\n */\nexport function resolveIntegrationAction(toolName: string): ParsedIntegrationAction | undefined {\n let parsed: { providerId: string; connectorId: string; actionId: string }\n try {\n parsed = parseIntegrationToolName(toolName)\n } catch {\n return undefined\n }\n if (!parsed.providerId || !parsed.connectorId || !parsed.actionId) return undefined\n return { ...parsed, path: `${parsed.providerId}.${parsed.connectorId}.${parsed.actionId}` }\n}\n\ninterface HubEnvelope {\n success: boolean\n data?: { result?: unknown }\n error?: { code?: string; message?: string; details?: { approval?: unknown } }\n}\n\n/** Typed client over the platform hub `/v1/hub/exec`. The hub holds the user's\n * credentials, resolves the connection from the bearer principal, evaluates\n * per-action policy (read → allow, write/destructive → approval), and runs the\n * action server-side. Never throws on a policy block — a gated write is a\n * normal `succeeded: false` outcome. */\nexport class HubExecClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: HubExecClientOptions) {\n if (!options.baseUrl) throw new Error('HubExecClient: baseUrl is required')\n if (!options.bearer) throw new Error('HubExecClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl = options.fetchImpl ?? fetch\n }\n\n async exec(input: { path: string; actionInput?: unknown; connectionId?: string }): Promise<HubExecResult> {\n const response = await this.fetchImpl(`${this.baseUrl}/v1/hub/exec`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${this.bearer}`, 'Content-Type': 'application/json', Accept: 'application/json' },\n body: JSON.stringify({ path: input.path, input: input.actionInput, connectionId: input.connectionId }),\n })\n const envelope = await this.readEnvelope(response)\n if (response.ok && envelope.success) return { succeeded: true, result: envelope.data?.result }\n return {\n succeeded: false,\n code: envelope.error?.code ?? `HUB_HTTP_${response.status}`,\n message: envelope.error?.message ?? `Hub /exec returned ${response.status}`,\n approval: envelope.error?.details?.approval,\n }\n }\n\n private async readEnvelope(response: Response): Promise<HubEnvelope> {\n const text = await response.text()\n if (!text) return { success: false, error: { code: `HUB_HTTP_${response.status}`, message: `Hub returned ${response.status} with no body` } }\n try {\n return JSON.parse(text) as HubEnvelope\n } catch {\n return { success: false, error: { code: 'HUB_BAD_RESPONSE', message: `Hub returned non-JSON (${response.status}): ${text.slice(0, 200)}` } }\n }\n }\n}\n\n/** Define input parameters for invoking a hub tool with user ID, tool name, and optional arguments */\nexport interface HubInvokeInput {\n userId: string\n /** The MCP tool name the agent called (`int_<provider>_<connector>_<action>`). */\n toolName: string\n args?: Record<string, unknown>\n}\n/** Describe the outcome of a hub invocation including status and response body */\nexport interface HubInvokeOutcome {\n status: number\n body: Record<string, unknown>\n}\n/** Define dependencies for invoking hub operations including API key resolution and optional configuration */\nexport interface HubInvokeDeps {\n /** Resolve the user's Tangle API key (the hub principal bearer). Required —\n * the product binds its own session-key resolver. Null → user not linked. */\n apiKeyResolver: (userId: string) => Promise<string | null>\n /** Platform base URL. Defaults to `env.TANGLE_PLATFORM_URL`. */\n baseUrl?: string\n fetchImpl?: typeof fetch\n env?: Record<string, string | undefined>\n}\n\n/**\n * Resolve + execute one integration tool call through the hub: resolve the\n * per-user bearer, map the MCP tool name to the hub action path, forward to\n * `/v1/hub/exec`, and shape the route response (200 ok / 401 not-linked /\n * 400 unknown-tool / 409 approval-required / 502 hub-error). A write that's\n * approval-gated surfaces verbatim as 409, never silently executed.\n */\nexport async function invokeIntegrationHub(input: HubInvokeInput, deps: HubInvokeDeps): Promise<HubInvokeOutcome> {\n const env = deps.env ?? (process.env as Record<string, string | undefined>)\n const baseUrl = deps.baseUrl ?? env.TANGLE_PLATFORM_URL?.trim()\n if (!baseUrl) return { status: 500, body: { error: 'TANGLE_PLATFORM_URL is not configured' } }\n\n const action = resolveIntegrationAction(input.toolName)\n if (!action) return { status: 400, body: { error: `Unsupported integration tool: ${input.toolName}` } }\n\n const bearer = await deps.apiKeyResolver(input.userId)\n if (!bearer) return { status: 401, body: { error: 'Tangle account not linked — connect integrations from the app first' } }\n\n const client = new HubExecClient({ baseUrl, bearer, fetchImpl: deps.fetchImpl })\n const outcome = await client.exec({ path: action.path, actionInput: input.args ?? {} })\n\n if (outcome.succeeded) {\n return { status: 200, body: { success: true, path: action.path, providerId: action.providerId, action: action.actionId, result: outcome.result } }\n }\n const status = outcome.code === 'HUB_APPROVAL_REQUIRED' ? 409 : 502\n return {\n status,\n body: { success: false, path: action.path, code: outcome.code, error: outcome.message, ...(outcome.approval ? { approval: outcome.approval } : {}) },\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/integrations/index.ts"],"sourcesContent":["/**\n * Integration-hub WIRING — the agent→hub invocation path every Tangle agent app\n * forks. The integration ENGINE (catalog, connectors, OAuth, policy) is\n * `@tangle-network/agent-integrations` (a peer dependency); this module is the\n * thin app-side wiring on top: an outcome adapter over hub-sdk's\n * `POST /v1/hub/exec`, MCP-tool-name → hub-action-path resolution, and the\n * per-turn invoke flow the `integration_invoke` tool calls.\n *\n * The product supplies its own catalog (which connectors it uses) and its own\n * per-user api-key resolver (the `apiKeyResolver` seam) — this module owns\n * neither credentials nor the action catalog.\n */\nimport { HubClient, HubSdkError } from '@tangle-network/hub-sdk'\nimport { parseIntegrationToolName } from '@tangle-network/agent-integrations/catalog'\n\n/** `{ success: false }` codes the hub returns on `/exec`. */\nexport type HubExecErrorCode =\n | 'HUB_APPROVAL_REQUIRED'\n | 'HUB_POLICY_DENIED'\n | 'HUB_CONNECTION_MISSING'\n | 'HUB_CONNECTION_REVOKED'\n | 'HUB_CONFIG_MISSING'\n | 'HUB_NOT_FOUND'\n | string\n\n/** Outcome of a hub `/exec` call. Callers MUST inspect `succeeded` before\n * reading `result` — a denied or approval-gated write resolves with\n * `succeeded: false` and a populated `code`, never a thrown silent failure. */\nexport type HubExecResult =\n | { succeeded: true; result: unknown }\n | { succeeded: false; code: HubExecErrorCode; message: string; approval?: unknown }\n\n/** Define configuration options for initializing a Hub execution client */\nexport interface HubExecClientOptions {\n /** Platform base URL (e.g. `TANGLE_PLATFORM_URL`). */\n baseUrl: string\n /** Calling user's Tangle API key — the hub principal bearer. */\n bearer: string\n /** Test seam. Defaults to global `fetch`. */\n fetchImpl?: typeof fetch\n}\n\n/** The provider/connector/action a hub action path addresses, plus the dotted\n * `path` the hub `/exec` endpoint expects. */\nexport interface ParsedIntegrationAction {\n providerId: string\n connectorId: string\n actionId: string\n /** `provider.connector.action`. */\n path: string\n}\n\n/**\n * Resolve an MCP tool name (the opaque `int_…` catalog name the agent calls)\n * into the dotted hub action path. Returns `undefined` when the name is not a\n * catalog integration tool, so the chat loop routes non-integration calls\n * elsewhere instead of misrouting them to the hub.\n */\nexport function resolveIntegrationAction(toolName: string): ParsedIntegrationAction | undefined {\n let parsed: { providerId: string; connectorId: string; actionId: string }\n try {\n parsed = parseIntegrationToolName(toolName)\n } catch {\n return undefined\n }\n if (!parsed.providerId || !parsed.connectorId || !parsed.actionId) return undefined\n return { ...parsed, path: `${parsed.providerId}.${parsed.connectorId}.${parsed.actionId}` }\n}\n\n/** Product outcome adapter over the published Hub transport. Never grants approval. */\nexport class HubExecClient {\n private readonly hub: HubClient\n\n constructor(options: HubExecClientOptions) {\n if (!options.baseUrl) throw new Error('HubExecClient: baseUrl is required')\n if (!options.bearer) throw new Error('HubExecClient: bearer is required')\n this.hub = new HubClient({ baseUrl: options.baseUrl, apiKey: options.bearer, fetch: options.fetchImpl })\n }\n\n async exec(input: { path: string; actionInput?: unknown; connectionId?: string }): Promise<HubExecResult> {\n try {\n // No approve flag. Hub still decides whether this exact action is permitted.\n const result = await this.hub.tools.invoke(input.path, input.actionInput, { connectionId: input.connectionId })\n return { succeeded: true, result: result.result }\n } catch (error) {\n if (!(error instanceof HubSdkError)) throw error\n const details = error.details\n const approval = details && typeof details === 'object' && 'approval' in details ? details.approval : undefined\n return { succeeded: false, code: error.code, message: error.message, ...(approval !== undefined ? { approval } : {}) }\n }\n }\n}\n\n/** Define input parameters for invoking a hub tool with user ID, tool name, and optional arguments */\nexport interface HubInvokeInput {\n userId: string\n /** The MCP tool name the agent called (`int_<provider>_<connector>_<action>`). */\n toolName: string\n args?: Record<string, unknown>\n}\n/** Describe the outcome of a hub invocation including status and response body */\nexport interface HubInvokeOutcome {\n status: number\n body: Record<string, unknown>\n}\n/** Define dependencies for invoking hub operations including API key resolution and optional configuration */\nexport interface HubInvokeDeps {\n /** Resolve the user's Tangle API key (the hub principal bearer). Required —\n * the product binds its own session-key resolver. Null → user not linked. */\n apiKeyResolver: (userId: string) => Promise<string | null>\n /** Platform base URL. Defaults to `env.TANGLE_PLATFORM_URL`. */\n baseUrl?: string\n fetchImpl?: typeof fetch\n env?: Record<string, string | undefined>\n}\n\n/**\n * Resolve + execute one integration tool call through the hub: resolve the\n * per-user bearer, map the MCP tool name to the hub action path, forward to\n * `/v1/hub/exec`, and shape the route response (200 ok / 401 not-linked /\n * 400 unknown-tool / 409 approval-required / 502 hub-error). A write that's\n * approval-gated surfaces verbatim as 409, never silently executed.\n */\nexport async function invokeIntegrationHub(input: HubInvokeInput, deps: HubInvokeDeps): Promise<HubInvokeOutcome> {\n const env = deps.env ?? (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env ?? {}\n const baseUrl = deps.baseUrl ?? env.TANGLE_PLATFORM_URL?.trim()\n if (!baseUrl) return { status: 500, body: { error: 'TANGLE_PLATFORM_URL is not configured' } }\n\n const action = resolveIntegrationAction(input.toolName)\n if (!action) return { status: 400, body: { error: `Unsupported integration tool: ${input.toolName}` } }\n\n const bearer = await deps.apiKeyResolver(input.userId)\n if (!bearer) return { status: 401, body: { error: 'Tangle account not linked — connect integrations from the app first' } }\n\n const client = new HubExecClient({ baseUrl, bearer, fetchImpl: deps.fetchImpl })\n const outcome = await client.exec({ path: action.path, actionInput: input.args ?? {} })\n\n if (outcome.succeeded) {\n return { status: 200, body: { success: true, path: action.path, providerId: action.providerId, action: action.actionId, result: outcome.result } }\n }\n const status = outcome.code === 'HUB_APPROVAL_REQUIRED' ? 409 : 502\n return {\n status,\n body: { success: false, path: action.path, code: outcome.code, error: outcome.message, ...(outcome.approval ? { approval: outcome.approval } : {}) },\n }\n}\n"],"mappings":";AAYA,SAAS,WAAW,mBAAmB;AACvC,SAAS,gCAAgC;AA6ClC,SAAS,yBAAyB,UAAuD;AAC9F,MAAI;AACJ,MAAI;AACF,aAAS,yBAAyB,QAAQ;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,OAAO,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,SAAU,QAAO;AAC1E,SAAO,EAAE,GAAG,QAAQ,MAAM,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW,IAAI,OAAO,QAAQ,GAAG;AAC5F;AAGO,IAAM,gBAAN,MAAoB;AAAA,EACR;AAAA,EAEjB,YAAY,SAA+B;AACzC,QAAI,CAAC,QAAQ,QAAS,OAAM,IAAI,MAAM,oCAAoC;AAC1E,QAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,MAAM,mCAAmC;AACxE,SAAK,MAAM,IAAI,UAAU,EAAE,SAAS,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,UAAU,CAAC;AAAA,EACzG;AAAA,EAEA,MAAM,KAAK,OAA+F;AACxG,QAAI;AAEF,YAAM,SAAS,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM,MAAM,MAAM,aAAa,EAAE,cAAc,MAAM,aAAa,CAAC;AAC9G,aAAO,EAAE,WAAW,MAAM,QAAQ,OAAO,OAAO;AAAA,IAClD,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,aAAc,OAAM;AAC3C,YAAM,UAAU,MAAM;AACtB,YAAM,WAAW,WAAW,OAAO,YAAY,YAAY,cAAc,UAAU,QAAQ,WAAW;AACtG,aAAO,EAAE,WAAW,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,SAAS,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC,EAAG;AAAA,IACvH;AAAA,EACF;AACF;AAgCA,eAAsB,qBAAqB,OAAuB,MAAgD;AAChH,QAAM,MAAM,KAAK,OAAQ,WAA0E,SAAS,OAAO,CAAC;AACpH,QAAM,UAAU,KAAK,WAAW,IAAI,qBAAqB,KAAK;AAC9D,MAAI,CAAC,QAAS,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,wCAAwC,EAAE;AAE7F,QAAM,SAAS,yBAAyB,MAAM,QAAQ;AACtD,MAAI,CAAC,OAAQ,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iCAAiC,MAAM,QAAQ,GAAG,EAAE;AAEtG,QAAM,SAAS,MAAM,KAAK,eAAe,MAAM,MAAM;AACrD,MAAI,CAAC,OAAQ,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,2EAAsE,EAAE;AAE1H,QAAM,SAAS,IAAI,cAAc,EAAE,SAAS,QAAQ,WAAW,KAAK,UAAU,CAAC;AAC/E,QAAM,UAAU,MAAM,OAAO,KAAK,EAAE,MAAM,OAAO,MAAM,aAAa,MAAM,QAAQ,CAAC,EAAE,CAAC;AAEtF,MAAI,QAAQ,WAAW;AACrB,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,SAAS,MAAM,MAAM,OAAO,MAAM,YAAY,OAAO,YAAY,QAAQ,OAAO,UAAU,QAAQ,QAAQ,OAAO,EAAE;AAAA,EACnJ;AACA,QAAM,SAAS,QAAQ,SAAS,0BAA0B,MAAM;AAChE,SAAO;AAAA,IACL;AAAA,IACA,MAAM,EAAE,SAAS,OAAO,MAAM,OAAO,MAAM,MAAM,QAAQ,MAAM,OAAO,QAAQ,SAAS,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC,EAAG;AAAA,EACrJ;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.49.
|
|
3
|
+
"version": "0.49.33",
|
|
4
4
|
"packageManager": "pnpm@11.24.0",
|
|
5
5
|
"description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
|
|
6
6
|
"keywords": [
|
|
@@ -545,15 +545,15 @@
|
|
|
545
545
|
"@storybook/react-vite": "^10.5.10",
|
|
546
546
|
"@tailwindcss/postcss": "^4.3.3",
|
|
547
547
|
"@tangle-network/agent-docs": "0.2.1",
|
|
548
|
-
"@tangle-network/agent-eval": "0.
|
|
548
|
+
"@tangle-network/agent-eval": "0.193.2",
|
|
549
549
|
"@tangle-network/agent-gateway": "0.11.4",
|
|
550
550
|
"@tangle-network/agent-integrations": "0.55.0",
|
|
551
|
-
"@tangle-network/agent-interface": "2.
|
|
552
|
-
"@tangle-network/agent-knowledge": "17.1.
|
|
551
|
+
"@tangle-network/agent-interface": "2.13.0",
|
|
552
|
+
"@tangle-network/agent-knowledge": "17.1.8",
|
|
553
553
|
"@tangle-network/agent-profile-materialize": "0.20.1",
|
|
554
554
|
"@tangle-network/agent-runtime": "0.277.0",
|
|
555
555
|
"@tangle-network/brand": "1.5.0",
|
|
556
|
-
"@tangle-network/hub-sdk": "0.19.
|
|
556
|
+
"@tangle-network/hub-sdk": "0.19.3",
|
|
557
557
|
"@tangle-network/sandbox": "0.53.0",
|
|
558
558
|
"@tangle-network/sandbox-ui": "0.113.3",
|
|
559
559
|
"@tangle-network/ui": "11.9.0",
|
|
@@ -614,7 +614,7 @@
|
|
|
614
614
|
"@tangle-network/agent-profile-materialize": ">=0.20.1 <0.21.0",
|
|
615
615
|
"@tangle-network/agent-runtime": ">=0.262.0 <0.278.0",
|
|
616
616
|
"@tangle-network/brand": ">=1.5.0",
|
|
617
|
-
"@tangle-network/hub-sdk": ">=0.19.
|
|
617
|
+
"@tangle-network/hub-sdk": ">=0.19.3 <0.20.0",
|
|
618
618
|
"@tangle-network/sandbox": ">=0.45.0 <0.48.0 || ^0.49.0 || ^0.50.0 || ^0.51.0 || ^0.52.0 || ^0.53.0",
|
|
619
619
|
"@tangle-network/sandbox-ui": ">=0.113.3 <0.114.0",
|
|
620
620
|
"@tangle-network/ui": ">=11.6.0 <12.0.0",
|