@tangle-network/agent-app 0.39.2 → 0.41.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.
Files changed (48) hide show
  1. package/.claude/skills/eval-campaign/SKILL.md +5 -5
  2. package/.claude/skills/surface-evolution/SKILL.md +2 -2
  3. package/dist/auth-DuptSkWh.d.ts +39 -0
  4. package/dist/{chunk-TQ5M7BFV.js → chunk-2A7STBX7.js} +2 -2
  5. package/dist/{chunk-FDJ6JQCI.js → chunk-3II3AWHY.js} +6 -4
  6. package/dist/{chunk-FDJ6JQCI.js.map → chunk-3II3AWHY.js.map} +1 -1
  7. package/dist/{chunk-RH74YJIK.js → chunk-7EVZUIHW.js} +7 -2
  8. package/dist/chunk-7EVZUIHW.js.map +1 -0
  9. package/dist/{chunk-DBIG2PHS.js → chunk-IZAH45W2.js} +3 -3
  10. package/dist/{chunk-PPSZNVKT.js → chunk-MFRCM32T.js} +29 -3
  11. package/dist/chunk-MFRCM32T.js.map +1 -0
  12. package/dist/{chunk-BUUJ7TEQ.js → chunk-NEOV2NQ3.js} +2 -2
  13. package/dist/{chunk-CPI3RILI.js → chunk-ULZEF45E.js} +49 -7
  14. package/dist/chunk-ULZEF45E.js.map +1 -0
  15. package/dist/{chunk-2FDTJIU4.js → chunk-WFMUDX5J.js} +2 -2
  16. package/dist/design-canvas/index.d.ts +3 -3
  17. package/dist/design-canvas/index.js +2 -2
  18. package/dist/eval/index.d.ts +1 -1
  19. package/dist/eval-campaign/index.d.ts +3 -3
  20. package/dist/eval-campaign/index.js +4 -4
  21. package/dist/eval-campaign/index.js.map +1 -1
  22. package/dist/index.d.ts +4 -4
  23. package/dist/index.js +18 -8
  24. package/dist/{mcp-4I_RHhNa.d.ts → mcp-BHfIoGLW.d.ts} +10 -6
  25. package/dist/preset-cloudflare/index.d.ts +1 -1
  26. package/dist/runtime/index.d.ts +3 -3
  27. package/dist/runtime/index.js +2 -2
  28. package/dist/sandbox/index.d.ts +2 -2
  29. package/dist/sandbox/index.js +4 -4
  30. package/dist/sequences/index.d.ts +3 -3
  31. package/dist/sequences/index.js +2 -2
  32. package/dist/stream/index.d.ts +37 -3
  33. package/dist/stream/index.js +5 -1
  34. package/dist/tools/index.d.ts +13 -8
  35. package/dist/tools/index.js +9 -3
  36. package/dist/{types-wHs0rmtu.d.ts → types-BEOvc_ue.d.ts} +68 -1
  37. package/dist/web-react/index.d.ts +58 -1
  38. package/dist/web-react/index.js +241 -137
  39. package/dist/web-react/index.js.map +1 -1
  40. package/package.json +12 -12
  41. package/dist/auth-DcK5ERaL.d.ts +0 -65
  42. package/dist/chunk-CPI3RILI.js.map +0 -1
  43. package/dist/chunk-PPSZNVKT.js.map +0 -1
  44. package/dist/chunk-RH74YJIK.js.map +0 -1
  45. /package/dist/{chunk-TQ5M7BFV.js.map → chunk-2A7STBX7.js.map} +0 -0
  46. /package/dist/{chunk-DBIG2PHS.js.map → chunk-IZAH45W2.js.map} +0 -0
  47. /package/dist/{chunk-BUUJ7TEQ.js.map → chunk-NEOV2NQ3.js.map} +0 -0
  48. /package/dist/{chunk-2FDTJIU4.js.map → chunk-WFMUDX5J.js.map} +0 -0
