@m6d/cortex-cli 1.1.0 → 1.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.
- package/package.json +1 -1
- package/src/contracts/interactive.ts +53 -0
- package/src/contracts/runtime.ts +22 -0
- package/src/contracts/wire.ts +32 -0
package/package.json
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The embed ↔ widget handshake for interactive 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:interactive", 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`, and treats the payload as untrusted — for
|
|
14
|
+
* tools with a verify endpoint the server re-checks the reference before the
|
|
15
|
+
* agent sees a result.
|
|
16
|
+
*
|
|
17
|
+
* Like `wire.ts`, 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 INTERACTIVE_MESSAGE_TYPE = "cortex:interactive";
|
|
23
|
+
|
|
24
|
+
export const INTERACTIVE_STATUSES = ["completed", "cancelled", "failed"] as const;
|
|
25
|
+
|
|
26
|
+
export type InteractiveStatus = (typeof INTERACTIVE_STATUSES)[number];
|
|
27
|
+
|
|
28
|
+
export type InteractiveHandshake = {
|
|
29
|
+
type: typeof INTERACTIVE_MESSAGE_TYPE;
|
|
30
|
+
status: InteractiveStatus;
|
|
31
|
+
/** Opaque id the tool's verify endpoint resolves (session id, envelope id, …). */
|
|
32
|
+
reference?: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parse a `message` event into a handshake, or null when the origin doesn't
|
|
37
|
+
* match the tool's `embedOrigin` or the payload isn't a well-formed handshake.
|
|
38
|
+
* Call from the widget's `message` listener with `event.data` / `event.origin`.
|
|
39
|
+
*/
|
|
40
|
+
export function parseInteractiveHandshake(data: unknown, origin: string, embedOrigin: string) {
|
|
41
|
+
if (origin !== embedOrigin) return null;
|
|
42
|
+
if (typeof data !== "object" || data === null) return null;
|
|
43
|
+
const message = data as Record<string, unknown>;
|
|
44
|
+
if (message["type"] !== INTERACTIVE_MESSAGE_TYPE) return null;
|
|
45
|
+
const status = INTERACTIVE_STATUSES.find((known) => known === message["status"]);
|
|
46
|
+
if (!status) return null;
|
|
47
|
+
const reference = message["reference"];
|
|
48
|
+
return {
|
|
49
|
+
type: INTERACTIVE_MESSAGE_TYPE,
|
|
50
|
+
status,
|
|
51
|
+
...(typeof reference === "string" ? { reference } : {}),
|
|
52
|
+
} satisfies InteractiveHandshake;
|
|
53
|
+
}
|
package/src/contracts/runtime.ts
CHANGED
|
@@ -89,6 +89,19 @@ export const knowledgeChunkSchema = z.object({
|
|
|
89
89
|
}),
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Runtime contract §5.4: present on signatures of `interactive` tools — flows
|
|
94
|
+
* the end user completes in an embedded surface inside the chat widget. The
|
|
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.
|
|
97
|
+
*/
|
|
98
|
+
export const toolInteractionSchema = z.object({
|
|
99
|
+
surface: z.enum(["inline", "modal"]),
|
|
100
|
+
embedOrigin: z.url(),
|
|
101
|
+
hasVerify: z.boolean(),
|
|
102
|
+
resultDelivery: z.enum(["agent", "endpoint", "both"]),
|
|
103
|
+
});
|
|
104
|
+
|
|
92
105
|
export const toolSignatureSchema = z.object({
|
|
93
106
|
toolId: z.uuid(),
|
|
94
107
|
name: z.string().regex(TOOL_NAME_PATTERN),
|
|
@@ -98,6 +111,11 @@ export const toolSignatureSchema = z.object({
|
|
|
98
111
|
signature: z.string(),
|
|
99
112
|
score: z.number().nullable(),
|
|
100
113
|
pinned: z.boolean(),
|
|
114
|
+
interaction: toolInteractionSchema.optional(),
|
|
115
|
+
/** Interactive tools only: the published input JSON Schema, verbatim.
|
|
116
|
+
* Client-executed declarations need a real schema — the rendered
|
|
117
|
+
* `signature` text alone is not enough for function calling. */
|
|
118
|
+
inputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
101
119
|
});
|
|
102
120
|
|
|
103
121
|
export const serviceCardSchema = z.object({
|
|
@@ -194,6 +212,9 @@ export const searchKnowledgeResponseSchema = z.object({
|
|
|
194
212
|
|
|
195
213
|
export const executeRequestSchema = z.object({
|
|
196
214
|
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(),
|
|
197
218
|
context: z
|
|
198
219
|
.object({
|
|
199
220
|
threadId: z.string().max(128).optional(),
|
|
@@ -236,6 +257,7 @@ export const runtimeErrorSchema = z.object({
|
|
|
236
257
|
}),
|
|
237
258
|
});
|
|
238
259
|
|
|
260
|
+
export type ToolInteraction = z.infer<typeof toolInteractionSchema>;
|
|
239
261
|
export type RuntimeAgentConfig = z.infer<typeof runtimeAgentConfigSchema>;
|
|
240
262
|
export type ResolveRequest = z.input<typeof resolveRequestSchema>;
|
|
241
263
|
export type ResolveResponse = z.infer<typeof resolveResponseSchema>;
|
package/src/contracts/wire.ts
CHANGED
|
@@ -70,12 +70,29 @@ export type TokenUsage = {
|
|
|
70
70
|
total: number;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* How to launch one interactive tool: stamped by the server, per tool name, on
|
|
75
|
+
* the metadata of an assistant message that may carry its pending call. Kept in
|
|
76
|
+
* the message so the binding survives server restarts while a run is parked.
|
|
77
|
+
*/
|
|
78
|
+
export type InteractiveToolBinding = {
|
|
79
|
+
toolId: string;
|
|
80
|
+
surface: "inline" | "modal";
|
|
81
|
+
embedOrigin: string;
|
|
82
|
+
hasVerify: boolean;
|
|
83
|
+
resultDelivery: "agent" | "endpoint" | "both";
|
|
84
|
+
};
|
|
85
|
+
|
|
73
86
|
export type MessageMetadata = {
|
|
74
87
|
modelId?: string;
|
|
75
88
|
providerMetadata?: unknown;
|
|
76
89
|
isAborted?: boolean;
|
|
77
90
|
tokenUsage?: TokenUsage;
|
|
78
91
|
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>;
|
|
79
96
|
};
|
|
80
97
|
|
|
81
98
|
/**
|
|
@@ -93,6 +110,21 @@ export type CortexMessage<TPart = unknown> = {
|
|
|
93
110
|
metadata?: MessageMetadata;
|
|
94
111
|
};
|
|
95
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Response of `POST /chat/:chatId/tools/:toolCallId/initiate`. `interactive:
|
|
115
|
+
* false` means the pending call is not an interactive CC tool — the widget
|
|
116
|
+
* falls back to its default rendering for the call. The payload is for the
|
|
117
|
+
* widget only; it never reaches the LLM.
|
|
118
|
+
*/
|
|
119
|
+
export type InteractiveInitiateResult =
|
|
120
|
+
| { interactive: false }
|
|
121
|
+
| {
|
|
122
|
+
interactive: true;
|
|
123
|
+
embedUrl: string;
|
|
124
|
+
surface: "inline" | "modal";
|
|
125
|
+
embedOrigin: string;
|
|
126
|
+
};
|
|
127
|
+
|
|
96
128
|
export type ThreadCreatedEvent = {
|
|
97
129
|
type: "thread:created";
|
|
98
130
|
payload: { thread: ThreadSummary };
|