@nowcrew/daemon 0.6.41 → 0.6.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.js +3 -9
- package/dist/execution-runner.js +29 -216
- package/dist/host-execution-coordinator.js +6 -0
- package/dist/identity-roster-telemetry.js +37 -0
- package/dist/local-executor.js +2 -0
- package/dist/runtimes/progress-watchdog.js +4 -16
- package/dist/workspace.js +5 -1
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -15,13 +15,10 @@ export const DEFAULT_EXECUTION_LIMITS = Object.freeze({
|
|
|
15
15
|
maxQueuedPerAgent: 32,
|
|
16
16
|
maxParallelTotal: 10,
|
|
17
17
|
maxQueuedTotal: 128,
|
|
18
|
-
maxStartingTotal:
|
|
19
|
-
maxStartingPerRuntime:
|
|
20
|
-
startupGapMs:
|
|
18
|
+
maxStartingTotal: 1,
|
|
19
|
+
maxStartingPerRuntime: 1,
|
|
20
|
+
startupGapMs: 3_000,
|
|
21
21
|
startupTimeoutMs: 120_000,
|
|
22
|
-
maxQueueWaitMs: 5 * 60_000,
|
|
23
|
-
maxFirstOutputWaitMs: 2 * 60_000,
|
|
24
|
-
firstOutputGraceMs: 3 * 60_000,
|
|
25
22
|
});
|
|
26
23
|
// Fits the largest mandatory v1 lifecycle envelope (UUID + timestamps + outcome facts) with margin.
|
|
27
24
|
export const MIN_EXECUTION_EVENT_BYTES = 512;
|
|
@@ -88,9 +85,6 @@ export function loadConfig(env = process.env) {
|
|
|
88
85
|
maxStartingPerRuntime: positiveIntegerEnv(env, "CREW_EXECUTION_MAX_STARTING_PER_RUNTIME", DEFAULT_EXECUTION_LIMITS.maxStartingPerRuntime),
|
|
89
86
|
startupGapMs: positiveIntegerEnv(env, "CREW_EXECUTION_START_GAP_MS", DEFAULT_EXECUTION_LIMITS.startupGapMs),
|
|
90
87
|
startupTimeoutMs: positiveIntegerEnv(env, "CREW_EXECUTION_STARTUP_TIMEOUT_MS", DEFAULT_EXECUTION_LIMITS.startupTimeoutMs),
|
|
91
|
-
maxQueueWaitMs: positiveIntegerEnv(env, "CREW_EXECUTION_MAX_QUEUE_WAIT_MS", DEFAULT_EXECUTION_LIMITS.maxQueueWaitMs),
|
|
92
|
-
maxFirstOutputWaitMs: positiveIntegerEnv(env, "CREW_EXECUTION_MAX_FIRST_OUTPUT_WAIT_MS", DEFAULT_EXECUTION_LIMITS.maxFirstOutputWaitMs),
|
|
93
|
-
firstOutputGraceMs: positiveIntegerEnv(env, "CREW_EXECUTION_FIRST_OUTPUT_GRACE_MS", DEFAULT_EXECUTION_LIMITS.firstOutputGraceMs),
|
|
94
88
|
});
|
|
95
89
|
return {
|
|
96
90
|
serverUrl,
|
package/dist/execution-runner.js
CHANGED
|
@@ -4,7 +4,7 @@ import { DaemonToServerExecutionFrameSchema, ExecutionCompletedSchema, Execution
|
|
|
4
4
|
import { JournalConflictError } from "./execution-journal.js";
|
|
5
5
|
import { boundExecutionFrame } from "./execution-event-limit.js";
|
|
6
6
|
import { mintAgentToken } from "./token.js";
|
|
7
|
-
import { executeLocal,
|
|
7
|
+
import { executeLocal, withLocalExecutionFacts, } from "./local-executor.js";
|
|
8
8
|
import { startDormantSupervisor, } from "./execution-supervisor.js";
|
|
9
9
|
import { CLAUDE_EFFORT_LEVELS } from "./runtimes/claude.js";
|
|
10
10
|
import { CODEX_EFFORT_LEVELS } from "./runtimes/codex.js";
|
|
@@ -12,17 +12,18 @@ import { KIMI_EFFORT_LEVELS } from "./runtimes/kimi.js";
|
|
|
12
12
|
import { executionBackendCapability } from "./execution-backend.js";
|
|
13
13
|
import { readBoundImDecisionFile, resetBoundImDecisionFile } from "./bound-im-decision.js";
|
|
14
14
|
import { RuntimeCancelledError } from "./runtime-cancellation.js";
|
|
15
|
+
import { HostReservationCancelledError } from "./host-execution-coordinator.js";
|
|
15
16
|
import { supervisorLaunch } from "./supervised-runtime.js";
|
|
16
17
|
import { appendAgentMemoryContext } from "./agent-memory/policy.js";
|
|
17
18
|
import { ProjectSkillRuntimeOwnershipUnverifiedError, } from "./project-skills/reconciler.js";
|
|
18
19
|
import { projectSkillExecutionProjection, projectSkillProjectionErrorCode } from "./project-skills/execution-adapter.js";
|
|
19
20
|
import { redactProjectSkillRuntimeRootError, } from "./project-skills/runtime-launch.js";
|
|
20
21
|
import { createProjectRegistry } from "./project-skills/registry.js";
|
|
21
|
-
import { ProjectDependencyError, } from "./project-dependencies.js";
|
|
22
22
|
import { ProjectContextUnavailableError, resolveProjectContext } from "./project-workspaces/resolver.js";
|
|
23
23
|
import { PROJECT_WORKSPACES_CAPABILITY } from "./machine-info.js";
|
|
24
24
|
import { PROJECT_SKILL_PROJECTION_V2_CAPABILITY } from "./project-skills/types.js";
|
|
25
25
|
import { dslog } from "./slog.js";
|
|
26
|
+
import { identityRosterPromptFacts } from "./identity-roster-telemetry.js";
|
|
26
27
|
export { supervisorLaunch } from "./supervised-runtime.js";
|
|
27
28
|
const ACTIVITY_KIND = {
|
|
28
29
|
init: "working",
|
|
@@ -297,12 +298,6 @@ class ExecutionCancelledError extends Error {
|
|
|
297
298
|
this.name = "ExecutionCancelledError";
|
|
298
299
|
}
|
|
299
300
|
}
|
|
300
|
-
class ExecutionQueueTimeoutError extends Error {
|
|
301
|
-
constructor(timeoutMs) {
|
|
302
|
-
super(`Execution queue wait exceeded ${timeoutMs}ms`);
|
|
303
|
-
this.name = "ExecutionQueueTimeoutError";
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
301
|
async function cancellable(promise, cancellation) {
|
|
307
302
|
if (cancellation === undefined)
|
|
308
303
|
return promise;
|
|
@@ -313,30 +308,13 @@ async function cancellable(promise, cancellation) {
|
|
|
313
308
|
cancellation.requested.then(() => { throw new ExecutionCancelledError(); }),
|
|
314
309
|
]);
|
|
315
310
|
}
|
|
316
|
-
async function cancellableWithTimeout(promise, timeoutMs, cancellation, timeoutError) {
|
|
317
|
-
let timer;
|
|
318
|
-
try {
|
|
319
|
-
return await Promise.race([
|
|
320
|
-
cancellable(promise, cancellation),
|
|
321
|
-
new Promise((_resolve, reject) => {
|
|
322
|
-
timer = setTimeout(() => reject(timeoutError), timeoutMs);
|
|
323
|
-
}),
|
|
324
|
-
]);
|
|
325
|
-
}
|
|
326
|
-
finally {
|
|
327
|
-
if (timer !== undefined)
|
|
328
|
-
clearTimeout(timer);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
311
|
function failedCompletion(spec, error, startedAt, finishedAt) {
|
|
332
312
|
const message = error instanceof Error ? error.message : String(error);
|
|
333
|
-
const errorCode = error instanceof
|
|
313
|
+
const errorCode = error instanceof HostReservationCancelledError
|
|
334
314
|
? "queue_timeout"
|
|
335
315
|
: error instanceof ProjectContextUnavailableError
|
|
336
316
|
? error.code
|
|
337
|
-
: error
|
|
338
|
-
? error.code
|
|
339
|
-
: projectSkillProjectionErrorCode(error) ?? "local_execution_failed";
|
|
317
|
+
: projectSkillProjectionErrorCode(error) ?? "local_execution_failed";
|
|
340
318
|
return ExecutionCompletedSchema.parse({
|
|
341
319
|
type: "execution:completed",
|
|
342
320
|
protocolVersion: 1,
|
|
@@ -367,6 +345,15 @@ export async function runExecution(config, input, dependencies) {
|
|
|
367
345
|
return { kind: "rejected", frame };
|
|
368
346
|
}
|
|
369
347
|
const spec = parsed.data;
|
|
348
|
+
dslog("execution.identity_roster_received", "daemon 已收到执行提示词中的工作区身份名册", {
|
|
349
|
+
execution_id: spec.executionId,
|
|
350
|
+
agent_handle: spec.agent.handle,
|
|
351
|
+
channel_id: spec.context.channelId,
|
|
352
|
+
thread_id: spec.context.threadId,
|
|
353
|
+
wake_message_id: spec.context.wakeMessageId,
|
|
354
|
+
runtime: spec.runtime.name,
|
|
355
|
+
...identityRosterPromptFacts(spec.instructions.systemPrompt),
|
|
356
|
+
});
|
|
370
357
|
const capabilityRejection = projectWorkspaceCapabilityRejection(spec, dependencies.capabilities, initialAt);
|
|
371
358
|
if (capabilityRejection !== null) {
|
|
372
359
|
const frame = ExecutionRejectedSchema.parse(boundExecutionFrame(capabilityRejection, config.executionLimits.maxEventBytes));
|
|
@@ -411,7 +398,6 @@ export async function runExecution(config, input, dependencies) {
|
|
|
411
398
|
return { kind: "rejected", frame };
|
|
412
399
|
}
|
|
413
400
|
const { permission } = checked;
|
|
414
|
-
const effectiveTimeoutMs = spec.runtime.timeoutMs ?? config.executionLimits.maxTimeoutMs;
|
|
415
401
|
const accepted = await dependencies.journal.accept(spec.executionId, specHash, {
|
|
416
402
|
runtime: spec.runtime.name,
|
|
417
403
|
...(spec.runtime.model === undefined ? {} : { model: spec.runtime.model }),
|
|
@@ -480,12 +466,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
480
466
|
};
|
|
481
467
|
let startedAt = accepted.acceptedAt;
|
|
482
468
|
let runtimeCancel = null;
|
|
483
|
-
let timeout;
|
|
484
|
-
let firstOutputTimer;
|
|
485
|
-
let timedOut = false;
|
|
486
|
-
let firstOutputTimedOut = false;
|
|
487
469
|
let completion;
|
|
488
|
-
let abandonedRuntimeRunningCompletion = null;
|
|
489
470
|
let memoryCaptureFinalText = null;
|
|
490
471
|
let boundImDecision = spec.reporting.allowBoundImDecision
|
|
491
472
|
? "silent"
|
|
@@ -496,24 +477,11 @@ export async function runExecution(config, input, dependencies) {
|
|
|
496
477
|
});
|
|
497
478
|
try {
|
|
498
479
|
if (dependencies.slot !== undefined) {
|
|
499
|
-
await
|
|
480
|
+
await cancellable(dependencies.slot.ready, dependencies.cancellation);
|
|
500
481
|
}
|
|
501
482
|
let projectContext;
|
|
502
483
|
let sessionContextFingerprint;
|
|
503
484
|
const logicalProjectContext = spec.workspace.projectContext;
|
|
504
|
-
dslog("project_dependencies.preflight", "项目依赖准备前置状态", {
|
|
505
|
-
execution_id: spec.executionId,
|
|
506
|
-
agent_handle: spec.agent.handle,
|
|
507
|
-
has_ability_release: spec.agent.abilityRelease !== undefined,
|
|
508
|
-
ability_release_id: spec.agent.abilityRelease?.releaseId,
|
|
509
|
-
ability_root_commit: spec.agent.abilityRelease?.rootCommit,
|
|
510
|
-
has_project_context: logicalProjectContext !== undefined,
|
|
511
|
-
project_ids: JSON.stringify(logicalProjectContext?.projectIds ?? []),
|
|
512
|
-
project_context_primary: logicalProjectContext?.primaryProjectId,
|
|
513
|
-
dependency_prepare_expected: spec.agent.abilityRelease !== undefined
|
|
514
|
-
&& logicalProjectContext !== undefined
|
|
515
|
-
&& logicalProjectContext.projectIds.length > 0,
|
|
516
|
-
});
|
|
517
485
|
if (logicalProjectContext !== undefined && logicalProjectContext.projectIds.length > 0) {
|
|
518
486
|
const projectSnapshot = {
|
|
519
487
|
projectIds: logicalProjectContext.projectIds,
|
|
@@ -521,50 +489,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
521
489
|
? {}
|
|
522
490
|
: { primaryProjectId: logicalProjectContext.primaryProjectId }),
|
|
523
491
|
};
|
|
524
|
-
|
|
525
|
-
?? dependencies.projectRegistry
|
|
526
|
-
?? createProjectRegistry(config.agentsRoot);
|
|
527
|
-
if (spec.agent.abilityRelease !== undefined && dependencies.projectDependencies !== undefined) {
|
|
528
|
-
if (dependencies.abilityRelease !== undefined) {
|
|
529
|
-
await cancellable(dependencies.abilityRelease.apply(config.agentsRoot, spec.agent.handle, spec.agent.abilityRelease), dependencies.cancellation);
|
|
530
|
-
}
|
|
531
|
-
const preparedProjectDependencies = await cancellable(dependencies.projectDependencies.prepare({
|
|
532
|
-
trainingRoot: join(config.agentsRoot, spec.agent.handle, "training"),
|
|
533
|
-
projectsRoot: join(config.agentsRoot, "Projects"),
|
|
534
|
-
projectIds: projectSnapshot.projectIds,
|
|
535
|
-
}), dependencies.cancellation);
|
|
536
|
-
for (const project of preparedProjectDependencies) {
|
|
537
|
-
dslog("project_dependencies.prepared", "Training project dependency prepared", {
|
|
538
|
-
execution_id: spec.executionId,
|
|
539
|
-
agent_handle: spec.agent.handle,
|
|
540
|
-
project_id: project.projectId,
|
|
541
|
-
project_branch: project.branch,
|
|
542
|
-
project_branch_source: project.branchSource,
|
|
543
|
-
project_commit: project.resolvedCommit,
|
|
544
|
-
project_checkout_mode: project.checkoutMode,
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
else if (spec.agent.abilityRelease === undefined) {
|
|
549
|
-
dslog("project_dependencies.skipped", "缺少 abilityRelease,未执行项目依赖准备", {
|
|
550
|
-
level: "WARN",
|
|
551
|
-
execution_id: spec.executionId,
|
|
552
|
-
agent_handle: spec.agent.handle,
|
|
553
|
-
project_ids: JSON.stringify(projectSnapshot.projectIds),
|
|
554
|
-
reason: "ability_release_missing",
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
else {
|
|
558
|
-
dslog("project_dependencies.skipped", "Daemon 未提供项目依赖准备器", {
|
|
559
|
-
level: "WARN",
|
|
560
|
-
execution_id: spec.executionId,
|
|
561
|
-
agent_handle: spec.agent.handle,
|
|
562
|
-
project_ids: JSON.stringify(projectSnapshot.projectIds),
|
|
563
|
-
ability_release_id: spec.agent.abilityRelease.releaseId,
|
|
564
|
-
reason: "provisioner_missing",
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
projectContext = await cancellable(resolveProjectContext(projectSnapshot, projectWorkspaceRegistry), dependencies.cancellation);
|
|
492
|
+
projectContext = await cancellable(resolveProjectContext(projectSnapshot, dependencies.projectWorkspaceRegistry ?? createProjectRegistry(config.agentsRoot)), dependencies.cancellation);
|
|
568
493
|
sessionContextFingerprint = projectSessionContextFingerprint(spec.runtime.name, projectSnapshot);
|
|
569
494
|
}
|
|
570
495
|
let recalledMemory = "";
|
|
@@ -583,88 +508,23 @@ export async function runExecution(config, input, dependencies) {
|
|
|
583
508
|
let consoleSequence = 0;
|
|
584
509
|
let externalOutputSequence = 0;
|
|
585
510
|
const callbacks = {
|
|
586
|
-
|
|
587
|
-
dependencies.onRuntimePhase?.("starting", spec.runtime.name);
|
|
588
|
-
},
|
|
589
|
-
onRuntimeRunning: async () => {
|
|
590
|
-
const callbackStartedAt = Date.now();
|
|
591
|
-
let callbackStage = "journal";
|
|
511
|
+
onRuntimeReady: async () => {
|
|
592
512
|
if (dependencies.cancellation?.isRequested())
|
|
593
513
|
return;
|
|
594
|
-
const
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
firstOutputTimer = setTimeout(() => {
|
|
598
|
-
firstOutputTimedOut = true;
|
|
599
|
-
try {
|
|
600
|
-
void cancel().catch(rejectCancellationFailure);
|
|
601
|
-
}
|
|
602
|
-
catch (error) {
|
|
603
|
-
rejectCancellationFailure(error);
|
|
604
|
-
}
|
|
605
|
-
}, config.executionLimits.maxFirstOutputWaitMs + config.executionLimits.firstOutputGraceMs);
|
|
606
|
-
}
|
|
607
|
-
timeout = setTimeout(() => {
|
|
608
|
-
timedOut = true;
|
|
609
|
-
try {
|
|
610
|
-
void cancel().catch(rejectCancellationFailure);
|
|
611
|
-
}
|
|
612
|
-
catch (error) {
|
|
613
|
-
rejectCancellationFailure(error);
|
|
614
|
-
}
|
|
615
|
-
}, effectiveTimeoutMs);
|
|
616
|
-
}
|
|
617
|
-
dependencies.onRuntimePhase?.("running", spec.runtime.name);
|
|
618
|
-
const journalStartedAt = Date.now();
|
|
619
|
-
try {
|
|
620
|
-
const ready = await dependencies.journal.markRuntimeReady(spec.executionId, now().toISOString());
|
|
621
|
-
const journalMs = Date.now() - journalStartedAt;
|
|
622
|
-
if (ready.runtimeReadyAt === null) {
|
|
623
|
-
throw new Error(`Execution ${spec.executionId} runtime readiness was not persisted`);
|
|
624
|
-
}
|
|
625
|
-
if (abandonedRuntimeRunningCompletion !== null) {
|
|
626
|
-
await dependencies.journal.complete(spec.executionId, abandonedRuntimeRunningCompletion);
|
|
627
|
-
await dependencies.report(abandonedRuntimeRunningCompletion);
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
startedAt = ready.runtimeReadyAt;
|
|
631
|
-
callbackStage = "started_report";
|
|
632
|
-
const reportStartedAt = Date.now();
|
|
633
|
-
const reportDelivered = await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
634
|
-
type: "execution:started",
|
|
635
|
-
protocolVersion: 1,
|
|
636
|
-
executionId: spec.executionId,
|
|
637
|
-
at: startedAt,
|
|
638
|
-
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
639
|
-
dslog("execution.runtime_running_callback", "runtime-running callback 已完成", {
|
|
640
|
-
execution_id: spec.executionId,
|
|
641
|
-
runtime: spec.runtime.name,
|
|
642
|
-
outcome: "succeeded",
|
|
643
|
-
journal_ms: journalMs,
|
|
644
|
-
started_report_ms: Date.now() - reportStartedAt,
|
|
645
|
-
started_report_delivered: reportDelivered,
|
|
646
|
-
callback_total_ms: Date.now() - callbackStartedAt,
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
catch (error) {
|
|
650
|
-
dslog("execution.runtime_running_callback", "runtime-running callback 失败", {
|
|
651
|
-
level: "ERROR",
|
|
652
|
-
execution_id: spec.executionId,
|
|
653
|
-
runtime: spec.runtime.name,
|
|
654
|
-
outcome: "failed",
|
|
655
|
-
failed_stage: callbackStage,
|
|
656
|
-
callback_total_ms: Date.now() - callbackStartedAt,
|
|
657
|
-
error_message: error instanceof Error ? error.message.slice(0, 500) : String(error).slice(0, 500),
|
|
658
|
-
});
|
|
659
|
-
throw error;
|
|
514
|
+
const ready = await dependencies.journal.markRuntimeReady(spec.executionId, now().toISOString());
|
|
515
|
+
if (ready.runtimeReadyAt === null) {
|
|
516
|
+
throw new Error(`Execution ${spec.executionId} runtime readiness was not persisted`);
|
|
660
517
|
}
|
|
518
|
+
startedAt = ready.runtimeReadyAt;
|
|
519
|
+
await reportBestEffort(dependencies.report, boundExecutionFrame(DaemonToServerExecutionFrameSchema.parse({
|
|
520
|
+
type: "execution:started",
|
|
521
|
+
protocolVersion: 1,
|
|
522
|
+
executionId: spec.executionId,
|
|
523
|
+
at: startedAt,
|
|
524
|
+
}), config.executionLimits.maxEventBytes), bestEffortTimeoutMs);
|
|
661
525
|
},
|
|
662
526
|
...(spec.reporting.streamActivity ? {
|
|
663
527
|
onActivity: (activity) => {
|
|
664
|
-
if (firstOutputTimer !== undefined) {
|
|
665
|
-
clearTimeout(firstOutputTimer);
|
|
666
|
-
firstOutputTimer = undefined;
|
|
667
|
-
}
|
|
668
528
|
const frame = DaemonToServerExecutionFrameSchema.parse({
|
|
669
529
|
type: "execution:activity",
|
|
670
530
|
protocolVersion: 1,
|
|
@@ -683,10 +543,6 @@ export async function runExecution(config, input, dependencies) {
|
|
|
683
543
|
} : {}),
|
|
684
544
|
...(spec.reporting.streamConsole ? {
|
|
685
545
|
onConsole: (chunk) => {
|
|
686
|
-
if (firstOutputTimer !== undefined) {
|
|
687
|
-
clearTimeout(firstOutputTimer);
|
|
688
|
-
firstOutputTimer = undefined;
|
|
689
|
-
}
|
|
690
546
|
const frame = DaemonToServerExecutionFrameSchema.parse({
|
|
691
547
|
type: "execution:console",
|
|
692
548
|
protocolVersion: 1,
|
|
@@ -706,10 +562,6 @@ export async function runExecution(config, input, dependencies) {
|
|
|
706
562
|
} : {}),
|
|
707
563
|
...(spec.context.externalResponseSessionId || spec.context.answerStream ? {
|
|
708
564
|
onExternalOutput: (text) => {
|
|
709
|
-
if (firstOutputTimer !== undefined) {
|
|
710
|
-
clearTimeout(firstOutputTimer);
|
|
711
|
-
firstOutputTimer = undefined;
|
|
712
|
-
}
|
|
713
565
|
const frame = DaemonToServerExecutionFrameSchema.parse({
|
|
714
566
|
type: "execution:output",
|
|
715
567
|
protocolVersion: 1,
|
|
@@ -883,10 +735,6 @@ export async function runExecution(config, input, dependencies) {
|
|
|
883
735
|
execute(localInput, callbacks, localDependencies),
|
|
884
736
|
cancellationFailure,
|
|
885
737
|
]);
|
|
886
|
-
if (timeout !== undefined)
|
|
887
|
-
clearTimeout(timeout);
|
|
888
|
-
if (firstOutputTimer !== undefined)
|
|
889
|
-
clearTimeout(firstOutputTimer);
|
|
890
738
|
const finishedAt = now().toISOString();
|
|
891
739
|
if (result.exitCode === 0 && result.finalText?.trim())
|
|
892
740
|
memoryCaptureFinalText = result.finalText;
|
|
@@ -896,32 +744,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
896
744
|
await resetBoundImDecision(path);
|
|
897
745
|
boundImDecision = selected?.decision ?? "silent";
|
|
898
746
|
}
|
|
899
|
-
completion = ExecutionCompletedSchema.parse(
|
|
900
|
-
type: "execution:completed",
|
|
901
|
-
protocolVersion: 1,
|
|
902
|
-
executionId: spec.executionId,
|
|
903
|
-
outcome: "cancelled",
|
|
904
|
-
errorCode: "runtime_no_first_output",
|
|
905
|
-
errorMessage: "Runtime produced no activity before the first-output deadline",
|
|
906
|
-
runtime: result.runtime,
|
|
907
|
-
...(result.model === null ? {} : { model: result.model }),
|
|
908
|
-
resumed: result.resumed,
|
|
909
|
-
startedAt,
|
|
910
|
-
finishedAt,
|
|
911
|
-
} : timedOut ? {
|
|
912
|
-
type: "execution:completed",
|
|
913
|
-
protocolVersion: 1,
|
|
914
|
-
executionId: spec.executionId,
|
|
915
|
-
outcome: "cancelled",
|
|
916
|
-
errorCode: "timeout",
|
|
917
|
-
errorMessage: "Execution exceeded its local timeout",
|
|
918
|
-
runtime: result.runtime,
|
|
919
|
-
...(result.model === null ? {} : { model: result.model }),
|
|
920
|
-
resumed: result.resumed,
|
|
921
|
-
...(boundImDecision ? { boundImDecision } : {}),
|
|
922
|
-
startedAt,
|
|
923
|
-
finishedAt,
|
|
924
|
-
} : {
|
|
747
|
+
completion = ExecutionCompletedSchema.parse({
|
|
925
748
|
type: "execution:completed",
|
|
926
749
|
protocolVersion: 1,
|
|
927
750
|
executionId: spec.executionId,
|
|
@@ -956,10 +779,6 @@ export async function runExecution(config, input, dependencies) {
|
|
|
956
779
|
});
|
|
957
780
|
}
|
|
958
781
|
catch (error) {
|
|
959
|
-
if (timeout !== undefined)
|
|
960
|
-
clearTimeout(timeout);
|
|
961
|
-
if (firstOutputTimer !== undefined)
|
|
962
|
-
clearTimeout(firstOutputTimer);
|
|
963
782
|
const cancelled = error instanceof ExecutionCancelledError || error instanceof RuntimeCancelledError;
|
|
964
783
|
if (cancelled) {
|
|
965
784
|
await closeLaunchGate();
|
|
@@ -976,7 +795,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
976
795
|
else {
|
|
977
796
|
await proveActiveSupervisorStopped(error, spec.agent.projectSkillBindingGeneration !== undefined);
|
|
978
797
|
}
|
|
979
|
-
|
|
798
|
+
completion = cancelled
|
|
980
799
|
? ExecutionCompletedSchema.parse({
|
|
981
800
|
type: "execution:completed",
|
|
982
801
|
protocolVersion: 1,
|
|
@@ -991,12 +810,6 @@ export async function runExecution(config, input, dependencies) {
|
|
|
991
810
|
finishedAt: now().toISOString(),
|
|
992
811
|
})
|
|
993
812
|
: failedCompletion(spec, error, startedAt, now().toISOString());
|
|
994
|
-
if (error instanceof RuntimeRunningCallbackTimeoutError) {
|
|
995
|
-
abandonedRuntimeRunningCompletion = boundExecutionFrame(failureCompletion, config.executionLimits.maxEventBytes);
|
|
996
|
-
await telemetry.closeAndDrain();
|
|
997
|
-
throw error;
|
|
998
|
-
}
|
|
999
|
-
completion = failureCompletion;
|
|
1000
813
|
}
|
|
1001
814
|
completion = boundExecutionFrame(completion, config.executionLimits.maxEventBytes);
|
|
1002
815
|
await telemetry.closeAndDrain();
|
|
@@ -10,6 +10,12 @@ const HOST_STARTUP_SLOT_COUNT = 10;
|
|
|
10
10
|
const HOST_STARTUP_GAP_MS = 500;
|
|
11
11
|
const RETRY_MS = 50;
|
|
12
12
|
const RELEASE_RETRY_MAX_MS = 5_000;
|
|
13
|
+
export class HostReservationCancelledError extends Error {
|
|
14
|
+
name = "HostReservationCancelledError";
|
|
15
|
+
constructor(message = "host execution reservation was cancelled before it could be granted") {
|
|
16
|
+
super(message);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
13
19
|
export function defaultHostExecutionCoordinatorRoot(userHome = homedir()) {
|
|
14
20
|
// Deliberately independent of CREW_DAEMON_HOME and agentsRoot: every profile
|
|
15
21
|
// owned by this OS user must share the same physical-compute safety boundary.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { dslog } from "./slog.js";
|
|
2
|
+
const IDENTITY_ROSTER_OPEN = "<nowwork_workspace_identity_roster>";
|
|
3
|
+
const IDENTITY_ROSTER_CLOSE = "</nowwork_workspace_identity_roster>";
|
|
4
|
+
export function identityRosterPromptFacts(prompt) {
|
|
5
|
+
const start = prompt.indexOf(IDENTITY_ROSTER_OPEN);
|
|
6
|
+
if (start < 0)
|
|
7
|
+
return { identity_roster_marker_present: false };
|
|
8
|
+
const payloadStart = start + IDENTITY_ROSTER_OPEN.length;
|
|
9
|
+
const close = prompt.indexOf(IDENTITY_ROSTER_CLOSE, payloadStart);
|
|
10
|
+
const payload = prompt.slice(payloadStart, close < 0 ? prompt.length : close).trim();
|
|
11
|
+
let entryCount;
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(payload);
|
|
14
|
+
if (Array.isArray(parsed))
|
|
15
|
+
entryCount = parsed.length;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Keep the marker as evidence even when a malformed prompt reaches the daemon.
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
identity_roster_marker_present: true,
|
|
22
|
+
identity_roster_section_bytes: Buffer.byteLength(payload, "utf8"),
|
|
23
|
+
...(entryCount === undefined ? {} : { identity_roster_entry_count: entryCount }),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function logIdentityRosterRuntimePrepared(input, runtime, prompt) {
|
|
27
|
+
dslog("execution.identity_roster_runtime_prepared", "daemon 已将工作区身份名册准备给 runtime", {
|
|
28
|
+
execution_id: input.executionId,
|
|
29
|
+
agent_handle: input.handle,
|
|
30
|
+
channel_id: input.channelId,
|
|
31
|
+
task_key: input.taskKey,
|
|
32
|
+
wake_message_id: input.wakeMessageId,
|
|
33
|
+
runtime,
|
|
34
|
+
prompt_bytes: Buffer.byteLength(prompt, "utf8"),
|
|
35
|
+
...identityRosterPromptFacts(prompt),
|
|
36
|
+
});
|
|
37
|
+
}
|
package/dist/local-executor.js
CHANGED
|
@@ -26,6 +26,7 @@ import { boundedDiagnosticJsonArray } from "./diagnostic-json.js";
|
|
|
26
26
|
import { ProjectProjectionError, } from "./project-skills/reconciler.js";
|
|
27
27
|
import { formatProjectSkillRuntimeWarning } from "./project-skills/runtime-warning.js";
|
|
28
28
|
import { projectSkillRuntimeDirectories, redactProjectSkillRuntimeRootText, redactProjectSkillRuntimeRootValue, } from "./project-skills/runtime-launch.js";
|
|
29
|
+
import { logIdentityRosterRuntimePrepared } from "./identity-roster-telemetry.js";
|
|
29
30
|
import { diffMemoryPruneNotes, evaluateMemoryPrunePostcondition, inspectMemoryPruneFilesWithinDeadline, parseMemoryPruneTraceId, } from "./memory-prune-diagnostics.js";
|
|
30
31
|
import { createLocalMemoryTelemetry, logLocalMemoryContextPrepareFailure, logLocalMemoryDiagnosticsFailure, } from "./local-memory-telemetry.js";
|
|
31
32
|
import { CodexStartupStageParser } from "./codex-startup-stage.js";
|
|
@@ -547,6 +548,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
547
548
|
? {}
|
|
548
549
|
: { memorySeedCreated: executionWorkspace.memorySeedCreated }),
|
|
549
550
|
});
|
|
551
|
+
logIdentityRosterRuntimePrepared(input, runtime.name, effectiveSystemPrompt);
|
|
550
552
|
if (abilityContext !== undefined) {
|
|
551
553
|
dslog("ability.execution.context_loaded", "Agent training context loaded from workspace", {
|
|
552
554
|
level: "INFO", execution_id: input.executionId, agent_handle: input.handle,
|
|
@@ -4,23 +4,11 @@ export const DEFAULT_FIRST_PROGRESS_TIMEOUT_MS = 120_000;
|
|
|
4
4
|
* the runtime's configured total timeout remains authoritative; long-running tools are not killed
|
|
5
5
|
* merely because they produce no output.
|
|
6
6
|
*/
|
|
7
|
-
export function startFirstProgressWatchdog(
|
|
7
|
+
export function startFirstProgressWatchdog(_onTimeout, timeoutMs = DEFAULT_FIRST_PROGRESS_TIMEOUT_MS) {
|
|
8
8
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
9
9
|
throw new RangeError("First-progress timeout must be a positive finite number");
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return;
|
|
15
|
-
active = false;
|
|
16
|
-
onTimeout();
|
|
17
|
-
}, timeoutMs);
|
|
18
|
-
timer.unref?.();
|
|
19
|
-
const stop = () => {
|
|
20
|
-
if (!active)
|
|
21
|
-
return;
|
|
22
|
-
active = false;
|
|
23
|
-
clearTimeout(timer);
|
|
24
|
-
};
|
|
25
|
-
return { observe: stop, stop };
|
|
11
|
+
// Progress is observational only. Runtime tasks must not be terminated because
|
|
12
|
+
// an upstream provider is temporarily silent.
|
|
13
|
+
return { observe: () => undefined, stop: () => undefined };
|
|
26
14
|
}
|
package/dist/workspace.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { mkdir, writeFile, readFile, chmod, access } from "node:fs/promises";
|
|
12
12
|
import { createHash, randomUUID } from "node:crypto";
|
|
13
|
-
import { join } from "node:path";
|
|
13
|
+
import { dirname, join } from "node:path";
|
|
14
14
|
import { dslog } from "./slog.js";
|
|
15
15
|
/** 文件系统安全的 taskKey:仅留 [\w.-],其余转 _,截断,避免路径穿越/超长。 */
|
|
16
16
|
export function safeKey(key) {
|
|
@@ -86,6 +86,10 @@ export async function prepareWorkspace(input) {
|
|
|
86
86
|
await mkdir(runDir, { recursive: true });
|
|
87
87
|
workLogPath = join(runDir, "work-log.md");
|
|
88
88
|
}
|
|
89
|
+
// The first turn legitimately has no progress yet, but the path is part of the
|
|
90
|
+
// Runtime contract and memory-prune diagnostics expect it to be inspectable.
|
|
91
|
+
await mkdir(dirname(workLogPath), { recursive: true });
|
|
92
|
+
await writeFile(workLogPath, "", { flag: "a" });
|
|
89
93
|
const workLog = (await exists(workLogPath)) ? await readFile(workLogPath, "utf8") : "";
|
|
90
94
|
// resumeKey 可跨不同 task cwd 维持同一底层会话;协议键用 opaque 映射,legacy 保持 safeKey。
|
|
91
95
|
// 未绑定项目时保留原有分支,避免改变旧 sessionDir 与 import 语义。
|