@meistrari/agent-core 0.2.0-experimental.0 → 0.2.0-experimental.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +82 -0
  2. package/docs/consumer-capability-matrix.md +374 -0
  3. package/package.json +17 -10
  4. package/scripts/generate-codex-protocol.ts +711 -0
  5. package/src/agents/agent-operation.ts +8 -0
  6. package/src/agents/agent-provider.ts +3 -0
  7. package/src/agents/agent-run.ts +14 -2
  8. package/src/agents/agent-runtime-error.ts +28 -0
  9. package/src/agents/agent-session-events.ts +33 -0
  10. package/src/agents/agent-tool-runner.ts +12 -11
  11. package/src/agents/agent-tool.ts +12 -4
  12. package/src/agents/author-context.ts +1 -1
  13. package/src/agents/claude/claude-auth.ts +40 -0
  14. package/src/agents/claude/claude-browser-turn-metadata.ts +70 -0
  15. package/src/agents/claude/claude-code-process.ts +98 -0
  16. package/src/agents/claude/claude-command-mapper.ts +63 -3
  17. package/src/agents/claude/claude-desktop.ts +55 -0
  18. package/src/agents/claude/claude-event-mapper.ts +876 -124
  19. package/src/agents/claude/claude-file-change.ts +128 -0
  20. package/src/agents/claude/claude-provider.ts +344 -29
  21. package/src/agents/claude/claude-run.ts +922 -91
  22. package/src/agents/claude/claude-selected-repository-instructions.ts +91 -0
  23. package/src/agents/claude/claude-skill-catalog.ts +75 -0
  24. package/src/agents/claude/claude-steered-notifications.ts +180 -0
  25. package/src/agents/claude/claude-tool-mapper.ts +81 -2
  26. package/src/agents/claude/claude-workspace-skills.ts +87 -0
  27. package/src/agents/claude/index.ts +2 -0
  28. package/src/agents/codex/codex-auth-mapper.ts +27 -0
  29. package/src/agents/codex/codex-auth.ts +19 -0
  30. package/src/agents/codex/codex-browser-auth-broker.ts +320 -0
  31. package/src/agents/codex/codex-browser-auth-status.ts +55 -0
  32. package/src/agents/codex/codex-command-mapper.ts +38 -3
  33. package/src/agents/codex/codex-event-mapper.ts +375 -64
  34. package/src/agents/codex/codex-json-rpc-client.ts +66 -21
  35. package/src/agents/codex/codex-provider.ts +118 -236
  36. package/src/agents/codex/codex-run-auth.ts +113 -0
  37. package/src/agents/codex/codex-run.ts +428 -48
  38. package/src/agents/codex/codex-tool-mapper.ts +2 -2
  39. package/src/agents/codex/codex.errors.ts +8 -0
  40. package/src/agents/codex/generated/meta.gen.ts +144 -6
  41. package/src/agents/codex/generated/namespaces.gen.ts +92 -3
  42. package/src/agents/codex/generated/schema.gen.ts +24698 -15638
  43. package/src/agents/codex/lazy-codex-run-auth.ts +47 -0
  44. package/src/agents/index.ts +5 -0
  45. package/src/agents/input-attachment-preparation.ts +13 -0
  46. package/src/agents/mcp-tool-content.ts +82 -0
  47. package/src/agents/model-rebinding-run.ts +14 -3
  48. package/src/agents/selected-repository-instructions.ts +202 -0
  49. package/src/agents/session-context.ts +41 -0
  50. package/src/agents/subscription-token-refresh.ts +73 -0
  51. package/src/agents/user-input-request.ts +19 -20
  52. package/src/errors/index.ts +1 -1
  53. package/src/errors/validation-error.ts +6 -0
  54. package/src/protocol/agent-catalog.ts +159 -0
  55. package/src/protocol/agent-command.ts +54 -7
  56. package/src/protocol/agent-content.ts +36 -16
  57. package/src/protocol/agent-event.ts +210 -73
  58. package/src/protocol/agent-identity.ts +29 -0
  59. package/src/protocol/agent-json.ts +122 -8
  60. package/src/protocol/agent-metadata.ts +2 -2
  61. package/src/protocol/agent-model.ts +13 -1
  62. package/src/protocol/agent-notification.ts +110 -0
  63. package/src/protocol/agent-presentation.ts +71 -20
  64. package/src/protocol/agent-tool.ts +66 -10
  65. package/src/protocol/agent-usage.ts +4 -1
  66. package/src/protocol/agent-user-input.ts +4 -4
  67. package/src/protocol/agent-work.ts +12 -10
  68. package/src/protocol/index.ts +2 -0
  69. package/src/protocol/rejected-keys.ts +11 -0
  70. package/src/provenance.gen.ts +3 -3
  71. package/src/steps/contract.ts +4 -1
  72. package/src/steps/projector.ts +17 -1
  73. package/src/supervisor/agent-provider-factory.ts +60 -5
  74. package/src/supervisor/bootstrap-binder.ts +3 -2
  75. package/src/supervisor/index.ts +1 -1
  76. package/src/supervisor/persistence/supervisor-store.ts +22 -8
  77. package/src/supervisor/runtime-handler.ts +30 -2
  78. package/src/supervisor-protocol/agent-event-wrapper.ts +30 -0
  79. package/src/supervisor-protocol/bootstrap.ts +4 -1
  80. package/src/supervisor-protocol/command-body.ts +4 -1
  81. package/src/supervisor-protocol/envelopes/supervisor-to-control-plane.ts +1 -0
  82. package/src/testing/in-memory-runtime-control-plane.ts +118 -12
  83. package/src/testing/index.ts +1 -1
  84. package/src/worker-runtime-client/command-pump.ts +85 -10
  85. package/src/worker-runtime-client/connection-attempt.ts +95 -20
  86. package/src/worker-runtime-client/frame-processor.ts +242 -58
  87. package/src/worker-runtime-client/index.ts +8 -2
  88. package/src/worker-runtime-client/ports.ts +34 -2
  89. package/src/worker-runtime-client/rpc-request-manager.ts +152 -107
  90. package/src/worker-runtime-client/sandbox-connection-runtime.ts +72 -35
