@ponythewhite/base-context 1.0.11 → 1.0.12
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 +11 -0
- package/dist/base-context-runtime/pyproject.toml +1 -1
- package/dist/base-context-runtime/uv.lock +1 -1
- package/dist/build-info.json +1 -1
- package/dist/bundle/amazon-bedrock.js +3 -3
- package/dist/bundle/{anthropic-5PSCZEER.js → anthropic-BJVPUMPB.js} +2 -2
- package/dist/bundle/{azure-openai-responses-AYTLJR33.js → azure-openai-responses-ERRMAXK6.js} +4 -5
- package/dist/bundle/{bundled-modules-PEFT72QN.js → bundled-modules-WCGPZI2H.js} +5 -5
- package/dist/bundle/{chunk-D3KOF57W.js → chunk-25VYRAC6.js} +14 -1
- package/dist/bundle/{chunk-2IPDSTDR.js → chunk-AEMRBMI2.js} +9 -9
- package/dist/bundle/{chunk-Q3MBSBEB.js → chunk-FOGKLC7V.js} +1 -1
- package/dist/bundle/{chunk-JZHGOOFM.js → chunk-IAKHCQA2.js} +118 -22
- package/dist/bundle/{chunk-KT2BNEPE.js → chunk-MUFZODP5.js} +1 -1
- package/dist/bundle/{chunk-QKIFBA7N.js → chunk-Q6UAHLII.js} +2 -2
- package/dist/bundle/{chunk-TOOVREMP.js → chunk-YGV3Y4AD.js} +515 -107
- package/dist/bundle/{cli-main-BRXGYTGK.js → cli-main-CTYDQHFE.js} +4 -4
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{google-HTMCUJ7X.js → google-4GA4YMUX.js} +2 -2
- package/dist/bundle/{google-vertex-ZQO65AXF.js → google-vertex-7AMALD7D.js} +2 -2
- package/dist/bundle/{main-POUXGEL6.js → main-GVGK354K.js} +5 -5
- package/dist/bundle/{mistral-SB7LU56G.js → mistral-74BXMNRM.js} +1 -1
- package/dist/bundle/{openai-codex-responses-5CEW4VN3.js → openai-codex-responses-COXNC4IH.js} +2 -2
- package/dist/bundle/{openai-completions-BAZJQSS2.js → openai-completions-BCSA5Q6S.js} +2 -2
- package/dist/bundle/{openai-responses-VHOE427P.js → openai-responses-ONCIZSJS.js} +3 -3
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +362 -103
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +9 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +29 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context-tree.d.ts +13 -10
- package/dist/core/context-tree.d.ts.map +1 -1
- package/dist/core/context-tree.js +49 -3
- package/dist/core/context-tree.js.map +1 -1
- package/dist/core/inference-coordinator.d.ts +1 -1
- package/dist/core/inference-coordinator.d.ts.map +1 -1
- package/dist/core/inference-coordinator.js +18 -5
- package/dist/core/inference-coordinator.js.map +1 -1
- package/dist/core/messages.d.ts +2 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +2 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/refinement/refinement.d.ts +2 -0
- package/dist/core/refinement/refinement.d.ts.map +1 -1
- package/dist/core/refinement/refinement.js +10 -1
- package/dist/core/refinement/refinement.js.map +1 -1
- package/dist/core/request-usage.d.ts +34 -0
- package/dist/core/request-usage.d.ts.map +1 -0
- package/dist/core/request-usage.js +111 -0
- package/dist/core/request-usage.js.map +1 -0
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +7 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +8 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +13 -3
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +10 -2
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.d.ts +3 -0
- package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.js +71 -32
- package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
- package/dist/modes/interactive/components/context-tree-format.d.ts.map +1 -1
- package/dist/modes/interactive/components/context-tree-format.js +49 -0
- package/dist/modes/interactive/components/context-tree-format.js.map +1 -1
- package/docs/compaction.md +27 -3
- package/docs/context-management.md +17 -1
- package/docs/rlm.md +1 -1
- package/docs/settings.md +12 -0
- package/docs/usage.md +24 -1
- package/package.json +4 -4
|
@@ -16,8 +16,8 @@ import { addAutonomousContinuation, addAutonomousUsage, autonomousStatus, create
|
|
|
16
16
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
17
17
|
import { stringifyBoundedJson } from "./bounded-json.js";
|
|
18
18
|
import { CanonicalContextCompiler, canonicalRecoveryBoundary, getCanonicalEpochContext, getCanonicalMessageSource, getCanonicalViewSelectionSource, getCanonicalViewUnits, MissingRecoveryReplayContractError, prepareCanonicalEpoch, prepareContextModeEpoch, prepareRecoveryCompaction, readCanonicalContextMode, } from "./canonical-context.js";
|
|
19
|
-
import { COMPACT_SKILL_NAME, calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, prepareViewCompaction, serializeConversation, shouldCompact, takeNativeBranchSummaryWrite, } from "./compaction/index.js";
|
|
20
|
-
import { appendContextEpoch, assertContextRequestContract, CONTEXT_EPOCH_DETAIL, CONTEXT_SKILL_EPOCH_RENDERER, contextEpochMode, contextEpochRepresentation, contextRequestContract, retainedContextRequestContract, snapshotContextEpoch, UnsupportedContextEpochConfigurationError, } from "./context-epoch.js";
|
|
19
|
+
import { COMPACT_SKILL_NAME, calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateFixedCompactionTokens, generateBranchSummary, prepareCompaction, prepareViewCompaction, serializeConversation, shouldCompact, takeNativeBranchSummaryWrite, } from "./compaction/index.js";
|
|
20
|
+
import { appendContextEpoch, assertContextRequestContract, CONTEXT_EPOCH_DETAIL, CONTEXT_SKILL_EPOCH_RENDERER, contextEpochMode, contextEpochRepresentation, contextRequestContract, readContextEpoch, retainedContextRequestContract, snapshotContextEpoch, UnsupportedContextEpochConfigurationError, } from "./context-epoch.js";
|
|
21
21
|
import { ContextTreeRequest, computeOwnAndTotalUsage, loadContextTreeChildFromDisk, loadContextTreeChildrenFromDisk, readContextTreeUsage, readResidentContextTreeUsage, } from "./context-tree.js";
|
|
22
22
|
import { normalizeHeartbeatDeliveryMode } from "./cron-jobs.js";
|
|
23
23
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
@@ -28,10 +28,10 @@ import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
|
28
28
|
import { createGoalContextMessage, emptyGoalState, GOAL_CONTEXT_CUSTOM_TYPE, GOAL_CONTEXT_PREVIEW_LABEL, GOAL_SKILL_NAME, GOAL_STATE_CUSTOM_TYPE, goalHostResponse, goalTokenDeltaForUsage, isPersistedGoalState, normalizeGoalState, validateGoalBudget, validateGoalObjective, } from "./goals.js";
|
|
29
29
|
import { captureNativeBranchRequests, captureNativeCompactionRequests, captureNativePlannerRequests, captureNativeReviewerRequests, InferenceCoordinator, takeNativeInferenceAuthSource, } from "./inference-coordinator.js";
|
|
30
30
|
import { snapshotPathIn } from "./kernel/state-snapshot.js";
|
|
31
|
-
import { convertToLlm, createCompactionOutcomeMessage, createHeartbeatPromptMessage, createRefinementOutcomeMessage, createRlmChildFailureMessage, createRlmChildTerminalNoticeMessage, createSessionSlashCommandMessage, createSessionSlashCommandResultMessage, HEARTBEAT_PROMPT_CUSTOM_TYPE, HEARTBEAT_PROMPT_PREVIEW_LABEL, IPYTHON_STATE_RESTORED_CUSTOM_TYPE, isSessionSlashCommandMessage, RLM_CHILD_FAILURE_CUSTOM_TYPE, RLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE, } from "./messages.js";
|
|
31
|
+
import { convertToLlm, createCompactionOutcomeMessage, createHeartbeatPromptMessage, createRefinementOutcomeMessage, createRlmChildFailureMessage, createRlmChildTerminalNoticeMessage, createSessionSlashCommandMessage, createSessionSlashCommandResultMessage, HARNESS_SNAPSHOT_CUSTOM_TYPE, HEARTBEAT_PROMPT_CUSTOM_TYPE, HEARTBEAT_PROMPT_PREVIEW_LABEL, IPYTHON_STATE_RESTORED_CUSTOM_TYPE, isSessionSlashCommandMessage, RLM_CHILD_FAILURE_CUSTOM_TYPE, RLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE, } from "./messages.js";
|
|
32
32
|
import { throwIfPromptAdmissionCancelled } from "./prompt-admission.js";
|
|
33
33
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
34
|
-
import { appendGlobalRefinement, applyRefinementProposal, generateRefinementId, getGlobalHarnessStateDir, getLocalHarnessStateDir, getRefinementHistory, getWorkspaceHarnessStateDir, inferRefinementResultScope, loadGlobalRefinementHistory, loadHarnessState, mergeHarnessStates, mergeRefinementHistory, normalizeRefinementProposal, planRefinement, prepareRefinementApplication, REFINE_SKILL_NAME, reviewAutoRefine, saveHarnessState, takeNativePlannerRequestWrite, withRefinementBaseline, } from "./refinement/index.js";
|
|
34
|
+
import { appendGlobalRefinement, applyRefinementProposal, formatHarnessStateForPrompt, generateRefinementId, getGlobalHarnessStateDir, getLocalHarnessStateDir, getRefinementHistory, getWorkspaceHarnessStateDir, inferRefinementResultScope, loadGlobalRefinementHistory, loadHarnessState, mergeHarnessStates, mergeRefinementHistory, normalizeRefinementProposal, planRefinement, prepareRefinementApplication, REFINE_SKILL_NAME, reviewAutoRefine, saveHarnessState, takeNativePlannerRequestWrite, withRefinementBaseline, } from "./refinement/index.js";
|
|
35
35
|
import { getRecoveryCompactionAuthorization, PublicContextBudgetError } from "./request-view-selection.js";
|
|
36
36
|
import { resolveConfigValue } from "./resolve-config-value.js";
|
|
37
37
|
import { assertResourceCurrent } from "./resource-view.js";
|
|
@@ -45,7 +45,7 @@ import { appendSentAgentMessageToToolResult, IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_E
|
|
|
45
45
|
import { ContextUsageReader } from "./session-context-usage.js";
|
|
46
46
|
import { bindNativeEntryWriter, } from "./session-entry-origin.js";
|
|
47
47
|
import { readUserMessagesForForking } from "./session-fork-messages.js";
|
|
48
|
-
import { hydrateCapturedHistoryEntry } from "./session-history-index.js";
|
|
48
|
+
import { hydrateCapturedHistoryEntry, } from "./session-history-index.js";
|
|
49
49
|
import { exportSessionBranchToJsonl } from "./session-jsonl-export.js";
|
|
50
50
|
import { getLatestCompactionEntry, SessionManager, } from "./session-manager.js";
|
|
51
51
|
import { getPythonSkillRuntimeInfo } from "./skills.js";
|
|
@@ -192,6 +192,7 @@ function createPostCompactionContinuationSettlement(resume) {
|
|
|
192
192
|
return { ...createAgentMessageDeferred(), resume, settled: false };
|
|
193
193
|
}
|
|
194
194
|
import { LocalRlmSubagentCapacity, } from "./rlm-max-subagents.js";
|
|
195
|
+
const RLM_PARENT_USAGE_CUSTOM_TYPE = "rlm_parent_usage";
|
|
195
196
|
const KERNEL_STATE_LISTING_TIMEOUT_MS = 5000;
|
|
196
197
|
const RLM_MAX_DEPTH_STATE_CUSTOM_TYPE = "rlm_max_depth_state";
|
|
197
198
|
function noopRlmChildAbort() { }
|
|
@@ -436,6 +437,8 @@ export class AgentSession {
|
|
|
436
437
|
// Kept alive for retained children so nested updates (e.g. a grandchild cancel)
|
|
437
438
|
// still forward to root; torn down when the retained child is disposed.
|
|
438
439
|
_rlmChildUnsubscribes = new Map();
|
|
440
|
+
_rlmChildUsageSources = new Map();
|
|
441
|
+
_rlmParentUsageAttribution;
|
|
439
442
|
/** Latest recap for this session, written by the daemon summarizer; read by a parent to label its child snapshots. */
|
|
440
443
|
_currentRecap;
|
|
441
444
|
_initialGoal;
|
|
@@ -560,11 +563,13 @@ export class AgentSession {
|
|
|
560
563
|
await this._goalResumeOperation;
|
|
561
564
|
await this._waitForAgentEventsBeforeContext();
|
|
562
565
|
await this._waitForChildUsageWrites();
|
|
566
|
+
const assertHarnessSourceCurrent = await this._appendHarnessSnapshotIfChanged();
|
|
563
567
|
await this.sessionManager.flushNow();
|
|
568
|
+
assertHarnessSourceCurrent();
|
|
564
569
|
// In-memory sessions have no canonical archive. This is an explicit mode, not an index-error fallback.
|
|
565
570
|
if (!this.sessionManager.isPersisted()) {
|
|
566
571
|
if (!this._compactionSetupFailure)
|
|
567
|
-
return;
|
|
572
|
+
return { messages: this.agent.state.messages, adoptMessages: true };
|
|
568
573
|
const rebuilt = await readSessionBootstrap(this.sessionManager, this.settingsManager.getCanonicalContextLimits());
|
|
569
574
|
this._compactionSetupFailure = undefined;
|
|
570
575
|
return { messages: rebuilt.context.messages, adoptMessages: true };
|
|
@@ -2950,7 +2955,8 @@ export class AgentSession {
|
|
|
2950
2955
|
if (compactionTimestamp !== undefined && context.message.timestamp <= compactionTimestamp)
|
|
2951
2956
|
return false;
|
|
2952
2957
|
const contextTokens = this._getThresholdContextTokens(context.message, compactionTimestamp);
|
|
2953
|
-
if (contextTokens === undefined ||
|
|
2958
|
+
if (contextTokens === undefined ||
|
|
2959
|
+
!shouldCompact(contextTokens, contextWindow, settings, estimateFixedCompactionTokens(this.systemPrompt, this.agent.state.tools, this.messages)))
|
|
2954
2960
|
return false;
|
|
2955
2961
|
if (this._hasFailedThresholdCompaction())
|
|
2956
2962
|
return false;
|
|
@@ -3314,7 +3320,7 @@ export class AgentSession {
|
|
|
3314
3320
|
}
|
|
3315
3321
|
return {
|
|
3316
3322
|
scheduled: true,
|
|
3317
|
-
note: "Refinement runs when the current turn ends;
|
|
3323
|
+
note: "Refinement runs when the current turn ends; fresh harness advice is added to the next request and you resume automatically. Continue working normally.",
|
|
3318
3324
|
};
|
|
3319
3325
|
}
|
|
3320
3326
|
default:
|
|
@@ -4382,6 +4388,7 @@ export class AgentSession {
|
|
|
4382
4388
|
for (const { session } of this._rlmChildSessions.values())
|
|
4383
4389
|
await drain(() => session.disposeAsync());
|
|
4384
4390
|
this._rlmChildSessions.clear();
|
|
4391
|
+
this._rlmChildUsageSources.clear();
|
|
4385
4392
|
this._rlmChildCleanupFailures.clear();
|
|
4386
4393
|
this._deletedRlmChildIds.clear();
|
|
4387
4394
|
// Stop kernel-backed tools before waiting for their terminal agent events.
|
|
@@ -4477,6 +4484,7 @@ export class AgentSession {
|
|
|
4477
4484
|
session.dispose();
|
|
4478
4485
|
}
|
|
4479
4486
|
this._rlmChildSessions.clear();
|
|
4487
|
+
this._rlmChildUsageSources.clear();
|
|
4480
4488
|
this._rlmChildCleanupFailures.clear();
|
|
4481
4489
|
this._deletedRlmChildIds.clear();
|
|
4482
4490
|
this._pendingNextTurnMessages = [];
|
|
@@ -4721,6 +4729,7 @@ export class AgentSession {
|
|
|
4721
4729
|
rlmDepth: this._rlmDepth,
|
|
4722
4730
|
rlmParentAgent: this._rlmParentAgent,
|
|
4723
4731
|
harnessState: this._loadMergedHarnessState(),
|
|
4732
|
+
harnessSection: "instructions",
|
|
4724
4733
|
errorFixSelection: {
|
|
4725
4734
|
enabled: this.settingsManager.getLearningEnabled(),
|
|
4726
4735
|
tools: validToolNames,
|
|
@@ -4733,6 +4742,118 @@ export class AgentSession {
|
|
|
4733
4742
|
};
|
|
4734
4743
|
return buildSystemPrompt(this._baseSystemPromptOptions);
|
|
4735
4744
|
}
|
|
4745
|
+
/** Read only snapshot candidates in the active literal tail and accepted epoch recipes. */
|
|
4746
|
+
async _readHarnessSnapshot(view) {
|
|
4747
|
+
const { maxMessages, maxSourceBytes } = this.settingsManager.getCanonicalContextLimits();
|
|
4748
|
+
const refs = [];
|
|
4749
|
+
let summary = null;
|
|
4750
|
+
let cursor;
|
|
4751
|
+
let count = 0;
|
|
4752
|
+
let bytes = 0;
|
|
4753
|
+
do {
|
|
4754
|
+
const page = await view.contextManifest({ cursor, limit: 128 });
|
|
4755
|
+
if (page.selection !== "known")
|
|
4756
|
+
throw new Error(`Harness snapshot context selection is ${page.selection}`);
|
|
4757
|
+
summary = page.summaryRef;
|
|
4758
|
+
count += page.refs.length;
|
|
4759
|
+
if (count + (summary ? 1 : 0) > maxMessages)
|
|
4760
|
+
throw new Error("Harness snapshot context message budget exceeded");
|
|
4761
|
+
refs.push(...page.refs.filter((ref) => ref.kind === "custom_message"));
|
|
4762
|
+
cursor = page.nextCursor ?? undefined;
|
|
4763
|
+
} while (cursor);
|
|
4764
|
+
const read = async (ref, source = view) => {
|
|
4765
|
+
bytes += ref.locator.length;
|
|
4766
|
+
if (bytes > maxSourceBytes)
|
|
4767
|
+
throw new Error("Harness snapshot source byte budget exceeded");
|
|
4768
|
+
const metadata = await source.get(ref.entryId);
|
|
4769
|
+
if (!metadata || metadata.revision !== ref.revision)
|
|
4770
|
+
throw new Error("Harness snapshot source is unavailable");
|
|
4771
|
+
const hydrated = await hydrateCapturedHistoryEntry(metadata, ref.locator.length, source.readPayload);
|
|
4772
|
+
if (!hydrated)
|
|
4773
|
+
throw new Error("Harness snapshot payload is unavailable");
|
|
4774
|
+
return hydrated.entry;
|
|
4775
|
+
};
|
|
4776
|
+
const content = (entry) => entry.type === "custom_message" &&
|
|
4777
|
+
entry.customType === HARNESS_SNAPSHOT_CUSTOM_TYPE &&
|
|
4778
|
+
typeof entry.content === "string"
|
|
4779
|
+
? entry.content
|
|
4780
|
+
: undefined;
|
|
4781
|
+
for (const ref of refs.reverse()) {
|
|
4782
|
+
const snapshot = content(await read(ref));
|
|
4783
|
+
if (snapshot !== undefined)
|
|
4784
|
+
return snapshot;
|
|
4785
|
+
}
|
|
4786
|
+
if (!summary)
|
|
4787
|
+
return;
|
|
4788
|
+
const entry = await read(summary);
|
|
4789
|
+
if (entry.type !== "compaction" ||
|
|
4790
|
+
summary.qualification !== "native-context-epoch" ||
|
|
4791
|
+
summary.retention === "retained-import")
|
|
4792
|
+
return;
|
|
4793
|
+
const checkpoint = readContextEpoch(entry.details, maxSourceBytes);
|
|
4794
|
+
if (!checkpoint)
|
|
4795
|
+
return;
|
|
4796
|
+
if (count + checkpoint.views.length > maxMessages)
|
|
4797
|
+
throw new Error("Harness snapshot context message budget exceeded");
|
|
4798
|
+
for (const pinned of [...checkpoint.views].reverse()) {
|
|
4799
|
+
if (pinned.ref.kind !== "custom_message")
|
|
4800
|
+
continue;
|
|
4801
|
+
if (!view.atSnapshot)
|
|
4802
|
+
throw new Error("Harness snapshot epoch requires its captured source");
|
|
4803
|
+
const snapshot = content(await read(pinned.ref, await view.atSnapshot(pinned.source)));
|
|
4804
|
+
if (snapshot !== undefined)
|
|
4805
|
+
return snapshot;
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
/** Persist mutable advice before the request owner captures its source and epoch ACK boundary. */
|
|
4809
|
+
async _appendHarnessSnapshotIfChanged() {
|
|
4810
|
+
const manager = this.sessionManager;
|
|
4811
|
+
let leafId = manager.getLeafId();
|
|
4812
|
+
const sourceIsCurrent = manager.captureCompactionSourceOwner();
|
|
4813
|
+
const assertCurrent = () => {
|
|
4814
|
+
if (this._disposed || this.sessionManager !== manager || !sourceIsCurrent() || manager.getLeafId() !== leafId)
|
|
4815
|
+
throw new Error("Harness snapshot source changed before request ownership");
|
|
4816
|
+
};
|
|
4817
|
+
let previous;
|
|
4818
|
+
if (manager.isPersisted()) {
|
|
4819
|
+
previous = await manager.readBranchHistory((view) => this._readHarnessSnapshot(view.branchContext));
|
|
4820
|
+
}
|
|
4821
|
+
else {
|
|
4822
|
+
const snapshot = manager
|
|
4823
|
+
.buildSessionContext()
|
|
4824
|
+
.messages.reverse()
|
|
4825
|
+
.find((message) => message.role === "custom" && message.customType === HARNESS_SNAPSHOT_CUSTOM_TYPE);
|
|
4826
|
+
if (snapshot?.role === "custom")
|
|
4827
|
+
previous = snapshot.content;
|
|
4828
|
+
}
|
|
4829
|
+
assertCurrent();
|
|
4830
|
+
const options = this._baseSystemPromptOptions;
|
|
4831
|
+
const tools = options.selectedTools ?? [];
|
|
4832
|
+
const hasIpython = tools.includes("ipython");
|
|
4833
|
+
const content = formatHarnessStateForPrompt(this._loadMergedHarnessState(), {
|
|
4834
|
+
section: "entries",
|
|
4835
|
+
includeIpythonExamples: hasIpython,
|
|
4836
|
+
includeShellExamples: tools.includes("bash"),
|
|
4837
|
+
errorFixSelection: options.errorFixSelection
|
|
4838
|
+
? { ...options.errorFixSelection, enabled: this.settingsManager.getLearningEnabled() }
|
|
4839
|
+
: undefined,
|
|
4840
|
+
});
|
|
4841
|
+
if (previous === content)
|
|
4842
|
+
return assertCurrent;
|
|
4843
|
+
const entryId = await manager.appendCustomMessageEntryWithRollback(HARNESS_SNAPSHOT_CUSTOM_TYPE, content, false);
|
|
4844
|
+
if (this._disposed || this.sessionManager !== manager || !sourceIsCurrent() || manager.getLeafId() !== entryId)
|
|
4845
|
+
throw new Error("Harness snapshot source changed during append");
|
|
4846
|
+
if (!manager.isPersisted())
|
|
4847
|
+
this.agent.state.messages.push({
|
|
4848
|
+
role: "custom",
|
|
4849
|
+
customType: HARNESS_SNAPSHOT_CUSTOM_TYPE,
|
|
4850
|
+
content,
|
|
4851
|
+
display: false,
|
|
4852
|
+
timestamp: Date.now(),
|
|
4853
|
+
});
|
|
4854
|
+
leafId = entryId;
|
|
4855
|
+
return assertCurrent;
|
|
4856
|
+
}
|
|
4736
4857
|
_refreshExtensionSystemPrompt(extensionPrompt, baseSnapshot) {
|
|
4737
4858
|
if (this._baseSystemPrompt === baseSnapshot) {
|
|
4738
4859
|
return extensionPrompt;
|
|
@@ -8928,8 +9049,12 @@ export class AgentSession {
|
|
|
8928
9049
|
}
|
|
8929
9050
|
if (refinementAuditAppendError)
|
|
8930
9051
|
throw refinementAuditAppendError.error;
|
|
8931
|
-
|
|
8932
|
-
this.
|
|
9052
|
+
// Keep extension-facing state fresh, but do not rewrite the cached system prefix.
|
|
9053
|
+
this._baseSystemPromptOptions = {
|
|
9054
|
+
...this._baseSystemPromptOptions,
|
|
9055
|
+
harnessState: this._loadMergedHarnessState(),
|
|
9056
|
+
};
|
|
9057
|
+
// The next owned request appends the new advice before capturing its source.
|
|
8933
9058
|
try {
|
|
8934
9059
|
this._emit({ type: "refine_complete", result });
|
|
8935
9060
|
}
|
|
@@ -9111,7 +9236,7 @@ export class AgentSession {
|
|
|
9111
9236
|
const contextTokens = this._getThresholdContextTokens(assistantMessage, compactionTimestamp);
|
|
9112
9237
|
if (contextTokens === undefined)
|
|
9113
9238
|
return false;
|
|
9114
|
-
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
9239
|
+
if (shouldCompact(contextTokens, contextWindow, settings, estimateFixedCompactionTokens(this.systemPrompt, this.agent.state.tools, this.messages))) {
|
|
9115
9240
|
if (this._hasFailedThresholdCompaction())
|
|
9116
9241
|
return false;
|
|
9117
9242
|
if (!this._pendingCheckpoint && queueAutonomousContinuation) {
|
|
@@ -10691,6 +10816,7 @@ export class AgentSession {
|
|
|
10691
10816
|
this._rlmChildUnsubscribes.get(childId)?.();
|
|
10692
10817
|
this._rlmChildUnsubscribes.delete(childId);
|
|
10693
10818
|
this._rlmChildSessions.delete(childId);
|
|
10819
|
+
this._rlmChildUsageSources.delete(childId);
|
|
10694
10820
|
this._rlmChildCleanupFailures.delete(childId);
|
|
10695
10821
|
this._abandonedRlmQuiescenceChildIds.delete(childId);
|
|
10696
10822
|
if (!run || this._activeRlmChildRuns.get(childId) === run) {
|
|
@@ -10776,6 +10902,170 @@ export class AgentSession {
|
|
|
10776
10902
|
this._removeRlmSubagentTracking(childId);
|
|
10777
10903
|
return { subagent };
|
|
10778
10904
|
}
|
|
10905
|
+
async _restoreRlmChildUsageSource(childId, child) {
|
|
10906
|
+
if (this._rlmChildUsageSources.has(childId))
|
|
10907
|
+
return;
|
|
10908
|
+
const readSource = (entry) => {
|
|
10909
|
+
if (entry.type !== "custom" || entry.customType !== RLM_PARENT_USAGE_CUSTOM_TYPE)
|
|
10910
|
+
return;
|
|
10911
|
+
const data = entry.data;
|
|
10912
|
+
if (!data ||
|
|
10913
|
+
data.sessionId !== this.sessionId ||
|
|
10914
|
+
data.sessionFile !== this.sessionFile ||
|
|
10915
|
+
typeof data.entryId !== "string")
|
|
10916
|
+
return;
|
|
10917
|
+
return { sessionId: data.sessionId, sessionFile: data.sessionFile, entryId: data.entryId };
|
|
10918
|
+
};
|
|
10919
|
+
const source = child.sessionManager.supportsCapturedHistoryReads()
|
|
10920
|
+
? await child.sessionManager.readBranchHistory(async (history) => {
|
|
10921
|
+
let after = 0;
|
|
10922
|
+
while (true) {
|
|
10923
|
+
const page = await history.page(after, 64);
|
|
10924
|
+
for (const ref of page.events) {
|
|
10925
|
+
if (ref.kind !== "custom" || ref.locator.length > 16 * 1024)
|
|
10926
|
+
continue;
|
|
10927
|
+
const record = await history.hydrateEntry(ref.id, 16 * 1024);
|
|
10928
|
+
const source = record && readSource(record.entry);
|
|
10929
|
+
if (source)
|
|
10930
|
+
return source;
|
|
10931
|
+
}
|
|
10932
|
+
if (page.nextAfter === null)
|
|
10933
|
+
return;
|
|
10934
|
+
after = page.nextAfter;
|
|
10935
|
+
}
|
|
10936
|
+
})
|
|
10937
|
+
: child.sessionManager
|
|
10938
|
+
.getBranch()
|
|
10939
|
+
.map(readSource)
|
|
10940
|
+
.find((source) => source !== undefined);
|
|
10941
|
+
if (!source || source.sessionId !== this.sessionId || source.sessionFile !== this.sessionFile)
|
|
10942
|
+
return;
|
|
10943
|
+
const target = await this.sessionManager.readEntry(source.entryId);
|
|
10944
|
+
if (target?.type !== "message" || target.message.role !== "assistant")
|
|
10945
|
+
return;
|
|
10946
|
+
if (source.sessionId !== this.sessionId || source.sessionFile !== this.sessionFile)
|
|
10947
|
+
return;
|
|
10948
|
+
this._rlmChildUsageSources.set(childId, source);
|
|
10949
|
+
}
|
|
10950
|
+
_subscribeRlmChildEvents(childId, child, run, onUsageWrite) {
|
|
10951
|
+
let runningToolCount = 0;
|
|
10952
|
+
const emitChildUpdate = () => {
|
|
10953
|
+
if (run)
|
|
10954
|
+
run.emitUpdate?.();
|
|
10955
|
+
else
|
|
10956
|
+
this._emit({ type: "rlm_child_update", child: this._rlmChildSnapshotForSession(childId, child) });
|
|
10957
|
+
};
|
|
10958
|
+
const attributeUsage = (usage, origin) => {
|
|
10959
|
+
const source = this._rlmChildUsageSources.get(childId);
|
|
10960
|
+
if (!source || source.sessionId !== this.sessionId || source.sessionFile !== this.sessionFile)
|
|
10961
|
+
return Promise.resolve();
|
|
10962
|
+
const delta = structuredClone(usage);
|
|
10963
|
+
const target = this.messages.find((message) => message.role === "assistant" && this._findAssistantEntryIdForMessage(message) === source.entryId);
|
|
10964
|
+
const refreshOutput = this._refreshInvocationOutput;
|
|
10965
|
+
const forwardUsage = this._rlmParentUsageAttribution;
|
|
10966
|
+
const write = this.sessionManager
|
|
10967
|
+
.appendChildUsageAttributionWithAggregate(source.entryId, delta, undefined, origin)
|
|
10968
|
+
.then(async ({ aggregateUsage }) => {
|
|
10969
|
+
if (target) {
|
|
10970
|
+
target.usage = structuredClone(aggregateUsage);
|
|
10971
|
+
refreshOutput?.(target);
|
|
10972
|
+
}
|
|
10973
|
+
// Ancestors receive only this newly acknowledged delta, never the aggregate again.
|
|
10974
|
+
await forwardUsage?.(delta, origin);
|
|
10975
|
+
});
|
|
10976
|
+
this._childUsageWrites.add(write);
|
|
10977
|
+
onUsageWrite?.(write);
|
|
10978
|
+
void write.then(() => this._childUsageWrites.delete(write), (error) => {
|
|
10979
|
+
this._childUsageWrites.delete(write);
|
|
10980
|
+
if (run)
|
|
10981
|
+
run.error = `Child usage attribution was not acknowledged: ${this._asError(error).message}`;
|
|
10982
|
+
this._surfaceSessionInputError(error);
|
|
10983
|
+
});
|
|
10984
|
+
return write;
|
|
10985
|
+
};
|
|
10986
|
+
child._rlmParentUsageAttribution = attributeUsage;
|
|
10987
|
+
const unsubscribe = child.subscribe((event) => {
|
|
10988
|
+
if (event.type === "rlm_child_update") {
|
|
10989
|
+
this._emit(event);
|
|
10990
|
+
return;
|
|
10991
|
+
}
|
|
10992
|
+
if (event.type === "agent_start") {
|
|
10993
|
+
if (run)
|
|
10994
|
+
run.activity = { kind: "waiting" };
|
|
10995
|
+
emitChildUpdate();
|
|
10996
|
+
}
|
|
10997
|
+
else if (event.type === "agent_end") {
|
|
10998
|
+
if (run)
|
|
10999
|
+
run.activity = undefined;
|
|
11000
|
+
emitChildUpdate();
|
|
11001
|
+
}
|
|
11002
|
+
else if (event.type === "message_end" && event.message.role === "assistant") {
|
|
11003
|
+
const assistant = event.message;
|
|
11004
|
+
if (run) {
|
|
11005
|
+
run.terminalAssistantOutcome = {
|
|
11006
|
+
stopReason: assistant.stopReason,
|
|
11007
|
+
errorMessage: assistant.errorMessage,
|
|
11008
|
+
};
|
|
11009
|
+
}
|
|
11010
|
+
const update = () => {
|
|
11011
|
+
const text = compactRlmText(readAssistantText(assistant));
|
|
11012
|
+
if (run && text)
|
|
11013
|
+
run.answerPreview = text;
|
|
11014
|
+
emitChildUpdate();
|
|
11015
|
+
};
|
|
11016
|
+
if (assistant.stopReason !== "error" && assistant.stopReason !== "aborted") {
|
|
11017
|
+
const messages = child.messages;
|
|
11018
|
+
const precedingPrompt = messages
|
|
11019
|
+
.slice(0, messages.lastIndexOf(assistant))
|
|
11020
|
+
.reverse()
|
|
11021
|
+
.find((message) => message.role === "user" ||
|
|
11022
|
+
(message.role === "custom" && message.customType !== HARNESS_SNAPSHOT_CUSTOM_TYPE));
|
|
11023
|
+
const origin = precedingPrompt?.role === "custom" && isAgentSessionMessage(precedingPrompt)
|
|
11024
|
+
? precedingPrompt.details.id.startsWith("spawn:")
|
|
11025
|
+
? "spawn_task"
|
|
11026
|
+
: "agent_message"
|
|
11027
|
+
: "direct_user";
|
|
11028
|
+
void attributeUsage(assistant.usage, origin).then(update, () => { });
|
|
11029
|
+
}
|
|
11030
|
+
else
|
|
11031
|
+
update();
|
|
11032
|
+
}
|
|
11033
|
+
else if (event.type === "message_start" || event.type === "message_update") {
|
|
11034
|
+
if (event.message.role === "assistant") {
|
|
11035
|
+
if (run) {
|
|
11036
|
+
const text = compactRlmText(readAssistantText(event.message));
|
|
11037
|
+
if (text)
|
|
11038
|
+
run.answerPreview = text;
|
|
11039
|
+
run.activity = { kind: "writing" };
|
|
11040
|
+
}
|
|
11041
|
+
emitChildUpdate();
|
|
11042
|
+
}
|
|
11043
|
+
}
|
|
11044
|
+
else if (event.type === "tool_execution_start") {
|
|
11045
|
+
if (run) {
|
|
11046
|
+
run.toolUseCount++;
|
|
11047
|
+
runningToolCount++;
|
|
11048
|
+
run.activity = { kind: "executing", toolName: event.toolName };
|
|
11049
|
+
}
|
|
11050
|
+
emitChildUpdate();
|
|
11051
|
+
}
|
|
11052
|
+
else if (event.type === "tool_execution_end") {
|
|
11053
|
+
if (run) {
|
|
11054
|
+
runningToolCount = Math.max(0, runningToolCount - 1);
|
|
11055
|
+
if (runningToolCount === 0)
|
|
11056
|
+
run.activity = { kind: "waiting" };
|
|
11057
|
+
}
|
|
11058
|
+
emitChildUpdate();
|
|
11059
|
+
}
|
|
11060
|
+
else if (event.type === "session_info_changed" || event.type === "recap_update")
|
|
11061
|
+
emitChildUpdate();
|
|
11062
|
+
});
|
|
11063
|
+
return () => {
|
|
11064
|
+
unsubscribe();
|
|
11065
|
+
if (child._rlmParentUsageAttribution === attributeUsage)
|
|
11066
|
+
child._rlmParentUsageAttribution = undefined;
|
|
11067
|
+
};
|
|
11068
|
+
}
|
|
10779
11069
|
/**
|
|
10780
11070
|
* Retain a finished child session for the parent lifetime so inspectors and
|
|
10781
11071
|
* daemon-hosted agent messaging can keep addressing it. Returns false (and disposes
|
|
@@ -10808,10 +11098,24 @@ export class AgentSession {
|
|
|
10808
11098
|
}
|
|
10809
11099
|
}
|
|
10810
11100
|
}
|
|
10811
|
-
this.
|
|
10812
|
-
if (
|
|
10813
|
-
|
|
11101
|
+
await this._restoreRlmChildUsageSource(childId, session);
|
|
11102
|
+
if (this._disposed || this._disposing) {
|
|
11103
|
+
await session.disposeAsync();
|
|
11104
|
+
return false;
|
|
11105
|
+
}
|
|
11106
|
+
if (this._deletingRlmChildren.has(childId) || this._deletedRlmChildIds.has(childId))
|
|
11107
|
+
return false;
|
|
11108
|
+
const retained = this._rlmChildSessions.get(childId);
|
|
11109
|
+
const run = this._activeRlmChildRuns.get(childId);
|
|
11110
|
+
if (!run?.unsubscribe && (retained?.session !== session || !this._rlmChildUnsubscribes.has(childId))) {
|
|
11111
|
+
this._rlmChildUnsubscribes.get(childId)?.();
|
|
11112
|
+
const ownedUnsubscribe = this._subscribeRlmChildEvents(childId, session);
|
|
11113
|
+
this._rlmChildUnsubscribes.set(childId, () => {
|
|
11114
|
+
ownedUnsubscribe();
|
|
11115
|
+
unsubscribe?.();
|
|
11116
|
+
});
|
|
10814
11117
|
}
|
|
11118
|
+
this._rlmChildSessions.set(childId, { session, run });
|
|
10815
11119
|
return true;
|
|
10816
11120
|
}
|
|
10817
11121
|
releaseRlmChildSession(childId, session) {
|
|
@@ -10819,8 +11123,10 @@ export class AgentSession {
|
|
|
10819
11123
|
if (run?.session === session && run.status === "done") {
|
|
10820
11124
|
const unsubscribe = run.unsubscribe ?? noopRlmChildEventUnsubscribe;
|
|
10821
11125
|
return () => {
|
|
10822
|
-
run.unsubscribe
|
|
10823
|
-
|
|
11126
|
+
if (run.unsubscribe === unsubscribe)
|
|
11127
|
+
run.unsubscribe = undefined;
|
|
11128
|
+
if (this._activeRlmChildRuns.get(childId) === run)
|
|
11129
|
+
this._activeRlmChildRuns.delete(childId);
|
|
10824
11130
|
unsubscribe();
|
|
10825
11131
|
};
|
|
10826
11132
|
}
|
|
@@ -10828,8 +11134,11 @@ export class AgentSession {
|
|
|
10828
11134
|
return false;
|
|
10829
11135
|
const unsubscribe = this._rlmChildUnsubscribes.get(childId) ?? noopRlmChildEventUnsubscribe;
|
|
10830
11136
|
return () => {
|
|
10831
|
-
this.
|
|
10832
|
-
|
|
11137
|
+
if (this._rlmChildSessions.get(childId)?.session === session &&
|
|
11138
|
+
this._rlmChildUnsubscribes.get(childId) === unsubscribe) {
|
|
11139
|
+
this._rlmChildUnsubscribes.delete(childId);
|
|
11140
|
+
this._rlmChildSessions.delete(childId);
|
|
11141
|
+
}
|
|
10833
11142
|
unsubscribe();
|
|
10834
11143
|
};
|
|
10835
11144
|
}
|
|
@@ -10956,7 +11265,7 @@ export class AgentSession {
|
|
|
10956
11265
|
return [...sessions];
|
|
10957
11266
|
}
|
|
10958
11267
|
_hasUnsettledRlmQuiescenceWork() {
|
|
10959
|
-
if (this.requests.hasPending)
|
|
11268
|
+
if (this.requests.hasPending || this._childUsageWrites.size > 0)
|
|
10960
11269
|
return true;
|
|
10961
11270
|
if (this._hasDeferredRlmTerminalNotices())
|
|
10962
11271
|
return true;
|
|
@@ -11000,6 +11309,7 @@ export class AgentSession {
|
|
|
11000
11309
|
return;
|
|
11001
11310
|
await wait(Promise.all([
|
|
11002
11311
|
...unsettledRuns.map((run) => run.settlement.promise),
|
|
11312
|
+
...this._childUsageWrites,
|
|
11003
11313
|
...childSessions.map((child) => child.waitForRlmQuiescence(cancellation.signal)),
|
|
11004
11314
|
]));
|
|
11005
11315
|
// Always loop through the self-active/deferred checks again. Work may
|
|
@@ -11167,6 +11477,14 @@ export class AgentSession {
|
|
|
11167
11477
|
// firing while the parent is idle) has no such turn; an absent edge beats a wrong one.
|
|
11168
11478
|
const spawnedByRequestId = this.isStreaming ? this._semanticEdges.lastTurnRequestId : undefined;
|
|
11169
11479
|
const parentAssistantForUsage = this._findLastAssistantMessage();
|
|
11480
|
+
const parentEntryId = parentAssistantForUsage && this._findAssistantEntryIdForMessage(parentAssistantForUsage);
|
|
11481
|
+
const usageSource = parentEntryId
|
|
11482
|
+
? {
|
|
11483
|
+
sessionId: this.sessionId,
|
|
11484
|
+
sessionFile: this.sessionFile,
|
|
11485
|
+
entryId: parentEntryId,
|
|
11486
|
+
}
|
|
11487
|
+
: undefined;
|
|
11170
11488
|
const { name: rawName, model: rawModel, thinking: rawThinking, ...unsupported } = kwargs;
|
|
11171
11489
|
const unsupportedKwargs = Object.keys(unsupported);
|
|
11172
11490
|
if (unsupportedKwargs.length > 0) {
|
|
@@ -11212,7 +11530,6 @@ export class AgentSession {
|
|
|
11212
11530
|
await this._assertRlmSubagentSessionNameAvailable(sessionName);
|
|
11213
11531
|
admission.assertCurrent();
|
|
11214
11532
|
const startedAt = Date.now();
|
|
11215
|
-
let runningToolCount = 0;
|
|
11216
11533
|
let childSession;
|
|
11217
11534
|
let usageSettlement = Promise.resolve();
|
|
11218
11535
|
const run = {
|
|
@@ -11234,6 +11551,8 @@ export class AgentSession {
|
|
|
11234
11551
|
throw new Error(run.error ?? "RLM child cancelled");
|
|
11235
11552
|
};
|
|
11236
11553
|
this._activeRlmChildRuns.set(run.id, run);
|
|
11554
|
+
if (usageSource)
|
|
11555
|
+
this._rlmChildUsageSources.set(run.id, usageSource);
|
|
11237
11556
|
this._unsettledRlmChildRuns.add(run);
|
|
11238
11557
|
const emitChildUpdate = () => {
|
|
11239
11558
|
const child = this._rlmChildSnapshotForRun(run);
|
|
@@ -11324,88 +11643,12 @@ export class AgentSession {
|
|
|
11324
11643
|
throwIfCancelled();
|
|
11325
11644
|
run.status = "running";
|
|
11326
11645
|
emitChildUpdate();
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
run.activity = { kind: "waiting" };
|
|
11334
|
-
emitChildUpdate();
|
|
11335
|
-
}
|
|
11336
|
-
else if (event.type === "agent_end") {
|
|
11337
|
-
run.activity = undefined;
|
|
11338
|
-
emitChildUpdate();
|
|
11339
|
-
}
|
|
11340
|
-
else if (event.type === "message_end" && event.message.role === "assistant") {
|
|
11341
|
-
const assistant = event.message;
|
|
11342
|
-
if (assistant.stopReason !== "error" && assistant.stopReason !== "aborted") {
|
|
11343
|
-
if (parentAssistantForUsage) {
|
|
11344
|
-
const parentEntryId = this._findAssistantEntryIdForMessage(parentAssistantForUsage);
|
|
11345
|
-
if (parentEntryId) {
|
|
11346
|
-
const messages = child.messages;
|
|
11347
|
-
const assistantIndex = messages.lastIndexOf(assistant);
|
|
11348
|
-
const precedingPrompt = messages
|
|
11349
|
-
.slice(0, assistantIndex)
|
|
11350
|
-
.reverse()
|
|
11351
|
-
.find((message) => message.role === "user" || message.role === "custom");
|
|
11352
|
-
const origin = precedingPrompt?.role === "custom" && isAgentSessionMessage(precedingPrompt)
|
|
11353
|
-
? precedingPrompt.details.id.startsWith("spawn:")
|
|
11354
|
-
? "spawn_task"
|
|
11355
|
-
: "agent_message"
|
|
11356
|
-
: "direct_user";
|
|
11357
|
-
const text = compactRlmText(readAssistantText(assistant));
|
|
11358
|
-
const refreshOutput = this._refreshInvocationOutput;
|
|
11359
|
-
const write = this.sessionManager
|
|
11360
|
-
.appendChildUsageAttributionWithAggregate(parentEntryId, assistant.usage, undefined, origin)
|
|
11361
|
-
.then(({ aggregateUsage }) => {
|
|
11362
|
-
parentAssistantForUsage.usage = structuredClone(aggregateUsage);
|
|
11363
|
-
refreshOutput?.(parentAssistantForUsage);
|
|
11364
|
-
if (text)
|
|
11365
|
-
run.answerPreview = text;
|
|
11366
|
-
emitChildUpdate();
|
|
11367
|
-
});
|
|
11368
|
-
this._childUsageWrites.add(write);
|
|
11369
|
-
usageSettlement = Promise.all([usageSettlement, write]).then(() => undefined);
|
|
11370
|
-
void usageSettlement.catch(() => undefined);
|
|
11371
|
-
void write.then(() => this._childUsageWrites.delete(write), (error) => {
|
|
11372
|
-
this._childUsageWrites.delete(write);
|
|
11373
|
-
run.error = `Child usage attribution was not acknowledged: ${this._asError(error).message}`;
|
|
11374
|
-
this._surfaceSessionInputError(error);
|
|
11375
|
-
});
|
|
11376
|
-
return;
|
|
11377
|
-
}
|
|
11378
|
-
}
|
|
11379
|
-
}
|
|
11380
|
-
const text = compactRlmText(readAssistantText(assistant));
|
|
11381
|
-
if (text)
|
|
11382
|
-
run.answerPreview = text;
|
|
11383
|
-
emitChildUpdate();
|
|
11384
|
-
}
|
|
11385
|
-
else if (event.type === "message_start" || event.type === "message_update") {
|
|
11386
|
-
if (event.message.role === "assistant") {
|
|
11387
|
-
const text = compactRlmText(readAssistantText(event.message));
|
|
11388
|
-
if (text)
|
|
11389
|
-
run.answerPreview = text;
|
|
11390
|
-
run.activity = { kind: "writing" };
|
|
11391
|
-
emitChildUpdate();
|
|
11392
|
-
}
|
|
11393
|
-
}
|
|
11394
|
-
else if (event.type === "tool_execution_start") {
|
|
11395
|
-
run.toolUseCount += 1;
|
|
11396
|
-
runningToolCount += 1;
|
|
11397
|
-
run.activity = { kind: "executing", toolName: event.toolName };
|
|
11398
|
-
emitChildUpdate();
|
|
11399
|
-
}
|
|
11400
|
-
else if (event.type === "tool_execution_end") {
|
|
11401
|
-
runningToolCount = Math.max(0, runningToolCount - 1);
|
|
11402
|
-
if (runningToolCount === 0)
|
|
11403
|
-
run.activity = { kind: "waiting" };
|
|
11404
|
-
emitChildUpdate();
|
|
11405
|
-
}
|
|
11406
|
-
else if (event.type === "session_info_changed" || event.type === "recap_update") {
|
|
11407
|
-
emitChildUpdate();
|
|
11408
|
-
}
|
|
11646
|
+
if (usageSource) {
|
|
11647
|
+
await child.sessionManager.appendCustomEntry(RLM_PARENT_USAGE_CUSTOM_TYPE, usageSource);
|
|
11648
|
+
}
|
|
11649
|
+
const unsubscribeChildEvents = this._subscribeRlmChildEvents(run.id, child, run, (write) => {
|
|
11650
|
+
usageSettlement = Promise.all([usageSettlement, write]).then(() => undefined);
|
|
11651
|
+
void usageSettlement.catch(() => undefined);
|
|
11409
11652
|
});
|
|
11410
11653
|
run.unsubscribe = unsubscribeChildEvents;
|
|
11411
11654
|
const content = `[task from parent]\n\n${prompt}`;
|
|
@@ -11433,8 +11676,19 @@ export class AgentSession {
|
|
|
11433
11676
|
source: "extension",
|
|
11434
11677
|
customMessage: spawnMessage,
|
|
11435
11678
|
});
|
|
11679
|
+
// promptAndWait can resolve after a provider error or abort. Only outcomes
|
|
11680
|
+
// emitted during this run count; a recovered intermediate error is not terminal.
|
|
11681
|
+
const terminal = run.terminalAssistantOutcome;
|
|
11682
|
+
if (terminal?.stopReason === "aborted") {
|
|
11683
|
+
run.status = "cancelled";
|
|
11684
|
+
run.error ??= terminal.errorMessage || "RLM child aborted";
|
|
11685
|
+
}
|
|
11686
|
+
throwIfCancelled();
|
|
11687
|
+
if (terminal?.stopReason === "error")
|
|
11688
|
+
throw new Error(terminal.errorMessage || "RLM child inference failed");
|
|
11436
11689
|
await child.waitForRlmQuiescence();
|
|
11437
11690
|
await usageSettlement;
|
|
11691
|
+
throwIfCancelled();
|
|
11438
11692
|
if (run.error)
|
|
11439
11693
|
throw new Error(run.error);
|
|
11440
11694
|
run.status = "done";
|
|
@@ -12424,7 +12678,12 @@ export class AgentSession {
|
|
|
12424
12678
|
? { tokens: estimate.tokens, contextWindow, percent: (estimate.tokens / contextWindow) * 100 }
|
|
12425
12679
|
: { tokens: null, contextWindow, percent: null }
|
|
12426
12680
|
: undefined;
|
|
12427
|
-
const usageMetadata = {
|
|
12681
|
+
const usageMetadata = {
|
|
12682
|
+
ownUsage: usage.ownUsage,
|
|
12683
|
+
totalUsage: usage.totalUsage,
|
|
12684
|
+
...(usage.ownRequestUsage ? { ownRequestUsage: usage.ownRequestUsage } : {}),
|
|
12685
|
+
contextUsage,
|
|
12686
|
+
};
|
|
12428
12687
|
request.retainMetadata({ contextUsage });
|
|
12429
12688
|
return {
|
|
12430
12689
|
...rootNode,
|