@agentuity/core 3.0.0-alpha.2 → 3.0.0-alpha.6
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/api.d.ts +1 -1
- package/dist/services/api.d.ts.map +1 -1
- package/dist/services/api.js +4 -6
- package/dist/services/api.js.map +1 -1
- package/dist/services/coder/api-reference.d.ts.map +1 -1
- package/dist/services/coder/api-reference.js +46 -7
- package/dist/services/coder/api-reference.js.map +1 -1
- package/dist/services/coder/protocol.d.ts +199 -10
- package/dist/services/coder/protocol.d.ts.map +1 -1
- package/dist/services/coder/protocol.js +23 -2
- package/dist/services/coder/protocol.js.map +1 -1
- package/dist/services/coder/types.d.ts.map +1 -1
- package/dist/services/coder/types.js +9 -0
- package/dist/services/coder/types.js.map +1 -1
- package/dist/services/coder/websocket.d.ts +13 -1
- package/dist/services/coder/websocket.d.ts.map +1 -1
- package/dist/services/coder/websocket.js +91 -19
- package/dist/services/coder/websocket.js.map +1 -1
- package/package.json +2 -2
- package/src/services/api.ts +6 -7
- package/src/services/coder/api-reference.ts +46 -7
- package/src/services/coder/protocol.ts +33 -2
- package/src/services/coder/types.ts +17 -0
- package/src/services/coder/websocket.ts +120 -21
|
@@ -22,7 +22,7 @@ import { z } from 'zod/v4';
|
|
|
22
22
|
|
|
23
23
|
/** Connection role assigned by the server in the init message */
|
|
24
24
|
export const CoderHubInitRoleSchema = z
|
|
25
|
-
.enum(['lead', 'sub_agent', 'controller'])
|
|
25
|
+
.enum(['lead', 'sub_agent', 'observer', 'controller'])
|
|
26
26
|
.describe(
|
|
27
27
|
'Role assigned to a connecting client, determining its permissions and message routing.'
|
|
28
28
|
);
|
|
@@ -215,10 +215,20 @@ export const CoderHubControllerInitMessageSchema = BaseCoderHubInitMessageSchema
|
|
|
215
215
|
);
|
|
216
216
|
export type CoderHubControllerInitMessage = z.infer<typeof CoderHubControllerInitMessageSchema>;
|
|
217
217
|
|
|
218
|
+
export const CoderHubObserverInitMessageSchema = BaseCoderHubInitMessageSchema.extend({
|
|
219
|
+
role: z
|
|
220
|
+
.literal('observer')
|
|
221
|
+
.describe('Indicates this client is connecting as a read-only observer.'),
|
|
222
|
+
}).describe(
|
|
223
|
+
'Initialization message sent by an observer client when the server chooses to send an explicit init frame.'
|
|
224
|
+
);
|
|
225
|
+
export type CoderHubObserverInitMessage = z.infer<typeof CoderHubObserverInitMessageSchema>;
|
|
226
|
+
|
|
218
227
|
export const CoderHubInitMessageSchema = z
|
|
219
228
|
.discriminatedUnion('role', [
|
|
220
229
|
CoderHubLeadInitMessageSchema,
|
|
221
230
|
CoderHubSubAgentInitMessageSchema,
|
|
231
|
+
CoderHubObserverInitMessageSchema,
|
|
222
232
|
CoderHubControllerInitMessageSchema,
|
|
223
233
|
])
|
|
224
234
|
.describe('Union of all initialization messages, discriminated by the client role.');
|
|
@@ -743,6 +753,22 @@ export const BootstrapReadyMessageSchema = z
|
|
|
743
753
|
);
|
|
744
754
|
export type BootstrapReadyMessage = z.infer<typeof BootstrapReadyMessageSchema>;
|
|
745
755
|
|
|
756
|
+
export const ObserverSubscribeMessageSchema = z
|
|
757
|
+
.object({
|
|
758
|
+
type: z
|
|
759
|
+
.literal('subscribe')
|
|
760
|
+
.describe('Discriminator indicating an observer subscription update.'),
|
|
761
|
+
patterns: z
|
|
762
|
+
.array(z.string())
|
|
763
|
+
.describe(
|
|
764
|
+
'Event filters to receive, including categories, exact names, wildcard prefixes, or "*".'
|
|
765
|
+
),
|
|
766
|
+
})
|
|
767
|
+
.describe(
|
|
768
|
+
'Client message updating the observer event filters for a live Coder Hub WebSocket connection.'
|
|
769
|
+
);
|
|
770
|
+
export type ObserverSubscribeMessage = z.infer<typeof ObserverSubscribeMessageSchema>;
|
|
771
|
+
|
|
746
772
|
export const SessionEntryMessageSchema = z
|
|
747
773
|
.object({
|
|
748
774
|
type: z
|
|
@@ -978,6 +1004,7 @@ export const ClientMessageSchema = z
|
|
|
978
1004
|
SessionEntryMessageSchema,
|
|
979
1005
|
SessionWriteMessageSchema,
|
|
980
1006
|
BootstrapReadyMessageSchema,
|
|
1007
|
+
ObserverSubscribeMessageSchema,
|
|
981
1008
|
RpcCommandMessageSchema,
|
|
982
1009
|
RpcUiResponseMessageSchema,
|
|
983
1010
|
PingMessageSchema,
|
|
@@ -993,7 +1020,7 @@ export type ClientMessage = z.infer<typeof ClientMessageSchema>;
|
|
|
993
1020
|
* Messages the Coder Hub server can send to connected clients.
|
|
994
1021
|
*/
|
|
995
1022
|
export const ServerMessageSchema = z
|
|
996
|
-
.
|
|
1023
|
+
.union([
|
|
997
1024
|
CoderHubInitMessageSchema,
|
|
998
1025
|
CoderHubResponseSchema,
|
|
999
1026
|
CoderHubHydrationMessageSchema,
|
|
@@ -1129,6 +1156,10 @@ export const ConnectionParamsSchema = z
|
|
|
1129
1156
|
.enum(['lead', 'observer', 'controller'])
|
|
1130
1157
|
.optional()
|
|
1131
1158
|
.describe('Requested session role; the server may override based on permissions.'),
|
|
1159
|
+
subscribe: z
|
|
1160
|
+
.string()
|
|
1161
|
+
.optional()
|
|
1162
|
+
.describe('Comma-separated event filters requested during observer connection bootstrap.'),
|
|
1132
1163
|
coordJobId: z
|
|
1133
1164
|
.string()
|
|
1134
1165
|
.optional()
|
|
@@ -322,6 +322,20 @@ export const CoderWorkspaceListResponseSchema = z
|
|
|
322
322
|
.describe('Response payload for listing workspaces');
|
|
323
323
|
export type CoderWorkspaceListResponse = z.infer<typeof CoderWorkspaceListResponseSchema>;
|
|
324
324
|
|
|
325
|
+
function hasWorkspaceSelections(input: {
|
|
326
|
+
repos?: unknown[];
|
|
327
|
+
savedSkillIds?: unknown[];
|
|
328
|
+
skillBucketIds?: unknown[];
|
|
329
|
+
enabledAgents?: unknown[];
|
|
330
|
+
}): boolean {
|
|
331
|
+
return (
|
|
332
|
+
(input.repos?.length ?? 0) > 0 ||
|
|
333
|
+
(input.savedSkillIds?.length ?? 0) > 0 ||
|
|
334
|
+
(input.skillBucketIds?.length ?? 0) > 0 ||
|
|
335
|
+
(input.enabledAgents?.length ?? 0) > 0
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
325
339
|
export const CoderCreateWorkspaceRequestSchema = z
|
|
326
340
|
.object({
|
|
327
341
|
name: z.string().describe('Workspace name'),
|
|
@@ -335,6 +349,9 @@ export const CoderCreateWorkspaceRequestSchema = z
|
|
|
335
349
|
.optional()
|
|
336
350
|
.describe('Effective agent roster to store on the workspace'),
|
|
337
351
|
})
|
|
352
|
+
.refine(hasWorkspaceSelections, {
|
|
353
|
+
message: 'A workspace needs at least one repo, saved skill, skill bucket, or agent',
|
|
354
|
+
})
|
|
338
355
|
.describe('Request body for creating a workspace');
|
|
339
356
|
export type CoderCreateWorkspaceRequest = z.infer<typeof CoderCreateWorkspaceRequestSchema>;
|
|
340
357
|
|
|
@@ -70,7 +70,7 @@ import type {
|
|
|
70
70
|
ConnectionParams,
|
|
71
71
|
ServerMessage,
|
|
72
72
|
} from './protocol.ts';
|
|
73
|
-
import { CoderHubInitMessageSchema } from './protocol.ts';
|
|
73
|
+
import { CoderHubInitMessageSchema, parseServerMessage } from './protocol.ts';
|
|
74
74
|
import { normalizeCoderUrl } from './util.ts';
|
|
75
75
|
|
|
76
76
|
/**
|
|
@@ -118,6 +118,11 @@ export const CoderHubWebSocketOptionsSchema = z.object({
|
|
|
118
118
|
task: z.string().optional().describe('Initial task for driver mode'),
|
|
119
119
|
/** Human-readable session label */
|
|
120
120
|
label: z.string().optional().describe('Session label'),
|
|
121
|
+
/** Observer event filters to request during the initial connection. */
|
|
122
|
+
subscribe: z
|
|
123
|
+
.array(z.string())
|
|
124
|
+
.optional()
|
|
125
|
+
.describe('Observer event filters to request during connection setup'),
|
|
121
126
|
/** Client origin (web, desktop, tui, sdk) */
|
|
122
127
|
origin: z.enum(['web', 'desktop', 'tui', 'sdk']).optional().describe('Client origin'),
|
|
123
128
|
/** Driver mode: 'rpc' for RPC bridge driver */
|
|
@@ -198,7 +203,13 @@ export const CoderHubWebSocketError = StructuredError('CoderHubWebSocketError')<
|
|
|
198
203
|
| 'response_timeout'
|
|
199
204
|
| 'invalid_response';
|
|
200
205
|
sessionId?: string;
|
|
206
|
+
serverCode?: string;
|
|
207
|
+
serverMessage?: string;
|
|
208
|
+
serverMessageType?: 'connection_rejected' | 'protocol_error';
|
|
209
|
+
closeCode?: number;
|
|
210
|
+
closeReason?: string;
|
|
201
211
|
}>();
|
|
212
|
+
export type CoderHubWebSocketErrorInstance = InstanceType<typeof CoderHubWebSocketError>;
|
|
202
213
|
|
|
203
214
|
interface PendingRequest {
|
|
204
215
|
resolve: (response: CoderHubResponse) => void;
|
|
@@ -270,6 +281,7 @@ export class CoderHubWebSocketClient {
|
|
|
270
281
|
parentSessionId: string;
|
|
271
282
|
task: string;
|
|
272
283
|
label: string;
|
|
284
|
+
subscribe: string[];
|
|
273
285
|
origin: 'web' | 'desktop' | 'tui' | 'sdk';
|
|
274
286
|
driverMode: 'rpc' | undefined;
|
|
275
287
|
driverInstanceId: string;
|
|
@@ -317,6 +329,7 @@ export class CoderHubWebSocketClient {
|
|
|
317
329
|
parentSessionId: options.parentSessionId ?? '',
|
|
318
330
|
task: options.task ?? '',
|
|
319
331
|
label: options.label ?? '',
|
|
332
|
+
subscribe: options.subscribe ?? [],
|
|
320
333
|
origin: options.origin ?? 'sdk',
|
|
321
334
|
driverMode: options.driverMode,
|
|
322
335
|
driverInstanceId: options.driverInstanceId ?? '',
|
|
@@ -522,6 +535,57 @@ export class CoderHubWebSocketClient {
|
|
|
522
535
|
return `${Date.now()}-${++this.#messageId}`;
|
|
523
536
|
}
|
|
524
537
|
|
|
538
|
+
#buildHandshakeError(input: {
|
|
539
|
+
code: 'auth_failed' | 'connection_error';
|
|
540
|
+
message: string;
|
|
541
|
+
serverCode?: string;
|
|
542
|
+
serverMessage?: string;
|
|
543
|
+
serverMessageType?: 'connection_rejected' | 'protocol_error';
|
|
544
|
+
closeCode?: number;
|
|
545
|
+
closeReason?: string;
|
|
546
|
+
}): CoderHubWebSocketErrorInstance {
|
|
547
|
+
return new CoderHubWebSocketError({
|
|
548
|
+
code: input.code,
|
|
549
|
+
message: input.message,
|
|
550
|
+
sessionId: this.sessionId,
|
|
551
|
+
serverCode: input.serverCode,
|
|
552
|
+
serverMessage: input.serverMessage,
|
|
553
|
+
serverMessageType: input.serverMessageType,
|
|
554
|
+
closeCode: input.closeCode,
|
|
555
|
+
closeReason: input.closeReason,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
#markReady(input?: {
|
|
560
|
+
initMessage?: CoderHubInitMessage;
|
|
561
|
+
firstMessage?: ServerMessage;
|
|
562
|
+
sendBootstrapReady?: boolean;
|
|
563
|
+
}): void {
|
|
564
|
+
this.#authenticated = true;
|
|
565
|
+
this.#initMessage = input?.initMessage ?? null;
|
|
566
|
+
this.#sessionId =
|
|
567
|
+
input?.initMessage?.sessionId ??
|
|
568
|
+
(input?.firstMessage && 'sessionId' in input.firstMessage
|
|
569
|
+
? input.firstMessage.sessionId
|
|
570
|
+
: undefined) ??
|
|
571
|
+
this.#options.sessionId ??
|
|
572
|
+
null;
|
|
573
|
+
this.#reconnectAttempts = 0;
|
|
574
|
+
this.#setState('connected');
|
|
575
|
+
this.#startHeartbeat();
|
|
576
|
+
if (input?.initMessage) {
|
|
577
|
+
this.#options.onInit(input.initMessage);
|
|
578
|
+
}
|
|
579
|
+
if (input?.sendBootstrapReady && this.#ws?.readyState === WebSocket.OPEN) {
|
|
580
|
+
this.#ws.send(JSON.stringify({ type: 'bootstrap_ready' }));
|
|
581
|
+
}
|
|
582
|
+
this.#flushMessageQueue();
|
|
583
|
+
this.#options.onOpen();
|
|
584
|
+
if (input?.firstMessage) {
|
|
585
|
+
this.#options.onMessage(input.firstMessage);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
525
589
|
#setState(state: CoderHubWebSocketState): void {
|
|
526
590
|
if (this.#state !== state) {
|
|
527
591
|
this.#state = state;
|
|
@@ -589,6 +653,8 @@ export class CoderHubWebSocketClient {
|
|
|
589
653
|
parent: this.#options.parentSessionId || undefined,
|
|
590
654
|
task: this.#options.task || undefined,
|
|
591
655
|
label: this.#options.label || undefined,
|
|
656
|
+
subscribe:
|
|
657
|
+
this.#options.subscribe.length > 0 ? this.#options.subscribe.join(',') : undefined,
|
|
592
658
|
orgId: this.#options.orgId || undefined,
|
|
593
659
|
origin: this.#options.origin || undefined,
|
|
594
660
|
driverMode: this.#options.driverMode || undefined,
|
|
@@ -601,6 +667,9 @@ export class CoderHubWebSocketClient {
|
|
|
601
667
|
params.set(key, String(value));
|
|
602
668
|
}
|
|
603
669
|
}
|
|
670
|
+
if (this.#options.apiKey) {
|
|
671
|
+
params.set('api_key', this.#options.apiKey);
|
|
672
|
+
}
|
|
604
673
|
|
|
605
674
|
const queryString = params.toString();
|
|
606
675
|
return queryString ? `${wsUrl}?${queryString}` : wsUrl;
|
|
@@ -642,12 +711,16 @@ export class CoderHubWebSocketClient {
|
|
|
642
711
|
ws.onopen = () => {
|
|
643
712
|
if (ws !== this.#ws) return;
|
|
644
713
|
this.#setState('authenticating');
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
|
|
714
|
+
if (this.#options.apiKey || this.#options.orgId) {
|
|
715
|
+
const bootstrapPayload: { authorization?: string; org_id?: string } = {};
|
|
716
|
+
if (this.#options.apiKey) {
|
|
717
|
+
bootstrapPayload.authorization = this.#options.apiKey;
|
|
718
|
+
}
|
|
719
|
+
if (this.#options.orgId) {
|
|
720
|
+
bootstrapPayload.org_id = this.#options.orgId;
|
|
721
|
+
}
|
|
722
|
+
ws.send(JSON.stringify(bootstrapPayload));
|
|
723
|
+
}
|
|
651
724
|
};
|
|
652
725
|
|
|
653
726
|
ws.onmessage = (event: MessageEvent) => {
|
|
@@ -685,10 +758,12 @@ export class CoderHubWebSocketClient {
|
|
|
685
758
|
if (msg.type === 'connection_rejected' || msg.type === 'protocol_error') {
|
|
686
759
|
this.#setState('closed');
|
|
687
760
|
this.#options.onError(
|
|
688
|
-
|
|
689
|
-
message: `Connection rejected: ${msg.message ?? msg.code ?? 'Unknown error'}`,
|
|
761
|
+
this.#buildHandshakeError({
|
|
690
762
|
code: 'auth_failed',
|
|
691
|
-
|
|
763
|
+
message: `Connection rejected: ${msg.message ?? msg.code ?? 'Unknown error'}`,
|
|
764
|
+
serverCode: msg.code,
|
|
765
|
+
serverMessage: msg.message,
|
|
766
|
+
serverMessageType: msg.type,
|
|
692
767
|
})
|
|
693
768
|
);
|
|
694
769
|
this.#intentionallyClosed = true;
|
|
@@ -700,15 +775,18 @@ export class CoderHubWebSocketClient {
|
|
|
700
775
|
const initResult = CoderHubInitMessageSchema.safeParse(parsed);
|
|
701
776
|
if (initResult.success) {
|
|
702
777
|
const initMsg = initResult.data;
|
|
703
|
-
this.#
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
778
|
+
this.#markReady({
|
|
779
|
+
initMessage: initMsg,
|
|
780
|
+
sendBootstrapReady: this.#options.role === 'controller',
|
|
781
|
+
});
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
if (this.#options.role === 'observer') {
|
|
786
|
+
const firstObserverMessage = parseServerMessage(parsed);
|
|
787
|
+
if (firstObserverMessage) {
|
|
788
|
+
this.#markReady({ firstMessage: firstObserverMessage });
|
|
789
|
+
}
|
|
712
790
|
}
|
|
713
791
|
return;
|
|
714
792
|
}
|
|
@@ -759,14 +837,31 @@ export class CoderHubWebSocketClient {
|
|
|
759
837
|
this.#clearTimers();
|
|
760
838
|
this.#setState('closed');
|
|
761
839
|
|
|
840
|
+
const wasAuthenticated = this.#authenticated;
|
|
841
|
+
const hadTerminalError = this.#intentionallyClosed;
|
|
842
|
+
const terminalClose = isTerminalCloseCode(event.code);
|
|
843
|
+
|
|
762
844
|
// Clear auth state for clean reconnect
|
|
763
845
|
this.#authenticated = false;
|
|
764
846
|
this.#initMessage = null;
|
|
765
847
|
|
|
766
|
-
if (
|
|
848
|
+
if (terminalClose) {
|
|
767
849
|
this.#intentionallyClosed = true;
|
|
768
850
|
}
|
|
769
851
|
|
|
852
|
+
if (!wasAuthenticated && terminalClose && !hadTerminalError) {
|
|
853
|
+
this.#options.onError(
|
|
854
|
+
this.#buildHandshakeError({
|
|
855
|
+
code: 'connection_error',
|
|
856
|
+
message: `WebSocket closed before connection was ready (code ${event.code})${
|
|
857
|
+
event.reason ? `: ${event.reason}` : ''
|
|
858
|
+
}`,
|
|
859
|
+
closeCode: event.code,
|
|
860
|
+
closeReason: event.reason || undefined,
|
|
861
|
+
})
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
770
865
|
this.#options.onClose(event.code, event.reason);
|
|
771
866
|
|
|
772
867
|
if (!this.#intentionallyClosed) {
|
|
@@ -896,7 +991,11 @@ export async function* subscribeToCoderHub(
|
|
|
896
991
|
onError: (error) => {
|
|
897
992
|
if (
|
|
898
993
|
error instanceof CoderHubWebSocketError &&
|
|
899
|
-
(error.code === 'max_reconnects_exceeded' ||
|
|
994
|
+
(error.code === 'max_reconnects_exceeded' ||
|
|
995
|
+
error.code === 'auth_failed' ||
|
|
996
|
+
(error.code === 'connection_error' &&
|
|
997
|
+
typeof error.closeCode === 'number' &&
|
|
998
|
+
isTerminalCloseCode(error.closeCode)))
|
|
900
999
|
) {
|
|
901
1000
|
terminalError = error;
|
|
902
1001
|
done = true;
|