@m6d/cortex-cli 1.7.0 → 1.8.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
CHANGED
|
@@ -1,47 +1,82 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* The grammar and rendering pipeline for user-authored rich text that reaches
|
|
3
|
-
* the LLM (agent prompts, service descriptions). Both sides of
|
|
4
|
-
* it: the console edits and validates these strings, the
|
|
5
|
-
* pre-renders them (mentions + heading demotion), and
|
|
6
|
-
* applies per-request variable values.
|
|
3
|
+
* the LLM (agent prompts, service descriptions, skill bodies). Both sides of
|
|
4
|
+
* the wire share it: the console edits and validates these strings, the
|
|
5
|
+
* console's runtime API pre-renders them (mentions + heading demotion), and
|
|
6
|
+
* `@m6d/cortex-server` applies per-request variable values. Three token
|
|
7
|
+
* grammars live here:
|
|
7
8
|
*
|
|
8
|
-
* - Tool mentions `@[name](uuid)`
|
|
9
|
-
* is only a display cache refreshed
|
|
10
|
-
* resolved live when text is
|
|
9
|
+
* - Tool mentions `@[name](uuid)` and skill mentions `/[name](uuid)` — the
|
|
10
|
+
* uuid is authoritative; the inline name is only a display cache refreshed
|
|
11
|
+
* on save ({@link normalizeMentions}) and resolved live when text is
|
|
12
|
+
* rendered for the LLM ({@link renderMentions}).
|
|
11
13
|
* - Variables `{{name}}` — validated against a known list at authoring time
|
|
12
14
|
* ({@link analyzeVariables}) and substituted per request on the server
|
|
13
15
|
* ({@link substituteVariables}).
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
const UUID = String.raw`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`;
|
|
19
|
+
|
|
20
|
+
/** One tool mention token, unanchored and flagless — the editor's tokenizer anchors it, the helpers below add `g`. */
|
|
21
|
+
export const MENTION_PATTERN_SOURCE = String.raw`@\[([^\]\n]*)\]\((${UUID})\)`;
|
|
22
|
+
/** One skill mention token; `/` is the slash-command convention skills already carry elsewhere. */
|
|
23
|
+
export const SKILL_MENTION_PATTERN_SOURCE = String.raw`/\[([^\]\n]*)\]\((${UUID})\)`;
|
|
18
24
|
|
|
19
25
|
const MENTION_PATTERN = new RegExp(MENTION_PATTERN_SOURCE, "g");
|
|
26
|
+
const SKILL_MENTION_PATTERN = new RegExp(SKILL_MENTION_PATTERN_SOURCE, "g");
|
|
20
27
|
|
|
21
28
|
const VARIABLE_PATTERN = /{{\s*([^{}]*?)\s*}}/g;
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
/** Entity names by id for the two mention grammars; a missing map leaves that grammar's cached names in place. */
|
|
31
|
+
export type MentionNames = {
|
|
32
|
+
tools?: ReadonlyMap<string, string>;
|
|
33
|
+
skills?: ReadonlyMap<string, string>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const NO_NAMES: ReadonlyMap<string, string> = new Map();
|
|
37
|
+
|
|
38
|
+
function extractIds(text: string, pattern: RegExp) {
|
|
24
39
|
const ids: string[] = [];
|
|
25
|
-
for (const match of text.matchAll(
|
|
40
|
+
for (const match of text.matchAll(pattern)) {
|
|
26
41
|
const id = match[2];
|
|
27
42
|
if (id && !ids.includes(id)) ids.push(id);
|
|
28
43
|
}
|
|
29
44
|
return ids;
|
|
30
45
|
}
|
|
31
46
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
export function extractMentionedToolIds(text: string) {
|
|
48
|
+
return extractIds(text, MENTION_PATTERN);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function extractMentionedSkillIds(text: string) {
|
|
52
|
+
return extractIds(text, SKILL_MENTION_PATTERN);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Replaces each mention token with the entity's current name (falling back to the cached inline name). */
|
|
56
|
+
export function renderMentions(text: string, names: MentionNames) {
|
|
57
|
+
const tools = names.tools ?? NO_NAMES;
|
|
58
|
+
const skills = names.skills ?? NO_NAMES;
|
|
59
|
+
return text
|
|
60
|
+
.replace(MENTION_PATTERN, (_, cached: string, id: string) => tools.get(id) ?? cached)
|
|
61
|
+
.replace(
|
|
62
|
+
SKILL_MENTION_PATTERN,
|
|
63
|
+
(_, cached: string, id: string) => skills.get(id) ?? cached,
|
|
64
|
+
);
|
|
37
65
|
}
|
|
38
66
|
|
|
39
67
|
/** Refreshes stale display names inside stored text, keeping the tokens intact. */
|
|
40
|
-
export function normalizeMentions(text: string,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
export function normalizeMentions(text: string, names: MentionNames) {
|
|
69
|
+
const tools = names.tools ?? NO_NAMES;
|
|
70
|
+
const skills = names.skills ?? NO_NAMES;
|
|
71
|
+
return text
|
|
72
|
+
.replace(MENTION_PATTERN, (token, _cached: string, id: string) => {
|
|
73
|
+
const name = tools.get(id);
|
|
74
|
+
return name === undefined ? token : `@[${name}](${id})`;
|
|
75
|
+
})
|
|
76
|
+
.replace(SKILL_MENTION_PATTERN, (token, _cached: string, id: string) => {
|
|
77
|
+
const name = skills.get(id);
|
|
78
|
+
return name === undefined ? token : `/[${name}](${id})`;
|
|
79
|
+
});
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
/** Splits the `{{variables}}` referenced in a text into known and unknown ones. */
|
|
@@ -65,7 +100,7 @@ export function analyzeVariables<Variable extends string>(
|
|
|
65
100
|
|
|
66
101
|
/** Fills `{{variables}}` with per-request values; unknown names stay verbatim. */
|
|
67
102
|
export function substituteVariables(text: string, values: Record<string, string>) {
|
|
68
|
-
return text.replace(
|
|
103
|
+
return text.replace(VARIABLE_PATTERN, (match, name: string) => values[name] ?? match);
|
|
69
104
|
}
|
|
70
105
|
|
|
71
106
|
/**
|
|
@@ -164,23 +199,21 @@ export function demoteHeadings(text: string) {
|
|
|
164
199
|
}
|
|
165
200
|
|
|
166
201
|
/** The one render step for LLM-bound rich text: resolve mentions, then demote headings. */
|
|
167
|
-
export function renderRichText(text: string,
|
|
168
|
-
return demoteHeadings(renderMentions(text,
|
|
202
|
+
export function renderRichText(text: string, names: MentionNames) {
|
|
203
|
+
return demoteHeadings(renderMentions(text, names));
|
|
169
204
|
}
|
|
170
205
|
|
|
171
206
|
/**
|
|
172
|
-
* Reduces rich text to plain prose for embeddings: mentions become
|
|
173
|
-
* (cached inline names when no map is given) and markdown syntax is
|
|
207
|
+
* Reduces rich text to plain prose for embeddings: mentions become entity
|
|
208
|
+
* names (cached inline names when no map is given) and markdown syntax is
|
|
209
|
+
* dropped.
|
|
174
210
|
* ponytail: a regex stripper, not a markdown parser — nested emphasis or exotic
|
|
175
211
|
* constructs may leave residue; swap in a real parser if retrieval quality
|
|
176
212
|
* ever shows it.
|
|
177
213
|
*/
|
|
178
|
-
export function stripToPlaintext(
|
|
179
|
-
text: string,
|
|
180
|
-
toolNameById: ReadonlyMap<string, string> = new Map(),
|
|
181
|
-
) {
|
|
214
|
+
export function stripToPlaintext(text: string, names: MentionNames = {}) {
|
|
182
215
|
const lineState = fenceTracker();
|
|
183
|
-
return renderMentions(text,
|
|
216
|
+
return renderMentions(text, names)
|
|
184
217
|
.split("\n")
|
|
185
218
|
.filter((line) => {
|
|
186
219
|
const state = lineState(line);
|
|
@@ -117,17 +117,196 @@ export const toolSignatureSchema = z.object({
|
|
|
117
117
|
inputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
/** Consumer-facing slugs: service keys and skill names share it, the model types both. */
|
|
121
|
+
export const SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* One always-listed skill line. The description is the whole trigger: the
|
|
125
|
+
* model reads it every turn and calls `loadSkill` when it matches the task.
|
|
126
|
+
*/
|
|
127
|
+
export const skillLineSchema = z.object({
|
|
128
|
+
name: z.string().regex(SLUG_PATTERN).max(64),
|
|
129
|
+
description: z.string().max(500),
|
|
130
|
+
});
|
|
131
|
+
|
|
120
132
|
export const serviceCardSchema = z.object({
|
|
121
133
|
serviceId: z.uuid(),
|
|
122
|
-
key: z
|
|
123
|
-
.string()
|
|
124
|
-
.regex(/^[a-z0-9]+(-[a-z0-9]+)*$/)
|
|
125
|
-
.max(64),
|
|
134
|
+
key: z.string().regex(SLUG_PATTERN).max(64),
|
|
126
135
|
name: z.string(),
|
|
127
136
|
card: z.string(),
|
|
128
137
|
score: z.number(),
|
|
138
|
+
/** Skills scoped to this service; listed only while the card is in context. Defaulted so an older Control Center still parses. */
|
|
139
|
+
skills: z.array(skillLineSchema).default([]),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* A skill body served on `loadSkill`: mentions rendered to current names and
|
|
144
|
+
* headings demoted by the console, `{{variables}}` left for the server to
|
|
145
|
+
* fill per request. `mentionedTools` are the sandbox bindings the body
|
|
146
|
+
* refers to, so the turn can register them before the model acts on it.
|
|
147
|
+
*/
|
|
148
|
+
/**
|
|
149
|
+
* Opaque handle the Control Center assigns a resolved agent. Servers echo it
|
|
150
|
+
* on reports about that agent so they attach to it even if the slug or alias
|
|
151
|
+
* they used later moves.
|
|
152
|
+
*/
|
|
153
|
+
export const agentRefSchema = z.string().max(128);
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Response header carrying the resolved agent's ref on every agent-scoped
|
|
157
|
+
* runtime answer, errors included, so a server can attribute a request even
|
|
158
|
+
* when the body is an error envelope. Absent only when no agent resolved.
|
|
159
|
+
*/
|
|
160
|
+
export const AGENT_REF_HEADER = "X-CC-Agent-Ref";
|
|
161
|
+
|
|
162
|
+
/** A sandbox binding a piece of rich text mentions, so the turn can register it before the model reads the text. */
|
|
163
|
+
export const mentionedToolSchema = z.object({
|
|
164
|
+
toolId: z.uuid(),
|
|
165
|
+
name: z.string().regex(TOOL_NAME_PATTERN),
|
|
166
|
+
readOnly: z.boolean(),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
export const skillBodyResponseSchema = z.object({
|
|
170
|
+
name: z.string(),
|
|
171
|
+
body: z.string(),
|
|
172
|
+
mentionedTools: z.array(mentionedToolSchema),
|
|
173
|
+
catalogVersion: catalogVersionSchema,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
/*
|
|
177
|
+
* Triggers: named entry points on an agent. A firing is one invocation with a
|
|
178
|
+
* payload and starts at most one run. The end user's message is the built-in
|
|
179
|
+
* `message` trigger; every other trigger is fired by an external caller over
|
|
180
|
+
* `POST /agents/:agentId/triggers/:name` with the trigger's own secret.
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
export const MESSAGE_TRIGGER_NAME = "message";
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The first characters of a fire bearer say what it is: the secret callers
|
|
187
|
+
* hold, or a one-shot test token the console minted. A test token is a JWT
|
|
188
|
+
* the Control Center signed, so a server verifies it against the Control
|
|
189
|
+
* Center's JWKS before saying a word to it, and the Control Center then
|
|
190
|
+
* consumes it so it fires once.
|
|
191
|
+
*/
|
|
192
|
+
export const TRIGGER_SECRET_PREFIXES = { live: "tr_live_", test: "tr_test_" } as const;
|
|
193
|
+
export const TRIGGER_TEST_TOKEN_AUDIENCE = "cortex:trigger-test";
|
|
194
|
+
|
|
195
|
+
/** The claims a test token carries beside the standard ones; the server checks them against the route it arrived on. */
|
|
196
|
+
export const triggerTestTokenClaimsSchema = z.object({
|
|
197
|
+
agent: agentSlugSchema,
|
|
198
|
+
trigger: z.string().regex(SLUG_PATTERN).max(64),
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const sha256HexSchema = z.string().regex(/^[0-9a-f]{64}$/);
|
|
202
|
+
|
|
203
|
+
export const TRIGGER_OUTCOMES = [
|
|
204
|
+
"started",
|
|
205
|
+
"completed",
|
|
206
|
+
"failed",
|
|
207
|
+
"rejected",
|
|
208
|
+
"dropped",
|
|
209
|
+
"disabled",
|
|
210
|
+
] as const;
|
|
211
|
+
|
|
212
|
+
/** Why a firing was dropped: the thread was busy, or the daily budget was spent. */
|
|
213
|
+
export const TRIGGER_DROP_REASONS = ["busy", "budget"] as const;
|
|
214
|
+
|
|
215
|
+
export const TRIGGER_SOURCES = ["code", "cc"] as const;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Which thread a firing lands in. `single`: one thread for the trigger.
|
|
219
|
+
* `per-firing`: a fresh thread every time. `keyed`: one thread per distinct
|
|
220
|
+
* value at a JSON pointer into the payload (e.g. `/pull_request/number`).
|
|
221
|
+
*/
|
|
222
|
+
export const triggerThreadPolicySchema = z.discriminatedUnion("policy", [
|
|
223
|
+
z.object({ policy: z.literal("single") }),
|
|
224
|
+
z.object({ policy: z.literal("per-firing") }),
|
|
225
|
+
z.object({ policy: z.literal("keyed"), key: z.string().regex(/^\//).max(256) }),
|
|
226
|
+
]);
|
|
227
|
+
|
|
228
|
+
/** A trigger as both sides describe it. Secrets and credentials never cross this contract. */
|
|
229
|
+
export const triggerDeclarationSchema = z.object({
|
|
230
|
+
name: z.string().regex(SLUG_PATTERN).max(64),
|
|
231
|
+
description: z.string().max(500),
|
|
232
|
+
/** JSON Schema for the payload; cc triggers are validated from it on the server. */
|
|
233
|
+
input: z.record(z.string(), z.unknown()),
|
|
234
|
+
/**
|
|
235
|
+
* The prompt the run starts from, mentions already rendered to names by
|
|
236
|
+
* the console; `{{variables}}` and `{{/json/pointer}}` payload fields
|
|
237
|
+
* are the server's to fill per firing.
|
|
238
|
+
*/
|
|
239
|
+
instructions: z.string().max(20_000),
|
|
240
|
+
/** Tools the instructions mention, registered as sandbox bindings for the run. Defaulted so an older Control Center still parses. */
|
|
241
|
+
mentionedTools: z.array(mentionedToolSchema).default([]),
|
|
242
|
+
thread: triggerThreadPolicySchema.default({ policy: "single" }),
|
|
243
|
+
budgetPerDay: z.number().int().positive().nullable().default(null),
|
|
244
|
+
/** Consecutive failed or rejected firings before the trigger disables itself. */
|
|
245
|
+
disableAfterFailures: z.number().int().positive().default(5),
|
|
246
|
+
hasCredential: z.boolean().default(false),
|
|
247
|
+
/**
|
|
248
|
+
* sha256 of the fire secret, so a server checks a presented bearer in
|
|
249
|
+
* process; the Control Center hears only about console test secrets,
|
|
250
|
+
* which it alone can consume.
|
|
251
|
+
*/
|
|
252
|
+
secretHash: sha256HexSchema,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
export const triggerFiringResponseSchema = z.discriminatedUnion("outcome", [
|
|
256
|
+
z.object({
|
|
257
|
+
firingId: z.uuid(),
|
|
258
|
+
outcome: z.literal("started"),
|
|
259
|
+
threadId: z.uuid(),
|
|
260
|
+
runId: z.string(),
|
|
261
|
+
}),
|
|
262
|
+
z.object({
|
|
263
|
+
firingId: z.uuid(),
|
|
264
|
+
outcome: z.literal("dropped"),
|
|
265
|
+
reason: z.enum(TRIGGER_DROP_REASONS),
|
|
266
|
+
threadId: z.uuid().nullable(),
|
|
267
|
+
}),
|
|
268
|
+
z.object({ firingId: z.uuid(), outcome: z.literal("disabled") }),
|
|
269
|
+
z.object({
|
|
270
|
+
firingId: z.uuid(),
|
|
271
|
+
outcome: z.literal("rejected"),
|
|
272
|
+
issues: z.array(z.object({ path: z.string(), message: z.string() })),
|
|
273
|
+
}),
|
|
274
|
+
]);
|
|
275
|
+
|
|
276
|
+
export const triggerFiringSchema = z.object({
|
|
277
|
+
id: z.uuid(),
|
|
278
|
+
triggerName: z.string(),
|
|
279
|
+
threadId: z.uuid().nullable(),
|
|
280
|
+
runId: z.string().nullable(),
|
|
281
|
+
outcome: z.enum(TRIGGER_OUTCOMES),
|
|
282
|
+
reason: z.string().nullable(),
|
|
283
|
+
createdAt: z.iso.datetime(),
|
|
284
|
+
finishedAt: z.iso.datetime().nullable(),
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
export const triggerFiringListResponseSchema = z.object({
|
|
288
|
+
firings: z.array(triggerFiringSchema),
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* `POST /api/runtime/agents/:id/triggers/:name/auth`: a server holding a
|
|
293
|
+
* bearer for a cc trigger asks cc whether it is the trigger's secret. Only the
|
|
294
|
+
* hash travels; a positive answer carries the trigger's credential, if any.
|
|
295
|
+
*/
|
|
296
|
+
export const triggerAuthRequestSchema = z.object({
|
|
297
|
+
secretHash: sha256HexSchema,
|
|
129
298
|
});
|
|
130
299
|
|
|
300
|
+
export const triggerAuthResponseSchema = z.discriminatedUnion("ok", [
|
|
301
|
+
z.object({
|
|
302
|
+
ok: z.literal(true),
|
|
303
|
+
credential: z.string().nullable(),
|
|
304
|
+
/** The bearer was a single-use test secret, now spent: the server must not cache this verdict. */
|
|
305
|
+
oneShot: z.boolean().optional(),
|
|
306
|
+
}),
|
|
307
|
+
z.object({ ok: z.literal(false) }),
|
|
308
|
+
]);
|
|
309
|
+
|
|
131
310
|
export const runtimeAgentConfigSchema = z.object({
|
|
132
311
|
agentId: agentSlugSchema,
|
|
133
312
|
/**
|
|
@@ -166,6 +345,14 @@ export const runtimeAgentConfigSchema = z.object({
|
|
|
166
345
|
executeTimeoutMs: z.number().int().positive(),
|
|
167
346
|
maxResponseBytes: z.number().int().positive(),
|
|
168
347
|
}),
|
|
348
|
+
/** Unscoped published skills; service-scoped ones travel on their card. Defaulted so an older Control Center still parses. */
|
|
349
|
+
skills: z.array(skillLineSchema).default([]),
|
|
350
|
+
/** Published triggers. Defaulted so an older Control Center still parses. */
|
|
351
|
+
triggers: z.array(triggerDeclarationSchema).default([]),
|
|
352
|
+
/** Whether end users may message this agent; false makes it headless. */
|
|
353
|
+
messageTrigger: z.boolean().default(true),
|
|
354
|
+
/** Absent from older Control Centers; reports then carry only the slug. */
|
|
355
|
+
agentRef: agentRefSchema.optional(),
|
|
169
356
|
catalogVersion: catalogVersionSchema,
|
|
170
357
|
publishedAt: z.iso.datetime(),
|
|
171
358
|
});
|
|
@@ -299,7 +486,8 @@ export const tokenUsageSchema = z.object({
|
|
|
299
486
|
total: tokenCountSchema,
|
|
300
487
|
});
|
|
301
488
|
|
|
302
|
-
|
|
489
|
+
/** `trigger` rows hold a firing's rendered instructions; the model sees them as `user` turns. */
|
|
490
|
+
export const MESSAGE_ROLES = ["system", "user", "assistant", "tool", "trigger"] as const;
|
|
303
491
|
|
|
304
492
|
export const syncEventSchema = z.discriminatedUnion("type", [
|
|
305
493
|
z.object({
|
|
@@ -309,6 +497,9 @@ export const syncEventSchema = z.discriminatedUnion("type", [
|
|
|
309
497
|
userId: z.string().max(255),
|
|
310
498
|
title: z.string().max(256).nullable(),
|
|
311
499
|
isTest: z.boolean(),
|
|
500
|
+
/** Set on headless threads a trigger owns; `userId` is then a sentinel. */
|
|
501
|
+
triggerName: z.string().max(64).nullable().default(null),
|
|
502
|
+
triggerKey: z.string().max(256).nullable().default(null),
|
|
312
503
|
createdAt: z.iso.datetime(),
|
|
313
504
|
updatedAt: z.iso.datetime(),
|
|
314
505
|
}),
|
|
@@ -337,6 +528,52 @@ export const syncEventSchema = z.discriminatedUnion("type", [
|
|
|
337
528
|
// column, but the mirror needs one for time-bucketed usage stats.
|
|
338
529
|
createdAt: z.iso.datetime(),
|
|
339
530
|
}),
|
|
531
|
+
// One loadSkill call, hit or miss, from either skill source. Bounded by
|
|
532
|
+
// construction (no body travels), so it can never trip the size cap.
|
|
533
|
+
z.object({
|
|
534
|
+
type: z.literal("skill.load"),
|
|
535
|
+
id: z.uuid(),
|
|
536
|
+
threadId: z.uuid(),
|
|
537
|
+
agentSlug: agentSlugSchema,
|
|
538
|
+
/** The ref cc issued for the agent that answered; a code-only agent or a miss has none. */
|
|
539
|
+
agentRef: agentRefSchema.optional(),
|
|
540
|
+
/** As the model asked for it, even when nothing answered. */
|
|
541
|
+
skillName: z.string().max(64),
|
|
542
|
+
source: z.enum(["code", "cc"]).nullable(),
|
|
543
|
+
hit: z.boolean(),
|
|
544
|
+
/** The user message this turn answers; the mirror joins it for the drill-down. */
|
|
545
|
+
messageId: z.string().max(128),
|
|
546
|
+
createdAt: z.iso.datetime(),
|
|
547
|
+
}),
|
|
548
|
+
// One firing, upserted on start and again on its terminal outcome; the
|
|
549
|
+
// firing id is the event id so both land on one mirror row.
|
|
550
|
+
z.object({
|
|
551
|
+
type: z.literal("trigger.firing"),
|
|
552
|
+
id: z.uuid(),
|
|
553
|
+
agentSlug: agentSlugSchema,
|
|
554
|
+
agentRef: agentRefSchema.optional(),
|
|
555
|
+
triggerName: z.string().max(64),
|
|
556
|
+
source: z.enum(TRIGGER_SOURCES),
|
|
557
|
+
threadId: z.uuid().nullable(),
|
|
558
|
+
runId: z.string().max(64).nullable(),
|
|
559
|
+
outcome: z.enum(TRIGGER_OUTCOMES),
|
|
560
|
+
reason: z.string().max(64).nullable(),
|
|
561
|
+
createdAt: z.iso.datetime(),
|
|
562
|
+
finishedAt: z.iso.datetime().nullable(),
|
|
563
|
+
}),
|
|
564
|
+
// Every code trigger the server declares, sent whole at boot so cc can
|
|
565
|
+
// list them read-only beside its own. Replaces the server's previous
|
|
566
|
+
// declaration, so an agent removed from code takes its triggers with it.
|
|
567
|
+
z.object({
|
|
568
|
+
type: z.literal("trigger.declare"),
|
|
569
|
+
id: z.uuid(),
|
|
570
|
+
triggers: z.array(
|
|
571
|
+
triggerDeclarationSchema
|
|
572
|
+
.pick({ name: true, description: true, input: true, thread: true })
|
|
573
|
+
.extend({ agentSlug: agentSlugSchema }),
|
|
574
|
+
),
|
|
575
|
+
createdAt: z.iso.datetime(),
|
|
576
|
+
}),
|
|
340
577
|
]);
|
|
341
578
|
|
|
342
579
|
/*
|
|
@@ -372,6 +609,18 @@ export type ToolEmbed = z.infer<typeof toolEmbedSchema>;
|
|
|
372
609
|
export type RuntimeAgentConfig = z.infer<typeof runtimeAgentConfigSchema>;
|
|
373
610
|
export type ResolveRequest = z.input<typeof resolveRequestSchema>;
|
|
374
611
|
export type ResolveResponse = z.infer<typeof resolveResponseSchema>;
|
|
612
|
+
export type SkillLine = z.infer<typeof skillLineSchema>;
|
|
613
|
+
export type SkillBodyResponse = z.infer<typeof skillBodyResponseSchema>;
|
|
614
|
+
export type TriggerDeclaration = z.infer<typeof triggerDeclarationSchema>;
|
|
615
|
+
export type TriggerThreadPolicy = z.infer<typeof triggerThreadPolicySchema>;
|
|
616
|
+
export type TriggerOutcome = (typeof TRIGGER_OUTCOMES)[number];
|
|
617
|
+
export type TriggerDropReason = (typeof TRIGGER_DROP_REASONS)[number];
|
|
618
|
+
export type TriggerSource = (typeof TRIGGER_SOURCES)[number];
|
|
619
|
+
export type TriggerFiringResponse = z.infer<typeof triggerFiringResponseSchema>;
|
|
620
|
+
export type TriggerFiring = z.infer<typeof triggerFiringSchema>;
|
|
621
|
+
export type TriggerFiringListResponse = z.infer<typeof triggerFiringListResponseSchema>;
|
|
622
|
+
export type TriggerAuthRequest = z.infer<typeof triggerAuthRequestSchema>;
|
|
623
|
+
export type TriggerAuthResponse = z.infer<typeof triggerAuthResponseSchema>;
|
|
375
624
|
export type SearchRequest = z.input<typeof searchRequestSchema>;
|
|
376
625
|
export type ExecuteRequest = z.input<typeof executeRequestSchema>;
|
|
377
626
|
export type SyncEvent = z.infer<typeof syncEventSchema>;
|
|
@@ -44,6 +44,8 @@ export type ThreadSummary = {
|
|
|
44
44
|
createdAt: string;
|
|
45
45
|
updatedAt: string;
|
|
46
46
|
isRunning: boolean;
|
|
47
|
+
/** Present on a headless thread a trigger owns. Widgets never list these. */
|
|
48
|
+
trigger?: { name: string };
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
/**
|
|
@@ -87,6 +89,8 @@ export type ClientToolBinding = {
|
|
|
87
89
|
*/
|
|
88
90
|
export type AgentCapabilities = {
|
|
89
91
|
attachments: boolean;
|
|
92
|
+
/** False when the agent's `message` trigger is off: the widget hides its composer. */
|
|
93
|
+
messages: boolean;
|
|
90
94
|
};
|
|
91
95
|
|
|
92
96
|
export type MessageMetadata = {
|
|
@@ -96,6 +100,15 @@ export type MessageMetadata = {
|
|
|
96
100
|
tokenUsage?: TokenUsage;
|
|
97
101
|
attachments?: AttachmentSummary[];
|
|
98
102
|
clientTools?: Record<string, ClientToolBinding>;
|
|
103
|
+
/** Set on `trigger` messages: the firing that wrote them. */
|
|
104
|
+
trigger?: TriggerFiringSummary;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type TriggerFiringSummary = {
|
|
108
|
+
name: string;
|
|
109
|
+
firingId: string;
|
|
110
|
+
firedAt: string;
|
|
111
|
+
payload: unknown;
|
|
99
112
|
};
|
|
100
113
|
|
|
101
114
|
/**
|
|
@@ -108,7 +121,8 @@ export type MessageMetadata = {
|
|
|
108
121
|
*/
|
|
109
122
|
export type CortexMessage<TPart = unknown> = {
|
|
110
123
|
id: string;
|
|
111
|
-
|
|
124
|
+
/** `trigger` rows carry a firing's instructions; the UIs render them as an event, not a bubble. */
|
|
125
|
+
role: "system" | "user" | "assistant" | "trigger";
|
|
112
126
|
parts: TPart[];
|
|
113
127
|
metadata?: MessageMetadata;
|
|
114
128
|
};
|