@@ -13,14 +13,128 @@ export interface JsonObject { readonly [key: string]: JsonValue }
13
13
  export type JsonArray = readonly JsonValue[]
14
14
  export type JsonValue = JsonPrimitive | JsonObject | JsonArray
15
15
 
16
- export const jsonValueSchema: ZodType<JsonValue> = z.lazy(() => z.union([
17
- jsonPrimitiveSchema,
18
- z.array(jsonValueSchema),
19
- z.record(z.string(), jsonValueSchema),
20
- ]))
21
-
22
- export const jsonObjectSchema: ZodType<JsonObject> = z.record(z.string(), jsonValueSchema)
23
- export const jsonArraySchema: ZodType<JsonArray> = z.array(jsonValueSchema)
16
+ const jsonWireValueSchema = z.json()
17
+ type JsonWireValue = z.infer<typeof jsonWireValueSchema>
18
+ const jsonWireObjectSchema = z.record(z.string(), jsonWireValueSchema)
19
+ const jsonWireArraySchema = z.array(jsonWireValueSchema)
20
+
21
+ export const jsonValueSchema: ZodType<JsonValue> = z
22
+ .preprocess(encodeJsonObjectKeys, jsonWireValueSchema)
23
+ .overwrite(decodeJsonObjectKeys)
24
+
25
+ export const jsonObjectSchema: ZodType<JsonObject> = z
26
+ .preprocess(encodeJsonObjectKeys, jsonWireObjectSchema)
27
+ .overwrite(decodeJsonObject)
28
+
29
+ export const jsonArraySchema: ZodType<JsonArray> = z
30
+ .preprocess(encodeJsonObjectKeys, jsonWireArraySchema)
31
+ .overwrite(values => values.map(decodeJsonObjectKeys))
32
+
33
+ const JSON_VALIDATION_KEY_PREFIX = '$'
34
+ const invalidJsonValue = Symbol('invalid canonical JSON value')
35
+
36
+ function encodeJsonObjectKeys(value: unknown): unknown {
37
+ return encodeJsonValue(value, new WeakSet())
38
+ }
39
+
40
+ function encodeJsonValue(value: unknown, ancestors: WeakSet<object>): unknown {
41
+ if (Array.isArray(value))
42
+ return encodeJsonArray(value, ancestors)
43
+ if (typeof value !== 'object' || value === null)
44
+ return value
45
+ if (!isPlainObject(value))
46
+ return invalidJsonValue
47
+ return encodeJsonObject(value, ancestors)
48
+ }
49
+
50
+ function encodeJsonArray(value: unknown[], ancestors: WeakSet<object>): unknown {
51
+ if (ancestors.has(value))
52
+ return invalidJsonValue
53
+ ancestors.add(value)
54
+
55
+ try {
56
+ const encoded: unknown[] = []
57
+ for (let index = 0; index < value.length; index += 1) {
58
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index))
59
+ if (!descriptor?.enumerable || !('value' in descriptor))
60
+ return invalidJsonValue
61
+ const entry = encodeJsonValue(descriptor.value, ancestors)
62
+ if (entry === invalidJsonValue)
63
+ return invalidJsonValue
64
+ encoded.push(entry)
65
+ }
66
+
67
+ for (const key of Reflect.ownKeys(value)) {
68
+ const descriptor = Object.getOwnPropertyDescriptor(value, key)
69
+ if (!descriptor || !descriptor.enumerable)
70
+ continue
71
+ if (typeof key !== 'string' || !isArrayIndex(key, value.length))
72
+ return invalidJsonValue
73
+ }
74
+ return encoded
75
+ }
76
+ finally {
77
+ ancestors.delete(value)
78
+ }
79
+ }
80
+
81
+ function encodeJsonObject(value: object, ancestors: WeakSet<object>): unknown {
82
+ if (ancestors.has(value))
83
+ return invalidJsonValue
84
+ ancestors.add(value)
85
+
86
+ try {
87
+ const entries: Array<[string, unknown]> = []
88
+ for (const key of Reflect.ownKeys(value)) {
89
+ const descriptor = Object.getOwnPropertyDescriptor(value, key)
90
+ if (!descriptor || !descriptor.enumerable)
91
+ continue
92
+ if (typeof key !== 'string' || !('value' in descriptor))
93
+ return invalidJsonValue
94
+ const entry = encodeJsonValue(descriptor.value, ancestors)
95
+ if (entry === invalidJsonValue)
96
+ return invalidJsonValue
97
+ entries.push([encodeJsonKey(key), entry])
98
+ }
99
+ return Object.fromEntries(entries)
100
+ }
101
+ finally {
102
+ ancestors.delete(value)
103
+ }
104
+ }
105
+
106
+ function decodeJsonObjectKeys(value: JsonWireValue): JsonWireValue {
107
+ if (Array.isArray(value))
108
+ return value.map(decodeJsonObjectKeys)
109
+ if (typeof value !== 'object' || value === null)
110
+ return value
111
+ return decodeJsonObject(value)
112
+ }
113
+
114
+ function decodeJsonObject(value: Record<string, JsonWireValue>): Record<string, JsonWireValue> {
115
+ const entries: Array<[string, JsonWireValue]> = []
116
+ for (const [key, entry] of Object.entries(value))
117
+ entries.push([decodeJsonKey(key), decodeJsonObjectKeys(entry)])
118
+ return Object.fromEntries(entries)
119
+ }
120
+
121
+ function isPlainObject(value: object): boolean {
122
+ const prototype = Object.getPrototypeOf(value)
123
+ return prototype === Object.prototype || prototype === null
124
+ }
125
+
126
+ function isArrayIndex(value: string, length: number): boolean {
127
+ const index = Number(value)
128
+ return Number.isInteger(index) && index >= 0 && index < length && String(index) === value
129
+ }
130
+
131
+ function encodeJsonKey(value: string): string {
132
+ return `${JSON_VALIDATION_KEY_PREFIX}${value}`
133
+ }
134
+
135
+ function decodeJsonKey(value: string): string {
136
+ return value.slice(JSON_VALIDATION_KEY_PREFIX.length)
137
+ }
24
138
 
