@meistrari/agent-core 0.0.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.
Files changed (50) hide show
  1. package/README.md +26 -0
  2. package/package.json +69 -0
  3. package/scripts/write-provenance.ts +74 -0
  4. package/src/errors/app-error.ts +66 -0
  5. package/src/errors/application-error.ts +55 -0
  6. package/src/errors/index.ts +16 -0
  7. package/src/errors/infrastructure-error.ts +13 -0
  8. package/src/errors/provider-error.ts +13 -0
  9. package/src/errors/validation-error.ts +19 -0
  10. package/src/logger/index.ts +75 -0
  11. package/src/protocol/agent-command.ts +65 -0
  12. package/src/protocol/agent-content.ts +73 -0
  13. package/src/protocol/agent-error.ts +81 -0
  14. package/src/protocol/agent-event.ts +391 -0
  15. package/src/protocol/agent-json.ts +30 -0
  16. package/src/protocol/agent-metadata.ts +30 -0
  17. package/src/protocol/agent-model.ts +68 -0
  18. package/src/protocol/agent-overflow.ts +18 -0
  19. package/src/protocol/agent-presentation.ts +98 -0
  20. package/src/protocol/agent-provider.ts +4 -0
  21. package/src/protocol/agent-tool-name.ts +48 -0
  22. package/src/protocol/agent-tool.ts +40 -0
  23. package/src/protocol/agent-usage.ts +14 -0
  24. package/src/protocol/agent-user-input.ts +38 -0
  25. package/src/protocol/agent-work.ts +100 -0
  26. package/src/protocol/index.ts +13 -0
  27. package/src/provenance.gen.ts +6 -0
  28. package/src/provenance.ts +27 -0
  29. package/src/supervisor-protocol/agent-event-wrapper.ts +179 -0
  30. package/src/supervisor-protocol/bootstrap-rejection-receipt.ts +3 -0
  31. package/src/supervisor-protocol/bootstrap.ts +126 -0
  32. package/src/supervisor-protocol/command-body.ts +82 -0
  33. package/src/supervisor-protocol/context-file-content.ts +90 -0
  34. package/src/supervisor-protocol/control-authority.ts +88 -0
  35. package/src/supervisor-protocol/durability.ts +33 -0
  36. package/src/supervisor-protocol/envelope.ts +58 -0
  37. package/src/supervisor-protocol/envelopes/common.ts +7 -0
  38. package/src/supervisor-protocol/envelopes/control-plane-to-supervisor.ts +38 -0
  39. package/src/supervisor-protocol/envelopes/supervisor-to-control-plane.ts +89 -0
  40. package/src/supervisor-protocol/event-body.ts +13 -0
  41. package/src/supervisor-protocol/input-attachment-content.ts +3 -0
  42. package/src/supervisor-protocol/payload-overflow.ts +15 -0
  43. package/src/supervisor-protocol/product-event.ts +27 -0
  44. package/src/supervisor-protocol/profile.ts +22 -0
  45. package/src/supervisor-protocol/rpc.ts +77 -0
  46. package/src/supervisor-protocol/supervisor-agent-run-snapshot.ts +12 -0
  47. package/src/supervisor-protocol/supervisor-event.ts +361 -0
  48. package/src/supervisor-protocol/tela-page-content.ts +6 -0
  49. package/src/supervisor-protocol/wire-codec.ts +71 -0
  50. package/tsconfig.json +24 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The tool vocabulary `agent.tool.call.started.toolName` is guaranteed to speak.
