@paperclipai/adapter-utils 2026.910.0-beta.0 → 2026.910.0-canary.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/dist/acpx-engine/execute.d.ts.map +1 -1
- package/dist/acpx-engine/execute.js +11 -147
- package/dist/acpx-engine/execute.js.map +1 -1
- package/dist/acpx-engine/execute.test.js +0 -138
- package/dist/acpx-engine/execute.test.js.map +1 -1
- package/dist/acpx-engine/run-site-host.d.ts +0 -2
- package/dist/acpx-engine/run-site-host.d.ts.map +1 -1
- package/dist/acpx-engine/run-site-host.js.map +1 -1
- package/dist/acpx-engine/session-codec.d.ts.map +1 -1
- package/dist/acpx-engine/session-codec.js +0 -1
- package/dist/acpx-engine/session-codec.js.map +1 -1
- package/dist/acpx-engine/spawn-smoke.test.js +1 -115
- package/dist/acpx-engine/spawn-smoke.test.js.map +1 -1
- package/dist/acpx-engine/turn-sequence.d.ts +0 -1
- package/dist/acpx-engine/turn-sequence.d.ts.map +1 -1
- package/dist/acpx-engine/turn-sequence.js +0 -20
- package/dist/acpx-engine/turn-sequence.js.map +1 -1
- package/dist/server-utils.d.ts +0 -38
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +116 -554
- package/dist/server-utils.js.map +1 -1
- package/dist/server-utils.test.js +14 -437
- package/dist/server-utils.test.js.map +1 -1
- package/dist/types.d.ts +0 -13
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/acpx-engine/local-process-control.d.ts +0 -5
- package/dist/acpx-engine/local-process-control.d.ts.map +0 -1
- package/dist/acpx-engine/local-process-control.js +0 -39
- package/dist/acpx-engine/local-process-control.js.map +0 -1
- package/dist/acpx-engine/local-process-control.test.d.ts +0 -2
- package/dist/acpx-engine/local-process-control.test.d.ts.map +0 -1
- package/dist/acpx-engine/local-process-control.test.js +0 -38
- package/dist/acpx-engine/local-process-control.test.js.map +0 -1
- package/dist/acpx-engine/operator-stop.test.d.ts +0 -2
- package/dist/acpx-engine/operator-stop.test.d.ts.map +0 -1
- package/dist/acpx-engine/operator-stop.test.js +0 -99
- package/dist/acpx-engine/operator-stop.test.js.map +0 -1
- package/dist/chat-file-delivery.d.ts +0 -10
- package/dist/chat-file-delivery.d.ts.map +0 -1
- package/dist/chat-file-delivery.js +0 -37
- package/dist/chat-file-delivery.js.map +0 -1
- package/dist/chat-file-delivery.test.d.ts +0 -2
- package/dist/chat-file-delivery.test.d.ts.map +0 -1
- package/dist/chat-file-delivery.test.js +0 -92
- package/dist/chat-file-delivery.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/acpx-engine/execute.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,EACtB,YAAY,EACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAcL,KAAK,sBAAsB,EAI3B,KAAK,0BAA0B,EAC/B,KAAK,qCAAqC,EAC1C,KAAK,gCAAgC,EAEtC,MAAM,6CAA6C,CAAC;
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/acpx-engine/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,10 +7,9 @@ import { promisify } from "node:util";
|
|
|
7
7
|
import { createHash, randomUUID } from "node:crypto";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { adapterExecutionTargetSessionIdentity, describeAdapterExecutionTarget, adapterExecutionTargetDuplexObservabilityRecorder, adapterExecutionTargetEnablesSandboxDuplexBridge, formatAdapterExecutionTimeoutErrorMessage, formatAdapterExecutionTimeoutStartLogLine, prepareAdapterExecutionTargetRuntime, readAdapterExecutionTarget, resolveAdapterExecutionTargetTimeout, resolveReferencedSourceIgnore, runAdapterExecutionTargetShellCommand, startAdapterExecutionTargetPaperclipBridge, startAdapterExecutionTargetProcessSessionBridge, } from "@paperclipai/adapter-utils/execution-target";
|
|
10
|
-
import { captureLocalProcess, capturedProcessExited, killCapturedLocalProcess } from "./local-process-control.js";
|
|
11
10
|
import { DUPLEX_CHANNEL_LOST_ERROR_CODE } from "../bridge-transport-contract.js";
|
|
12
11
|
import { classifyWorkspaceRestoreFailure, describeWorkspaceRestoreFailure, } from "../workspace-restore-merge.js";
|
|
13
|
-
import { DEFAULT_PAPERCLIP_AGENT_PROMPT_TEMPLATE, applyPaperclipWorkspaceEnv, asNumber, asString, buildInvocationEnvForLogs, buildPaperclipEnv, ensureAbsoluteDirectory, ensurePathInEnv, ensurePaperclipSkillSymlink, isForbiddenConfigEnvKey,
|
|
12
|
+
import { DEFAULT_PAPERCLIP_AGENT_PROMPT_TEMPLATE, applyPaperclipWorkspaceEnv, asNumber, asString, buildInvocationEnvForLogs, buildPaperclipEnv, ensureAbsoluteDirectory, ensurePathInEnv, ensurePaperclipSkillSymlink, isForbiddenConfigEnvKey, isPaperclipRuntimeEnvKey, joinPromptSections, materializePaperclipSkillCopy, parseObject, isPaperclipSkillSourceMissing, readPaperclipRuntimeSkillEntries, readPaperclipIssueWorkModeFromContext, renderPaperclipWakePrompt, renderTemplate, resolvePaperclipInstanceRootForAdapter, selectPaperclipTaskMarkdown, resolveLegacyPaperclipDesiredSkillNames, removeMaintainerOnlySkillSymlinks, rewriteWorkspaceCwdEnvVarsForExecution, shapePaperclipWorkspaceEnvForExecution, stringifyPaperclipWakePayload, } from "@paperclipai/adapter-utils/server-utils";
|
|
14
13
|
import { shellQuote } from "@paperclipai/adapter-utils/ssh";
|
|
15
14
|
import { createAcpRuntime, createAgentRegistry, createRuntimeStore, isAcpRuntimeError, } from "acpx/runtime";
|
|
16
15
|
import { ACPX_HANDSHAKE_TIMEOUT_MS, ACPX_HANDSHAKE_TRANSPORT_POLL_MS, DEFAULT_ACP_ENGINE_AGENT, DEFAULT_ACP_ENGINE_MODE, DEFAULT_ACP_ENGINE_NON_INTERACTIVE_PERMISSIONS, DEFAULT_ACP_ENGINE_PERMISSION_MODE, DEFAULT_ACP_ENGINE_TIMEOUT_SEC, DEFAULT_ACP_ENGINE_WARM_HANDLE_IDLE_MS, } from "./constants.js";
|
|
@@ -1207,11 +1206,6 @@ async function buildRuntime(input) {
|
|
|
1207
1206
|
// `env` above and are never present in shapedEnvConfig, so they inherently
|
|
1208
1207
|
// stay out of the hash and don't reset the session every heartbeat.
|
|
1209
1208
|
const resolvedAdapterEnv = {};
|
|
1210
|
-
const scratch = parseObject(context.paperclipScratch);
|
|
1211
|
-
const scratchKeys = scratch.type === "heartbeat_run" && typeof scratch.dir === "string"
|
|
1212
|
-
? new Set(["PAPERCLIP_RUN_SCRATCH_DIR", "PAPERCLIP_TASK_SCRATCH_DIR", "PAPERCLIP_SCRATCH_DIR", "PAPERCLIP_TMPDIR",
|
|
1213
|
-
...(Array.isArray(scratch.tempKeysApplied) ? scratch.tempKeysApplied.filter((key) => typeof key === "string" && ["TMPDIR", "TEMP", "TMP"].includes(key)) : [])])
|
|
1214
|
-
: new Set();
|
|
1215
1209
|
for (const [key, value] of Object.entries(shapedEnvConfig)) {
|
|
1216
1210
|
if (typeof value !== "string")
|
|
1217
1211
|
continue;
|
|
@@ -1225,11 +1219,7 @@ async function buildRuntime(input) {
|
|
|
1225
1219
|
if (isPaperclipRuntimeEnvKey(key) && key in env)
|
|
1226
1220
|
continue;
|
|
1227
1221
|
env[key] = value;
|
|
1228
|
-
|
|
1229
|
-
// them, but only hash actual adapter settings. User-supplied temp overrides
|
|
1230
|
-
// are absent from tempKeysApplied and keep their compatibility protection.
|
|
1231
|
-
if (!scratchKeys.has(key) || value !== scratch.dir)
|
|
1232
|
-
resolvedAdapterEnv[key] = value;
|
|
1222
|
+
resolvedAdapterEnv[key] = value;
|
|
1233
1223
|
}
|
|
1234
1224
|
if (authToken)
|
|
1235
1225
|
env.PAPERCLIP_API_KEY = authToken;
|
|
@@ -2018,11 +2008,7 @@ function renderApiAccessNote(env) {
|
|
|
2018
2008
|
}
|
|
2019
2009
|
async function buildPrompt(ctx, resumedSession, env) {
|
|
2020
2010
|
const { agent, runId, config, context, onLog } = ctx;
|
|
2021
|
-
const
|
|
2022
|
-
const hasCustomPromptTemplate = configuredPromptTemplate.trim().length > 0;
|
|
2023
|
-
const promptTemplate = hasCustomPromptTemplate
|
|
2024
|
-
? configuredPromptTemplate
|
|
2025
|
-
: DEFAULT_PAPERCLIP_AGENT_PROMPT_TEMPLATE;
|
|
2011
|
+
const promptTemplate = asString(config.promptTemplate, DEFAULT_PAPERCLIP_AGENT_PROMPT_TEMPLATE);
|
|
2026
2012
|
const instructionsFilePath = asString(config.instructionsFilePath, "").trim();
|
|
2027
2013
|
const instructionsDir = instructionsFilePath ? `${path.dirname(instructionsFilePath)}/` : "";
|
|
2028
2014
|
let instructionsPrefix = "";
|
|
@@ -2056,7 +2042,6 @@ async function buildPrompt(ctx, resumedSession, env) {
|
|
|
2056
2042
|
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
|
2057
2043
|
: "";
|
|
2058
2044
|
const taskContextNote = selectPaperclipTaskMarkdown(context, { resumedSession });
|
|
2059
|
-
const externalChatTurn = isPaperclipExternalChatTurn(context.paperclipWake);
|
|
2060
2045
|
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, {
|
|
2061
2046
|
resumedSession,
|
|
2062
2047
|
// The task-context markdown is the authoritative brief on this lane; keep
|
|
@@ -2065,12 +2050,10 @@ async function buildPrompt(ctx, resumedSession, env) {
|
|
|
2065
2050
|
});
|
|
2066
2051
|
const shouldUseResumeDeltaPrompt = resumedSession && wakePrompt.length > 0;
|
|
2067
2052
|
const promptInstructionsPrefix = shouldUseResumeDeltaPrompt ? "" : instructionsPrefix;
|
|
2068
|
-
const renderedPrompt = shouldUseResumeDeltaPrompt
|
|
2069
|
-
? ""
|
|
2070
|
-
: renderTemplate(promptTemplate, templateData);
|
|
2053
|
+
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
|
2071
2054
|
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
|
2072
|
-
const paperclipEnvNote =
|
|
2073
|
-
const apiAccessNote =
|
|
2055
|
+
const paperclipEnvNote = renderPaperclipEnvNote(env);
|
|
2056
|
+
const apiAccessNote = renderApiAccessNote(env);
|
|
2074
2057
|
const prompt = joinPromptSections([
|
|
2075
2058
|
promptInstructionsPrefix,
|
|
2076
2059
|
renderedBootstrapPrompt,
|
|
@@ -2864,22 +2847,7 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
2864
2847
|
// null on the host lane (no staging) and on a build failure (where
|
|
2865
2848
|
// `buildRuntime` already released its own partial lease).
|
|
2866
2849
|
let releaseStagingLease = null;
|
|
2867
|
-
let stopTimer;
|
|
2868
|
-
let removeStopListener;
|
|
2869
|
-
let forcedStop = false;
|
|
2870
|
-
let runtimeStopConfirmed = false;
|
|
2871
|
-
let safeInterruptedSession = false;
|
|
2872
|
-
const interruptionTools = new Map();
|
|
2873
|
-
let incompleteToolInventory = false;
|
|
2874
2850
|
try {
|
|
2875
|
-
await ctx.onCancellationReady?.();
|
|
2876
|
-
if (ctx.signal?.aborted)
|
|
2877
|
-
return {
|
|
2878
|
-
exitCode: null, signal: null, timedOut: false,
|
|
2879
|
-
errorCode: "cancelled", errorMessage: "Stopped before provider startup",
|
|
2880
|
-
executionRecovery: { kind: "bootstrap", providerWorkStarted: false },
|
|
2881
|
-
resultJson: { executionCancellation: { state: "acknowledged", acknowledgedAt: new Date().toISOString(), forced: false } },
|
|
2882
|
-
};
|
|
2883
2851
|
// Evict idle staged runtimes BEFORE building the runtime, since buildRuntime
|
|
2884
2852
|
// consults the staged cache to decide whether a compatible resume may reuse
|
|
2885
2853
|
// an already-staged runtime — an expired entry must not be reused.
|
|
@@ -3085,9 +3053,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3085
3053
|
await hostStore.evictIdle(now());
|
|
3086
3054
|
const previousParams = parseObject(ctx.runtime.sessionParams);
|
|
3087
3055
|
const canResume = isCompatibleSession(previousParams, prepared);
|
|
3088
|
-
if (previousParams.interruptedCheckpoint === true && !canResume) {
|
|
3089
|
-
throw new Error("The interrupted session is no longer compatible. Its action history must be checked before starting a new session.");
|
|
3090
|
-
}
|
|
3091
3056
|
const resumeSessionId = canResume ? asString(previousParams.acpSessionId, "") || undefined : undefined;
|
|
3092
3057
|
// Borrow the warm entry without removing it, so an overlapping run of the
|
|
3093
3058
|
// same session still sees it. The borrow clears the entry's idle timer, so
|
|
@@ -3105,28 +3070,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3105
3070
|
processIdentitySink.current = ctx.onSpawn;
|
|
3106
3071
|
flushChildStderr(childStderrState);
|
|
3107
3072
|
childStderrState.logPath = prepared.childStderrLogPath;
|
|
3108
|
-
const persistedRuntimeStore = createRuntimeStore({ stateDir: prepared.stateDir });
|
|
3109
|
-
const runtimeStore = {
|
|
3110
|
-
async load(id) {
|
|
3111
|
-
const record = await persistedRuntimeStore.load(id);
|
|
3112
|
-
if (!record)
|
|
3113
|
-
return undefined;
|
|
3114
|
-
// ACPX resumes from the stored session options rather than the
|
|
3115
|
-
// options passed to ensureSession. Keep conversation state, but
|
|
3116
|
-
// launch the provider with this run's credentials and scratch paths.
|
|
3117
|
-
return {
|
|
3118
|
-
...record,
|
|
3119
|
-
acpx: {
|
|
3120
|
-
...record.acpx,
|
|
3121
|
-
session_options: {
|
|
3122
|
-
...record.acpx?.session_options,
|
|
3123
|
-
env: { ...prepared.env },
|
|
3124
|
-
},
|
|
3125
|
-
},
|
|
3126
|
-
};
|
|
3127
|
-
},
|
|
3128
|
-
save: (record) => persistedRuntimeStore.save(record),
|
|
3129
|
-
};
|
|
3130
3073
|
const runtimeOptions = {
|
|
3131
3074
|
cwd: prepared.cwd,
|
|
3132
3075
|
// Host-only spawn cwd for the relay proxy on the remote process-session
|
|
@@ -3135,7 +3078,7 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3135
3078
|
// fingerprint / compat key are unaffected — this redirects ONLY the host
|
|
3136
3079
|
// `spawn()` `chdir`, not the in-sandbox data path.
|
|
3137
3080
|
spawnCwd: prepared.hostSpawnCwd,
|
|
3138
|
-
sessionStore:
|
|
3081
|
+
sessionStore: createRuntimeStore({ stateDir: prepared.stateDir }),
|
|
3139
3082
|
agentRegistry: prepared.agentRegistry,
|
|
3140
3083
|
permissionMode: prepared.permissionMode,
|
|
3141
3084
|
nonInteractivePermissions: prepared.nonInteractivePermissions,
|
|
@@ -3154,7 +3097,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3154
3097
|
: undefined,
|
|
3155
3098
|
onAgentSpawn: async (meta) => {
|
|
3156
3099
|
processIdentitySink.latest = meta;
|
|
3157
|
-
processIdentitySink.localProcess = prepared.processSessionBridge ? undefined : captureLocalProcess(meta.pid);
|
|
3158
3100
|
await processIdentitySink.current?.({
|
|
3159
3101
|
pid: meta.pid,
|
|
3160
3102
|
processGroupId: null,
|
|
@@ -3280,7 +3222,7 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3280
3222
|
});
|
|
3281
3223
|
}
|
|
3282
3224
|
catch (err) {
|
|
3283
|
-
if (!resumeSessionId || !isResumeFailure(err)
|
|
3225
|
+
if (!resumeSessionId || !isResumeFailure(err))
|
|
3284
3226
|
throw err;
|
|
3285
3227
|
clearSession = true;
|
|
3286
3228
|
resumedSession = false;
|
|
@@ -3326,9 +3268,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3326
3268
|
});
|
|
3327
3269
|
}
|
|
3328
3270
|
// A compatible warm handle reuses the already-running ACP agent and does
|
|
3329
|
-
if (previousParams.interruptedCheckpoint === true && handle?.backendSessionId !== resumeSessionId) {
|
|
3330
|
-
throw new Error("The provider did not restore the interrupted session; refusing a fresh-session fallback.");
|
|
3331
|
-
}
|
|
3332
3271
|
// not emit another spawn event. Persist its known identity on this run
|
|
3333
3272
|
// before the next prompt starts so every running heartbeat is adoptable.
|
|
3334
3273
|
if (handle && cached && processIdentitySink.latest && ctx.onSpawn) {
|
|
@@ -3635,7 +3574,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3635
3574
|
turnPhaseStart = now();
|
|
3636
3575
|
};
|
|
3637
3576
|
const stepTurnStart = (signal, startTimeoutMs) => {
|
|
3638
|
-
ctx.signal?.throwIfAborted();
|
|
3639
3577
|
const turn = runtime.startTurn({
|
|
3640
3578
|
handle: sessionHandle,
|
|
3641
3579
|
text: runPrompt,
|
|
@@ -3645,27 +3583,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3645
3583
|
signal,
|
|
3646
3584
|
});
|
|
3647
3585
|
activeTurn = turn;
|
|
3648
|
-
// ACP can resolve the turn before its provider exits. Keep the Stop
|
|
3649
|
-
// deadline armed through settlement, including provider cleanup.
|
|
3650
|
-
const armStopDeadline = () => {
|
|
3651
|
-
stopTimer = setTimeout(() => {
|
|
3652
|
-
forcedStop = true;
|
|
3653
|
-
const providerPid = processIdentitySink.latest?.pid;
|
|
3654
|
-
if (providerPid && !prepared.processSessionBridge) {
|
|
3655
|
-
// Escalate the owned local process directly. A second ACP close
|
|
3656
|
-
// can wait behind the same hung cleanup (or open a new client).
|
|
3657
|
-
killCapturedLocalProcess(processIdentitySink.localProcess);
|
|
3658
|
-
}
|
|
3659
|
-
else {
|
|
3660
|
-
void runtime.close({ handle: sessionHandle, reason: "operator stop deadline", discardPersistentState: true })
|
|
3661
|
-
.catch(() => { });
|
|
3662
|
-
}
|
|
3663
|
-
}, Math.max(1, asNumber(ctx.config.graceSec, 15)) * 1000);
|
|
3664
|
-
};
|
|
3665
|
-
ctx.signal?.addEventListener("abort", armStopDeadline, { once: true });
|
|
3666
|
-
removeStopListener = () => ctx.signal?.removeEventListener("abort", armStopDeadline);
|
|
3667
|
-
if (ctx.signal?.aborted)
|
|
3668
|
-
armStopDeadline();
|
|
3669
3586
|
return {
|
|
3670
3587
|
cancel: async (reason) => {
|
|
3671
3588
|
await turn.cancel({ reason });
|
|
@@ -3676,21 +3593,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3676
3593
|
const turn = activeTurn;
|
|
3677
3594
|
const toolTitles = new Map();
|
|
3678
3595
|
for await (const event of turn.events) {
|
|
3679
|
-
// ACPX currently flattens client-side filesystem/terminal receipts
|
|
3680
|
-
// into status text. They cannot establish complete action outcomes.
|
|
3681
|
-
if (event.type === "status" && /^(fs|terminal)\//.test(event.text))
|
|
3682
|
-
incompleteToolInventory = true;
|
|
3683
|
-
if (event.type === "tool_call") {
|
|
3684
|
-
if (!event.toolCallId)
|
|
3685
|
-
incompleteToolInventory = true;
|
|
3686
|
-
else {
|
|
3687
|
-
const previous = interruptionTools.get(event.toolCallId);
|
|
3688
|
-
interruptionTools.set(event.toolCallId, {
|
|
3689
|
-
kind: event.kind ?? previous?.kind,
|
|
3690
|
-
status: event.status ?? previous?.status,
|
|
3691
|
-
});
|
|
3692
|
-
}
|
|
3693
|
-
}
|
|
3694
3596
|
if (event.type === "text_delta" && event.stream !== "thought") {
|
|
3695
3597
|
currentOutputChunk.push(event.text);
|
|
3696
3598
|
}
|
|
@@ -3765,15 +3667,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3765
3667
|
eventCostUsd,
|
|
3766
3668
|
});
|
|
3767
3669
|
const failedTurn = terminal.status === "failed" || terminal.status === "cancelled" || timedOut;
|
|
3768
|
-
// A provider-native command/write has no reliable external outcome
|
|
3769
|
-
// receipt. Only settled reads (or a turn with no tools) can establish
|
|
3770
|
-
// automatic interrupted-session continuity here.
|
|
3771
|
-
safeInterruptedSession = ctx.signal?.aborted === true && !forcedStop && !timedOut && !channelLost
|
|
3772
|
-
&& (terminal.status === "cancelled" || terminal.status === "completed")
|
|
3773
|
-
&& prepared.mode === "persistent" && !prepared.processSessionBridge
|
|
3774
|
-
&& Boolean(sessionHandle.backendSessionId)
|
|
3775
|
-
&& !incompleteToolInventory
|
|
3776
|
-
&& [...interruptionTools.values()].every((tool) => tool.kind === "read" && tool.status === "completed");
|
|
3777
3670
|
// Record how the settlement `endSession` step closes the runtime for this
|
|
3778
3671
|
// outcome. A clean persistent host turn is save-eligible, but the
|
|
3779
3672
|
// Amendment B credential gate fails on the host lane (the run API key is
|
|
@@ -3793,7 +3686,7 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3793
3686
|
: failedTurn
|
|
3794
3687
|
? `paperclip turn ${terminal.status}`
|
|
3795
3688
|
: "paperclip completed turn cleanup",
|
|
3796
|
-
discardPersistentState:
|
|
3689
|
+
discardPersistentState: terminal.status === "cancelled" || timedOut || channelLost,
|
|
3797
3690
|
dropWarmEntry: false,
|
|
3798
3691
|
recordCloseError: false,
|
|
3799
3692
|
cancelTurnReason: null,
|
|
@@ -3969,7 +3862,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
3969
3862
|
};
|
|
3970
3863
|
try {
|
|
3971
3864
|
return await runTurnSequence({
|
|
3972
|
-
signal: ctx.signal,
|
|
3973
3865
|
timeoutMs: prepared.timeoutSec > 0 ? prepared.timeoutSec * 1000 : undefined,
|
|
3974
3866
|
timeoutMessage: formatAdapterExecutionTimeoutErrorMessage(prepared.timeoutResolution),
|
|
3975
3867
|
promptBuild: stepPromptBuild,
|
|
@@ -4108,7 +4000,7 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
4108
4000
|
});
|
|
4109
4001
|
return;
|
|
4110
4002
|
}
|
|
4111
|
-
const onCloseError = settlement.recordCloseError
|
|
4003
|
+
const onCloseError = settlement.recordCloseError
|
|
4112
4004
|
? (closeErr) => recordTeardownError("runtime-close", closeErr)
|
|
4113
4005
|
: () => { };
|
|
4114
4006
|
await runtime
|
|
@@ -4117,7 +4009,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
4117
4009
|
reason: settlement.reason,
|
|
4118
4010
|
discardPersistentState: settlement.discardPersistentState,
|
|
4119
4011
|
})
|
|
4120
|
-
.then(() => { runtimeStopConfirmed = true; })
|
|
4121
4012
|
.catch(onCloseError);
|
|
4122
4013
|
if (settlement.dropWarmEntry && warmHandleMatches(existing, runtime, settlement.handle) && existing) {
|
|
4123
4014
|
clearWarmHandleTimer(existing);
|
|
@@ -4191,35 +4082,10 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
4191
4082
|
if (childStderrState)
|
|
4192
4083
|
flushChildStderr(childStderrState);
|
|
4193
4084
|
},
|
|
4194
|
-
reproduceResult:
|
|
4085
|
+
reproduceResult: () => {
|
|
4195
4086
|
if (!capturedResult) {
|
|
4196
4087
|
throw new Error("run coordinator reproduced a result before the run recorded one");
|
|
4197
4088
|
}
|
|
4198
|
-
clearTimeout(stopTimer);
|
|
4199
|
-
let providerExited = false;
|
|
4200
|
-
const providerPid = processIdentitySink?.latest?.pid;
|
|
4201
|
-
if (ctx.signal?.aborted && providerPid && !prepared.processSessionBridge) {
|
|
4202
|
-
for (let attempt = 0; attempt < 40; attempt += 1) {
|
|
4203
|
-
providerExited = capturedProcessExited(processIdentitySink.localProcess);
|
|
4204
|
-
if (providerExited || !forcedStop)
|
|
4205
|
-
break;
|
|
4206
|
-
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
4207
|
-
}
|
|
4208
|
-
}
|
|
4209
|
-
// A forced process exit can reject ACP close after the OS has already
|
|
4210
|
-
// confirmed termination. Acknowledge Stop, but never grant replay.
|
|
4211
|
-
if (ctx.signal?.aborted && providerExited && (runtimeStopConfirmed || forcedStop)) {
|
|
4212
|
-
capturedResult = {
|
|
4213
|
-
...capturedResult,
|
|
4214
|
-
...(safeInterruptedSession && !forcedStop && !("workspaceRestoreFailure" in workspaceRestoreFailureField)
|
|
4215
|
-
? { executionRecovery: { kind: "interrupted", providerStopped: true, sessionPreserved: true, actionOutcomes: "settled" },
|
|
4216
|
-
sessionParams: { ...capturedResult.sessionParams, interruptedCheckpoint: true } }
|
|
4217
|
-
: {}),
|
|
4218
|
-
resultJson: { ...capturedResult.resultJson, executionCancellation: {
|
|
4219
|
-
state: "acknowledged", acknowledgedAt: new Date().toISOString(), forced: forcedStop,
|
|
4220
|
-
} },
|
|
4221
|
-
};
|
|
4222
|
-
}
|
|
4223
4089
|
// The sync-back settlement step runs before this reproduces the result
|
|
4224
4090
|
// (settlement precedes reproduction), so a failed workspace restore is
|
|
4225
4091
|
// already recorded by the time we get here. Merge it into `resultJson`
|
|
@@ -4239,8 +4105,6 @@ export function createAcpxEngineExecutor(deps = {}) {
|
|
|
4239
4105
|
return await runAttempt(plan);
|
|
4240
4106
|
}
|
|
4241
4107
|
finally {
|
|
4242
|
-
clearTimeout(stopTimer);
|
|
4243
|
-
removeStopListener?.();
|
|
4244
4108
|
// End the run root span exactly once, on every return and on a throw.
|
|
4245
4109
|
runRootSpan.end(runFailed);
|
|
4246
4110
|
// Release the per-session staging lease as the run's final act, AFTER the
|