@@ -62,13 +62,35 @@ interface BufferedTurnEvent {
62
62
  interface TurnEventStore {
63
63
  append(turnId: string, events: BufferedTurnEvent[]): Promise<void>;
64
64
  read(turnId: string, fromSeq: number): Promise<BufferedTurnEvent[]>;
65
- setStatus(turnId: string, status: TurnStatus): Promise<void>;
65
+ /** Record turn lifecycle. `scopeId` (a thread/session id) is optional and lets
66
+ * {@link TurnEventStore.listRunning} rediscover this turn after a client reload
67
+ * loses the turnId; stores that don't track scope ignore it. */
68
+ setStatus(turnId: string, status: TurnStatus, scopeId?: string): Promise<void>;
66
69
  getStatus(turnId: string): Promise<TurnStatus | null>;
70
+ /** Running turnIds for a scope, newest first — so a reloaded client (clientRunId
71
+ * lost) can find and resume the in-flight turn. Optional: a store records it
72
+ * only if `setStatus` was given a `scopeId`. */
73
+ listRunning?(scopeId: string): Promise<string[]>;
67
74
  }
68
75
  /** Merge consecutive text/reasoning deltas of the same type into one event.
69
76
  * Concatenation-preserving: replaying the coalesced stream produces the same
70
77
  * accumulated text as the original. */
71
78
  declare function coalesceDeltas(events: unknown[]): unknown[];
79
+ /**
80
+ * Coalesce consecutive `message.part.updated` deltas for the SAME part into one
81
+ * event. agent-runtime products stream `ChatStreamEvent` NDJSON
82
+ * (`{type:'message.part.updated', data:{part, delta}}`); pumped through the
83
+ * buffer with the default tool-loop coalescer, every per-token delta persists as
84
+ * its own row because that coalescer never recognizes the shape. Pass this as
85
+ * {@link PumpBufferedTurnOptions.coalesce} instead.
86
+ *
87
+ * Concatenation-preserving for BOTH consumer styles: the merged event keeps the
88
+ * LATEST event's `data.part` (already the cumulative accumulation) and sets
89
+ * `data.delta` to the concatenation of the merged deltas, so a client that
90
+ * appends `delta` and one that reads the cumulative `part` both reconstruct the
91
+ * identical final text.
92
+ */
93
+ declare function coalesceChatStreamEvents(events: unknown[]): unknown[];
72
94
  interface PumpBufferedTurnOptions {
73
95
  source: AsyncIterable<unknown>;
74
96
  store: TurnEventStore;
@@ -78,6 +100,14 @@ interface PumpBufferedTurnOptions {
78
100
  write?: (line: string) => Promise<void> | void;
79
101
  /** Flush buffered events to the store at most this often. Default 400ms. */
80
102
  flushIntervalMs?: number;
103
+ /** Per-flush coalescer. Default {@link coalesceDeltas} (tool-loop text/reasoning
104
+ * deltas). agent-runtime products streaming `ChatStreamEvent` pass
105
+ * {@link coalesceChatStreamEvents} so per-token deltas don't each persist as a
106
+ * row. Must be concatenation-preserving. */
107
+ coalesce?: (events: unknown[]) => unknown[];
108
+ /** Optional scope (thread/session id) recorded with the turn status, so
109
+ * {@link TurnEventStore.listRunning} can find this turn after a reload. */
110
+ scopeId?: string;
81
111
  }
82
112
  /**
83
113
  * Drive a turn to completion regardless of the live client: every source
@@ -118,9 +148,13 @@ interface D1LikeForTurns {
118
148
  };
119
149
  }
120
150
  /** Schema for the D1 store — append to the product's migrations. */
121
- declare const TURN_EVENTS_MIGRATION_SQL = "\nCREATE TABLE IF NOT EXISTS turn_events (\n turnId TEXT NOT NULL,\n seq INTEGER NOT NULL,\n event TEXT NOT NULL,\n PRIMARY KEY (turnId, seq)\n);\nCREATE TABLE IF NOT EXISTS turn_status (\n turnId TEXT PRIMARY KEY,\n status TEXT NOT NULL,\n updatedAt TEXT NOT NULL\n);\n";
151
+ declare const TURN_EVENTS_MIGRATION_SQL = "\nCREATE TABLE IF NOT EXISTS turn_events (\n turnId TEXT NOT NULL,\n seq INTEGER NOT NULL,\n event TEXT NOT NULL,\n PRIMARY KEY (turnId, seq)\n);\nCREATE TABLE IF NOT EXISTS turn_status (\n turnId TEXT PRIMARY KEY,\n status TEXT NOT NULL,\n scopeId TEXT,\n updatedAt TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_turn_status_scope ON turn_status (scopeId, status);\n";
152
+ /** For deployments whose `turn_status` table predates `scopeId`/`listRunning` —
153
+ * run once to add the column (the CREATE above already includes it for new
154
+ * deployments). SQLite ignores a duplicate-add error if already applied. */
155
+ declare const TURN_STATUS_SCOPE_MIGRATION_SQL = "ALTER TABLE turn_status ADD COLUMN scopeId TEXT;";
122
156
  declare function createD1TurnEventStore(db: D1LikeForTurns): TurnEventStore;
123
157
  /** In-memory store for tests and keyless local dev. */
124
158
  declare function createMemoryTurnEventStore(): TurnEventStore;
125
159
 
126
- export { type BufferedTurnEvent, type D1LikeForTurns, type JsonRecord, type PersistedChatMessageForTurn, type PumpBufferedTurnOptions, type ReplayTurnEventsOptions, type ResolvedChatTurn, type StreamEvent, TURN_EVENTS_MIGRATION_SQL, type TurnEventStore, type TurnStatus, asRecord, asString, buildUserTextParts, coalesceDeltas, createD1TurnEventStore, createMemoryTurnEventStore, encodeEvent, finalizeAssistantParts, getPartKey, mergePersistedPart, messageHasTurnId, normalizeClientTurnId, normalizePersistedPart, normalizeTime, normalizeToolEvent, pumpBufferedTurn, replayTurnEvents, resolveChatTurn, resolveToolId, resolveToolName };
160
+ export { type BufferedTurnEvent, type D1LikeForTurns, type JsonRecord, type PersistedChatMessageForTurn, type PumpBufferedTurnOptions, type ReplayTurnEventsOptions, type ResolvedChatTurn, type StreamEvent, TURN_EVENTS_MIGRATION_SQL, TURN_STATUS_SCOPE_MIGRATION_SQL, type TurnEventStore, type TurnStatus, asRecord, asString, buildUserTextParts, coalesceChatStreamEvents, coalesceDeltas, createD1TurnEventStore, createMemoryTurnEventStore, encodeEvent, finalizeAssistantParts, getPartKey, mergePersistedPart, messageHasTurnId, normalizeClientTurnId, normalizePersistedPart, normalizeTime, normalizeToolEvent, pumpBufferedTurn, replayTurnEvents, resolveChatTurn, resolveToolId, resolveToolName };
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  TURN_EVENTS_MIGRATION_SQL,
3
+ TURN_STATUS_SCOPE_MIGRATION_SQL,
3
4
  asRecord,
4
5
  asString,
5
6
  buildUserTextParts,
7
+ coalesceChatStreamEvents,
6
8
  coalesceDeltas,
7
9
  createD1TurnEventStore,
8
10
  createMemoryTurnEventStore,
@@ -20,12 +22,14 @@ import {
20
22
  resolveChatTurn,
21
23
  resolveToolId,
22
24
  resolveToolName
23
- } from "../chunk-CPI3RILI.js";
25
+ } from "../chunk-ULZEF45E.js";
24
26
  export {
25
27
  TURN_EVENTS_MIGRATION_SQL,
28
+ TURN_STATUS_SCOPE_MIGRATION_SQL,
26
29
  asRecord,
27
30
  asString,
28
31
  buildUserTextParts,
32
+ coalesceChatStreamEvents,
29
33
  coalesceDeltas,
30
34
  createD1TurnEventStore,
31
35
  createMemoryTurnEventStore,
@@ -1,8 +1,8 @@
1
- import { a as AppToolName, c as ToolHeaderNames } from '../auth-DcK5ERaL.js';
2
- export { A as APP_TOOL_NAMES, b as AuthenticateOptions, D as DEFAULT_HEADER_NAMES, O as OpenAIFunctionTool, T as ToolAuthResult, d as authenticateToolRequest, e as buildAppToolOpenAITools, i as isAppToolName, r as readToolArgs } from '../auth-DcK5ERaL.js';
3
- import { f as AppToolTaxonomy, c as AppToolHandlers, b as AppToolContext, e as AppToolProducedEvent, d as AppToolOutcome } from '../types-wHs0rmtu.js';
4
- export { A as AddCitationArgs, a as AddCitationResult, B as BuildAppToolsOptions, R as RenderUiArgs, g as RenderUiResult, S as ScheduleFollowupArgs, h as ScheduleFollowupResult, i as SubmitProposalArgs, j as SubmitProposalResult } from '../types-wHs0rmtu.js';
5
- export { A as AppToolMcpServer, B as BuildHttpMcpServerOptions, a as BuildMcpServerOptions, D as DEFAULT_APP_TOOL_PATHS, S as ScopedMcpServerEntryOptions, b as buildAppToolMcpServer, c as buildHttpMcpServer, d as buildScopedMcpServerEntry } from '../mcp-4I_RHhNa.js';
1
+ import { a as ToolHeaderNames } from '../auth-DuptSkWh.js';
2
+ export { A as AuthenticateOptions, D as DEFAULT_HEADER_NAMES, T as ToolAuthResult, b as authenticateToolRequest, r as readToolArgs } from '../auth-DuptSkWh.js';
3
+ import { i as AppToolTaxonomy, e as AppToolHandlers, d as AppToolDefinition, c as AppToolContext, h as AppToolProducedEvent, g as AppToolOutcome, f as AppToolName } from '../types-BEOvc_ue.js';
4
+ export { A as APP_TOOL_NAMES, a as AddCitationArgs, b as AddCitationResult, B as BuildAppToolsOptions, O as OpenAIFunctionTool, R as RenderUiArgs, j as RenderUiResult, S as ScheduleFollowupArgs, k as ScheduleFollowupResult, l as SubmitProposalArgs, m as SubmitProposalResult, n as buildAppToolOpenAITools, o as customToolToOpenAI, p as defineAppTool, q as findCustomTool, r as isAppToolName } from '../types-BEOvc_ue.js';
5
+ export { A as AppToolMcpServer, B as BuildHttpMcpServerOptions, a as BuildMcpServerOptions, D as DEFAULT_APP_TOOL_PATHS, S as ScopedMcpServerEntryOptions, b as buildAppToolMcpServer, c as buildHttpMcpServer, d as buildScopedMcpServerEntry } from '../mcp-BHfIoGLW.js';
6
6
  export { C as CreateMcpToolHandlerOptions, M as MCP_PROTOCOL_VERSIONS, a as McpProtocolVersion, b as McpServerInfo, c as McpToolDefinition, d as createMcpToolHandler } from '../mcp-rpc-DLw_r9PQ.js';
7
7
 
8
8
  /** A correctable bad-input error a tool handler throws; the HTTP layer maps it
@@ -131,6 +131,10 @@ declare function restrictTaxonomy(taxonomy: AppToolTaxonomy, allowed: readonly s
131
131
  interface DispatchOptions {
132
132
  handlers: AppToolHandlers;
133
133
  taxonomy: AppToolTaxonomy;
134
+ /** Product-registered tools beyond the four built-ins. A called name that is
135
+ * not a built-in is dispatched to the matching {@link AppToolDefinition.execute}
136
+ * through this same validation/outcome path. */
137
+ customTools?: readonly AppToolDefinition[];
134
138
  /** Per-call approval policy. When provided it OVERRIDES the static
135
139
  * `taxonomy.regulatedTypes` membership check, so products can gate by
136
140
  * cost threshold, environment, or first-use instead of always/never.
@@ -180,8 +184,9 @@ interface RuntimeExecutorOptions extends DispatchOptions {
180
184
  declare function createAppToolRuntimeExecutor(opts: RuntimeExecutorOptions): AppToolRuntimeExecutor;
181
185
 
182
186
  interface HandleToolRequestOptions extends DispatchOptions {
183
- /** Which app tool this route serves. */
184
- tool: AppToolName;
187
+ /** Which app tool this route serves — a built-in name or a product-registered
188
+ * {@link AppToolDefinition} (auto-added to `customTools` for dispatch). */
189
+ tool: AppToolName | AppToolDefinition;
185
190
  /** Verify the bearer capability token belongs to the header user. */
186
191
  verifyToken: (userId: string, bearer: string) => Promise<boolean>;
187
192
  headerNames?: ToolHeaderNames;
@@ -197,4 +202,4 @@ interface HandleToolRequestOptions extends DispatchOptions {
197
202
  */
198
203
  declare function handleAppToolRequest(request: Request, opts: HandleToolRequestOptions): Promise<Response>;
199
204
 
200
- export { AppToolContext, AppToolHandlers, AppToolName, AppToolOutcome, AppToolProducedEvent, type AppToolRuntimeExecutor, AppToolTaxonomy, type CapabilityTokenOptions, type DispatchOptions, type ExpiringCapabilityTokenOptions, type HandleToolRequestOptions, type ResolveToolCapabilitiesOptions, type ResolvedToolCapabilities, type RuntimeExecutorOptions, type ToolCapability, ToolHeaderNames, ToolInputError, createAppToolRuntimeExecutor, createCapabilityToken, createExpiringCapabilityToken, dispatchAppTool, handleAppToolRequest, outcomeStatus, resolveToolCapabilities, restrictTaxonomy, verifyCapabilityToken, verifyExpiringCapabilityToken };
205
+ export { AppToolContext, AppToolDefinition, AppToolHandlers, AppToolName, AppToolOutcome, AppToolProducedEvent, type AppToolRuntimeExecutor, AppToolTaxonomy, type CapabilityTokenOptions, type DispatchOptions, type ExpiringCapabilityTokenOptions, type HandleToolRequestOptions, type ResolveToolCapabilitiesOptions, type ResolvedToolCapabilities, type RuntimeExecutorOptions, type ToolCapability, ToolHeaderNames, ToolInputError, createAppToolRuntimeExecutor, createCapabilityToken, createExpiringCapabilityToken, dispatchAppTool, handleAppToolRequest, outcomeStatus, resolveToolCapabilities, restrictTaxonomy, verifyCapabilityToken, verifyExpiringCapabilityToken };
@@ -6,7 +6,7 @@ import {
6
6
  restrictTaxonomy,
7
7
  verifyCapabilityToken,
8
8
  verifyExpiringCapabilityToken
9
- } from "../chunk-FDJ6JQCI.js";
9
+ } from "../chunk-3II3AWHY.js";
10
10
  import {
11
11
  DEFAULT_APP_TOOL_PATHS,
12
12
  DEFAULT_HEADER_NAMES,
@@ -17,16 +17,19 @@ import {
17
17
  buildScopedMcpServerEntry,
18
18
  createMcpToolHandler,
19
19
  readToolArgs
20
- } from "../chunk-RH74YJIK.js";
20
+ } from "../chunk-7EVZUIHW.js";
21
21
  import {
22
22
  APP_TOOL_NAMES,
23
23
  ToolInputError,
24
24
  buildAppToolOpenAITools,
25
25
  createAppToolRuntimeExecutor,
26
+ customToolToOpenAI,
27
+ defineAppTool,
26
28
  dispatchAppTool,
29
+ findCustomTool,
27
30
  isAppToolName,
28
31
  outcomeStatus
29
- } from "../chunk-PPSZNVKT.js";
32
+ } from "../chunk-MFRCM32T.js";
30
33
  export {
31
34
  APP_TOOL_NAMES,
32
35
  DEFAULT_APP_TOOL_PATHS,
@@ -42,7 +45,10 @@ export {
42
45
  createCapabilityToken,
43
46
  createExpiringCapabilityToken,
44
47
  createMcpToolHandler,
48
+ customToolToOpenAI,
49
+ defineAppTool,
45
50
  dispatchAppTool,
51
+ findCustomTool,
46
52
  handleAppToolRequest,
47
53
  isAppToolName,
48
54
  outcomeStatus,
@@ -1,3 +1,67 @@
1
+ /** The four canonical app-tool names. Stable identifiers the model calls in
2
+ * both the sandbox (MCP server name) and runtime (function-tool name) paths. */
3
+ declare const APP_TOOL_NAMES: readonly ["submit_proposal", "schedule_followup", "render_ui", "add_citation"];
4
+ type AppToolName = (typeof APP_TOOL_NAMES)[number];
5
+ declare function isAppToolName(name: string): name is AppToolName;
6
+ /** A minimal OpenAI Chat Completions function-tool shape — structurally
7
+ * compatible with `@tangle-network/agent-runtime`'s `OpenAIChatTool` without
8
+ * importing it (keeps this package runtime-free). */
9
+ interface OpenAIFunctionTool {
10
+ type: 'function';
11
+ function: {
12
+ name: string;
13
+ description: string;
14
+ parameters: Record<string, unknown>;
15
+ };
16
+ }
17
+ /**
18
+ * Build the four app tools in OpenAI function-tool shape. `submit_proposal`'s
19
+ * `type` enum is the product's {@link AppToolTaxonomy.proposalTypes}; the
20
+ * model-facing descriptions and the follow-up priority enum default to the
21
+ * Tangle reference vocabulary and can be retuned via {@link BuildAppToolsOptions}
22
+ * (the tool names + JSON-Schema shapes stay fixed — they are mechanism). Pass
23
+ * the result to the agent-runtime backend's `tools`.
24
+ */
25
+ declare function buildAppToolOpenAITools(taxonomy: AppToolTaxonomy, opts?: BuildAppToolsOptions): OpenAIFunctionTool[];
26
+
27
+ /**
28
+ * A product-defined app tool — the open registration seam.
29
+ *
30
+ * The four built-ins (`submit_proposal`/`schedule_followup`/`render_ui`/
31
+ * `add_citation`) are mechanism and stay hard-typed. This is how a product adds
32
+ * a fifth+ tool (e.g. gtm-agent's `set_config`) WITHOUT forking the shell: the
33
+ * `name` + JSON-Schema `parameters` are what the model sees, and `execute` is
34
+ * dispatched through the SAME validation/outcome path as the built-ins — a
35
+ * thrown {@link ToolInputError} becomes a correctable 4xx, any other throw an
36
+ * internal error, and a tool call never silently "succeeds" without its effect.
37
+ */
38
+ interface AppToolDefinition<Args = Record<string, unknown>> {
39
+ /** Stable identifier the model calls (and the MCP server name). Must not
40
+ * collide with a built-in app tool. */
41
+ name: string;
42
+ /** Model-facing description. */
43
+ description: string;
44
+ /** JSON-Schema for the parameters (the OpenAI `function.parameters` object). */
45
+ parameters: Record<string, unknown>;
46
+ /** Default route path the per-turn MCP server / HTTP handler is mounted at.
47
+ * Overridable per call via `paths`/`buildHttpMcpServer`. */
48
+ path?: string;
49
+ /** Fulfil the call; the return value is the tool result the model sees.
50
+ * `ctx` is the trusted per-turn identity (never from tool args). */
51
+ execute: (args: Args, ctx: AppToolContext) => Promise<unknown> | unknown;
52
+ }
53
+ /**
54
+ * Validate + brand a product tool definition. Throws when the name is empty or
55
+ * collides with a built-in (those are reserved mechanism). Identity otherwise —
56
+ * call it at module scope so a bad definition fails at boot, not first use.
57
+ */
58
+ declare function defineAppTool<Args = Record<string, unknown>>(def: AppToolDefinition<Args>): AppToolDefinition<Args>;
59
+ /** The OpenAI function-tool def for a custom tool — appended to the built-ins by
60
+ * `buildAppToolOpenAITools`. */
61
+ declare function customToolToOpenAI(def: AppToolDefinition): OpenAIFunctionTool;
62
+ /** Find a registered custom tool by the name the model called. */
63
+ declare function findCustomTool(name: string, tools: readonly AppToolDefinition[] | undefined): AppToolDefinition | undefined;
64
+
1
65
  /**
2
66
  * The structured agent→app tool side channel, domain-seamed.
3
67
  *
@@ -47,6 +111,9 @@ interface BuildAppToolsOptions {
47
111
  descriptions?: Partial<Record<'submit_proposal' | 'schedule_followup' | 'render_ui' | 'add_citation', string>>;
48
112
  /** The `schedule_followup.priority` enum (defaults to `['low','medium','high']`). */
49
113
  priorityValues?: readonly string[];
114
+ /** Product-registered tools to advertise to the model alongside the four
115
+ * built-ins (appended in order, after the built-ins). */
116
+ customTools?: readonly AppToolDefinition[];
50
117
  }
51
118
  interface SubmitProposalArgs {
52
119
  type: string;
@@ -142,4 +209,4 @@ type AppToolOutcome = {
142
209
  status?: number;
143
210
  };
144
211
 
145
- export type { AddCitationArgs as A, BuildAppToolsOptions as B, RenderUiArgs as R, ScheduleFollowupArgs as S, AddCitationResult as a, AppToolContext as b, AppToolHandlers as c, AppToolOutcome as d, AppToolProducedEvent as e, AppToolTaxonomy as f, RenderUiResult as g, ScheduleFollowupResult as h, SubmitProposalArgs as i, SubmitProposalResult as j };
212
+ export { APP_TOOL_NAMES as A, type BuildAppToolsOptions as B, type OpenAIFunctionTool as O, type RenderUiArgs as R, type ScheduleFollowupArgs as S, type AddCitationArgs as a, type AddCitationResult as b, type AppToolContext as c, type AppToolDefinition as d, type AppToolHandlers as e, type AppToolName as f, type AppToolOutcome as g, type AppToolProducedEvent as h, type AppToolTaxonomy as i, type RenderUiResult as j, type ScheduleFollowupResult as k, type SubmitProposalArgs as l, type SubmitProposalResult as m, buildAppToolOpenAITools as n, customToolToOpenAI as o, defineAppTool as p, findCustomTool as q, isAppToolName as r };
@@ -229,6 +229,63 @@ interface UseSandboxTerminalConnectionResult extends SandboxTerminalConnection {
229
229
  connect: () => Promise<void>;
230
230
  }
231
231
  declare function useSandboxTerminalConnection(opts: UseSandboxTerminalConnectionOptions): UseSandboxTerminalConnectionResult;
232
+ /**
233
+ * Stable-per-tab, unique-per-client terminal connection id.
234
+ *
235
+ * Persists in `sessionStorage` so a reload in the same tab reuses the id (the
236
+ * sidecar restores the same PTY session via `TerminalView.connectionId`), while
237
+ * separate tabs/windows each get a distinct id. Pass the result as
238
+ * `TerminalView`'s `connectionId`. Without it (e.g. gtm-agent today) every tab
239
+ * shares one connection id and their reconnects evict each other.
240
+ *
241
+ * Falls back to an ephemeral id when `sessionStorage` is unavailable (SSR,
242
+ * privacy mode) — still unique per call, just not reload-stable.
243
+ */
244
+ declare function tabTerminalConnectionId(storageKey?: string): string;
245
+
246
+ /**
247
+ * `WorkspaceTerminalPanel` — the shared sandbox-terminal surface: a header with
248
+ * a status badge, connect/provisioning/error states with a retry, and the lazy
249
+ * `TerminalView` (from `@tangle-network/sandbox-ui`) mounted only once the
250
+ * connection is live. creative-agent and gtm-agent each hand-roll a structurally
251
+ * identical panel; only the copy and the status-tone map are app-specific, so
252
+ * those are props and everything else lives here.
253
+ *
254
+ * Pair it with {@link useSandboxTerminalConnection} (the `connection` prop) and
255
+ * {@link tabTerminalConnectionId} (the `connectionId` prop) so reloads restore
256
+ * the same PTY and separate tabs don't evict each other.
257
+ *
258
+ * Styling matches the rest of `web-react`: Tailwind over the shared design
259
+ * tokens; glyphs inline; no icon/UI library.
260
+ */
261
+
262
+ type TerminalStatusTone = 'idle' | 'connecting' | 'connected' | 'error';
263
+ interface TerminalStatusDisplay {
264
+ tone: TerminalStatusTone;
265
+ label: string;
266
+ }
267
+ interface WorkspaceTerminalPanelProps {
268
+ /** Live connection state (from {@link useSandboxTerminalConnection}). */
269
+ connection: SandboxTerminalConnection;
270
+ /** Stable per-tab id (from {@link tabTerminalConnectionId}) so the sidecar
271
+ * restores the same PTY across remounts and tabs don't collide. */
272
+ connectionId?: string;
273
+ /** Header title. Default "Terminal". */
274
+ title?: string;
275
+ /** Header subtitle / sandbox label. */
276
+ subtitle?: string;
277
+ /** Whether the terminal tab is visible (forwarded to `TerminalView` for fit). */
278
+ isActive?: boolean;
279
+ /** Reconnect handler — wire to the hook's `connect`. Shown on idle/error. */
280
+ onRetry?: () => void;
281
+ /** Map a `connection.status` to a badge tone + label. The default covers
282
+ * idle/provisioning/running/error; override for app-specific vocabulary. */
283
+ statusDisplay?: (connection: SandboxTerminalConnection) => TerminalStatusDisplay;
284
+ /** Extra header content, right-aligned (actions, sandbox id, …). */
285
+ headerExtra?: ReactNode;
286
+ className?: string;
287
+ }
288
+ declare function WorkspaceTerminalPanel({ connection, connectionId, title, subtitle, isActive, onRetry, statusDisplay, headerExtra, className, }: WorkspaceTerminalPanelProps): ReactNode;
232
289
 
233
290
  /**
234
291
  * `SeatPaywall` — the shared "unlock this product" screen every agent app
@@ -459,4 +516,4 @@ type ToolDetailRenderers = Record<string, (call: ChatToolCallInfo, message: Chat
459
516
  */
460
517
  declare function ChatMessages({ messages, models, renderMarkdown, renderExtras, userLabel, agentLabel, loading, approval, onToolCallClick, toolRenderers, error, onRetry, renderEmpty, }: ChatMessagesProps): react.JSX.Element;
461
518
 
462
- export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, type ChatMessageMetrics, ChatMessages, type ChatMessagesProps, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ConsumeChatStreamResult, EffortPicker, type EffortPickerProps, FlowWaterfall, type FlowWaterfallProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, type SandboxTerminalConnection, type SandboxTerminalConnectionResponse, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseSandboxTerminalConnectionOptions, type UseSandboxTerminalConnectionResult, type WaterfallRow, activityTone, consumeChatStream, dispatchChatStreamLine, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, mergeActivityPages, nextRevealCount, pendingApprovalOf, streamChatTurn, usePending, usePopover, useSandboxTerminalConnection, useSmoothText, waterfallLayout };
519
+ export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, type ChatMessageMetrics, ChatMessages, type ChatMessagesProps, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ConsumeChatStreamResult, EffortPicker, type EffortPickerProps, FlowWaterfall, type FlowWaterfallProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, type SandboxTerminalConnection, type SandboxTerminalConnectionResponse, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type TerminalStatusDisplay, type TerminalStatusTone, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseSandboxTerminalConnectionOptions, type UseSandboxTerminalConnectionResult, type WaterfallRow, WorkspaceTerminalPanel, type WorkspaceTerminalPanelProps, activityTone, consumeChatStream, dispatchChatStreamLine, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, mergeActivityPages, nextRevealCount, pendingApprovalOf, streamChatTurn, tabTerminalConnectionId, usePending, usePopover, useSandboxTerminalConnection, useSmoothText, waterfallLayout };