@nowcrew/daemon 0.5.26 → 0.5.28
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/package.json +1 -1
- package/dist/attachments.js +0 -196
- package/dist/bound-im-decision.js +0 -22
- package/dist/completion-retransmitter.js +0 -77
- package/dist/computer-cli.js +0 -274
- package/dist/computer-profile-lock.js +0 -395
- package/dist/computer-profile.js +0 -364
- package/dist/computer-service.js +0 -358
- package/dist/config.js +0 -82
- package/dist/console-collapse.js +0 -13
- package/dist/console-formatter.js +0 -77
- package/dist/console-payload.js +0 -73
- package/dist/console.js +0 -329
- package/dist/daemon-startup-error.js +0 -30
- package/dist/execution-backend.js +0 -44
- package/dist/execution-event-limit.js +0 -64
- package/dist/execution-journal-lock.js +0 -421
- package/dist/execution-journal.js +0 -716
- package/dist/execution-protocol.js +0 -342
- package/dist/execution-recovery.js +0 -95
- package/dist/execution-runner.js +0 -659
- package/dist/execution-supervisor-child.js +0 -236
- package/dist/execution-supervisor.js +0 -302
- package/dist/execution-telemetry-journal.js +0 -71
- package/dist/external-output.js +0 -114
- package/dist/i18n.js +0 -64
- package/dist/json-result.js +0 -27
- package/dist/list-models.js +0 -92
- package/dist/local-executor.js +0 -439
- package/dist/log-format.js +0 -10
- package/dist/machine-info.js +0 -124
- package/dist/main.js +0 -118
- package/dist/normalize.js +0 -170
- package/dist/origin-decision.js +0 -44
- package/dist/platform.js +0 -8
- package/dist/prompt.js +0 -307
- package/dist/provider-env.js +0 -90
- package/dist/runner.js +0 -234
- package/dist/runtime-cancellation.js +0 -74
- package/dist/runtime-capabilities.js +0 -43
- package/dist/runtime-path.js +0 -60
- package/dist/runtimes/claude.js +0 -51
- package/dist/runtimes/codex-app-server-runner.js +0 -340
- package/dist/runtimes/codex-deepseek-catalog.js +0 -7
- package/dist/runtimes/codex-deepseek-config.js +0 -50
- package/dist/runtimes/codex.js +0 -53
- package/dist/runtimes/kimi-acp-runner.js +0 -364
- package/dist/runtimes/kimi.js +0 -45
- package/dist/runtimes/progress-watchdog.js +0 -26
- package/dist/scheduled-report.js +0 -51
- package/dist/scheduled-run-report.js +0 -57
- package/dist/serve-lifecycle.js +0 -82
- package/dist/serve.js +0 -868
- package/dist/session.js +0 -82
- package/dist/shared-execution-slots.js +0 -68
- package/dist/shutdown-deadline.js +0 -32
- package/dist/skill-preview.js +0 -21
- package/dist/skills.js +0 -56
- package/dist/slog.js +0 -228
- package/dist/supervised-runtime.js +0 -104
- package/dist/token.js +0 -24
- package/dist/unified-diff.js +0 -84
- package/dist/websocket-shutdown.js +0 -53
- package/dist/win32-job-object.js +0 -193
- package/dist/workspace-fs.js +0 -80
- package/dist/workspace-import.js +0 -127
- package/dist/workspace.js +0 -148
package/dist/execution-runner.js
DELETED
|
@@ -1,659 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { DaemonToServerExecutionFrameSchema, ExecutionCompletedSchema, ExecutionRejectedSchema, ExecutionStartSchema, } from "./execution-protocol.js";
|
|
4
|
-
import { JournalConflictError } from "./execution-journal.js";
|
|
5
|
-
import { boundExecutionFrame } from "./execution-event-limit.js";
|
|
6
|
-
import { mintAgentToken } from "./token.js";
|
|
7
|
-
import { executeLocal, withLocalExecutionFacts, } from "./local-executor.js";
|
|
8
|
-
import { startDormantSupervisor, } from "./execution-supervisor.js";
|
|
9
|
-
import { CLAUDE_EFFORT_LEVELS } from "./runtimes/claude.js";
|
|
10
|
-
import { CODEX_EFFORT_LEVELS } from "./runtimes/codex.js";
|
|
11
|
-
import { KIMI_EFFORT_LEVELS } from "./runtimes/kimi.js";
|
|
12
|
-
import { executionBackendCapability } from "./execution-backend.js";
|
|
13
|
-
import { readBoundImDecisionFile, resetBoundImDecisionFile } from "./bound-im-decision.js";
|
|
14
|
-
import { RuntimeCancelledError } from "./runtime-cancellation.js";
|
|
15
|
-
import { supervisorLaunch } from "./supervised-runtime.js";
|
|
16
|
-
export { supervisorLaunch } from "./supervised-runtime.js";
|
|
17
|
-
const ACTIVITY_KIND = {
|
|
18
|
-
init: "working",
|
|
19
|
-
text: "thinking",
|
|
20
|
-
reading: "reading",
|
|
21
|
-
sending: "sending",
|
|
22
|
-
checking: "checking",
|
|
23
|
-
claiming: "claiming",
|
|
24
|
-
crew: "working",
|
|
25
|
-
tool: "working",
|
|
26
|
-
tool_result: "working",
|
|
27
|
-
done: "done",
|
|
28
|
-
error: "error",
|
|
29
|
-
};
|
|
30
|
-
function canonical(value) {
|
|
31
|
-
if (Array.isArray(value))
|
|
32
|
-
return value.map(canonical);
|
|
33
|
-
if (value !== null && typeof value === "object") {
|
|
34
|
-
return Object.fromEntries(Object.entries(value)
|
|
35
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
36
|
-
.map(([key, nested]) => [key, canonical(nested)]));
|
|
37
|
-
}
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
40
|
-
export function hashExecutionSpec(spec) {
|
|
41
|
-
return createHash("sha256").update(JSON.stringify(canonical(spec))).digest("hex");
|
|
42
|
-
}
|
|
43
|
-
async function reportBestEffort(report, frame, timeoutMs) {
|
|
44
|
-
let timeout;
|
|
45
|
-
try {
|
|
46
|
-
return await Promise.race([
|
|
47
|
-
Promise.resolve(report(frame)).then(() => true, () => false),
|
|
48
|
-
new Promise((resolve) => {
|
|
49
|
-
timeout = setTimeout(() => resolve(false), timeoutMs);
|
|
50
|
-
}),
|
|
51
|
-
]);
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
finally {
|
|
57
|
-
if (timeout !== undefined)
|
|
58
|
-
clearTimeout(timeout);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
const DEFAULT_TELEMETRY_DRAIN_TIMEOUT_MS = 2_000;
|
|
62
|
-
const DEFAULT_TELEMETRY_MAX_PENDING_FRAMES = 256;
|
|
63
|
-
const DEFAULT_TELEMETRY_MAX_PENDING_BYTES = 1_048_576;
|
|
64
|
-
const MAX_TIMER_MS = 2_147_483_647;
|
|
65
|
-
class TelemetryQueue {
|
|
66
|
-
report;
|
|
67
|
-
timeoutMs;
|
|
68
|
-
maxPendingFrames;
|
|
69
|
-
maxPendingBytes;
|
|
70
|
-
pending = [];
|
|
71
|
-
idleWaiters = [];
|
|
72
|
-
pendingBytes = 0;
|
|
73
|
-
running = false;
|
|
74
|
-
closed = false;
|
|
75
|
-
constructor(report, timeoutMs, maxPendingFrames, maxPendingBytes) {
|
|
76
|
-
this.report = report;
|
|
77
|
-
this.timeoutMs = timeoutMs;
|
|
78
|
-
this.maxPendingFrames = maxPendingFrames;
|
|
79
|
-
this.maxPendingBytes = maxPendingBytes;
|
|
80
|
-
}
|
|
81
|
-
enqueue(frame) {
|
|
82
|
-
if (this.closed)
|
|
83
|
-
return;
|
|
84
|
-
const bytes = Buffer.byteLength(JSON.stringify(frame), "utf8");
|
|
85
|
-
if (this.pending.length >= this.maxPendingFrames
|
|
86
|
-
|| this.pendingBytes + bytes > this.maxPendingBytes)
|
|
87
|
-
return;
|
|
88
|
-
this.pending.push({ frame, bytes });
|
|
89
|
-
this.pendingBytes += bytes;
|
|
90
|
-
void this.pump();
|
|
91
|
-
}
|
|
92
|
-
async closeAndDrain() {
|
|
93
|
-
this.closed = true;
|
|
94
|
-
if (!this.running && this.pending.length === 0)
|
|
95
|
-
return;
|
|
96
|
-
let timeout;
|
|
97
|
-
let resolveIdle;
|
|
98
|
-
const idleWaiter = () => resolveIdle();
|
|
99
|
-
const drained = await Promise.race([
|
|
100
|
-
new Promise((resolve) => {
|
|
101
|
-
resolveIdle = () => resolve(true);
|
|
102
|
-
this.idleWaiters.push(idleWaiter);
|
|
103
|
-
}),
|
|
104
|
-
new Promise((resolve) => {
|
|
105
|
-
timeout = setTimeout(() => resolve(false), this.timeoutMs);
|
|
106
|
-
}),
|
|
107
|
-
]);
|
|
108
|
-
if (timeout !== undefined)
|
|
109
|
-
clearTimeout(timeout);
|
|
110
|
-
if (!drained) {
|
|
111
|
-
const waiterIndex = this.idleWaiters.indexOf(idleWaiter);
|
|
112
|
-
if (waiterIndex >= 0)
|
|
113
|
-
this.idleWaiters.splice(waiterIndex, 1);
|
|
114
|
-
this.fuse();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
async pump() {
|
|
118
|
-
if (this.running)
|
|
119
|
-
return;
|
|
120
|
-
this.running = true;
|
|
121
|
-
while (this.pending.length > 0) {
|
|
122
|
-
const pending = this.pending.shift();
|
|
123
|
-
if (pending !== undefined) {
|
|
124
|
-
this.pendingBytes -= pending.bytes;
|
|
125
|
-
await this.reportBounded(pending.frame);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
this.running = false;
|
|
129
|
-
for (const resolve of this.idleWaiters.splice(0))
|
|
130
|
-
resolve();
|
|
131
|
-
}
|
|
132
|
-
async reportBounded(frame) {
|
|
133
|
-
const settled = await reportBestEffort(this.report, frame, this.timeoutMs);
|
|
134
|
-
if (!settled)
|
|
135
|
-
this.fuse();
|
|
136
|
-
}
|
|
137
|
-
fuse() {
|
|
138
|
-
this.closed = true;
|
|
139
|
-
this.pending.length = 0;
|
|
140
|
-
this.pendingBytes = 0;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
function telemetryDrainTimeout(value) {
|
|
144
|
-
if (value === undefined || !Number.isFinite(value))
|
|
145
|
-
return DEFAULT_TELEMETRY_DRAIN_TIMEOUT_MS;
|
|
146
|
-
return Math.min(MAX_TIMER_MS, Math.max(1, Math.floor(value)));
|
|
147
|
-
}
|
|
148
|
-
function positiveTelemetryLimit(value, fallback) {
|
|
149
|
-
if (value === undefined || !Number.isFinite(value))
|
|
150
|
-
return fallback;
|
|
151
|
-
return Math.max(1, Math.floor(value));
|
|
152
|
-
}
|
|
153
|
-
function effectivePermission(spec, config) {
|
|
154
|
-
const requested = spec.permissions.requested === "local_default"
|
|
155
|
-
? (config.dangerous ? "full_access" : "workspace_write")
|
|
156
|
-
: spec.permissions.requested;
|
|
157
|
-
if (!config.dangerous && requested === "full_access")
|
|
158
|
-
return "workspace_write";
|
|
159
|
-
return requested;
|
|
160
|
-
}
|
|
161
|
-
function validReasoning(spec) {
|
|
162
|
-
const reasoning = spec.runtime.reasoning;
|
|
163
|
-
if (reasoning === undefined || reasoning === "default")
|
|
164
|
-
return true;
|
|
165
|
-
if (spec.runtime.name === "claude") {
|
|
166
|
-
return CLAUDE_EFFORT_LEVELS.includes(reasoning);
|
|
167
|
-
}
|
|
168
|
-
if (spec.runtime.name === "codex") {
|
|
169
|
-
return CODEX_EFFORT_LEVELS.includes(reasoning);
|
|
170
|
-
}
|
|
171
|
-
return KIMI_EFFORT_LEVELS.includes(reasoning);
|
|
172
|
-
}
|
|
173
|
-
function launchProviderConfig(config) {
|
|
174
|
-
if (config === undefined)
|
|
175
|
-
return {};
|
|
176
|
-
return {
|
|
177
|
-
...(config.provider === undefined ? {} : { provider: config.provider }),
|
|
178
|
-
...(config.providerBaseUrl === undefined ? {} : { providerBaseUrl: config.providerBaseUrl }),
|
|
179
|
-
...(config.providerApiKey === undefined ? {} : { providerApiKey: config.providerApiKey }),
|
|
180
|
-
...(config.providerAuthMode === undefined ? {} : { providerAuthMode: config.providerAuthMode }),
|
|
181
|
-
...(config.providerSmallFastModel === undefined
|
|
182
|
-
? {}
|
|
183
|
-
: { providerSmallFastModel: config.providerSmallFastModel }),
|
|
184
|
-
...(config.envVars === undefined ? {} : { envVars: config.envVars }),
|
|
185
|
-
...(config.description === undefined ? {} : { description: config.description }),
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
function rejection(executionId, reason, message, at) {
|
|
189
|
-
return ExecutionRejectedSchema.parse({
|
|
190
|
-
type: "execution:rejected",
|
|
191
|
-
protocolVersion: 1,
|
|
192
|
-
executionId,
|
|
193
|
-
reason,
|
|
194
|
-
message,
|
|
195
|
-
at,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
function admission(spec, config, dependencies, at) {
|
|
199
|
-
const backend = executionBackendCapability(dependencies.platform ?? process.platform);
|
|
200
|
-
if (!backend.supported) {
|
|
201
|
-
return { rejected: rejection(spec.executionId, "capability_missing", backend.reason, at) };
|
|
202
|
-
}
|
|
203
|
-
const promptBytes = Buffer.byteLength(spec.instructions.systemPrompt, "utf8")
|
|
204
|
-
+ Buffer.byteLength(spec.instructions.wakePrompt, "utf8");
|
|
205
|
-
if (promptBytes > config.executionLimits.maxPromptBytes) {
|
|
206
|
-
return { rejected: rejection(spec.executionId, "resource_limit", "Prompt exceeds the local byte limit", at) };
|
|
207
|
-
}
|
|
208
|
-
if (spec.runtime.timeoutMs !== undefined
|
|
209
|
-
&& spec.runtime.timeoutMs > config.executionLimits.maxTimeoutMs) {
|
|
210
|
-
return { rejected: rejection(spec.executionId, "resource_limit", "Timeout exceeds the local limit", at) };
|
|
211
|
-
}
|
|
212
|
-
if (!dependencies.facts.availableRuntimes.includes(spec.runtime.name)) {
|
|
213
|
-
return { rejected: rejection(spec.executionId, "runtime_unavailable", "Requested runtime is unavailable", at) };
|
|
214
|
-
}
|
|
215
|
-
if (!validReasoning(spec)) {
|
|
216
|
-
return { rejected: rejection(spec.executionId, "invalid_spec", "Reasoning mode is unsupported by the runtime", at) };
|
|
217
|
-
}
|
|
218
|
-
if (!Number.isInteger(dependencies.facts.activeForAgent)
|
|
219
|
-
|| !Number.isInteger(dependencies.facts.queuedForAgent)
|
|
220
|
-
|| dependencies.facts.activeForAgent < 0
|
|
221
|
-
|| dependencies.facts.queuedForAgent < 0) {
|
|
222
|
-
return { rejected: rejection(spec.executionId, "invalid_spec", "Invalid local resource facts", at) };
|
|
223
|
-
}
|
|
224
|
-
const slotInvalid = dependencies.slot?.state === "ready"
|
|
225
|
-
? dependencies.facts.activeForAgent >= config.executionLimits.maxParallelPerAgent
|
|
226
|
-
: dependencies.slot?.state === "queued"
|
|
227
|
-
? dependencies.facts.activeForAgent < config.executionLimits.maxParallelPerAgent
|
|
228
|
-
|| dependencies.facts.queuedForAgent >= config.executionLimits.maxQueuedPerAgent
|
|
229
|
-
: false;
|
|
230
|
-
if (slotInvalid || (dependencies.slot === undefined && (dependencies.facts.activeForAgent >= config.executionLimits.maxParallelPerAgent
|
|
231
|
-
|| dependencies.facts.queuedForAgent >= config.executionLimits.maxQueuedPerAgent))) {
|
|
232
|
-
return { rejected: rejection(spec.executionId, "resource_limit", "Local execution capacity is exhausted", at) };
|
|
233
|
-
}
|
|
234
|
-
const permission = effectivePermission(spec, config);
|
|
235
|
-
if (spec.runtime.name === "kimi" && permission !== "full_access") {
|
|
236
|
-
return { rejected: rejection(spec.executionId, "local_policy_denied", `Kimi cannot enforce ${permission} permission`, at) };
|
|
237
|
-
}
|
|
238
|
-
return { spec, permission };
|
|
239
|
-
}
|
|
240
|
-
class ExecutionCancelledError extends Error {
|
|
241
|
-
constructor() {
|
|
242
|
-
super("Execution cancelled before completion");
|
|
243
|
-
this.name = "ExecutionCancelledError";
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
async function cancellable(promise, cancellation) {
|
|
247
|
-
if (cancellation === undefined)
|
|
248
|
-
return promise;
|
|
249
|
-
if (cancellation.isRequested())
|
|
250
|
-
throw new ExecutionCancelledError();
|
|
251
|
-
return Promise.race([
|
|
252
|
-
promise,
|
|
253
|
-
cancellation.requested.then(() => { throw new ExecutionCancelledError(); }),
|
|
254
|
-
]);
|
|
255
|
-
}
|
|
256
|
-
function failedCompletion(spec, error, startedAt, finishedAt) {
|
|
257
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
258
|
-
return ExecutionCompletedSchema.parse({
|
|
259
|
-
type: "execution:completed",
|
|
260
|
-
protocolVersion: 1,
|
|
261
|
-
executionId: spec.executionId,
|
|
262
|
-
outcome: "failed",
|
|
263
|
-
errorCode: "local_execution_failed",
|
|
264
|
-
errorMessage: message || "Unknown local execution failure",
|
|
265
|
-
runtime: spec.runtime.name,
|
|
266
|
-
...(spec.runtime.model === undefined ? {} : { model: spec.runtime.model }),
|
|
267
|
-
resumed: false,
|
|
268
|
-
startedAt,
|
|
269
|
-
finishedAt,
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
export async function runExecution(config, input, dependencies) {
|
|
273
|
-
const now = dependencies.now ?? (() => new Date());
|
|
274
|
-
const initialAt = now().toISOString();
|
|
275
|
-
const parsed = ExecutionStartSchema.safeParse(input);
|
|
276
|
-
if (!parsed.success) {
|
|
277
|
-
const executionId = typeof input === "object" && input !== null && "executionId" in input
|
|
278
|
-
&& typeof input.executionId === "string"
|
|
279
|
-
? input.executionId
|
|
280
|
-
: null;
|
|
281
|
-
if (executionId === null)
|
|
282
|
-
throw new TypeError("Invalid execution spec without an executionId");
|
|
283
|
-
const frame = ExecutionRejectedSchema.parse(boundExecutionFrame(rejection(executionId, "invalid_spec", parsed.error.message, initialAt), config.executionLimits.maxEventBytes));
|
|
284
|
-
await dependencies.report(frame);
|
|
285
|
-
return { kind: "rejected", frame };
|
|
286
|
-
}
|
|
287
|
-
const spec = parsed.data;
|
|
288
|
-
const bestEffortTimeoutMs = telemetryDrainTimeout(dependencies.telemetryDrainTimeoutMs);
|
|
289
|
-
const specHash = hashExecutionSpec(spec);
|
|
290
|
-
const replay = await dependencies.journal.get(spec.executionId);
|
|
291
|
-
if (replay !== null) {
|
|
292
|
-
if (replay.specHash !== specHash) {
|
|
293
|
-
throw new JournalConflictError(`Execution ${spec.executionId} already has a different specHash`);
|
|
294
|
-
}
|
|
295
|
-
const replayPermission = replay.effectivePermission ?? effectivePermission(spec, config);
|
|
296
|
-
if ((replay.state === "completed" || replay.state === "interrupted")
|
|
297
|
-
&& replay.completion !== null) {
|
|
298
|
-
await dependencies.report(boundExecutionFrame(replay.completion, config.executionLimits.maxEventBytes));
|
|
299
|
-
return { kind: "existing", entry: replay };
|
|
300
|
-
}
|
|
301
|
-
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
302
|
-
type: "execution:accepted",
|
|
303
|
-
protocolVersion: 1,
|
|
304
|
-
executionId: spec.executionId,
|
|
305
|
-
state: dependencies.slot?.state ?? "ready",
|
|
306
|
-
effectivePermission: replayPermission,
|
|
307
|
-
at: replay.acceptedAt,
|
|
308
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
309
|
-
if (replay.state === "running" && replay.processStartedAt !== null) {
|
|
310
|
-
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
311
|
-
type: "execution:started",
|
|
312
|
-
protocolVersion: 1,
|
|
313
|
-
executionId: spec.executionId,
|
|
314
|
-
at: replay.processStartedAt,
|
|
315
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
316
|
-
}
|
|
317
|
-
return { kind: "existing", entry: replay };
|
|
318
|
-
}
|
|
319
|
-
const checked = admission(spec, config, dependencies, initialAt);
|
|
320
|
-
if ("rejected" in checked) {
|
|
321
|
-
const frame = ExecutionRejectedSchema.parse(boundExecutionFrame(checked.rejected, config.executionLimits.maxEventBytes));
|
|
322
|
-
await dependencies.report(frame);
|
|
323
|
-
return { kind: "rejected", frame };
|
|
324
|
-
}
|
|
325
|
-
const { permission } = checked;
|
|
326
|
-
const effectiveTimeoutMs = spec.runtime.timeoutMs ?? config.executionLimits.maxTimeoutMs;
|
|
327
|
-
const accepted = await dependencies.journal.accept(spec.executionId, specHash, {
|
|
328
|
-
runtime: spec.runtime.name,
|
|
329
|
-
...(spec.runtime.model === undefined ? {} : { model: spec.runtime.model }),
|
|
330
|
-
resumed: false,
|
|
331
|
-
effectivePermission: permission,
|
|
332
|
-
});
|
|
333
|
-
if (accepted.kind === "existing") {
|
|
334
|
-
if ((accepted.state === "completed" || accepted.state === "interrupted")
|
|
335
|
-
&& accepted.completion !== null) {
|
|
336
|
-
await dependencies.report(boundExecutionFrame(accepted.completion, config.executionLimits.maxEventBytes));
|
|
337
|
-
return { kind: "existing", entry: accepted };
|
|
338
|
-
}
|
|
339
|
-
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
340
|
-
type: "execution:accepted",
|
|
341
|
-
protocolVersion: 1,
|
|
342
|
-
executionId: spec.executionId,
|
|
343
|
-
state: dependencies.slot?.state ?? "ready",
|
|
344
|
-
effectivePermission: accepted.effectivePermission ?? permission,
|
|
345
|
-
at: accepted.acceptedAt,
|
|
346
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
347
|
-
if (accepted.state === "running" && accepted.processStartedAt !== null) {
|
|
348
|
-
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
349
|
-
type: "execution:started",
|
|
350
|
-
protocolVersion: 1,
|
|
351
|
-
executionId: spec.executionId,
|
|
352
|
-
at: accepted.processStartedAt,
|
|
353
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
354
|
-
}
|
|
355
|
-
return { kind: "existing", entry: accepted };
|
|
356
|
-
}
|
|
357
|
-
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
358
|
-
type: "execution:accepted",
|
|
359
|
-
protocolVersion: 1,
|
|
360
|
-
executionId: spec.executionId,
|
|
361
|
-
state: dependencies.slot?.state ?? "ready",
|
|
362
|
-
effectivePermission: permission,
|
|
363
|
-
at: accepted.acceptedAt,
|
|
364
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
365
|
-
const mint = dependencies.mintAgentToken ?? mintAgentToken;
|
|
366
|
-
const execute = dependencies.executeLocal ?? executeLocal;
|
|
367
|
-
const startSupervisor = dependencies.startSupervisor ?? startDormantSupervisor;
|
|
368
|
-
const readBoundImDecision = dependencies.readBoundImDecision ?? readBoundImDecisionFile;
|
|
369
|
-
const resetBoundImDecision = dependencies.resetBoundImDecision ?? resetBoundImDecisionFile;
|
|
370
|
-
const telemetry = new TelemetryQueue(dependencies.report, bestEffortTimeoutMs, positiveTelemetryLimit(dependencies.telemetryMaxPendingFrames, DEFAULT_TELEMETRY_MAX_PENDING_FRAMES), Math.max(config.executionLimits.maxEventBytes, positiveTelemetryLimit(dependencies.telemetryMaxPendingBytes, DEFAULT_TELEMETRY_MAX_PENDING_BYTES)));
|
|
371
|
-
const supervisorState = { active: null, abortOnce: null };
|
|
372
|
-
let launchClosed = false;
|
|
373
|
-
const launchAttempts = new Set();
|
|
374
|
-
const closeLaunchGate = async () => {
|
|
375
|
-
launchClosed = true;
|
|
376
|
-
await Promise.all([...launchAttempts]);
|
|
377
|
-
};
|
|
378
|
-
let startedAt = accepted.acceptedAt;
|
|
379
|
-
let timeout;
|
|
380
|
-
let timedOut = false;
|
|
381
|
-
let completion;
|
|
382
|
-
let boundImDecision = spec.reporting.allowBoundImDecision
|
|
383
|
-
? "silent"
|
|
384
|
-
: undefined;
|
|
385
|
-
let rejectCancellationFailure;
|
|
386
|
-
const cancellationFailure = new Promise((_resolve, reject) => {
|
|
387
|
-
rejectCancellationFailure = reject;
|
|
388
|
-
});
|
|
389
|
-
try {
|
|
390
|
-
if (dependencies.slot !== undefined) {
|
|
391
|
-
await cancellable(dependencies.slot.ready, dependencies.cancellation);
|
|
392
|
-
}
|
|
393
|
-
const credential = await cancellable(mint(config.serverUrl, config.machineToken, spec.agent.handle, undefined, { executionId: spec.executionId, agentRunId: spec.executionId }), dependencies.cancellation);
|
|
394
|
-
const providerConfig = launchProviderConfig(credential.config);
|
|
395
|
-
let activitySequence = 0;
|
|
396
|
-
let consoleSequence = 0;
|
|
397
|
-
let externalOutputSequence = 0;
|
|
398
|
-
const callbacks = {
|
|
399
|
-
...(spec.reporting.streamActivity ? {
|
|
400
|
-
onActivity: (activity) => {
|
|
401
|
-
const frame = DaemonToServerExecutionFrameSchema.parse({
|
|
402
|
-
type: "execution:activity",
|
|
403
|
-
protocolVersion: 1,
|
|
404
|
-
executionId: spec.executionId,
|
|
405
|
-
activity: ACTIVITY_KIND[activity.kind] ?? "working",
|
|
406
|
-
detail: activity.detail ?? activity.label,
|
|
407
|
-
seq: activitySequence++,
|
|
408
|
-
at: now().toISOString(),
|
|
409
|
-
});
|
|
410
|
-
try {
|
|
411
|
-
const bounded = boundExecutionFrame(frame, config.executionLimits.maxEventBytes);
|
|
412
|
-
telemetry.enqueue(bounded);
|
|
413
|
-
}
|
|
414
|
-
catch { /* best-effort activity omitted when its envelope cannot fit */ }
|
|
415
|
-
},
|
|
416
|
-
} : {}),
|
|
417
|
-
...(spec.reporting.streamConsole ? {
|
|
418
|
-
onConsole: (chunk) => {
|
|
419
|
-
const frame = DaemonToServerExecutionFrameSchema.parse({
|
|
420
|
-
type: "execution:console",
|
|
421
|
-
protocolVersion: 1,
|
|
422
|
-
executionId: spec.executionId,
|
|
423
|
-
stream: chunk.stream,
|
|
424
|
-
text: chunk.text,
|
|
425
|
-
...(chunk.payload ? { payload: chunk.payload } : {}),
|
|
426
|
-
seq: consoleSequence++,
|
|
427
|
-
at: now().toISOString(),
|
|
428
|
-
});
|
|
429
|
-
try {
|
|
430
|
-
const bounded = boundExecutionFrame(frame, config.executionLimits.maxEventBytes);
|
|
431
|
-
telemetry.enqueue(bounded);
|
|
432
|
-
}
|
|
433
|
-
catch { /* best-effort console omitted when its envelope cannot fit */ }
|
|
434
|
-
},
|
|
435
|
-
} : {}),
|
|
436
|
-
...(spec.context.externalResponseSessionId || spec.context.answerStream ? {
|
|
437
|
-
onExternalOutput: (text) => {
|
|
438
|
-
const frame = DaemonToServerExecutionFrameSchema.parse({
|
|
439
|
-
type: "execution:output",
|
|
440
|
-
protocolVersion: 1,
|
|
441
|
-
executionId: spec.executionId,
|
|
442
|
-
channel: "external_answer",
|
|
443
|
-
text,
|
|
444
|
-
seq: externalOutputSequence++,
|
|
445
|
-
at: now().toISOString(),
|
|
446
|
-
});
|
|
447
|
-
try {
|
|
448
|
-
telemetry.enqueue(boundExecutionFrame(frame, config.executionLimits.maxEventBytes));
|
|
449
|
-
}
|
|
450
|
-
catch { /* final completion remains the authoritative repair */ }
|
|
451
|
-
},
|
|
452
|
-
} : {}),
|
|
453
|
-
};
|
|
454
|
-
const localDependencies = {
|
|
455
|
-
...(dependencies.cancellation === undefined ? {} : { cancellation: dependencies.cancellation }),
|
|
456
|
-
launchRuntime: async (request) => {
|
|
457
|
-
if (launchClosed || dependencies.cancellation?.isRequested())
|
|
458
|
-
throw new ExecutionCancelledError();
|
|
459
|
-
let settleLaunch;
|
|
460
|
-
const launchSettled = new Promise((resolve) => { settleLaunch = resolve; });
|
|
461
|
-
launchAttempts.add(launchSettled);
|
|
462
|
-
try {
|
|
463
|
-
const processStartedAt = now().toISOString();
|
|
464
|
-
const launchControl = { cancel: null };
|
|
465
|
-
const guarded = await dependencies.journal.startGuarded(spec.executionId, processStartedAt, () => startSupervisor(supervisorLaunch(request)), {
|
|
466
|
-
beforeRelease: ({ entry, handle, abort }) => {
|
|
467
|
-
supervisorState.active = handle;
|
|
468
|
-
let stopPromise = null;
|
|
469
|
-
let releaseStarted = false;
|
|
470
|
-
const stopOnce = (operation) => {
|
|
471
|
-
if (stopPromise === null) {
|
|
472
|
-
try {
|
|
473
|
-
stopPromise = Promise.resolve(operation());
|
|
474
|
-
}
|
|
475
|
-
catch (error) {
|
|
476
|
-
stopPromise = Promise.reject(error);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
return stopPromise;
|
|
480
|
-
};
|
|
481
|
-
launchControl.cancel = () => stopOnce(releaseStarted ? handle.cancel : abort);
|
|
482
|
-
supervisorState.abortOnce = () => stopOnce(abort);
|
|
483
|
-
dependencies.cancellation?.register(launchControl.cancel);
|
|
484
|
-
startedAt = entry.processStartedAt ?? processStartedAt;
|
|
485
|
-
if (dependencies.cancellation?.isRequested()) {
|
|
486
|
-
return dependencies.cancellation.waitForStop().then(() => {
|
|
487
|
-
throw new ExecutionCancelledError();
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
releaseStarted = true;
|
|
491
|
-
},
|
|
492
|
-
});
|
|
493
|
-
if (guarded.kind !== "started") {
|
|
494
|
-
throw new Error(`Execution became ${guarded.entry.state} before local launch`);
|
|
495
|
-
}
|
|
496
|
-
if (launchControl.cancel === null) {
|
|
497
|
-
throw new Error("Execution launch cancellation gate was not installed");
|
|
498
|
-
}
|
|
499
|
-
const installedCancel = launchControl.cancel;
|
|
500
|
-
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
501
|
-
type: "execution:started",
|
|
502
|
-
protocolVersion: 1,
|
|
503
|
-
executionId: spec.executionId,
|
|
504
|
-
at: startedAt,
|
|
505
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
506
|
-
if (!dependencies.cancellation?.isRequested()) {
|
|
507
|
-
timeout = setTimeout(() => {
|
|
508
|
-
timedOut = true;
|
|
509
|
-
try {
|
|
510
|
-
void installedCancel().catch(rejectCancellationFailure);
|
|
511
|
-
}
|
|
512
|
-
catch (error) {
|
|
513
|
-
rejectCancellationFailure(error);
|
|
514
|
-
}
|
|
515
|
-
}, effectiveTimeoutMs);
|
|
516
|
-
}
|
|
517
|
-
return { ...guarded.handle, cancel: installedCancel };
|
|
518
|
-
}
|
|
519
|
-
finally {
|
|
520
|
-
launchAttempts.delete(launchSettled);
|
|
521
|
-
settleLaunch();
|
|
522
|
-
}
|
|
523
|
-
},
|
|
524
|
-
};
|
|
525
|
-
const localInput = {
|
|
526
|
-
executionId: spec.executionId,
|
|
527
|
-
handle: spec.agent.handle,
|
|
528
|
-
channelId: spec.context.channelId,
|
|
529
|
-
keyMode: "opaque",
|
|
530
|
-
taskKey: spec.workspace.taskKey,
|
|
531
|
-
...(spec.workspace.resumeKey === undefined ? {} : { resumeKey: spec.workspace.resumeKey }),
|
|
532
|
-
...(spec.context.wakeMessageId === undefined ? {} : { wakeMessageId: spec.context.wakeMessageId }),
|
|
533
|
-
...(spec.context.attachments === undefined ? {} : { attachments: spec.context.attachments }),
|
|
534
|
-
systemPrompt: withLocalExecutionFacts(spec.instructions.systemPrompt, config.executionLimits.maxPromptBytes
|
|
535
|
-
- Buffer.byteLength(spec.instructions.wakePrompt, "utf8")),
|
|
536
|
-
wakePrompt: spec.instructions.wakePrompt,
|
|
537
|
-
runtime: {
|
|
538
|
-
name: spec.runtime.name,
|
|
539
|
-
...(spec.runtime.model === undefined ? {} : { model: spec.runtime.model }),
|
|
540
|
-
...(spec.runtime.reasoning === undefined ? {} : { reasoning: spec.runtime.reasoning }),
|
|
541
|
-
},
|
|
542
|
-
effectivePermission: permission,
|
|
543
|
-
captureFinal: spec.reporting.captureFinal,
|
|
544
|
-
launch: {
|
|
545
|
-
serverUrl: config.serverUrl,
|
|
546
|
-
token: credential.token,
|
|
547
|
-
agentId: credential.agentId,
|
|
548
|
-
agentsRoot: config.agentsRoot,
|
|
549
|
-
cliPath: config.cliPath,
|
|
550
|
-
providerConfig,
|
|
551
|
-
...(providerConfig.description ? { description: providerConfig.description } : {}),
|
|
552
|
-
...(spec.reporting.allowBoundImDecision ? {
|
|
553
|
-
systemEnv: {
|
|
554
|
-
CREW_BOUND_IM_DECISION_FILE: `.bound-im-decision-${spec.executionId}.json`,
|
|
555
|
-
},
|
|
556
|
-
} : {}),
|
|
557
|
-
},
|
|
558
|
-
session: {
|
|
559
|
-
enabled: config.resume,
|
|
560
|
-
warmMs: config.resumeWarmMs,
|
|
561
|
-
budgetTokens: config.sessionBudgetTokens,
|
|
562
|
-
softTokens: config.sessionSoftTokens,
|
|
563
|
-
maxTurns: config.sessionMaxTurns,
|
|
564
|
-
},
|
|
565
|
-
};
|
|
566
|
-
const result = await Promise.race([
|
|
567
|
-
execute(localInput, callbacks, localDependencies),
|
|
568
|
-
cancellationFailure,
|
|
569
|
-
]);
|
|
570
|
-
if (timeout !== undefined)
|
|
571
|
-
clearTimeout(timeout);
|
|
572
|
-
const finishedAt = now().toISOString();
|
|
573
|
-
if (spec.reporting.allowBoundImDecision) {
|
|
574
|
-
const path = join(result.workspaceRunDir, `.bound-im-decision-${spec.executionId}.json`);
|
|
575
|
-
const selected = await readBoundImDecision(path);
|
|
576
|
-
await resetBoundImDecision(path);
|
|
577
|
-
boundImDecision = selected?.decision ?? "silent";
|
|
578
|
-
}
|
|
579
|
-
completion = ExecutionCompletedSchema.parse(timedOut ? {
|
|
580
|
-
type: "execution:completed",
|
|
581
|
-
protocolVersion: 1,
|
|
582
|
-
executionId: spec.executionId,
|
|
583
|
-
outcome: "cancelled",
|
|
584
|
-
errorCode: "timeout",
|
|
585
|
-
errorMessage: "Execution exceeded its local timeout",
|
|
586
|
-
runtime: result.runtime,
|
|
587
|
-
...(result.model === null ? {} : { model: result.model }),
|
|
588
|
-
resumed: result.resumed,
|
|
589
|
-
...(boundImDecision ? { boundImDecision } : {}),
|
|
590
|
-
startedAt,
|
|
591
|
-
finishedAt,
|
|
592
|
-
} : {
|
|
593
|
-
type: "execution:completed",
|
|
594
|
-
protocolVersion: 1,
|
|
595
|
-
executionId: spec.executionId,
|
|
596
|
-
outcome: result.exitCode === 0 ? "succeeded" : "failed",
|
|
597
|
-
exitCode: result.exitCode,
|
|
598
|
-
...(result.terminationSignal === undefined ? {} : { terminationSignal: result.terminationSignal }),
|
|
599
|
-
...(result.exitCode === 0 ? {} : {
|
|
600
|
-
errorCode: "runtime_failed",
|
|
601
|
-
...(result.errorMessage ? { errorMessage: result.errorMessage } : {}),
|
|
602
|
-
}),
|
|
603
|
-
runtime: result.runtime,
|
|
604
|
-
...(result.model === null ? {} : { model: result.model }),
|
|
605
|
-
resumed: result.resumed,
|
|
606
|
-
...(boundImDecision ? { boundImDecision } : {}),
|
|
607
|
-
...(!spec.reporting.captureFinal || result.finalText === null
|
|
608
|
-
? {}
|
|
609
|
-
: { finalText: result.finalText }),
|
|
610
|
-
// externalAnswer 是本轮完成的权威结果,与 answerStream(增量流式的可选增强)解耦转发;
|
|
611
|
-
// 否则能力协商降级后模型仍可能沿用同线程记住的 marker 契约,回复却永远发不到频道
|
|
612
|
-
// (incident: 2026-07-30, 2026-08-03)。
|
|
613
|
-
...(result.exitCode === 0 && result.externalAnswer
|
|
614
|
-
? { externalAnswer: result.externalAnswer }
|
|
615
|
-
: {}),
|
|
616
|
-
...(result.usage === undefined ? {} : { usage: result.usage }),
|
|
617
|
-
startedAt,
|
|
618
|
-
finishedAt,
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
catch (error) {
|
|
622
|
-
if (timeout !== undefined)
|
|
623
|
-
clearTimeout(timeout);
|
|
624
|
-
const cancelled = error instanceof ExecutionCancelledError || error instanceof RuntimeCancelledError;
|
|
625
|
-
if (cancelled) {
|
|
626
|
-
await closeLaunchGate();
|
|
627
|
-
await dependencies.cancellation?.waitForStop();
|
|
628
|
-
}
|
|
629
|
-
else if (supervisorState.active !== null && supervisorState.abortOnce !== null) {
|
|
630
|
-
try {
|
|
631
|
-
await supervisorState.abortOnce();
|
|
632
|
-
}
|
|
633
|
-
catch (abortError) {
|
|
634
|
-
const detail = abortError instanceof Error ? abortError.message : String(abortError);
|
|
635
|
-
throw new AggregateError([error, abortError], `Failed to stop the execution supervisor: ${detail}`);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
completion = cancelled
|
|
639
|
-
? ExecutionCompletedSchema.parse({
|
|
640
|
-
type: "execution:completed",
|
|
641
|
-
protocolVersion: 1,
|
|
642
|
-
executionId: spec.executionId,
|
|
643
|
-
outcome: "cancelled",
|
|
644
|
-
errorCode: "cancelled",
|
|
645
|
-
errorMessage: "Execution cancelled by server request",
|
|
646
|
-
runtime: spec.runtime.name,
|
|
647
|
-
...(spec.runtime.model === undefined ? {} : { model: spec.runtime.model }),
|
|
648
|
-
resumed: false,
|
|
649
|
-
startedAt,
|
|
650
|
-
finishedAt: now().toISOString(),
|
|
651
|
-
})
|
|
652
|
-
: failedCompletion(spec, error, startedAt, now().toISOString());
|
|
653
|
-
}
|
|
654
|
-
completion = boundExecutionFrame(completion, config.executionLimits.maxEventBytes);
|
|
655
|
-
await telemetry.closeAndDrain();
|
|
656
|
-
await dependencies.journal.complete(spec.executionId, completion);
|
|
657
|
-
await dependencies.report(completion);
|
|
658
|
-
return { kind: "completed", frame: completion };
|
|
659
|
-
}
|