agent-relay 2.0.33 → 2.0.35

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 (67) hide show
  1. package/README.md +44 -0
  2. package/dist/index.cjs +10323 -15012
  3. package/package.json +26 -19
  4. package/packages/api-types/.trajectories/active/traj_xbsvuzogscey.json +15 -0
  5. package/packages/api-types/.trajectories/index.json +12 -0
  6. package/packages/api-types/package.json +1 -1
  7. package/packages/benchmark/package.json +4 -4
  8. package/packages/bridge/dist/spawner.d.ts.map +1 -1
  9. package/packages/bridge/dist/spawner.js +127 -0
  10. package/packages/bridge/dist/spawner.js.map +1 -1
  11. package/packages/bridge/package.json +8 -8
  12. package/packages/bridge/src/spawner.ts +137 -0
  13. package/packages/cli-tester/package.json +1 -1
  14. package/packages/config/package.json +2 -2
  15. package/packages/continuity/package.json +1 -1
  16. package/packages/daemon/package.json +12 -12
  17. package/packages/hooks/package.json +4 -4
  18. package/packages/mcp/package.json +3 -3
  19. package/packages/memory/package.json +2 -2
  20. package/packages/policy/package.json +2 -2
  21. package/packages/protocol/package.json +1 -1
  22. package/packages/resiliency/package.json +1 -1
  23. package/packages/sdk/package.json +2 -2
  24. package/packages/spawner/package.json +1 -1
  25. package/packages/state/package.json +1 -1
  26. package/packages/storage/package.json +2 -2
  27. package/packages/telemetry/package.json +1 -1
  28. package/packages/trajectory/package.json +2 -2
  29. package/packages/user-directory/package.json +2 -2
  30. package/packages/utils/package.json +2 -2
  31. package/packages/wrapper/dist/base-wrapper.d.ts.map +1 -1
  32. package/packages/wrapper/dist/base-wrapper.js +27 -7
  33. package/packages/wrapper/dist/base-wrapper.js.map +1 -1
  34. package/packages/wrapper/dist/client.d.ts +27 -0
  35. package/packages/wrapper/dist/client.d.ts.map +1 -1
  36. package/packages/wrapper/dist/client.js +116 -0
  37. package/packages/wrapper/dist/client.js.map +1 -1
  38. package/packages/wrapper/dist/index.d.ts +3 -0
  39. package/packages/wrapper/dist/index.d.ts.map +1 -1
  40. package/packages/wrapper/dist/index.js +6 -0
  41. package/packages/wrapper/dist/index.js.map +1 -1
  42. package/packages/wrapper/dist/opencode-api.d.ts +106 -0
  43. package/packages/wrapper/dist/opencode-api.d.ts.map +1 -0
  44. package/packages/wrapper/dist/opencode-api.js +219 -0
  45. package/packages/wrapper/dist/opencode-api.js.map +1 -0
  46. package/packages/wrapper/dist/opencode-wrapper.d.ts +157 -0
  47. package/packages/wrapper/dist/opencode-wrapper.d.ts.map +1 -0
  48. package/packages/wrapper/dist/opencode-wrapper.js +414 -0
  49. package/packages/wrapper/dist/opencode-wrapper.js.map +1 -0
  50. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts.map +1 -1
  51. package/packages/wrapper/dist/relay-pty-orchestrator.js +18 -0
  52. package/packages/wrapper/dist/relay-pty-orchestrator.js.map +1 -1
  53. package/packages/wrapper/dist/wrapper-events.d.ts +489 -0
  54. package/packages/wrapper/dist/wrapper-events.d.ts.map +1 -0
  55. package/packages/wrapper/dist/wrapper-events.js +252 -0
  56. package/packages/wrapper/dist/wrapper-events.js.map +1 -0
  57. package/packages/wrapper/package.json +7 -6
  58. package/packages/wrapper/src/base-wrapper.ts +23 -7
  59. package/packages/wrapper/src/client.test.ts +92 -3
  60. package/packages/wrapper/src/client.ts +163 -0
  61. package/packages/wrapper/src/index.ts +29 -0
  62. package/packages/wrapper/src/opencode-api.test.ts +292 -0
  63. package/packages/wrapper/src/opencode-api.ts +285 -0
  64. package/packages/wrapper/src/opencode-wrapper.ts +513 -0
  65. package/packages/wrapper/src/relay-pty-orchestrator.test.ts +176 -0
  66. package/packages/wrapper/src/relay-pty-orchestrator.ts +20 -0
  67. package/packages/wrapper/src/wrapper-events.ts +395 -0