3
+ * Provider adapters map their own names onto it before the event is emitted, so
4
+ * every consumer — supervisor, server, web — reads one taxonomy.
5
+ */
6
+ export const CANONICAL_TOOL = {
7
+ bash: 'bash',
8
+ read: 'read',
9
+ write: 'write',
10
+ edit: 'edit',
11
+ webSearch: 'web_search',
12
+ webFetch: 'web_fetch',
13
+ glob: 'glob',
14
+ grep: 'grep',
15
+ viewImage: 'view_image',
16
+ imageGeneration: 'image_generation',
17
+ todoWrite: 'todo_write',
18
+ task: 'task',
19
+ taskCreate: 'task_create',
20
+ taskGet: 'task_get',
21
+ taskUpdate: 'task_update',
22
+ taskList: 'task_list',
23
+ } as const
24
+
25
+ export type AgentCanonicalToolName = typeof CANONICAL_TOOL[keyof typeof CANONICAL_TOOL]
26
+
27
+ const PROVIDER_TOOL_NAME_ALIASES: Record<string, string> = {
28
+ Bash: CANONICAL_TOOL.bash,
29
+ Read: CANONICAL_TOOL.read,
30
+ Write: CANONICAL_TOOL.write,
31
+ Edit: CANONICAL_TOOL.edit,
32
+ MultiEdit: CANONICAL_TOOL.edit,
33
+ NotebookEdit: CANONICAL_TOOL.edit,
34
+ WebSearch: CANONICAL_TOOL.webSearch,
35
+ WebFetch: CANONICAL_TOOL.webFetch,
36
+ Glob: CANONICAL_TOOL.glob,
37
+ Grep: CANONICAL_TOOL.grep,
38
+ Task: CANONICAL_TOOL.task,
39
+ TaskCreate: CANONICAL_TOOL.taskCreate,
40
+ TaskGet: CANONICAL_TOOL.taskGet,
41
+ TaskUpdate: CANONICAL_TOOL.taskUpdate,
42
+ TaskList: CANONICAL_TOOL.taskList,
43
+ TodoWrite: CANONICAL_TOOL.todoWrite,
44
+ }
45
+
46
+ export function canonicalToolName(rawName: string): string {
47
+ return PROVIDER_TOOL_NAME_ALIASES[rawName] ?? rawName
48
+ }
@@ -0,0 +1,40 @@
1
+ import z from 'zod'
2
+ import { jsonObjectSchema, jsonValueSchema } from './agent-json'
3
+
4
+ export const agentToolDefinitionSchema = z.object({
5
+ name: z.string().regex(/^[\w-]{1,128}$/),
6
+ description: z.string().min(1),
7
+ inputSchema: jsonObjectSchema,
8
+ }).strict()
9
+
10
+ export const agentToolTextContentSchema = z.object({
11
+ type: z.literal('text'),
12
+ text: z.string(),
13
+ }).strict()
14
+
15
+ export const agentToolImageContentSchema = z.object({
16
+ type: z.literal('image'),
17
+ data: z.string().min(1),
18
+ mimeType: z.string().min(1),
19
+ }).strict()
20
+
21
+ export const agentToolContentSchema = z.discriminatedUnion('type', [
22
+ agentToolTextContentSchema,
23
+ agentToolImageContentSchema,
24
+ ])
25
+
26
+ export const agentToolResultSchema = z.object({
27
+ success: z.boolean(),
28
+ content: z.array(agentToolContentSchema),
29
+ }).strict()
30
+
31
+ export const agentToolCallStatusSchema = z.enum(['completed', 'failed', 'cancelled'])
32
+
33
+ export const agentToolCallInputSchema = jsonValueSchema
34
+
35
+ export type AgentToolDefinition = z.infer<typeof agentToolDefinitionSchema>
36
+ export type AgentToolTextContent = z.infer<typeof agentToolTextContentSchema>
37
+ export type AgentToolImageContent = z.infer<typeof agentToolImageContentSchema>
38
+ export type AgentToolContent = z.infer<typeof agentToolContentSchema>
39
+ export type AgentToolResult = z.infer<typeof agentToolResultSchema>
40
+ export type AgentToolCallStatus = z.infer<typeof agentToolCallStatusSchema>
@@ -0,0 +1,14 @@
1
+ import z from 'zod'
2
+
3
+ const tokenCountSchema = z.number().int().nonnegative()
4
+
5
+ export const agentUsageSchema = z.object({
6
+ inputTokens: tokenCountSchema.optional(),
7
+ outputTokens: tokenCountSchema.optional(),
8
+ cacheReadTokens: tokenCountSchema.optional(),
9
+ cacheWriteTokens: tokenCountSchema.optional(),
10
+ reasoningOutputTokens: tokenCountSchema.optional(),
11
+ totalTokens: tokenCountSchema.optional(),
12
+ }).strict()
13
+
14
+ export type AgentUsage = z.infer<typeof agentUsageSchema>
@@ -0,0 +1,38 @@
1
+ import z from 'zod'
2
+ import { jsonValueSchema } from './agent-json'
3
+
4
+ export const agentUserInputOptionSchema = z.object({
5
+ value: z.string().min(1),
6
+ label: z.string().min(1),
7
+ description: z.string().min(1).optional(),
8
+ }).strict()
9
+
10
+ const agentUserInputQuestionBaseSchema = z.object({
11
+ id: z.string().min(1),
12
+ label: z.string().min(1),
13
+ description: z.string().min(1).optional(),
14
+ required: z.boolean().optional(),
15
+ }).strict()
16
+
17
+ export const agentUserInputTextQuestionSchema = agentUserInputQuestionBaseSchema.extend({
18
+ type: z.literal('text'),
19
+ placeholder: z.string().min(1).optional(),
20
+ }).strict()
21
+
22
+ export const agentUserInputSingleSelectQuestionSchema = agentUserInputQuestionBaseSchema.extend({
23
+ type: z.literal('single_select'),
24
+ options: z.array(agentUserInputOptionSchema).min(1),
25
+ }).strict()
26
+
27
+ export const agentUserInputQuestionSchema = z.discriminatedUnion('type', [
28
+ agentUserInputTextQuestionSchema,
29
+ agentUserInputSingleSelectQuestionSchema,
30
+ ])
31
+
32
+ export const agentUserInputAnswersSchema = z.record(z.string().min(1), jsonValueSchema)
33
+
34
+ export type AgentUserInputOption = z.infer<typeof agentUserInputOptionSchema>
35
+ export type AgentUserInputTextQuestion = z.infer<typeof agentUserInputTextQuestionSchema>
36
+ export type AgentUserInputSingleSelectQuestion = z.infer<typeof agentUserInputSingleSelectQuestionSchema>
37
+ export type AgentUserInputQuestion = z.infer<typeof agentUserInputQuestionSchema>
38
+ export type AgentUserInputAnswers = z.infer<typeof agentUserInputAnswersSchema>
@@ -0,0 +1,100 @@
1
+ import z from 'zod'
2
+
3
+ export const agentWorkStatusSchema = z.enum(['pending', 'in_progress', 'completed'])
4
+
5
+ export const agentWorkItemSchema = z.object({
6
+ id: z.string().min(1),
7
+ title: z.string().min(1),
8
+ status: agentWorkStatusSchema,
9
+ }).strict()
10
+
11
+ const agentWorkSnapshotObservationSchema = z.object({
12
+ kind: z.literal('snapshot'),
13
+ items: z.array(agentWorkItemSchema),
14
+ }).strict().superRefine(({ items }, context) => {
15
+ const seenIds = new Set<string>()
16
+
17
+ for (const [index, item] of items.entries()) {
18
+ if (seenIds.has(item.id)) {
19
+ context.addIssue({
20
+ code: 'custom',
21
+ message: 'Snapshot item ids must be unique.',
22
+ path: ['items', index, 'id'],
23
+ })
24
+ }
25
+ seenIds.add(item.id)
26
+ }
27
+ })
28
+
29
+ export const agentWorkObservationSchema = z.discriminatedUnion('kind', [
30
+ agentWorkSnapshotObservationSchema,
31
+ z.object({
32
+ kind: z.literal('item_observed'),
33
+ item: agentWorkItemSchema,
34
+ }).strict(),
35
+ z.object({
36
+ kind: z.literal('item_renamed'),
37
+ itemId: z.string().min(1),
38
+ title: z.string().min(1),
39
+ }).strict(),
40
+ z.object({
41
+ kind: z.literal('item_status_changed'),
42
+ itemId: z.string().min(1),
43
+ status: agentWorkStatusSchema,
44
+ }).strict(),
45
+ z.object({
46
+ kind: z.literal('item_removed'),
47
+ itemId: z.string().min(1),
48
+ }).strict(),
49
+ ])
50
+
51
+ export const agentWorkStateSchema = z.object({
52
+ items: z.array(agentWorkItemSchema),
53
+ }).strict()
54
+
55
+ export type AgentWorkStatus = z.infer<typeof agentWorkStatusSchema>
56
+ export type AgentWorkItem = z.infer<typeof agentWorkItemSchema>
57
+ export type AgentWorkObservation = z.infer<typeof agentWorkObservationSchema>
58
+ export type AgentWorkState = z.infer<typeof agentWorkStateSchema>
59
+
60
+ export function applyAgentWorkObservations(
61
+ state: AgentWorkState,
62
+ observations: readonly AgentWorkObservation[],
63
+ ): AgentWorkState {
64
+ let items = state.items.map(item => ({ ...item }))
65
+
66
+ for (const observation of observations) {
67
+ switch (observation.kind) {
68
+ case 'snapshot':
69
+ items = observation.items.map(item => ({ ...item }))
70
+ break
71
+ case 'item_observed': {
72
+ const existingIndex = items.findIndex(item => item.id === observation.item.id)
73
+ if (existingIndex === -1)
74
+ items = [...items, { ...observation.item }]
75
+ else
76
+ items = items.map((item, index) => index === existingIndex ? { ...observation.item } : item)
77
+ break
78
+ }
79
+ case 'item_renamed':
80
+ items = items.map(item => item.id === observation.itemId
81
+ ? { ...item, title: observation.title }
82
+ : item)
83
+ break
84
+ case 'item_status_changed':
85
+ items = items.map(item => item.id === observation.itemId
86
+ ? { ...item, status: observation.status }
87
+ : item)
88
+ break
89
+ case 'item_removed':
90
+ items = items.filter(item => item.id !== observation.itemId)
91
+ break
92
+ default: {
93
+ const exhaustiveObservation: never = observation
94
+ void exhaustiveObservation
95
+ }
96
+ }
97
+ }
98
+
99
+ return { items }
100
+ }
@@ -0,0 +1,13 @@
1
+ export * from './agent-command'
2
+ export * from './agent-content'
3
+ export * from './agent-error'
4
+ export * from './agent-event'
5
+ export * from './agent-json'
6
+ export * from './agent-metadata'
7
+ export * from './agent-model'
8
+ export * from './agent-overflow'
9
+ export * from './agent-presentation'
10
+ export * from './agent-provider'
11
+ export * from './agent-tool'
12
+ export * from './agent-usage'
13
+ export * from './agent-user-input'
@@ -0,0 +1,6 @@
1
+ // Generated by scripts/write-provenance.ts. Do not edit by hand.
2
+ export const generatedProvenance = {
3
+ version: "0.0.0",
4
+ sha: "3a023ce55b472e60cc194b759feac98f7ae61dba",
5
+ buildTime: "2026-09-04T18:05:02.217Z",
6
+ } as const
@@ -0,0 +1,27 @@
1
+ import { generatedProvenance } from './provenance.gen'
2
+
3
+ export interface AgentCoreProvenance {
4
+ /** Published package version, or `0.0.0-development` for a checkout. */
5
+ readonly version: string
6
+ /** Full git sha of the source that produced this build. */
7
+ readonly sha: string
8
+ /** ISO-8601 timestamp of the provenance generation. */
9
+ readonly buildTime: string
10
+ /** True when running from an unpublished development checkout. */
11
+ readonly isDevelopmentBuild: boolean
12
+ }
13
+
14
+ /**
15
+ * Identity of the agent-core build embedded in a process. Consumers record it in
16
+ * sandbox image/snapshot provenance so the immutable-sandbox invariant can be
17
+ * checked centrally: a snapshot built against one agent-core version is never
18
+ * served by a control plane expecting another.
19
+ */
20
+ export function agentCoreProvenance(): AgentCoreProvenance {
21
+ return {
22
+ version: generatedProvenance.version,
23
+ sha: generatedProvenance.sha,
24
+ buildTime: generatedProvenance.buildTime,
25
+ isDevelopmentBuild: generatedProvenance.version.endsWith('-development'),
26
+ }
27
+ }
@@ -0,0 +1,179 @@
1
+ import type { AgentEvent } from '../protocol'
2
+ import z from 'zod'
3
+ import {
4
+ contextCompactionCompletedAgentEventSchema,
5
+ contextCompactionStartedAgentEventSchema,
6
+ errorAgentEventSchema,
7
+ messageDeltaAgentEventSchema,
8
+ messageEndedAgentEventSchema,
9
+ messageStartedAgentEventSchema,
10
+ reasoningEndedAgentEventSchema,
11
+ reasoningStartedAgentEventSchema,
12
+ reasoningSummaryDeltaAgentEventSchema,
13
+ sessionConfiguredAgentEventSchema,
14
+ sessionEndedAgentEventSchema,
15
+ sessionSkillsUpdatedAgentEventSchema,
16
+ sessionStartedAgentEventSchema,
17
+ sessionStateChangedAgentEventSchema,
18
+ subagentEndedAgentEventSchema,
19
+ subagentProgressAgentEventSchema,
20
+ subagentStartedAgentEventSchema,
21
+ toolCallCompletedAgentEventSchema,
22
+ toolCallStartedAgentEventSchema,
23
+ toolOutputDeltaAgentEventSchema,
24
+ turnEndedAgentEventSchema,
25
+ turnStartedAgentEventSchema,
26
+ usageAgentEventSchema,
27
+ userInputRequestedAgentEventSchema,
28
+ userInputResolvedAgentEventSchema,
29
+ workObservedAgentEventSchema,
30
+ } from '../protocol'
31
+
32
+ export type WrappedAgentEventType<TType extends AgentEvent['type'] = AgentEvent['type']> = `agent.${TType}`
33
+ export type WrappedAgentEvent<TEvent extends AgentEvent = AgentEvent> = TEvent extends AgentEvent
34
+ ? Omit<TEvent, 'type'> & { type: WrappedAgentEventType<TEvent['type']> }
35
+ : never
36
+
37
+ export const wrappedSessionStartedAgentEventSchema = sessionStartedAgentEventSchema.extend({
38
+ type: z.literal('agent.session.started'),
39
+ }).strict()
40
+
41
+ export const wrappedSessionConfiguredAgentEventSchema = sessionConfiguredAgentEventSchema.extend({
42
+ type: z.literal('agent.session.configured'),
43
+ }).strict()
44
+
45
+ export const wrappedSessionSkillsUpdatedAgentEventSchema = sessionSkillsUpdatedAgentEventSchema.extend({
46
+ type: z.literal('agent.session.skills.updated'),
47
+ }).strict()
48
+
49
+ export const wrappedSessionStateChangedAgentEventSchema = sessionStateChangedAgentEventSchema.extend({
50
+ type: z.literal('agent.session.state.changed'),
51
+ }).strict()
52
+
53
+ export const wrappedSessionEndedAgentEventSchema = sessionEndedAgentEventSchema.extend({
54
+ type: z.literal('agent.session.ended'),
55
+ }).strict()
56
+
57
+ export const wrappedTurnStartedAgentEventSchema = turnStartedAgentEventSchema.extend({
58
+ type: z.literal('agent.turn.started'),
59
+ }).strict()
60
+
61
+ export const wrappedTurnEndedAgentEventSchema = turnEndedAgentEventSchema.extend({
62
+ type: z.literal('agent.turn.ended'),
63
+ }).strict()
64
+
65
+ export const wrappedWorkObservedAgentEventSchema = workObservedAgentEventSchema.extend({
66
+ type: z.literal('agent.work.observed'),
67
+ }).strict()
68
+
69
+ export const wrappedMessageStartedAgentEventSchema = messageStartedAgentEventSchema.extend({
70
+ type: z.literal('agent.message.started'),
71
+ }).strict()
72
+
73
+ export const wrappedMessageDeltaAgentEventSchema = messageDeltaAgentEventSchema.extend({
74
+ type: z.literal('agent.message.delta'),
75
+ }).strict()
76
+
77
+ export const wrappedMessageEndedAgentEventSchema = messageEndedAgentEventSchema.extend({
78
+ type: z.literal('agent.message.ended'),
79
+ }).strict()
80
+
81
+ export const wrappedReasoningStartedAgentEventSchema = reasoningStartedAgentEventSchema.extend({
82
+ type: z.literal('agent.reasoning.started'),
83
+ }).strict()
84
+
85
+ export const wrappedReasoningSummaryDeltaAgentEventSchema = reasoningSummaryDeltaAgentEventSchema.extend({
86
+ type: z.literal('agent.reasoning.summary.delta'),
87
+ }).strict()
88
+
89
+ export const wrappedReasoningEndedAgentEventSchema = reasoningEndedAgentEventSchema.extend({
90
+ type: z.literal('agent.reasoning.ended'),
91
+ }).strict()
92
+
93
+ export const wrappedToolCallStartedAgentEventSchema = toolCallStartedAgentEventSchema.extend({
94
+ type: z.literal('agent.tool.call.started'),
95
+ }).strict()
96
+
97
+ export const wrappedToolOutputDeltaAgentEventSchema = toolOutputDeltaAgentEventSchema.extend({
98
+ type: z.literal('agent.tool.output.delta'),
99
+ }).strict()
100
+
101
+ export const wrappedToolCallCompletedAgentEventSchema = toolCallCompletedAgentEventSchema.extend({
102
+ type: z.literal('agent.tool.call.completed'),
103
+ }).strict()
104
+
105
+ export const wrappedSubagentStartedAgentEventSchema = subagentStartedAgentEventSchema.extend({
106
+ type: z.literal('agent.subagent.started'),
107
+ }).strict()
108
+
109
+ export const wrappedSubagentProgressAgentEventSchema = subagentProgressAgentEventSchema.extend({
110
+ type: z.literal('agent.subagent.progress'),
111
+ }).strict()
112
+
113
+ export const wrappedSubagentEndedAgentEventSchema = subagentEndedAgentEventSchema.extend({
114
+ type: z.literal('agent.subagent.ended'),
115
+ }).strict()
116
+
117
+ export const wrappedUsageAgentEventSchema = usageAgentEventSchema.extend({
118
+ type: z.literal('agent.usage'),
119
+ }).strict()
120
+
121
+ export const wrappedContextCompactionStartedAgentEventSchema = contextCompactionStartedAgentEventSchema.extend({
122
+ type: z.literal('agent.context.compaction.started'),
123
+ }).strict()
124
+
125
+ export const wrappedContextCompactionCompletedAgentEventSchema = contextCompactionCompletedAgentEventSchema.extend({
126
+ type: z.literal('agent.context.compaction.completed'),
127
+ }).strict()
128
+
129
+ export const wrappedUserInputRequestedAgentEventSchema = userInputRequestedAgentEventSchema.extend({
130
+ type: z.literal('agent.user-input.requested'),
131
+ }).strict()
132
+
133
+ export const wrappedUserInputResolvedAgentEventSchema = userInputResolvedAgentEventSchema.extend({
134
+ type: z.literal('agent.user-input.resolved'),
135
+ }).strict()
136
+
137
+ export const wrappedErrorAgentEventSchema = errorAgentEventSchema.extend({
138
+ type: z.literal('agent.error'),
139
+ }).strict()
140
+
141
+ export const wrappedAgentEventSchema = z.discriminatedUnion('type', [
142
+ wrappedSessionStartedAgentEventSchema,
143
+ wrappedSessionConfiguredAgentEventSchema,
144
+ wrappedSessionSkillsUpdatedAgentEventSchema,
145
+ wrappedSessionStateChangedAgentEventSchema,
146
+ wrappedSessionEndedAgentEventSchema,
147
+ wrappedTurnStartedAgentEventSchema,
148
+ wrappedTurnEndedAgentEventSchema,
149
+ wrappedWorkObservedAgentEventSchema,
150
+ wrappedMessageStartedAgentEventSchema,
151
+ wrappedMessageDeltaAgentEventSchema,
152
+ wrappedMessageEndedAgentEventSchema,
153
+ wrappedReasoningStartedAgentEventSchema,
154
+ wrappedReasoningSummaryDeltaAgentEventSchema,
155
+ wrappedReasoningEndedAgentEventSchema,
156
+ wrappedToolCallStartedAgentEventSchema,
157
+ wrappedToolOutputDeltaAgentEventSchema,
158
+ wrappedToolCallCompletedAgentEventSchema,
159
+ wrappedSubagentStartedAgentEventSchema,
160
+ wrappedSubagentProgressAgentEventSchema,
161
+ wrappedSubagentEndedAgentEventSchema,
162
+ wrappedUsageAgentEventSchema,
163
+ wrappedContextCompactionStartedAgentEventSchema,
164
+ wrappedContextCompactionCompletedAgentEventSchema,
165
+ wrappedUserInputRequestedAgentEventSchema,
166
+ wrappedUserInputResolvedAgentEventSchema,
167
+ wrappedErrorAgentEventSchema,
168
+ ])
169
+
170
+ export function wrapAgentEventType<TType extends AgentEvent['type']>(type: TType): WrappedAgentEventType<TType> {
171
+ return `agent.${type}`
172
+ }
173
+
174
+ export function wrapAgentEvent<TEvent extends AgentEvent>(event: TEvent): WrappedAgentEvent<TEvent> {
175
+ return {
176
+ ...event,
177
+ type: wrapAgentEventType(event.type),
178
+ }
179
+ }
@@ -0,0 +1,3 @@
1
+ // WHATWG permits 3000–4999 and 123 reason bytes; pinned Bun preserves this three-byte reason in its server close callback.
2
+ export const supervisorBootstrapRejectionReceiptCloseCode = 4409
3
+ export const supervisorBootstrapRejectionReceiptCloseReason = 'ack'
@@ -0,0 +1,126 @@
1
+ import z from 'zod'
2
+ import { agentProviderIdSchema, agentReasoningEffortSchema } from '../protocol'
3
+ import { wireCommandBodySchema } from './command-body'
4
+ import { sessionProfileSchema } from './profile'
5
+
6
+ /**
7
+ * Absolute, normalized POSIX path: no trailing slash, no empty, `.` or `..`
8
+ * segments, no NUL bytes. The coding-agent product always sends
9
+ * `/home/user/workspace`; agent-api sends its prepared repository root.
10
+ */
11
+ const absoluteDirectoryPathPattern = /^\/(?:[^/\0]+\/)*[^/\0]+$/u
12
+ export const absoluteDirectoryPathSchema = z.string()
13
+ .max(4096)
14
+ .regex(absoluteDirectoryPathPattern)
15
+ .refine(value => value.split('/').every(segment => segment !== '.' && segment !== '..'), {
16
+ message: 'path must be normalized (no . or .. segments)',
17
+ })
18
+
19
+ const repositorySchema = z.object({
20
+ id: z.string().min(1),
21
+ fullName: z.string().regex(/^[^/\s]+\/[^/\s]+$/u),
22
+ root: absoluteDirectoryPathSchema,
23
+ branch: z.string().min(1),
24
+ }).strict()
25
+
26
+ const gitIdentityNameSchema = z.string()
27
+ .min(1)
28
+ .max(200)
29
+ .refine(hasNoAsciiControlCharacters)
30
+ const gitIdentityEmailSchema = z.string()
31
+ .min(3)
32
+ .max(320)
33
+ .regex(/^[^@<>\s]+@[^@<>\s]+$/u)
34
+ .refine(hasNoAsciiControlCharacters)
35
+ const gitIdentitySchema = z.object({
36
+ name: gitIdentityNameSchema,
37
+ email: gitIdentityEmailSchema,
38
+ }).strict()
39
+
40
+ export const sessionBootstrapBodySchema = z.object({
41
+ sessionId: z.string().min(1),
42
+ agent: z.object({
43
+ provider: agentProviderIdSchema,
44
+ cwd: absoluteDirectoryPathSchema,
45
+ model: z.string().min(1).optional(),
46
+ reasoningEffort: agentReasoningEffortSchema.optional(),
47
+ }).strict(),
48
+ repositories: z.array(repositorySchema).superRefine((repositories, context) => {
49
+ const ids = new Set<string>()
50
+ const roots = new Set<string>()
51
+ for (const [index, repository] of repositories.entries()) {
52
+ if (ids.has(repository.id))
53
+ context.addIssue({ code: 'custom', path: [index, 'id'], message: 'repository id must be unique' })
54
+ if (roots.has(repository.root))
55
+ context.addIssue({ code: 'custom', path: [index, 'root'], message: 'repository root must be unique' })
56
+ ids.add(repository.id)
57
+ roots.add(repository.root)
58
+ }
59
+ }),
60
+ gitBotIdentity: gitIdentitySchema.optional(),
61
+ profile: sessionProfileSchema.optional(),
62
+ initialCommand: z.object({
63
+ commandId: z.string().min(1),
64
+ commandSeq: z.literal(1),
65
+ body: wireCommandBodySchema,
66
+ }).strict(),
67
+ }).strict().superRefine((body, context) => {
68
+ const workspacePrefix = `${body.agent.cwd}/`
69
+ for (const [index, repository] of body.repositories.entries()) {
70
+ if (!repository.root.startsWith(workspacePrefix)) {
71
+ context.addIssue({
72
+ code: 'custom',
73
+ path: ['repositories', index, 'root'],
74
+ message: `repository root must be inside the agent cwd (${body.agent.cwd})`,
75
+ })
76
+ }
77
+ }
78
+ if (body.repositories.length > 0 && body.gitBotIdentity === undefined) {
79
+ context.addIssue({
80
+ code: 'custom',
81
+ path: ['gitBotIdentity'],
82
+ message: 'gitBotIdentity is required when repositories are selected',
83
+ })
84
+ }
85
+ })
86
+
87
+ export const sessionBootstrapGitTokenSchema = z.object({
88
+ token: z.string().min(1),
89
+ expiresAt: z.iso.datetime(),
90
+ }).strict()
91
+
92
+ /**
93
+ * Secrets handed to the supervisor at bootstrap and on every reconnect. They are
94
+ * memory-only on both sides: never persisted to SQLite, never part of the
95
+ * bootstrap hash, never logged. Keys are environment-variable shaped because
96
+ * `ProviderCredentialsSource.environmentFor` maps them straight into the harness
97
+ * child environment.
98
+ */
99
+ export const ephemeralCredentialNameSchema = z.string().max(128).regex(/^[A-Z][A-Z0-9_]*$/u)
100
+ export const ephemeralCredentialMaxValueBytes = 16 * 1024
101
+ export const ephemeralCredentialsMaxEntries = 64
102
+
103
+ export const ephemeralCredentialSchema = z.object({
104
+ value: z.string().min(1).refine(value => new TextEncoder().encode(value).byteLength <= ephemeralCredentialMaxValueBytes, {
105
+ message: `credential value must be at most ${ephemeralCredentialMaxValueBytes} bytes`,
106
+ }),
107
+ expiresAt: z.iso.datetime().optional(),
108
+ }).strict()
109
+
110
+ export const ephemeralCredentialsSchema = z.record(ephemeralCredentialNameSchema, ephemeralCredentialSchema)
111
+ .refine(value => Object.keys(value).length <= ephemeralCredentialsMaxEntries, {
112
+ message: `at most ${ephemeralCredentialsMaxEntries} credentials may be issued`,
113
+ })
114
+
115
+ export type SessionBootstrapBody = z.infer<typeof sessionBootstrapBodySchema>
116
+ export type SessionBootstrapRepository = SessionBootstrapBody['repositories'][number]
117
+ export type SessionBootstrapGitToken = z.infer<typeof sessionBootstrapGitTokenSchema>
118
+ export type EphemeralCredential = z.infer<typeof ephemeralCredentialSchema>
119
+ export type EphemeralCredentials = z.infer<typeof ephemeralCredentialsSchema>
120
+
121
+ function hasNoAsciiControlCharacters(value: string): boolean {
122
+ return [...value].every((character) => {
123
+ const codePoint = character.codePointAt(0)
124
+ return codePoint !== undefined && codePoint > 31 && codePoint !== 127
125
+ })
126
+ }