larkin 0.5.4 → 0.5.6
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/CHANGELOG.md +6 -0
- package/README.md +7 -1
- package/artifacts/release/THIRD_PARTY_NOTICES.txt +1 -100
- package/dist/agent/context-prompt.cjs +19 -17
- package/dist/agent/context-prompt.mjs +18 -16
- package/dist/runtime/pi-state-dir.cjs +105 -0
- package/dist/runtime/pi-state-dir.mjs +94 -0
- package/dist/runtime/pi-tmux-extension.mjs +137 -0
- package/dist/runtime/pi-tmux-injection.mjs +49 -0
- package/dist/runtime/pi-tmux.bundle.js +600 -0
- package/dist/runtime/pi-tmux.mjs +408 -0
- package/dist/runtime/runtime-adapters.mjs +34 -114
- package/dist/runtime/runtime-host.cjs +3 -413
- package/dist/runtime/runtime-host.mjs +2 -412
- package/package.json +2 -8
- package/dist/runtime/pi-bash-timeout-extension.mjs +0 -60
- package/dist/runtime/pi-bash-timeout-injection.mjs +0 -54
- package/dist/runtime/pi-bash-timeout.bundle.js +0 -43
- package/dist/runtime/pi-extension-api.mjs +0 -1
- package/dist/runtime/pi-subagent-injection.mjs +0 -290
- package/dist/runtime/pi-subagent-ledger.cjs +0 -632
- package/dist/runtime/pi-subagent-ledger.mjs +0 -594
- package/dist/runtime/pi-subagent-record-watchdog-injection.mjs +0 -43
- package/dist/runtime/pi-subagent-record-watchdog.bundle.js +0 -183
- package/dist/runtime/pi-subagent-record-watchdog.mjs +0 -46
- package/dist/runtime/pi-subagents-notification.mjs +0 -175
- package/dist/runtime/pi-subagents.bundle.js +0 -9110
- package/dist/runtime/pi-supervised-command-extension.mjs +0 -72
- package/dist/runtime/pi-supervised-command.bundle.js +0 -4735
- package/dist/runtime/pi-supervised-command.mjs +0 -420
- package/patches/@tintinweb%2Fpi-subagents@0.14.3.patch +0 -945
|
@@ -17,7 +17,7 @@ const runtime_readiness_js_1 = require("./runtime-readiness.cjs");
|
|
|
17
17
|
const official_lark_cli_js_1 = require("../app/official-lark-cli.cjs");
|
|
18
18
|
const agent_lark_cli_workspace_js_1 = require("../app/agent-lark-cli-workspace.cjs");
|
|
19
19
|
const pi_compaction_recovery_js_1 = require("./pi-compaction-recovery.cjs");
|
|
20
|
-
const
|
|
20
|
+
const pi_state_dir_js_1 = require("./pi-state-dir.cjs");
|
|
21
21
|
class RuntimeSessionResetError extends Error {
|
|
22
22
|
code;
|
|
23
23
|
pendingCount;
|
|
@@ -41,8 +41,6 @@ class RuntimeSessionRecoveryError extends Error {
|
|
|
41
41
|
}
|
|
42
42
|
exports.RuntimeSessionRecoveryError = RuntimeSessionRecoveryError;
|
|
43
43
|
const MAX_DELIVERIES = 2048;
|
|
44
|
-
const BACKGROUND_COMPLETION_IMMEDIATE_RETRY_LIMIT = 5;
|
|
45
|
-
const DEFAULT_SUBAGENT_RECONCILE_INTERVAL_MS = 15_000;
|
|
46
44
|
const now = () => new Date().toISOString();
|
|
47
45
|
const isActiveDelivery = (status) => ["pending", "submitting", "accepted"].includes(status);
|
|
48
46
|
const previousSessionRefFor = (session, reason) => session.sessionId
|
|
@@ -310,10 +308,6 @@ function createRuntimeHost(options) {
|
|
|
310
308
|
maxAttempts: options.retryPolicy?.maxAttempts ?? 6,
|
|
311
309
|
stableWindowMs: options.retryPolicy?.stableWindowMs ?? 30_000,
|
|
312
310
|
};
|
|
313
|
-
const subagentReconcileIntervalMs = options.subagentReconcileIntervalMs ?? DEFAULT_SUBAGENT_RECONCILE_INTERVAL_MS;
|
|
314
|
-
if (!Number.isFinite(subagentReconcileIntervalMs) || subagentReconcileIntervalMs < 0) {
|
|
315
|
-
throw new Error("subagentReconcileIntervalMs must be >= 0");
|
|
316
|
-
}
|
|
317
311
|
const emit = (event) => {
|
|
318
312
|
if (event.type === "delivery")
|
|
319
313
|
telemetry?.delivery(event.agentId, event.messageId, event.status);
|
|
@@ -325,11 +319,10 @@ function createRuntimeHost(options) {
|
|
|
325
319
|
LARKIN_AGENT_ID: config.agentId,
|
|
326
320
|
...(generation ? {
|
|
327
321
|
LARKIN_RUNTIME_OBSERVATION_GENERATION: generation,
|
|
328
|
-
[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV]: generation,
|
|
329
322
|
} : {}),
|
|
330
323
|
LARKIN_CONFIG_DIR: process.env.LARKIN_CONFIG_DIR,
|
|
331
324
|
LARKIN_HOME: process.env.LARKIN_HOME,
|
|
332
|
-
LARKIN_STATE_DIR: (0,
|
|
325
|
+
LARKIN_STATE_DIR: (0, pi_state_dir_js_1.effectivePiStateDir)(config),
|
|
333
326
|
...(process.env.HOME ? { HOME: process.env.HOME } : {}),
|
|
334
327
|
...(process.env.SHELL ? { SHELL: process.env.SHELL } : {}),
|
|
335
328
|
...(process.env.ZDOTDIR ? { ZDOTDIR: process.env.ZDOTDIR } : {}),
|
|
@@ -726,12 +719,6 @@ function createRuntimeHost(options) {
|
|
|
726
719
|
queueMicrotask(() => { void retryPending(agent); });
|
|
727
720
|
}
|
|
728
721
|
queueMicrotask(() => { void scanAndPromoteAcceptedInboxUpdates(agent); });
|
|
729
|
-
// A completion queued during this submit has no turn-end if prompt
|
|
730
|
-
// rejected/threw before turn-start. Drain now that submitting is clear.
|
|
731
|
-
if (!agent.busy && !agent.turnInProgress && agent.backgroundCompletionQueue.length > 0
|
|
732
|
-
&& !agent.backgroundCompletionRetryTimer) {
|
|
733
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
734
|
-
}
|
|
735
722
|
}
|
|
736
723
|
};
|
|
737
724
|
const retryPending = async (agent) => {
|
|
@@ -808,326 +795,6 @@ function createRuntimeHost(options) {
|
|
|
808
795
|
agent.retryAfterSubmit = true;
|
|
809
796
|
await retryPending(agent);
|
|
810
797
|
};
|
|
811
|
-
const clearBackgroundCompletionRetryTimer = (agent) => {
|
|
812
|
-
if (!agent.backgroundCompletionRetryTimer)
|
|
813
|
-
return;
|
|
814
|
-
clearTimeout(agent.backgroundCompletionRetryTimer);
|
|
815
|
-
agent.backgroundCompletionRetryTimer = null;
|
|
816
|
-
};
|
|
817
|
-
const scheduleBackgroundCompletionDrain = (agent, delayMs = 0) => {
|
|
818
|
-
if (agent.stopped)
|
|
819
|
-
return;
|
|
820
|
-
if (delayMs > 0) {
|
|
821
|
-
if (agent.backgroundCompletionRetryTimer)
|
|
822
|
-
return;
|
|
823
|
-
agent.backgroundCompletionRetryTimer = setTimeout(() => {
|
|
824
|
-
agent.backgroundCompletionRetryTimer = null;
|
|
825
|
-
if (agent.stopped)
|
|
826
|
-
return;
|
|
827
|
-
void drainBackgroundCompletionQueue(agent);
|
|
828
|
-
}, delayMs);
|
|
829
|
-
agent.backgroundCompletionRetryTimer.unref?.();
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
clearBackgroundCompletionRetryTimer(agent);
|
|
833
|
-
queueMicrotask(() => { void drainBackgroundCompletionQueue(agent); });
|
|
834
|
-
};
|
|
835
|
-
const dropBackgroundCompletion = (agent, completionKey) => {
|
|
836
|
-
if (!completionKey)
|
|
837
|
-
return;
|
|
838
|
-
if (agent.backgroundCompletionQueue[0] === completionKey)
|
|
839
|
-
agent.backgroundCompletionQueue.shift();
|
|
840
|
-
else {
|
|
841
|
-
const index = agent.backgroundCompletionQueue.indexOf(completionKey);
|
|
842
|
-
if (index >= 0)
|
|
843
|
-
agent.backgroundCompletionQueue.splice(index, 1);
|
|
844
|
-
}
|
|
845
|
-
agent.backgroundCompletionKeys.add(completionKey);
|
|
846
|
-
if (agent.backgroundCompletionInFlight === completionKey) {
|
|
847
|
-
agent.backgroundCompletionInFlight = null;
|
|
848
|
-
agent.backgroundCompletionWakeInputId = null;
|
|
849
|
-
}
|
|
850
|
-
agent.backgroundCompletionRejectStreak = 0;
|
|
851
|
-
clearBackgroundCompletionRetryTimer(agent);
|
|
852
|
-
// Leave the durable wake pending so a later restart can requeue it.
|
|
853
|
-
};
|
|
854
|
-
const scheduleBackgroundCompletionRetry = (agent) => {
|
|
855
|
-
const streak = agent.backgroundCompletionRejectStreak;
|
|
856
|
-
if (streak < BACKGROUND_COMPLETION_IMMEDIATE_RETRY_LIMIT) {
|
|
857
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
858
|
-
return;
|
|
859
|
-
}
|
|
860
|
-
const delayedAttempt = streak - BACKGROUND_COMPLETION_IMMEDIATE_RETRY_LIMIT;
|
|
861
|
-
if (delayedAttempt >= retryPolicy.maxAttempts) {
|
|
862
|
-
const exhausted = agent.backgroundCompletionQueue[0];
|
|
863
|
-
if (exhausted) {
|
|
864
|
-
log("background completion wake retries exhausted", exhausted);
|
|
865
|
-
dropBackgroundCompletion(agent, exhausted);
|
|
866
|
-
}
|
|
867
|
-
if (agent.backgroundCompletionQueue.length > 0)
|
|
868
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
const delay = Math.min(retryPolicy.maxDelayMs, retryPolicy.baseDelayMs * 2 ** delayedAttempt);
|
|
872
|
-
scheduleBackgroundCompletionDrain(agent, delay);
|
|
873
|
-
};
|
|
874
|
-
const isPersistentBackgroundWakeFailure = (event) => {
|
|
875
|
-
if (!event)
|
|
876
|
-
return false;
|
|
877
|
-
const category = event.errorCategory;
|
|
878
|
-
if (category === "auth" || category === "billing" || category === "quota")
|
|
879
|
-
return true;
|
|
880
|
-
return category === "provider" && event.retryable === false;
|
|
881
|
-
};
|
|
882
|
-
const failBackgroundCompletionWake = (agent, event) => {
|
|
883
|
-
const completionKey = agent.backgroundCompletionInFlight ?? agent.backgroundCompletionQueue[0];
|
|
884
|
-
if (!completionKey)
|
|
885
|
-
return;
|
|
886
|
-
rearmBackgroundCompletion(agent, completionKey);
|
|
887
|
-
if (isPersistentBackgroundWakeFailure(event)) {
|
|
888
|
-
log("background completion wake dropped", event?.errorCategory ?? "persistent");
|
|
889
|
-
dropBackgroundCompletion(agent, completionKey);
|
|
890
|
-
if (agent.backgroundCompletionQueue.length > 0)
|
|
891
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
892
|
-
return;
|
|
893
|
-
}
|
|
894
|
-
agent.backgroundCompletionRejectStreak += 1;
|
|
895
|
-
scheduleBackgroundCompletionRetry(agent);
|
|
896
|
-
};
|
|
897
|
-
const rearmBackgroundCompletion = (agent, completionKey = agent.backgroundCompletionInFlight) => {
|
|
898
|
-
if (!completionKey)
|
|
899
|
-
return;
|
|
900
|
-
agent.backgroundCompletionKeys.delete(completionKey);
|
|
901
|
-
if (agent.backgroundCompletionInFlight === completionKey) {
|
|
902
|
-
agent.backgroundCompletionInFlight = null;
|
|
903
|
-
agent.backgroundCompletionWakeInputId = null;
|
|
904
|
-
}
|
|
905
|
-
if (!agent.backgroundCompletionQueue.includes(completionKey)) {
|
|
906
|
-
agent.backgroundCompletionQueue.unshift(completionKey);
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
|
-
const commitBackgroundCompletion = (agent) => {
|
|
910
|
-
const completionKey = agent.backgroundCompletionInFlight;
|
|
911
|
-
if (!completionKey)
|
|
912
|
-
return;
|
|
913
|
-
if (agent.backgroundCompletionQueue[0] === completionKey)
|
|
914
|
-
agent.backgroundCompletionQueue.shift();
|
|
915
|
-
agent.backgroundCompletionInFlight = null;
|
|
916
|
-
agent.backgroundCompletionWakeInputId = null;
|
|
917
|
-
agent.backgroundCompletionRejectStreak = 0;
|
|
918
|
-
clearBackgroundCompletionRetryTimer(agent);
|
|
919
|
-
acknowledgeSubagentWake(agent, completionKey);
|
|
920
|
-
};
|
|
921
|
-
const wakeOnBackgroundCompletion = async (agent) => {
|
|
922
|
-
// Caller already reserved submitting/busy so a concurrent idle drain cannot
|
|
923
|
-
// dequeue another head while ensureSession/prompt yields.
|
|
924
|
-
try {
|
|
925
|
-
const session = await ensureSession(agent);
|
|
926
|
-
if (agent.session !== session || agent.stopped)
|
|
927
|
-
return { status: "dropped" };
|
|
928
|
-
const headKey = agent.backgroundCompletionQueue[0];
|
|
929
|
-
const tasks = (0, pi_subagent_ledger_js_1.taskIdsFromCompletionKey)(headKey ?? "")
|
|
930
|
-
.map((taskId) => (0, pi_subagent_ledger_js_1.getDispatchedSubagent)(agent.subagentLedger, taskId))
|
|
931
|
-
.filter((task) => Boolean(task));
|
|
932
|
-
const details = tasks.map((task) => `task ${task.taskId} status=${task.status}`).join("; ");
|
|
933
|
-
const wakeReason = details
|
|
934
|
-
? `background subagent completed; ${details}`
|
|
935
|
-
: "background subagent completed";
|
|
936
|
-
const input = options.promptBuilder.buildRuntimeInput("wake", node_crypto_1.default.randomUUID(), { wakeReason });
|
|
937
|
-
const result = await session.prompt(input);
|
|
938
|
-
if (agent.session !== session || agent.stopped)
|
|
939
|
-
return { status: "dropped" };
|
|
940
|
-
if (result.status === "accepted") {
|
|
941
|
-
markSessionStable(agent, session);
|
|
942
|
-
return { status: "accepted", inputId: input.inputId };
|
|
943
|
-
}
|
|
944
|
-
agent.busy = false;
|
|
945
|
-
return { status: "retry" };
|
|
946
|
-
}
|
|
947
|
-
catch (error) {
|
|
948
|
-
agent.busy = false;
|
|
949
|
-
log("background completion wake failed", error instanceof Error ? error.message : String(error));
|
|
950
|
-
return { status: "retry" };
|
|
951
|
-
}
|
|
952
|
-
};
|
|
953
|
-
const drainBackgroundCompletionQueue = async (agent) => {
|
|
954
|
-
if (agent.stopped || agent.busy || agent.turnInProgress || agent.submitting)
|
|
955
|
-
return;
|
|
956
|
-
if (agent.backgroundCompletionInFlight || !agent.backgroundCompletionQueue.length)
|
|
957
|
-
return;
|
|
958
|
-
clearBackgroundCompletionRetryTimer(agent);
|
|
959
|
-
const proactive = agent.piProactiveCompaction
|
|
960
|
-
&& agent.piProactiveCompactionGeneration === agent.generation
|
|
961
|
-
&& agent.piProactiveCompactionSession === agent.session
|
|
962
|
-
? agent.piProactiveCompaction : null;
|
|
963
|
-
if (proactive)
|
|
964
|
-
await proactive;
|
|
965
|
-
if (agent.adapter.id === "pi" && !agent.busy && !agent.turnInProgress && agent.session) {
|
|
966
|
-
const idleGate = proactivelyCompactPiAtIdle(agent, agent.session);
|
|
967
|
-
if (idleGate)
|
|
968
|
-
await idleGate;
|
|
969
|
-
}
|
|
970
|
-
if (agent.stopped || agent.busy || agent.turnInProgress || agent.submitting)
|
|
971
|
-
return;
|
|
972
|
-
if (agent.backgroundCompletionInFlight || !agent.backgroundCompletionQueue.length)
|
|
973
|
-
return;
|
|
974
|
-
agent.submitting = true;
|
|
975
|
-
agent.busy = true;
|
|
976
|
-
const completionKey = agent.backgroundCompletionQueue[0];
|
|
977
|
-
try {
|
|
978
|
-
const outcome = await wakeOnBackgroundCompletion(agent);
|
|
979
|
-
if (outcome.status === "accepted") {
|
|
980
|
-
agent.backgroundCompletionKeys.add(completionKey);
|
|
981
|
-
agent.backgroundCompletionInFlight = completionKey;
|
|
982
|
-
agent.backgroundCompletionWakeInputId = outcome.inputId;
|
|
983
|
-
// Keep the reject streak until the wake turn actually succeeds. An accepted
|
|
984
|
-
// prompt that later terminal-fails must not reset the bounded retry budget.
|
|
985
|
-
clearBackgroundCompletionRetryTimer(agent);
|
|
986
|
-
}
|
|
987
|
-
else if (outcome.status === "dropped") {
|
|
988
|
-
if (agent.stopped) {
|
|
989
|
-
if (agent.backgroundCompletionQueue[0] === completionKey)
|
|
990
|
-
agent.backgroundCompletionQueue.shift();
|
|
991
|
-
agent.backgroundCompletionKeys.delete(completionKey);
|
|
992
|
-
clearBackgroundCompletionRetryTimer(agent);
|
|
993
|
-
}
|
|
994
|
-
else {
|
|
995
|
-
rearmBackgroundCompletion(agent, completionKey);
|
|
996
|
-
agent.busy = false;
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
else {
|
|
1000
|
-
agent.busy = false;
|
|
1001
|
-
agent.backgroundCompletionRejectStreak += 1;
|
|
1002
|
-
// Leave the item queued+deduped. Immediate microtask retries cover a
|
|
1003
|
-
// brief reject; after that a bounded timer still drains because Pi will
|
|
1004
|
-
// not re-emit the same completion.
|
|
1005
|
-
scheduleBackgroundCompletionRetry(agent);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
finally {
|
|
1009
|
-
agent.submitting = false;
|
|
1010
|
-
}
|
|
1011
|
-
};
|
|
1012
|
-
const persistSubagentLedger = (agent) => {
|
|
1013
|
-
(0, pi_subagent_ledger_js_1.writeDispatchedSubagentLedger)((0, pi_subagent_ledger_js_1.ledgerFilePath)((0, pi_subagent_ledger_js_1.effectivePiStateDir)(agent.config)), agent.subagentLedger);
|
|
1014
|
-
};
|
|
1015
|
-
const dropQueuedBackgroundCompletionFallback = (agent, completionKey) => {
|
|
1016
|
-
const keys = new Set([completionKey, ...(0, pi_subagent_ledger_js_1.taskIdsFromCompletionKey)(completionKey)]);
|
|
1017
|
-
for (let index = agent.backgroundCompletionQueue.length - 1; index >= 0; index -= 1) {
|
|
1018
|
-
const queued = agent.backgroundCompletionQueue[index];
|
|
1019
|
-
if (queued && keys.has(queued))
|
|
1020
|
-
agent.backgroundCompletionQueue.splice(index, 1);
|
|
1021
|
-
}
|
|
1022
|
-
for (const key of keys)
|
|
1023
|
-
agent.backgroundCompletionKeys.add(key);
|
|
1024
|
-
};
|
|
1025
|
-
const acknowledgeSubagentWake = (agent, completionKey) => {
|
|
1026
|
-
const next = (0, pi_subagent_ledger_js_1.noteDispatchedSubagentWakeAcknowledged)(agent.subagentLedger, { completionKey });
|
|
1027
|
-
if (next === agent.subagentLedger)
|
|
1028
|
-
return;
|
|
1029
|
-
agent.subagentLedger = next;
|
|
1030
|
-
persistSubagentLedger(agent);
|
|
1031
|
-
for (const taskId of (0, pi_subagent_ledger_js_1.taskIdsFromCompletionKey)(completionKey)) {
|
|
1032
|
-
(0, pi_subagent_ledger_js_1.retirePiSubagentRecord)((0, pi_subagent_ledger_js_1.getDispatchedSubagent)(agent.subagentLedger, taskId)?.recordFile);
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
const enqueueUndeliveredTerminalWakes = (agent) => {
|
|
1036
|
-
for (const key of (0, pi_subagent_ledger_js_1.undeliveredTerminalWakeKeys)(agent.subagentLedger)) {
|
|
1037
|
-
agent.backgroundCompletionKeys.delete(key);
|
|
1038
|
-
for (const taskId of (0, pi_subagent_ledger_js_1.taskIdsFromCompletionKey)(key))
|
|
1039
|
-
agent.backgroundCompletionKeys.delete(taskId);
|
|
1040
|
-
noteBackgroundCompletion(agent, key);
|
|
1041
|
-
}
|
|
1042
|
-
};
|
|
1043
|
-
const reconcileAfterSessionSwap = (agent) => {
|
|
1044
|
-
reconcileSubagentLedger(agent, { forceMissing: true, missingReason: "pi session gone" });
|
|
1045
|
-
enqueueUndeliveredTerminalWakes(agent);
|
|
1046
|
-
if (agent.backgroundCompletionQueue.length > 0)
|
|
1047
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
1048
|
-
};
|
|
1049
|
-
const loadSubagentLedger = (config) => {
|
|
1050
|
-
return (0, pi_subagent_ledger_js_1.readDispatchedSubagentLedger)((0, pi_subagent_ledger_js_1.ledgerFilePath)((0, pi_subagent_ledger_js_1.effectivePiStateDir)(config)));
|
|
1051
|
-
};
|
|
1052
|
-
const clearSubagentReconcileTimer = (agent) => {
|
|
1053
|
-
if (!agent.subagentReconcileTimer)
|
|
1054
|
-
return;
|
|
1055
|
-
clearInterval(agent.subagentReconcileTimer);
|
|
1056
|
-
agent.subagentReconcileTimer = null;
|
|
1057
|
-
};
|
|
1058
|
-
const hasActiveDispatchedSubagent = (agent) => agent.subagentLedger.tasks.some((task) => task.status === "dispatched");
|
|
1059
|
-
const noteBackgroundCompletion = (agent, completionKey) => {
|
|
1060
|
-
const taskIds = (0, pi_subagent_ledger_js_1.taskIdsFromCompletionKey)(completionKey);
|
|
1061
|
-
if (agent.backgroundCompletionKeys.has(completionKey))
|
|
1062
|
-
return;
|
|
1063
|
-
if (taskIds.length > 0 && taskIds.every((taskId) => agent.backgroundCompletionKeys.has(taskId)))
|
|
1064
|
-
return;
|
|
1065
|
-
agent.backgroundCompletionKeys.add(completionKey);
|
|
1066
|
-
for (const taskId of taskIds)
|
|
1067
|
-
agent.backgroundCompletionKeys.add(taskId);
|
|
1068
|
-
if (!agent.backgroundCompletionQueue.includes(completionKey)) {
|
|
1069
|
-
agent.backgroundCompletionQueue.push(completionKey);
|
|
1070
|
-
}
|
|
1071
|
-
if (!agent.busy && !agent.turnInProgress && !agent.submitting && !agent.backgroundCompletionInFlight) {
|
|
1072
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
1073
|
-
}
|
|
1074
|
-
};
|
|
1075
|
-
const recordDispatchedSubagent = (agent, taskId, outputFile) => {
|
|
1076
|
-
const recordFile = (0, pi_subagent_ledger_js_1.writeDispatchedSubagentRecordFile)((0, pi_subagent_ledger_js_1.effectivePiStateDir)(agent.config), taskId, agent.piSessionOwner);
|
|
1077
|
-
agent.subagentLedger = (0, pi_subagent_ledger_js_1.noteDispatchedSubagent)(agent.subagentLedger, { taskId, outputFile, recordFile });
|
|
1078
|
-
persistSubagentLedger(agent);
|
|
1079
|
-
armSubagentReconcileTimer(agent);
|
|
1080
|
-
};
|
|
1081
|
-
const recordTerminalSubagentNotification = (agent, completionKey, statuses) => {
|
|
1082
|
-
let next = agent.subagentLedger;
|
|
1083
|
-
for (const taskId of (0, pi_subagent_ledger_js_1.taskIdsFromCompletionKey)(completionKey)) {
|
|
1084
|
-
const status = statuses?.[taskId];
|
|
1085
|
-
next = (0, pi_subagent_ledger_js_1.noteDispatchedSubagentTerminal)(next, {
|
|
1086
|
-
taskId,
|
|
1087
|
-
status: status && status !== "dispatched" && status !== "orphaned" ? status : "completed",
|
|
1088
|
-
wakeKey: completionKey,
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
|
-
agent.subagentLedger = next;
|
|
1092
|
-
persistSubagentLedger(agent);
|
|
1093
|
-
if (!hasActiveDispatchedSubagent(agent))
|
|
1094
|
-
clearSubagentReconcileTimer(agent);
|
|
1095
|
-
};
|
|
1096
|
-
const reconcileSubagentLedger = (agent, input = {}) => {
|
|
1097
|
-
if (agent.stopped)
|
|
1098
|
-
return;
|
|
1099
|
-
const result = (0, pi_subagent_ledger_js_1.reconcileDispatchedSubagents)(agent.subagentLedger, {
|
|
1100
|
-
probe: options.subagentRecordProbe ?? pi_subagent_ledger_js_1.probePiSubagentRecord,
|
|
1101
|
-
forceMissing: input.forceMissing === true,
|
|
1102
|
-
missingReason: input.missingReason,
|
|
1103
|
-
});
|
|
1104
|
-
const previousLedger = agent.subagentLedger;
|
|
1105
|
-
agent.subagentLedger = result.ledger;
|
|
1106
|
-
if (result.orphaned.length > 0 || result.terminals.length > 0 || result.ledger !== previousLedger) {
|
|
1107
|
-
persistSubagentLedger(agent);
|
|
1108
|
-
}
|
|
1109
|
-
for (const record of [...result.orphaned, ...result.terminals]) {
|
|
1110
|
-
noteBackgroundCompletion(agent, record.wakeKey ?? record.taskId);
|
|
1111
|
-
}
|
|
1112
|
-
if (!hasActiveDispatchedSubagent(agent))
|
|
1113
|
-
clearSubagentReconcileTimer(agent);
|
|
1114
|
-
else
|
|
1115
|
-
armSubagentReconcileTimer(agent);
|
|
1116
|
-
};
|
|
1117
|
-
const armSubagentReconcileTimer = (agent) => {
|
|
1118
|
-
if (agent.stopped || agent.subagentReconcileTimer || subagentReconcileIntervalMs === 0)
|
|
1119
|
-
return;
|
|
1120
|
-
if (!hasActiveDispatchedSubagent(agent))
|
|
1121
|
-
return;
|
|
1122
|
-
agent.subagentReconcileTimer = setInterval(() => {
|
|
1123
|
-
if (agent.stopped) {
|
|
1124
|
-
clearSubagentReconcileTimer(agent);
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
reconcileSubagentLedger(agent);
|
|
1128
|
-
}, subagentReconcileIntervalMs);
|
|
1129
|
-
agent.subagentReconcileTimer.unref?.();
|
|
1130
|
-
};
|
|
1131
798
|
const scheduleRecreate = (agent, reason) => {
|
|
1132
799
|
if (agent.stopped || agent.retryTimer || agent.starting || agent.session)
|
|
1133
800
|
return;
|
|
@@ -1149,11 +816,7 @@ function createRuntimeHost(options) {
|
|
|
1149
816
|
const proactive = session ? proactivelyCompactPiAtIdle(agent, session) : null;
|
|
1150
817
|
if (proactive)
|
|
1151
818
|
await proactive;
|
|
1152
|
-
reconcileSubagentLedger(agent, { forceMissing: true, missingReason: "pi session gone" });
|
|
1153
|
-
enqueueUndeliveredTerminalWakes(agent);
|
|
1154
819
|
await retryPending(agent);
|
|
1155
|
-
if (agent.backgroundCompletionQueue.length > 0)
|
|
1156
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
1157
820
|
}).catch((error) => {
|
|
1158
821
|
const readiness = error instanceof runtime_readiness_js_1.RuntimePrerequisiteError ? error.readiness
|
|
1159
822
|
: (0, runtime_readiness_js_1.classifyRuntimePrerequisite)(agent.adapter.id, error);
|
|
@@ -1176,7 +839,6 @@ function createRuntimeHost(options) {
|
|
|
1176
839
|
agent.busy = false;
|
|
1177
840
|
agent.submitting = false;
|
|
1178
841
|
agent.generation += 1;
|
|
1179
|
-
rearmBackgroundCompletion(agent);
|
|
1180
842
|
agent.recreateReason = reason;
|
|
1181
843
|
if (agent.stabilityTimer)
|
|
1182
844
|
clearTimeout(agent.stabilityTimer);
|
|
@@ -1186,14 +848,11 @@ function createRuntimeHost(options) {
|
|
|
1186
848
|
record.status = "pending";
|
|
1187
849
|
emitConsumed(agent, persist(agent));
|
|
1188
850
|
emit({ type: "agent-status", agentId: agent.config.agentId, status: "error", error: reason });
|
|
1189
|
-
// Close first so the shutdown sweep can bridge consumed or terminal state
|
|
1190
|
-
// before force-missing reconcile treats a plain sidecar as orphaned.
|
|
1191
851
|
void session.close(`replace after ${reason}`)
|
|
1192
852
|
.catch((error) => log("runtime close after replacement failed", String(error)))
|
|
1193
853
|
.finally(() => {
|
|
1194
854
|
if (agent.stopped)
|
|
1195
855
|
return;
|
|
1196
|
-
reconcileAfterSessionSwap(agent);
|
|
1197
856
|
scheduleRecreate(agent, reason);
|
|
1198
857
|
});
|
|
1199
858
|
};
|
|
@@ -1205,7 +864,6 @@ function createRuntimeHost(options) {
|
|
|
1205
864
|
agent.busy = false;
|
|
1206
865
|
agent.submitting = false;
|
|
1207
866
|
agent.generation += 1;
|
|
1208
|
-
rearmBackgroundCompletion(agent);
|
|
1209
867
|
if (agent.stabilityTimer)
|
|
1210
868
|
clearTimeout(agent.stabilityTimer);
|
|
1211
869
|
agent.stabilityTimer = null;
|
|
@@ -1220,8 +878,6 @@ function createRuntimeHost(options) {
|
|
|
1220
878
|
const recovery = (async () => {
|
|
1221
879
|
try {
|
|
1222
880
|
await session.close("runtime configuration error");
|
|
1223
|
-
if (!agent.stopped)
|
|
1224
|
-
reconcileAfterSessionSwap(agent);
|
|
1225
881
|
const result = agent.adapter.recoverConfigurationError
|
|
1226
882
|
? await agent.adapter.recoverConfigurationError(message)
|
|
1227
883
|
: { recovered: false, reason: "runtime adapter does not support automatic configuration recovery" };
|
|
@@ -1498,16 +1154,6 @@ function createRuntimeHost(options) {
|
|
|
1498
1154
|
// closed instead of inheriting a previous turn's chat or reminder.
|
|
1499
1155
|
agent.stateStore?.clearCurrentInboxSource?.();
|
|
1500
1156
|
finalizeReminderContexts(agent, "Runtime turn ended without a matching Feishu write");
|
|
1501
|
-
if (agent.backgroundCompletionInFlight) {
|
|
1502
|
-
if (agent.turnHadFailure)
|
|
1503
|
-
failBackgroundCompletionWake(agent);
|
|
1504
|
-
else
|
|
1505
|
-
commitBackgroundCompletion(agent);
|
|
1506
|
-
}
|
|
1507
|
-
if (agent.backgroundCompletionQueue.length > 0 && !agent.backgroundCompletionRetryTimer) {
|
|
1508
|
-
scheduleBackgroundCompletionDrain(agent);
|
|
1509
|
-
}
|
|
1510
|
-
reconcileSubagentLedger(agent);
|
|
1511
1157
|
telemetry?.runtimeEvent(agent.config.agentId, event);
|
|
1512
1158
|
if (recoveredAuthentication) {
|
|
1513
1159
|
clearAuthFailure(agent);
|
|
@@ -1525,34 +1171,12 @@ function createRuntimeHost(options) {
|
|
|
1525
1171
|
void (proactive ?? Promise.resolve("noop")).then(() => retryPending(agent));
|
|
1526
1172
|
queueMicrotask(() => { void scanAndPromoteAcceptedInboxUpdates(agent); });
|
|
1527
1173
|
}
|
|
1528
|
-
else if (event.type === "runtime-observation") {
|
|
1529
|
-
if (event.phase === "background_dispatched" && typeof event.taskId === "string" && event.taskId) {
|
|
1530
|
-
recordDispatchedSubagent(agent, event.taskId, typeof event.outputFile === "string" ? event.outputFile : undefined);
|
|
1531
|
-
}
|
|
1532
|
-
else if (event.phase === "completed" && typeof event.completionKey === "string") {
|
|
1533
|
-
recordTerminalSubagentNotification(agent, event.completionKey, event.completionStatuses);
|
|
1534
|
-
if (event.handledInTurn === true) {
|
|
1535
|
-
acknowledgeSubagentWake(agent, event.completionKey);
|
|
1536
|
-
dropQueuedBackgroundCompletionFallback(agent, event.completionKey);
|
|
1537
|
-
}
|
|
1538
|
-
else {
|
|
1539
|
-
noteBackgroundCompletion(agent, event.completionKey);
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
1174
|
else if (event.type === "activity") {
|
|
1544
1175
|
if (agent.turnInProgress && event.activity !== "internal")
|
|
1545
1176
|
agent.turnHadAuthenticatedOutput = true;
|
|
1546
1177
|
emit({ type: "activity", agentId: agent.config.agentId, activity: event.activity, activityKind: event.activity });
|
|
1547
1178
|
}
|
|
1548
1179
|
else if (event.type === "input-error") {
|
|
1549
|
-
if (agent.backgroundCompletionInFlight
|
|
1550
|
-
&& (!event.inputId || !agent.backgroundCompletionWakeInputId
|
|
1551
|
-
|| event.inputId === agent.backgroundCompletionWakeInputId)
|
|
1552
|
-
&& event.willRetry !== true) {
|
|
1553
|
-
agent.turnHadFailure = true;
|
|
1554
|
-
failBackgroundCompletionWake(agent, event);
|
|
1555
|
-
}
|
|
1556
1180
|
const record = event.inputId
|
|
1557
1181
|
? agent.records.get(event.inputId) ?? [...agent.records.values()].find((candidate) => candidate.input.inputId === event.inputId)
|
|
1558
1182
|
: undefined;
|
|
@@ -1682,7 +1306,6 @@ function createRuntimeHost(options) {
|
|
|
1682
1306
|
throw new Error("stale runtime session creation");
|
|
1683
1307
|
}
|
|
1684
1308
|
agent.session = session;
|
|
1685
|
-
agent.piSessionOwner = sessionEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
|
|
1686
1309
|
session.subscribe((event) => observe(agent, session, event));
|
|
1687
1310
|
if (agent.session !== session)
|
|
1688
1311
|
return session;
|
|
@@ -1828,9 +1451,7 @@ function createRuntimeHost(options) {
|
|
|
1828
1451
|
...(agent.previousSession ? { previousSession: agent.previousSession } : {}) });
|
|
1829
1452
|
}
|
|
1830
1453
|
emit({ type: "agent-status", agentId, status: "active", readiness });
|
|
1831
|
-
agent.piSessionOwner = probeEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
|
|
1832
1454
|
await oldSession.close("Pi context fallback committed").catch((error) => log("previous Pi session close after fallback failed", String(error)));
|
|
1833
|
-
reconcileAfterSessionSwap(agent);
|
|
1834
1455
|
const proactive = proactivelyCompactPiAtIdle(agent, fresh);
|
|
1835
1456
|
void (proactive ?? Promise.resolve("noop")).then(() => retryPending(agent));
|
|
1836
1457
|
return { generationChanged: true, sessionChanged: oldSessionId !== fresh.sessionId, turns: 0,
|
|
@@ -1900,10 +1521,6 @@ function createRuntimeHost(options) {
|
|
|
1900
1521
|
clearTimeout(previous.retryTimer);
|
|
1901
1522
|
if (previous.stabilityTimer)
|
|
1902
1523
|
clearTimeout(previous.stabilityTimer);
|
|
1903
|
-
if (previous.backgroundCompletionRetryTimer)
|
|
1904
|
-
clearTimeout(previous.backgroundCompletionRetryTimer);
|
|
1905
|
-
if (previous.subagentReconcileTimer)
|
|
1906
|
-
clearInterval(previous.subagentReconcileTimer);
|
|
1907
1524
|
const previousFailure = currentAuthFailure(previous);
|
|
1908
1525
|
const scoped = Boolean(previousFailure
|
|
1909
1526
|
&& (0, runtime_readiness_js_1.authFailureAppliesTo)({
|
|
@@ -1915,7 +1532,6 @@ function createRuntimeHost(options) {
|
|
|
1915
1532
|
...previous, config, adapter, session, launchId: node_crypto_1.default.randomUUID(), busy: false, submitting: false,
|
|
1916
1533
|
starting: null, retryAfterSubmit: false, generation: 0, poller: null, retryTimer: null,
|
|
1917
1534
|
recreateAttempts: 0, stabilityTimer: null, recreateReason: null, stopped: false,
|
|
1918
|
-
backgroundCompletionRetryTimer: null, subagentReconcileTimer: null,
|
|
1919
1535
|
disabledReason: null, configurationRecovery: null,
|
|
1920
1536
|
authFailureActive: scoped && previous.authFailureActive,
|
|
1921
1537
|
authFailureKind: scoped ? previous.authFailureKind : null,
|
|
@@ -1937,14 +1553,8 @@ function createRuntimeHost(options) {
|
|
|
1937
1553
|
if (!candidate.authFailureActive) {
|
|
1938
1554
|
emit({ type: "agent-status", agentId: config.agentId, status: "active", readiness: candidate.readiness ?? readiness });
|
|
1939
1555
|
}
|
|
1940
|
-
candidate.piSessionOwner = stageEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
|
|
1941
|
-
// Close first so the old session's shutdown sweep can bridge consumed
|
|
1942
|
-
// terminals before force-missing reconcile. Commit also clears any
|
|
1943
|
-
// inherited backoff timer; reschedule so a queued completion still
|
|
1944
|
-
// drains on the new session.
|
|
1945
1556
|
await previous.session?.close("runtime candidate committed")
|
|
1946
1557
|
.catch((error) => log("previous runtime close after candidate commit failed", String(error)));
|
|
1947
|
-
reconcileAfterSessionSwap(candidate);
|
|
1948
1558
|
},
|
|
1949
1559
|
rollback,
|
|
1950
1560
|
};
|
|
@@ -2047,10 +1657,8 @@ function createRuntimeHost(options) {
|
|
|
2047
1657
|
...(agent.authFailureActive ? { error: `${agent.readiness?.reason} ${agent.readiness?.nextAction}` } : {}),
|
|
2048
1658
|
readiness: agent.authFailureActive ? agent.readiness ?? readiness : readiness,
|
|
2049
1659
|
});
|
|
2050
|
-
agent.piSessionOwner = probeEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
|
|
2051
1660
|
await oldSession.close("fresh session reset committed")
|
|
2052
1661
|
.catch((error) => log("previous runtime close after fresh reset failed", String(error)));
|
|
2053
|
-
reconcileAfterSessionSwap(agent);
|
|
2054
1662
|
return { generationChanged: true, sessionChanged: oldSessionId !== fresh.sessionId, turns: 0,
|
|
2055
1663
|
runtimeReady: true, pendingCount: 0, sessionId: fresh.sessionId };
|
|
2056
1664
|
},
|
|
@@ -2211,10 +1819,8 @@ function createRuntimeHost(options) {
|
|
|
2211
1819
|
readiness: agent.authFailureActive ? agent.readiness ?? readiness : readiness,
|
|
2212
1820
|
});
|
|
2213
1821
|
durableRollback = null;
|
|
2214
|
-
agent.piSessionOwner = probeEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
|
|
2215
1822
|
await oldSession.close("context-window recovery committed")
|
|
2216
1823
|
.catch((error) => log("previous runtime close after context-window recovery failed", String(error)));
|
|
2217
|
-
reconcileAfterSessionSwap(agent);
|
|
2218
1824
|
const proactive = proactivelyCompactPiAtIdle(agent, fresh);
|
|
2219
1825
|
void (proactive ?? Promise.resolve("noop")).then(() => retryPending(agent));
|
|
2220
1826
|
return { generationChanged: true, sessionChanged: oldSessionId !== fresh.sessionId, turns: 0,
|
|
@@ -2300,11 +1906,7 @@ function createRuntimeHost(options) {
|
|
|
2300
1906
|
previousSession: loadPersistedPreviousSession(config, stateStore), readiness: null,
|
|
2301
1907
|
turnInProgress: false, turnHadFailure: false, turnHadAuthenticatedOutput: false, authFailureActive: false,
|
|
2302
1908
|
authFailureKind: null, authFailureProvider: null,
|
|
2303
|
-
promotedInboxUpdateIds: new Set()
|
|
2304
|
-
backgroundCompletionQueue: [], backgroundCompletionKeys: new Set(),
|
|
2305
|
-
backgroundCompletionInFlight: null, backgroundCompletionWakeInputId: null,
|
|
2306
|
-
backgroundCompletionRejectStreak: 0, backgroundCompletionRetryTimer: null,
|
|
2307
|
-
subagentLedger: loadSubagentLedger(config), subagentReconcileTimer: null };
|
|
1909
|
+
promotedInboxUpdateIds: new Set() };
|
|
2308
1910
|
restoreAuthFailure(agent);
|
|
2309
1911
|
const startupConsumed = [];
|
|
2310
1912
|
const startupQuarantined = [];
|
|
@@ -2338,8 +1940,6 @@ function createRuntimeHost(options) {
|
|
|
2338
1940
|
await ensureSession(agent);
|
|
2339
1941
|
if (agent.stopped)
|
|
2340
1942
|
return;
|
|
2341
|
-
reconcileSubagentLedger(agent, { forceMissing: true, missingReason: "runtime restarted" });
|
|
2342
|
-
enqueueUndeliveredTerminalWakes(agent);
|
|
2343
1943
|
await recoverStalePiCompaction(agent);
|
|
2344
1944
|
const startupSession = agent.session;
|
|
2345
1945
|
const proactive = startupSession ? proactivelyCompactPiAtIdle(agent, startupSession) : null;
|
|
@@ -2356,8 +1956,6 @@ function createRuntimeHost(options) {
|
|
|
2356
1956
|
const reason = error instanceof Error ? error.message : String(error);
|
|
2357
1957
|
const transient = error instanceof runtime_readiness_js_1.RuntimePrerequisiteError && error.readiness.state === "unavailable";
|
|
2358
1958
|
agent.disabledReason = transient ? null : reason;
|
|
2359
|
-
reconcileSubagentLedger(agent, { forceMissing: true, missingReason: "runtime restarted" });
|
|
2360
|
-
enqueueUndeliveredTerminalWakes(agent);
|
|
2361
1959
|
if (transient) {
|
|
2362
1960
|
recoveringCount += 1;
|
|
2363
1961
|
scheduleRecreate(agent, reason);
|
|
@@ -2469,10 +2067,6 @@ function createRuntimeHost(options) {
|
|
|
2469
2067
|
clearTimeout(agent.retryTimer);
|
|
2470
2068
|
if (agent.stabilityTimer)
|
|
2471
2069
|
clearTimeout(agent.stabilityTimer);
|
|
2472
|
-
if (agent.backgroundCompletionRetryTimer)
|
|
2473
|
-
clearTimeout(agent.backgroundCompletionRetryTimer);
|
|
2474
|
-
if (agent.subagentReconcileTimer)
|
|
2475
|
-
clearInterval(agent.subagentReconcileTimer);
|
|
2476
2070
|
if (agent.busy)
|
|
2477
2071
|
await agent.session?.cancel(reason);
|
|
2478
2072
|
await agent.session?.close(reason);
|
|
@@ -2485,9 +2079,5 @@ function createRuntimeHost(options) {
|
|
|
2485
2079
|
},
|
|
2486
2080
|
async shutdown(reason) { await Promise.allSettled([...managed.keys()].map((id) => this.stop(id, reason))); },
|
|
2487
2081
|
subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener); },
|
|
2488
|
-
getDispatchedSubagent(agentId, taskId) {
|
|
2489
|
-
const agent = managed.get(agentId);
|
|
2490
|
-
return agent ? (0, pi_subagent_ledger_js_1.getDispatchedSubagent)(agent.subagentLedger, taskId) : null;
|
|
2491
|
-
},
|
|
2492
2082
|
};
|
|
2493
2083
|
}
|