25
139
  const utf8Encoder = new TextEncoder()
26
140
 
@@ -12,13 +12,13 @@ export const codexAgentRunMetadataSchema = z.object({
12
12
  provider: z.literal('codex'),
13
13
  ...metadataShape,
14
14
  model: codexModelIdSchema.optional(),
15
- }).strict()
15
+ })
16
16
 
17
17
  export const claudeAgentRunMetadataSchema = z.object({
18
18
  provider: z.literal('claude'),
19
19
  ...metadataShape,
20
20
  model: claudeModelIdSchema.optional(),
21
- }).strict()
21
+ })
22
22
 
23
23
  export const agentRunMetadataSchema = z.discriminatedUnion('provider', [
24
24
  codexAgentRunMetadataSchema,
@@ -8,15 +8,27 @@ import z from 'zod'
8
8
  * schema that carries a model id accepts any non-empty string.
9
9
  */
10
10
  export const codexModelIds = [
11
+ 'gpt-6-astra',
11
12
  'gpt-5.6-sol',
13
+ 'gpt-5.6-terra',
14
+ 'gpt-5.6-luna',
12
15
  'gpt-5.5',
13
16
  'gpt-5.4',
14
17
  'gpt-5.4-mini',
15
- 'gpt-5.3-codex',
16
18
  'gpt-5.2',
17
19
  ] as const
18
20
 
21
+ /**
22
+ * Every Claude model id the wire accepts, including historical ids retained so stored
23
+ * `session.started` metadata keeps parsing. Add new ids; never remove one. The ids
24
+ * users can select live in `agent-catalog.ts`.
25
+ */
19
26
  export const claudeModelIds = [
27
+ 'claude-opus-5-5',
28
+ 'claude-sonnet-5',
29
+ 'claude-fable-5-1',
30
+ 'claude-opus-5',
31
+ 'claude-fable-5',
20
32
  'sonnet',
21
33
  'claude-opus-4-8',
22
34
  'opus',
@@ -0,0 +1,110 @@
1
+ import type { JsonValue } from './agent-json'
2
+ import z from 'zod'
3
+ import { jsonValueSchema } from './agent-json'
4
+
5
+ export const agentNotificationSchema = jsonValueSchema
6
+ export const agentNotificationsSchema = z.array(agentNotificationSchema).min(1).max(20)
7
+ export const agentNotificationInstructionSchema = z.string().trim().min(1).max(4_096)
8
+
9
+ export const agentNotificationToolOutputMaxBytes = 64 * 1024
10
+
11
+ const notificationTransportEnvelopeType = 'coding_agent.notification_command.v1'
12
+ const textEncoder = new TextEncoder()
13
+
14
+ export type AgentNotification = JsonValue
15
+ export type AgentNotifications = z.infer<typeof agentNotificationsSchema>
16
+ export type AgentNotificationInstruction = z.infer<typeof agentNotificationInstructionSchema>
17
+ export interface AgentNotificationCommandPayload {
18
+ instruction: AgentNotificationInstruction | null
19
+ notifications: AgentNotifications
20
+ }
21
+ export type AgentNotificationToolOutput = AgentNotificationCommandPayload & {
22
+ commandId: string
23
+ }
24
+
25
+ interface AgentNotificationToolOutputInput {
26
+ commandId: string
27
+ instruction: AgentNotificationInstruction | null
28
+ notifications: readonly AgentNotification[]
29
+ }
30
+
31
+ // The supervisor wire command keeps its historical JSON-array shape so a newer control plane can
32
+ // still deliver notifications to image-baked older sandboxes. The generated command id prevents an
33
+ // observation value from masquerading as the trusted envelope before the command exists.
34
+ const notificationTransportEnvelopeSchema = z.object({
35
+ type: z.literal(notificationTransportEnvelopeType),
36
+ commandId: z.string().min(1),
37
+ instruction: agentNotificationInstructionSchema.nullable(),
38
+ notifications: agentNotificationsSchema,
39
+ })
40
+
41
+ function notificationTransportEnvelope(input: AgentNotificationToolOutputInput) {
42
+ return {
43
+ type: notificationTransportEnvelopeType,
44
+ commandId: input.commandId,
45
+ instruction: input.instruction,
46
+ notifications: [...input.notifications],
47
+ } as const
48
+ }
49
+
50
+ export function encodeAgentNotificationCommandPayloadForTransport(
51
+ input: AgentNotificationToolOutputInput,
52
+ ): AgentNotifications {
53
+ return [notificationTransportEnvelopeSchema.parse(notificationTransportEnvelope(input))]
54
+ }
55
+
56
+ export function decodeAgentNotificationCommandPayloadFromTransport(input: {
57
+ commandId: string
58
+ notifications: AgentNotifications
59
+ }): AgentNotificationCommandPayload {
60
+ if (input.notifications.length === 1) {
61
+ const envelope = notificationTransportEnvelopeSchema.safeParse(input.notifications[0])
62
+ if (envelope.success && envelope.data.commandId === input.commandId) {
63
+ return {
64
+ instruction: envelope.data.instruction,
65
+ notifications: envelope.data.notifications,
66
+ }
67
+ }
68
+ }
69
+
70
+ return {
71
+ instruction: null,
72
+ notifications: input.notifications,
73
+ }
74
+ }
75
+
76
+ export function isAgentNotificationPublicPayloadWithinSizeLimit(
77
+ input: Pick<AgentNotificationToolOutputInput, 'commandId' | 'notifications'>,
78
+ ): boolean {
79
+ return textEncoder.encode(JSON.stringify({
80
+ commandId: input.commandId,
81
+ notifications: input.notifications,
82
+ })).byteLength <= agentNotificationToolOutputMaxBytes
83
+ }
84
+
85
+ export function isAgentNotificationToolOutputWithinSizeLimit(input: AgentNotificationToolOutputInput): boolean {
86
+ const canonicalBytes = textEncoder.encode(JSON.stringify(input)).byteLength
87
+ const compatibilityBytes = textEncoder.encode(JSON.stringify({
88
+ commandId: input.commandId,
89
+ notifications: [notificationTransportEnvelope(input)],
90
+ })).byteLength
91
+ return Math.max(canonicalBytes, compatibilityBytes) <= agentNotificationToolOutputMaxBytes
92
+ }
93
+
94
+ export const agentNotificationToolOutputSchema: z.ZodType<AgentNotificationToolOutput> = z.object({
95
+ commandId: z.string().min(1),
96
+ instruction: agentNotificationInstructionSchema.nullable(),
97
+ notifications: agentNotificationsSchema,
98
+ }).strict().superRefine((output, context) => {
99
+ if (isAgentNotificationToolOutputWithinSizeLimit(output))
100
+ return
101
+ context.addIssue({
102
+ code: 'custom',
103
+ path: ['notifications'],
104
+ message: `Serialized notification tool output exceeds ${agentNotificationToolOutputMaxBytes} bytes.`,
105
+ })
106
+ })
107
+
108
+ export function serializeAgentNotificationToolOutput(input: AgentNotificationToolOutput): string {
109
+ return JSON.stringify(agentNotificationToolOutputSchema.parse(input))
110
+ }
@@ -1,3 +1,4 @@
1
+ import type { SelectableClaudeModelId } from './agent-catalog'
1
2
  import type { AgentReasoningEffort } from './agent-command'
2
3
  import type { KnownCodexModelId } from './agent-model'
3
4
 
@@ -6,11 +7,13 @@ import type { KnownCodexModelId } from './agent-model'
6
7
  * or effort added to the wire unions cannot ship without its presentation: the
7
8
  * `Record` types below fail to compile until every identifier is covered.
8
9
  *
9
- * Copy and figures mirror the bundled Codex CLI catalog
10
- * (`codex-rs/models-manager/models.json` at the pinned `@openai/codex@0.145.0`).
11
- * Update this file together with the pinned CLI version. Upstream defines efforts
12
- * by description only — no per-effort reasoning-token budget exists, so none is
13
- * invented here.
10
+ * Labels, descriptions, and image support follow the non-hidden `model/list`
11
+ * catalog observed through Codex 0.153.4. Context windows use its model metadata's
12
+ * default `context_window`, not the opt-in `max_context_window`.
13
+ * Refresh alongside the model registry; the live catalog can change without a CLI
14
+ * upgrade. Relative cost weights are product-owned, not provider-reported prices.
15
+ * Upstream defines efforts by description only — no per-effort reasoning-token
16
+ * budget exists, so none is invented here.
14
17
  *
15
18
  * This is UI copy and relative sizing only. Billing, pricing, and cost estimation
16
19
  * stay out of protocol (docs/agents-protocol.md) — `relativeCost` is a 1–5 picker
@@ -29,43 +32,55 @@ export interface AgentModelPresentation {
29
32
  const CODEX_CONTEXT_WINDOW = 272_000
30
33
 
31
34
  export const codexModelPresentation: Record<KnownCodexModelId, AgentModelPresentation> = {
35
+ 'gpt-6-astra': {
36
+ label: 'GPT 6.0 Astra',
37
+ description: 'Our most capable model for complex, demanding work.',
38
+ relativeCost: 5,
39
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
40
+ isMultiModal: true,
41
+ },
32
42
  'gpt-5.6-sol': {
33
- label: 'GPT-5.6-Sol',
34
- description: 'Latest frontier agentic coding model.',
43
+ label: 'GPT 5.6 Sol',
44
+ description: 'Reliable agentic workhorse for everyday tasks.',
35
45
  relativeCost: 5,
36
46
  maxInputTokens: CODEX_CONTEXT_WINDOW,
37
47
  isMultiModal: true,
38
48
  },
49
+ 'gpt-5.6-terra': {
50
+ label: 'GPT 5.6 Terra',
51
+ description: 'Balanced agentic coding model for everyday work.',
52
+ relativeCost: 3,
53
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
54
+ isMultiModal: true,
55
+ },
56
+ 'gpt-5.6-luna': {
57
+ label: 'GPT 5.6 Luna',
58
+ description: 'Fast and affordable agentic coding model.',
59
+ relativeCost: 2,
60
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
61
+ isMultiModal: true,
62
+ },
39
63
  'gpt-5.5': {
40
- label: 'GPT-5.5',
41
- description: 'Frontier model for complex coding, research, and real-world work.',
64
+ label: 'GPT 5.5',
65
+ description: 'Proven previous-generation model for coding and general work.',
42
66
  relativeCost: 4,
43
67
  maxInputTokens: CODEX_CONTEXT_WINDOW,
44
68
  isMultiModal: true,
45
69
  },
46
70
  'gpt-5.4': {
47
- label: 'GPT-5.4',
71
+ label: 'GPT 5.4',
48
72
  description: 'Strong model for everyday coding.',
49
73
  relativeCost: 3,
50
74
  maxInputTokens: CODEX_CONTEXT_WINDOW,
51
75
  isMultiModal: true,
52
76
  },
53
77
  'gpt-5.4-mini': {
54
- label: 'GPT-5.4-Mini',
78
+ label: 'GPT 5.4 Mini',
55
79
  description: 'Small, fast, and cost-efficient model for simpler coding tasks.',
56
80
  relativeCost: 2,
57
81
  maxInputTokens: CODEX_CONTEXT_WINDOW,
58
82
  isMultiModal: true,
59
83
  },
60
- /* Absent from the 0.145.0 upstream catalog; retained in our registry, so the
61
- copy below is ours. */
62
- 'gpt-5.3-codex': {
63
- label: 'GPT-5.3-Codex',
64
- description: 'Code-tuned model for focused engineering tasks.',
65
- relativeCost: 3,
66
- maxInputTokens: CODEX_CONTEXT_WINDOW,
67
- isMultiModal: true,
68
- },
69
84
  'gpt-5.2': {
70
85
  label: 'GPT-5.2',
71
86
  description: 'Optimized for professional work and long-running agents.',
@@ -75,6 +90,42 @@ export const codexModelPresentation: Record<KnownCodexModelId, AgentModelPresent
75
90
  },
76
91
  }
77
92
 
93
+ /*
94
+ * Claude presentation covers the selectable ids only (`agent-catalog.ts`); historical wire
95
+ * ids render through the unknown-model fallback. Labels, context windows, output limits,
96
+ * and image support follow the model catalog baked into Claude Code 2.1.280, the CLI the
97
+ * sandbox image pins. Relative cost follows that catalog's pricing tiers on the same
98
+ * product-owned 1–5 scale as Codex.
99
+ */
100
+ const CLAUDE_CONTEXT_WINDOW = 1_000_000
101
+
102
+ export const claudeModelPresentation: Record<SelectableClaudeModelId, AgentModelPresentation> = {
103
+ 'claude-opus-5-5': {
104
+ label: 'Opus 5.5',
105
+ description: 'Best for everyday, complex tasks.',
106
+ relativeCost: 4,
107
+ maxInputTokens: CLAUDE_CONTEXT_WINDOW,
108
+ maxOutputTokens: 128_000,
109
+ isMultiModal: true,
110
+ },
111
+ 'claude-sonnet-5': {
112
+ label: 'Sonnet 5',
113
+ description: 'Efficient for routine coding tasks.',
114
+ relativeCost: 2,
115
+ maxInputTokens: CLAUDE_CONTEXT_WINDOW,
116
+ maxOutputTokens: 64_000,
117
+ isMultiModal: true,
118
+ },
119
+ 'claude-fable-5-1': {
120
+ label: 'Fable 5.1',
121
+ description: 'Most intelligent generally available Claude model.',
122
+ relativeCost: 5,
123
+ maxInputTokens: CLAUDE_CONTEXT_WINDOW,
124
+ maxOutputTokens: 64_000,
125
+ isMultiModal: true,
126
+ },
127
+ }
128
+
78
129
  interface AgentReasoningEffortPresentation {
79
130
  label: string
80
131
  description: string
@@ -1,32 +1,88 @@
1
1
  import z from 'zod'
2
2
  import { jsonObjectSchema, jsonValueSchema } from './agent-json'
3
+ import { objectRejectingKeys } from './rejected-keys'
3
4
 
4
5
  export const agentToolDefinitionSchema = z.object({
5
6
  name: z.string().regex(/^[\w-]{1,128}$/),
6
7
  description: z.string().min(1),
7
8
  inputSchema: jsonObjectSchema,
8
- }).strict()
9
+ })
9
10
 
10
- export const agentToolTextContentSchema = z.object({
11
+ // Provider-private metadata containers are rejected, not stripped, at every content boundary.
12
+ const privateMetadataKeys = ['_meta', 'metadata'] as const
13
+
14
+ export const agentToolTextContentSchema = objectRejectingKeys({
11
15
  type: z.literal('text'),
12
16
  text: z.string(),
13
- }).strict()
17
+ }, privateMetadataKeys)
14
18
 
15
- export const agentToolImageContentSchema = z.object({
19
+ // An image is either embedded data or a URI reference, never both.
20
+ export const agentToolImageContentSchema = objectRejectingKeys({
16
21
  type: z.literal('image'),
17
22
  data: z.string().min(1),
18
23
  mimeType: z.string().min(1),
19
- }).strict()
24
+ }, ['uri', ...privateMetadataKeys])
25
+
26
+ const observedContentMetadata = {
27
+ annotations: jsonObjectSchema.optional(),
28
+ extras: jsonObjectSchema.optional(),
29
+ }
30
+
31
+ const agentToolResourceLinkContentSchema = objectRejectingKeys({
32
+ type: z.literal('resource_link'),
33
+ name: z.string(),
34
+ uri: z.string(),
35
+ mimeType: z.string().optional(),
36
+ description: z.string().optional(),
37
+ title: z.string().optional(),
38
+ size: z.number().nonnegative().optional(),
39
+ ...observedContentMetadata,
40
+ }, privateMetadataKeys)
41
+
42
+ const resourceMetadata = {
43
+ uri: z.string(),
44
+ mimeType: z.string().optional(),
45
+ extras: jsonObjectSchema.optional(),
46
+ }
47
+
48
+ const agentToolResourceContentSchema = objectRejectingKeys({
49
+ type: z.literal('resource'),
50
+ // An embedded resource is either text or blob, never both.
51
+ resource: z.union([
52
+ objectRejectingKeys({ ...resourceMetadata, text: z.string() }, ['blob']),
53
+ objectRejectingKeys({ ...resourceMetadata, blob: z.string() }, ['text']),
54
+ ]),
55
+ ...observedContentMetadata,
56
+ }, privateMetadataKeys)
57
+
58
+ const agentToolAudioContentSchema = objectRejectingKeys({
59
+ type: z.literal('audio'),
60
+ data: z.string().min(1),
61
+ mimeType: z.string().min(1),
62
+ ...observedContentMetadata,
63
+ }, privateMetadataKeys)
64
+
65
+ const agentToolJsonContentSchema = objectRejectingKeys({
66
+ type: z.literal('json'),
67
+ value: jsonValueSchema,
68
+ }, privateMetadataKeys)
20
69
 
21
- export const agentToolContentSchema = z.discriminatedUnion('type', [
22
- agentToolTextContentSchema,
23
- agentToolImageContentSchema,
70
+ export const agentToolContentSchema = z.union([
71
+ agentToolTextContentSchema.extend(observedContentMetadata),
72
+ agentToolImageContentSchema.extend(observedContentMetadata),
73
+ objectRejectingKeys({ type: z.literal('image'), uri: z.string().min(1), ...observedContentMetadata }, ['data', ...privateMetadataKeys]),
74
+ agentToolAudioContentSchema,
75
+ agentToolResourceContentSchema,
76
+ agentToolResourceLinkContentSchema,
77
+ agentToolJsonContentSchema,
24
78
  ])
25
79
 
26
- export const agentToolResultSchema = z.object({
80
+ export const agentToolResultSchema = objectRejectingKeys({
27
81
  success: z.boolean(),
28
82
  content: z.array(agentToolContentSchema),
29
- }).strict()
83
+ structuredContent: jsonValueSchema.optional(),
84
+ reportedSuccess: z.boolean().optional(),
85
+ }, privateMetadataKeys)
30
86
 
31
87
  export const agentToolCallStatusSchema = z.enum(['completed', 'failed', 'cancelled'])
32
88
 
@@ -9,7 +9,8 @@ export const agentUsageSchema = z.object({
9
9
  cacheWriteTokens: tokenCountSchema.optional(),
10
10
  reasoningOutputTokens: tokenCountSchema.optional(),
11
11
  totalTokens: tokenCountSchema.optional(),
12
- }).strict()
12
+ webSearchRequests: tokenCountSchema.optional(),
13
+ })
13
14
 
14
15
  export type AgentUsage = z.infer<typeof agentUsageSchema>
15
16
 
@@ -26,3 +27,5 @@ export const agentUsageAccountingSchema = z.object({
26
27
  model: z.string().min(1).optional(),
27
28
  models: z.record(z.string(), agentUsageSchema).optional(),
28
29
  }).strict()
30
+
31
+ export type AgentUsageAccounting = z.infer<typeof agentUsageAccountingSchema>
@@ -5,24 +5,24 @@ export const agentUserInputOptionSchema = z.object({
5
5
  value: z.string().min(1),
6
6
  label: z.string().min(1),
7
7
  description: z.string().min(1).optional(),
8
- }).strict()
8
+ })
9
9
 
10
10
  const agentUserInputQuestionBaseSchema = z.object({
11
11
  id: z.string().min(1),
12
12
  label: z.string().min(1),
13
13
  description: z.string().min(1).optional(),
14
14
  required: z.boolean().optional(),
15
- }).strict()
15
+ })
16
16
 
