@crowdedkingdoms/crowdyjs 11.0.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +118 -0
- package/README.md +208 -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 +40 -0
- package/dist/crowdy-studio/agent-dom-shell.d.ts.map +1 -0
- package/dist/crowdy-studio/agent-dom-shell.js +354 -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 +4 -1
- package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.js +6 -1
- package/dist/crowdy-studio/index.d.ts +6 -3
- package/dist/crowdy-studio/index.d.ts.map +1 -1
- package/dist/crowdy-studio/index.js +3 -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 +22 -1
- package/dist/crowdy-studio/mount.d.ts.map +1 -1
- package/dist/crowdy-studio/mount.js +163 -2
- 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 +5 -3
- 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/index.d.ts +5 -0
- package/dist/player-host/index.d.ts.map +1 -0
- package/dist/player-host/index.js +3 -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 +12 -2
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { CrowdyAgentError, CrowdyAgentOutcomeUnknownError, toAgentError, } from './errors.js';
|
|
2
|
+
import { canonicalJson, sha256Digest } from './schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Exact browser tool router with execute-once semantics. It has no fallback
|
|
5
|
+
* executor: unknown names, raw SDK access, and missing handlers fail closed.
|
|
6
|
+
*/
|
|
7
|
+
export class CrowdyAgentBrowserToolDispatcher {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.records = new Map();
|
|
11
|
+
this.active = new Map();
|
|
12
|
+
this.now = options.now ?? Date.now;
|
|
13
|
+
for (const name of Object.keys(options.handlers)) {
|
|
14
|
+
const matches = options.registry
|
|
15
|
+
.list({ executor: 'BROWSER' })
|
|
16
|
+
.filter(({ descriptor }) => descriptor.name === name);
|
|
17
|
+
if (matches.length === 0) {
|
|
18
|
+
throw new CrowdyAgentError('AGENT_TOOL_UNKNOWN', `Browser handler ${name} is not an exact registered browser tool`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
dispatch(invocation) {
|
|
23
|
+
if (typeof invocation.toolCallId !== 'string' ||
|
|
24
|
+
invocation.toolCallId.length < 1 ||
|
|
25
|
+
invocation.toolCallId.length > 128) {
|
|
26
|
+
return this.execute(invocation);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
// Bound arguments before canonical fingerprinting or cache insertion.
|
|
30
|
+
this.options.registry.validateInput(invocation.name, invocation.version, invocation.arguments);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return this.execute(invocation);
|
|
34
|
+
}
|
|
35
|
+
const fingerprint = invocationFingerprint(invocation);
|
|
36
|
+
const previous = this.records.get(invocation.toolCallId);
|
|
37
|
+
if (previous) {
|
|
38
|
+
if (previous.fingerprint !== fingerprint) {
|
|
39
|
+
return Promise.reject(new CrowdyAgentError('AGENT_IDEMPOTENCY_CONFLICT', `Tool call ${invocation.toolCallId} was replayed with different arguments`));
|
|
40
|
+
}
|
|
41
|
+
return previous.promise;
|
|
42
|
+
}
|
|
43
|
+
const max = this.options.maxRememberedCalls ?? 2048;
|
|
44
|
+
if (this.records.size >= max) {
|
|
45
|
+
return Promise.reject(new CrowdyAgentError('AGENT_RATE_LIMITED', 'Browser execute-once cache is full; attach a fresh session before continuing'));
|
|
46
|
+
}
|
|
47
|
+
const promise = this.execute(invocation);
|
|
48
|
+
this.records.set(invocation.toolCallId, { fingerprint, promise });
|
|
49
|
+
return promise;
|
|
50
|
+
}
|
|
51
|
+
has(toolCallId) {
|
|
52
|
+
return this.records.has(toolCallId);
|
|
53
|
+
}
|
|
54
|
+
/** Abort pending browser work during human or context preemption. */
|
|
55
|
+
cancelActive() {
|
|
56
|
+
for (const controller of this.active.values())
|
|
57
|
+
controller.abort();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Cache lifetime is the attached session. Call only after that session is
|
|
61
|
+
* closed or fenced; clearing during a live session could repeat an effect.
|
|
62
|
+
*/
|
|
63
|
+
clearClosedSession() {
|
|
64
|
+
this.cancelActive();
|
|
65
|
+
this.records.clear();
|
|
66
|
+
}
|
|
67
|
+
async execute(invocation) {
|
|
68
|
+
const startedMs = this.now();
|
|
69
|
+
const startedAt = new Date(startedMs).toISOString();
|
|
70
|
+
let entry;
|
|
71
|
+
let activeAbort = null;
|
|
72
|
+
try {
|
|
73
|
+
this.validateEnvelope(invocation, startedMs);
|
|
74
|
+
entry = this.options.registry.require(invocation.name, invocation.version);
|
|
75
|
+
if (entry.descriptor.executor !== 'BROWSER') {
|
|
76
|
+
throw new CrowdyAgentError('AGENT_TOOL_UNKNOWN', `${invocation.name} is not a browser-executed tool`);
|
|
77
|
+
}
|
|
78
|
+
if (entry.descriptorDigest !== invocation.descriptorDigest) {
|
|
79
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', `${invocation.name} descriptor digest changed`);
|
|
80
|
+
}
|
|
81
|
+
if (this.options.getMode &&
|
|
82
|
+
!entry.descriptor.modes.includes(this.options.getMode())) {
|
|
83
|
+
throw new CrowdyAgentError('AGENT_SCOPE_DENIED', `${invocation.name} is unavailable in the selected mode`);
|
|
84
|
+
}
|
|
85
|
+
if (entry.descriptor.approval.policy === 'REQUIRED' &&
|
|
86
|
+
!invocation.approvalGrant) {
|
|
87
|
+
throw new CrowdyAgentError('AGENT_APPROVAL_REQUIRED', `${invocation.name} requires exact human approval`);
|
|
88
|
+
}
|
|
89
|
+
this.options.registry.validateInput(invocation.name, invocation.version, invocation.arguments);
|
|
90
|
+
if (!isRecord(invocation.arguments)) {
|
|
91
|
+
throw new CrowdyAgentError('AGENT_TOOL_INPUT_INVALID', 'Browser tool arguments must be an object');
|
|
92
|
+
}
|
|
93
|
+
const handler = this.options.handlers[invocation.name];
|
|
94
|
+
if (!handler) {
|
|
95
|
+
throw new CrowdyAgentError('AGENT_HOST_UNAVAILABLE', `No browser host implements ${invocation.name}`);
|
|
96
|
+
}
|
|
97
|
+
const deadlineMs = Date.parse(invocation.deadline);
|
|
98
|
+
const remaining = Math.min(entry.descriptor.timeoutMs, Math.max(0, deadlineMs - startedMs));
|
|
99
|
+
const abort = new AbortController();
|
|
100
|
+
activeAbort = abort;
|
|
101
|
+
this.active.set(invocation.toolCallId, abort);
|
|
102
|
+
const output = await runWithDeadline(Promise.resolve(handler(invocation.arguments, {
|
|
103
|
+
invocation,
|
|
104
|
+
signal: abort.signal,
|
|
105
|
+
})), remaining, abort);
|
|
106
|
+
if (abort.signal.aborted) {
|
|
107
|
+
throw new CrowdyAgentError('AGENT_CANCELLED', 'Browser tool was cancelled before its result was accepted');
|
|
108
|
+
}
|
|
109
|
+
if (invocation.contextVersion !== this.options.getContextVersion()) {
|
|
110
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', 'Browser tool context changed before its result was accepted');
|
|
111
|
+
}
|
|
112
|
+
this.options.registry.validateOutput(invocation.name, invocation.version, output);
|
|
113
|
+
return {
|
|
114
|
+
protocolVersion: 'crowdy.tool-result/1',
|
|
115
|
+
toolCallId: invocation.toolCallId,
|
|
116
|
+
status: 'SUCCEEDED',
|
|
117
|
+
output,
|
|
118
|
+
observedContextVersion: this.options.getContextVersion(),
|
|
119
|
+
startedAt,
|
|
120
|
+
finishedAt: new Date(this.now()).toISOString(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const registered = this.options.registry.get(invocation.name, invocation.version);
|
|
125
|
+
const timedOut = error instanceof CrowdyAgentError && error.code === 'AGENT_TOOL_TIMEOUT';
|
|
126
|
+
const ambiguous = error instanceof CrowdyAgentOutcomeUnknownError ||
|
|
127
|
+
(timedOut &&
|
|
128
|
+
registered !== undefined &&
|
|
129
|
+
['TOOL_CALL_ONCE', 'NON_RETRYABLE'].includes(registered.descriptor.idempotency.class));
|
|
130
|
+
return {
|
|
131
|
+
protocolVersion: 'crowdy.tool-result/1',
|
|
132
|
+
toolCallId: invocation.toolCallId,
|
|
133
|
+
status: ambiguous
|
|
134
|
+
? 'OUTCOME_UNKNOWN'
|
|
135
|
+
: timedOut
|
|
136
|
+
? 'TIMED_OUT'
|
|
137
|
+
: error instanceof CrowdyAgentError &&
|
|
138
|
+
error.code === 'AGENT_CANCELLED'
|
|
139
|
+
? 'CANCELLED'
|
|
140
|
+
: 'FAILED',
|
|
141
|
+
error: toAgentError(ambiguous
|
|
142
|
+
? new CrowdyAgentOutcomeUnknownError(error instanceof Error ? error.message : undefined)
|
|
143
|
+
: error, timedOut ? 'AGENT_TOOL_TIMEOUT' : 'AGENT_TOOL_FAILED'),
|
|
144
|
+
observedContextVersion: this.options.getContextVersion(),
|
|
145
|
+
startedAt,
|
|
146
|
+
finishedAt: new Date(this.now()).toISOString(),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
if (activeAbort)
|
|
151
|
+
this.active.delete(invocation.toolCallId);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
validateEnvelope(invocation, now) {
|
|
155
|
+
if (invocation.protocolVersion !== 'crowdy.tool-call/1') {
|
|
156
|
+
throw new CrowdyAgentError('AGENT_TOOL_INPUT_INVALID', 'Unsupported browser tool-call protocol');
|
|
157
|
+
}
|
|
158
|
+
for (const [field, value, max] of [
|
|
159
|
+
['sessionId', invocation.sessionId, 128],
|
|
160
|
+
['runId', invocation.runId, 128],
|
|
161
|
+
['toolCallId', invocation.toolCallId, 128],
|
|
162
|
+
['contextVersion', invocation.contextVersion, 128],
|
|
163
|
+
]) {
|
|
164
|
+
if (typeof value !== 'string' ||
|
|
165
|
+
value.length < 1 ||
|
|
166
|
+
value.length > max) {
|
|
167
|
+
throw new CrowdyAgentError('AGENT_TOOL_INPUT_INVALID', `${field} is outside protocol bounds`, { field });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const currentSessionId = this.options.getSessionId?.();
|
|
171
|
+
if (currentSessionId && invocation.sessionId !== currentSessionId) {
|
|
172
|
+
throw new CrowdyAgentError('AGENT_SESSION_NOT_FOUND', 'Browser tool dispatch belongs to a different session');
|
|
173
|
+
}
|
|
174
|
+
if (typeof invocation.descriptorDigest !== 'string' ||
|
|
175
|
+
typeof invocation.argumentHash !== 'string' ||
|
|
176
|
+
!/^sha256:[0-9a-f]{64}$/u.test(invocation.descriptorDigest) ||
|
|
177
|
+
!/^sha256:[0-9a-f]{64}$/u.test(invocation.argumentHash) ||
|
|
178
|
+
(invocation.approvalGrant !== undefined &&
|
|
179
|
+
(typeof invocation.approvalGrant !== 'string' ||
|
|
180
|
+
invocation.approvalGrant.length < 1)) ||
|
|
181
|
+
(invocation.approvalGrant?.length ?? 0) > 512 ||
|
|
182
|
+
(invocation.idempotencyKey !== undefined &&
|
|
183
|
+
(typeof invocation.idempotencyKey !== 'string' ||
|
|
184
|
+
invocation.idempotencyKey.length < 1)) ||
|
|
185
|
+
(invocation.idempotencyKey?.length ?? 0) > 240) {
|
|
186
|
+
throw new CrowdyAgentError('AGENT_TOOL_INPUT_INVALID', 'Browser tool dispatch contains invalid digest or capability metadata');
|
|
187
|
+
}
|
|
188
|
+
const currentEpoch = this.options.getClientEpoch();
|
|
189
|
+
if (!currentEpoch ||
|
|
190
|
+
!invocation.clientEpoch ||
|
|
191
|
+
invocation.clientEpoch !== currentEpoch) {
|
|
192
|
+
throw new CrowdyAgentError('AGENT_CLIENT_EPOCH_STALE', 'Browser tool dispatch belongs to a stale client epoch');
|
|
193
|
+
}
|
|
194
|
+
if (invocation.contextVersion !== this.options.getContextVersion()) {
|
|
195
|
+
throw new CrowdyAgentError('AGENT_CONTEXT_STALE', 'Browser tool dispatch belongs to a stale app, project, or game context');
|
|
196
|
+
}
|
|
197
|
+
if (typeof invocation.deadline !== 'string' ||
|
|
198
|
+
invocation.deadline.length < 20 ||
|
|
199
|
+
invocation.deadline.length > 40) {
|
|
200
|
+
throw new CrowdyAgentError('AGENT_TOOL_INPUT_INVALID', 'Browser tool deadline is invalid');
|
|
201
|
+
}
|
|
202
|
+
const deadline = Date.parse(invocation.deadline);
|
|
203
|
+
if (!Number.isFinite(deadline) || deadline <= now) {
|
|
204
|
+
throw new CrowdyAgentError('AGENT_TOOL_TIMEOUT', 'Browser tool deadline has expired');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function invocationFingerprint(invocation) {
|
|
209
|
+
return sha256Digest(canonicalJson({
|
|
210
|
+
protocolVersion: invocation.protocolVersion,
|
|
211
|
+
sessionId: invocation.sessionId,
|
|
212
|
+
runId: invocation.runId,
|
|
213
|
+
toolCallId: invocation.toolCallId,
|
|
214
|
+
name: invocation.name,
|
|
215
|
+
version: invocation.version,
|
|
216
|
+
descriptorDigest: invocation.descriptorDigest,
|
|
217
|
+
arguments: invocation.arguments,
|
|
218
|
+
argumentHash: invocation.argumentHash,
|
|
219
|
+
contextVersion: invocation.contextVersion,
|
|
220
|
+
...(invocation.clientEpoch
|
|
221
|
+
? { clientEpoch: invocation.clientEpoch }
|
|
222
|
+
: {}),
|
|
223
|
+
...(invocation.leaseId ? { leaseId: invocation.leaseId } : {}),
|
|
224
|
+
...(invocation.approvalGrant
|
|
225
|
+
? { approvalGrant: invocation.approvalGrant }
|
|
226
|
+
: {}),
|
|
227
|
+
...(invocation.idempotencyKey
|
|
228
|
+
? { idempotencyKey: invocation.idempotencyKey }
|
|
229
|
+
: {}),
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
232
|
+
function runWithDeadline(operation, timeoutMs, abort) {
|
|
233
|
+
if (timeoutMs <= 0) {
|
|
234
|
+
abort.abort();
|
|
235
|
+
return Promise.reject(new CrowdyAgentError('AGENT_TOOL_TIMEOUT', 'Browser tool deadline expired'));
|
|
236
|
+
}
|
|
237
|
+
return new Promise((resolve, reject) => {
|
|
238
|
+
let timedOut = false;
|
|
239
|
+
const onAbort = () => {
|
|
240
|
+
if (!timedOut) {
|
|
241
|
+
clearTimeout(timer);
|
|
242
|
+
reject(new CrowdyAgentError('AGENT_CANCELLED', 'Browser tool was cancelled by human or context preemption'));
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
abort.signal.addEventListener('abort', onAbort, { once: true });
|
|
246
|
+
const timer = setTimeout(() => {
|
|
247
|
+
timedOut = true;
|
|
248
|
+
abort.abort();
|
|
249
|
+
reject(new CrowdyAgentError('AGENT_TOOL_TIMEOUT', `Browser tool exceeded its ${timeoutMs}ms deadline`));
|
|
250
|
+
}, timeoutMs);
|
|
251
|
+
operation.then((value) => {
|
|
252
|
+
clearTimeout(timer);
|
|
253
|
+
abort.signal.removeEventListener('abort', onAbort);
|
|
254
|
+
resolve(value);
|
|
255
|
+
}, (error) => {
|
|
256
|
+
clearTimeout(timer);
|
|
257
|
+
abort.signal.removeEventListener('abort', onAbort);
|
|
258
|
+
reject(error);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function isRecord(value) {
|
|
263
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
264
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { type AgentErrorV1 } from './errors.js';
|
|
2
|
+
import type { CrowdyAgentBrowserToolDispatcher } from './browser-dispatcher.js';
|
|
3
|
+
import type { CrowdyAgentApprovalV1, CrowdyAgentBudgetV1, CrowdyAgentCheckpointV1, CrowdyAgentEventV1, CrowdyAgentLeaseV1, CrowdyAgentMessageV1, CrowdyAgentMode, CrowdyAgentPreemptionReason, CrowdyAgentRegisteredToolV1, CrowdyAgentSessionV1, CrowdyAgentToolTimelineItemV1 } from './types.js';
|
|
4
|
+
import type { CrowdyAgentCreateSessionInputV1, CrowdyStudioAgentTransportV1 } from './transport.js';
|
|
5
|
+
export type CrowdyStudioAgentConnectionState = 'DISCONNECTED' | 'ATTACHING' | 'REPLAYING' | 'CONNECTED' | 'RECONNECTING' | 'ERROR';
|
|
6
|
+
export interface CrowdyStudioAgentStateV1 {
|
|
7
|
+
readonly connection: CrowdyStudioAgentConnectionState;
|
|
8
|
+
readonly session: CrowdyAgentSessionV1 | null;
|
|
9
|
+
readonly clientEpoch: string | null;
|
|
10
|
+
readonly lastContiguousSeq: string;
|
|
11
|
+
readonly lastAcknowledgedSeq: string;
|
|
12
|
+
readonly events: readonly CrowdyAgentEventV1[];
|
|
13
|
+
readonly messages: readonly CrowdyAgentMessageV1[];
|
|
14
|
+
readonly streamingText: string;
|
|
15
|
+
readonly tools: readonly CrowdyAgentToolTimelineItemV1[];
|
|
16
|
+
readonly approvals: readonly CrowdyAgentApprovalV1[];
|
|
17
|
+
readonly leases: readonly CrowdyAgentLeaseV1[];
|
|
18
|
+
readonly checkpoints: readonly CrowdyAgentCheckpointV1[];
|
|
19
|
+
readonly budget: CrowdyAgentBudgetV1 | null;
|
|
20
|
+
readonly toolDescriptors: readonly CrowdyAgentRegisteredToolV1[];
|
|
21
|
+
readonly lastHeartbeatAt: string | null;
|
|
22
|
+
readonly playLeaseFreshUntil: string | null;
|
|
23
|
+
readonly lastError: AgentErrorV1 | null;
|
|
24
|
+
readonly reconnectRequired: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface CrowdyStudioAgentControllerOptionsV1 {
|
|
27
|
+
readonly transport: CrowdyStudioAgentTransportV1;
|
|
28
|
+
readonly sessionId?: string;
|
|
29
|
+
readonly createSession?: CrowdyAgentCreateSessionInputV1 | (() => CrowdyAgentCreateSessionInputV1 | Promise<CrowdyAgentCreateSessionInputV1>);
|
|
30
|
+
/** Resolve the currently selected, fully saved Studio project at attach time. */
|
|
31
|
+
readonly resolveProjectBinding?: () => {
|
|
32
|
+
readonly projectId?: string;
|
|
33
|
+
readonly gridId?: string;
|
|
34
|
+
} | Promise<{
|
|
35
|
+
readonly projectId?: string;
|
|
36
|
+
readonly gridId?: string;
|
|
37
|
+
}>;
|
|
38
|
+
readonly browserDispatcher?: CrowdyAgentBrowserToolDispatcher;
|
|
39
|
+
/** Stable browser UUID reused across fresh attach epochs. */
|
|
40
|
+
readonly clientInstanceId?: string;
|
|
41
|
+
/** Flush autosave and validate conflicts before accepting a human turn. */
|
|
42
|
+
readonly beforeAgentWork?: (mode: CrowdyAgentMode) => void | Promise<void>;
|
|
43
|
+
/** Called synchronously for local preemption before transport cleanup. */
|
|
44
|
+
readonly onPreempt?: (reason: CrowdyAgentPreemptionReason) => void;
|
|
45
|
+
readonly onEpochAttached?: (clientEpoch: string) => void;
|
|
46
|
+
readonly onLeaseChanged?: (lease: CrowdyAgentLeaseV1) => void;
|
|
47
|
+
readonly createIdempotencyKey?: (operation: string) => string;
|
|
48
|
+
readonly historyPageSize?: number;
|
|
49
|
+
readonly maxRetainedEvents?: number;
|
|
50
|
+
readonly autoReconnect?: boolean;
|
|
51
|
+
readonly reconnectDelayMs?: number;
|
|
52
|
+
readonly maxReconnectAttempts?: number;
|
|
53
|
+
readonly heartbeatIntervalMs?: number;
|
|
54
|
+
readonly heartbeatStaleMs?: number;
|
|
55
|
+
readonly workspaceRenewIntervalMs?: number;
|
|
56
|
+
readonly onStateChange?: (state: CrowdyStudioAgentStateV1) => void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Durable session client for the `crowdy.studio-agent/1` protocol. The
|
|
60
|
+
* transport is injectable and contains no generated GraphQL dependency.
|
|
61
|
+
*/
|
|
62
|
+
export declare class CrowdyStudioAgentController {
|
|
63
|
+
private readonly options;
|
|
64
|
+
private state;
|
|
65
|
+
private readonly listeners;
|
|
66
|
+
private readonly buffered;
|
|
67
|
+
private readonly appliedEventIds;
|
|
68
|
+
private subscription;
|
|
69
|
+
private generation;
|
|
70
|
+
private drainPromise;
|
|
71
|
+
private acknowledgePromise;
|
|
72
|
+
private reconnectTimer;
|
|
73
|
+
private heartbeatTimer;
|
|
74
|
+
private workspaceRenewTimer;
|
|
75
|
+
private reconnectAttempts;
|
|
76
|
+
private keySequence;
|
|
77
|
+
private readonly clientInstanceId;
|
|
78
|
+
private pageVisible;
|
|
79
|
+
private destroyed;
|
|
80
|
+
constructor(options: CrowdyStudioAgentControllerOptionsV1);
|
|
81
|
+
getState(): CrowdyStudioAgentStateV1;
|
|
82
|
+
subscribe(listener: (state: CrowdyStudioAgentStateV1) => void): () => void;
|
|
83
|
+
setPageVisible(visible: boolean): void;
|
|
84
|
+
initialize(): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Fail closed when the human selects another project. The v1 Game API has no
|
|
87
|
+
* set-project mutation, so callers must create/remount a session for it.
|
|
88
|
+
*/
|
|
89
|
+
projectSelectionChanged(projectId: string | undefined): void;
|
|
90
|
+
reconnect(): Promise<void>;
|
|
91
|
+
sendMessage(content: string): Promise<{
|
|
92
|
+
runId: string;
|
|
93
|
+
}>;
|
|
94
|
+
setMode(mode: CrowdyAgentMode): Promise<void>;
|
|
95
|
+
approveTool(toolCallId: string, expectedArgumentHash?: string): Promise<void>;
|
|
96
|
+
rejectTool(toolCallId: string, reason?: string): Promise<void>;
|
|
97
|
+
grantPlayLease(input: {
|
|
98
|
+
readonly scopes: readonly string[];
|
|
99
|
+
readonly durationSeconds: number;
|
|
100
|
+
readonly controlledEntityId: string;
|
|
101
|
+
readonly hostCapabilityRevision: string;
|
|
102
|
+
}): Promise<CrowdyAgentLeaseV1>;
|
|
103
|
+
revokeLease(leaseId: string, reason?: CrowdyAgentPreemptionReason): Promise<void>;
|
|
104
|
+
pause(): Promise<void>;
|
|
105
|
+
resume(): Promise<void>;
|
|
106
|
+
cancelRun(runId?: string | undefined): Promise<void>;
|
|
107
|
+
/** Immediate human Stop: local preemption happens before transport calls. */
|
|
108
|
+
stop(): Promise<void>;
|
|
109
|
+
/** Editor changes synchronously preempt Build before best-effort cleanup. */
|
|
110
|
+
preemptForHumanEdit(): void;
|
|
111
|
+
restoreCheckpoint(checkpointId: string): Promise<void>;
|
|
112
|
+
close(): Promise<void>;
|
|
113
|
+
destroy(): void;
|
|
114
|
+
private attach;
|
|
115
|
+
private replayHistory;
|
|
116
|
+
private enqueueEvent;
|
|
117
|
+
private startDrain;
|
|
118
|
+
private bufferEvent;
|
|
119
|
+
private drainBuffered;
|
|
120
|
+
private applyEvent;
|
|
121
|
+
private dispatchBrowserTool;
|
|
122
|
+
private scheduleAcknowledge;
|
|
123
|
+
private handleDisconnect;
|
|
124
|
+
private refreshHeartbeat;
|
|
125
|
+
private sendHeartbeat;
|
|
126
|
+
private stopHeartbeat;
|
|
127
|
+
private refreshWorkspaceRenewal;
|
|
128
|
+
private renewWorkspaceLease;
|
|
129
|
+
private stopWorkspaceRenewal;
|
|
130
|
+
private scheduleReconnect;
|
|
131
|
+
private loadRemoteContext;
|
|
132
|
+
private assertProjectBinding;
|
|
133
|
+
private mutationContext;
|
|
134
|
+
private nextKey;
|
|
135
|
+
private patchSession;
|
|
136
|
+
private upsertLease;
|
|
137
|
+
private disconnectSubscription;
|
|
138
|
+
private requireSession;
|
|
139
|
+
private preemptLocal;
|
|
140
|
+
private update;
|
|
141
|
+
private fail;
|
|
142
|
+
private ensureAlive;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/crowdy-agent/controller.ts"],"names":[],"mappings":"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"}
|