@claxedo/agent-runtime-contract 0.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/dist/index.mjs ADDED
@@ -0,0 +1,815 @@
1
+ // ../claxedo-helpers/src/guards.ts
2
+ function isRecord(value) {
3
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4
+ }
5
+ function asRecord(value) {
6
+ return isRecord(value) ? value : undefined;
7
+ }
8
+
9
+ // src/values.ts
10
+ function asText(value) {
11
+ return typeof value === "string" && value !== "" ? value : undefined;
12
+ }
13
+
14
+ // src/claims.ts
15
+ function jwtClaims(token) {
16
+ const payload = token?.split(".")[1];
17
+ if (!payload)
18
+ return;
19
+ const base64 = payload.replaceAll("-", "+").replaceAll("_", "/");
20
+ try {
21
+ const binary = atob(base64 + "=".repeat((4 - base64.length % 4) % 4));
22
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
23
+ return asRecord(JSON.parse(new TextDecoder().decode(bytes)));
24
+ } catch {
25
+ return;
26
+ }
27
+ }
28
+ function tokensOf(input) {
29
+ const tokens = asRecord(input?.tokens);
30
+ return [
31
+ asText(input?.id_token) ?? asText(tokens?.id_token),
32
+ asText(input?.access_token) ?? asText(input?.access) ?? asText(tokens?.access_token)
33
+ ];
34
+ }
35
+ function emailFromClaims(input) {
36
+ return tokensOf(input).map(emailFromJwt).find((value) => value !== undefined);
37
+ }
38
+ function emailFromJwt(token) {
39
+ const claims = jwtClaims(token);
40
+ const openai = asRecord(claims?.["https://api.openai.com/auth"]);
41
+ return [claims?.email, claims?.preferred_username, openai?.email].map(asText).find((value) => value !== undefined && value.includes("@"));
42
+ }
43
+ function accountIdFromClaims(input) {
44
+ return tokensOf(input).map(accountIdFromJwt).find((value) => value !== undefined);
45
+ }
46
+ function accountIdFromJwt(token) {
47
+ const claims = jwtClaims(token);
48
+ if (!claims)
49
+ return;
50
+ const openai = asRecord(claims["https://api.openai.com/auth"]);
51
+ const named = asText(claims.chatgpt_account_id) ?? asText(openai?.chatgpt_account_id);
52
+ if (named)
53
+ return named;
54
+ const organizations = claims.organizations;
55
+ return Array.isArray(organizations) ? asText(asRecord(organizations[0])?.id) : undefined;
56
+ }
57
+ // src/connections.ts
58
+ function decodeHarnessConnectionsCatalog(value) {
59
+ const root = record(value);
60
+ if (root.status === "unsupported") {
61
+ if (typeof root.reason !== "string" || !root.reason.trim() || "connections" in root)
62
+ invalid("unsupported discovery");
63
+ return { status: "unsupported", reason: root.reason };
64
+ }
65
+ if (root.status !== "supported" || !Array.isArray(root.connections))
66
+ invalid("discovery envelope");
67
+ return { status: "supported", connections: root.connections.map(decodeConnection) };
68
+ }
69
+ function decodeConnection(value) {
70
+ const row = record(value);
71
+ if (typeof row.connectionId !== "string" || !row.connectionId.trim() || typeof row.label !== "string" || !row.label.trim() || typeof row.enabled !== "boolean" || row.readiness !== "ready" && row.readiness !== "unavailable" && row.readiness !== "disabled")
72
+ invalid("connection reference");
73
+ return {
74
+ connectionId: row.connectionId,
75
+ label: row.label,
76
+ enabled: row.enabled,
77
+ readiness: row.readiness,
78
+ capabilities: decodeCapabilities(row.capabilities),
79
+ ...row.modelSelection !== undefined ? { modelSelection: decodeModelSelection(row.modelSelection) } : {}
80
+ };
81
+ }
82
+ function decodeCapabilities(value) {
83
+ const source = record(value);
84
+ return {
85
+ abort: capabilityFlag(source, "abort"),
86
+ reconnect: capabilityFlag(source, "reconnect"),
87
+ replay: capabilityFlag(source, "replay"),
88
+ permissions: capabilityFlag(source, "permissions"),
89
+ questions: capabilityFlag(source, "questions"),
90
+ todos: capabilityFlag(source, "todos"),
91
+ commands: capabilityFlag(source, "commands"),
92
+ fork: capabilityFlag(source, "fork"),
93
+ revert: capabilityFlag(source, "revert"),
94
+ unrevert: capabilityFlag(source, "unrevert"),
95
+ configOptions: capabilityFlag(source, "configOptions"),
96
+ subagents: capabilityFlag(source, "subagents")
97
+ };
98
+ }
99
+ function capabilityFlag(source, key) {
100
+ const flag = source[key];
101
+ if (typeof flag !== "boolean")
102
+ invalid(`capability ${key}`);
103
+ return flag;
104
+ }
105
+ function decodeModelSelection(value) {
106
+ const row = record(value);
107
+ if (row.status === "unsupported" && row.models === undefined)
108
+ return { status: "unsupported" };
109
+ if (row.status !== "required" && row.status !== "optional")
110
+ invalid("model selection");
111
+ const models = row.models === undefined ? undefined : decodeModels(row.models);
112
+ if (row.status === "required") {
113
+ if (!models?.length)
114
+ invalid("required models");
115
+ return { status: "required", models };
116
+ }
117
+ return { status: "optional", ...models ? { models } : {} };
118
+ }
119
+ function decodeModels(value) {
120
+ if (!Array.isArray(value))
121
+ invalid("models");
122
+ return value.map((item) => {
123
+ const row = record(item);
124
+ if (typeof row.providerId !== "string" || !row.providerId || typeof row.modelId !== "string" || !row.modelId || typeof row.name !== "string" || !row.name || row.description !== undefined && typeof row.description !== "string")
125
+ invalid("model");
126
+ return {
127
+ providerId: row.providerId,
128
+ modelId: row.modelId,
129
+ name: row.name,
130
+ ...typeof row.description === "string" ? { description: row.description } : {}
131
+ };
132
+ });
133
+ }
134
+ function record(value) {
135
+ if (!value || typeof value !== "object" || Array.isArray(value))
136
+ invalid("object");
137
+ return Object.fromEntries(Object.entries(value));
138
+ }
139
+ function invalid(field) {
140
+ throw new Error(`Invalid agent connection ${field}`);
141
+ }
142
+ // src/tool-names.ts
143
+ var TOOL_NAME_ALIASES = {
144
+ agent: "task",
145
+ subagent: "task",
146
+ spawn_agent: "task",
147
+ spawnagent: "task",
148
+ create_subagent: "task",
149
+ mcp__claxedo__create_subagent: "task",
150
+ claxedo_create_subagent: "task",
151
+ command: "bash",
152
+ shell: "bash",
153
+ local_shell: "bash",
154
+ read_file: "read",
155
+ write_file: "write",
156
+ edit_file: "edit",
157
+ ls: "list",
158
+ askuserquestion: "question",
159
+ web_search: "websearch"
160
+ };
161
+ function canonicalToolName(name) {
162
+ const lowered = name.toLowerCase();
163
+ return TOOL_NAME_ALIASES[lowered] ?? lowered;
164
+ }
165
+ function toolNameAliases() {
166
+ return Object.entries(TOOL_NAME_ALIASES);
167
+ }
168
+
169
+ // src/content.ts
170
+ function isSubagentSpawnToolName(toolName) {
171
+ return canonicalToolName(toolName) === "task";
172
+ }
173
+ function isStringField(container, key) {
174
+ return typeof container[key] === "string";
175
+ }
176
+ function optionalIs(container, key, check) {
177
+ return container[key] === undefined || check(container[key]);
178
+ }
179
+ function isTokenUsage(value) {
180
+ if (!isRecord(value))
181
+ return false;
182
+ const cache = value.cache;
183
+ if (!isRecord(cache) || typeof cache.read !== "number" || typeof cache.write !== "number")
184
+ return false;
185
+ if (typeof value.input !== "number" || typeof value.output !== "number" || typeof value.reasoning !== "number")
186
+ return false;
187
+ return optionalIs(value, "total", (total) => typeof total === "number");
188
+ }
189
+ function isSpan(value) {
190
+ return isRecord(value) && typeof value.start === "number" && optionalIs(value, "end", (end) => typeof end === "number");
191
+ }
192
+ function isMessageError(value) {
193
+ return isRecord(value) && typeof value.name === "string" && isRecord(value.data);
194
+ }
195
+ function isToolState(value) {
196
+ if (!isRecord(value) || !isRecord(value.input))
197
+ return false;
198
+ switch (value.status) {
199
+ case "pending":
200
+ return isStringField(value, "raw");
201
+ case "running":
202
+ return isSpan(value.time);
203
+ case "completed":
204
+ return isStringField(value, "output") && isStringField(value, "title") && isRecord(value.metadata) && isSpan(value.time);
205
+ case "error":
206
+ return isStringField(value, "error") && isSpan(value.time);
207
+ default:
208
+ return false;
209
+ }
210
+ }
211
+ function isHandoffEnd(value) {
212
+ return isRecord(value) && typeof value.id === "string" && typeof value.access === "string";
213
+ }
214
+ function hasPartIdentity(value) {
215
+ return isRecord(value) && isStringField(value, "id") && isStringField(value, "sessionID") && isStringField(value, "messageID") && isStringField(value, "type");
216
+ }
217
+ function hasVariantFields(part) {
218
+ switch (part.type) {
219
+ case "text":
220
+ return isStringField(part, "text");
221
+ case "reasoning":
222
+ return isStringField(part, "text") && isSpan(part.time);
223
+ case "file":
224
+ return isStringField(part, "mime") && isStringField(part, "url");
225
+ case "tool":
226
+ return isStringField(part, "callID") && isStringField(part, "tool") && isToolState(part.state);
227
+ case "subtask":
228
+ return isStringField(part, "prompt") && isStringField(part, "description") && isStringField(part, "agent");
229
+ case "step-start":
230
+ return optionalIs(part, "snapshot", (snapshot) => typeof snapshot === "string");
231
+ case "step-finish":
232
+ return isStringField(part, "reason") && typeof part.cost === "number" && isTokenUsage(part.tokens);
233
+ case "snapshot":
234
+ return isStringField(part, "snapshot");
235
+ case "patch":
236
+ return isStringField(part, "hash") && Array.isArray(part.files) && part.files.every((file) => typeof file === "string");
237
+ case "agent":
238
+ return isStringField(part, "name");
239
+ case "retry":
240
+ return typeof part.attempt === "number" && isMessageError(part.error) && isRecord(part.time) && typeof part.time.created === "number";
241
+ case "compaction":
242
+ return typeof part.auto === "boolean";
243
+ case "handoff":
244
+ return isHandoffEnd(part.from) && isHandoffEnd(part.to);
245
+ default:
246
+ return false;
247
+ }
248
+ }
249
+ function isAgentContentPart(value) {
250
+ return hasPartIdentity(value) && hasVariantFields(value);
251
+ }
252
+ function parseAgentContentPart(value) {
253
+ return isAgentContentPart(value) ? value : undefined;
254
+ }
255
+ function isAgentMessageInfo(value) {
256
+ return isRecord(value) && isStringField(value, "id") && isStringField(value, "role") && isStringField(value, "sessionID") && optionalIs(value, "parentID", (parentID) => typeof parentID === "string") && optionalIs(value, "tokens", isTokenUsage) && optionalIs(value, "error", isMessageError);
257
+ }
258
+ function isAgentMessage(value) {
259
+ return isRecord(value) && isAgentMessageInfo(value.info) && Array.isArray(value.parts) && value.parts.every(isAgentContentPart);
260
+ }
261
+ function parseAgentMessage(value) {
262
+ return isAgentMessage(value) ? value : undefined;
263
+ }
264
+ // src/credential-broker-errors.ts
265
+ var CREDENTIAL_BROKER_ERRORS = {
266
+ binding_route_required: {
267
+ fault: "harness",
268
+ message: "The credential broker serves binding paths only"
269
+ },
270
+ runtime_token_required: {
271
+ fault: "harness",
272
+ message: "The request carried no runtime token, or two that disagree"
273
+ },
274
+ runtime_token_invalid: {
275
+ fault: "credential",
276
+ message: "The runtime token could not be verified"
277
+ },
278
+ binding_not_permitted: {
279
+ fault: "harness",
280
+ message: "This runtime token does not name that binding"
281
+ },
282
+ binding_unavailable: {
283
+ fault: "credential",
284
+ message: "The binding names no account this runtime can spend"
285
+ },
286
+ credential_unavailable: {
287
+ fault: "credential",
288
+ message: "The account behind this binding has no readable value"
289
+ },
290
+ binding_destination_invalid: {
291
+ fault: "harness",
292
+ message: "The binding's destination is not a usable vendor origin"
293
+ },
294
+ binding_injection_invalid: {
295
+ fault: "harness",
296
+ message: "The binding names a header the broker cannot set"
297
+ },
298
+ request_outside_policy: {
299
+ fault: "harness",
300
+ message: "The request is outside the routes this binding allows"
301
+ },
302
+ upstream_unavailable: {
303
+ fault: "model",
304
+ message: "The vendor could not be reached"
305
+ },
306
+ upstream_redirect_refused: {
307
+ fault: "model",
308
+ message: "The vendor answered with a redirect, which the broker does not follow"
309
+ },
310
+ broker_authority_unavailable: {
311
+ fault: "harness",
312
+ message: "The credential authority could not be reached"
313
+ },
314
+ loopback_required: {
315
+ fault: "harness",
316
+ message: "The credential broker answers loopback callers only"
317
+ }
318
+ };
319
+ function credentialBrokerErrorCode(message) {
320
+ const inBody = codeFromBody(message);
321
+ if (inBody)
322
+ return inBody;
323
+ const inProse = codeInProse.exec(message)?.[1];
324
+ return inProse && isCredentialBrokerErrorCode(inProse) ? inProse : undefined;
325
+ }
326
+ var codeInProse = new RegExp(`\\b(${Object.keys(CREDENTIAL_BROKER_ERRORS).join("|")})\\b`);
327
+ function codeFromBody(message) {
328
+ const start = message.indexOf("{");
329
+ const end = message.lastIndexOf("}");
330
+ if (start === -1 || end <= start)
331
+ return;
332
+ try {
333
+ const body = JSON.parse(message.slice(start, end + 1));
334
+ const error = isRecord(body) ? body.error : undefined;
335
+ const code = typeof error === "string" ? error : isRecord(error) ? error.code : undefined;
336
+ return typeof code === "string" && isCredentialBrokerErrorCode(code) ? code : undefined;
337
+ } catch {
338
+ return;
339
+ }
340
+ }
341
+ function isCredentialBrokerErrorCode(value) {
342
+ return Object.hasOwn(CREDENTIAL_BROKER_ERRORS, value);
343
+ }
344
+ // src/errors.ts
345
+ var AGENT_RUNTIME_ERROR_CODES = [
346
+ "selection_required",
347
+ "harness_unavailable",
348
+ "workspace_offline",
349
+ "unsupported_operation",
350
+ "replay_gap",
351
+ "upstream_error",
352
+ "invalid_execution_binding"
353
+ ];
354
+
355
+ class AgentRuntimeContractError extends Error {
356
+ detail;
357
+ constructor(detail) {
358
+ super(detail.message);
359
+ this.detail = detail;
360
+ this.name = "AgentRuntimeContractError";
361
+ }
362
+ }
363
+ var BINDING_FIELDS = ["sessionId", "workspaceId", "directory", "connectionId", "upstreamSessionId"];
364
+ function assertAgentExecutionBinding(binding, expected = binding) {
365
+ if ((binding.scope ?? "workspace") !== (expected.scope ?? "workspace")) {
366
+ throw new AgentRuntimeContractError({ code: "invalid_execution_binding", field: "scope", message: "execution binding scope mismatch" });
367
+ }
368
+ if (binding.scope !== undefined && binding.scope !== "workspace") {
369
+ throw new AgentRuntimeContractError({ code: "invalid_execution_binding", field: "scope", message: "workspace execution scope is required" });
370
+ }
371
+ for (const field of BINDING_FIELDS) {
372
+ const value = binding[field];
373
+ if (typeof value !== "string" || value.trim() === "") {
374
+ throw new AgentRuntimeContractError({
375
+ code: "invalid_execution_binding",
376
+ field,
377
+ message: `execution binding ${field} is required`
378
+ });
379
+ }
380
+ if (binding[field] !== expected[field]) {
381
+ throw new AgentRuntimeContractError({
382
+ code: "invalid_execution_binding",
383
+ field,
384
+ message: `execution binding ${field} mismatch`
385
+ });
386
+ }
387
+ }
388
+ return binding;
389
+ }
390
+ // src/events.ts
391
+ var AGENT_PRESENTATION_EVENT_TYPE_REGISTRY = {
392
+ "message.updated": true,
393
+ "message.removed": true,
394
+ "message.part.updated": true,
395
+ "message.part.removed": true,
396
+ "message.part.delta": true,
397
+ "message.completed": true,
398
+ "permission.asked": true,
399
+ "permission.replied": true,
400
+ "question.asked": true,
401
+ "question.replied": true,
402
+ "question.rejected": true,
403
+ "todo.updated": true,
404
+ "session.status": true,
405
+ "session.idle": true,
406
+ "session.error": true,
407
+ "session.updated": true,
408
+ "session.diff": true,
409
+ "session.compacted": true,
410
+ "session.agent": true,
411
+ "session.config": true,
412
+ "session.usage": true,
413
+ "runtime.diagnostic": true,
414
+ "server.connected": true,
415
+ "server.heartbeat": true
416
+ };
417
+ function isAgentPresentationEventType(value) {
418
+ return Object.hasOwn(AGENT_PRESENTATION_EVENT_TYPE_REGISTRY, value);
419
+ }
420
+ var AGENT_PRESENTATION_EVENT_TYPES = Object.keys(AGENT_PRESENTATION_EVENT_TYPE_REGISTRY).filter(isAgentPresentationEventType);
421
+ // src/files.ts
422
+ function isAgentReviewFileDiff(value) {
423
+ if (!value || typeof value !== "object" || Array.isArray(value))
424
+ return false;
425
+ if (!("file" in value) || typeof value.file !== "string")
426
+ return false;
427
+ if (!("additions" in value) || typeof value.additions !== "number")
428
+ return false;
429
+ if (!("deletions" in value) || typeof value.deletions !== "number")
430
+ return false;
431
+ if ("patch" in value && value.patch !== undefined && typeof value.patch !== "string")
432
+ return false;
433
+ if ("before" in value && value.before !== undefined && typeof value.before !== "string")
434
+ return false;
435
+ if ("after" in value && value.after !== undefined && typeof value.after !== "string")
436
+ return false;
437
+ if (!("status" in value) || value.status === undefined)
438
+ return true;
439
+ return value.status === "added" || value.status === "deleted" || value.status === "modified";
440
+ }
441
+ function agentReviewFileDiffList(value) {
442
+ if (Array.isArray(value) && value.every(isAgentReviewFileDiff))
443
+ return value;
444
+ if (Array.isArray(value))
445
+ return value.filter(isAgentReviewFileDiff);
446
+ if (isAgentReviewFileDiff(value))
447
+ return [value];
448
+ if (!value || typeof value !== "object")
449
+ return [];
450
+ return Object.values(value).filter(isAgentReviewFileDiff);
451
+ }
452
+ // src/harness-effort.ts
453
+ var HARNESS_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
454
+ function isHarnessEffortLevel(value) {
455
+ return HARNESS_EFFORT_LEVELS.includes(value);
456
+ }
457
+ var NO_HARNESS_EFFORT = { status: "unsupported", models: [] };
458
+ function harnessEffortVerdict(catalog, modelID, effort) {
459
+ if (!effort)
460
+ return "accepted";
461
+ if (!catalog)
462
+ return "unknown";
463
+ if (catalog.status === "unsupported")
464
+ return "refused";
465
+ if (catalog.status === "unresolved")
466
+ return "unknown";
467
+ const row = modelID ? catalog.models.find((model) => model.modelID === modelID) : undefined;
468
+ if (!row)
469
+ return "refused";
470
+ return row.levels.includes(effort) ? "accepted" : "refused";
471
+ }
472
+ function parseHarnessEffortLevels(value) {
473
+ if (!isRecord(value))
474
+ return;
475
+ const status = value.status;
476
+ if (status !== "resolved" && status !== "unresolved" && status !== "unsupported")
477
+ return;
478
+ const models = Array.isArray(value.models) ? value.models : [];
479
+ return {
480
+ status,
481
+ models: models.flatMap((entry) => {
482
+ if (!isRecord(entry))
483
+ return [];
484
+ const modelID = entry.modelID;
485
+ if (typeof modelID !== "string" || !modelID)
486
+ return [];
487
+ const levels = Array.isArray(entry.levels) ? entry.levels.filter((level) => typeof level === "string" && !!level) : [];
488
+ return [{
489
+ modelID,
490
+ levels,
491
+ ...typeof entry.default === "string" && entry.default ? { default: entry.default } : {}
492
+ }];
493
+ })
494
+ };
495
+ }
496
+ function harnessEffortRefusal(input) {
497
+ if (input.catalog?.status !== "resolved")
498
+ return;
499
+ if (!input.effort)
500
+ return;
501
+ if (harnessEffortVerdict(input.catalog, input.modelID, input.effort) !== "refused")
502
+ return;
503
+ const levels = input.catalog.models.find((model) => model.modelID === input.modelID)?.levels ?? [];
504
+ return `The ${input.harness} harness does not run ${input.modelID ?? "its default model"} at effort ${input.effort}; ${levels.length > 0 ? `it accepts ${levels.join(", ")}` : "it accepts no effort for that model"}`;
505
+ }
506
+ // src/harness-table.ts
507
+ var HARNESS_IDS = ["claude", "codex", "cursor"];
508
+ var HARNESS_TABLE = {
509
+ claude: {
510
+ label: "Claude Code",
511
+ vendor: "Anthropic",
512
+ providerIds: ["claude-sdk", "claude-acp", "anthropic"],
513
+ connectProvider: "claude-sdk",
514
+ vendorProvider: "anthropic",
515
+ machineLoginServes: ["claude-sdk", "claude-acp"]
516
+ },
517
+ codex: {
518
+ label: "Codex",
519
+ vendor: "OpenAI",
520
+ providerIds: ["codex-app-server", "openai"],
521
+ connectProvider: "codex-app-server",
522
+ vendorProvider: "openai",
523
+ machineLoginServes: ["codex-app-server", "openai"]
524
+ },
525
+ cursor: {
526
+ label: "Cursor",
527
+ vendor: "Cursor",
528
+ providerIds: ["cursor-sdk", "cursor-acp", "cursor"],
529
+ connectProvider: "cursor-sdk",
530
+ vendorProvider: "cursor",
531
+ machineLoginServes: ["cursor-acp"]
532
+ }
533
+ };
534
+ function isHarnessId(value) {
535
+ return HARNESS_IDS.includes(value);
536
+ }
537
+ function harnessForProviderId(id) {
538
+ return HARNESS_IDS.find((harness) => HARNESS_TABLE[harness].providerIds.includes(id));
539
+ }
540
+ function harnessBindingIds(harness) {
541
+ const record2 = HARNESS_TABLE[harness];
542
+ return record2.providerIds.filter((id) => id !== record2.vendorProvider);
543
+ }
544
+ // src/harnesses.ts
545
+ var AGENT_HARNESS_DEFINITIONS = [
546
+ {
547
+ key: "claude",
548
+ id: "claude",
549
+ access: "native",
550
+ label: "Claude",
551
+ authEnv: "ANTHROPIC_API_KEY",
552
+ authSlot: "anthropic"
553
+ },
554
+ {
555
+ key: "codex",
556
+ id: "codex",
557
+ access: "native",
558
+ label: "Codex",
559
+ authEnv: "OPENAI_API_KEY",
560
+ authSlot: "openai"
561
+ },
562
+ {
563
+ key: "cursor",
564
+ id: "cursor",
565
+ access: "native",
566
+ label: "Cursor",
567
+ authEnv: "CURSOR_API_KEY",
568
+ authSlot: "cursor"
569
+ },
570
+ {
571
+ key: "pi",
572
+ id: "pi",
573
+ access: "native",
574
+ label: "Pi",
575
+ authEnv: null,
576
+ authSlot: null
577
+ },
578
+ {
579
+ key: "opencode",
580
+ id: "opencode",
581
+ access: "native",
582
+ label: "OpenCode",
583
+ authEnv: null,
584
+ authSlot: null
585
+ }
586
+ ];
587
+ var AGENT_HARNESS_IDS = ["claude", "codex", "cursor", "pi", "opencode"];
588
+ var AGENT_HARNESS_ACCESSES = ["connection", "native"];
589
+ var AGENT_HARNESS_KEYS = AGENT_HARNESS_DEFINITIONS.map((item) => item.key);
590
+ var ACP_CONNECTION_ID_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
591
+ function isAcpConnectionId(id) {
592
+ return ACP_CONNECTION_ID_PATTERN.test(id);
593
+ }
594
+ function harnessDefinition(input) {
595
+ if (typeof input === "string")
596
+ return AGENT_HARNESS_DEFINITIONS.find((item) => item.key === input);
597
+ return AGENT_HARNESS_DEFINITIONS.find((item) => item.id === input.id && item.access === input.access);
598
+ }
599
+ function isAgentHarnessId(id) {
600
+ return AGENT_HARNESS_IDS.includes(id);
601
+ }
602
+ function isAgentHarnessAccess(access) {
603
+ return AGENT_HARNESS_ACCESSES.includes(access);
604
+ }
605
+ function normalizeAgentHarnessTransport(input) {
606
+ if (input === undefined)
607
+ return;
608
+ if (input === "stdio" || input === "streamable-http" || input === "websocket")
609
+ return input;
610
+ return;
611
+ }
612
+ function harnessKey(input) {
613
+ const definition = harnessDefinition(input);
614
+ if (definition)
615
+ return definition.key;
616
+ if (input.access === "connection" && isAcpConnectionId(input.id))
617
+ return `connection:${input.id}`;
618
+ return;
619
+ }
620
+ function normalizeHarnessIdentity(input) {
621
+ if (typeof input === "string") {
622
+ if (isAgentHarnessId(input))
623
+ return { id: input, access: "native" };
624
+ return;
625
+ }
626
+ const row = asRecord(input);
627
+ if (!row)
628
+ return;
629
+ const idInput = typeof row.id === "string" ? row.id : undefined;
630
+ const accessInput = typeof row.access === "string" ? row.access : undefined;
631
+ const id = idInput && isAgentHarnessId(idInput) ? idInput : idInput && accessInput === "connection" && isAcpConnectionId(idInput) ? idInput : undefined;
632
+ const access = accessInput && isAgentHarnessAccess(accessInput) ? accessInput : id ? "native" : undefined;
633
+ if (!id || !access)
634
+ return;
635
+ return { id, access };
636
+ }
637
+ var HARNESS_INSTRUCTION_CHANNELS = [
638
+ "turn-system-prompt",
639
+ "thread-start",
640
+ "prompt-prefix",
641
+ "none"
642
+ ];
643
+ // src/question-answers.ts
644
+ var MULTI_SELECT_JOIN = ", ";
645
+ function reconstructQuestionAnswers(questions, answers) {
646
+ return questions.map((question) => {
647
+ const value = answers[question.question];
648
+ if (typeof value !== "string" || !value)
649
+ return [];
650
+ const labels = new Set(question.optionLabels);
651
+ if (labels.has(value) || !question.multiple)
652
+ return [value];
653
+ const selected = value.split(MULTI_SELECT_JOIN);
654
+ return selected.length > 1 && selected.every((label) => labels.has(label)) ? selected : [value];
655
+ });
656
+ }
657
+ // src/session-group.ts
658
+ var SESSION_GROUP_SLOTS = ["primary", "planning", "implementation", "review"];
659
+ function isSessionGroupSlot(value) {
660
+ return SESSION_GROUP_SLOTS.includes(value);
661
+ }
662
+ function parseSessionModelGroup(input) {
663
+ if (!isRecord(input))
664
+ return { field: "group", message: "group must be an object of slot entries" };
665
+ const group = {};
666
+ for (const [slot, value] of Object.entries(input)) {
667
+ if (!isSessionGroupSlot(slot)) {
668
+ return { field: `group.${slot}`, message: `group slot must be one of ${SESSION_GROUP_SLOTS.join(", ")}` };
669
+ }
670
+ const entry = parseEntry(`group.${slot}`, value);
671
+ if ("field" in entry)
672
+ return entry;
673
+ group[slot] = entry.entry;
674
+ }
675
+ return { group };
676
+ }
677
+ function sessionVariantForEffort(effort) {
678
+ return effort ? { variant: effort } : {};
679
+ }
680
+ function sessionModelGroupJson(group) {
681
+ return group && Object.keys(group).length > 0 ? JSON.stringify(group) : null;
682
+ }
683
+ function parseStoredSessionModelGroup(json) {
684
+ if (!json)
685
+ return;
686
+ const parsed = jsonOrUndefined(json);
687
+ if (parsed === undefined)
688
+ return;
689
+ const result = parseSessionModelGroup(parsed);
690
+ return "group" in result && Object.keys(result.group).length > 0 ? result.group : undefined;
691
+ }
692
+ function jsonOrUndefined(json) {
693
+ try {
694
+ return JSON.parse(json);
695
+ } catch {
696
+ return;
697
+ }
698
+ }
699
+ function parseEntry(field, value) {
700
+ if (!isRecord(value))
701
+ return { field, message: "group slot must be an object" };
702
+ const harness = normalizeHarnessIdentity(value.harness);
703
+ if (!harness)
704
+ return { field: `${field}.harness`, message: "group slot needs a known harness" };
705
+ const model = parseModel(value.model);
706
+ if (!model)
707
+ return { field: `${field}.model`, message: "group slot needs a model with providerID and modelID" };
708
+ if (value.effort !== undefined && (typeof value.effort !== "string" || !value.effort)) {
709
+ return { field: `${field}.effort`, message: "group slot effort must be a non-empty string" };
710
+ }
711
+ return {
712
+ entry: {
713
+ harness,
714
+ model,
715
+ ...typeof value.effort === "string" ? { effort: value.effort } : {}
716
+ }
717
+ };
718
+ }
719
+ function parseModel(value) {
720
+ if (!isRecord(value))
721
+ return;
722
+ const providerID = value.providerID;
723
+ const modelID = value.modelID;
724
+ if (typeof providerID !== "string" || !providerID)
725
+ return;
726
+ if (typeof modelID !== "string" || !modelID)
727
+ return;
728
+ return { providerID, modelID };
729
+ }
730
+ // src/sessions.ts
731
+ function connectionIdForHarness(harness) {
732
+ return `${harness.access}:${harness.id}`;
733
+ }
734
+ // src/usage-windows.ts
735
+ var USAGE_WINDOW_NAMES = {
736
+ claude: { five_hour: "session", seven_day: "weekly", seven_day_opus: "weekly_opus" },
737
+ codex: {
738
+ primary_window: "session",
739
+ secondary_window: "weekly",
740
+ credit_window: "credits",
741
+ spark_primary_window: "spark_session",
742
+ spark_secondary_window: "spark_weekly"
743
+ },
744
+ cursor: { primary_window: "plan", secondary_window: "auto", tertiary_window: "api" }
745
+ };
746
+ var CODEX_WINDOW_NAME_BY_SECONDS = {
747
+ 18000: "session",
748
+ 604800: "weekly"
749
+ };
750
+
751
+ // src/index.ts
752
+ var AGENT_RUNTIME_CONTRACT_VERSION = 1;
753
+ export {
754
+ toolNameAliases,
755
+ sessionVariantForEffort,
756
+ sessionModelGroupJson,
757
+ reconstructQuestionAnswers,
758
+ parseStoredSessionModelGroup,
759
+ parseSessionModelGroup,
760
+ parseHarnessEffortLevels,
761
+ parseAgentMessage,
762
+ parseAgentContentPart,
763
+ normalizeHarnessIdentity,
764
+ normalizeAgentHarnessTransport,
765
+ isSubagentSpawnToolName,
766
+ isSessionGroupSlot,
767
+ isRecord,
768
+ isHarnessId,
769
+ isHarnessEffortLevel,
770
+ isCredentialBrokerErrorCode,
771
+ isAgentReviewFileDiff,
772
+ isAgentPresentationEventType,
773
+ isAgentMessageInfo,
774
+ isAgentMessage,
775
+ isAgentHarnessId,
776
+ isAgentHarnessAccess,
777
+ isAgentContentPart,
778
+ isAcpConnectionId,
779
+ harnessKey,
780
+ harnessForProviderId,
781
+ harnessEffortVerdict,
782
+ harnessEffortRefusal,
783
+ harnessDefinition,
784
+ harnessBindingIds,
785
+ emailFromClaims,
786
+ decodeModelSelection,
787
+ decodeHarnessConnectionsCatalog,
788
+ credentialBrokerErrorCode,
789
+ connectionIdForHarness,
790
+ canonicalToolName,
791
+ assertAgentExecutionBinding,
792
+ asText,
793
+ asRecord,
794
+ agentReviewFileDiffList,
795
+ accountIdFromClaims,
796
+ USAGE_WINDOW_NAMES,
797
+ SESSION_GROUP_SLOTS,
798
+ NO_HARNESS_EFFORT,
799
+ HARNESS_TABLE,
800
+ HARNESS_INSTRUCTION_CHANNELS,
801
+ HARNESS_IDS,
802
+ HARNESS_EFFORT_LEVELS,
803
+ CREDENTIAL_BROKER_ERRORS,
804
+ CODEX_WINDOW_NAME_BY_SECONDS,
805
+ AgentRuntimeContractError,
806
+ AGENT_RUNTIME_ERROR_CODES,
807
+ AGENT_RUNTIME_CONTRACT_VERSION,
808
+ AGENT_PRESENTATION_EVENT_TYPE_REGISTRY,
809
+ AGENT_PRESENTATION_EVENT_TYPES,
810
+ AGENT_HARNESS_KEYS,
811
+ AGENT_HARNESS_IDS,
812
+ AGENT_HARNESS_DEFINITIONS,
813
+ AGENT_HARNESS_ACCESSES,
814
+ ACP_CONNECTION_ID_PATTERN
815
+ };