@m6d/cortex-cli 0.22.0 → 0.24.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/commands/management.ts +8 -5
- package/src/commands/setup.ts +15 -8
- package/src/contracts/management/procedures.generated.ts +792 -178
- package/src/contracts/manifest/index.ts +413 -97
- package/src/contracts/pattern/index.ts +276 -0
- package/src/contracts/runs/index.ts +187 -0
- package/src/contracts/schedule/index.ts +62 -0
- package/src/contracts/server/index.ts +99 -28
- package/src/contracts/triggers/index.ts +36 -93
- package/src/contracts/wire/index.ts +119 -55
- package/src/management/flags.ts +14 -4
- package/src/scaffold/files.ts +8 -3
- package/src/ui/prompts.ts +18 -24
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { CONNECT_ACCOUNT_TOOL, REQUEST_LOCATION_TOOL } from "../client-tools/index";
|
|
3
3
|
import { backendErrorSchema } from "../errors/index";
|
|
4
|
-
import {
|
|
4
|
+
import { runRecordSchema, runWaitSchema } from "../runs/index";
|
|
5
|
+
import { TRIGGER_ANSWER_TOOL_NAME } from "../triggers/index";
|
|
5
6
|
import { isRecord, readJsonPointer } from "../json/index";
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
APPROVAL_TITLE_FIELD,
|
|
9
|
+
CANCEL_TASK_TOOL,
|
|
10
|
+
DELEGATE_TASK_TOOL,
|
|
11
|
+
LOCALES,
|
|
12
|
+
SCHEDULE_WAKE_TOOL,
|
|
13
|
+
} from "../wire/index";
|
|
7
14
|
|
|
8
15
|
/*
|
|
9
16
|
* The server protocol: what Cortex calls on a customer's backend. `GET /`
|
|
10
17
|
* answers the manifest (the variables it fills, the native tools it runs,
|
|
11
|
-
* whether it verifies end-user tokens,
|
|
18
|
+
* whether it verifies end-user tokens, whether Cortex may act for a user
|
|
19
|
+
* whose token is gone, the events it hears); the other
|
|
12
20
|
* routes are the calls behind them. Every request carries the server key as
|
|
13
21
|
* its bearer, and a run-scoped one also the run's token in
|
|
14
22
|
* `END_USER_TOKEN_HEADER` when the run has one. A refusal on any route
|
|
@@ -121,6 +129,14 @@ export const BUILT_IN_VARIABLES = [
|
|
|
121
129
|
type: "string",
|
|
122
130
|
computed: true,
|
|
123
131
|
},
|
|
132
|
+
{
|
|
133
|
+
name: "threadId",
|
|
134
|
+
description:
|
|
135
|
+
"The thread's id: a backend that keeps it fires a trigger back into the thread",
|
|
136
|
+
example: "3d206d66-4b28-4608-904c-3e8599e63a7b",
|
|
137
|
+
type: "string",
|
|
138
|
+
computed: true,
|
|
139
|
+
},
|
|
124
140
|
] as const satisfies ReadonlyArray<VariableDeclaration>;
|
|
125
141
|
|
|
126
142
|
/**
|
|
@@ -129,6 +145,8 @@ export const BUILT_IN_VARIABLES = [
|
|
|
129
145
|
* carries them to the .NET SDK.
|
|
130
146
|
*/
|
|
131
147
|
export const BUILT_IN_TOOL_NAMES = [
|
|
148
|
+
CANCEL_TASK_TOOL,
|
|
149
|
+
DELEGATE_TASK_TOOL,
|
|
132
150
|
"describeDataset",
|
|
133
151
|
"executeCode",
|
|
134
152
|
"fetchImage",
|
|
@@ -138,6 +156,7 @@ export const BUILT_IN_TOOL_NAMES = [
|
|
|
138
156
|
"readReport",
|
|
139
157
|
"searchRegistries",
|
|
140
158
|
"searchThreadHistory",
|
|
159
|
+
SCHEDULE_WAKE_TOOL,
|
|
141
160
|
REQUEST_LOCATION_TOOL,
|
|
142
161
|
CONNECT_ACCOUNT_TOOL,
|
|
143
162
|
TRIGGER_ANSWER_TOOL_NAME,
|
|
@@ -188,33 +207,58 @@ export const serverToolSchema = z.object({
|
|
|
188
207
|
});
|
|
189
208
|
export type ServerTool = z.infer<typeof serverToolSchema>;
|
|
190
209
|
|
|
191
|
-
/**
|
|
192
|
-
|
|
210
|
+
/**
|
|
211
|
+
* The events a server hears at `POST /events/:event`, and a webhook
|
|
212
|
+
* delivers: a run that waits on a decision, and a run a trigger started
|
|
213
|
+
* that ended. A chat's runs end in their widget, which follows them.
|
|
214
|
+
*/
|
|
215
|
+
export const SERVER_EVENTS = ["run_waiting", "run_finished"] as const;
|
|
216
|
+
export type ServerEventName = (typeof SERVER_EVENTS)[number];
|
|
193
217
|
|
|
194
218
|
/** The header a webhook delivery names its event in, so a receiver tells events apart without parsing the body. */
|
|
195
219
|
export const EVENT_HEADER = "X-Cortex-Event";
|
|
196
220
|
|
|
197
|
-
/**
|
|
198
|
-
|
|
199
|
-
* receiver hears of it: a webhook's body and the agent's server's event are
|
|
200
|
-
* this one object. `firingId` and `triggerName` are set when a trigger
|
|
201
|
-
* started the run, which is what a receiver answering through the firing
|
|
202
|
-
* route needs. Every parked call is named; one whose input would carry the
|
|
203
|
-
* event past `SERVER_REQUEST_MAX_BYTES` comes without its input.
|
|
204
|
-
*/
|
|
205
|
-
export const approvalRequestedEventSchema = z.object({
|
|
206
|
-
event: z.literal("approval_requested"),
|
|
221
|
+
/** What every event names: the agent it happened on, the run, the trigger that started that run if one did, and when. */
|
|
222
|
+
const runEventFields = {
|
|
207
223
|
agentName: nameSchema,
|
|
208
224
|
agentId: z.uuid(),
|
|
209
|
-
|
|
210
|
-
runId: z.string(),
|
|
211
|
-
userId: z.string(),
|
|
212
|
-
firingId: z.uuid().optional(),
|
|
225
|
+
runId: z.uuid(),
|
|
213
226
|
triggerName: z.string().optional(),
|
|
214
|
-
approvals: z.array(pendingApprovalSchema.partial({ input: true })),
|
|
215
227
|
occurredAt: z.iso.datetime(),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* A run parked on calls that wait for a decision, as every receiver hears
|
|
232
|
+
* of it: a webhook's body and the agent's server's event are this one
|
|
233
|
+
* object. `runId` names the run a receiver decides through
|
|
234
|
+
* `POST /agents/:agentName/runs/:id/answer`. Every call it waits on is
|
|
235
|
+
* named, a client tool's among them; one whose input would carry the event
|
|
236
|
+
* past `SERVER_REQUEST_MAX_BYTES` comes without its input. A run waiting
|
|
237
|
+
* only on its widget's calls is not announced.
|
|
238
|
+
*/
|
|
239
|
+
export const runWaitingEventSchema = z.object({
|
|
240
|
+
event: z.literal("run_waiting"),
|
|
241
|
+
...runEventFields,
|
|
242
|
+
threadId: z.string(),
|
|
243
|
+
userId: z.string(),
|
|
244
|
+
waits: z.array(runWaitSchema.partial({ input: true })),
|
|
245
|
+
});
|
|
246
|
+
export type RunWaitingEvent = z.infer<typeof runWaitingEventSchema>;
|
|
247
|
+
|
|
248
|
+
/** A run a trigger started that ended, with its record: how it ended and what it answered with. */
|
|
249
|
+
export const runFinishedEventSchema = z.object({
|
|
250
|
+
event: z.literal("run_finished"),
|
|
251
|
+
...runEventFields,
|
|
252
|
+
run: runRecordSchema,
|
|
216
253
|
});
|
|
217
|
-
export type
|
|
254
|
+
export type RunFinishedEvent = z.infer<typeof runFinishedEventSchema>;
|
|
255
|
+
|
|
256
|
+
/** Any event a receiver hears, told apart by `event`: `POST /events/:event` names it too. */
|
|
257
|
+
export const serverEventSchema = z.discriminatedUnion("event", [
|
|
258
|
+
runWaitingEventSchema,
|
|
259
|
+
runFinishedEventSchema,
|
|
260
|
+
]);
|
|
261
|
+
export type ServerEvent = z.infer<typeof serverEventSchema>;
|
|
218
262
|
|
|
219
263
|
/** What a local `$ref` (`#/$defs/order`) points at in `root`, read as the input compiler reads it; undefined for any other. */
|
|
220
264
|
function pointedAt(root: unknown, ref: string) {
|
|
@@ -305,6 +349,13 @@ export const serverManifestSchema = z.object({
|
|
|
305
349
|
tools.forEach((tool, index) => refuseBlockedApprovalTitle(tool, context, [index]));
|
|
306
350
|
}),
|
|
307
351
|
verify: z.boolean(),
|
|
352
|
+
/**
|
|
353
|
+
* Whether Cortex may act for a user whose token is gone, naming them in
|
|
354
|
+
* the body with `user.delegated`. Without it, such a run names no user
|
|
355
|
+
* to the server (`user: null`, as on a trigger's run), so it never acts
|
|
356
|
+
* for someone who is not there.
|
|
357
|
+
*/
|
|
358
|
+
delegation: z.boolean(),
|
|
308
359
|
events: z.array(z.enum(SERVER_EVENTS)),
|
|
309
360
|
});
|
|
310
361
|
export type ServerManifest = z.infer<typeof serverManifestSchema>;
|
|
@@ -312,9 +363,34 @@ export type ServerManifest = z.infer<typeof serverManifestSchema>;
|
|
|
312
363
|
/** The agent a call is for. */
|
|
313
364
|
const agentSchema = z.object({ id: z.uuid(), name: nameSchema });
|
|
314
365
|
|
|
315
|
-
/**
|
|
366
|
+
/**
|
|
367
|
+
* Why Cortex acts for a user with no valid token of theirs: their message
|
|
368
|
+
* waited past its token (`queued`), or a run (`run`), a schedule (`schedule`)
|
|
369
|
+
* or a trigger (`trigger`) started the work.
|
|
370
|
+
*/
|
|
371
|
+
export const DELEGATION_REASONS = ["queued", "run", "schedule", "trigger"] as const;
|
|
372
|
+
|
|
373
|
+
/** Cortex acting for a user who is not there: why, and the run that acts. */
|
|
374
|
+
export const delegationSchema = z.object({
|
|
375
|
+
reason: z.enum(DELEGATION_REASONS),
|
|
376
|
+
runId: z.uuid(),
|
|
377
|
+
});
|
|
378
|
+
export type Delegation = z.infer<typeof delegationSchema>;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* The end user a run acts for, as their token was verified; null for a
|
|
382
|
+
* trigger's run, and for a run acting for a user who is not there toward a
|
|
383
|
+
* server whose manifest does not set `delegation`. `delegated` when the run acts for them without their
|
|
384
|
+
* token, told only to a server whose manifest sets `delegation`, which
|
|
385
|
+
* then trusts the body's user as it trusts the key: a tool reads it to
|
|
386
|
+
* refuse what a user who is not there should not do.
|
|
387
|
+
*/
|
|
316
388
|
const serverUserSchema = z
|
|
317
|
-
.object({
|
|
389
|
+
.object({
|
|
390
|
+
id: userIdSchema,
|
|
391
|
+
claims: z.record(z.string(), z.unknown()),
|
|
392
|
+
delegated: delegationSchema.optional(),
|
|
393
|
+
})
|
|
318
394
|
.nullable();
|
|
319
395
|
|
|
320
396
|
/** `POST /variables`: the values one thread runs with, asked once per thread. */
|
|
@@ -356,8 +432,3 @@ export const verifyResponseSchema = z.union([
|
|
|
356
432
|
z.object({ sub: z.null() }),
|
|
357
433
|
]);
|
|
358
434
|
export type VerifyResponse = z.infer<typeof verifyResponseSchema>;
|
|
359
|
-
|
|
360
|
-
/** `POST /events/:event`: the body of each event a manifest subscribes to. */
|
|
361
|
-
export const serverEventSchemas = {
|
|
362
|
-
approval_requested: approvalRequestedEventSchema,
|
|
363
|
-
} as const satisfies Record<(typeof SERVER_EVENTS)[number], z.ZodType>;
|
|
@@ -1,116 +1,59 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { inputReceiptSchema, runRecordSchema } from "../runs/index";
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
|
-
* Triggers: named entry points on an agent. A
|
|
7
|
-
* payload and starts at most one run. The end user's message is the built-in
|
|
8
|
-
* `message` trigger; every other trigger is fired by a caller over
|
|
6
|
+
* Triggers: named entry points on an agent. A caller fires one over
|
|
9
7
|
* `POST /agents/:agentName/triggers/:name` with the trigger's secret as its
|
|
10
|
-
* bearer
|
|
8
|
+
* bearer; the fire is an input on the thread the trigger's policy names,
|
|
9
|
+
* and the run that takes it is read and decided under `/runs/:id`. These
|
|
10
|
+
* are the shapes Cortex answers that caller with.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export const MESSAGE_TRIGGER_NAME = "message";
|
|
14
|
-
|
|
15
13
|
/** The tool a trigger run with an output schema answers through; no other tool may take its name. */
|
|
16
14
|
export const TRIGGER_ANSWER_TOOL_NAME = "submitAnswer";
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
"started",
|
|
20
|
-
/** The run parked on a tool that needs approval; `POST .../firings/:id/answer` resumes it. */
|
|
21
|
-
"awaiting_approval",
|
|
22
|
-
"completed",
|
|
23
|
-
"failed",
|
|
24
|
-
"rejected",
|
|
25
|
-
"dropped",
|
|
26
|
-
] as const;
|
|
27
|
-
export type TriggerOutcome = (typeof TRIGGER_OUTCOMES)[number];
|
|
28
|
-
|
|
29
|
-
/** The engine route of agent `agentName`, which the widget chats with and its triggers sit under. */
|
|
16
|
+
/** The engine route of agent `agentName`, which the widget chats with and its triggers and runs sit under. */
|
|
30
17
|
export function agentRoute(agentName: string) {
|
|
31
18
|
return `/agents/${encodeURIComponent(agentName)}`;
|
|
32
19
|
}
|
|
33
20
|
|
|
34
|
-
/** The engine route a trigger is fired at on agent `agentName`; its
|
|
21
|
+
/** The engine route a trigger is fired at on agent `agentName`; its runs are listed under it. */
|
|
35
22
|
export function triggerRoute(agentName: string, name: string) {
|
|
36
23
|
return `${agentRoute(agentName)}/triggers/${encodeURIComponent(name)}`;
|
|
37
24
|
}
|
|
38
25
|
|
|
39
|
-
/**
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
/** The engine route a run of agent `agentName` is read at, and answered and cancelled under. */
|
|
27
|
+
export function runRoute(agentName: string, runId: string) {
|
|
28
|
+
return `${agentRoute(agentName)}/runs/${encodeURIComponent(runId)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** What a fire answers once its run started: its input, run and thread; `GET .../runs/:id` reads the run. */
|
|
32
|
+
export const fireStartedSchema = z.object({
|
|
33
|
+
inputId: z.uuid(),
|
|
34
|
+
state: z.literal("started"),
|
|
35
|
+
runId: z.uuid(),
|
|
36
|
+
threadId: z.uuid(),
|
|
44
37
|
});
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
runId: z.string(),
|
|
52
|
-
}),
|
|
53
|
-
/* The shapes a caller that waited (`?wait=`) gets instead of `started`: the run ended, or it parked for a decision. */
|
|
54
|
-
z.object({
|
|
55
|
-
firingId: z.uuid(),
|
|
56
|
-
outcome: z.literal("awaiting_approval"),
|
|
57
|
-
threadId: z.uuid(),
|
|
58
|
-
runId: z.string(),
|
|
59
|
-
approvals: z.array(pendingApprovalSchema),
|
|
60
|
-
}),
|
|
61
|
-
z.object({
|
|
62
|
-
firingId: z.uuid(),
|
|
63
|
-
outcome: z.literal("completed"),
|
|
64
|
-
threadId: z.uuid(),
|
|
65
|
-
runId: z.string(),
|
|
66
|
-
/** The validated answer when the trigger declares an output schema, else the run's last text (null when it wrote none), cut past 1 MiB with a trailing `…[truncated]`. */
|
|
67
|
-
output: z.unknown(),
|
|
68
|
-
}),
|
|
69
|
-
z.object({
|
|
70
|
-
firingId: z.uuid(),
|
|
71
|
-
outcome: z.literal("failed"),
|
|
72
|
-
threadId: z.uuid(),
|
|
73
|
-
runId: z.string(),
|
|
74
|
-
reason: z.enum(TRIGGER_REASONS).nullable(),
|
|
75
|
-
}),
|
|
76
|
-
z.object({
|
|
77
|
-
firingId: z.uuid(),
|
|
78
|
-
outcome: z.literal("dropped"),
|
|
79
|
-
reason: z.enum(TRIGGER_DROP_REASONS),
|
|
80
|
-
threadId: z.uuid().nullable(),
|
|
81
|
-
}),
|
|
82
|
-
z.object({
|
|
83
|
-
firingId: z.uuid(),
|
|
84
|
-
outcome: z.literal("rejected"),
|
|
85
|
-
issues: z.array(z.object({ path: z.string(), message: z.string() })),
|
|
86
|
-
}),
|
|
87
|
-
]);
|
|
88
|
-
export type TriggerFiringResponse = z.infer<typeof triggerFiringResponseSchema>;
|
|
39
|
+
/** A fire whose payload the trigger refused, each issue at its path. */
|
|
40
|
+
export const fireRejectedSchema = z.object({
|
|
41
|
+
state: z.literal("rejected"),
|
|
42
|
+
issues: z.array(z.object({ path: z.string(), message: z.string() })),
|
|
43
|
+
});
|
|
89
44
|
|
|
90
45
|
/**
|
|
91
|
-
* `POST /agents/:agentName/triggers/:name
|
|
92
|
-
*
|
|
93
|
-
*
|
|
46
|
+
* What `POST /agents/:agentName/triggers/:name` answers as JSON: the run it
|
|
47
|
+
* started (`started`, 202); with `?wait=`, that run once it ended (a
|
|
48
|
+
* `RunRecord`, 200) or parked on a decision (202); the fire's input while it
|
|
49
|
+
* waits on the thread, once refused, or once cancelled before any run took
|
|
50
|
+
* it (an `InputReceipt`: 202, or 409, and 429 for a spent budget or
|
|
51
|
+
* bucket); or a payload the trigger refused (422).
|
|
94
52
|
*/
|
|
95
|
-
export const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
export const triggerFiringRecordSchema = z.object({
|
|
103
|
-
id: z.uuid(),
|
|
104
|
-
triggerName: z.string(),
|
|
105
|
-
threadId: z.uuid().nullable(),
|
|
106
|
-
runId: z.string().nullable(),
|
|
107
|
-
outcome: z.enum(TRIGGER_OUTCOMES),
|
|
108
|
-
reason: z.enum(TRIGGER_REASONS).nullable(),
|
|
109
|
-
/** What a completed run answered with, as a fire's `completed` answer carries it; null otherwise. */
|
|
110
|
-
output: z.unknown(),
|
|
111
|
-
/** The calls an `awaiting_approval` firing waits on; filled by the single-firing read, empty in the list and for every other outcome. */
|
|
112
|
-
approvals: z.array(pendingApprovalSchema),
|
|
113
|
-
createdAt: z.iso.datetime(),
|
|
114
|
-
finishedAt: z.iso.datetime().nullable(),
|
|
115
|
-
});
|
|
116
|
-
export type TriggerFiringRecord = z.infer<typeof triggerFiringRecordSchema>;
|
|
53
|
+
export const fireAnswerSchema = z.union([
|
|
54
|
+
fireStartedSchema,
|
|
55
|
+
fireRejectedSchema,
|
|
56
|
+
inputReceiptSchema,
|
|
57
|
+
runRecordSchema,
|
|
58
|
+
]);
|
|
59
|
+
export type FireAnswer = z.infer<typeof fireAnswerSchema>;
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* alike.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import type { RunReason, RunStatus } from "../runs/index";
|
|
12
|
+
|
|
11
13
|
/** The UI locales every localized value is keyed by; the console's message catalogs follow it. */
|
|
12
14
|
export const LOCALES = ["en", "ar"] as const;
|
|
13
15
|
export type Locale = (typeof LOCALES)[number];
|
|
@@ -31,8 +33,8 @@ export function byLocale<T>(valueOf: (locale: Locale) => T) {
|
|
|
31
33
|
export const TOOL_SURFACES = ["inline", "modal"] as const;
|
|
32
34
|
export type ToolSurface = (typeof TOOL_SURFACES)[number];
|
|
33
35
|
|
|
34
|
-
/** `
|
|
35
|
-
export const MESSAGE_ROLES = ["system", "user", "assistant", "
|
|
36
|
+
/** `event` rows hold something that happened, a trigger's rendered instructions among them; the model sees them as `user` turns. */
|
|
37
|
+
export const MESSAGE_ROLES = ["system", "user", "assistant", "event"] as const;
|
|
36
38
|
export type MessageRole = (typeof MESSAGE_ROLES)[number];
|
|
37
39
|
|
|
38
40
|
/** The fenced blocks an agent may draw in its replies instead of text. */
|
|
@@ -46,6 +48,29 @@ export const DEFAULT_MEDIA_FORMS = [
|
|
|
46
48
|
"map",
|
|
47
49
|
] as const satisfies readonly MediaForm[];
|
|
48
50
|
|
|
51
|
+
/**
|
|
52
|
+
* What an agent does with a message someone sends while a run holds its
|
|
53
|
+
* thread: refuses it, queues it as the next turn, or steers the running turn
|
|
54
|
+
* with it before its next step (one that arrives too late is queued).
|
|
55
|
+
*/
|
|
56
|
+
export const WHILE_BUSY = ["refuse", "queue", "steer"] as const;
|
|
57
|
+
export type WhileBusy = (typeof WHILE_BUSY)[number];
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Where one message sent while a run holds its thread goes, named by its
|
|
61
|
+
* sender under `forwardedProps[MESSAGE_BUSY_KEY]`, or set on a waiting one
|
|
62
|
+
* by `PATCH /threads/:threadId/inputs/:inputId` (`{ busy }`): `steer` joins
|
|
63
|
+
* the running turn, `queue` waits for a turn of its own.
|
|
64
|
+
*/
|
|
65
|
+
export const MESSAGE_BUSY = ["queue", "steer"] as const;
|
|
66
|
+
export type MessageBusy = (typeof MESSAGE_BUSY)[number];
|
|
67
|
+
export const MESSAGE_BUSY_KEY = "busy";
|
|
68
|
+
|
|
69
|
+
/** What a message sent while a run holds the thread does: its sender's pick, never past an agent that refuses. */
|
|
70
|
+
export function busyFor(whileBusy: WhileBusy, picked: MessageBusy | undefined) {
|
|
71
|
+
return whileBusy === "refuse" ? whileBusy : (picked ?? whileBusy);
|
|
72
|
+
}
|
|
73
|
+
|
|
49
74
|
export const ATTACHMENT_MIME_TYPES = [
|
|
50
75
|
"image/png",
|
|
51
76
|
"image/jpeg",
|
|
@@ -221,6 +246,8 @@ export type AgentCapabilities = {
|
|
|
221
246
|
messages: boolean;
|
|
222
247
|
/** True when the caller only reads, as an operator inspecting a user's thread does. */
|
|
223
248
|
readOnly: boolean;
|
|
249
|
+
/** What a message sent while a run holds the thread does; under `refuse`, nothing sends until the run ends. */
|
|
250
|
+
whileBusy: WhileBusy;
|
|
224
251
|
/** Prompt chips on the blank-chat landing per locale; clicking one sends its `prompt` as the first message. */
|
|
225
252
|
suggestions: Suggestions;
|
|
226
253
|
/** Headline of the blank-chat landing per locale; "" falls back to the widget's built-in copy. */
|
|
@@ -240,8 +267,8 @@ export type MessageMetadata = {
|
|
|
240
267
|
isAborted?: boolean;
|
|
241
268
|
tokenUsage?: TokenUsage;
|
|
242
269
|
attachments?: AttachmentSummary[];
|
|
243
|
-
/** Set on `
|
|
244
|
-
|
|
270
|
+
/** Set on `event` messages: what happened, and the input that brought it. */
|
|
271
|
+
event?: EventSummary;
|
|
245
272
|
};
|
|
246
273
|
|
|
247
274
|
/**
|
|
@@ -280,6 +307,22 @@ export const STATEMENT_TOOLS = ["executeCode", "queryDataset", "describeDataset"
|
|
|
280
307
|
*/
|
|
281
308
|
export const APPROVAL_TITLE_FIELD = "approvalTitle";
|
|
282
309
|
|
|
310
|
+
/**
|
|
311
|
+
* The chat's own tool by which an agent hands a task to a copy of itself.
|
|
312
|
+
* Its input's `brief` is the task, which the copy's card shows.
|
|
313
|
+
*/
|
|
314
|
+
export const DELEGATE_TASK_TOOL = "delegateTask";
|
|
315
|
+
|
|
316
|
+
/** The chat's tool by which an agent stops a copy it handed a task, by the subagent id its start answered. */
|
|
317
|
+
export const CANCEL_TASK_TOOL = "cancelTask";
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* The chat's tool by which an agent schedules a check-back: it comes back
|
|
321
|
+
* to the thread on its own at a time it picks, with a note to itself. Its
|
|
322
|
+
* output's `checkBackId` is the input the user may cancel.
|
|
323
|
+
*/
|
|
324
|
+
export const SCHEDULE_WAKE_TOOL = "scheduleWake";
|
|
325
|
+
|
|
283
326
|
/** A line the model wrote into a call input's `field`, trimmed; undefined while it streams in or is blank. */
|
|
284
327
|
export function modelLineOf(input: unknown, field: string) {
|
|
285
328
|
if (!input || typeof input !== "object") return undefined;
|
|
@@ -306,6 +349,23 @@ export type ToolCallMetadata = {
|
|
|
306
349
|
embed?: ClientToolBinding;
|
|
307
350
|
/** Set beside `answeredBy` on a `connectAccount` call: the widget starts the sign-in with it. */
|
|
308
351
|
connect?: ConnectAccountBinding;
|
|
352
|
+
/**
|
|
353
|
+
* Set on a call a run paused on for the user's decision: the interrupt the run raised for
|
|
354
|
+
* it and the run it paused, so a client that reloads re-prompts the decision exactly as the
|
|
355
|
+
* live run asked it.
|
|
356
|
+
*/
|
|
357
|
+
paused?: { runId: string; interrupt: RunInterrupt };
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
/** An interrupt as a paused run raises it on its end, in AG-UI's shape. */
|
|
361
|
+
export type RunInterrupt = {
|
|
362
|
+
id: string;
|
|
363
|
+
reason: string;
|
|
364
|
+
message?: string;
|
|
365
|
+
toolCallId?: string;
|
|
366
|
+
responseSchema?: Record<string, unknown>;
|
|
367
|
+
expiresAt?: string;
|
|
368
|
+
metadata?: Record<string, unknown>;
|
|
309
369
|
};
|
|
310
370
|
|
|
311
371
|
/** The `metadata.cortex` a tool call carries, when Cortex stamped one. */
|
|
@@ -314,11 +374,16 @@ export function toolCallMetadataOf(part: { metadata?: unknown }) {
|
|
|
314
374
|
return metadata?.cortex ?? undefined;
|
|
315
375
|
}
|
|
316
376
|
|
|
317
|
-
|
|
377
|
+
/** An event that entered a conversation: a trigger fired, a schedule came due, a run finished. */
|
|
378
|
+
export type EventSummary = {
|
|
379
|
+
source: "trigger" | "schedule" | "run";
|
|
380
|
+
/** The trigger's name, or what the schedule or run was for. */
|
|
318
381
|
name: string;
|
|
319
|
-
|
|
320
|
-
|
|
382
|
+
inputId: string;
|
|
383
|
+
at: string;
|
|
321
384
|
payload: unknown;
|
|
385
|
+
/** What a trigger that leaves a note tells the thread, for its user to read. */
|
|
386
|
+
note?: string;
|
|
322
387
|
};
|
|
323
388
|
|
|
324
389
|
/**
|
|
@@ -332,19 +397,19 @@ export type TriggerFiringSummary = {
|
|
|
332
397
|
*/
|
|
333
398
|
export type CortexMessage<TPart = unknown> = {
|
|
334
399
|
id: string;
|
|
335
|
-
/** `
|
|
400
|
+
/** `event` rows carry what happened; the UIs render them as an event, not a bubble. */
|
|
336
401
|
role: MessageRole;
|
|
337
402
|
parts: TPart[];
|
|
338
403
|
metadata?: MessageMetadata;
|
|
339
404
|
};
|
|
340
405
|
|
|
341
406
|
/**
|
|
342
|
-
* A stored message as the SDK's chat client takes it. The SDK has no `
|
|
343
|
-
* role, so
|
|
344
|
-
* the envelope (`metadata.
|
|
407
|
+
* A stored message as the SDK's chat client takes it. The SDK has no `event`
|
|
408
|
+
* role, so an event message travels as a user turn; its true role stays on
|
|
409
|
+
* the envelope (`metadata.event`), which is what the UIs render the event from.
|
|
345
410
|
*/
|
|
346
411
|
export function toUiMessage<TPart>(message: CortexMessage<TPart>) {
|
|
347
|
-
return { ...message, role: message.role === "
|
|
412
|
+
return { ...message, role: message.role === "event" ? ("user" as const) : message.role };
|
|
348
413
|
}
|
|
349
414
|
|
|
350
415
|
/**
|
|
@@ -427,14 +492,20 @@ export type ThreadRunStartedEvent = {
|
|
|
427
492
|
|
|
428
493
|
/**
|
|
429
494
|
* Run `runId` ended, committed or not, and left the thread free, so it takes
|
|
430
|
-
* a new message now; whatever turn it committed is in the transcript.
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
495
|
+
* a new message now; whatever turn it committed is in the transcript.
|
|
496
|
+
* `status` and `reason` say how: `waiting` for a run parked on calls that
|
|
497
|
+
* wait. Sent only for a run announced as started, and never by one whose
|
|
498
|
+
* thread another run had already taken, so a finish naming a run other than
|
|
499
|
+
* the one a client saw start last is stale.
|
|
434
500
|
*/
|
|
435
501
|
export type ThreadRunFinishedEvent = {
|
|
436
502
|
type: "thread:run-finished";
|
|
437
|
-
payload: {
|
|
503
|
+
payload: {
|
|
504
|
+
thread: ThreadSummary;
|
|
505
|
+
runId: string;
|
|
506
|
+
status: RunStatus;
|
|
507
|
+
reason: RunReason | null;
|
|
508
|
+
};
|
|
438
509
|
};
|
|
439
510
|
|
|
440
511
|
export type ThreadMessagesUpdatedEvent = {
|
|
@@ -442,13 +513,26 @@ export type ThreadMessagesUpdatedEvent = {
|
|
|
442
513
|
payload: { thread: ThreadSummary };
|
|
443
514
|
};
|
|
444
515
|
|
|
516
|
+
/**
|
|
517
|
+
* The inputs waiting on the thread changed: one was offered, taken up as a
|
|
518
|
+
* turn of its own, or cancelled. `inputIds` are the ones still waiting, in
|
|
519
|
+
* the order dispatch takes them; `GET /threads/:threadId/inputs` reads
|
|
520
|
+
* them. A steer the running turn took in waits on until that turn stores
|
|
521
|
+
* it, which announces nothing: the run's stream carries it.
|
|
522
|
+
*/
|
|
523
|
+
export type ThreadInputsChangedEvent = {
|
|
524
|
+
type: "thread:inputs-changed";
|
|
525
|
+
payload: { threadId: string; inputIds: string[] };
|
|
526
|
+
};
|
|
527
|
+
|
|
445
528
|
export type WsEvent =
|
|
446
529
|
| ThreadCreatedEvent
|
|
447
530
|
| ThreadDeletedEvent
|
|
448
531
|
| ThreadTitleUpdatedEvent
|
|
449
532
|
| ThreadRunStartedEvent
|
|
450
533
|
| ThreadRunFinishedEvent
|
|
451
|
-
| ThreadMessagesUpdatedEvent
|
|
534
|
+
| ThreadMessagesUpdatedEvent
|
|
535
|
+
| ThreadInputsChangedEvent;
|
|
452
536
|
|
|
453
537
|
/** The header the widget sends the browser's IANA time zone in; the turn reasons in that clock. */
|
|
454
538
|
export const TIMEZONE_HEADER = "X-Cortex-Timezone";
|
|
@@ -473,53 +557,33 @@ export const OPERATOR_HEADER = "X-Cortex-Operator";
|
|
|
473
557
|
export const INSPECT_HEADER = "X-Cortex-Inspect";
|
|
474
558
|
|
|
475
559
|
/**
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Every reason a firing records beside its outcome: why it was dropped, why
|
|
485
|
-
* its payload was rejected (`invalid_payload`, `missing_thread_key`), that
|
|
486
|
-
* no turn ran for it (`no_turn`), or why a run with an output schema failed
|
|
487
|
-
* without an answer the schema accepted (`no_output`, `invalid_output`).
|
|
488
|
-
*/
|
|
489
|
-
export const TRIGGER_REASONS = [
|
|
490
|
-
...TRIGGER_DROP_REASONS,
|
|
491
|
-
"invalid_payload",
|
|
492
|
-
"missing_thread_key",
|
|
493
|
-
"no_turn",
|
|
494
|
-
"no_output",
|
|
495
|
-
"invalid_output",
|
|
496
|
-
] as const;
|
|
497
|
-
export type TriggerReason = (typeof TRIGGER_REASONS)[number];
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* Body of a `POST /chat` the thread did not take: 409 while a run holds the
|
|
501
|
-
* thread or a call on it waits for a decision, or when the answers it
|
|
502
|
-
* carried fit no open call, were already applied, or answer a call whose
|
|
503
|
-
* origin is out of reach (`no_turn`); 429 once the agent's request bucket is
|
|
504
|
-
* spent, with `Retry-After`.
|
|
560
|
+
* One input waiting on a thread, in the order dispatch takes them, in
|
|
561
|
+
* `GET /threads/:threadId/inputs`: the user message as it will be stored
|
|
562
|
+
* once a run takes it up, and how it waits: to steer the running turn, or
|
|
563
|
+
* for a turn of its own. `DELETE /threads/:threadId/inputs/:inputId`
|
|
564
|
+
* cancels it and `PATCH` (`{ busy }`) moves it to steer or queue, unless a
|
|
565
|
+
* run already took it in (404).
|
|
505
566
|
*/
|
|
506
|
-
export type
|
|
507
|
-
|
|
508
|
-
|
|
567
|
+
export type WaitingInput<TPart = unknown> = {
|
|
568
|
+
inputId: string;
|
|
569
|
+
delivery: "prompt" | "steer" | "followUp" | "answer" | "note";
|
|
570
|
+
message: CortexMessage<TPart>;
|
|
571
|
+
/** Whether it is text alone, which a running turn may take in as a steer; one with files waits for a turn of its own. */
|
|
572
|
+
textOnly: boolean;
|
|
509
573
|
};
|
|
510
574
|
|
|
511
575
|
/**
|
|
512
|
-
* The
|
|
513
|
-
* for approval, so the message goes back to the composer. Any other
|
|
514
|
-
* shows as a failed turn.
|
|
576
|
+
* The refusal a widget tells its user about by name: a call on the thread
|
|
577
|
+
* waits for approval, so the message goes back to the composer. Any other
|
|
578
|
+
* refusal shows as a failed turn.
|
|
515
579
|
*/
|
|
516
|
-
export type SendRefusal =
|
|
580
|
+
export type SendRefusal = "approval_pending";
|
|
517
581
|
|
|
518
582
|
/**
|
|
519
583
|
* What became of the client tool answers a `POST /chat` carried, by the
|
|
520
584
|
* status Cortex answered it with, apart from how the run it started goes.
|
|
521
585
|
* `persisted` (2xx): Cortex took them up, and sending them again changes
|
|
522
|
-
* nothing. `refused` (4xx,
|
|
586
|
+
* nothing. `refused` (4xx, an `InputReceipt` among them): it did not take
|
|
523
587
|
* them up as given, and the stored transcript says what stands. `lost`
|
|
524
588
|
* (5xx, or no answer at all): its word never came, and only the stored
|
|
525
589
|
* transcript can tell.
|