@ponythewhite/base-context 1.0.10 → 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 +22 -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-MX6YNAM2.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-UHLGPYMI.js → chunk-IAKHCQA2.js} +185 -39
- 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-CDXQNS5P.js → chunk-YGV3Y4AD.js} +1009 -185
- package/dist/bundle/{cli-main-D7W3WWCV.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-5J3QBZ5Y.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 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +445 -146
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/canonical-context.d.ts +19 -3
- package/dist/core/canonical-context.d.ts.map +1 -1
- package/dist/core/canonical-context.js +130 -9
- package/dist/core/canonical-context.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-epoch-copy.d.ts +1 -1
- package/dist/core/context-epoch-copy.d.ts.map +1 -1
- package/dist/core/context-epoch-copy.js +18 -7
- package/dist/core/context-epoch-copy.js.map +1 -1
- package/dist/core/context-epoch.d.ts +4 -0
- package/dist/core/context-epoch.d.ts.map +1 -1
- package/dist/core/context-epoch.js +8 -1
- package/dist/core/context-epoch.js.map +1 -1
- package/dist/core/context-tree.d.ts +14 -11
- package/dist/core/context-tree.d.ts.map +1 -1
- package/dist/core/context-tree.js +145 -9
- package/dist/core/context-tree.js.map +1 -1
- package/dist/core/history-index-worker.d.ts.map +1 -1
- package/dist/core/history-index-worker.js +59 -6
- package/dist/core/history-index-worker.js.map +1 -1
- package/dist/core/history-index.d.ts +17 -0
- package/dist/core/history-index.d.ts.map +1 -1
- package/dist/core/history-index.js +22 -0
- package/dist/core/history-index.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 +23 -6
- 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/request-view-selection.d.ts +2 -1
- package/dist/core/request-view-selection.d.ts.map +1 -1
- package/dist/core/request-view-selection.js +29 -2
- package/dist/core/request-view-selection.js.map +1 -1
- package/dist/core/session-fork-messages.d.ts +5 -0
- package/dist/core/session-fork-messages.d.ts.map +1 -1
- package/dist/core/session-fork-messages.js +44 -0
- package/dist/core/session-fork-messages.js.map +1 -1
- package/dist/core/session-history-index.d.ts +5 -0
- package/dist/core/session-history-index.d.ts.map +1 -1
- package/dist/core/session-history-index.js +7 -0
- package/dist/core/session-history-index.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +155 -13
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-tree.d.ts +9 -0
- package/dist/core/session-tree.d.ts.map +1 -1
- package/dist/core/session-tree.js +71 -11
- package/dist/core/session-tree.js.map +1 -1
- 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/agent-connection/in-process-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.js +4 -4
- package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +4 -4
- package/dist/modes/daemon/daemon-mode.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
|
@@ -15,9 +15,9 @@ import { addLoginGuidanceToAuthError, formatAuthenticationFailedMessage, formatN
|
|
|
15
15
|
import { addAutonomousContinuation, addAutonomousUsage, autonomousStatus, createAutonomousRuntimeState, nextAutonomousContinuation, refreshAutonomousQualityGates, setAutonomousEnabled, } from "./autonomous.js";
|
|
16
16
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
17
17
|
import { stringifyBoundedJson } from "./bounded-json.js";
|
|
18
|
-
import { CanonicalContextCompiler, canonicalRecoveryBoundary, getCanonicalEpochContext, getCanonicalMessageSource, getCanonicalViewUnits, 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, } from "./context-epoch.js";
|
|
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, 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,11 +28,11 @@ 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";
|
|
35
|
-
import { PublicContextBudgetError } from "./request-view-selection.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
|
+
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";
|
|
38
38
|
import { createDefaultRlmSubagentSessionName, createRlmDeleteSubagentHostHandler, createRlmFindModelsHostHandler, createRlmListSubagentsHostHandler, createRlmRunHostHandler, findRlmModelMatches, normalizeRequestedRlmSubagentModel, normalizeRequestedRlmSubagentSessionName, normalizeRequestedRlmSubagentThinkingLevel, } from "./rlm-runtime.js";
|
|
@@ -45,8 +45,9 @@ 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
49
|
import { exportSessionBranchToJsonl } from "./session-jsonl-export.js";
|
|
49
|
-
import {
|
|
50
|
+
import { getLatestCompactionEntry, SessionManager, } from "./session-manager.js";
|
|
50
51
|
import { getPythonSkillRuntimeInfo } from "./skills.js";
|
|
51
52
|
import { parseRefineCommandOptions, parseSessionSlashCommand, parseSlashCommand, } from "./slash-commands.js";
|
|
52
53
|
import { createSyntheticSourceInfo } from "./source-info.js";
|
|
@@ -191,6 +192,7 @@ function createPostCompactionContinuationSettlement(resume) {
|
|
|
191
192
|
return { ...createAgentMessageDeferred(), resume, settled: false };
|
|
192
193
|
}
|
|
193
194
|
import { LocalRlmSubagentCapacity, } from "./rlm-max-subagents.js";
|
|
195
|
+
const RLM_PARENT_USAGE_CUSTOM_TYPE = "rlm_parent_usage";
|
|
194
196
|
const KERNEL_STATE_LISTING_TIMEOUT_MS = 5000;
|
|
195
197
|
const RLM_MAX_DEPTH_STATE_CUSTOM_TYPE = "rlm_max_depth_state";
|
|
196
198
|
function noopRlmChildAbort() { }
|
|
@@ -435,6 +437,8 @@ export class AgentSession {
|
|
|
435
437
|
// Kept alive for retained children so nested updates (e.g. a grandchild cancel)
|
|
436
438
|
// still forward to root; torn down when the retained child is disposed.
|
|
437
439
|
_rlmChildUnsubscribes = new Map();
|
|
440
|
+
_rlmChildUsageSources = new Map();
|
|
441
|
+
_rlmParentUsageAttribution;
|
|
438
442
|
/** Latest recap for this session, written by the daemon summarizer; read by a parent to label its child snapshots. */
|
|
439
443
|
_currentRecap;
|
|
440
444
|
_initialGoal;
|
|
@@ -559,11 +563,13 @@ export class AgentSession {
|
|
|
559
563
|
await this._goalResumeOperation;
|
|
560
564
|
await this._waitForAgentEventsBeforeContext();
|
|
561
565
|
await this._waitForChildUsageWrites();
|
|
566
|
+
const assertHarnessSourceCurrent = await this._appendHarnessSnapshotIfChanged();
|
|
562
567
|
await this.sessionManager.flushNow();
|
|
568
|
+
assertHarnessSourceCurrent();
|
|
563
569
|
// In-memory sessions have no canonical archive. This is an explicit mode, not an index-error fallback.
|
|
564
570
|
if (!this.sessionManager.isPersisted()) {
|
|
565
571
|
if (!this._compactionSetupFailure)
|
|
566
|
-
return;
|
|
572
|
+
return { messages: this.agent.state.messages, adoptMessages: true };
|
|
567
573
|
const rebuilt = await readSessionBootstrap(this.sessionManager, this.settingsManager.getCanonicalContextLimits());
|
|
568
574
|
this._compactionSetupFailure = undefined;
|
|
569
575
|
return { messages: rebuilt.context.messages, adoptMessages: true };
|
|
@@ -616,7 +622,10 @@ export class AgentSession {
|
|
|
616
622
|
if (epochContext)
|
|
617
623
|
this._contextMode = epochContext.mode;
|
|
618
624
|
const unbudgetedPublic = !contextEpochsEnabled &&
|
|
619
|
-
Boolean(epochContext?.toolContinuations?.length ||
|
|
625
|
+
Boolean(epochContext?.toolContinuations?.length ||
|
|
626
|
+
epochContext?.taskFrameRebased ||
|
|
627
|
+
epochContext?.checkpoint ||
|
|
628
|
+
getCanonicalViewSelectionSource(messages)?.recoveryContractRequested);
|
|
620
629
|
const nativeSkills = Boolean(contextEpochsEnabled || epochContext?.checkpoint || unbudgetedPublic);
|
|
621
630
|
const skillPolicy = nativeSkills ? (this._nativeRecoveryEnabled() ? "enabled" : "unavailable") : undefined;
|
|
622
631
|
if (this._baseSystemPromptOptions.nativeSkillSelection !== skillPolicy) {
|
|
@@ -663,7 +672,37 @@ export class AgentSession {
|
|
|
663
672
|
candidate.projection.pendingPublicMessageGroups?.length))
|
|
664
673
|
throw new Error("Tool continuation requires its exact public candidate before epoch ACK");
|
|
665
674
|
assertResourceCurrent(resource);
|
|
666
|
-
|
|
675
|
+
let representation;
|
|
676
|
+
try {
|
|
677
|
+
representation = contextEpochRepresentation(candidate.request, candidate.assessment, limits.maxSourceBytes, unbudgetedPublic, candidate.responseItemIdentity);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
if (error instanceof UnsupportedContextEpochConfigurationError &&
|
|
681
|
+
!contextEpochsEnabled &&
|
|
682
|
+
!candidate.assessment &&
|
|
683
|
+
!committed &&
|
|
684
|
+
!acknowledged &&
|
|
685
|
+
!epochContext.taskFrameRebased &&
|
|
686
|
+
!epochContext.selectedSkills?.length &&
|
|
687
|
+
!epochContext.toolContinuations?.length &&
|
|
688
|
+
!candidate.publicMessages) {
|
|
689
|
+
const source = getCanonicalViewSelectionSource(messages);
|
|
690
|
+
const selected = new Set(candidate.selectedUnitIds);
|
|
691
|
+
if (source.recoveryContractRequested &&
|
|
692
|
+
!source.requiresEpoch &&
|
|
693
|
+
!source.pendingPublicMessageGroups?.length &&
|
|
694
|
+
this.sessionManager === epochManager &&
|
|
695
|
+
compaction.isCurrent() &&
|
|
696
|
+
JSON.stringify(candidate.source) === JSON.stringify(source.source) &&
|
|
697
|
+
candidate.selectedUnitIds.length === source.units.length &&
|
|
698
|
+
selected.size === source.units.length &&
|
|
699
|
+
source.units.every((unit) => selected.has(unit.id))) {
|
|
700
|
+
// Optional capture only. Keep the unchanged full-native offer; grant no epoch or omission.
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
throw error;
|
|
705
|
+
}
|
|
667
706
|
const replayContract = "replayContract" in candidate.projection &&
|
|
668
707
|
candidate.projection.replayContract === "message-groups"
|
|
669
708
|
? "message-groups"
|
|
@@ -2916,7 +2955,8 @@ export class AgentSession {
|
|
|
2916
2955
|
if (compactionTimestamp !== undefined && context.message.timestamp <= compactionTimestamp)
|
|
2917
2956
|
return false;
|
|
2918
2957
|
const contextTokens = this._getThresholdContextTokens(context.message, compactionTimestamp);
|
|
2919
|
-
if (contextTokens === undefined ||
|
|
2958
|
+
if (contextTokens === undefined ||
|
|
2959
|
+
!shouldCompact(contextTokens, contextWindow, settings, estimateFixedCompactionTokens(this.systemPrompt, this.agent.state.tools, this.messages)))
|
|
2920
2960
|
return false;
|
|
2921
2961
|
if (this._hasFailedThresholdCompaction())
|
|
2922
2962
|
return false;
|
|
@@ -3280,7 +3320,7 @@ export class AgentSession {
|
|
|
3280
3320
|
}
|
|
3281
3321
|
return {
|
|
3282
3322
|
scheduled: true,
|
|
3283
|
-
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.",
|
|
3284
3324
|
};
|
|
3285
3325
|
}
|
|
3286
3326
|
default:
|
|
@@ -4348,6 +4388,7 @@ export class AgentSession {
|
|
|
4348
4388
|
for (const { session } of this._rlmChildSessions.values())
|
|
4349
4389
|
await drain(() => session.disposeAsync());
|
|
4350
4390
|
this._rlmChildSessions.clear();
|
|
4391
|
+
this._rlmChildUsageSources.clear();
|
|
4351
4392
|
this._rlmChildCleanupFailures.clear();
|
|
4352
4393
|
this._deletedRlmChildIds.clear();
|
|
4353
4394
|
// Stop kernel-backed tools before waiting for their terminal agent events.
|
|
@@ -4443,6 +4484,7 @@ export class AgentSession {
|
|
|
4443
4484
|
session.dispose();
|
|
4444
4485
|
}
|
|
4445
4486
|
this._rlmChildSessions.clear();
|
|
4487
|
+
this._rlmChildUsageSources.clear();
|
|
4446
4488
|
this._rlmChildCleanupFailures.clear();
|
|
4447
4489
|
this._deletedRlmChildIds.clear();
|
|
4448
4490
|
this._pendingNextTurnMessages = [];
|
|
@@ -4687,6 +4729,7 @@ export class AgentSession {
|
|
|
4687
4729
|
rlmDepth: this._rlmDepth,
|
|
4688
4730
|
rlmParentAgent: this._rlmParentAgent,
|
|
4689
4731
|
harnessState: this._loadMergedHarnessState(),
|
|
4732
|
+
harnessSection: "instructions",
|
|
4690
4733
|
errorFixSelection: {
|
|
4691
4734
|
enabled: this.settingsManager.getLearningEnabled(),
|
|
4692
4735
|
tools: validToolNames,
|
|
@@ -4699,6 +4742,118 @@ export class AgentSession {
|
|
|
4699
4742
|
};
|
|
4700
4743
|
return buildSystemPrompt(this._baseSystemPromptOptions);
|
|
4701
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
|
+
}
|
|
4702
4857
|
_refreshExtensionSystemPrompt(extensionPrompt, baseSnapshot) {
|
|
4703
4858
|
if (this._baseSystemPrompt === baseSnapshot) {
|
|
4704
4859
|
return extensionPrompt;
|
|
@@ -4755,7 +4910,7 @@ export class AgentSession {
|
|
|
4755
4910
|
async _runPreTurnCompaction() {
|
|
4756
4911
|
const lastAssistant = this._findLastAssistantMessage();
|
|
4757
4912
|
if (lastAssistant)
|
|
4758
|
-
await this._checkCompaction(lastAssistant, false, false);
|
|
4913
|
+
await this._checkCompaction(lastAssistant, false, false, undefined, true);
|
|
4759
4914
|
}
|
|
4760
4915
|
async _prepareForCommit(policy, steps) {
|
|
4761
4916
|
if (policy.initialRefineBarrier === "always" ||
|
|
@@ -7727,7 +7882,7 @@ export class AgentSession {
|
|
|
7727
7882
|
}
|
|
7728
7883
|
}
|
|
7729
7884
|
/** A private compiled context keeps extension summary edits separate from retained source recipes. */
|
|
7730
|
-
async _prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false) {
|
|
7885
|
+
async _prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false, capacity) {
|
|
7731
7886
|
this._assertCompactionOwner(owner);
|
|
7732
7887
|
const limits = this.settingsManager.getCanonicalContextLimits();
|
|
7733
7888
|
const resource = this._captureKernelResource();
|
|
@@ -7744,13 +7899,14 @@ export class AgentSession {
|
|
|
7744
7899
|
const context = getCanonicalEpochContext(messages);
|
|
7745
7900
|
if (context.checkpoint?.includeSummary && pathEntries.at(-1)?.type === "compaction")
|
|
7746
7901
|
return { preparation: undefined, maxSourceBytes: limits.maxSourceBytes };
|
|
7747
|
-
const
|
|
7902
|
+
const authorization = getRecoveryCompactionAuthorization(capacity);
|
|
7903
|
+
const boundary = canonicalRecoveryBoundary(messages, authorization);
|
|
7748
7904
|
const preparation = budgetPressure || context.checkpoint || boundary
|
|
7749
7905
|
? prepareViewCompaction(messages, context.references.map((ref) => ref?.ref.entryId), pathEntries, settings, boundary, allowShortSession, budgetPressure)
|
|
7750
7906
|
: prepareCompaction(pathEntries, settings, allowShortSession);
|
|
7751
7907
|
// Refuse unsupported public data or open groups before starting the summary model call.
|
|
7752
7908
|
if (preparation)
|
|
7753
|
-
prepareRecoveryCompaction(messages, preparation.firstKeptEntryId, limits.maxSourceBytes);
|
|
7909
|
+
prepareRecoveryCompaction(messages, preparation.firstKeptEntryId, limits.maxSourceBytes, authorization);
|
|
7754
7910
|
return {
|
|
7755
7911
|
preparation,
|
|
7756
7912
|
messages,
|
|
@@ -7766,7 +7922,7 @@ export class AgentSession {
|
|
|
7766
7922
|
*/
|
|
7767
7923
|
async _performCompaction(options) {
|
|
7768
7924
|
const { model, apiKey, headers, customInstructions, signal, thinkingLevel, requests, compaction, semanticEdges, pathEntries, settings, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false, } = options;
|
|
7769
|
-
const prepared = await this._prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner, allowShortSession, budgetPressure);
|
|
7925
|
+
const prepared = await this._prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner, allowShortSession, budgetPressure, options.capacity);
|
|
7770
7926
|
this._assertCompactionOwner(owner);
|
|
7771
7927
|
if (prepared.resource)
|
|
7772
7928
|
assertResourceCurrent(prepared.resource);
|
|
@@ -7864,7 +8020,7 @@ export class AgentSession {
|
|
|
7864
8020
|
this._assertCompactionOwner(owner);
|
|
7865
8021
|
const result = JSON.parse(JSON.stringify({ summary, firstKeptEntryId, tokensBefore, details }));
|
|
7866
8022
|
const recovery = prepared.messages
|
|
7867
|
-
? prepareRecoveryCompaction(prepared.messages, firstKeptEntryId, prepared.maxSourceBytes)
|
|
8023
|
+
? prepareRecoveryCompaction(prepared.messages, firstKeptEntryId, prepared.maxSourceBytes, getRecoveryCompactionAuthorization(options.capacity))
|
|
7868
8024
|
: undefined;
|
|
7869
8025
|
if (prepared.resource)
|
|
7870
8026
|
assertResourceCurrent(prepared.resource);
|
|
@@ -8557,7 +8713,31 @@ export class AgentSession {
|
|
|
8557
8713
|
const sessionHistory = (async () => {
|
|
8558
8714
|
if (residentEntries !== undefined)
|
|
8559
8715
|
return residentEntries;
|
|
8560
|
-
return
|
|
8716
|
+
return this.sessionManager.readSourceHistory(async (history) => {
|
|
8717
|
+
const entries = [];
|
|
8718
|
+
let sourceBytes = 0;
|
|
8719
|
+
let after = 0;
|
|
8720
|
+
for (;;) {
|
|
8721
|
+
const page = await history.page(after, 128);
|
|
8722
|
+
if (page.indexedThrough < history.source.sourceSequence)
|
|
8723
|
+
throw new Error("Captured refinement history has incomplete index coverage");
|
|
8724
|
+
for (const reference of page.events) {
|
|
8725
|
+
if (reference.kind !== "custom")
|
|
8726
|
+
continue;
|
|
8727
|
+
// Refinement consumes custom records, not archived conversation or request bodies.
|
|
8728
|
+
if (entries.length >= limits.maxEntries)
|
|
8729
|
+
throw new Error("Refinement history entry budget exceeded");
|
|
8730
|
+
if (sourceBytes + reference.locator.length > limits.maxSourceBytes)
|
|
8731
|
+
throw new Error("Refinement history source byte budget exceeded");
|
|
8732
|
+
const hydrated = await hydrateCapturedHistoryEntry(reference, limits.maxSourceBytes - sourceBytes, history.readPayload);
|
|
8733
|
+
entries.push(hydrated.entry);
|
|
8734
|
+
sourceBytes += reference.locator.length;
|
|
8735
|
+
}
|
|
8736
|
+
if (page.nextAfter === null)
|
|
8737
|
+
return entries;
|
|
8738
|
+
after = page.nextAfter;
|
|
8739
|
+
}
|
|
8740
|
+
});
|
|
8561
8741
|
})();
|
|
8562
8742
|
const [globalResult, sessionResult] = await Promise.allSettled([globalHistory, sessionHistory]);
|
|
8563
8743
|
if (globalResult.status === "rejected") {
|
|
@@ -8869,8 +9049,12 @@ export class AgentSession {
|
|
|
8869
9049
|
}
|
|
8870
9050
|
if (refinementAuditAppendError)
|
|
8871
9051
|
throw refinementAuditAppendError.error;
|
|
8872
|
-
|
|
8873
|
-
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.
|
|
8874
9058
|
try {
|
|
8875
9059
|
this._emit({ type: "refine_complete", result });
|
|
8876
9060
|
}
|
|
@@ -8935,7 +9119,7 @@ export class AgentSession {
|
|
|
8935
9119
|
return undefined;
|
|
8936
9120
|
return calculateContextTokens(assistantMessage.usage);
|
|
8937
9121
|
}
|
|
8938
|
-
async _checkCompaction(assistantMessage, skipAbortedCheck = true, queueAutonomousContinuation = true, invocationOwner) {
|
|
9122
|
+
async _checkCompaction(assistantMessage, skipAbortedCheck = true, queueAutonomousContinuation = true, invocationOwner, beforeNextTurn = false) {
|
|
8939
9123
|
if (this._compactionSetupFailure)
|
|
8940
9124
|
return false;
|
|
8941
9125
|
if (invocationOwner && !this._isCompactionSourceOwnerCurrent(invocationOwner))
|
|
@@ -9036,7 +9220,7 @@ export class AgentSession {
|
|
|
9036
9220
|
if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
|
|
9037
9221
|
this._removeLastAssistantFromContext();
|
|
9038
9222
|
}
|
|
9039
|
-
return await this._runAutoCompaction("overflow", true, owner);
|
|
9223
|
+
return await this._runAutoCompaction("overflow", true, owner, false, undefined, beforeNextTurn);
|
|
9040
9224
|
}
|
|
9041
9225
|
if (this._pendingRequestedCompaction !== undefined) {
|
|
9042
9226
|
return await this._runAutoCompaction("requested", false, owner);
|
|
@@ -9052,7 +9236,7 @@ export class AgentSession {
|
|
|
9052
9236
|
const contextTokens = this._getThresholdContextTokens(assistantMessage, compactionTimestamp);
|
|
9053
9237
|
if (contextTokens === undefined)
|
|
9054
9238
|
return false;
|
|
9055
|
-
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
9239
|
+
if (shouldCompact(contextTokens, contextWindow, settings, estimateFixedCompactionTokens(this.systemPrompt, this.agent.state.tools, this.messages))) {
|
|
9056
9240
|
if (this._hasFailedThresholdCompaction())
|
|
9057
9241
|
return false;
|
|
9058
9242
|
if (!this._pendingCheckpoint && queueAutonomousContinuation) {
|
|
@@ -9063,7 +9247,7 @@ export class AgentSession {
|
|
|
9063
9247
|
}
|
|
9064
9248
|
if (!this._isCompactionOwnerCurrent(owner) || !this._contextOptimizationAllowed())
|
|
9065
9249
|
return false;
|
|
9066
|
-
return await this._runAutoCompaction("threshold", false, owner);
|
|
9250
|
+
return await this._runAutoCompaction("threshold", false, owner, false, undefined, beforeNextTurn);
|
|
9067
9251
|
}
|
|
9068
9252
|
return false;
|
|
9069
9253
|
}
|
|
@@ -9109,7 +9293,7 @@ export class AgentSession {
|
|
|
9109
9293
|
this._emit({ type: "message_start", message: outcomeMessage });
|
|
9110
9294
|
this._emit({ type: "message_end", message: outcomeMessage });
|
|
9111
9295
|
}
|
|
9112
|
-
async _runAutoCompaction(reason, willRetry, capturedOwner, resumeInPlace = false, capacity) {
|
|
9296
|
+
async _runAutoCompaction(reason, willRetry, capturedOwner, resumeInPlace = false, capacity, beforeNextTurn = false) {
|
|
9113
9297
|
const checkpoint = this._pendingCheckpoint;
|
|
9114
9298
|
const pending = this._pendingRequestedCompaction;
|
|
9115
9299
|
const owner = checkpoint?.owner ?? pending?.owner ?? capturedOwner ?? this._captureCompactionOwner();
|
|
@@ -9245,6 +9429,13 @@ export class AgentSession {
|
|
|
9245
9429
|
if (!this._isCompactionSourceOwnerCurrent(owner))
|
|
9246
9430
|
throw failure;
|
|
9247
9431
|
this._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(reason === "threshold" && shouldContinueAfterCompaction, queuedAutonomousContinuationsForThisCompaction);
|
|
9432
|
+
if (beforeNextTurn && error instanceof MissingRecoveryReplayContractError) {
|
|
9433
|
+
// Let the imminent MAIN obtain its own actual projection/ACK. This was not a recovery attempt.
|
|
9434
|
+
if (reason === "overflow")
|
|
9435
|
+
this._overflowRecovery = "idle";
|
|
9436
|
+
await this._endCompactionUnsuccessfully(reason, "skipped", "Compaction deferred until the next native request establishes recovery replay coverage.", { errorSeverity: "warning", customInstructions, owner });
|
|
9437
|
+
return false;
|
|
9438
|
+
}
|
|
9248
9439
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
9249
9440
|
const aborted = errorMessage === "Compaction cancelled" ||
|
|
9250
9441
|
(error instanceof Error && error.name === "AbortError") ||
|
|
@@ -10625,6 +10816,7 @@ export class AgentSession {
|
|
|
10625
10816
|
this._rlmChildUnsubscribes.get(childId)?.();
|
|
10626
10817
|
this._rlmChildUnsubscribes.delete(childId);
|
|
10627
10818
|
this._rlmChildSessions.delete(childId);
|
|
10819
|
+
this._rlmChildUsageSources.delete(childId);
|
|
10628
10820
|
this._rlmChildCleanupFailures.delete(childId);
|
|
10629
10821
|
this._abandonedRlmQuiescenceChildIds.delete(childId);
|
|
10630
10822
|
if (!run || this._activeRlmChildRuns.get(childId) === run) {
|
|
@@ -10710,6 +10902,170 @@ export class AgentSession {
|
|
|
10710
10902
|
this._removeRlmSubagentTracking(childId);
|
|
10711
10903
|
return { subagent };
|
|
10712
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
|
+
}
|
|
10713
11069
|
/**
|
|
10714
11070
|
* Retain a finished child session for the parent lifetime so inspectors and
|
|
10715
11071
|
* daemon-hosted agent messaging can keep addressing it. Returns false (and disposes
|
|
@@ -10742,10 +11098,24 @@ export class AgentSession {
|
|
|
10742
11098
|
}
|
|
10743
11099
|
}
|
|
10744
11100
|
}
|
|
10745
|
-
this.
|
|
10746
|
-
if (
|
|
10747
|
-
|
|
11101
|
+
await this._restoreRlmChildUsageSource(childId, session);
|
|
11102
|
+
if (this._disposed || this._disposing) {
|
|
11103
|
+
await session.disposeAsync();
|
|
11104
|
+
return false;
|
|
10748
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
|
+
});
|
|
11117
|
+
}
|
|
11118
|
+
this._rlmChildSessions.set(childId, { session, run });
|
|
10749
11119
|
return true;
|
|
10750
11120
|
}
|
|
10751
11121
|
releaseRlmChildSession(childId, session) {
|
|
@@ -10753,8 +11123,10 @@ export class AgentSession {
|
|
|
10753
11123
|
if (run?.session === session && run.status === "done") {
|
|
10754
11124
|
const unsubscribe = run.unsubscribe ?? noopRlmChildEventUnsubscribe;
|
|
10755
11125
|
return () => {
|
|
10756
|
-
run.unsubscribe
|
|
10757
|
-
|
|
11126
|
+
if (run.unsubscribe === unsubscribe)
|
|
11127
|
+
run.unsubscribe = undefined;
|
|
11128
|
+
if (this._activeRlmChildRuns.get(childId) === run)
|
|
11129
|
+
this._activeRlmChildRuns.delete(childId);
|
|
10758
11130
|
unsubscribe();
|
|
10759
11131
|
};
|
|
10760
11132
|
}
|
|
@@ -10762,8 +11134,11 @@ export class AgentSession {
|
|
|
10762
11134
|
return false;
|
|
10763
11135
|
const unsubscribe = this._rlmChildUnsubscribes.get(childId) ?? noopRlmChildEventUnsubscribe;
|
|
10764
11136
|
return () => {
|
|
10765
|
-
this.
|
|
10766
|
-
|
|
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
|
+
}
|
|
10767
11142
|
unsubscribe();
|
|
10768
11143
|
};
|
|
10769
11144
|
}
|
|
@@ -10890,7 +11265,7 @@ export class AgentSession {
|
|
|
10890
11265
|
return [...sessions];
|
|
10891
11266
|
}
|
|
10892
11267
|
_hasUnsettledRlmQuiescenceWork() {
|
|
10893
|
-
if (this.requests.hasPending)
|
|
11268
|
+
if (this.requests.hasPending || this._childUsageWrites.size > 0)
|
|
10894
11269
|
return true;
|
|
10895
11270
|
if (this._hasDeferredRlmTerminalNotices())
|
|
10896
11271
|
return true;
|
|
@@ -10934,6 +11309,7 @@ export class AgentSession {
|
|
|
10934
11309
|
return;
|
|
10935
11310
|
await wait(Promise.all([
|
|
10936
11311
|
...unsettledRuns.map((run) => run.settlement.promise),
|
|
11312
|
+
...this._childUsageWrites,
|
|
10937
11313
|
...childSessions.map((child) => child.waitForRlmQuiescence(cancellation.signal)),
|
|
10938
11314
|
]));
|
|
10939
11315
|
// Always loop through the self-active/deferred checks again. Work may
|
|
@@ -11101,6 +11477,14 @@ export class AgentSession {
|
|
|
11101
11477
|
// firing while the parent is idle) has no such turn; an absent edge beats a wrong one.
|
|
11102
11478
|
const spawnedByRequestId = this.isStreaming ? this._semanticEdges.lastTurnRequestId : undefined;
|
|
11103
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;
|
|
11104
11488
|
const { name: rawName, model: rawModel, thinking: rawThinking, ...unsupported } = kwargs;
|
|
11105
11489
|
const unsupportedKwargs = Object.keys(unsupported);
|
|
11106
11490
|
if (unsupportedKwargs.length > 0) {
|
|
@@ -11146,7 +11530,6 @@ export class AgentSession {
|
|
|
11146
11530
|
await this._assertRlmSubagentSessionNameAvailable(sessionName);
|
|
11147
11531
|
admission.assertCurrent();
|
|
11148
11532
|
const startedAt = Date.now();
|
|
11149
|
-
let runningToolCount = 0;
|
|
11150
11533
|
let childSession;
|
|
11151
11534
|
let usageSettlement = Promise.resolve();
|
|
11152
11535
|
const run = {
|
|
@@ -11168,6 +11551,8 @@ export class AgentSession {
|
|
|
11168
11551
|
throw new Error(run.error ?? "RLM child cancelled");
|
|
11169
11552
|
};
|
|
11170
11553
|
this._activeRlmChildRuns.set(run.id, run);
|
|
11554
|
+
if (usageSource)
|
|
11555
|
+
this._rlmChildUsageSources.set(run.id, usageSource);
|
|
11171
11556
|
this._unsettledRlmChildRuns.add(run);
|
|
11172
11557
|
const emitChildUpdate = () => {
|
|
11173
11558
|
const child = this._rlmChildSnapshotForRun(run);
|
|
@@ -11258,88 +11643,12 @@ export class AgentSession {
|
|
|
11258
11643
|
throwIfCancelled();
|
|
11259
11644
|
run.status = "running";
|
|
11260
11645
|
emitChildUpdate();
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
run.activity = { kind: "waiting" };
|
|
11268
|
-
emitChildUpdate();
|
|
11269
|
-
}
|
|
11270
|
-
else if (event.type === "agent_end") {
|
|
11271
|
-
run.activity = undefined;
|
|
11272
|
-
emitChildUpdate();
|
|
11273
|
-
}
|
|
11274
|
-
else if (event.type === "message_end" && event.message.role === "assistant") {
|
|
11275
|
-
const assistant = event.message;
|
|
11276
|
-
if (assistant.stopReason !== "error" && assistant.stopReason !== "aborted") {
|
|
11277
|
-
if (parentAssistantForUsage) {
|
|
11278
|
-
const parentEntryId = this._findAssistantEntryIdForMessage(parentAssistantForUsage);
|
|
11279
|
-
if (parentEntryId) {
|
|
11280
|
-
const messages = child.messages;
|
|
11281
|
-
const assistantIndex = messages.lastIndexOf(assistant);
|
|
11282
|
-
const precedingPrompt = messages
|
|
11283
|
-
.slice(0, assistantIndex)
|
|
11284
|
-
.reverse()
|
|
11285
|
-
.find((message) => message.role === "user" || message.role === "custom");
|
|
11286
|
-
const origin = precedingPrompt?.role === "custom" && isAgentSessionMessage(precedingPrompt)
|
|
11287
|
-
? precedingPrompt.details.id.startsWith("spawn:")
|
|
11288
|
-
? "spawn_task"
|
|
11289
|
-
: "agent_message"
|
|
11290
|
-
: "direct_user";
|
|
11291
|
-
const text = compactRlmText(readAssistantText(assistant));
|
|
11292
|
-
const refreshOutput = this._refreshInvocationOutput;
|
|
11293
|
-
const write = this.sessionManager
|
|
11294
|
-
.appendChildUsageAttributionWithAggregate(parentEntryId, assistant.usage, undefined, origin)
|
|
11295
|
-
.then(({ aggregateUsage }) => {
|
|
11296
|
-
parentAssistantForUsage.usage = structuredClone(aggregateUsage);
|
|
11297
|
-
refreshOutput?.(parentAssistantForUsage);
|
|
11298
|
-
if (text)
|
|
11299
|
-
run.answerPreview = text;
|
|
11300
|
-
emitChildUpdate();
|
|
11301
|
-
});
|
|
11302
|
-
this._childUsageWrites.add(write);
|
|
11303
|
-
usageSettlement = Promise.all([usageSettlement, write]).then(() => undefined);
|
|
11304
|
-
void usageSettlement.catch(() => undefined);
|
|
11305
|
-
void write.then(() => this._childUsageWrites.delete(write), (error) => {
|
|
11306
|
-
this._childUsageWrites.delete(write);
|
|
11307
|
-
run.error = `Child usage attribution was not acknowledged: ${this._asError(error).message}`;
|
|
11308
|
-
this._surfaceSessionInputError(error);
|
|
11309
|
-
});
|
|
11310
|
-
return;
|
|
11311
|
-
}
|
|
11312
|
-
}
|
|
11313
|
-
}
|
|
11314
|
-
const text = compactRlmText(readAssistantText(assistant));
|
|
11315
|
-
if (text)
|
|
11316
|
-
run.answerPreview = text;
|
|
11317
|
-
emitChildUpdate();
|
|
11318
|
-
}
|
|
11319
|
-
else if (event.type === "message_start" || event.type === "message_update") {
|
|
11320
|
-
if (event.message.role === "assistant") {
|
|
11321
|
-
const text = compactRlmText(readAssistantText(event.message));
|
|
11322
|
-
if (text)
|
|
11323
|
-
run.answerPreview = text;
|
|
11324
|
-
run.activity = { kind: "writing" };
|
|
11325
|
-
emitChildUpdate();
|
|
11326
|
-
}
|
|
11327
|
-
}
|
|
11328
|
-
else if (event.type === "tool_execution_start") {
|
|
11329
|
-
run.toolUseCount += 1;
|
|
11330
|
-
runningToolCount += 1;
|
|
11331
|
-
run.activity = { kind: "executing", toolName: event.toolName };
|
|
11332
|
-
emitChildUpdate();
|
|
11333
|
-
}
|
|
11334
|
-
else if (event.type === "tool_execution_end") {
|
|
11335
|
-
runningToolCount = Math.max(0, runningToolCount - 1);
|
|
11336
|
-
if (runningToolCount === 0)
|
|
11337
|
-
run.activity = { kind: "waiting" };
|
|
11338
|
-
emitChildUpdate();
|
|
11339
|
-
}
|
|
11340
|
-
else if (event.type === "session_info_changed" || event.type === "recap_update") {
|
|
11341
|
-
emitChildUpdate();
|
|
11342
|
-
}
|
|
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);
|
|
11343
11652
|
});
|
|
11344
11653
|
run.unsubscribe = unsubscribeChildEvents;
|
|
11345
11654
|
const content = `[task from parent]\n\n${prompt}`;
|
|
@@ -11367,8 +11676,19 @@ export class AgentSession {
|
|
|
11367
11676
|
source: "extension",
|
|
11368
11677
|
customMessage: spawnMessage,
|
|
11369
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");
|
|
11370
11689
|
await child.waitForRlmQuiescence();
|
|
11371
11690
|
await usageSettlement;
|
|
11691
|
+
throwIfCancelled();
|
|
11372
11692
|
if (run.error)
|
|
11373
11693
|
throw new Error(run.error);
|
|
11374
11694
|
run.status = "done";
|
|
@@ -12282,39 +12602,13 @@ export class AgentSession {
|
|
|
12282
12602
|
_contextWindowResolver() {
|
|
12283
12603
|
return (provider, modelId) => this._modelRegistry.find(provider, modelId)?.contextWindow;
|
|
12284
12604
|
}
|
|
12285
|
-
_ownUsageMemo;
|
|
12286
12605
|
// Whole-source own spend, identical to the catalog reduction at passivation.
|
|
12287
12606
|
async getOwnUsageSummary() {
|
|
12288
12607
|
if (!this.sessionManager.supportsCapturedHistoryReads()) {
|
|
12289
|
-
const entries =
|
|
12608
|
+
const entries = this.sessionManager.getEntries();
|
|
12290
12609
|
return sessionUsageSummaryFrom(computeOwnAndTotalUsage(entries, entries).ownUsage);
|
|
12291
12610
|
}
|
|
12292
|
-
|
|
12293
|
-
return this.sessionManager.readSourceHistory(async (history) => {
|
|
12294
|
-
const { sessionId, sessionFile, sourceSequence } = history.source;
|
|
12295
|
-
const memo = this._ownUsageMemo;
|
|
12296
|
-
if (memo &&
|
|
12297
|
-
memo.sessionId === sessionId &&
|
|
12298
|
-
memo.sessionFile === sessionFile &&
|
|
12299
|
-
memo.sourceSequence === sourceSequence &&
|
|
12300
|
-
memo.count <= limits.maxEntries &&
|
|
12301
|
-
memo.sourceBytes <= limits.maxSourceBytes) {
|
|
12302
|
-
return memo.usage ? { ...memo.usage } : undefined;
|
|
12303
|
-
}
|
|
12304
|
-
const materialized = await history.materialize(limits);
|
|
12305
|
-
const entries = materialized.entries.map(({ entry }) => entry);
|
|
12306
|
-
applyChildUsageAttributions(entries);
|
|
12307
|
-
const usage = sessionUsageSummaryFrom(computeOwnAndTotalUsage(entries, entries).ownUsage);
|
|
12308
|
-
this._ownUsageMemo = {
|
|
12309
|
-
sessionId,
|
|
12310
|
-
sessionFile,
|
|
12311
|
-
sourceSequence,
|
|
12312
|
-
count: entries.length,
|
|
12313
|
-
sourceBytes: materialized.sourceBytes,
|
|
12314
|
-
usage,
|
|
12315
|
-
};
|
|
12316
|
-
return usage ? { ...usage } : undefined;
|
|
12317
|
-
});
|
|
12611
|
+
return this.sessionManager.readOwnUsageSummary();
|
|
12318
12612
|
}
|
|
12319
12613
|
/**
|
|
12320
12614
|
* Build the agent context overview for /context: this session as the root
|
|
@@ -12384,7 +12678,12 @@ export class AgentSession {
|
|
|
12384
12678
|
? { tokens: estimate.tokens, contextWindow, percent: (estimate.tokens / contextWindow) * 100 }
|
|
12385
12679
|
: { tokens: null, contextWindow, percent: null }
|
|
12386
12680
|
: undefined;
|
|
12387
|
-
const usageMetadata = {
|
|
12681
|
+
const usageMetadata = {
|
|
12682
|
+
ownUsage: usage.ownUsage,
|
|
12683
|
+
totalUsage: usage.totalUsage,
|
|
12684
|
+
...(usage.ownRequestUsage ? { ownRequestUsage: usage.ownRequestUsage } : {}),
|
|
12685
|
+
contextUsage,
|
|
12686
|
+
};
|
|
12388
12687
|
request.retainMetadata({ contextUsage });
|
|
12389
12688
|
return {
|
|
12390
12689
|
...rootNode,
|