17
17
  export const agentUserInputTextQuestionSchema = agentUserInputQuestionBaseSchema.extend({
18
18
  type: z.literal('text'),
19
19
  placeholder: z.string().min(1).optional(),
20
- }).strict()
20
+ })
21
21
 
22
22
  export const agentUserInputSingleSelectQuestionSchema = agentUserInputQuestionBaseSchema.extend({
23
23
  type: z.literal('single_select'),
24
24
  options: z.array(agentUserInputOptionSchema).min(1),
25
- }).strict()
25
+ })
26
26
 
27
27
  export const agentUserInputQuestionSchema = z.discriminatedUnion('type', [
28
28
  agentUserInputTextQuestionSchema,
@@ -1,17 +1,19 @@
1
1
  import z from 'zod'
2
+ import { objectRejectingKeys } from './rejected-keys'
2
3
 
3
4
  export const agentWorkStatusSchema = z.enum(['pending', 'in_progress', 'completed'])
4
5
 
5
- export const agentWorkItemSchema = z.object({
6
+ // Provider-only fields (Claude `activeForm`/`explanation`, provider tags) are rejected, not stripped.
7
+ export const agentWorkItemSchema = objectRejectingKeys({
6
8
  id: z.string().min(1),
7
9
  title: z.string().min(1),
8
10
  status: agentWorkStatusSchema,
9
- }).strict()
11
+ }, ['activeForm'])
10
12
 
11
- const agentWorkSnapshotObservationSchema = z.object({
13
+ const agentWorkSnapshotObservationSchema = objectRejectingKeys({
12
14
  kind: z.literal('snapshot'),
13
15
  items: z.array(agentWorkItemSchema),
14
- }).strict().superRefine(({ items }, context) => {
16
+ }, ['explanation']).superRefine(({ items }, context) => {
15
17
  const seenIds = new Set<string>()
16
18
 
17
19
  for (const [index, item] of items.entries()) {
@@ -31,26 +33,26 @@ export const agentWorkObservationSchema = z.discriminatedUnion('kind', [
31
33
  z.object({
32
34
  kind: z.literal('item_observed'),
33
35
  item: agentWorkItemSchema,
34
- }).strict(),
36
+ }),
35
37
  z.object({
36
38
  kind: z.literal('item_renamed'),
37
39
  itemId: z.string().min(1),
38
40
  title: z.string().min(1),
39
- }).strict(),
41
+ }),
40
42
  z.object({
41
43
  kind: z.literal('item_status_changed'),
42
44
  itemId: z.string().min(1),
43
45
  status: agentWorkStatusSchema,
44
- }).strict(),
46
+ }),
45
47
  z.object({
46
48
  kind: z.literal('item_removed'),
47
49
  itemId: z.string().min(1),
48
- }).strict(),
50
+ }),
49
51
  ])
