@m6d/cortex-server 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +23 -9
  2. package/contracts/README.md +22 -8
  3. package/contracts/src/client-tools/index.ts +56 -0
  4. package/contracts/src/graph/index.ts +30 -0
  5. package/contracts/{runtime.ts → src/runtime/index.ts} +7 -11
  6. package/contracts/{wire.ts → src/wire/index.ts} +25 -13
  7. package/dist/contracts/{graph.d.ts → src/graph/index.d.ts} +8 -8
  8. package/dist/contracts/{runtime.d.ts → src/runtime/index.d.ts} +9 -42
  9. package/dist/contracts/{wire.d.ts → src/wire/index.d.ts} +23 -13
  10. package/dist/src/lib/adapters/database/index.d.ts +0 -7
  11. package/dist/src/lib/adapters/database/message-content.d.ts +1 -2
  12. package/dist/src/lib/adapters/database/mssql/index.d.ts +0 -1
  13. package/dist/src/lib/adapters/database/mssql/messages.d.ts +0 -1
  14. package/dist/src/lib/adapters/database/postgres/index.d.ts +0 -1
  15. package/dist/src/lib/adapters/database/postgres/messages.d.ts +0 -1
  16. package/dist/src/lib/ai/cc-runtime.d.ts +2 -2
  17. package/dist/src/lib/ai/client-tools.d.ts +84 -0
  18. package/dist/src/lib/ai/tools/query-graph.tool.d.ts +1 -1
  19. package/dist/src/lib/ai/turn-tools.d.ts +8 -6
  20. package/dist/src/lib/cc/client.d.ts +4 -10
  21. package/dist/src/lib/cc/registry.d.ts +6 -6
  22. package/dist/src/lib/cc/types.d.ts +1 -1
  23. package/dist/src/lib/config.d.ts +9 -4
  24. package/dist/src/lib/graph/index.d.ts +1 -1
  25. package/dist/src/lib/graph/resolver.d.ts +1 -1
  26. package/dist/src/lib/index.d.ts +2 -1
  27. package/dist/src/lib/types.d.ts +2 -2
  28. package/dist/src/lib/ws/connections.d.ts +1 -1
  29. package/package.json +2 -2
  30. package/src/lib/adapters/database/index.ts +0 -12
  31. package/src/lib/adapters/database/mssql/messages.ts +1 -28
  32. package/src/lib/adapters/database/postgres/messages.ts +1 -22
  33. package/src/lib/ai/cc-runtime.ts +7 -7
  34. package/src/lib/ai/client-tools.ts +288 -0
  35. package/src/lib/ai/index.ts +60 -47
  36. package/src/lib/ai/tools/search-tools.tool.ts +2 -2
  37. package/src/lib/ai/turn-tools.ts +7 -8
  38. package/src/lib/cc/client.ts +1 -1
  39. package/src/lib/cc/format.ts +2 -2
  40. package/src/lib/cc/registry.ts +7 -7
  41. package/src/lib/cc/types.ts +1 -1
  42. package/src/lib/config.ts +8 -3
  43. package/src/lib/index.ts +4 -0
  44. package/src/lib/routes/chat.ts +5 -5
  45. package/tsconfig.json +1 -1
  46. package/contracts/graph.ts +0 -36
  47. package/contracts/interactive.ts +0 -53
  48. package/dist/contracts/interactive.d.ts +0 -39
  49. package/dist/src/lib/ai/interactive.d.ts +0 -62
  50. package/src/lib/ai/interactive.ts +0 -364
  51. /package/contracts/{graph → src/graph/clients}/embed.ts +0 -0
  52. /package/contracts/{graph → src/graph/clients}/neo4j.ts +0 -0
  53. /package/contracts/{graph → src/graph}/helpers.ts +0 -0
  54. /package/contracts/{graph → src/graph}/schema.ts +0 -0
  55. /package/contracts/{graph → src/graph}/types.ts +0 -0
  56. /package/contracts/{rich-text.ts → src/rich-text/index.ts} +0 -0
  57. /package/dist/contracts/{graph → src/graph/clients}/embed.d.ts +0 -0
  58. /package/dist/contracts/{graph → src/graph/clients}/neo4j.d.ts +0 -0
  59. /package/dist/contracts/{graph → src/graph}/helpers.d.ts +0 -0
  60. /package/dist/contracts/{graph → src/graph}/schema.d.ts +0 -0
  61. /package/dist/contracts/{graph → src/graph}/types.d.ts +0 -0
  62. /package/dist/contracts/{rich-text.d.ts → src/rich-text/index.d.ts} +0 -0
