@agentuity/core 2.0.10 → 2.0.11
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/services/coder/agents.d.ts +170 -0
- package/dist/services/coder/agents.d.ts.map +1 -0
- package/dist/services/coder/agents.js +77 -0
- package/dist/services/coder/agents.js.map +1 -0
- package/dist/services/coder/api-reference.d.ts.map +1 -1
- package/dist/services/coder/api-reference.js +391 -39
- package/dist/services/coder/api-reference.js.map +1 -1
- package/dist/services/coder/client.d.ts +43 -1
- package/dist/services/coder/client.d.ts.map +1 -1
- package/dist/services/coder/client.js +87 -1
- package/dist/services/coder/client.js.map +1 -1
- package/dist/services/coder/close-codes.d.ts +76 -0
- package/dist/services/coder/close-codes.d.ts.map +1 -0
- package/dist/services/coder/close-codes.js +77 -0
- package/dist/services/coder/close-codes.js.map +1 -0
- package/dist/services/coder/index.d.ts +9 -2
- package/dist/services/coder/index.d.ts.map +1 -1
- package/dist/services/coder/index.js +6 -1
- package/dist/services/coder/index.js.map +1 -1
- package/dist/services/coder/protocol.d.ts +1855 -0
- package/dist/services/coder/protocol.d.ts.map +1 -0
- package/dist/services/coder/protocol.js +976 -0
- package/dist/services/coder/protocol.js.map +1 -0
- package/dist/services/coder/sessions.d.ts +9 -0
- package/dist/services/coder/sessions.d.ts.map +1 -1
- package/dist/services/coder/sessions.js +30 -6
- package/dist/services/coder/sessions.js.map +1 -1
- package/dist/services/coder/sse.d.ts +255 -0
- package/dist/services/coder/sse.d.ts.map +1 -0
- package/dist/services/coder/sse.js +676 -0
- package/dist/services/coder/sse.js.map +1 -0
- package/dist/services/coder/types.d.ts +1013 -0
- package/dist/services/coder/types.d.ts.map +1 -1
- package/dist/services/coder/types.js +215 -1
- package/dist/services/coder/types.js.map +1 -1
- package/dist/services/coder/websocket.d.ts +346 -0
- package/dist/services/coder/websocket.d.ts.map +1 -0
- package/dist/services/coder/websocket.js +791 -0
- package/dist/services/coder/websocket.js.map +1 -0
- package/dist/services/oauth/types.d.ts +10 -0
- package/dist/services/oauth/types.d.ts.map +1 -1
- package/dist/services/oauth/types.js +3 -0
- package/dist/services/oauth/types.js.map +1 -1
- package/dist/services/project/deploy.d.ts +1 -1
- package/dist/services/sandbox/run.d.ts +2 -2
- package/dist/services/sandbox/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/services/coder/agents.ts +148 -0
- package/src/services/coder/api-reference.ts +409 -43
- package/src/services/coder/client.ts +131 -0
- package/src/services/coder/close-codes.ts +83 -0
- package/src/services/coder/index.ts +29 -1
- package/src/services/coder/protocol.ts +1200 -0
- package/src/services/coder/sessions.ts +40 -10
- package/src/services/coder/sse.ts +796 -0
- package/src/services/coder/types.ts +249 -1
- package/src/services/coder/websocket.ts +943 -0
- package/src/services/oauth/types.ts +3 -0
|
@@ -0,0 +1,1200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol message types for Coder Hub WebSocket and SSE communication.
|
|
3
|
+
*
|
|
4
|
+
* This module defines all message types exchanged between clients and the
|
|
5
|
+
* Coder Hub server. Messages are validated using Zod schemas for type safety.
|
|
6
|
+
*
|
|
7
|
+
* @module coder/protocol
|
|
8
|
+
*
|
|
9
|
+
* @example Parsing server messages
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { parseServerMessage, type ServerMessage } from '@agentuity/core/coder';
|
|
12
|
+
*
|
|
13
|
+
* const raw = JSON.parse(websocketData);
|
|
14
|
+
* const message = parseServerMessage(raw);
|
|
15
|
+
* if (message?.type === 'broadcast') {
|
|
16
|
+
* console.log('Event:', message.event);
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { z } from 'zod/v4';
|
|
22
|
+
|
|
23
|
+
/** Connection role assigned by the server in the init message */
|
|
24
|
+
export const CoderHubInitRoleSchema = z
|
|
25
|
+
.enum(['lead', 'sub_agent', 'controller'])
|
|
26
|
+
.describe(
|
|
27
|
+
'Role assigned to a connecting client, determining its permissions and message routing.'
|
|
28
|
+
);
|
|
29
|
+
export type CoderHubInitRole = z.infer<typeof CoderHubInitRoleSchema>;
|
|
30
|
+
|
|
31
|
+
/** Tool definition provided by the server to clients */
|
|
32
|
+
export const CoderHubToolDefinitionSchema = z
|
|
33
|
+
.object({
|
|
34
|
+
name: z.string().describe('Unique programmatic identifier for the tool.'),
|
|
35
|
+
label: z.string().describe('Human-readable display name for the tool.'),
|
|
36
|
+
description: z.string().describe('Explanation of what the tool does, shown to the LLM.'),
|
|
37
|
+
parameters: z
|
|
38
|
+
.record(z.string(), z.unknown())
|
|
39
|
+
.describe('JSON Schema describing the tool input parameters.'),
|
|
40
|
+
promptSnippet: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Snippet injected into the system prompt when this tool is available.'),
|
|
44
|
+
promptGuidelines: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe(
|
|
48
|
+
'Usage guidelines appended to the prompt to help the LLM use this tool correctly.'
|
|
49
|
+
),
|
|
50
|
+
timeoutMs: z
|
|
51
|
+
.number()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Maximum execution time in milliseconds before the tool call is aborted.'),
|
|
54
|
+
})
|
|
55
|
+
.describe('Definition of a hub-provided tool that can be invoked by agents during a session.');
|
|
56
|
+
export type CoderHubToolDefinition = z.infer<typeof CoderHubToolDefinitionSchema>;
|
|
57
|
+
|
|
58
|
+
export const CoderHubCommandDefinitionSchema = z
|
|
59
|
+
.object({
|
|
60
|
+
name: z.string().describe('Unique identifier for the command.'),
|
|
61
|
+
description: z.string().describe('Human-readable description of what the command does.'),
|
|
62
|
+
})
|
|
63
|
+
.describe('Definition of a slash-command available to clients for direct execution.');
|
|
64
|
+
export type CoderHubCommandDefinition = z.infer<typeof CoderHubCommandDefinitionSchema>;
|
|
65
|
+
|
|
66
|
+
export const AgentDefinitionSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
name: z.string().describe('Unique programmatic name used to reference this agent.'),
|
|
69
|
+
displayName: z
|
|
70
|
+
.string()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('Human-friendly name shown in UIs; defaults to name if omitted.'),
|
|
73
|
+
description: z.string().describe('Summary of the agent role and capabilities.'),
|
|
74
|
+
systemPrompt: z
|
|
75
|
+
.string()
|
|
76
|
+
.describe('Base system prompt that defines the agent personality and instructions.'),
|
|
77
|
+
model: z
|
|
78
|
+
.string()
|
|
79
|
+
.optional()
|
|
80
|
+
.describe('LLM model identifier to use; inherits the session default if omitted.'),
|
|
81
|
+
tools: z
|
|
82
|
+
.array(z.string())
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('List of tool names this agent is allowed to invoke.'),
|
|
85
|
+
temperature: z.number().optional().describe('Sampling temperature override for this agent.'),
|
|
86
|
+
thinkingLevel: z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe('Extended-thinking budget level (e.g. "low", "medium", "high").'),
|
|
90
|
+
readOnly: z
|
|
91
|
+
.boolean()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe('When true, the agent cannot make file modifications or run commands.'),
|
|
94
|
+
hubTools: z
|
|
95
|
+
.array(CoderHubToolDefinitionSchema)
|
|
96
|
+
.optional()
|
|
97
|
+
.describe('Additional hub-provided tools scoped exclusively to this agent.'),
|
|
98
|
+
capabilities: z
|
|
99
|
+
.array(z.string())
|
|
100
|
+
.optional()
|
|
101
|
+
.describe('Capability tags advertising what this agent can do (e.g. "code", "review").'),
|
|
102
|
+
status: z
|
|
103
|
+
.enum(['available', 'busy', 'offline'])
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('Current availability status of the agent for task assignment.'),
|
|
106
|
+
})
|
|
107
|
+
.describe(
|
|
108
|
+
'Full definition of a coder agent including its prompt, model, tools, and operational constraints.'
|
|
109
|
+
);
|
|
110
|
+
export type AgentDefinition = z.infer<typeof AgentDefinitionSchema>;
|
|
111
|
+
|
|
112
|
+
export const CoderHubConfigSchema = z
|
|
113
|
+
.object({
|
|
114
|
+
systemPromptPrefix: z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe('Text prepended to every agent system prompt in this session.'),
|
|
118
|
+
systemPromptSuffix: z
|
|
119
|
+
.string()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe('Text appended to every agent system prompt in this session.'),
|
|
122
|
+
})
|
|
123
|
+
.describe('Session-level configuration overrides sent by the hub during initialization.');
|
|
124
|
+
export type CoderHubConfig = z.infer<typeof CoderHubConfigSchema>;
|
|
125
|
+
|
|
126
|
+
export const CoderHubLeadResumeDescriptorSchema = z
|
|
127
|
+
.object({
|
|
128
|
+
sessionFile: z.string().describe('Path to the session file on disk to resume from.'),
|
|
129
|
+
piSessionId: z
|
|
130
|
+
.string()
|
|
131
|
+
.optional()
|
|
132
|
+
.describe('Platform session ID to correlate the resumed session with the backend.'),
|
|
133
|
+
cwd: z
|
|
134
|
+
.string()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe(
|
|
137
|
+
'Working directory to restore; defaults to the original session cwd if omitted.'
|
|
138
|
+
),
|
|
139
|
+
})
|
|
140
|
+
.describe('Descriptor for resuming a previously interrupted lead session from a saved file.');
|
|
141
|
+
export type CoderHubLeadResumeDescriptor = z.infer<typeof CoderHubLeadResumeDescriptorSchema>;
|
|
142
|
+
|
|
143
|
+
const BaseCoderHubInitMessageSchema = z
|
|
144
|
+
.object({
|
|
145
|
+
type: z
|
|
146
|
+
.literal('init')
|
|
147
|
+
.describe('Discriminator indicating this is an initialization message.'),
|
|
148
|
+
role: CoderHubInitRoleSchema,
|
|
149
|
+
sessionId: z
|
|
150
|
+
.string()
|
|
151
|
+
.optional()
|
|
152
|
+
.describe('Existing session ID to join; omit to create a new session.'),
|
|
153
|
+
resume: CoderHubLeadResumeDescriptorSchema.optional().describe(
|
|
154
|
+
'Resume descriptor for reconnecting to a prior session.'
|
|
155
|
+
),
|
|
156
|
+
tools: z
|
|
157
|
+
.array(CoderHubToolDefinitionSchema)
|
|
158
|
+
.optional()
|
|
159
|
+
.describe('Tools the connecting client provides to the session.'),
|
|
160
|
+
commands: z
|
|
161
|
+
.array(CoderHubCommandDefinitionSchema)
|
|
162
|
+
.optional()
|
|
163
|
+
.describe('Slash-commands the connecting client registers.'),
|
|
164
|
+
agents: z
|
|
165
|
+
.array(AgentDefinitionSchema)
|
|
166
|
+
.optional()
|
|
167
|
+
.describe('Agent definitions the client contributes to the session pool.'),
|
|
168
|
+
config: CoderHubConfigSchema.optional().describe(
|
|
169
|
+
'Session configuration overrides applied at initialization.'
|
|
170
|
+
),
|
|
171
|
+
model: z
|
|
172
|
+
.object({
|
|
173
|
+
provider: z.string().describe('LLM provider name (e.g. "anthropic", "openai").'),
|
|
174
|
+
id: z.string().describe('Specific model identifier within the provider.'),
|
|
175
|
+
})
|
|
176
|
+
.optional()
|
|
177
|
+
.describe('Preferred LLM model for this session; overrides the hub default.'),
|
|
178
|
+
thinkingLevel: z
|
|
179
|
+
.string()
|
|
180
|
+
.optional()
|
|
181
|
+
.describe('Extended-thinking budget level requested for this session.'),
|
|
182
|
+
task: z
|
|
183
|
+
.string()
|
|
184
|
+
.optional()
|
|
185
|
+
.describe('Initial task prompt to begin working on immediately after connection.'),
|
|
186
|
+
agentRole: z
|
|
187
|
+
.string()
|
|
188
|
+
.optional()
|
|
189
|
+
.describe('Specific agent role name this client should assume in the session.'),
|
|
190
|
+
})
|
|
191
|
+
.describe('Base initialization message sent by any client when first connecting to the hub.');
|
|
192
|
+
|
|
193
|
+
export const CoderHubLeadInitMessageSchema = BaseCoderHubInitMessageSchema.extend({
|
|
194
|
+
role: z
|
|
195
|
+
.literal('lead')
|
|
196
|
+
.describe('Indicates this client is connecting as the lead orchestrator.'),
|
|
197
|
+
}).describe('Initialization message sent by a lead client that orchestrates the coding session.');
|
|
198
|
+
export type CoderHubLeadInitMessage = z.infer<typeof CoderHubLeadInitMessageSchema>;
|
|
199
|
+
|
|
200
|
+
export const CoderHubSubAgentInitMessageSchema = BaseCoderHubInitMessageSchema.extend({
|
|
201
|
+
role: z
|
|
202
|
+
.literal('sub_agent')
|
|
203
|
+
.describe('Indicates this client is connecting as a sub-agent worker.'),
|
|
204
|
+
}).describe(
|
|
205
|
+
'Initialization message sent by a sub-agent that executes tasks delegated by the lead.'
|
|
206
|
+
);
|
|
207
|
+
export type CoderHubSubAgentInitMessage = z.infer<typeof CoderHubSubAgentInitMessageSchema>;
|
|
208
|
+
|
|
209
|
+
export const CoderHubControllerInitMessageSchema = BaseCoderHubInitMessageSchema.extend({
|
|
210
|
+
role: z
|
|
211
|
+
.literal('controller')
|
|
212
|
+
.describe('Indicates this client is connecting as an external controller.'),
|
|
213
|
+
}).describe(
|
|
214
|
+
'Initialization message sent by a controller client that manages sessions without direct coding.'
|
|
215
|
+
);
|
|
216
|
+
export type CoderHubControllerInitMessage = z.infer<typeof CoderHubControllerInitMessageSchema>;
|
|
217
|
+
|
|
218
|
+
export const CoderHubInitMessageSchema = z
|
|
219
|
+
.discriminatedUnion('role', [
|
|
220
|
+
CoderHubLeadInitMessageSchema,
|
|
221
|
+
CoderHubSubAgentInitMessageSchema,
|
|
222
|
+
CoderHubControllerInitMessageSchema,
|
|
223
|
+
])
|
|
224
|
+
.describe('Union of all initialization messages, discriminated by the client role.');
|
|
225
|
+
export type CoderHubInitMessage = z.infer<typeof CoderHubInitMessageSchema>;
|
|
226
|
+
|
|
227
|
+
export const CoderHubStreamReadyMessageSchema = z
|
|
228
|
+
.object({
|
|
229
|
+
type: z
|
|
230
|
+
.literal('session_stream_ready')
|
|
231
|
+
.describe('Discriminator indicating the session stream is ready for consumption.'),
|
|
232
|
+
streamId: z.string().describe('Unique identifier for this stream instance.'),
|
|
233
|
+
streamUrl: z
|
|
234
|
+
.string()
|
|
235
|
+
.describe('URL endpoint where the client can consume the session stream.'),
|
|
236
|
+
})
|
|
237
|
+
.describe(
|
|
238
|
+
'Server message indicating that the real-time session stream is established and ready for the client.'
|
|
239
|
+
);
|
|
240
|
+
export type CoderHubStreamReadyMessage = z.infer<typeof CoderHubStreamReadyMessageSchema>;
|
|
241
|
+
|
|
242
|
+
export const CoderHubSessionResumeMessageSchema = z
|
|
243
|
+
.object({
|
|
244
|
+
type: z
|
|
245
|
+
.literal('session_resume')
|
|
246
|
+
.describe('Discriminator indicating this is a session resume notification.'),
|
|
247
|
+
streamUrl: z.string().describe('URL endpoint for the resumed session stream.'),
|
|
248
|
+
streamId: z.string().describe('Unique identifier for the resumed stream instance.'),
|
|
249
|
+
activePrdKey: z
|
|
250
|
+
.string()
|
|
251
|
+
.optional()
|
|
252
|
+
.describe(
|
|
253
|
+
'Key of the active PRD document if one was in progress when the session was interrupted.'
|
|
254
|
+
),
|
|
255
|
+
})
|
|
256
|
+
.describe('Server message sent when a previously disconnected session is successfully resumed.');
|
|
257
|
+
export type CoderHubSessionResumeMessage = z.infer<typeof CoderHubSessionResumeMessageSchema>;
|
|
258
|
+
|
|
259
|
+
export const ConnectionRejectedMessageSchema = z
|
|
260
|
+
.object({
|
|
261
|
+
type: z
|
|
262
|
+
.literal('connection_rejected')
|
|
263
|
+
.describe('Discriminator indicating the connection was refused by the server.'),
|
|
264
|
+
code: z.string().describe('Machine-readable rejection reason code (e.g. "session_expired").'),
|
|
265
|
+
message: z
|
|
266
|
+
.string()
|
|
267
|
+
.describe('Human-readable explanation of why the connection was rejected.'),
|
|
268
|
+
sessionId: z
|
|
269
|
+
.string()
|
|
270
|
+
.optional()
|
|
271
|
+
.describe('Session ID the client tried to join, if applicable.'),
|
|
272
|
+
reconnectState: z
|
|
273
|
+
.string()
|
|
274
|
+
.optional()
|
|
275
|
+
.describe('Opaque state token the client can use to attempt reconnection.'),
|
|
276
|
+
expiredAt: z
|
|
277
|
+
.number()
|
|
278
|
+
.optional()
|
|
279
|
+
.describe('Unix timestamp (ms) when the session expired, if rejection is due to expiry.'),
|
|
280
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the rejection occurred.'),
|
|
281
|
+
})
|
|
282
|
+
.describe(
|
|
283
|
+
'Server message sent when a client connection is rejected due to authentication failure, session expiry, or capacity limits.'
|
|
284
|
+
);
|
|
285
|
+
export type ConnectionRejectedMessage = z.infer<typeof ConnectionRejectedMessageSchema>;
|
|
286
|
+
|
|
287
|
+
export const ProtocolErrorMessageSchema = z
|
|
288
|
+
.object({
|
|
289
|
+
type: z
|
|
290
|
+
.literal('protocol_error')
|
|
291
|
+
.describe('Discriminator indicating a protocol-level error occurred.'),
|
|
292
|
+
code: z.string().describe('Machine-readable error code identifying the error type.'),
|
|
293
|
+
message: z.string().describe('Human-readable description of the protocol error.'),
|
|
294
|
+
sessionId: z
|
|
295
|
+
.string()
|
|
296
|
+
.optional()
|
|
297
|
+
.describe('Session ID associated with the error, if the error is session-scoped.'),
|
|
298
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the error occurred.'),
|
|
299
|
+
})
|
|
300
|
+
.describe('Server message reporting a protocol violation or malformed message from the client.');
|
|
301
|
+
export type ProtocolErrorMessage = z.infer<typeof ProtocolErrorMessageSchema>;
|
|
302
|
+
|
|
303
|
+
export const AckActionSchema = z
|
|
304
|
+
.object({
|
|
305
|
+
action: z
|
|
306
|
+
.literal('ACK')
|
|
307
|
+
.describe('Discriminator indicating a simple acknowledgement with no payload.'),
|
|
308
|
+
})
|
|
309
|
+
.describe('Action acknowledging receipt of a request with no additional data.');
|
|
310
|
+
export type AckAction = z.infer<typeof AckActionSchema>;
|
|
311
|
+
|
|
312
|
+
export const BlockActionSchema = z
|
|
313
|
+
.object({
|
|
314
|
+
action: z
|
|
315
|
+
.literal('BLOCK')
|
|
316
|
+
.describe('Discriminator indicating the requested operation was blocked.'),
|
|
317
|
+
reason: z.string().describe('Explanation of why the operation was blocked.'),
|
|
318
|
+
})
|
|
319
|
+
.describe('Action indicating the hub blocked a tool call or operation, with a reason.');
|
|
320
|
+
export type BlockAction = z.infer<typeof BlockActionSchema>;
|
|
321
|
+
|
|
322
|
+
export const ConfirmActionSchema = z
|
|
323
|
+
.object({
|
|
324
|
+
action: z
|
|
325
|
+
.literal('CONFIRM')
|
|
326
|
+
.describe('Discriminator indicating user confirmation is required.'),
|
|
327
|
+
title: z.string().describe('Short title for the confirmation dialog.'),
|
|
328
|
+
message: z.string().describe('Detailed message explaining what the user is confirming.'),
|
|
329
|
+
deny_reason: z
|
|
330
|
+
.string()
|
|
331
|
+
.optional()
|
|
332
|
+
.describe('Pre-filled reason shown if the user denies the confirmation.'),
|
|
333
|
+
})
|
|
334
|
+
.describe(
|
|
335
|
+
'Action requesting the user to confirm or deny a potentially destructive operation before proceeding.'
|
|
336
|
+
);
|
|
337
|
+
export type ConfirmAction = z.infer<typeof ConfirmActionSchema>;
|
|
338
|
+
|
|
339
|
+
export const NotifyActionSchema = z
|
|
340
|
+
.object({
|
|
341
|
+
action: z
|
|
342
|
+
.literal('NOTIFY')
|
|
343
|
+
.describe('Discriminator indicating a notification to display to the user.'),
|
|
344
|
+
message: z.string().describe('Notification text to display.'),
|
|
345
|
+
level: z
|
|
346
|
+
.enum(['info', 'warning', 'error'])
|
|
347
|
+
.optional()
|
|
348
|
+
.describe(
|
|
349
|
+
'Severity level controlling how the notification is displayed; defaults to info.'
|
|
350
|
+
),
|
|
351
|
+
})
|
|
352
|
+
.describe(
|
|
353
|
+
'Action displaying a transient notification message to the user at the specified severity.'
|
|
354
|
+
);
|
|
355
|
+
export type NotifyAction = z.infer<typeof NotifyActionSchema>;
|
|
356
|
+
|
|
357
|
+
export const ReturnActionSchema = z
|
|
358
|
+
.object({
|
|
359
|
+
action: z
|
|
360
|
+
.literal('RETURN')
|
|
361
|
+
.describe('Discriminator indicating this action carries a return value for a tool call.'),
|
|
362
|
+
result: z.unknown().describe('Arbitrary result value returned from a hub tool execution.'),
|
|
363
|
+
})
|
|
364
|
+
.describe('Action returning the result of a hub tool invocation back to the calling agent.');
|
|
365
|
+
export type ReturnAction = z.infer<typeof ReturnActionSchema>;
|
|
366
|
+
|
|
367
|
+
export const StatusActionSchema = z
|
|
368
|
+
.object({
|
|
369
|
+
action: z.literal('STATUS').describe('Discriminator indicating a status indicator update.'),
|
|
370
|
+
key: z.string().describe('Unique key identifying which status indicator to update.'),
|
|
371
|
+
text: z
|
|
372
|
+
.string()
|
|
373
|
+
.optional()
|
|
374
|
+
.describe('Display text for the status indicator; omit to clear the status.'),
|
|
375
|
+
})
|
|
376
|
+
.describe(
|
|
377
|
+
'Action updating a named status indicator in the client UI (e.g. progress, phase label).'
|
|
378
|
+
);
|
|
379
|
+
export type StatusAction = z.infer<typeof StatusActionSchema>;
|
|
380
|
+
|
|
381
|
+
export const SystemPromptActionSchema = z
|
|
382
|
+
.object({
|
|
383
|
+
action: z
|
|
384
|
+
.literal('SYSTEM_PROMPT')
|
|
385
|
+
.describe('Discriminator indicating a system prompt modification.'),
|
|
386
|
+
systemPrompt: z.string().describe('The system prompt content to apply.'),
|
|
387
|
+
mode: z
|
|
388
|
+
.enum(['replace', 'prefix', 'suffix'])
|
|
389
|
+
.optional()
|
|
390
|
+
.describe(
|
|
391
|
+
'How to apply the prompt: replace the entire prompt, prepend, or append; defaults to replace.'
|
|
392
|
+
),
|
|
393
|
+
})
|
|
394
|
+
.describe(
|
|
395
|
+
'Action modifying the active agent system prompt mid-session by replacing, prefixing, or suffixing content.'
|
|
396
|
+
);
|
|
397
|
+
export type SystemPromptAction = z.infer<typeof SystemPromptActionSchema>;
|
|
398
|
+
|
|
399
|
+
export const InjectMessageActionSchema = z
|
|
400
|
+
.object({
|
|
401
|
+
action: z
|
|
402
|
+
.literal('INJECT_MESSAGE')
|
|
403
|
+
.describe('Discriminator indicating a message should be injected into the conversation.'),
|
|
404
|
+
message: z
|
|
405
|
+
.object({
|
|
406
|
+
role: z
|
|
407
|
+
.enum(['user', 'assistant'])
|
|
408
|
+
.describe('Conversation role for the injected message.'),
|
|
409
|
+
content: z.string().describe('Text content of the injected message.'),
|
|
410
|
+
})
|
|
411
|
+
.describe('The synthetic message to inject into the conversation history.'),
|
|
412
|
+
})
|
|
413
|
+
.describe(
|
|
414
|
+
'Action injecting a synthetic user or assistant message into the conversation context without an actual turn.'
|
|
415
|
+
);
|
|
416
|
+
export type InjectMessageAction = z.infer<typeof InjectMessageActionSchema>;
|
|
417
|
+
|
|
418
|
+
export const CoderHubActionSchema = z
|
|
419
|
+
.discriminatedUnion('action', [
|
|
420
|
+
AckActionSchema,
|
|
421
|
+
BlockActionSchema,
|
|
422
|
+
ConfirmActionSchema,
|
|
423
|
+
NotifyActionSchema,
|
|
424
|
+
ReturnActionSchema,
|
|
425
|
+
StatusActionSchema,
|
|
426
|
+
SystemPromptActionSchema,
|
|
427
|
+
InjectMessageActionSchema,
|
|
428
|
+
])
|
|
429
|
+
.describe(
|
|
430
|
+
'Union of all hub response actions, discriminated by the action field. Multiple actions can be batched in a single response.'
|
|
431
|
+
);
|
|
432
|
+
export type CoderHubAction = z.infer<typeof CoderHubActionSchema>;
|
|
433
|
+
|
|
434
|
+
export const CoderHubResponseSchema = z
|
|
435
|
+
.object({
|
|
436
|
+
id: z.string().describe('Request ID this response correlates to.'),
|
|
437
|
+
actions: z
|
|
438
|
+
.array(CoderHubActionSchema)
|
|
439
|
+
.describe('Ordered list of actions the client should execute in response to the request.'),
|
|
440
|
+
})
|
|
441
|
+
.describe(
|
|
442
|
+
'Server response to a client request, containing one or more actions to execute (e.g. ACK, BLOCK, RETURN).'
|
|
443
|
+
);
|
|
444
|
+
export type CoderHubResponse = z.infer<typeof CoderHubResponseSchema>;
|
|
445
|
+
|
|
446
|
+
export const ConversationAuthorSchema = z
|
|
447
|
+
.object({
|
|
448
|
+
userId: z.string().optional().describe('Platform user ID of the author.'),
|
|
449
|
+
displayName: z.string().optional().describe('Display name shown in the conversation UI.'),
|
|
450
|
+
email: z.string().optional().describe('Email address of the author.'),
|
|
451
|
+
avatarUrl: z.string().optional().describe('URL to the author avatar image.'),
|
|
452
|
+
actorType: z
|
|
453
|
+
.enum(['user', 'api_key', 'service'])
|
|
454
|
+
.optional()
|
|
455
|
+
.describe(
|
|
456
|
+
'Type of actor that authored the entry: a human user, API key, or internal service.'
|
|
457
|
+
),
|
|
458
|
+
apiKeyLabel: z
|
|
459
|
+
.string()
|
|
460
|
+
.optional()
|
|
461
|
+
.describe('Label of the API key used, when actorType is "api_key".'),
|
|
462
|
+
})
|
|
463
|
+
.describe('Identity metadata for the author of a conversation entry or prompt.');
|
|
464
|
+
export type ConversationAuthor = z.infer<typeof ConversationAuthorSchema>;
|
|
465
|
+
|
|
466
|
+
export const RuntimeProcessDescriptorSchema = z
|
|
467
|
+
.object({
|
|
468
|
+
pid: z.number().optional().describe('Operating system process ID.'),
|
|
469
|
+
command: z.string().optional().describe('Executable name or path that was run.'),
|
|
470
|
+
args: z
|
|
471
|
+
.array(z.string())
|
|
472
|
+
.optional()
|
|
473
|
+
.describe('Command-line arguments passed to the process.'),
|
|
474
|
+
cwd: z.string().optional().describe('Working directory the process was started in.'),
|
|
475
|
+
env: z
|
|
476
|
+
.record(z.string(), z.string())
|
|
477
|
+
.optional()
|
|
478
|
+
.describe('Environment variables set for the process.'),
|
|
479
|
+
status: z
|
|
480
|
+
.string()
|
|
481
|
+
.optional()
|
|
482
|
+
.describe('Current lifecycle status (e.g. "running", "exited").'),
|
|
483
|
+
exitCode: z
|
|
484
|
+
.number()
|
|
485
|
+
.optional()
|
|
486
|
+
.describe('Process exit code after termination; null while running.'),
|
|
487
|
+
signal: z
|
|
488
|
+
.string()
|
|
489
|
+
.optional()
|
|
490
|
+
.describe('Signal that terminated the process (e.g. "SIGTERM"), if applicable.'),
|
|
491
|
+
})
|
|
492
|
+
.describe(
|
|
493
|
+
'Snapshot of a runtime process spawned during a session, including its lifecycle state.'
|
|
494
|
+
);
|
|
495
|
+
export type RuntimeProcessDescriptor = z.infer<typeof RuntimeProcessDescriptorSchema>;
|
|
496
|
+
|
|
497
|
+
export const RuntimePreviewDescriptorSchema = z
|
|
498
|
+
.object({
|
|
499
|
+
url: z.string().optional().describe('Public URL where the preview can be accessed.'),
|
|
500
|
+
port: z.number().optional().describe('Local port the preview server is listening on.'),
|
|
501
|
+
protocol: z
|
|
502
|
+
.string()
|
|
503
|
+
.optional()
|
|
504
|
+
.describe('Protocol used by the preview (e.g. "http", "https").'),
|
|
505
|
+
path: z.string().optional().describe('URL path suffix appended to the preview base URL.'),
|
|
506
|
+
status: z
|
|
507
|
+
.string()
|
|
508
|
+
.optional()
|
|
509
|
+
.describe('Current status of the preview (e.g. "ready", "starting").'),
|
|
510
|
+
})
|
|
511
|
+
.describe(
|
|
512
|
+
'Descriptor for a live web preview of a running application within the session sandbox.'
|
|
513
|
+
);
|
|
514
|
+
export type RuntimePreviewDescriptor = z.infer<typeof RuntimePreviewDescriptorSchema>;
|
|
515
|
+
|
|
516
|
+
export const PromptAttachmentDescriptorSchema = z
|
|
517
|
+
.object({
|
|
518
|
+
type: z.string().describe('Attachment type identifier (e.g. "file", "image", "url").'),
|
|
519
|
+
name: z.string().optional().describe('Display name or filename of the attachment.'),
|
|
520
|
+
url: z.string().optional().describe('URL to fetch the attachment content from.'),
|
|
521
|
+
content: z
|
|
522
|
+
.string()
|
|
523
|
+
.optional()
|
|
524
|
+
.describe('Inline content of the attachment when small enough to embed directly.'),
|
|
525
|
+
mimeType: z.string().optional().describe('MIME type of the attachment content.'),
|
|
526
|
+
size: z.number().optional().describe('Size of the attachment in bytes.'),
|
|
527
|
+
})
|
|
528
|
+
.describe('File or media attachment associated with a user prompt or conversation entry.');
|
|
529
|
+
export type PromptAttachmentDescriptor = z.infer<typeof PromptAttachmentDescriptorSchema>;
|
|
530
|
+
|
|
531
|
+
export const ConversationEntrySchema = z
|
|
532
|
+
.object({
|
|
533
|
+
type: z
|
|
534
|
+
.enum([
|
|
535
|
+
'message',
|
|
536
|
+
'thinking',
|
|
537
|
+
'tool_call',
|
|
538
|
+
'tool_result',
|
|
539
|
+
'task_result',
|
|
540
|
+
'runtime_status',
|
|
541
|
+
'runtime_output',
|
|
542
|
+
'runtime_preview',
|
|
543
|
+
'turn',
|
|
544
|
+
'user_prompt',
|
|
545
|
+
])
|
|
546
|
+
.describe('Kind of conversation entry, determining which fields are populated.'),
|
|
547
|
+
agent: z
|
|
548
|
+
.string()
|
|
549
|
+
.optional()
|
|
550
|
+
.describe('Name of the agent that produced this entry, if agent-scoped.'),
|
|
551
|
+
content: z.string().optional().describe('Text content of a message or tool result.'),
|
|
552
|
+
thinking: z
|
|
553
|
+
.string()
|
|
554
|
+
.optional()
|
|
555
|
+
.describe('Extended-thinking text generated by the model before responding.'),
|
|
556
|
+
toolName: z
|
|
557
|
+
.string()
|
|
558
|
+
.optional()
|
|
559
|
+
.describe('Name of the tool invoked, for tool_call and tool_result entries.'),
|
|
560
|
+
toolArgs: z
|
|
561
|
+
.record(z.string(), z.unknown())
|
|
562
|
+
.optional()
|
|
563
|
+
.describe('Arguments passed to the tool invocation.'),
|
|
564
|
+
toolCallId: z
|
|
565
|
+
.string()
|
|
566
|
+
.optional()
|
|
567
|
+
.describe('Unique identifier linking a tool_call to its corresponding tool_result.'),
|
|
568
|
+
runtime: RuntimeProcessDescriptorSchema.optional().describe(
|
|
569
|
+
'Process descriptor for runtime_status and runtime_output entries.'
|
|
570
|
+
),
|
|
571
|
+
preview: RuntimePreviewDescriptorSchema.optional().describe(
|
|
572
|
+
'Preview descriptor for runtime_preview entries.'
|
|
573
|
+
),
|
|
574
|
+
attachments: z
|
|
575
|
+
.array(PromptAttachmentDescriptorSchema)
|
|
576
|
+
.optional()
|
|
577
|
+
.describe('Files or media attached to a user_prompt entry.'),
|
|
578
|
+
author: ConversationAuthorSchema.optional().describe(
|
|
579
|
+
'Identity of the human or service that authored this entry.'
|
|
580
|
+
),
|
|
581
|
+
isError: z
|
|
582
|
+
.boolean()
|
|
583
|
+
.optional()
|
|
584
|
+
.describe('When true, indicates this entry represents an error condition.'),
|
|
585
|
+
taskId: z
|
|
586
|
+
.string()
|
|
587
|
+
.optional()
|
|
588
|
+
.describe('Task ID this entry belongs to, for multi-task sessions.'),
|
|
589
|
+
turnId: z
|
|
590
|
+
.string()
|
|
591
|
+
.optional()
|
|
592
|
+
.describe('Turn ID grouping related entries within a single conversational turn.'),
|
|
593
|
+
replyId: z
|
|
594
|
+
.string()
|
|
595
|
+
.optional()
|
|
596
|
+
.describe('ID of a prior entry this is replying to, for threaded conversations.'),
|
|
597
|
+
sequence: z
|
|
598
|
+
.number()
|
|
599
|
+
.optional()
|
|
600
|
+
.describe('Monotonically increasing sequence number for ordering entries.'),
|
|
601
|
+
elapsedMs: z
|
|
602
|
+
.number()
|
|
603
|
+
.optional()
|
|
604
|
+
.describe('Time in milliseconds this entry took to produce (e.g. tool execution time).'),
|
|
605
|
+
timestamp: z.number().describe('Unix timestamp (ms) when this entry was created.'),
|
|
606
|
+
})
|
|
607
|
+
.describe(
|
|
608
|
+
'A single entry in the session conversation log, representing a message, tool call, thinking block, or runtime event.'
|
|
609
|
+
);
|
|
610
|
+
export type ConversationEntry = z.infer<typeof ConversationEntrySchema>;
|
|
611
|
+
|
|
612
|
+
export const SessionTaskStateSchema = z
|
|
613
|
+
.object({
|
|
614
|
+
taskId: z.string().describe('Unique identifier for this task.'),
|
|
615
|
+
agent: z.string().describe('Name of the agent assigned to execute this task.'),
|
|
616
|
+
status: z
|
|
617
|
+
.enum(['running', 'completed', 'failed'])
|
|
618
|
+
.describe('Current execution status of the task.'),
|
|
619
|
+
prompt: z.string().describe('The original prompt or instruction that initiated this task.'),
|
|
620
|
+
startedAt: z
|
|
621
|
+
.string()
|
|
622
|
+
.optional()
|
|
623
|
+
.describe('ISO 8601 timestamp when the task began execution.'),
|
|
624
|
+
completedAt: z
|
|
625
|
+
.string()
|
|
626
|
+
.optional()
|
|
627
|
+
.describe('ISO 8601 timestamp when the task finished, if completed or failed.'),
|
|
628
|
+
duration: z.number().optional().describe('Total execution duration in milliseconds.'),
|
|
629
|
+
result: z
|
|
630
|
+
.string()
|
|
631
|
+
.optional()
|
|
632
|
+
.describe('Summary of the task result on successful completion.'),
|
|
633
|
+
error: z.string().optional().describe('Error message if the task failed.'),
|
|
634
|
+
})
|
|
635
|
+
.describe('Tracks the lifecycle state of a delegated task within a multi-agent session.');
|
|
636
|
+
export type SessionTaskState = z.infer<typeof SessionTaskStateSchema>;
|
|
637
|
+
|
|
638
|
+
export const SessionStreamBlockSchema = z
|
|
639
|
+
.object({
|
|
640
|
+
output: z.string().describe('Accumulated assistant output text for this stream block.'),
|
|
641
|
+
thinking: z.string().describe('Accumulated extended-thinking text for this stream block.'),
|
|
642
|
+
})
|
|
643
|
+
.describe(
|
|
644
|
+
'A block of streamed content containing both the visible output and internal thinking text.'
|
|
645
|
+
);
|
|
646
|
+
export type SessionStreamBlock = z.infer<typeof SessionStreamBlockSchema>;
|
|
647
|
+
|
|
648
|
+
export const SessionStreamProjectionSchema = SessionStreamBlockSchema.extend({
|
|
649
|
+
tasks: z
|
|
650
|
+
.record(z.string(), SessionStreamBlockSchema)
|
|
651
|
+
.describe('Per-task stream blocks keyed by task ID.'),
|
|
652
|
+
}).describe(
|
|
653
|
+
'Projection of the full session stream state, including the main stream and per-task sub-streams.'
|
|
654
|
+
);
|
|
655
|
+
export type SessionStreamProjection = z.infer<typeof SessionStreamProjectionSchema>;
|
|
656
|
+
|
|
657
|
+
export const SessionAgentActivitySchema = z
|
|
658
|
+
.object({
|
|
659
|
+
name: z.string().optional().describe('Display name of the agent.'),
|
|
660
|
+
status: z.string().describe('Current agent status (e.g. "idle", "working", "tool_calling").'),
|
|
661
|
+
currentTool: z
|
|
662
|
+
.string()
|
|
663
|
+
.optional()
|
|
664
|
+
.describe('Name of the tool the agent is currently executing, if any.'),
|
|
665
|
+
currentToolArgs: z
|
|
666
|
+
.string()
|
|
667
|
+
.optional()
|
|
668
|
+
.describe('Serialized arguments of the currently executing tool call.'),
|
|
669
|
+
toolCallCount: z
|
|
670
|
+
.number()
|
|
671
|
+
.describe('Total number of tool calls made by this agent in the session.'),
|
|
672
|
+
lastActivity: z.number().describe('Unix timestamp (ms) of the agent last activity.'),
|
|
673
|
+
totalElapsed: z
|
|
674
|
+
.number()
|
|
675
|
+
.optional()
|
|
676
|
+
.describe('Total active time in milliseconds the agent has spent working.'),
|
|
677
|
+
})
|
|
678
|
+
.describe(
|
|
679
|
+
'Real-time activity snapshot of an agent within a session, used for UI status indicators and monitoring.'
|
|
680
|
+
);
|
|
681
|
+
export type SessionAgentActivity = z.infer<typeof SessionAgentActivitySchema>;
|
|
682
|
+
|
|
683
|
+
export const CoderHubHydrationMessageSchema = z
|
|
684
|
+
.object({
|
|
685
|
+
type: z
|
|
686
|
+
.literal('session_hydration')
|
|
687
|
+
.describe('Discriminator indicating this is a session hydration payload.'),
|
|
688
|
+
sessionId: z.string().describe('ID of the session being hydrated.'),
|
|
689
|
+
label: z.string().optional().describe('Human-readable session label, if one was assigned.'),
|
|
690
|
+
resumedAt: z.number().describe('Unix timestamp (ms) when the session was resumed.'),
|
|
691
|
+
entries: z
|
|
692
|
+
.array(ConversationEntrySchema)
|
|
693
|
+
.describe('Historical conversation entries to replay for state reconstruction.'),
|
|
694
|
+
task: z
|
|
695
|
+
.string()
|
|
696
|
+
.optional()
|
|
697
|
+
.describe('Active task prompt at the time of hydration, if work is in progress.'),
|
|
698
|
+
leadConnected: z
|
|
699
|
+
.boolean()
|
|
700
|
+
.optional()
|
|
701
|
+
.describe('Whether a lead client is currently connected to this session.'),
|
|
702
|
+
stream: SessionStreamProjectionSchema.optional().describe(
|
|
703
|
+
'Current stream projection state to restore live-streaming UI.'
|
|
704
|
+
),
|
|
705
|
+
tasks: z
|
|
706
|
+
.array(SessionTaskStateSchema)
|
|
707
|
+
.optional()
|
|
708
|
+
.describe('Active and completed task states to restore the task tracker UI.'),
|
|
709
|
+
streamingState: z
|
|
710
|
+
.object({
|
|
711
|
+
isStreaming: z
|
|
712
|
+
.boolean()
|
|
713
|
+
.optional()
|
|
714
|
+
.describe('Whether the session is actively streaming output right now.'),
|
|
715
|
+
activeTasks: z
|
|
716
|
+
.array(
|
|
717
|
+
z
|
|
718
|
+
.object({
|
|
719
|
+
taskId: z.string().describe('ID of the currently active task.'),
|
|
720
|
+
agent: z.string().describe('Agent executing the task.'),
|
|
721
|
+
})
|
|
722
|
+
.describe('Reference to a task that is currently in progress.')
|
|
723
|
+
)
|
|
724
|
+
.optional()
|
|
725
|
+
.describe('Tasks that are actively being worked on at the time of hydration.'),
|
|
726
|
+
})
|
|
727
|
+
.optional()
|
|
728
|
+
.describe('Snapshot of the streaming and task execution state for UI restoration.'),
|
|
729
|
+
})
|
|
730
|
+
.describe(
|
|
731
|
+
'Server message delivering a full session state snapshot to a newly connected or resumed client for hydration.'
|
|
732
|
+
);
|
|
733
|
+
export type CoderHubHydrationMessage = z.infer<typeof CoderHubHydrationMessageSchema>;
|
|
734
|
+
|
|
735
|
+
export const BootstrapReadyMessageSchema = z
|
|
736
|
+
.object({
|
|
737
|
+
type: z
|
|
738
|
+
.literal('bootstrap_ready')
|
|
739
|
+
.describe('Discriminator indicating the client has finished bootstrapping.'),
|
|
740
|
+
})
|
|
741
|
+
.describe(
|
|
742
|
+
'Client message signaling that initialization is complete and the client is ready to receive session data.'
|
|
743
|
+
);
|
|
744
|
+
export type BootstrapReadyMessage = z.infer<typeof BootstrapReadyMessageSchema>;
|
|
745
|
+
|
|
746
|
+
export const SessionEntryMessageSchema = z
|
|
747
|
+
.object({
|
|
748
|
+
type: z
|
|
749
|
+
.literal('session_entry')
|
|
750
|
+
.describe('Discriminator indicating a single line append to the session file.'),
|
|
751
|
+
path: z.string().describe('Absolute path to the session file being written.'),
|
|
752
|
+
line: z.string().describe('Single JSONL line to append to the session file.'),
|
|
753
|
+
})
|
|
754
|
+
.describe(
|
|
755
|
+
'Client message appending a single JSONL line to the session file for incremental persistence.'
|
|
756
|
+
);
|
|
757
|
+
export type SessionEntryMessage = z.infer<typeof SessionEntryMessageSchema>;
|
|
758
|
+
|
|
759
|
+
export const SessionWriteMessageSchema = z
|
|
760
|
+
.object({
|
|
761
|
+
type: z
|
|
762
|
+
.literal('session_write')
|
|
763
|
+
.describe('Discriminator indicating a full session file write.'),
|
|
764
|
+
path: z.string().describe('Absolute path to the session file to write.'),
|
|
765
|
+
content: z
|
|
766
|
+
.string()
|
|
767
|
+
.describe(
|
|
768
|
+
'Complete content to write to the session file, replacing any existing content.'
|
|
769
|
+
),
|
|
770
|
+
})
|
|
771
|
+
.describe(
|
|
772
|
+
'Client message writing the full content of a session file, used for initial creation or full replacement.'
|
|
773
|
+
);
|
|
774
|
+
export type SessionWriteMessage = z.infer<typeof SessionWriteMessageSchema>;
|
|
775
|
+
|
|
776
|
+
export const SessionParticipantSchema = z
|
|
777
|
+
.object({
|
|
778
|
+
id: z.string().describe('Unique identifier for this participant connection.'),
|
|
779
|
+
role: z
|
|
780
|
+
.enum(['lead', 'observer', 'controller'])
|
|
781
|
+
.describe('Role of the participant determining their permissions in the session.'),
|
|
782
|
+
transport: z
|
|
783
|
+
.enum(['ws', 'sse'])
|
|
784
|
+
.describe(
|
|
785
|
+
'Transport protocol used by this participant (WebSocket or Server-Sent Events).'
|
|
786
|
+
),
|
|
787
|
+
subscriptions: z
|
|
788
|
+
.array(z.string())
|
|
789
|
+
.describe('Event categories this participant is subscribed to.'),
|
|
790
|
+
connectedAt: z.number().describe('Unix timestamp (ms) when this participant connected.'),
|
|
791
|
+
lastActivity: z.number().describe('Unix timestamp (ms) of the participant last activity.'),
|
|
792
|
+
metadata: z
|
|
793
|
+
.record(z.string(), z.unknown())
|
|
794
|
+
.optional()
|
|
795
|
+
.describe(
|
|
796
|
+
'Arbitrary metadata attached to this participant (e.g. client version, origin).'
|
|
797
|
+
),
|
|
798
|
+
})
|
|
799
|
+
.describe(
|
|
800
|
+
'Represents a connected participant in a session with their role, transport, and activity state.'
|
|
801
|
+
);
|
|
802
|
+
export type SessionParticipant = z.infer<typeof SessionParticipantSchema>;
|
|
803
|
+
|
|
804
|
+
export const PresenceEventMessageSchema = z
|
|
805
|
+
.object({
|
|
806
|
+
type: z.literal('presence').describe('Discriminator indicating a presence change event.'),
|
|
807
|
+
event: z
|
|
808
|
+
.enum(['session_join', 'session_leave', 'presence_update'])
|
|
809
|
+
.describe('Specific presence event type that occurred.'),
|
|
810
|
+
participant: SessionParticipantSchema.optional().describe(
|
|
811
|
+
'The participant that triggered the event (for join/leave).'
|
|
812
|
+
),
|
|
813
|
+
participants: z
|
|
814
|
+
.array(SessionParticipantSchema)
|
|
815
|
+
.optional()
|
|
816
|
+
.describe('Full list of current participants (sent with presence_update).'),
|
|
817
|
+
sessionId: z.string().describe('Session ID where the presence event occurred.'),
|
|
818
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the event occurred.'),
|
|
819
|
+
})
|
|
820
|
+
.describe(
|
|
821
|
+
'Server message notifying clients of participant join, leave, or presence state changes in the session.'
|
|
822
|
+
);
|
|
823
|
+
export type PresenceEventMessage = z.infer<typeof PresenceEventMessageSchema>;
|
|
824
|
+
|
|
825
|
+
export const BroadcastEventMessageSchema = z
|
|
826
|
+
.object({
|
|
827
|
+
type: z
|
|
828
|
+
.literal('broadcast')
|
|
829
|
+
.describe('Discriminator indicating a broadcast event to all session participants.'),
|
|
830
|
+
event: z
|
|
831
|
+
.string()
|
|
832
|
+
.describe('Event name identifying the broadcast type (e.g. "agent_activity").'),
|
|
833
|
+
data: z.record(z.string(), z.unknown()).describe('Event-specific payload data.'),
|
|
834
|
+
category: z
|
|
835
|
+
.string()
|
|
836
|
+
.describe('Category for filtering broadcasts (e.g. "session", "agent", "runtime").'),
|
|
837
|
+
sessionId: z.string().describe('Session ID this broadcast belongs to.'),
|
|
838
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the broadcast was emitted.'),
|
|
839
|
+
})
|
|
840
|
+
.describe(
|
|
841
|
+
'Server message broadcasting a named event with arbitrary data to all connected session participants.'
|
|
842
|
+
);
|
|
843
|
+
export type BroadcastEventMessage = z.infer<typeof BroadcastEventMessageSchema>;
|
|
844
|
+
|
|
845
|
+
export const RpcCommandMessageSchema = z
|
|
846
|
+
.object({
|
|
847
|
+
type: z
|
|
848
|
+
.literal('rpc_command')
|
|
849
|
+
.describe('Discriminator indicating an RPC command from the client.'),
|
|
850
|
+
command: z
|
|
851
|
+
.record(z.string(), z.unknown())
|
|
852
|
+
.describe('RPC command payload to execute on the server.'),
|
|
853
|
+
})
|
|
854
|
+
.describe('Client message sending an RPC command to the server for execution by the driver.');
|
|
855
|
+
export type RpcCommandMessage = z.infer<typeof RpcCommandMessageSchema>;
|
|
856
|
+
|
|
857
|
+
export const RpcEventMessageSchema = z
|
|
858
|
+
.object({
|
|
859
|
+
type: z
|
|
860
|
+
.literal('rpc_event')
|
|
861
|
+
.describe('Discriminator indicating an RPC event from the server.'),
|
|
862
|
+
event: z.record(z.string(), z.unknown()).describe('RPC event payload.'),
|
|
863
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the event was emitted.'),
|
|
864
|
+
})
|
|
865
|
+
.describe(
|
|
866
|
+
'Server message delivering an RPC event notification from the driver to connected clients.'
|
|
867
|
+
);
|
|
868
|
+
export type RpcEventMessage = z.infer<typeof RpcEventMessageSchema>;
|
|
869
|
+
|
|
870
|
+
export const RpcResponseMessageSchema = z
|
|
871
|
+
.object({
|
|
872
|
+
type: z
|
|
873
|
+
.literal('rpc_response')
|
|
874
|
+
.describe('Discriminator indicating an RPC response from the server.'),
|
|
875
|
+
response: z.record(z.string(), z.unknown()).describe('RPC response payload from the driver.'),
|
|
876
|
+
})
|
|
877
|
+
.describe('Server message returning the result of a previously sent RPC command.');
|
|
878
|
+
export type RpcResponseMessage = z.infer<typeof RpcResponseMessageSchema>;
|
|
879
|
+
|
|
880
|
+
export const RpcUiRequestMessageSchema = z
|
|
881
|
+
.object({
|
|
882
|
+
type: z
|
|
883
|
+
.literal('rpc_ui_request')
|
|
884
|
+
.describe('Discriminator indicating a UI interaction request from the server.'),
|
|
885
|
+
id: z.string().describe('Request ID for correlating the UI response.'),
|
|
886
|
+
method: z.string().describe('UI method to invoke (e.g. "confirm_dialog", "select_option").'),
|
|
887
|
+
params: z
|
|
888
|
+
.record(z.string(), z.unknown())
|
|
889
|
+
.describe('Method-specific parameters for the UI request.'),
|
|
890
|
+
})
|
|
891
|
+
.describe(
|
|
892
|
+
'Server message requesting the client UI to perform an interactive action and return a response.'
|
|
893
|
+
);
|
|
894
|
+
export type RpcUiRequestMessage = z.infer<typeof RpcUiRequestMessageSchema>;
|
|
895
|
+
|
|
896
|
+
export const RpcUiResponseMessageSchema = z
|
|
897
|
+
.object({
|
|
898
|
+
type: z
|
|
899
|
+
.literal('rpc_ui_response')
|
|
900
|
+
.describe('Discriminator indicating a client response to a UI request.'),
|
|
901
|
+
id: z.string().describe('Request ID this response correlates to.'),
|
|
902
|
+
result: z.unknown().describe('Result of the UI interaction provided by the user.'),
|
|
903
|
+
})
|
|
904
|
+
.describe('Client message returning the result of a server-initiated UI interaction request.');
|
|
905
|
+
export type RpcUiResponseMessage = z.infer<typeof RpcUiResponseMessageSchema>;
|
|
906
|
+
|
|
907
|
+
export const PingMessageSchema = z
|
|
908
|
+
.object({
|
|
909
|
+
type: z.literal('ping').describe('Discriminator indicating a keep-alive ping.'),
|
|
910
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the ping was sent.'),
|
|
911
|
+
})
|
|
912
|
+
.describe('Client message used for connection keep-alive and latency measurement.');
|
|
913
|
+
export type PingMessage = z.infer<typeof PingMessageSchema>;
|
|
914
|
+
|
|
915
|
+
export const PongMessageSchema = z
|
|
916
|
+
.object({
|
|
917
|
+
type: z.literal('pong').describe('Discriminator indicating a keep-alive pong reply.'),
|
|
918
|
+
timestamp: z.number().describe('Unix timestamp (ms) when the pong was sent.'),
|
|
919
|
+
echoedTimestamp: z
|
|
920
|
+
.number()
|
|
921
|
+
.optional()
|
|
922
|
+
.describe('Original ping timestamp echoed back for round-trip latency calculation.'),
|
|
923
|
+
})
|
|
924
|
+
.describe('Server response to a ping message, used for keep-alive and latency measurement.');
|
|
925
|
+
export type PongMessage = z.infer<typeof PongMessageSchema>;
|
|
926
|
+
|
|
927
|
+
export const EventRequestSchema = z
|
|
928
|
+
.object({
|
|
929
|
+
id: z.string().describe('Unique request ID for correlating the server response.'),
|
|
930
|
+
type: z.literal('event').describe('Discriminator indicating this is an event request.'),
|
|
931
|
+
event: z
|
|
932
|
+
.string()
|
|
933
|
+
.describe('Name of the event being reported (e.g. "tool_start", "task_complete").'),
|
|
934
|
+
data: z.record(z.string(), z.unknown()).describe('Event-specific payload data.'),
|
|
935
|
+
})
|
|
936
|
+
.describe('Client message reporting a named event with associated data to the hub.');
|
|
937
|
+
export type EventRequest = z.infer<typeof EventRequestSchema>;
|
|
938
|
+
|
|
939
|
+
export const ToolRequestSchema = z
|
|
940
|
+
.object({
|
|
941
|
+
id: z.string().describe('Unique request ID for correlating the server response.'),
|
|
942
|
+
type: z
|
|
943
|
+
.literal('tool')
|
|
944
|
+
.describe('Discriminator indicating this is a tool invocation request.'),
|
|
945
|
+
name: z.string().describe('Name of the hub tool to invoke.'),
|
|
946
|
+
toolCallId: z
|
|
947
|
+
.string()
|
|
948
|
+
.describe('Tool call ID from the LLM, used to route the result back to the correct call.'),
|
|
949
|
+
params: z
|
|
950
|
+
.record(z.string(), z.unknown())
|
|
951
|
+
.describe('Input parameters for the tool invocation.'),
|
|
952
|
+
})
|
|
953
|
+
.describe('Client message requesting the hub to execute a named tool and return the result.');
|
|
954
|
+
export type ToolRequest = z.infer<typeof ToolRequestSchema>;
|
|
955
|
+
|
|
956
|
+
export const CommandRequestSchema = z
|
|
957
|
+
.object({
|
|
958
|
+
id: z.string().describe('Unique request ID for correlating the server response.'),
|
|
959
|
+
type: z
|
|
960
|
+
.literal('command')
|
|
961
|
+
.describe('Discriminator indicating this is a command execution request.'),
|
|
962
|
+
name: z.string().describe('Name of the slash-command to execute.'),
|
|
963
|
+
args: z.string().describe('Raw argument string passed after the command name.'),
|
|
964
|
+
})
|
|
965
|
+
.describe('Client message requesting the hub to execute a registered slash-command.');
|
|
966
|
+
export type CommandRequest = z.infer<typeof CommandRequestSchema>;
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* All possible client-to-server message types.
|
|
970
|
+
*
|
|
971
|
+
* Messages the client can send to the Coder Hub server.
|
|
972
|
+
*/
|
|
973
|
+
export const ClientMessageSchema = z
|
|
974
|
+
.discriminatedUnion('type', [
|
|
975
|
+
EventRequestSchema,
|
|
976
|
+
ToolRequestSchema,
|
|
977
|
+
CommandRequestSchema,
|
|
978
|
+
SessionEntryMessageSchema,
|
|
979
|
+
SessionWriteMessageSchema,
|
|
980
|
+
BootstrapReadyMessageSchema,
|
|
981
|
+
RpcCommandMessageSchema,
|
|
982
|
+
RpcUiResponseMessageSchema,
|
|
983
|
+
PingMessageSchema,
|
|
984
|
+
])
|
|
985
|
+
.describe(
|
|
986
|
+
'Union of all client-to-server messages, discriminated by type. Includes tool/event/command requests, session persistence, RPC, and keep-alive.'
|
|
987
|
+
);
|
|
988
|
+
export type ClientMessage = z.infer<typeof ClientMessageSchema>;
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* All possible server-to-client message types.
|
|
992
|
+
*
|
|
993
|
+
* Messages the Coder Hub server can send to connected clients.
|
|
994
|
+
*/
|
|
995
|
+
export const ServerMessageSchema = z
|
|
996
|
+
.discriminatedUnion('type', [
|
|
997
|
+
CoderHubInitMessageSchema,
|
|
998
|
+
CoderHubResponseSchema,
|
|
999
|
+
CoderHubHydrationMessageSchema,
|
|
1000
|
+
CoderHubStreamReadyMessageSchema,
|
|
1001
|
+
CoderHubSessionResumeMessageSchema,
|
|
1002
|
+
PongMessageSchema,
|
|
1003
|
+
ConnectionRejectedMessageSchema,
|
|
1004
|
+
ProtocolErrorMessageSchema,
|
|
1005
|
+
PresenceEventMessageSchema,
|
|
1006
|
+
BroadcastEventMessageSchema,
|
|
1007
|
+
RpcEventMessageSchema,
|
|
1008
|
+
RpcResponseMessageSchema,
|
|
1009
|
+
RpcUiRequestMessageSchema,
|
|
1010
|
+
])
|
|
1011
|
+
.describe(
|
|
1012
|
+
'Union of all server-to-client messages, discriminated by type. Includes init, responses, hydration, stream control, presence, broadcasts, RPC, and errors.'
|
|
1013
|
+
);
|
|
1014
|
+
export type ServerMessage = z.infer<typeof ServerMessageSchema>;
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* Initial session snapshot sent via SSE after connection.
|
|
1018
|
+
*
|
|
1019
|
+
* Contains the current session state, participants, and agent activity.
|
|
1020
|
+
*/
|
|
1021
|
+
export const SseSessionSnapshotMessageSchema = z
|
|
1022
|
+
.object({
|
|
1023
|
+
type: z.literal('snapshot').describe('Discriminator indicating this is a session snapshot.'),
|
|
1024
|
+
sessionId: z.string().describe('ID of the session this snapshot represents.'),
|
|
1025
|
+
label: z.string().describe('Human-readable label for the session.'),
|
|
1026
|
+
status: z
|
|
1027
|
+
.string()
|
|
1028
|
+
.describe('Current session lifecycle status (e.g. "active", "idle", "ended").'),
|
|
1029
|
+
createdAt: z.string().describe('ISO 8601 timestamp when the session was created.'),
|
|
1030
|
+
mode: z
|
|
1031
|
+
.enum(['sandbox', 'tui'])
|
|
1032
|
+
.describe('Execution environment mode: cloud sandbox or local TUI.'),
|
|
1033
|
+
participants: z
|
|
1034
|
+
.array(
|
|
1035
|
+
z
|
|
1036
|
+
.object({
|
|
1037
|
+
id: z.string().describe('Unique participant connection ID.'),
|
|
1038
|
+
role: z.string().describe('Participant role in the session.'),
|
|
1039
|
+
transport: z.string().describe('Transport protocol (ws or sse).'),
|
|
1040
|
+
connectedAt: z
|
|
1041
|
+
.string()
|
|
1042
|
+
.describe('ISO 8601 timestamp when the participant connected.'),
|
|
1043
|
+
idle: z
|
|
1044
|
+
.boolean()
|
|
1045
|
+
.optional()
|
|
1046
|
+
.describe('Whether the participant is currently idle.'),
|
|
1047
|
+
})
|
|
1048
|
+
.describe('Summary of a connected participant for the snapshot.')
|
|
1049
|
+
)
|
|
1050
|
+
.describe('List of all currently connected participants.'),
|
|
1051
|
+
taskCount: z.number().describe('Total number of tasks created in this session.'),
|
|
1052
|
+
agentActivity: z
|
|
1053
|
+
.record(z.string(), SessionAgentActivitySchema)
|
|
1054
|
+
.describe('Per-agent activity state keyed by agent name.'),
|
|
1055
|
+
stream: SessionStreamProjectionSchema.optional().describe(
|
|
1056
|
+
'Current stream projection if the session is actively streaming.'
|
|
1057
|
+
),
|
|
1058
|
+
})
|
|
1059
|
+
.describe(
|
|
1060
|
+
'Full point-in-time snapshot of the session state, sent to SSE observers on initial connection.'
|
|
1061
|
+
);
|
|
1062
|
+
export type SseSessionSnapshotMessage = z.infer<typeof SseSessionSnapshotMessageSchema>;
|
|
1063
|
+
|
|
1064
|
+
export const SseHydrationMessageSchema = z
|
|
1065
|
+
.object({
|
|
1066
|
+
type: z
|
|
1067
|
+
.literal('hydration')
|
|
1068
|
+
.describe('Discriminator indicating this is an SSE hydration payload.'),
|
|
1069
|
+
sessionId: z.string().describe('ID of the session being hydrated.'),
|
|
1070
|
+
entries: z
|
|
1071
|
+
.array(ConversationEntrySchema)
|
|
1072
|
+
.describe('Historical conversation entries for state reconstruction.'),
|
|
1073
|
+
task: z.string().optional().describe('Currently active task prompt, if work is in progress.'),
|
|
1074
|
+
stream: SessionStreamProjectionSchema.optional().describe('Current stream projection state.'),
|
|
1075
|
+
tasks: z
|
|
1076
|
+
.array(SessionTaskStateSchema)
|
|
1077
|
+
.optional()
|
|
1078
|
+
.describe('Active and completed task states.'),
|
|
1079
|
+
})
|
|
1080
|
+
.describe(
|
|
1081
|
+
'SSE-specific hydration message delivering conversation history and session state to an observer client.'
|
|
1082
|
+
);
|
|
1083
|
+
export type SseHydrationMessage = z.infer<typeof SseHydrationMessageSchema>;
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* All possible SSE message types sent to observers.
|
|
1087
|
+
*
|
|
1088
|
+
* SSE connections receive a subset of server messages suitable for
|
|
1089
|
+
* read-only observation (snapshots, broadcasts, presence).
|
|
1090
|
+
*/
|
|
1091
|
+
export const ObserverSseMessageSchema = z
|
|
1092
|
+
.discriminatedUnion('type', [
|
|
1093
|
+
SseSessionSnapshotMessageSchema,
|
|
1094
|
+
SseHydrationMessageSchema,
|
|
1095
|
+
PresenceEventMessageSchema,
|
|
1096
|
+
BroadcastEventMessageSchema,
|
|
1097
|
+
])
|
|
1098
|
+
.describe(
|
|
1099
|
+
'Union of all SSE observer messages, discriminated by type. Observers receive snapshots, hydration, presence, and broadcast events.'
|
|
1100
|
+
);
|
|
1101
|
+
export type ObserverSseMessage = z.infer<typeof ObserverSseMessageSchema>;
|
|
1102
|
+
|
|
1103
|
+
export const ConnectionParamsSchema = z
|
|
1104
|
+
.object({
|
|
1105
|
+
agent: z
|
|
1106
|
+
.string()
|
|
1107
|
+
.optional()
|
|
1108
|
+
.describe('Agent name this connection represents, for agent-specific connections.'),
|
|
1109
|
+
parent: z
|
|
1110
|
+
.string()
|
|
1111
|
+
.optional()
|
|
1112
|
+
.describe('Parent session ID for hierarchical session relationships.'),
|
|
1113
|
+
sessionId: z
|
|
1114
|
+
.string()
|
|
1115
|
+
.optional()
|
|
1116
|
+
.describe('Existing session ID to join; omit to create a new session.'),
|
|
1117
|
+
task: z
|
|
1118
|
+
.string()
|
|
1119
|
+
.optional()
|
|
1120
|
+
.describe('Initial task prompt to begin immediately after connecting.'),
|
|
1121
|
+
label: z.string().optional().describe('Human-readable label to assign to the new session.'),
|
|
1122
|
+
orgId: z.string().optional().describe('Organization ID for multi-tenant session scoping.'),
|
|
1123
|
+
userId: z.string().optional().describe('Authenticated user ID initiating the connection.'),
|
|
1124
|
+
origin: z
|
|
1125
|
+
.enum(['web', 'desktop', 'tui', 'sdk'])
|
|
1126
|
+
.optional()
|
|
1127
|
+
.describe('Client origin platform indicating where the connection originates from.'),
|
|
1128
|
+
role: z
|
|
1129
|
+
.enum(['lead', 'observer', 'controller'])
|
|
1130
|
+
.optional()
|
|
1131
|
+
.describe('Requested session role; the server may override based on permissions.'),
|
|
1132
|
+
coordJobId: z
|
|
1133
|
+
.string()
|
|
1134
|
+
.optional()
|
|
1135
|
+
.describe('Coordination job ID linking this connection to an orchestration workflow.'),
|
|
1136
|
+
coordRole: z
|
|
1137
|
+
.string()
|
|
1138
|
+
.optional()
|
|
1139
|
+
.describe('Role within the coordination job (e.g. "worker", "orchestrator").'),
|
|
1140
|
+
driverMode: z
|
|
1141
|
+
.enum(['rpc'])
|
|
1142
|
+
.optional()
|
|
1143
|
+
.describe(
|
|
1144
|
+
'Driver communication mode; "rpc" enables RPC-based interaction instead of standard messaging.'
|
|
1145
|
+
),
|
|
1146
|
+
driverInstanceId: z
|
|
1147
|
+
.string()
|
|
1148
|
+
.optional()
|
|
1149
|
+
.describe('Unique identifier of the driver instance for RPC routing.'),
|
|
1150
|
+
driverVersion: z
|
|
1151
|
+
.string()
|
|
1152
|
+
.optional()
|
|
1153
|
+
.describe('Semantic version of the driver for protocol compatibility negotiation.'),
|
|
1154
|
+
})
|
|
1155
|
+
.describe(
|
|
1156
|
+
'Query parameters provided during WebSocket or SSE connection handshake, controlling session creation, joining, and client identity.'
|
|
1157
|
+
);
|
|
1158
|
+
export type ConnectionParams = z.infer<typeof ConnectionParamsSchema>;
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Parse unknown data as a server message.
|
|
1162
|
+
*
|
|
1163
|
+
* @param data - The raw data to parse (typically from JSON.parse)
|
|
1164
|
+
* @returns The parsed server message, or null if invalid
|
|
1165
|
+
*
|
|
1166
|
+
* @example
|
|
1167
|
+
* ```typescript
|
|
1168
|
+
* const raw = JSON.parse(event.data);
|
|
1169
|
+
* const message = parseServerMessage(raw);
|
|
1170
|
+
* if (message?.type === 'init') {
|
|
1171
|
+
* console.log('Connected to session:', message.sessionId);
|
|
1172
|
+
* }
|
|
1173
|
+
* ```
|
|
1174
|
+
*/
|
|
1175
|
+
export function parseServerMessage(data: unknown): ServerMessage | null {
|
|
1176
|
+
const result = ServerMessageSchema.safeParse(data);
|
|
1177
|
+
return result.success ? result.data : null;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
/**
|
|
1181
|
+
* Parse unknown data as a client message.
|
|
1182
|
+
*
|
|
1183
|
+
* @param data - The raw data to parse (typically from JSON.parse)
|
|
1184
|
+
* @returns The parsed client message, or null if invalid
|
|
1185
|
+
*/
|
|
1186
|
+
export function parseClientMessage(data: unknown): ClientMessage | null {
|
|
1187
|
+
const result = ClientMessageSchema.safeParse(data);
|
|
1188
|
+
return result.success ? result.data : null;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Parse unknown data as an SSE observer message.
|
|
1193
|
+
*
|
|
1194
|
+
* @param data - The raw data to parse (typically from SSE event data)
|
|
1195
|
+
* @returns The parsed SSE message, or null if invalid
|
|
1196
|
+
*/
|
|
1197
|
+
export function parseObserverSseMessage(data: unknown): ObserverSseMessage | null {
|
|
1198
|
+
const result = ObserverSseMessageSchema.safeParse(data);
|
|
1199
|
+
return result.success ? result.data : null;
|
|
1200
|
+
}
|