50
52
 
51
- export const agentWorkStateSchema = z.object({
53
+ export const agentWorkStateSchema = objectRejectingKeys({
52
54
  items: z.array(agentWorkItemSchema),
53
- }).strict()
55
+ }, ['provider'])
54
56
 
55
57
  export type AgentWorkStatus = z.infer<typeof agentWorkStatusSchema>
56
58
  export type AgentWorkItem = z.infer<typeof agentWorkItemSchema>
@@ -1,3 +1,4 @@
1
+ export * from './agent-catalog'
1
2
  export * from './agent-command'
2
3
  export * from './agent-content'
3
4
  export * from './agent-error'
@@ -5,6 +6,7 @@ export * from './agent-event'
5
6
  export * from './agent-json'
6
7
  export * from './agent-metadata'
7
8
  export * from './agent-model'
9
+ export * from './agent-notification'
8
10
  export * from './agent-overflow'
9
11
  export * from './agent-presentation'
10
12
  export * from './agent-provider'
@@ -0,0 +1,11 @@
1
+ import z from 'zod'
2
+
3
+ // Builds a strip-on-read object schema that still rejects specific known-but-forbidden keys.
4
+ // Additive unknown fields are stripped, but a key listed here is a semantic violation (for
5
+ // example a turn id on a session-scoped event) and fails validation instead of being dropped.
6
+ // The rejecting keys are runtime-only: a valid value can never contain them, so they are
7
+ // intentionally absent from the inferred output type.
8
+ export function objectRejectingKeys<TShape extends z.ZodRawShape>(shape: TShape, rejectedKeys: readonly string[]): z.ZodObject<TShape> {
9
+ const rejections: object = Object.fromEntries(rejectedKeys.map(key => [key, z.never().optional()]))
10
+ return z.object({ ...shape, ...rejections })
11
+ }
@@ -1,6 +1,6 @@
1
1
  // Generated by scripts/write-provenance.ts. Do not edit by hand.
2
2
  export const generatedProvenance = {
3
- version: "0.2.0-experimental.0",
4
- sha: "da33c4f2db2875602c75e8ad3fde2d01d8ea7a94",
5
- buildTime: "2026-09-22T18:15:52.470Z",
3
+ version: "0.2.0-experimental.2",
4
+ sha: "b808a0e0d307bcaa2cd0d47d2fd1e4112f70290c",
5
+ buildTime: "2026-09-25T17:58:45.916Z",
6
6
  } as const