package/README.md CHANGED
@@ -64,15 +64,29 @@ Only `database`, `model`, and `agents` are required for a minimal setup. `storag
64
64
 
65
65
  Each key in `agents` becomes a route prefix (e.g. `assistant` → `/agents/assistant/...`). Agents can define per-agent `systemPrompt`, `tools`, `backendFetch`, `loadSessionData`, `resolveRequestContext`, and lifecycle hooks (`onToolCall`, `onStreamFinish`).
66
66
 
67
- ## Interactive tools
68
-
69
- Control-Center tools published with kind "interactive" are declared to the
70
- model as client-executed tools: the call streams to the widget, the run parks,
71
- and `POST /chat/:chatId/tools/:toolCallId/initiate` hands the widget its embed
72
- payload (never the model). When the widget answers, the server re-establishes
73
- the result through the tool's verify endpoint and applies the tool's result
74
- delivery masking before the model reads it. See
75
- `apps/cortex-cc/docs/interactive-tools.md` for authoring them.
67
+ ## Client tools
68
+
69
+ A tool in an agent's `tools` with an `execute` function runs on the server. One
70
+ without is a static client tool: it is declared to the model, the call streams
71
+ to the widget, and the host app answers it via `hooks.onToolCall` (or a
72
+ `toolComponents` entry calling `setOutput`).
73
+
74
+ ```ts
75
+ const getBrowserTimezone = toolDefinition({
76
+ name: "getBrowserTimezone",
77
+ description: "Read the user's IANA time zone from their browser.",
78
+ inputSchema: z.object({}),
79
+ }).client();
80
+ // agents.sample.tools = [getBrowserTimezone]
81
+ ```
82
+
83
+ Control-Center tools published with type "embedded" are the dynamic client
84
+ tools: declared the same way, but the widget first calls
85
+ `POST /chat/:chatId/tools/:toolCallId/initiate`, which runs the tool's endpoint
86
+ server-to-server and hands the widget its embed payload (never the model).
87
+ The result the embedded page reports back is relayed to the agent as-is —
88
+ verifying it is the integrating backend's job. See
89
+ `apps/cortex-cc/docs/client-tools.md` for authoring them.
76
90
 
77
91
  ## Requirements
78
92
 
@@ -4,18 +4,32 @@ The shapes both sides of a cortex boundary must agree on. Private on purpose —
4
4
  it never publishes; each publishable package carries its own copy:
5
5
 
6
6
  - `@m6d/cortex-server` and `@m6d/cortex-cli` publish raw source, so their
7
- `prepack` vendors a copy of this directory into the tarball (`contracts/` and
7
+ `prepack` vendors a copy of `src/` into the tarball (`contracts/src/` and
8
8
  `src/contracts/` respectively), resolved there by their shipped tsconfig paths.
9
9
  - `@m6d/cortex-angular` and `@m6d/cortex-react` compile the parts they import
10
- into their build artifacts.
10
+ into their build artifacts (angular's `vendor` copies the seam directories
11
+ into `src/internal/`).
11
12
 
12
- Three boundaries, one subpath each:
13
+ ## Layout
13
14
 
14
- | import | boundary |
15
- | --------------------------- | ------------------------------------------------------------- |
16
- | `@cortex/contracts/wire` | chat client server (HTTP/WebSocket types) |
17
- | `@cortex/contracts/runtime` | cortex-cc console server runtime API (zod schemas) |
18
- | `@cortex/contracts/graph` | graph authoring (cli) ↔ server (vocabulary, helpers, clients) |
15
+ Every seam is a directory: `src/<seam>/index.ts`, split into focused files
16
+ under the directory where that helps (see `graph/`). The `exports` map is a
17
+ single wildcard (`"./*": "./src/*/index.ts"`), so adding a seam is adding a
18
+ directory no manifest edit, no consumer tsconfig edit for wildcard-mapped
19
+ consumers (server, cli, sample-server, cc).
20
+
21
+ | import | boundary | consumers |
22
+ | -------------------------------- | ---------------------------------------------------- | ------------------------------------------------------- |
23
+ | `@cortex/contracts/wire` | chat client ↔ server (HTTP/WebSocket types) | server, client SDKs (`internal/client`, angular, react) |
24
+ | `@cortex/contracts/client-tools` | embedded page ↔ chat widget handshake | server, client SDKs |
25
+ | `@cortex/contracts/runtime` | cortex-cc console ↔ server runtime API (zod schemas) | server, cortex-cc |
26
+ | `@cortex/contracts/rich-text` | prompt/description grammar (mentions, variables) | server, cortex-cc |
27
+ | `@cortex/contracts/graph` | graph authoring (cli) ↔ server (vocabulary, helpers) | server, cortex-cli |
28
+
29
+ `src/graph/clients/` is the one deliberate exception to "contracts only":
30
+ `neo4j.ts` and `embed.ts` are runtime I/O clients shared by the CLI and the
31
+ server. They live here so there is exactly one copy, vendored the same way as
32
+ everything else; they are re-exported through `@cortex/contracts/graph`.
19
33
 
20
34
  Everything is consumed as TypeScript source — no build, no dist. Nothing here
21
35
  has a runtime dependency beyond zod (for `/runtime`), and nothing here may grow
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The embed ↔ widget handshake for client tools.
3
+ *
4
+ * A page embedded by the chat widget (a hosted checkout, signing page, …)
5
+ * reports its outcome with:
6
+ *
7
+ * window.parent.postMessage(
8
+ * { type: "cortex:client-tool", status: "completed", reference: "session_123" },
9
+ * "*",
10
+ * );
11
+ *
12
+ * The widget accepts the message only when the event's origin matches the
13
+ * tool's configured `embedOrigin`. The payload is the page's claim, relayed to
14
+ * the agent as-is: cortex does not verify it, and anything that must actually
15
+ * be true lives in the integrating backend's own records.
16
+ *
17
+ * Like the wire seam, this file is compiled into the client SDKs and must stay
18
+ * free of runtime dependencies. It is also the spec any future SDK (Flutter)
19
+ * reimplements against.
20
+ */
21
+
22
+ export const CLIENT_TOOL_MESSAGE_TYPE = "cortex:client-tool";
23
+
24
+ export const CLIENT_TOOL_STATUSES = ["completed", "cancelled", "failed"] as const;
25
+
26
+ export type ClientToolStatus = (typeof CLIENT_TOOL_STATUSES)[number];
27
+
28
+ export type ClientToolHandshake = {
29
+ type: typeof CLIENT_TOOL_MESSAGE_TYPE;
30
+ status: ClientToolStatus;
31
+ /** Opaque id for the integrating backend's own bookkeeping (session id, envelope id, …). */
32
+ reference?: string;
33
+ /** Optional payload passed through to the agent as part of the tool result. */
34
+ result?: unknown;
35
+ };
36
+
37
+ /**
38
+ * Parse a `message` event into a handshake, or null when the origin doesn't
39
+ * match the tool's `embedOrigin` or the payload isn't a well-formed handshake.
40
+ * Call from the widget's `message` listener with `event.data` / `event.origin`.
41
+ */
42
+ export function parseClientToolHandshake(data: unknown, origin: string, embedOrigin: string) {
43
+ if (origin !== embedOrigin) return null;
44
+ if (typeof data !== "object" || data === null) return null;
45
+ const message = data as Record<string, unknown>;
46
+ if (message["type"] !== CLIENT_TOOL_MESSAGE_TYPE) return null;
47
+ const status = CLIENT_TOOL_STATUSES.find((known) => known === message["status"]);
48
+ if (!status) return null;
49
+ const reference = message["reference"];
50
+ return {
51
+ type: CLIENT_TOOL_MESSAGE_TYPE,
52
+ status,
53
+ ...(typeof reference === "string" ? { reference } : {}),
54
+ ...(message["result"] !== undefined ? { result: message["result"] } : {}),
55
+ } satisfies ClientToolHandshake;
56
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The graph contract — the knowledge-graph vocabulary, authoring types and
3
+ * clients that `@m6d/cortex-cli` writes with and `@m6d/cortex-server` reads
4
+ * with. `@m6d/cortex-server` re-exports all of it, so a project authoring
5
+ * domains still has exactly one import path.
6
+ */
7
+
8
+ export type { GraphSchema } from "./schema";
9
+ export { GRAPH_SCHEMA, GRAPH_SCHEMA_VERSION } from "./schema";
10
+
11
+ export type {
12
+ EndpointScalarType,
13
+ EndpointProperty,
14
+ ResponseKind,
15
+ AutoGenerated,
16
+ ConceptDef,
17
+ EndpointDef,
18
+ EndpointInput,
19
+ ServiceDef,
20
+ RuleDef,
21
+ DomainDef,
22
+ } from "./types";
23
+
24
+ export { defineConcept, defineRule, defineService, defineDomain, defineEndpoint } from "./helpers";
25
+
26
+ export type { Neo4jConfig, Neo4jClient } from "./clients/neo4j";
27
+ export { createNeo4jClient } from "./clients/neo4j";
28
+
29
+ export type { EmbedFn, EmbeddingProviderConfig } from "./clients/embed";
30
+ export { createEmbedder } from "./clients/embed";
@@ -90,16 +90,15 @@ export const knowledgeChunkSchema = z.object({
90
90
  });
91
91
 
92
92
  /**
93
- * Runtime contract §5.4: present on signatures of `interactive` tools — flows
93
+ * Runtime contract §5.4: present on signatures of `embedded` tools — flows
94
94
  * the end user completes in an embedded surface inside the chat widget. The
95
95
  * tool's endpoint fields act as the *initiate* call (returns the embed URL);
96
- * `hasVerify` marks a second, server-trusted call that settles the result.
96
+ * the result the page reports back is relayed as-is verifying it is the
97
+ * integrating backend's job.
97
98
  */
98
- export const toolInteractionSchema = z.object({
99
+ export const toolEmbedSchema = z.object({
99
100
  surface: z.enum(["inline", "modal"]),
100
101
  embedOrigin: z.url(),
101
- hasVerify: z.boolean(),
102
- resultDelivery: z.enum(["agent", "endpoint", "both"]),
103
102
  });
104
103
 
105
104
  export const toolSignatureSchema = z.object({
@@ -111,8 +110,8 @@ export const toolSignatureSchema = z.object({
111
110
  signature: z.string(),
112
111
  score: z.number().nullable(),
113
112
  pinned: z.boolean(),
114
- interaction: toolInteractionSchema.optional(),
115
- /** Interactive tools only: the published input JSON Schema, verbatim.
113
+ embed: toolEmbedSchema.optional(),
114
+ /** Client tools only: the published input JSON Schema, verbatim.
116
115
  * Client-executed declarations need a real schema — the rendered
117
116
  * `signature` text alone is not enough for function calling. */
118
117
  inputSchema: z.record(z.string(), z.unknown()).optional(),
@@ -212,9 +211,6 @@ export const searchKnowledgeResponseSchema = z.object({
212
211
 
213
212
  export const executeRequestSchema = z.object({
214
213
  input: z.record(z.string(), z.unknown()).default({}),
215
- // Interactive tools only: absent | "initiate" targets the tool's endpoint
216
- // fields, "verify" targets its verify endpoint config.
217
- phase: z.enum(["initiate", "verify"]).optional(),
218
214
  context: z
219
215
  .object({
220
216
  threadId: z.string().max(128).optional(),
@@ -257,7 +253,7 @@ export const runtimeErrorSchema = z.object({
257
253
  }),
258
254
  });
259
255
 
260
- export type ToolInteraction = z.infer<typeof toolInteractionSchema>;
256
+ export type ToolEmbed = z.infer<typeof toolEmbedSchema>;
261
257
  export type RuntimeAgentConfig = z.infer<typeof runtimeAgentConfigSchema>;
262
258
  export type ResolveRequest = z.input<typeof resolveRequestSchema>;
263
259
  export type ResolveResponse = z.infer<typeof resolveResponseSchema>;
@@ -71,16 +71,14 @@ export type TokenUsage = {
71
71
  };
72
72
 
73
73
  /**
74
- * How to launch one interactive tool: stamped by the server, per tool name, on
74
+ * How to launch one client tool: stamped by the server, per tool name, on
75
75
  * the metadata of an assistant message that may carry its pending call. Kept in
76
76
  * the message so the binding survives server restarts while a run is parked.
77
77
  */
78
- export type InteractiveToolBinding = {
78
+ export type ClientToolBinding = {
79
79
  toolId: string;
80
80
  surface: "inline" | "modal";
81
81
  embedOrigin: string;
82
- hasVerify: boolean;
83
- resultDelivery: "agent" | "endpoint" | "both";
84
82
  };
85
83
 
86
84
  export type MessageMetadata = {
@@ -89,10 +87,7 @@ export type MessageMetadata = {
89
87
  isAborted?: boolean;
90
88
  tokenUsage?: TokenUsage;
91
89
  attachments?: AttachmentSummary[];
92
- interactiveTools?: Record<string, InteractiveToolBinding>;
93
- /** Per tool call: the trusted reference its initiate call returned. A
94
- * verified completion must match it — the browser's word is never enough. */
95
- interactiveReferences?: Record<string, string>;
90
+ clientTools?: Record<string, ClientToolBinding>;
96
91
  };
97
92
 
98
93
  /**
@@ -111,15 +106,32 @@ export type CortexMessage<TPart = unknown> = {
111
106
  };
112
107
 
113
108
  /**
114
- * Response of `POST /chat/:chatId/tools/:toolCallId/initiate`. `interactive:
115
- * false` means the pending call is not an interactive CC tool the widget
109
+ * Key under the AG-UI request's `forwardedProps` carrying the answers to
110
+ * parked client tool calls on a continuation request. The server owns the
111
+ * transcript (a continuation sends `messages: []`), so the answered assistant
112
+ * message itself never crosses the wire — the SDK's park-boundary snapshot
113
+ * does not preserve its id, and round-tripping it duplicated the stored
114
+ * message.
115
+ */
116
+ export const CLIENT_TOOL_ANSWERS_KEY = "clientToolAnswers";
117
+
118
+ /** One answered client tool call, applied to the stored transcript server-side. */
119
+ export type ClientToolAnswer = {
120
+ toolCallId: string;
121
+ output: unknown;
122
+ state: "complete" | "error";
123
+ };
124
+
125
+ /**
126
+ * Response of `POST /chat/:chatId/tools/:toolCallId/initiate`. `embed:
127
+ * false` means the pending call is not a CC client tool — the widget
116
128
  * falls back to its default rendering for the call. The payload is for the
117
129
  * widget only; it never reaches the LLM.
118
130
  */
119
- export type InteractiveInitiateResult =
120
- | { interactive: false }
131
+ export type ClientToolInitiateResult =
132
+ | { embed: false }
121
133
  | {
122
- interactive: true;
134
+ embed: true;
123
135
  embedUrl: string;
124
136
  surface: "inline" | "modal";
125
137
  embedOrigin: string;
@@ -4,11 +4,11 @@
4
4
  * with. `@m6d/cortex-server` re-exports all of it, so a project authoring
5
5
  * domains still has exactly one import path.
6
6
  */
7
- export type { GraphSchema } from "./graph/schema";
8
- export { GRAPH_SCHEMA, GRAPH_SCHEMA_VERSION } from "./graph/schema";
9
- export type { EndpointScalarType, EndpointProperty, ResponseKind, AutoGenerated, ConceptDef, EndpointDef, EndpointInput, ServiceDef, RuleDef, DomainDef, } from "./graph/types";
10
- export { defineConcept, defineRule, defineService, defineDomain, defineEndpoint, } from "./graph/helpers";
11
- export type { Neo4jConfig, Neo4jClient } from "./graph/neo4j";
12
- export { createNeo4jClient } from "./graph/neo4j";
13
- export type { EmbedFn, EmbeddingProviderConfig } from "./graph/embed";
14
- export { createEmbedder } from "./graph/embed";
7
+ export type { GraphSchema } from "./schema";
8
+ export { GRAPH_SCHEMA, GRAPH_SCHEMA_VERSION } from "./schema";
9
+ export type { EndpointScalarType, EndpointProperty, ResponseKind, AutoGenerated, ConceptDef, EndpointDef, EndpointInput, ServiceDef, RuleDef, DomainDef, } from "./types";
10
+ export { defineConcept, defineRule, defineService, defineDomain, defineEndpoint } from "./helpers";
11
+ export type { Neo4jConfig, Neo4jClient } from "./clients/neo4j";
12
+ export { createNeo4jClient } from "./clients/neo4j";
13
+ export type { EmbedFn, EmbeddingProviderConfig } from "./clients/embed";
14
+ export { createEmbedder } from "./clients/embed";
@@ -61,23 +61,18 @@ export declare const knowledgeChunkSchema: z.ZodObject<{
61
61
  }, z.core.$strip>;
62
62
  }, z.core.$strip>;
63
63
  /**
64
- * Runtime contract §5.4: present on signatures of `interactive` tools — flows
64
+ * Runtime contract §5.4: present on signatures of `embedded` tools — flows
65
65
  * the end user completes in an embedded surface inside the chat widget. The
66
66
  * tool's endpoint fields act as the *initiate* call (returns the embed URL);
67
- * `hasVerify` marks a second, server-trusted call that settles the result.
67
+ * the result the page reports back is relayed as-is verifying it is the
68
+ * integrating backend's job.
68
69
  */
69
- export declare const toolInteractionSchema: z.ZodObject<{
70
+ export declare const toolEmbedSchema: z.ZodObject<{
70
71
  surface: z.ZodEnum<{
71
72
  inline: "inline";
72
73
  modal: "modal";
73
74
  }>;
74
75
  embedOrigin: z.ZodURL;
75
- hasVerify: z.ZodBoolean;
76
- resultDelivery: z.ZodEnum<{
77
- agent: "agent";
78
- endpoint: "endpoint";
79
- both: "both";
80
- }>;
81
76
  }, z.core.$strip>;
82
77
  export declare const toolSignatureSchema: z.ZodObject<{
83
78
  toolId: z.ZodUUID;
@@ -88,18 +83,12 @@ export declare const toolSignatureSchema: z.ZodObject<{
88
83
  signature: z.ZodString;
89
84
  score: z.ZodNullable<z.ZodNumber>;
90
85
  pinned: z.ZodBoolean;
91
- interaction: z.ZodOptional<z.ZodObject<{
86
+ embed: z.ZodOptional<z.ZodObject<{
92
87
  surface: z.ZodEnum<{
93
88
  inline: "inline";
94
89
  modal: "modal";
95
90
  }>;
96
91
  embedOrigin: z.ZodURL;
97
- hasVerify: z.ZodBoolean;
98
- resultDelivery: z.ZodEnum<{
99
- agent: "agent";
100
- endpoint: "endpoint";
101
- both: "both";
102
- }>;
103
92
  }, z.core.$strip>>;
104
93
  inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
105
94
  }, z.core.$strip>;
@@ -185,18 +174,12 @@ export declare const resolveResponseSchema: z.ZodObject<{
185
174
  signature: z.ZodString;
186
175
  score: z.ZodNullable<z.ZodNumber>;
187
176
  pinned: z.ZodBoolean;
188
- interaction: z.ZodOptional<z.ZodObject<{
177
+ embed: z.ZodOptional<z.ZodObject<{
189
178
  surface: z.ZodEnum<{
190
179
  inline: "inline";
191
180
  modal: "modal";
192
181
  }>;
193
182
  embedOrigin: z.ZodURL;
194
- hasVerify: z.ZodBoolean;
195
- resultDelivery: z.ZodEnum<{
196
- agent: "agent";
197
- endpoint: "endpoint";
198
- both: "both";
199
- }>;
200
183
  }, z.core.$strip>>;
201
184
  inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
202
185
  }, z.core.$strip>>;
@@ -238,18 +221,12 @@ export declare const searchToolsResponseSchema: z.ZodObject<{
238
221
  signature: z.ZodString;
239
222
  score: z.ZodNullable<z.ZodNumber>;
240
223
  pinned: z.ZodBoolean;
241
- interaction: z.ZodOptional<z.ZodObject<{
224
+ embed: z.ZodOptional<z.ZodObject<{
242
225
  surface: z.ZodEnum<{
243
226
  inline: "inline";
244
227
  modal: "modal";
245
228
  }>;
246
229
  embedOrigin: z.ZodURL;
247
- hasVerify: z.ZodBoolean;
248
- resultDelivery: z.ZodEnum<{
249
- agent: "agent";
250
- endpoint: "endpoint";
251
- both: "both";
252
- }>;
253
230
  }, z.core.$strip>>;
254
231
  inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
255
232
  }, z.core.$strip>>;
@@ -276,18 +253,12 @@ export declare const searchServicesResponseSchema: z.ZodObject<{
276
253
  signature: z.ZodString;
277
254
  score: z.ZodNullable<z.ZodNumber>;
278
255
  pinned: z.ZodBoolean;
279
- interaction: z.ZodOptional<z.ZodObject<{
256
+ embed: z.ZodOptional<z.ZodObject<{
280
257
  surface: z.ZodEnum<{
281
258
  inline: "inline";
282
259
  modal: "modal";
283
260
  }>;
284
261
  embedOrigin: z.ZodURL;
285
- hasVerify: z.ZodBoolean;
286
- resultDelivery: z.ZodEnum<{
287
- agent: "agent";
288
- endpoint: "endpoint";
289
- both: "both";
290
- }>;
291
262
  }, z.core.$strip>>;
292
263
  inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
293
264
  }, z.core.$strip>>;
@@ -314,10 +285,6 @@ export declare const searchKnowledgeResponseSchema: z.ZodObject<{
314
285
  }, z.core.$strip>;
315
286
  export declare const executeRequestSchema: z.ZodObject<{
316
287
  input: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
317
- phase: z.ZodOptional<z.ZodEnum<{
318
- verify: "verify";
319
- initiate: "initiate";
320
- }>>;
321
288
  context: z.ZodOptional<z.ZodObject<{
322
289
  threadId: z.ZodOptional<z.ZodString>;
323
290
  userId: z.ZodOptional<z.ZodString>;
@@ -381,7 +348,7 @@ export declare const runtimeErrorSchema: z.ZodObject<{
381
348
  upstreamStatus: z.ZodOptional<z.ZodNumber>;
382
349
  }, z.core.$strip>;
383
350
  }, z.core.$strip>;
384
- export type ToolInteraction = z.infer<typeof toolInteractionSchema>;
351
+ export type ToolEmbed = z.infer<typeof toolEmbedSchema>;
385
352
  export type RuntimeAgentConfig = z.infer<typeof runtimeAgentConfigSchema>;
386
353
  export type ResolveRequest = z.input<typeof resolveRequestSchema>;
387
354
  export type ResolveResponse = z.infer<typeof resolveResponseSchema>;
@@ -51,16 +51,14 @@ export type TokenUsage = {
51
51
  total: number;
52
52
  };
53
53
  /**
54
- * How to launch one interactive tool: stamped by the server, per tool name, on
54
+ * How to launch one client tool: stamped by the server, per tool name, on
55
55
  * the metadata of an assistant message that may carry its pending call. Kept in
56
56
  * the message so the binding survives server restarts while a run is parked.
57
57
  */
58
- export type InteractiveToolBinding = {
58
+ export type ClientToolBinding = {
59
59
  toolId: string;
60
60
  surface: "inline" | "modal";
61
61
  embedOrigin: string;
62
- hasVerify: boolean;
63
- resultDelivery: "agent" | "endpoint" | "both";
64
62
  };
65
63
  export type MessageMetadata = {
66
64
  modelId?: string;
@@ -68,10 +66,7 @@ export type MessageMetadata = {
68
66
  isAborted?: boolean;
69
67
  tokenUsage?: TokenUsage;
70
68
  attachments?: AttachmentSummary[];
71
- interactiveTools?: Record<string, InteractiveToolBinding>;
72
- /** Per tool call: the trusted reference its initiate call returned. A
73
- * verified completion must match it — the browser's word is never enough. */
74
- interactiveReferences?: Record<string, string>;
69
+ clientTools?: Record<string, ClientToolBinding>;
75
70
  };
76
71
  /**
77
72
  * A stored message as it is persisted and served. TanStack AI's `UIMessage`
@@ -88,15 +83,30 @@ export type CortexMessage<TPart = unknown> = {
88
83
  metadata?: MessageMetadata;
89
84
  };
90
85
  /**
91
- * Response of `POST /chat/:chatId/tools/:toolCallId/initiate`. `interactive:
92
- * false` means the pending call is not an interactive CC tool the widget
86
+ * Key under the AG-UI request's `forwardedProps` carrying the answers to
87
+ * parked client tool calls on a continuation request. The server owns the
88
+ * transcript (a continuation sends `messages: []`), so the answered assistant
89
+ * message itself never crosses the wire — the SDK's park-boundary snapshot
90
+ * does not preserve its id, and round-tripping it duplicated the stored
91
+ * message.
92
+ */
93
+ export declare const CLIENT_TOOL_ANSWERS_KEY = "clientToolAnswers";
94
+ /** One answered client tool call, applied to the stored transcript server-side. */
95
+ export type ClientToolAnswer = {
96
+ toolCallId: string;
97
+ output: unknown;
98
+ state: "complete" | "error";
99
+ };
100
+ /**
101
+ * Response of `POST /chat/:chatId/tools/:toolCallId/initiate`. `embed:
102
+ * false` means the pending call is not a CC client tool — the widget
93
103
  * falls back to its default rendering for the call. The payload is for the
94
104
  * widget only; it never reaches the LLM.
95
105
  */
96
- export type InteractiveInitiateResult = {
97
- interactive: false;
106
+ export type ClientToolInitiateResult = {
107
+ embed: false;
98
108
  } | {
99
- interactive: true;
109
+ embed: true;
100
110
  embedUrl: string;
101
111
  surface: "inline" | "modal";
102
112
  embedOrigin: string;
@@ -34,13 +34,6 @@ export type DatabaseAdapter = {
34
34
  upsert(threadId: string, messages: ChatMessage[], options?: {
35
35
  replaceAttachments?: boolean;
36
36
  }): Promise<void>;
37
- /**
38
- * Atomically merges one anchored interactive reference into the
39
- * message's metadata as a single-statement JSON merge — safe under
40
- * concurrent writers across replicas, unlike a read-modify-write of
41
- * the whole message.
42
- */
43
- mergeInteractiveReference(threadId: string, messageId: string, toolCallId: string, reference: string): Promise<void>;
44
37
  };
45
38
  llmRequests: {
46
39
  insert(requests: {
@@ -16,8 +16,7 @@ export declare function withOwnedAttachments(messages: ChatMessage[], replaceAtt
16
16
  providerMetadata?: unknown;
17
17
  isAborted?: boolean;
18
18
  tokenUsage?: import("../../types").TokenUsage;
19
- interactiveTools?: Record<string, import("../..").InteractiveToolBinding>;
20
- interactiveReferences?: Record<string, string>;
19
+ clientTools?: Record<string, import("../..").ClientToolBinding>;
21
20
  };
22
21
  id: string;
23
22
  role: "system" | "user" | "assistant";
@@ -76,7 +76,6 @@ export declare function createMssqlAdapter(connectionString: string, storage?: S
76
76
  upsert(threadId: string, messagesToUpsert: import("../../../types").ChatMessage[], options?: {
77
77
  replaceAttachments?: boolean;
78
78
  }): Promise<void>;
79
- mergeInteractiveReference(threadId: string, messageId: string, toolCallId: string, reference: string): Promise<void>;
80
79
  };
81
80
  llmRequests: {
82
81
  insert(requests: {
@@ -34,5 +34,4 @@ export declare function createMessagesRepository(db: MssqlDb): {
34
34
  upsert(threadId: string, messagesToUpsert: ChatMessage[], options?: {
35
35
  replaceAttachments?: boolean;
36
36
  }): Promise<void>;
37
- mergeInteractiveReference(threadId: string, messageId: string, toolCallId: string, reference: string): Promise<void>;
38
37
  };
@@ -76,7 +76,6 @@ export declare function createPostgresAdapter(connectionString: string, storage?
76
76
  upsert(threadId: string, messagesToUpsert: import("../../../types").ChatMessage[], options?: {
77
77
  replaceAttachments?: boolean;
78
78
  }): Promise<void>;
79
- mergeInteractiveReference(threadId: string, messageId: string, toolCallId: string, reference: string): Promise<void>;
80
79
  };
81
80
  llmRequests: {
82
81
  insert(requests: {
@@ -34,5 +34,4 @@ export declare function createMessagesRepository(db: PostgresDb): {
34
34
  upsert(threadId: string, messagesToUpsert: ChatMessage[], options?: {
35
35
  replaceAttachments?: boolean;
36
36
  }): Promise<void>;
37
- mergeInteractiveReference(threadId: string, messageId: string, toolCallId: string, reference: string): Promise<void>;
38
37
  };
@@ -1,7 +1,7 @@
1
1
  import type { ResolvedCortexAgentConfig } from "../config";
2
2
  import type { Thread } from "../types";
3
3
  import type { ControlCenterClient } from "../cc/client";
4
- import type { CcInteractiveTool, CcToolRegistry } from "../cc/registry";
4
+ import type { CcClientTool, CcToolRegistry } from "../cc/registry";
5
5
  import type { ResolveResponse, RuntimeAgentConfig } from "../cc/types";
6
6
  type CcRuntimeOptions = {
7
7
  ccClient: ControlCenterClient | null;
@@ -48,7 +48,7 @@ export declare function createCcRuntime(options: CcRuntimeOptions): {
48
48
  publishedAt: string;
49
49
  };
50
50
  registry: CcToolRegistry;
51
- interactiveTools: Map<string, CcInteractiveTool>;
51
+ clientTools: Map<string, CcClientTool>;
52
52
  threadId: string;
53
53
  turnKey: string;
54
54
  userId: string;