@crowdedkingdoms/crowdyjs 11.1.0 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +152 -0
- package/README.md +262 -0
- package/dist/crowdy-agent/browser-dispatcher.d.ts +41 -0
- package/dist/crowdy-agent/browser-dispatcher.d.ts.map +1 -0
- package/dist/crowdy-agent/browser-dispatcher.js +264 -0
- package/dist/crowdy-agent/controller.d.ts +144 -0
- package/dist/crowdy-agent/controller.d.ts.map +1 -0
- package/dist/crowdy-agent/controller.js +1239 -0
- package/dist/crowdy-agent/errors.d.ts +37 -0
- package/dist/crowdy-agent/errors.d.ts.map +1 -0
- package/dist/crowdy-agent/errors.js +107 -0
- package/dist/crowdy-agent/graphql-transport.d.ts +154 -0
- package/dist/crowdy-agent/graphql-transport.d.ts.map +1 -0
- package/dist/crowdy-agent/graphql-transport.js +854 -0
- package/dist/crowdy-agent/index.d.ts +16 -0
- package/dist/crowdy-agent/index.d.ts.map +1 -0
- package/dist/crowdy-agent/index.js +15 -0
- package/dist/crowdy-agent/registry.d.ts +29 -0
- package/dist/crowdy-agent/registry.d.ts.map +1 -0
- package/dist/crowdy-agent/registry.js +281 -0
- package/dist/crowdy-agent/schema.d.ts +72 -0
- package/dist/crowdy-agent/schema.d.ts.map +1 -0
- package/dist/crowdy-agent/schema.js +467 -0
- package/dist/crowdy-agent/studio-tools.d.ts +15 -0
- package/dist/crowdy-agent/studio-tools.d.ts.map +1 -0
- package/dist/crowdy-agent/studio-tools.js +280 -0
- package/dist/crowdy-agent/tool-descriptors.d.ts +4 -0
- package/dist/crowdy-agent/tool-descriptors.d.ts.map +1 -0
- package/dist/crowdy-agent/tool-descriptors.js +1049 -0
- package/dist/crowdy-agent/transport.d.ts +152 -0
- package/dist/crowdy-agent/transport.d.ts.map +1 -0
- package/dist/crowdy-agent/transport.js +27 -0
- package/dist/crowdy-agent/types.d.ts +328 -0
- package/dist/crowdy-agent/types.d.ts.map +1 -0
- package/dist/crowdy-agent/types.js +37 -0
- package/dist/crowdy-client.d.ts +3 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +6 -0
- package/dist/crowdy-studio/agent-dom-shell.d.ts +68 -0
- package/dist/crowdy-studio/agent-dom-shell.d.ts.map +1 -0
- package/dist/crowdy-studio/agent-dom-shell.js +418 -0
- package/dist/crowdy-studio/controller.d.ts +74 -4
- package/dist/crowdy-studio/controller.d.ts.map +1 -1
- package/dist/crowdy-studio/controller.js +450 -17
- package/dist/crowdy-studio/dom-shell.d.ts +50 -4
- package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.js +554 -123
- package/dist/crowdy-studio/embed/dock.d.ts +56 -0
- package/dist/crowdy-studio/embed/dock.d.ts.map +1 -0
- package/dist/crowdy-studio/embed/dock.js +231 -0
- package/dist/crowdy-studio/embed/embed-styles.d.ts +12 -0
- package/dist/crowdy-studio/embed/embed-styles.d.ts.map +1 -0
- package/dist/crowdy-studio/embed/embed-styles.js +549 -0
- package/dist/crowdy-studio/embed/hud-layer.d.ts +40 -0
- package/dist/crowdy-studio/embed/hud-layer.d.ts.map +1 -0
- package/dist/crowdy-studio/embed/hud-layer.js +100 -0
- package/dist/crowdy-studio/embed/index.d.ts +5 -0
- package/dist/crowdy-studio/embed/index.d.ts.map +1 -0
- package/dist/crowdy-studio/embed/index.js +4 -0
- package/dist/crowdy-studio/embed/panel.d.ts +162 -0
- package/dist/crowdy-studio/embed/panel.d.ts.map +1 -0
- package/dist/crowdy-studio/embed/panel.js +642 -0
- package/dist/crowdy-studio/index.d.ts +9 -3
- package/dist/crowdy-studio/index.d.ts.map +1 -1
- package/dist/crowdy-studio/index.js +6 -0
- package/dist/crowdy-studio/layout.d.ts +50 -0
- package/dist/crowdy-studio/layout.d.ts.map +1 -0
- package/dist/crowdy-studio/layout.js +155 -0
- package/dist/crowdy-studio/models.d.ts +67 -0
- package/dist/crowdy-studio/models.d.ts.map +1 -1
- package/dist/crowdy-studio/mount.d.ts +15 -0
- package/dist/crowdy-studio/mount.d.ts.map +1 -1
- package/dist/crowdy-studio/mount.js +132 -3
- package/dist/crowdy-studio/splitter.d.ts +33 -0
- package/dist/crowdy-studio/splitter.d.ts.map +1 -0
- package/dist/crowdy-studio/splitter.js +133 -0
- package/dist/crowdy-studio/styles.d.ts +1 -1
- package/dist/crowdy-studio/styles.d.ts.map +1 -1
- package/dist/crowdy-studio/styles.js +128 -11
- package/dist/generated/graphql.d.ts +3753 -1
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +296 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/player-host/control-banner.d.ts +40 -0
- package/dist/player-host/control-banner.d.ts.map +1 -0
- package/dist/player-host/control-banner.js +252 -0
- package/dist/player-host/control-gate.d.ts +77 -0
- package/dist/player-host/control-gate.d.ts.map +1 -0
- package/dist/player-host/control-gate.js +197 -0
- package/dist/player-host/index.d.ts +7 -0
- package/dist/player-host/index.d.ts.map +1 -0
- package/dist/player-host/index.js +5 -0
- package/dist/player-host/lease-manager.d.ts +66 -0
- package/dist/player-host/lease-manager.d.ts.map +1 -0
- package/dist/player-host/lease-manager.js +428 -0
- package/dist/player-host/schemas.d.ts +9 -0
- package/dist/player-host/schemas.d.ts.map +1 -0
- package/dist/player-host/schemas.js +347 -0
- package/dist/player-host/tools.d.ts +13 -0
- package/dist/player-host/tools.d.ts.map +1 -0
- package/dist/player-host/tools.js +79 -0
- package/dist/player-host/types.d.ts +203 -0
- package/dist/player-host/types.d.ts.map +1 -0
- package/dist/player-host/types.js +1 -0
- package/package.json +17 -2
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
import { createClient as createWsClient } from 'graphql-ws';
|
|
2
|
+
import { print } from 'graphql';
|
|
3
|
+
import { CrowdyGraphQLError, } from '../errors.js';
|
|
4
|
+
import { CrowdyStudioAgentAcknowledgeEventsDocument, CrowdyStudioAgentApproveToolDocument, CrowdyStudioAgentAttachClientDocument, CrowdyStudioAgentBudgetDocument, CrowdyStudioAgentCancelRunDocument, CrowdyStudioAgentCloseSessionDocument, CrowdyStudioAgentCreateSessionDocument, CrowdyStudioAgentEventsDocument, CrowdyStudioAgentGrantLeaseDocument, CrowdyStudioAgentHeartbeatDocument, CrowdyStudioAgentHistoryDocument, CrowdyStudioAgentPauseDocument, CrowdyStudioAgentRejectToolDocument, CrowdyStudioAgentResumeDocument, CrowdyStudioAgentRevokeLeaseDocument, CrowdyStudioAgentSendMessageDocument, CrowdyStudioAgentSessionDocument, CrowdyStudioAgentSessionsDocument, CrowdyStudioAgentSetModeDocument, CrowdyStudioAgentToolDescriptorsDocument, CrowdyStudioAgentToolResultDocument, } from '../generated/graphql.js';
|
|
5
|
+
import { CrowdyAgentError, } from './errors.js';
|
|
6
|
+
import { canonicalJson, digestCanonicalJson, } from './schema.js';
|
|
7
|
+
import { CrowdyAgentToolRegistry } from './registry.js';
|
|
8
|
+
/**
|
|
9
|
+
* Production generated-GraphQL adapter for `CrowdyStudioAgentTransportV1`.
|
|
10
|
+
* Every HTTP and subscription shape is selected by committed typed documents.
|
|
11
|
+
*/
|
|
12
|
+
export class CrowdyAgentGraphQLTransport {
|
|
13
|
+
constructor(graphql, options) {
|
|
14
|
+
this.graphql = graphql;
|
|
15
|
+
this.options = options;
|
|
16
|
+
this.activeSubscriptions = new Set();
|
|
17
|
+
}
|
|
18
|
+
async getSession(sessionId) {
|
|
19
|
+
const data = await this.request(CrowdyStudioAgentSessionDocument, {
|
|
20
|
+
sessionId,
|
|
21
|
+
});
|
|
22
|
+
return mapSession(data.crowdyStudioAgentSession);
|
|
23
|
+
}
|
|
24
|
+
async listSessions(input) {
|
|
25
|
+
const data = await this.request(CrowdyStudioAgentSessionsDocument, {
|
|
26
|
+
appId: input.appId,
|
|
27
|
+
after: input.after ?? null,
|
|
28
|
+
first: input.first,
|
|
29
|
+
});
|
|
30
|
+
const connection = data.crowdyStudioAgentSessions;
|
|
31
|
+
const edges = connection.edges.map((edge) => ({
|
|
32
|
+
cursor: edge.cursor,
|
|
33
|
+
node: mapSession(edge.node),
|
|
34
|
+
}));
|
|
35
|
+
return {
|
|
36
|
+
edges,
|
|
37
|
+
pageInfo: {
|
|
38
|
+
hasNextPage: connection.pageInfo.hasNextPage,
|
|
39
|
+
...(connection.pageInfo.endCursor
|
|
40
|
+
? { endCursor: connection.pageInfo.endCursor }
|
|
41
|
+
: {}),
|
|
42
|
+
},
|
|
43
|
+
nodes: edges.map((edge) => edge.node),
|
|
44
|
+
...(connection.endCursor ? { endCursor: connection.endCursor } : {}),
|
|
45
|
+
hasNextPage: connection.hasNextPage,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async history(input) {
|
|
49
|
+
const data = await this.request(CrowdyStudioAgentHistoryDocument, {
|
|
50
|
+
sessionId: input.sessionId,
|
|
51
|
+
afterSeq: input.afterSeq,
|
|
52
|
+
first: input.first,
|
|
53
|
+
});
|
|
54
|
+
const connection = data.crowdyStudioAgentHistory;
|
|
55
|
+
const edges = connection.edges.map((edge) => ({
|
|
56
|
+
cursor: edge.cursor,
|
|
57
|
+
node: mapEvent(edge.node),
|
|
58
|
+
}));
|
|
59
|
+
return {
|
|
60
|
+
edges,
|
|
61
|
+
pageInfo: {
|
|
62
|
+
hasNextPage: connection.pageInfo.hasNextPage,
|
|
63
|
+
...(connection.pageInfo.endCursor
|
|
64
|
+
? { endCursor: connection.pageInfo.endCursor }
|
|
65
|
+
: {}),
|
|
66
|
+
},
|
|
67
|
+
events: edges.map((edge) => edge.node),
|
|
68
|
+
hasMore: connection.hasMore,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async toolDescriptors(sessionId) {
|
|
72
|
+
const data = await this.request(CrowdyStudioAgentToolDescriptorsDocument, { sessionId });
|
|
73
|
+
const result = data.crowdyStudioAgentToolDescriptors;
|
|
74
|
+
const descriptors = result.tools.map(mapDescriptor);
|
|
75
|
+
const registry = new CrowdyAgentToolRegistry(descriptors);
|
|
76
|
+
if (registry.registryDigest !== result.registryDigest) {
|
|
77
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', 'Game API descriptor registry digest does not match canonical descriptors');
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
registryDigest: result.registryDigest,
|
|
81
|
+
tools: registry.list(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async budget(sessionId) {
|
|
85
|
+
const data = await this.request(CrowdyStudioAgentBudgetDocument, {
|
|
86
|
+
sessionId,
|
|
87
|
+
});
|
|
88
|
+
return mapBudget(data.crowdyStudioAgentBudget);
|
|
89
|
+
}
|
|
90
|
+
async createSession(input) {
|
|
91
|
+
const data = await this.request(CrowdyStudioAgentCreateSessionDocument, {
|
|
92
|
+
input: {
|
|
93
|
+
idempotencyKey: input.idempotencyKey,
|
|
94
|
+
appId: input.appId,
|
|
95
|
+
mode: input.mode,
|
|
96
|
+
...(input.projectId ? { projectId: input.projectId } : {}),
|
|
97
|
+
...(input.gridId ? { gridId: input.gridId } : {}),
|
|
98
|
+
...(input.requestedModel
|
|
99
|
+
? { requestedModel: input.requestedModel }
|
|
100
|
+
: {}),
|
|
101
|
+
providerDataConsent: input.providerDataConsent ?? false,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
return mapSession(data.crowdyStudioAgentCreateSession);
|
|
105
|
+
}
|
|
106
|
+
async attachClient(input) {
|
|
107
|
+
const data = await this.request(CrowdyStudioAgentAttachClientDocument, {
|
|
108
|
+
input: {
|
|
109
|
+
sessionId: input.sessionId,
|
|
110
|
+
idempotencyKey: input.idempotencyKey,
|
|
111
|
+
...(input.clientInstanceId
|
|
112
|
+
? { clientInstanceId: input.clientInstanceId }
|
|
113
|
+
: {}),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
const attachment = data.crowdyStudioAgentAttachClient;
|
|
117
|
+
return {
|
|
118
|
+
session: mapSession(attachment.session),
|
|
119
|
+
clientEpoch: String(attachment.clientEpoch),
|
|
120
|
+
replayAfterSeq: String(attachment.replayAfterSeq),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async setMode(input) {
|
|
124
|
+
const data = await this.request(CrowdyStudioAgentSetModeDocument, {
|
|
125
|
+
input: {
|
|
126
|
+
...input,
|
|
127
|
+
mode: input.mode,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
return mapSession(data.crowdyStudioAgentSetMode);
|
|
131
|
+
}
|
|
132
|
+
async acknowledgeEvents(input) {
|
|
133
|
+
const data = await this.request(CrowdyStudioAgentAcknowledgeEventsDocument, { input });
|
|
134
|
+
return {
|
|
135
|
+
throughSeq: String(data.crowdyStudioAgentAcknowledgeEvents.throughSeq),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async heartbeat(input) {
|
|
139
|
+
const data = await this.request(CrowdyStudioAgentHeartbeatDocument, {
|
|
140
|
+
input,
|
|
141
|
+
});
|
|
142
|
+
const heartbeat = data.crowdyStudioAgentHeartbeat;
|
|
143
|
+
return {
|
|
144
|
+
serverTime: heartbeat.serverTime,
|
|
145
|
+
...(heartbeat.playLeaseFreshUntil
|
|
146
|
+
? { playLeaseFreshUntil: heartbeat.playLeaseFreshUntil }
|
|
147
|
+
: {}),
|
|
148
|
+
...(heartbeat.workspaceLeaseExpiresAt
|
|
149
|
+
? { workspaceLeaseExpiresAt: heartbeat.workspaceLeaseExpiresAt }
|
|
150
|
+
: {}),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async sendMessage(input) {
|
|
154
|
+
const data = await this.request(CrowdyStudioAgentSendMessageDocument, {
|
|
155
|
+
input: {
|
|
156
|
+
sessionId: input.sessionId,
|
|
157
|
+
clientEpoch: input.clientEpoch,
|
|
158
|
+
idempotencyKey: input.idempotencyKey,
|
|
159
|
+
content: input.message,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
return mapRun(data.crowdyStudioAgentSendMessage);
|
|
163
|
+
}
|
|
164
|
+
async approveTool(input) {
|
|
165
|
+
const data = await this.request(CrowdyStudioAgentApproveToolDocument, {
|
|
166
|
+
input,
|
|
167
|
+
});
|
|
168
|
+
return mapApproval(data.crowdyStudioAgentApproveTool);
|
|
169
|
+
}
|
|
170
|
+
async rejectTool(input) {
|
|
171
|
+
const data = await this.request(CrowdyStudioAgentRejectToolDocument, {
|
|
172
|
+
input: {
|
|
173
|
+
sessionId: input.sessionId,
|
|
174
|
+
clientEpoch: input.clientEpoch,
|
|
175
|
+
idempotencyKey: input.idempotencyKey,
|
|
176
|
+
toolCallId: input.toolCallId,
|
|
177
|
+
argumentHash: input.argumentHash,
|
|
178
|
+
...(input.reason ? { reason: input.reason } : {}),
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
return mapApproval(data.crowdyStudioAgentRejectTool);
|
|
182
|
+
}
|
|
183
|
+
async toolResult(input) {
|
|
184
|
+
const result = input.result;
|
|
185
|
+
const data = await this.request(CrowdyStudioAgentToolResultDocument, {
|
|
186
|
+
input: {
|
|
187
|
+
sessionId: input.sessionId,
|
|
188
|
+
clientEpoch: input.clientEpoch,
|
|
189
|
+
idempotencyKey: input.idempotencyKey,
|
|
190
|
+
result: {
|
|
191
|
+
protocolVersion: result.protocolVersion,
|
|
192
|
+
toolCallId: result.toolCallId,
|
|
193
|
+
status: result.status,
|
|
194
|
+
...(result.output !== undefined
|
|
195
|
+
? { outputJson: canonicalJson(result.output) }
|
|
196
|
+
: {}),
|
|
197
|
+
...(result.error
|
|
198
|
+
? {
|
|
199
|
+
errorCode: result.error.code,
|
|
200
|
+
errorMessage: result.error.message,
|
|
201
|
+
errorRetryable: result.error.retryable,
|
|
202
|
+
}
|
|
203
|
+
: {}),
|
|
204
|
+
observedContextVersion: result.observedContextVersion,
|
|
205
|
+
startedAt: result.startedAt,
|
|
206
|
+
finishedAt: result.finishedAt,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
const call = data.crowdyStudioAgentToolResult;
|
|
211
|
+
return {
|
|
212
|
+
toolCallId: call.toolCallId,
|
|
213
|
+
toolName: call.toolName,
|
|
214
|
+
status: call.status,
|
|
215
|
+
argumentHash: call.argumentHash,
|
|
216
|
+
...(call.error ? { error: mapError(call.error) } : {}),
|
|
217
|
+
accepted: call.accepted,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async grantLease(input) {
|
|
221
|
+
const data = await this.request(CrowdyStudioAgentGrantLeaseDocument, {
|
|
222
|
+
input: {
|
|
223
|
+
...input,
|
|
224
|
+
scopes: [...input.scopes],
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
return mapLease(data.crowdyStudioAgentGrantLease);
|
|
228
|
+
}
|
|
229
|
+
async revokeLease(input) {
|
|
230
|
+
const data = await this.request(CrowdyStudioAgentRevokeLeaseDocument, {
|
|
231
|
+
input: {
|
|
232
|
+
...input,
|
|
233
|
+
reason: input.reason,
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
return mapLease(data.crowdyStudioAgentRevokeLease);
|
|
237
|
+
}
|
|
238
|
+
async pause(input) {
|
|
239
|
+
const data = await this.request(CrowdyStudioAgentPauseDocument, { input });
|
|
240
|
+
return mapSession(data.crowdyStudioAgentPause);
|
|
241
|
+
}
|
|
242
|
+
async resume(input) {
|
|
243
|
+
const data = await this.request(CrowdyStudioAgentResumeDocument, { input });
|
|
244
|
+
return mapSession(data.crowdyStudioAgentResume);
|
|
245
|
+
}
|
|
246
|
+
async cancelRun(input) {
|
|
247
|
+
const data = await this.request(CrowdyStudioAgentCancelRunDocument, {
|
|
248
|
+
input,
|
|
249
|
+
});
|
|
250
|
+
return mapRun(data.crowdyStudioAgentCancelRun);
|
|
251
|
+
}
|
|
252
|
+
async closeSession(input) {
|
|
253
|
+
const data = await this.request(CrowdyStudioAgentCloseSessionDocument, {
|
|
254
|
+
input,
|
|
255
|
+
});
|
|
256
|
+
return mapSession(data.crowdyStudioAgentCloseSession);
|
|
257
|
+
}
|
|
258
|
+
subscribeEvents(input, handlers) {
|
|
259
|
+
const client = this.createSubscriptionClient();
|
|
260
|
+
let closed = false;
|
|
261
|
+
const dispose = client.subscribe({
|
|
262
|
+
query: print(CrowdyStudioAgentEventsDocument),
|
|
263
|
+
variables: input,
|
|
264
|
+
}, {
|
|
265
|
+
next: (message) => {
|
|
266
|
+
if (message.errors?.length) {
|
|
267
|
+
handlers.error(mapGraphQLErrors(message.errors));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const data = message.data;
|
|
271
|
+
if (data?.crowdyStudioAgentEvents) {
|
|
272
|
+
try {
|
|
273
|
+
handlers.next(mapEvent(data.crowdyStudioAgentEvents));
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
handlers.error(error);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
error: (error) => handlers.error(mapTransportError(error)),
|
|
281
|
+
complete: () => handlers.complete(),
|
|
282
|
+
});
|
|
283
|
+
const subscription = {
|
|
284
|
+
close: () => {
|
|
285
|
+
if (closed)
|
|
286
|
+
return;
|
|
287
|
+
closed = true;
|
|
288
|
+
this.activeSubscriptions.delete(subscription);
|
|
289
|
+
dispose();
|
|
290
|
+
void client.dispose();
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
this.activeSubscriptions.add(subscription);
|
|
294
|
+
return subscription;
|
|
295
|
+
}
|
|
296
|
+
/** Close all agent event sockets owned by this adapter. */
|
|
297
|
+
close() {
|
|
298
|
+
for (const subscription of [...this.activeSubscriptions]) {
|
|
299
|
+
subscription.close();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
createSubscriptionClient() {
|
|
303
|
+
if (this.options.subscriptionClientFactory) {
|
|
304
|
+
return this.options.subscriptionClientFactory();
|
|
305
|
+
}
|
|
306
|
+
if (!this.options.wsUrl) {
|
|
307
|
+
throw new CrowdyAgentError('AGENT_HOST_UNAVAILABLE', 'Crowdy agent events require a graphql-transport-ws endpoint');
|
|
308
|
+
}
|
|
309
|
+
return createWsClient({
|
|
310
|
+
url: this.options.wsUrl,
|
|
311
|
+
lazy: false,
|
|
312
|
+
retryAttempts: 0,
|
|
313
|
+
...(this.options.webSocketImpl
|
|
314
|
+
? { webSocketImpl: this.options.webSocketImpl }
|
|
315
|
+
: {}),
|
|
316
|
+
connectionParams: () => {
|
|
317
|
+
const token = this.options.getToken();
|
|
318
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
async request(document, variables) {
|
|
323
|
+
try {
|
|
324
|
+
return await this.graphql.request(document, variables);
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
throw mapTransportError(error);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function mapSession(value) {
|
|
332
|
+
return {
|
|
333
|
+
contractVersion: 'crowdy.studio-agent/1',
|
|
334
|
+
sessionId: value.sessionId,
|
|
335
|
+
appId: String(value.appId),
|
|
336
|
+
...(value.projectId ? { projectId: value.projectId } : {}),
|
|
337
|
+
...(value.gridId ? { gridId: String(value.gridId) } : {}),
|
|
338
|
+
mode: value.mode,
|
|
339
|
+
status: value.status,
|
|
340
|
+
requestedModel: value.requestedModel,
|
|
341
|
+
...(value.model ? { model: value.model } : {}),
|
|
342
|
+
...(value.resolvedModel ? { resolvedModel: value.resolvedModel } : {}),
|
|
343
|
+
providerDataConsent: value.providerDataConsent,
|
|
344
|
+
registryDigest: value.registryDigest,
|
|
345
|
+
providerPolicyVersion: value.providerPolicyVersion,
|
|
346
|
+
appPolicyVersion: value.appPolicyVersion,
|
|
347
|
+
contextVersion: value.contextVersion,
|
|
348
|
+
currentClientEpoch: String(value.currentClientEpoch),
|
|
349
|
+
...(value.clientEpoch ? { clientEpoch: String(value.clientEpoch) } : {}),
|
|
350
|
+
lastEventSeq: String(value.lastEventSeq),
|
|
351
|
+
...(value.currentRun ? { currentRun: mapRun(value.currentRun) } : {}),
|
|
352
|
+
activeLeases: value.activeLeases.map(mapLease),
|
|
353
|
+
...(value.pendingApproval
|
|
354
|
+
? { pendingApproval: mapApproval(value.pendingApproval) }
|
|
355
|
+
: {}),
|
|
356
|
+
createdAt: value.createdAt,
|
|
357
|
+
updatedAt: value.updatedAt,
|
|
358
|
+
...(value.closedAt ? { closedAt: value.closedAt } : {}),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
function mapRun(value) {
|
|
362
|
+
return {
|
|
363
|
+
runId: value.runId,
|
|
364
|
+
status: value.status,
|
|
365
|
+
providerRounds: value.providerRounds,
|
|
366
|
+
toolCalls: value.toolCalls,
|
|
367
|
+
...(value.errorCode ? { errorCode: value.errorCode } : {}),
|
|
368
|
+
...(value.terminalReason
|
|
369
|
+
? { terminalReason: value.terminalReason }
|
|
370
|
+
: {}),
|
|
371
|
+
...(value.reason ? { reason: value.reason } : {}),
|
|
372
|
+
...(value.startedAt ? { startedAt: value.startedAt } : {}),
|
|
373
|
+
...(value.finishedAt ? { finishedAt: value.finishedAt } : {}),
|
|
374
|
+
createdAt: value.createdAt,
|
|
375
|
+
cancelled: value.cancelled,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function mapApproval(value, reasons = []) {
|
|
379
|
+
return {
|
|
380
|
+
approvalId: value.approvalId,
|
|
381
|
+
toolCallId: value.toolCallId,
|
|
382
|
+
argumentHash: value.argumentHash,
|
|
383
|
+
status: value.status,
|
|
384
|
+
safeSummary: value.safeSummary,
|
|
385
|
+
reasons,
|
|
386
|
+
clientEpoch: String(value.clientEpoch),
|
|
387
|
+
expiresAt: value.expiresAt,
|
|
388
|
+
approved: value.approved,
|
|
389
|
+
rejected: value.rejected,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function mapLease(value) {
|
|
393
|
+
return {
|
|
394
|
+
leaseId: value.leaseId,
|
|
395
|
+
kind: value.kind,
|
|
396
|
+
status: value.status,
|
|
397
|
+
clientEpoch: String(value.clientEpoch),
|
|
398
|
+
scopes: value.scopes,
|
|
399
|
+
holder: value.holder,
|
|
400
|
+
...(value.controlledEntityId
|
|
401
|
+
? { controlledEntityId: value.controlledEntityId }
|
|
402
|
+
: {}),
|
|
403
|
+
...(value.hostCapabilityRevision
|
|
404
|
+
? { hostCapabilityRevision: value.hostCapabilityRevision }
|
|
405
|
+
: {}),
|
|
406
|
+
...(value.expectedProjectRevision
|
|
407
|
+
? { expectedProjectRevision: String(value.expectedProjectRevision) }
|
|
408
|
+
: {}),
|
|
409
|
+
contextVersion: value.contextVersion,
|
|
410
|
+
grantedAt: value.grantedAt,
|
|
411
|
+
expiresAt: value.expiresAt,
|
|
412
|
+
...(value.revokedReason
|
|
413
|
+
? {
|
|
414
|
+
revokedReason: mapPreemptionReason(value.revokedReason),
|
|
415
|
+
}
|
|
416
|
+
: {}),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function mapBudget(value) {
|
|
420
|
+
return {
|
|
421
|
+
dimensions: value.dimensions.map((dimension) => {
|
|
422
|
+
assertBudgetName(dimension.name);
|
|
423
|
+
assertBudgetScope(dimension.scope);
|
|
424
|
+
return {
|
|
425
|
+
name: dimension.name,
|
|
426
|
+
scope: dimension.scope,
|
|
427
|
+
limit: String(dimension.limit),
|
|
428
|
+
reserved: String(dimension.reserved),
|
|
429
|
+
consumed: String(dimension.consumed),
|
|
430
|
+
remaining: String(dimension.remaining),
|
|
431
|
+
unit: dimension.unit,
|
|
432
|
+
};
|
|
433
|
+
}),
|
|
434
|
+
...(value.resetAt ? { resetAt: value.resetAt } : {}),
|
|
435
|
+
platformFunded: value.platformFunded,
|
|
436
|
+
payer: mapPayer(value.payer),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function mapDescriptor(value) {
|
|
440
|
+
const parsed = parseJsonObject(value.descriptorJson, 'descriptorJson');
|
|
441
|
+
if (canonicalJson(parsed) !== value.descriptorJson) {
|
|
442
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', `${value.name} descriptor JSON is not canonical`);
|
|
443
|
+
}
|
|
444
|
+
if (digestCanonicalJson(parsed) !== value.descriptorDigest) {
|
|
445
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', `${value.name} descriptor digest does not match its canonical JSON`);
|
|
446
|
+
}
|
|
447
|
+
const descriptor = parsed;
|
|
448
|
+
if (descriptor.name !== value.name ||
|
|
449
|
+
descriptor.version !== value.version ||
|
|
450
|
+
descriptor.wireName !== value.wireName ||
|
|
451
|
+
descriptor.schemaVersion !== value.schemaVersion ||
|
|
452
|
+
descriptor.summary !== value.summary ||
|
|
453
|
+
descriptor.executor !== value.executor ||
|
|
454
|
+
canonicalJson(descriptor.modes) !== canonicalJson(value.modes) ||
|
|
455
|
+
descriptor.risk.class !== value.risk ||
|
|
456
|
+
canonicalJson(descriptor.risk.effects) !==
|
|
457
|
+
canonicalJson(value.riskEffects) ||
|
|
458
|
+
descriptor.risk.reversible !== value.riskReversible ||
|
|
459
|
+
canonicalJson(descriptor.scopes.map((scope) => scope.scope)) !==
|
|
460
|
+
canonicalJson(value.scopes) ||
|
|
461
|
+
canonicalJson(descriptor.scopes) !== value.scopeRequirementsJson ||
|
|
462
|
+
(descriptor.approval.policy === 'REQUIRED') !==
|
|
463
|
+
value.approvalRequired ||
|
|
464
|
+
descriptor.approval.policy !== value.approvalPolicy ||
|
|
465
|
+
canonicalJson(descriptor.approval.reasons) !==
|
|
466
|
+
canonicalJson(value.approvalReasons) ||
|
|
467
|
+
descriptor.approval.maxTtlSeconds !== value.approvalMaxTtlSeconds ||
|
|
468
|
+
descriptor.idempotency.class !== value.idempotencyClass ||
|
|
469
|
+
descriptor.idempotency.keyScope !== value.idempotencyKeyScope ||
|
|
470
|
+
descriptor.timeoutMs !== value.timeoutMs ||
|
|
471
|
+
canonicalJson(descriptor.inputSchema) !== value.inputSchemaJson ||
|
|
472
|
+
canonicalJson(descriptor.outputSchema) !== value.outputSchemaJson ||
|
|
473
|
+
canonicalJson(descriptor.redaction.input) !== value.inputRedactionJson ||
|
|
474
|
+
canonicalJson(descriptor.redaction.output) !== value.outputRedactionJson ||
|
|
475
|
+
descriptor.redaction.maxPersistedBytes !== value.maxPersistedBytes) {
|
|
476
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', `${value.name} descriptor fields diverge from descriptorJson`);
|
|
477
|
+
}
|
|
478
|
+
return descriptor;
|
|
479
|
+
}
|
|
480
|
+
function mapEvent(value) {
|
|
481
|
+
const base = {
|
|
482
|
+
protocolVersion: value.protocolVersion,
|
|
483
|
+
eventId: value.eventId,
|
|
484
|
+
sessionId: value.sessionId,
|
|
485
|
+
seq: String(value.seq),
|
|
486
|
+
createdAt: value.createdAt,
|
|
487
|
+
};
|
|
488
|
+
const type = value.type;
|
|
489
|
+
switch (value.__typename) {
|
|
490
|
+
case 'AgentLifecycleEvent':
|
|
491
|
+
if (type === 'MODE_SELECTED') {
|
|
492
|
+
if (!value.lifecycleMode) {
|
|
493
|
+
throw invalidEvent('MODE_SELECTED omitted mode');
|
|
494
|
+
}
|
|
495
|
+
return {
|
|
496
|
+
...base,
|
|
497
|
+
type,
|
|
498
|
+
payload: { mode: value.lifecycleMode },
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (type === 'CONTEXT_CHANGED') {
|
|
502
|
+
if (!value.lifecycleContextVersion) {
|
|
503
|
+
throw invalidEvent('CONTEXT_CHANGED omitted contextVersion');
|
|
504
|
+
}
|
|
505
|
+
return {
|
|
506
|
+
...base,
|
|
507
|
+
type,
|
|
508
|
+
payload: {
|
|
509
|
+
contextVersion: value.lifecycleContextVersion,
|
|
510
|
+
reason: value.lifecycleReason ?? 'CONTEXT_CHANGED',
|
|
511
|
+
},
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
if (type === 'CLIENT_ATTACHED' || type === 'CLIENT_DETACHED') {
|
|
515
|
+
return {
|
|
516
|
+
...base,
|
|
517
|
+
type,
|
|
518
|
+
payload: {
|
|
519
|
+
...(value.lifecycleClientEpoch
|
|
520
|
+
? { clientEpoch: String(value.lifecycleClientEpoch) }
|
|
521
|
+
: {}),
|
|
522
|
+
...(value.lifecycleReplayAfterSeq
|
|
523
|
+
? { replayAfterSeq: String(value.lifecycleReplayAfterSeq) }
|
|
524
|
+
: {}),
|
|
525
|
+
...(value.lifecycleReason
|
|
526
|
+
? { reason: value.lifecycleReason }
|
|
527
|
+
: {}),
|
|
528
|
+
},
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
return {
|
|
532
|
+
...base,
|
|
533
|
+
type,
|
|
534
|
+
payload: {
|
|
535
|
+
sessionId: value.sessionId,
|
|
536
|
+
...(value.lifecycleReason
|
|
537
|
+
? { reason: value.lifecycleReason }
|
|
538
|
+
: {}),
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
case 'AgentMessageEvent': {
|
|
542
|
+
const role = value.messageRole;
|
|
543
|
+
if (role !== 'USER' && role !== 'ASSISTANT') {
|
|
544
|
+
throw invalidEvent('Message event contains an unknown role');
|
|
545
|
+
}
|
|
546
|
+
if (type === 'ASSISTANT_CHUNK') {
|
|
547
|
+
return {
|
|
548
|
+
...base,
|
|
549
|
+
type,
|
|
550
|
+
payload: {
|
|
551
|
+
runId: value.runId ?? '',
|
|
552
|
+
content: value.messageContent,
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
const message = {
|
|
557
|
+
messageId: value.messageEventId,
|
|
558
|
+
role,
|
|
559
|
+
content: value.messageContent,
|
|
560
|
+
...(value.runId ? { runId: value.runId } : {}),
|
|
561
|
+
createdAt: value.createdAt,
|
|
562
|
+
};
|
|
563
|
+
return {
|
|
564
|
+
...base,
|
|
565
|
+
type,
|
|
566
|
+
payload: { message },
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
case 'AgentRunEvent':
|
|
570
|
+
if (!value.runId)
|
|
571
|
+
throw invalidEvent('Run event omitted runId');
|
|
572
|
+
return {
|
|
573
|
+
...base,
|
|
574
|
+
type,
|
|
575
|
+
payload: {
|
|
576
|
+
runId: value.runId,
|
|
577
|
+
status: value.runStatus,
|
|
578
|
+
...(value.runCode ? { code: value.runCode } : {}),
|
|
579
|
+
...(value.runReason ? { reason: value.runReason } : {}),
|
|
580
|
+
...(value.runError ? { error: mapError(value.runError) } : {}),
|
|
581
|
+
},
|
|
582
|
+
};
|
|
583
|
+
case 'AgentToolEvent':
|
|
584
|
+
return {
|
|
585
|
+
...base,
|
|
586
|
+
type,
|
|
587
|
+
payload: {
|
|
588
|
+
toolCallId: value.toolEventCallId,
|
|
589
|
+
name: value.toolEventName,
|
|
590
|
+
version: value.toolEventVersion,
|
|
591
|
+
status: value.toolStatus,
|
|
592
|
+
...(value.toolSafeSummary
|
|
593
|
+
? { safeSummary: value.toolSafeSummary }
|
|
594
|
+
: {}),
|
|
595
|
+
...(value.toolArgumentHash
|
|
596
|
+
? { argumentHash: value.toolArgumentHash }
|
|
597
|
+
: {}),
|
|
598
|
+
...(value.toolInvocation
|
|
599
|
+
? { invocation: mapInvocation(value.toolInvocation) }
|
|
600
|
+
: {}),
|
|
601
|
+
...(value.toolResult
|
|
602
|
+
? { result: mapResultEnvelope(value.toolResult) }
|
|
603
|
+
: {}),
|
|
604
|
+
...(value.toolError ? { error: mapError(value.toolError) } : {}),
|
|
605
|
+
},
|
|
606
|
+
};
|
|
607
|
+
case 'AgentApprovalEvent':
|
|
608
|
+
return {
|
|
609
|
+
...base,
|
|
610
|
+
type,
|
|
611
|
+
payload: {
|
|
612
|
+
approval: {
|
|
613
|
+
approvalId: value.approvalEventId,
|
|
614
|
+
toolCallId: value.approvalToolCallId,
|
|
615
|
+
argumentHash: value.approvalArgumentHash,
|
|
616
|
+
status: value.approvalStatus,
|
|
617
|
+
safeSummary: value.approvalSafeSummary,
|
|
618
|
+
reasons: value.approvalReasons,
|
|
619
|
+
expiresAt: value.approvalExpiresAt,
|
|
620
|
+
approved: value.approvalStatus === 'GRANTED' ||
|
|
621
|
+
value.approvalStatus === 'CONSUMED',
|
|
622
|
+
rejected: value.approvalStatus === 'DENIED',
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
};
|
|
626
|
+
case 'AgentLeaseEvent':
|
|
627
|
+
return {
|
|
628
|
+
...base,
|
|
629
|
+
type,
|
|
630
|
+
payload: {
|
|
631
|
+
lease: {
|
|
632
|
+
leaseId: value.leaseEventId,
|
|
633
|
+
kind: value.leaseKind,
|
|
634
|
+
status: value.leaseStatus,
|
|
635
|
+
clientEpoch: String(value.leaseClientEpoch),
|
|
636
|
+
scopes: value.leaseScopes,
|
|
637
|
+
holder: value.leaseHolder,
|
|
638
|
+
contextVersion: value.leaseContextVersion,
|
|
639
|
+
...(value.leaseControlledEntityId
|
|
640
|
+
? { controlledEntityId: value.leaseControlledEntityId }
|
|
641
|
+
: {}),
|
|
642
|
+
...(value.leaseHostCapabilityRevision
|
|
643
|
+
? {
|
|
644
|
+
hostCapabilityRevision: value.leaseHostCapabilityRevision,
|
|
645
|
+
}
|
|
646
|
+
: {}),
|
|
647
|
+
...(value.leaseExpectedProjectRevision
|
|
648
|
+
? {
|
|
649
|
+
expectedProjectRevision: String(value.leaseExpectedProjectRevision),
|
|
650
|
+
}
|
|
651
|
+
: {}),
|
|
652
|
+
grantedAt: value.leaseGrantedAt,
|
|
653
|
+
expiresAt: value.leaseExpiresAt,
|
|
654
|
+
...(value.leaseReason
|
|
655
|
+
? {
|
|
656
|
+
revokedReason: mapPreemptionReason(value.leaseReason),
|
|
657
|
+
}
|
|
658
|
+
: {}),
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
};
|
|
662
|
+
case 'AgentCheckpointEvent':
|
|
663
|
+
if (value.checkpointReason !== 'AGENT_WRITE' &&
|
|
664
|
+
value.checkpointReason !== 'RESTORE_PREIMAGE' &&
|
|
665
|
+
value.checkpointReason !== 'MANUAL') {
|
|
666
|
+
throw invalidEvent(`Unknown checkpoint reason ${value.checkpointReason}`);
|
|
667
|
+
}
|
|
668
|
+
return {
|
|
669
|
+
...base,
|
|
670
|
+
type,
|
|
671
|
+
payload: {
|
|
672
|
+
checkpoint: {
|
|
673
|
+
checkpointId: value.checkpointEventId,
|
|
674
|
+
projectRevision: String(value.checkpointProjectRevision),
|
|
675
|
+
contentHash: value.checkpointContentHash,
|
|
676
|
+
reason: value.checkpointReason,
|
|
677
|
+
files: value.checkpointFiles.map((file) => {
|
|
678
|
+
if (file.target !== 'SERVER' && file.target !== 'CLIENT') {
|
|
679
|
+
throw invalidEvent(`Unknown checkpoint file target ${file.target}`);
|
|
680
|
+
}
|
|
681
|
+
return {
|
|
682
|
+
target: file.target,
|
|
683
|
+
path: file.path,
|
|
684
|
+
contentHash: file.contentHash,
|
|
685
|
+
byteLength: file.byteLength,
|
|
686
|
+
};
|
|
687
|
+
}),
|
|
688
|
+
createdAt: value.createdAt,
|
|
689
|
+
...(value.checkpointRestoredAt
|
|
690
|
+
? { restoredAt: value.checkpointRestoredAt }
|
|
691
|
+
: {}),
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
};
|
|
695
|
+
case 'AgentBudgetEvent':
|
|
696
|
+
return {
|
|
697
|
+
...base,
|
|
698
|
+
type,
|
|
699
|
+
payload: { budget: mapBudget(value.budgetSnapshot) },
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function mapInvocation(value) {
|
|
704
|
+
return {
|
|
705
|
+
protocolVersion: value.protocolVersion,
|
|
706
|
+
sessionId: value.sessionId,
|
|
707
|
+
runId: value.runId,
|
|
708
|
+
toolCallId: value.toolCallId,
|
|
709
|
+
name: value.name,
|
|
710
|
+
version: value.version,
|
|
711
|
+
descriptorDigest: value.descriptorDigest,
|
|
712
|
+
arguments: parseJsonObject(value.argumentsJson, 'argumentsJson'),
|
|
713
|
+
argumentHash: value.argumentHash,
|
|
714
|
+
contextVersion: value.contextVersion,
|
|
715
|
+
...(value.clientEpoch
|
|
716
|
+
? { clientEpoch: String(value.clientEpoch) }
|
|
717
|
+
: {}),
|
|
718
|
+
...(value.leaseId ? { leaseId: value.leaseId } : {}),
|
|
719
|
+
...(value.approvalGrant
|
|
720
|
+
? { approvalGrant: value.approvalGrant }
|
|
721
|
+
: {}),
|
|
722
|
+
...(value.idempotencyKey
|
|
723
|
+
? { idempotencyKey: value.idempotencyKey }
|
|
724
|
+
: {}),
|
|
725
|
+
deadline: value.deadline,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function mapResultEnvelope(value) {
|
|
729
|
+
return {
|
|
730
|
+
protocolVersion: value.protocolVersion,
|
|
731
|
+
toolCallId: value.toolCallId,
|
|
732
|
+
status: value.status,
|
|
733
|
+
...(value.outputJson
|
|
734
|
+
? { output: parseJsonObject(value.outputJson, 'outputJson') }
|
|
735
|
+
: {}),
|
|
736
|
+
...(value.error ? { error: mapError(value.error) } : {}),
|
|
737
|
+
observedContextVersion: value.observedContextVersion,
|
|
738
|
+
startedAt: value.startedAt,
|
|
739
|
+
finishedAt: value.finishedAt,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
function mapError(value) {
|
|
743
|
+
return {
|
|
744
|
+
code: value.code,
|
|
745
|
+
message: value.message,
|
|
746
|
+
retryable: value.retryable,
|
|
747
|
+
...(value.remediation ? { remediation: value.remediation } : {}),
|
|
748
|
+
...(value.field ? { field: value.field } : {}),
|
|
749
|
+
...(value.requiredScope ? { requiredScope: value.requiredScope } : {}),
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function parseJsonObject(value, field) {
|
|
753
|
+
try {
|
|
754
|
+
const parsed = JSON.parse(value);
|
|
755
|
+
if (parsed === null ||
|
|
756
|
+
typeof parsed !== 'object' ||
|
|
757
|
+
Array.isArray(parsed)) {
|
|
758
|
+
throw new Error('not object');
|
|
759
|
+
}
|
|
760
|
+
return parsed;
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
throw new CrowdyAgentError('AGENT_EVENT_CURSOR_INVALID', `${field} must contain one JSON object`, { field });
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function assertBudgetName(value) {
|
|
767
|
+
if (![
|
|
768
|
+
'REQUESTS',
|
|
769
|
+
'INPUT_TOKENS',
|
|
770
|
+
'OUTPUT_TOKENS',
|
|
771
|
+
'REASONING_TOKENS',
|
|
772
|
+
'PROVIDER_COST',
|
|
773
|
+
'TOOL_ROUNDS',
|
|
774
|
+
'WALL_CLOCK_MS',
|
|
775
|
+
'TOOL_CALLS',
|
|
776
|
+
'COMPILES',
|
|
777
|
+
].includes(value)) {
|
|
778
|
+
throw invalidEvent(`Unknown budget dimension ${value}`);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
function assertBudgetScope(value) {
|
|
782
|
+
if (!['TURN', 'SESSION', 'PLAYER_DAY'].includes(value)) {
|
|
783
|
+
throw invalidEvent(`Unknown budget scope ${value}`);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
function mapPayer(value) {
|
|
787
|
+
if (value !== 'PLATFORM' && value !== 'APP' && value !== 'USER') {
|
|
788
|
+
throw invalidEvent(`Unknown agent budget payer ${value}`);
|
|
789
|
+
}
|
|
790
|
+
return value;
|
|
791
|
+
}
|
|
792
|
+
function mapPreemptionReason(value) {
|
|
793
|
+
const reasons = [
|
|
794
|
+
'HUMAN_INPUT',
|
|
795
|
+
'HUMAN_EDIT',
|
|
796
|
+
'HUMAN_STOP',
|
|
797
|
+
'ESCAPE',
|
|
798
|
+
'DEATH',
|
|
799
|
+
'CONTEXT_CHANGED',
|
|
800
|
+
'PERMISSION_CHANGED',
|
|
801
|
+
'ADMISSION_CHANGED',
|
|
802
|
+
'CONTROL_TARGET_CHANGED',
|
|
803
|
+
'DISCONNECTED',
|
|
804
|
+
'CLIENT_REATTACHED',
|
|
805
|
+
'QUOTA_FAILURE',
|
|
806
|
+
'BUDGET_FAILURE',
|
|
807
|
+
'OPERATOR_KILL',
|
|
808
|
+
'LEASE_EXPIRED',
|
|
809
|
+
'SESSION_CLOSED',
|
|
810
|
+
];
|
|
811
|
+
if (!reasons.includes(value)) {
|
|
812
|
+
throw invalidEvent(`Unknown agent preemption reason ${value}`);
|
|
813
|
+
}
|
|
814
|
+
return value;
|
|
815
|
+
}
|
|
816
|
+
function invalidEvent(message) {
|
|
817
|
+
return new CrowdyAgentError('AGENT_EVENT_CURSOR_INVALID', message);
|
|
818
|
+
}
|
|
819
|
+
function mapGraphQLErrors(errors) {
|
|
820
|
+
const payloads = errors.filter((error) => error !== null &&
|
|
821
|
+
typeof error === 'object' &&
|
|
822
|
+
typeof error.message === 'string');
|
|
823
|
+
return mapTransportError(new CrowdyGraphQLError(payloads.length > 0
|
|
824
|
+
? payloads
|
|
825
|
+
: [{ message: 'Agent subscription failed' }]));
|
|
826
|
+
}
|
|
827
|
+
function mapTransportError(error) {
|
|
828
|
+
if (error instanceof CrowdyAgentError)
|
|
829
|
+
return error;
|
|
830
|
+
if (error instanceof CrowdyGraphQLError) {
|
|
831
|
+
const code = error.code;
|
|
832
|
+
if (typeof code === 'string' &&
|
|
833
|
+
(code.startsWith('AGENT_') ||
|
|
834
|
+
code === 'CROWDY_STUDIO_REVISION_CONFLICT')) {
|
|
835
|
+
return new CrowdyAgentError(code, error.message, {
|
|
836
|
+
retryable: error.extensions?.retryable === true,
|
|
837
|
+
...(typeof error.extensions?.remediation === 'string'
|
|
838
|
+
? { remediation: error.extensions.remediation }
|
|
839
|
+
: {}),
|
|
840
|
+
...(typeof error.extensions?.field === 'string'
|
|
841
|
+
? { field: error.extensions.field }
|
|
842
|
+
: {}),
|
|
843
|
+
...(typeof error.extensions?.requiredScope === 'string'
|
|
844
|
+
? { requiredScope: error.extensions.requiredScope }
|
|
845
|
+
: {}),
|
|
846
|
+
cause: error,
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
return error;
|
|
850
|
+
}
|
|
851
|
+
if (Array.isArray(error))
|
|
852
|
+
return mapGraphQLErrors(error);
|
|
853
|
+
return new CrowdyAgentError('AGENT_DISCONNECTED', 'Crowdy agent GraphQL transport disconnected', { retryable: true, cause: error });
|
|
854
|
+
}
|