@@ -57,6 +57,13 @@ import {
57
57
 
58
58
  const MAX_SOCKET_PATH_LENGTH = 107;
59
59
 
60
+ /**
61
+ * Maximum size for output buffers (rawBuffer, outputBuffer) in bytes.
62
+ * Prevents RangeError: Invalid string length when agents produce lots of output.
63
+ * Set to 10MB - enough to capture context but won't exhaust memory.
64
+ */
65
+ const MAX_OUTPUT_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB
66
+
60
67
  function hashWorkspaceId(workspaceId: string): string {
61
68
  return createHash('sha256').update(workspaceId).digest('hex').slice(0, 12);
62
69
  }
@@ -956,6 +963,19 @@ export class RelayPtyOrchestrator extends BaseWrapper {
956
963
  this.outputBuffer += data;
957
964
  this.hasReceivedOutput = true;
958
965
 
966
+ // Trim buffers if they exceed max size to prevent RangeError: Invalid string length
967
+ // Keep the most recent output (tail) as it's more relevant for pattern matching
968
+ if (this.rawBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
969
+ const trimAmount = this.rawBuffer.length - MAX_OUTPUT_BUFFER_SIZE;
970
+ this.rawBuffer = this.rawBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
971
+ // Adjust lastParsedLength to stay in sync with the trimmed buffer
972
+ // This ensures parseRelayCommands() doesn't skip content or re-parse old content
973
+ this.lastParsedLength = Math.max(0, this.lastParsedLength - trimAmount);
974
+ }
975
+ if (this.outputBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
976
+ this.outputBuffer = this.outputBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
977
+ }
978
+
959
979
  // Feed to idle detector
960
980
  this.feedIdleDetectorOutput(data);
961
981
 
@@ -0,0 +1,395 @@
1
+ /**
2
+ * Typed Event Definitions for Agent Relay Wrapper
3
+ *
4
+ * Inspired by opencode's BusEvent pattern, this provides type-safe event
5
+ * definitions with Zod schema validation. Events can be used for:
6
+ * - Wrapper internal notifications
7
+ * - SDK client subscriptions
8
+ * - OpenAPI spec generation
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { RelayEvent, emitEvent, onEvent } from './wrapper-events.js';
13
+ *
14
+ * // Subscribe to events
15
+ * onEvent(RelayEvent.AgentConnected, (event) => {
16
+ * console.log(`Agent ${event.properties.agentName} connected`);
17
+ * });
18
+ *
19
+ * // Emit events
20
+ * emitEvent(RelayEvent.AgentConnected, {
21
+ * agentName: 'MyAgent',
22
+ * connectionId: 'abc123',
23
+ * });
24
+ * ```
25
+ */
26
+
27
+ import { z } from 'zod';
28
+ import { EventEmitter } from 'node:events';
29
+
30
+ // =========================================================================
31
+ // Event Definition Factory
32
+ // =========================================================================
33
+
34
+ /**
35
+ * Event definition with type and schema
36
+ */
37
+ export interface EventDefinition<
38
+ Type extends string = string,
39
+ Schema extends z.ZodType = z.ZodType
40
+ > {
41
+ type: Type;
42
+ schema: Schema;
43
+ }
44
+
45
+ /**
46
+ * Define a typed event with Zod schema validation
47
+ */
48
+ export function defineEvent<Type extends string, Schema extends z.ZodType>(
49
+ type: Type,
50
+ schema: Schema
51
+ ): EventDefinition<Type, Schema> {
52
+ return { type, schema };
53
+ }
54
+
55
+ /**
56
+ * Infer the properties type from an event definition
57
+ */
58
+ export type EventProperties<E extends EventDefinition> = z.infer<E['schema']>;
59
+
60
+ /**
61
+ * Event payload with type and properties
62
+ */
63
+ export interface EventPayload<E extends EventDefinition = EventDefinition> {
64
+ type: E['type'];
65
+ properties: EventProperties<E>;
66
+ timestamp: number;
67
+ }
68
+
69
+ // =========================================================================
70
+ // Daemon Event Definitions
71
+ // =========================================================================
72
+
73
+ export namespace RelayEvent {
74
+ // --- Agent Lifecycle Events ---
75
+
76
+ export const AgentConnected = defineEvent(
77
+ 'daemon.agent.connected',
78
+ z.object({
79
+ agentName: z.string(),
80
+ connectionId: z.string(),
81
+ cli: z.string().optional(),
82
+ task: z.string().optional(),
83
+ workingDirectory: z.string().optional(),
84
+ })
85
+ );
86
+
87
+ export const AgentDisconnected = defineEvent(
88
+ 'daemon.agent.disconnected',
89
+ z.object({
90
+ agentName: z.string(),
91
+ connectionId: z.string(),
92
+ reason: z.enum(['clean', 'error', 'timeout', 'replaced']).optional(),
93
+ })
94
+ );
95
+
96
+ export const AgentSpawned = defineEvent(
97
+ 'daemon.agent.spawned',
98
+ z.object({
99
+ agentName: z.string(),
100
+ parentAgent: z.string(),
101
+ cli: z.string(),
102
+ task: z.string(),
103
+ })
104
+ );
105
+
106
+ export const AgentReleased = defineEvent(
107
+ 'daemon.agent.released',
108
+ z.object({
109
+ agentName: z.string(),
110
+ releasedBy: z.string(),
111
+ })
112
+ );
113
+
114
+ // --- Message Events ---
115
+
116
+ export const MessageRouted = defineEvent(
117
+ 'daemon.message.routed',
118
+ z.object({
119
+ messageId: z.string(),
120
+ from: z.string(),
121
+ to: z.string(),
122
+ kind: z.string().optional(),
123
+ bodyPreview: z.string().optional(),
124
+ })
125
+ );
126
+
127
+ export const MessageDelivered = defineEvent(
128
+ 'daemon.message.delivered',
129
+ z.object({
130
+ messageId: z.string(),
131
+ to: z.string(),
132
+ deliverySeq: z.number(),
133
+ })
134
+ );
135
+
136
+ export const MessageFailed = defineEvent(
137
+ 'daemon.message.failed',
138
+ z.object({
139
+ messageId: z.string(),
140
+ to: z.string(),
141
+ error: z.string(),
142
+ })
143
+ );
144
+
145
+ // --- Channel Events ---
146
+
147
+ export const ChannelJoined = defineEvent(
148
+ 'daemon.channel.joined',
149
+ z.object({
150
+ channel: z.string(),
151
+ member: z.string(),
152
+ })
153
+ );
154
+
155
+ export const ChannelLeft = defineEvent(
156
+ 'daemon.channel.left',
157
+ z.object({
158
+ channel: z.string(),
159
+ member: z.string(),
160
+ })
161
+ );
162
+
163
+ export const ChannelMessage = defineEvent(
164
+ 'daemon.channel.message',
165
+ z.object({
166
+ channel: z.string(),
167
+ from: z.string(),
168
+ bodyPreview: z.string().optional(),
169
+ })
170
+ );
171
+
172
+ // --- Processing State Events ---
173
+
174
+ export const AgentProcessingStarted = defineEvent(
175
+ 'daemon.agent.processing.started',
176
+ z.object({
177
+ agentName: z.string(),
178
+ messageId: z.string(),
179
+ })
180
+ );
181
+
182
+ export const AgentProcessingEnded = defineEvent(
183
+ 'daemon.agent.processing.ended',
184
+ z.object({
185
+ agentName: z.string(),
186
+ durationMs: z.number().optional(),
187
+ })
188
+ );
189
+
190
+ // --- Shadow Events ---
191
+
192
+ export const ShadowBound = defineEvent(
193
+ 'daemon.shadow.bound',
194
+ z.object({
195
+ shadowAgent: z.string(),
196
+ primaryAgent: z.string(),
197
+ speakOn: z.array(z.string()),
198
+ })
199
+ );
200
+
201
+ export const ShadowUnbound = defineEvent(
202
+ 'daemon.shadow.unbound',
203
+ z.object({
204
+ shadowAgent: z.string(),
205
+ primaryAgent: z.string(),
206
+ })
207
+ );
208
+
209
+ // --- System Events ---
210
+
211
+ export const DaemonStarted = defineEvent(
212
+ 'daemon.system.started',
213
+ z.object({
214
+ socketPath: z.string(),
215
+ version: z.string().optional(),
216
+ })
217
+ );
218
+
219
+ export const DaemonStopped = defineEvent(
220
+ 'daemon.system.stopped',
221
+ z.object({
222
+ reason: z.string().optional(),
223
+ })
224
+ );
225
+
226
+ export const RateLimitExceeded = defineEvent(
227
+ 'daemon.system.rate_limit_exceeded',
228
+ z.object({
229
+ agentName: z.string(),
230
+ })
231
+ );
232
+
233
+ // --- All event definitions for iteration ---
234
+
235
+ export const all = [
236
+ AgentConnected,
237
+ AgentDisconnected,
238
+ AgentSpawned,
239
+ AgentReleased,
240
+ MessageRouted,
241
+ MessageDelivered,
242
+ MessageFailed,
243
+ ChannelJoined,
244
+ ChannelLeft,
245
+ ChannelMessage,
246
+ AgentProcessingStarted,
247
+ AgentProcessingEnded,
248
+ ShadowBound,
249
+ ShadowUnbound,
250
+ DaemonStarted,
251
+ DaemonStopped,
252
+ RateLimitExceeded,
253
+ ] as const;
254
+ }
255
+
256
+ // =========================================================================
257
+ // Event Bus
258
+ // =========================================================================
259
+
260
+ /**
261
+ * Type-safe event bus for daemon events
262
+ */
263
+ class RelayEventBus extends EventEmitter {
264
+ private static instance: RelayEventBus;
265
+
266
+ private constructor() {
267
+ super();
268
+ this.setMaxListeners(100); // Allow many subscribers
269
+ }
270
+
271
+ static getInstance(): RelayEventBus {
272
+ if (!RelayEventBus.instance) {
273
+ RelayEventBus.instance = new RelayEventBus();
274
+ }
275
+ return RelayEventBus.instance;
276
+ }
277
+
278
+ /**
279
+ * Emit a typed event
280
+ */
281
+ emitEvent<E extends EventDefinition>(
282
+ definition: E,
283
+ properties: EventProperties<E>
284
+ ): void {
285
+ const payload: EventPayload<E> = {
286
+ type: definition.type,
287
+ properties,
288
+ timestamp: Date.now(),
289
+ };
290
+
291
+ // Validate properties against schema
292
+ const result = definition.schema.safeParse(properties);
293
+ if (!result.success) {
294
+ console.error(`[RelayEventBus] Invalid event properties for ${definition.type}:`, result.error);
295
+ return;
296
+ }
297
+
298
+ // Emit to specific subscribers and wildcard subscribers
299
+ this.emit(definition.type, payload);
300
+ this.emit('*', payload);
301
+ }
302
+
303
+ /**
304
+ * Subscribe to a typed event
305
+ */
306
+ onEvent<E extends EventDefinition>(
307
+ definition: E,
308
+ callback: (event: EventPayload<E>) => void
309
+ ): () => void {
310
+ this.on(definition.type, callback);
311
+ return () => this.off(definition.type, callback);
312
+ }
313
+
314
+ /**
315
+ * Subscribe to all events (wildcard)
316
+ */
317
+ onAnyEvent(callback: (event: EventPayload) => void): () => void {
318
+ this.on('*', callback);
319
+ return () => this.off('*', callback);
320
+ }
321
+
322
+ /**
323
+ * Subscribe to an event once
324
+ */
325
+ onceEvent<E extends EventDefinition>(
326
+ definition: E,
327
+ callback: (event: EventPayload<E>) => void
328
+ ): void {
329
+ this.once(definition.type, callback);
330
+ }
331
+ }
332
+
333
+ // =========================================================================
334
+ // Exports
335
+ // =========================================================================
336
+
337
+ /**
338
+ * Global daemon event bus instance
339
+ */
340
+ export const relayEventBus = RelayEventBus.getInstance();
341
+
342
+ /**
343
+ * Emit a daemon event
344
+ */
345
+ export function emitEvent<E extends EventDefinition>(
346
+ definition: E,
347
+ properties: EventProperties<E>
348
+ ): void {
349
+ relayEventBus.emitEvent(definition, properties);
350
+ }
351
+
352
+ /**
353
+ * Subscribe to a daemon event
354
+ */
355
+ export function onEvent<E extends EventDefinition>(
356
+ definition: E,
357
+ callback: (event: EventPayload<E>) => void
358
+ ): () => void {
359
+ return relayEventBus.onEvent(definition, callback);
360
+ }
361
+
362
+ /**
363
+ * Subscribe to all daemon events
364
+ */
365
+ export function onAnyEvent(callback: (event: EventPayload) => void): () => void {
366
+ return relayEventBus.onAnyEvent(callback);
367
+ }
368
+
369
+ // =========================================================================
370
+ // OpenAPI Schema Generation
371
+ // =========================================================================
372
+
373
+ /**
374
+ * Generate OpenAPI-compatible schema for all daemon events
375
+ * This can be used to auto-generate SDK types
376
+ */
377
+ export function generateEventSchemas(): Record<string, unknown> {
378
+ const schemas: Record<string, unknown> = {};
379
+
380
+ for (const definition of RelayEvent.all) {
381
+ // Extract JSON Schema from Zod schema
382
+ // Note: This is a simplified version - production use should use zod-to-json-schema
383
+ schemas[definition.type] = {
384
+ type: 'object',
385
+ properties: {
386
+ type: { type: 'string', const: definition.type },
387
+ properties: definition.schema._def, // Simplified - use zod-to-json-schema for production
388
+ timestamp: { type: 'number' },
389
+ },
390
+ required: ['type', 'properties', 'timestamp'],
391
+ };
392
+ }
393
+
394
+ return schemas;
395
+ }