@myagentroam/agent 0.9.141 → 0.9.142
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-core/host/contracts.d.ts +64 -0
- package/dist/{host → agent-core/host}/local-agent-host.d.ts +6 -5
- package/dist/{host → agent-core/host}/local-agent-host.js +4 -4
- package/dist/{model → agent-core/model}/contracts.d.ts +2 -16
- package/dist/agent-core/model/recovery.d.ts +4 -0
- package/dist/agent-core/model/recovery.js +71 -0
- package/dist/{prompts → agent-core/prompts}/core.d.ts +3 -13
- package/dist/{prompts → agent-core/prompts}/index.d.ts +1 -1
- package/dist/{prompts → agent-core/prompts}/modes.d.ts +1 -1
- package/dist/{prompts → agent-core/prompts}/resources.d.ts +1 -1
- package/dist/{runtime/compact.d.ts → agent-core/runtime/compaction/history.d.ts} +2 -23
- package/dist/{runtime/compact.js → agent-core/runtime/compaction/history.js} +2 -92
- package/dist/agent-core/runtime/compaction/operation.d.ts +22 -0
- package/dist/agent-core/runtime/compaction/operation.js +91 -0
- package/dist/agent-core/runtime/context/contracts.d.ts +12 -0
- package/dist/{runtime/environment-context.d.ts → agent-core/runtime/context/environment.d.ts} +2 -2
- package/dist/{runtime/environment-context.js → agent-core/runtime/context/environment.js} +1 -1
- package/dist/{runtime/context-gc-runtime.d.ts → agent-core/runtime/context/gc-runtime.d.ts} +4 -4
- package/dist/{runtime/context-gc-runtime.js → agent-core/runtime/context/gc-runtime.js} +3 -3
- package/dist/{runtime/context-gc-tokens.d.ts → agent-core/runtime/context/gc-tokens.d.ts} +2 -2
- package/dist/{runtime/context-gc-tokens.js → agent-core/runtime/context/gc-tokens.js} +3 -3
- package/dist/{runtime/context-gc.d.ts → agent-core/runtime/context/gc.d.ts} +3 -3
- package/dist/{runtime/context-gc.js → agent-core/runtime/context/gc.js} +6 -6
- package/dist/{runtime → agent-core/runtime/context}/instructions.d.ts +1 -1
- package/dist/{runtime → agent-core/runtime/context}/instructions.js +1 -1
- package/dist/{runtime → agent-core/runtime/context}/normalize.d.ts +1 -1
- package/dist/{runtime/context-projection.d.ts → agent-core/runtime/context/projection.d.ts} +3 -3
- package/dist/{runtime/context-projection.js → agent-core/runtime/context/projection.js} +4 -4
- package/dist/agent-core/runtime/context/request-budget.d.ts +6 -0
- package/dist/agent-core/runtime/context/request-budget.js +22 -0
- package/dist/agent-core/runtime/context/restore.d.ts +15 -0
- package/dist/agent-core/runtime/context/restore.js +85 -0
- package/dist/agent-core/runtime/context/usage.d.ts +18 -0
- package/dist/agent-core/runtime/context/usage.js +138 -0
- package/dist/agent-core/runtime/context/world-state.d.ts +35 -0
- package/dist/agent-core/runtime/context/world-state.js +133 -0
- package/dist/agent-core/runtime/contracts.d.ts +37 -0
- package/dist/agent-core/runtime/event-projection.d.ts +5 -0
- package/dist/agent-core/runtime/event-projection.js +17 -0
- package/dist/agent-core/runtime/events.d.ts +142 -0
- package/dist/agent-core/runtime/execution.d.ts +50 -0
- package/dist/agent-core/runtime/execution.js +393 -0
- package/dist/{runtime → agent-core/runtime}/rollout-budget.d.ts +1 -1
- package/dist/agent-core/sdk/agent.js +209 -0
- package/dist/agent-core/sdk/model-runtime.d.ts +13 -0
- package/dist/agent-core/sdk/model-runtime.js +63 -0
- package/dist/agent-core/sdk/session-title.d.ts +3 -0
- package/dist/agent-core/sdk/session-title.js +42 -0
- package/dist/agent-core/sdk/session.d.ts +62 -0
- package/dist/agent-core/sdk/session.js +1147 -0
- package/dist/agent-core/sdk/subagent-backend.d.ts +3 -0
- package/dist/agent-core/sdk/subagent-backend.js +46 -0
- package/dist/agent-core/sdk/types.d.ts +56 -0
- package/dist/{session → agent-core/session}/catalog.d.ts +2 -1
- package/dist/{session → agent-core/session}/context-gc-checkpoint.js +1 -1
- package/dist/{session → agent-core/session}/jsonl-store.d.ts +2 -2
- package/dist/{session → agent-core/session}/jsonl-store.js +1 -1
- package/dist/agent-core/subagent/contracts.d.ts +91 -0
- package/dist/agent-core/subagent/contracts.js +1 -0
- package/dist/agent-core/subagent/scheduler.d.ts +117 -0
- package/dist/{subagent → agent-core/subagent}/session-controller.d.ts +3 -2
- package/dist/agent-core/tools/agent/agent-cancel.d.ts +7 -0
- package/dist/{tools → agent-core/tools/agent}/agent-cancel.js +1 -1
- package/dist/agent-core/tools/agent/agent-message.d.ts +7 -0
- package/dist/{tools → agent-core/tools/agent}/agent-message.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/agent-start.d.ts +3 -3
- package/dist/{tools → agent-core/tools/agent}/agent-start.js +3 -3
- package/dist/agent-core/tools/agent/agent-wait.d.ts +7 -0
- package/dist/{tools → agent-core/tools/agent}/agent-wait.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/question.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/question.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/skill.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/skill.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo-read.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo-write.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo-write.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo.d.ts +2 -9
- package/dist/{tools → agent-core/tools/agent}/todo.js +1 -1
- package/dist/{tools → agent-core/tools}/code-mode/cells.d.ts +1 -1
- package/dist/{tools → agent-core/tools}/code-mode/dispatch.d.ts +2 -4
- package/dist/{tools → agent-core/tools}/code-mode/dispatch.js +5 -4
- package/dist/{tools → agent-core/tools}/code-mode/engine.d.ts +1 -1
- package/dist/agent-core/tools/code-mode/engine.js +1 -0
- package/dist/{tools/code-mode.d.ts → agent-core/tools/code-mode/index.d.ts} +7 -7
- package/dist/{tools/code-mode.js → agent-core/tools/code-mode/index.js} +14 -15
- package/dist/{tools → agent-core/tools}/code-mode/state.d.ts +2 -13
- package/dist/agent-core/tools/code-mode/worker.d.ts +1 -0
- package/dist/agent-core/tools/contracts.d.ts +168 -0
- package/dist/agent-core/tools/contracts.js +1 -0
- package/dist/agent-core/tools/execution.d.ts +34 -0
- package/dist/agent-core/tools/execution.js +102 -0
- package/dist/agent-core/tools/local/apply-patch.d.ts +19 -0
- package/dist/{tools → agent-core/tools/local}/apply-patch.js +8 -2
- package/dist/{tools → agent-core/tools/local}/exec.d.ts +5 -17
- package/dist/{tools → agent-core/tools/local}/exec.js +4 -4
- package/dist/{tools → agent-core/tools/local}/read.d.ts +7 -15
- package/dist/{tools → agent-core/tools/local}/read.js +185 -2
- package/dist/{tools/local-registry.d.ts → agent-core/tools/local/registry.d.ts} +5 -5
- package/dist/agent-core/tools/local/registry.js +101 -0
- package/dist/{tools → agent-core/tools/local}/view-image.d.ts +4 -9
- package/dist/{tools → agent-core/tools/local}/view-image.js +2 -2
- package/dist/agent-core/tools/local/web-fetch.d.ts +4 -0
- package/dist/agent-core/tools/local/web-fetch.js +85 -0
- package/dist/agent-core/tools/local/web-search.d.ts +7 -0
- package/dist/agent-core/tools/local/web-search.js +34 -0
- package/dist/{tools/local-workspace-tools.js → agent-core/tools/local/workspace-tools.js} +1 -1
- package/dist/{sdk/mcp-catalog.d.ts → agent-core/tools/mcp/catalog.d.ts} +1 -2
- package/dist/{sdk/mcp-catalog.js → agent-core/tools/mcp/catalog.js} +1 -1
- package/dist/agent-core/tools/mcp/history.d.ts +4 -0
- package/dist/agent-core/tools/mcp/history.js +33 -0
- package/dist/{tools → agent-core/tools/mcp}/tool-search.d.ts +3 -3
- package/dist/{tools → agent-core/tools/mcp}/tool-search.js +4 -4
- package/dist/agent-core/tools/output-projection.d.ts +14 -0
- package/dist/agent-core/tools/output-projection.js +189 -0
- package/dist/{tools → agent-core/tools}/registry.d.ts +1 -1
- package/dist/agent-core/tools/registry.js +47 -0
- package/dist/{tools → agent-core/tools}/runtime-context.d.ts +8 -7
- package/dist/agent-core/tools/runtime-context.js +1 -0
- package/dist/{tools → agent-core/tools}/runtime.d.ts +1 -1
- package/dist/cli/codex-auth-file.d.ts +1 -1
- package/dist/cli/codex-auth-file.js +2 -2
- package/dist/cli/main.js +9 -9
- package/dist/index.d.ts +17 -15
- package/dist/index.js +8 -8
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.d.ts +1 -1
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +1 -1
- package/package.json +3 -3
- package/dist/host/contracts.d.ts +0 -21
- package/dist/sdk/agent.js +0 -2548
- package/dist/sdk/types.d.ts +0 -349
- package/dist/subagent/scheduler.d.ts +0 -206
- package/dist/tools/agent-cancel.d.ts +0 -7
- package/dist/tools/agent-message.d.ts +0 -7
- package/dist/tools/agent-wait.d.ts +0 -7
- package/dist/tools/apply-patch.d.ts +0 -32
- package/dist/tools/local-registry.js +0 -373
- package/dist/tools/registry.js +0 -47
- package/dist/tools/web-fetch.d.ts +0 -2
- package/dist/tools/web-fetch.js +0 -12
- package/dist/tools/web-search.d.ts +0 -2
- package/dist/tools/web-search.js +0 -15
- package/dist/{error.d.ts → agent-core/error.d.ts} +0 -0
- package/dist/{error.js → agent-core/error.js} +0 -0
- package/dist/{host → agent-core/host}/contracts.js +0 -0
- package/dist/{host → agent-core/host}/local-process-executor.d.ts +0 -0
- package/dist/{host → agent-core/host}/local-process-executor.js +0 -0
- package/dist/{host → agent-core/host}/network.d.ts +0 -0
- package/dist/{host → agent-core/host}/network.js +0 -0
- package/dist/{model → agent-core/model}/anthropic-messages.d.ts +0 -0
- package/dist/{model → agent-core/model}/anthropic-messages.js +0 -0
- package/dist/{model → agent-core/model}/anthropic-thinking.d.ts +0 -0
- package/dist/{model → agent-core/model}/anthropic-thinking.js +0 -0
- package/dist/{model → agent-core/model}/catalog-file.d.ts +0 -0
- package/dist/{model → agent-core/model}/catalog-file.js +0 -0
- package/dist/{model → agent-core/model}/configuration.d.ts +0 -0
- package/dist/{model → agent-core/model}/configuration.js +0 -0
- package/dist/{model → agent-core/model}/contracts.js +0 -0
- package/dist/{model → agent-core/model}/http.d.ts +0 -0
- package/dist/{model → agent-core/model}/http.js +0 -0
- package/dist/{model → agent-core/model}/openai-responses.d.ts +0 -0
- package/dist/{model → agent-core/model}/openai-responses.js +0 -0
- package/dist/{model → agent-core/model}/runtime-credential.d.ts +0 -0
- package/dist/{model → agent-core/model}/runtime-credential.js +0 -0
- package/dist/{model → agent-core/model}/sse.d.ts +0 -0
- package/dist/{model → agent-core/model}/sse.js +0 -0
- package/dist/{model → agent-core/model}/transport-test.d.ts +0 -0
- package/dist/{model → agent-core/model}/transport-test.js +0 -0
- package/dist/{prompts → agent-core/prompts}/compact.d.ts +0 -0
- package/dist/{prompts → agent-core/prompts}/compact.js +0 -0
- package/dist/{prompts → agent-core/prompts}/core.js +0 -0
- package/dist/{prompts → agent-core/prompts}/execution-budget.d.ts +0 -0
- package/dist/{prompts → agent-core/prompts}/execution-budget.js +0 -0
- package/dist/{prompts → agent-core/prompts}/index.js +0 -0
- package/dist/{prompts → agent-core/prompts}/modes.js +0 -0
- package/dist/{prompts → agent-core/prompts}/output.d.ts +0 -0
- package/dist/{prompts → agent-core/prompts}/output.js +0 -0
- package/dist/{prompts → agent-core/prompts}/resources.js +0 -0
- package/dist/{prompts → agent-core/prompts}/subagent.d.ts +0 -0
- package/dist/{prompts → agent-core/prompts}/subagent.js +0 -0
- package/dist/{prompts → agent-core/prompts}/title.d.ts +0 -0
- package/dist/{prompts → agent-core/prompts}/title.js +0 -0
- package/dist/{prompts → agent-core/prompts}/workflow.d.ts +0 -0
- package/dist/{prompts → agent-core/prompts}/workflow.js +0 -0
- package/dist/{runtime → agent-core/runtime}/async-queue.d.ts +0 -0
- package/dist/{runtime → agent-core/runtime}/async-queue.js +0 -0
- package/dist/{sdk/types.js → agent-core/runtime/context/contracts.js} +0 -0
- package/dist/{runtime → agent-core/runtime/context}/normalize.js +0 -0
- package/dist/{session/types.js → agent-core/runtime/contracts.js} +0 -0
- package/dist/{tools/code-mode/engine.js → agent-core/runtime/events.js} +0 -0
- package/dist/{runtime → agent-core/runtime}/execution-policy.d.ts +0 -0
- package/dist/{runtime → agent-core/runtime}/execution-policy.js +0 -0
- package/dist/{runtime → agent-core/runtime}/plan-output.d.ts +0 -0
- package/dist/{runtime → agent-core/runtime}/plan-output.js +0 -0
- package/dist/{runtime → agent-core/runtime}/rollout-budget.js +0 -0
- package/dist/{runtime → agent-core/runtime}/token-budget.d.ts +0 -0
- package/dist/{runtime → agent-core/runtime}/token-budget.js +0 -0
- package/dist/{sdk → agent-core/sdk}/agent.d.ts +0 -0
- package/dist/{tools/code-mode/worker.d.ts → agent-core/sdk/types.js} +0 -0
- package/dist/{session → agent-core/session}/catalog.js +0 -0
- package/dist/{session → agent-core/session}/context-gc-checkpoint.d.ts +0 -0
- package/dist/{session → agent-core/session}/context-gc-replacements.d.ts +0 -0
- package/dist/{session → agent-core/session}/context-gc-replacements.js +0 -0
- package/dist/{session → agent-core/session}/context-gc-subagent.d.ts +0 -0
- package/dist/{session → agent-core/session}/context-gc-subagent.js +0 -0
- package/dist/{session → agent-core/session}/transaction-recovery.d.ts +0 -0
- package/dist/{session → agent-core/session}/transaction-recovery.js +0 -0
- package/dist/{session → agent-core/session}/types.d.ts +0 -0
- package/dist/{tools/runtime-context.js → agent-core/session/types.js} +0 -0
- package/dist/{subagent → agent-core/subagent}/scheduler.js +0 -0
- package/dist/{subagent → agent-core/subagent}/session-controller.js +0 -0
- package/dist/{tools → agent-core/tools/agent}/todo-read.js +0 -0
- package/dist/{tools → agent-core/tools}/callers.d.ts +0 -0
- package/dist/{tools → agent-core/tools}/callers.js +0 -0
- package/dist/{tools → agent-core/tools}/code-mode/cells.js +1 -1
- /package/dist/{tools → agent-core/tools}/code-mode/quickjs-engine.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/quickjs-engine.js +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/state.js +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/text-output.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/text-output.js +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/worker.js +0 -0
- /package/dist/{tools → agent-core/tools}/execution-limits.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/execution-limits.js +0 -0
- /package/dist/{tools → agent-core/tools/local}/read-context.d.ts +0 -0
- /package/dist/{tools → agent-core/tools/local}/read-context.js +0 -0
- /package/dist/{tools/local-workspace-tools.d.ts → agent-core/tools/local/workspace-tools.d.ts} +0 -0
- /package/dist/{tools → agent-core/tools}/runtime.js +0 -0
- /package/dist/{tools → agent-core/tools}/scheduler.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/scheduler.js +0 -0
- /package/dist/{tools → agent-core/tools}/shared/path-resolver.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/shared/path-resolver.js +0 -0
|
@@ -0,0 +1,1147 @@
|
|
|
1
|
+
import { isProviderContextOverflow, recoverModelStream } from '../model/recovery.js';
|
|
2
|
+
import { estimatedRequestTokens } from '../runtime/context/request-budget.js';
|
|
3
|
+
import { restoreMessages } from '../runtime/context/restore.js';
|
|
4
|
+
import { lastConfigurationEffort, latestModelUsage, reasoningEffortBaseline, shouldUseNativeCompaction } from '../runtime/context/usage.js';
|
|
5
|
+
import { compactHistoryMayContainRetainedResources, contextualInstructionInsertIndex, insertContextualWorldState, latestContextualWorldStateGeneration, parsePersistedContextualWorldState, persistContextualWorldState, resetContextualWorldState, updateContextualWorldState } from '../runtime/context/world-state.js';
|
|
6
|
+
import { eventForPersistence, publicModelUsage } from '../runtime/event-projection.js';
|
|
7
|
+
import { ExecutionLoop } from '../runtime/execution.js';
|
|
8
|
+
import { closeModelAdapters, createModelTurnSession } from './model-runtime.js';
|
|
9
|
+
import { generateSessionTitle } from './session-title.js';
|
|
10
|
+
import { createSubagentBackend } from './subagent-backend.js';
|
|
11
|
+
import { discoveredMcpToolNames, rebindMcpToolSearchOutputs } from '../tools/mcp/history.js';
|
|
12
|
+
import { currentExecutionImages } from '../tools/output-projection.js';
|
|
13
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
14
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
15
|
+
import { MarAgentError, describeMarAgentError } from '../error.js';
|
|
16
|
+
import { usesResponsesConfigurationUpdates } from '../model/configuration.js';
|
|
17
|
+
import { buildEnvironmentContext } from '../prompts/core.js';
|
|
18
|
+
import { executionBudgetEnvironmentEntry } from '../prompts/execution-budget.js';
|
|
19
|
+
import { MAR_AGENT_PROMPT_VERSION, buildSystemPrompt } from '../prompts/index.js';
|
|
20
|
+
import { retainedSessionResourcesSnapshot } from '../prompts/resources.js';
|
|
21
|
+
import { childSubagentInstruction } from '../prompts/subagent.js';
|
|
22
|
+
import { AsyncQueue } from '../runtime/async-queue.js';
|
|
23
|
+
import { CompactionOperation } from '../runtime/compaction/operation.js';
|
|
24
|
+
import { DEFAULT_COMPACTION_FOCUS, buildCompactedHistory, buildCompactionInput, buildCompactionMessages, buildNativeCompactionMessages, compactedHistoryMessages } from '../runtime/compaction/history.js';
|
|
25
|
+
import { currentLocalTimeContext, environmentContextUpdate, restoreEnvironmentState } from '../runtime/context/environment.js';
|
|
26
|
+
import { ContextGcRuntime } from '../runtime/context/gc-runtime.js';
|
|
27
|
+
import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
28
|
+
import { loadAgentInstructions, renderAgentInstructions } from '../runtime/context/instructions.js';
|
|
29
|
+
import { normalizeMessagesForModel } from '../runtime/context/normalize.js';
|
|
30
|
+
import { RolloutBudget } from '../runtime/rollout-budget.js';
|
|
31
|
+
import { compactSummaryFromCheckpoint } from '../session/jsonl-store.js';
|
|
32
|
+
import { SubagentSessionController } from '../subagent/session-controller.js';
|
|
33
|
+
import { agentStartToolDefinitionWithModels } from '../tools/agent/agent-start.js';
|
|
34
|
+
import { allowsDirectTool, allowsToolCaller, toolCallers } from '../tools/callers.js';
|
|
35
|
+
import { projectCodeModeSearchResult, projectCodeModeTools } from '../tools/code-mode/index.js';
|
|
36
|
+
import { assertMcpToolCatalog } from '../tools/mcp/catalog.js';
|
|
37
|
+
import { BUILTIN_TOOL_DEFINITIONS } from '../tools/registry.js';
|
|
38
|
+
import { createSessionToolScheduler } from '../tools/scheduler.js';
|
|
39
|
+
import { TodoStore } from '../tools/agent/todo.js';
|
|
40
|
+
import { DeferredMcpRegistry } from '../tools/mcp/tool-search.js';
|
|
41
|
+
/** SDK Session orchestration owns warm resources; Runtime owns only the model/tool loop. */
|
|
42
|
+
export function createSessionOpener(services) {
|
|
43
|
+
const { host, description, settings, store, rolloutBudgetOptions, createAdapter, activeAdaptersExcept } = services;
|
|
44
|
+
const { active, activeExecutionAdapters, executionResults, sessionRuntimes, sessionWriterOwner } = services.registry;
|
|
45
|
+
const openSession = async (sessionId, workspace) => {
|
|
46
|
+
const storedSession = await store.getSession(sessionId);
|
|
47
|
+
const storedWorkspace = storedSession.workspace;
|
|
48
|
+
const sessionSource = storedSession.source;
|
|
49
|
+
const logicalWorkspace = settings.workspaceMapping?.logicalPath ?? workspace ?? storedWorkspace ?? '';
|
|
50
|
+
const instructionWorkspace = settings.workspaceMapping?.physicalPath ?? workspace ?? storedWorkspace ?? '';
|
|
51
|
+
const currentEnvironment = {
|
|
52
|
+
platform: description.platform,
|
|
53
|
+
...(description.architecture ? { architecture: description.architecture } : {}),
|
|
54
|
+
...(description.shell ? { shell: description.shell } : {}),
|
|
55
|
+
...(description.guaranteedCommands
|
|
56
|
+
? { guaranteedCommands: description.guaranteedCommands }
|
|
57
|
+
: {}),
|
|
58
|
+
workspace: logicalWorkspace
|
|
59
|
+
};
|
|
60
|
+
if (!restoreEnvironmentState({ version: 1, state: currentEnvironment }))
|
|
61
|
+
throw new MarAgentError('MAR_AGENT_HOST_INCOMPATIBLE', 'Host environment facts are invalid or exceed the context limit.');
|
|
62
|
+
const environmentContext = buildEnvironmentContext(currentEnvironment);
|
|
63
|
+
let sessionRuntime = sessionRuntimes.get(sessionId);
|
|
64
|
+
if (sessionRuntime === undefined) {
|
|
65
|
+
sessionRuntime = {
|
|
66
|
+
sourceType: sessionSource.type,
|
|
67
|
+
scheduleTool: createSessionToolScheduler(),
|
|
68
|
+
adapterGeneration: services.modelState().generation,
|
|
69
|
+
adapters: new Map()
|
|
70
|
+
};
|
|
71
|
+
sessionRuntimes.set(sessionId, sessionRuntime);
|
|
72
|
+
}
|
|
73
|
+
if (sessionSource.type === 'user' && sessionRuntime.subagents === undefined) {
|
|
74
|
+
sessionRuntime.subagentsOpening ??= SubagentSessionController.open({
|
|
75
|
+
parentSessionId: sessionId,
|
|
76
|
+
rootSessionId: sessionId,
|
|
77
|
+
backend: createSubagentBackend(store, storedWorkspace)
|
|
78
|
+
});
|
|
79
|
+
try {
|
|
80
|
+
sessionRuntime.subagents = await sessionRuntime.subagentsOpening;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
delete sessionRuntime.subagentsOpening;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const sessionAdapter = (modelId, configuredModels) => {
|
|
87
|
+
let selected = sessionRuntime.adapters.get(modelId);
|
|
88
|
+
if (selected === undefined) {
|
|
89
|
+
selected = createAdapter(modelId, configuredModels);
|
|
90
|
+
if (!services.hasCustomAdapters || selected.createTurnSession !== undefined)
|
|
91
|
+
sessionRuntime.adapters.set(modelId, selected);
|
|
92
|
+
}
|
|
93
|
+
return selected;
|
|
94
|
+
};
|
|
95
|
+
const refreshSessionAdapters = async (generation) => {
|
|
96
|
+
if (sessionRuntime.adapterGeneration === generation)
|
|
97
|
+
return;
|
|
98
|
+
const retainedByActiveSessions = activeAdaptersExcept(sessionId);
|
|
99
|
+
await closeModelAdapters([...sessionRuntime.adapters.values()].filter((adapter) => !retainedByActiveSessions.has(adapter)));
|
|
100
|
+
sessionRuntime.adapters.clear();
|
|
101
|
+
sessionRuntime.adapterGeneration = generation;
|
|
102
|
+
};
|
|
103
|
+
const execution = (mode, input, internal = {}) => {
|
|
104
|
+
services.assertCanStart();
|
|
105
|
+
if ([...active.keys()].some((key) => key.startsWith(`${sessionId}:`)))
|
|
106
|
+
throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'Session already has an active execution.');
|
|
107
|
+
const executionId = randomUUID(), turnId = internal.turnId ?? randomUUID(), queue = new AsyncQueue(), controller = new AbortController();
|
|
108
|
+
let executionEnvironment = {
|
|
109
|
+
...currentEnvironment,
|
|
110
|
+
...currentLocalTimeContext()
|
|
111
|
+
};
|
|
112
|
+
const { models: executionModels, defaultModelId: executionDefaultModelId, generation: executionModelGeneration } = services.modelState();
|
|
113
|
+
const manualCompactionId = mode === 'compact' ? randomUUID() : undefined;
|
|
114
|
+
active.set(`${sessionId}:${executionId}`, controller);
|
|
115
|
+
const mailbox = [...(internal.initialMailbox ?? [])];
|
|
116
|
+
let acceptsMailbox = sessionSource.type === 'subagent' && mode !== 'compact';
|
|
117
|
+
let sequence = 0;
|
|
118
|
+
let manualCompactionStarted = false;
|
|
119
|
+
let emitTail = Promise.resolve();
|
|
120
|
+
let exhaustedModelAttempt;
|
|
121
|
+
// Serialize durable events before either the local stream or Host observes them.
|
|
122
|
+
const emit = (event) => {
|
|
123
|
+
const full = {
|
|
124
|
+
...event,
|
|
125
|
+
eventId: randomUUID(),
|
|
126
|
+
sequence: ++sequence,
|
|
127
|
+
timestamp: new Date().toISOString(),
|
|
128
|
+
sessionId,
|
|
129
|
+
executionId,
|
|
130
|
+
turnId
|
|
131
|
+
};
|
|
132
|
+
const operation = emitTail.then(async () => {
|
|
133
|
+
// Transport-only progress events never become recoverable history.
|
|
134
|
+
const persistent = eventForPersistence(full);
|
|
135
|
+
if (persistent !== undefined)
|
|
136
|
+
await store.append(sessionId, {
|
|
137
|
+
type: full.type,
|
|
138
|
+
payload: persistent,
|
|
139
|
+
executionId,
|
|
140
|
+
turnId
|
|
141
|
+
});
|
|
142
|
+
queue.push(full);
|
|
143
|
+
if (internal.publishHostEvents !== false)
|
|
144
|
+
await host.emit(full);
|
|
145
|
+
});
|
|
146
|
+
emitTail = operation.catch(() => undefined);
|
|
147
|
+
return operation;
|
|
148
|
+
};
|
|
149
|
+
const recordModelAttempt = (purpose) => (diagnostic) => {
|
|
150
|
+
if (purpose === 'EXECUTION' || purpose === 'COMPACTION') {
|
|
151
|
+
if ((diagnostic.state === 'STARTED' && diagnostic.attempt === 1) ||
|
|
152
|
+
diagnostic.state === 'SUCCEEDED')
|
|
153
|
+
exhaustedModelAttempt = undefined;
|
|
154
|
+
else if (diagnostic.state === 'FAILED' &&
|
|
155
|
+
diagnostic.willRetry === false &&
|
|
156
|
+
diagnostic.attempt > 1)
|
|
157
|
+
exhaustedModelAttempt = {
|
|
158
|
+
attempts: diagnostic.attempt,
|
|
159
|
+
retries: diagnostic.attempt - 1
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const operation = emitTail.then(async () => {
|
|
163
|
+
await store.append(sessionId, {
|
|
164
|
+
type: 'model.attempt',
|
|
165
|
+
payload: { purpose, ...diagnostic },
|
|
166
|
+
executionId,
|
|
167
|
+
turnId
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
emitTail = operation.catch(() => undefined);
|
|
171
|
+
return operation;
|
|
172
|
+
};
|
|
173
|
+
const createCompactionOperation = (compactionId) => new CompactionOperation(controller.signal, (progress) => {
|
|
174
|
+
const operation = emitTail.then(async () => {
|
|
175
|
+
await store.append(sessionId, {
|
|
176
|
+
type: 'compact.progress',
|
|
177
|
+
payload: { compactionId, ...progress },
|
|
178
|
+
executionId,
|
|
179
|
+
turnId
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
emitTail = operation.catch(() => undefined);
|
|
183
|
+
return operation;
|
|
184
|
+
});
|
|
185
|
+
const result = (async () => {
|
|
186
|
+
let finalAnswer = '';
|
|
187
|
+
let executionLoop;
|
|
188
|
+
let manualCompaction;
|
|
189
|
+
const rolloutBudget = internal.sharedRolloutBudget ??
|
|
190
|
+
(rolloutBudgetOptions ? new RolloutBudget(rolloutBudgetOptions) : undefined);
|
|
191
|
+
const ownsRolloutBudget = rolloutBudget !== undefined && internal.sharedRolloutBudget === undefined;
|
|
192
|
+
let releaseSession;
|
|
193
|
+
let selectedTurn;
|
|
194
|
+
const contextGc = new ContextGcRuntime();
|
|
195
|
+
let selectedAdapter;
|
|
196
|
+
let titleAdapter;
|
|
197
|
+
const executionScopedAdapters = new Set();
|
|
198
|
+
let titleTask;
|
|
199
|
+
let titleSettled = false;
|
|
200
|
+
const settleTitle = async () => {
|
|
201
|
+
if (titleSettled)
|
|
202
|
+
return;
|
|
203
|
+
titleSettled = true;
|
|
204
|
+
const generatedTitle = await titleTask;
|
|
205
|
+
if (generatedTitle)
|
|
206
|
+
await store
|
|
207
|
+
.updateTitle(sessionId, generatedTitle, { executionId, turnId })
|
|
208
|
+
.catch(() => undefined);
|
|
209
|
+
};
|
|
210
|
+
const subagents = sessionSource.type === 'user' ? sessionRuntime.subagents : undefined;
|
|
211
|
+
try {
|
|
212
|
+
releaseSession = await store.acquireSessionLease(sessionId, sessionWriterOwner);
|
|
213
|
+
await refreshSessionAdapters(executionModelGeneration);
|
|
214
|
+
const sessionState = await store.readExecutionState(sessionId);
|
|
215
|
+
if (!store.hasRetainedSessionLease(sessionId, sessionWriterOwner))
|
|
216
|
+
sessionRuntime.todo = TodoStore.restore(sessionState.todo);
|
|
217
|
+
const todo = (sessionRuntime.todo ??= TodoStore.restore(sessionState.todo));
|
|
218
|
+
const contextRecords = sessionState.contextRecords;
|
|
219
|
+
const contextualWorldStateGeneration = latestContextualWorldStateGeneration(contextRecords);
|
|
220
|
+
const restoredContextualWorldState = sessionRuntime.contextualWorldState;
|
|
221
|
+
const persistedContextualWorldState = parsePersistedContextualWorldState(await store.readContextualWorldState(sessionId));
|
|
222
|
+
let contextualWorldState;
|
|
223
|
+
if (restoredContextualWorldState !== undefined &&
|
|
224
|
+
restoredContextualWorldState.generation === contextualWorldStateGeneration)
|
|
225
|
+
contextualWorldState = restoredContextualWorldState;
|
|
226
|
+
else if (persistedContextualWorldState !== undefined &&
|
|
227
|
+
persistedContextualWorldState.generation === contextualWorldStateGeneration) {
|
|
228
|
+
contextualWorldState = persistedContextualWorldState;
|
|
229
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
contextualWorldState = {
|
|
233
|
+
generation: contextualWorldStateGeneration,
|
|
234
|
+
initialized: false,
|
|
235
|
+
instructionSnapshot: undefined,
|
|
236
|
+
resourceSnapshot: undefined,
|
|
237
|
+
entries: []
|
|
238
|
+
};
|
|
239
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
240
|
+
}
|
|
241
|
+
const compactMayContainAgentInstructions = contextRecords.some((record) => compactSummaryFromCheckpoint(record) !== undefined);
|
|
242
|
+
const compactMayContainRetainedResources = compactHistoryMayContainRetainedResources(contextRecords);
|
|
243
|
+
const restored = await restoreMessages(store, sessionId, contextRecords, {
|
|
244
|
+
includeImages: mode !== 'compact'
|
|
245
|
+
});
|
|
246
|
+
const messages = restored.messages;
|
|
247
|
+
let recordedEnvironment = restored.environmentState;
|
|
248
|
+
let projectedExecutionBudgetStage;
|
|
249
|
+
const appendExecutionBudgetEnvironment = () => {
|
|
250
|
+
const currentStage = rolloutBudget?.active ? rolloutBudget.stage : 'inactive';
|
|
251
|
+
if (currentStage === projectedExecutionBudgetStage)
|
|
252
|
+
return;
|
|
253
|
+
const previousStage = projectedExecutionBudgetStage;
|
|
254
|
+
projectedExecutionBudgetStage = currentStage;
|
|
255
|
+
if ((previousStage === undefined &&
|
|
256
|
+
(currentStage === 'normal' || currentStage === 'inactive')) ||
|
|
257
|
+
(currentStage === 'inactive' && previousStage === 'normal'))
|
|
258
|
+
return;
|
|
259
|
+
const entry = executionBudgetEnvironmentEntry(currentStage === 'normal' ? 'inactive' : currentStage);
|
|
260
|
+
messages.push(environmentContextUpdate(executionEnvironment, executionEnvironment, [entry]));
|
|
261
|
+
};
|
|
262
|
+
const appendMailboxMessages = async () => {
|
|
263
|
+
let appended = false;
|
|
264
|
+
while (mailbox.length > 0) {
|
|
265
|
+
const pending = mailbox.splice(0);
|
|
266
|
+
for (const { text: prompt, delivery } of pending) {
|
|
267
|
+
await store.append(sessionId, {
|
|
268
|
+
type: 'turn.user',
|
|
269
|
+
payload: {
|
|
270
|
+
prompt,
|
|
271
|
+
inputSource: 'parent_agent',
|
|
272
|
+
...(delivery ? { messageId: delivery.messageId } : {})
|
|
273
|
+
},
|
|
274
|
+
executionId,
|
|
275
|
+
turnId
|
|
276
|
+
});
|
|
277
|
+
messages.push({ role: 'user', content: prompt });
|
|
278
|
+
delivery?.applied();
|
|
279
|
+
appended = true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return appended;
|
|
283
|
+
};
|
|
284
|
+
const recordEnvironment = async () => {
|
|
285
|
+
const message = environmentContextUpdate(executionEnvironment, recordedEnvironment);
|
|
286
|
+
if (!message)
|
|
287
|
+
return;
|
|
288
|
+
await store.append(sessionId, {
|
|
289
|
+
type: 'context.environment',
|
|
290
|
+
payload: { version: 1, state: executionEnvironment },
|
|
291
|
+
executionId,
|
|
292
|
+
turnId
|
|
293
|
+
});
|
|
294
|
+
messages.push(message);
|
|
295
|
+
recordedEnvironment = executionEnvironment;
|
|
296
|
+
};
|
|
297
|
+
let compactionUserMessages = [
|
|
298
|
+
...restored.userMessages,
|
|
299
|
+
...(mode === 'compact' ? [] : [input.prompt])
|
|
300
|
+
];
|
|
301
|
+
const hasRestoredUserImages = messages.some((message) => message.role === 'user' && Boolean(message.images?.length));
|
|
302
|
+
const modelInputImages = mode === 'compact'
|
|
303
|
+
? undefined
|
|
304
|
+
: input.images?.map(({ mimeType, dataBase64 }) => ({
|
|
305
|
+
mimeType,
|
|
306
|
+
dataBase64
|
|
307
|
+
}));
|
|
308
|
+
const currentExecutionToolImages = [];
|
|
309
|
+
let currentExecutionUserIndex;
|
|
310
|
+
if (mode !== 'compact') {
|
|
311
|
+
await recordEnvironment();
|
|
312
|
+
const inputImageMetadata = input.images?.length
|
|
313
|
+
? await store.persistInputImages(sessionId, input.images)
|
|
314
|
+
: [];
|
|
315
|
+
// A failed sync can still leave a complete record; lease recovery decides image ownership.
|
|
316
|
+
await store.append(sessionId, {
|
|
317
|
+
type: 'turn.user',
|
|
318
|
+
payload: {
|
|
319
|
+
prompt: input.prompt,
|
|
320
|
+
...(internal.delivery ? { messageId: internal.delivery.messageId } : {}),
|
|
321
|
+
...(internal.inputSource === undefined
|
|
322
|
+
? {}
|
|
323
|
+
: { inputSource: internal.inputSource }),
|
|
324
|
+
...(input.clientMessageId ? { clientMessageId: input.clientMessageId } : {}),
|
|
325
|
+
...(inputImageMetadata.length ? { images: inputImageMetadata } : {})
|
|
326
|
+
},
|
|
327
|
+
executionId,
|
|
328
|
+
turnId
|
|
329
|
+
});
|
|
330
|
+
messages.push({ role: 'user', content: input.prompt });
|
|
331
|
+
currentExecutionUserIndex = messages.length - 1;
|
|
332
|
+
internal.delivery?.applied();
|
|
333
|
+
await appendMailboxMessages();
|
|
334
|
+
if (sessionState.automaticTitlePending) {
|
|
335
|
+
const titleModel = [...executionModels.values()].find((model) => model.titleGeneration) ??
|
|
336
|
+
executionModels.get(input.modelId ?? executionDefaultModelId);
|
|
337
|
+
titleAdapter = createAdapter(titleModel.id, executionModels);
|
|
338
|
+
activeExecutionAdapters.add(titleAdapter);
|
|
339
|
+
titleTask = generateSessionTitle(titleAdapter, input.prompt, titleModel.defaultReasoningEffort, controller.signal, recordModelAttempt('TITLE')).catch(() => undefined);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
await emit({ type: 'execution.started', mode });
|
|
343
|
+
if (restored.ignoredImages > 0)
|
|
344
|
+
await store.append(sessionId, {
|
|
345
|
+
type: 'context.warning',
|
|
346
|
+
payload: {
|
|
347
|
+
code: 'MAR_AGENT_INPUT_IMAGE_IGNORED',
|
|
348
|
+
message: 'One or more corrupt historical input images were ignored.',
|
|
349
|
+
ignoredImages: restored.ignoredImages
|
|
350
|
+
},
|
|
351
|
+
executionId,
|
|
352
|
+
turnId
|
|
353
|
+
});
|
|
354
|
+
selectedAdapter = sessionAdapter(input.modelId ?? executionDefaultModelId, executionModels);
|
|
355
|
+
const selectedModel = executionModels.get(input.modelId ?? executionDefaultModelId);
|
|
356
|
+
if (services.hasCustomAdapters && selectedAdapter.createTurnSession === undefined) {
|
|
357
|
+
executionScopedAdapters.add(selectedAdapter);
|
|
358
|
+
activeExecutionAdapters.add(selectedAdapter);
|
|
359
|
+
}
|
|
360
|
+
const selected = createModelTurnSession(selectedAdapter);
|
|
361
|
+
selectedTurn = selected;
|
|
362
|
+
let lastServerUsage = latestModelUsage(contextRecords, selectedModel.id);
|
|
363
|
+
const compactUserTokenLimit = Math.min(20_000, Math.floor(selectedModel.contextWindowTokens / 8));
|
|
364
|
+
const reasoningEffort = input.reasoningEffort ?? selectedModel.defaultReasoningEffort;
|
|
365
|
+
const useEffortUpdates = usesResponsesConfigurationUpdates(selectedModel);
|
|
366
|
+
const previousReasoningEffort = useEffortUpdates
|
|
367
|
+
? reasoningEffortBaseline(contextRecords, selectedModel.id)
|
|
368
|
+
: undefined;
|
|
369
|
+
let requestReasoningEffort = useEffortUpdates
|
|
370
|
+
? (previousReasoningEffort ?? reasoningEffort)
|
|
371
|
+
: undefined;
|
|
372
|
+
let effectiveReasoningEffort = useEffortUpdates
|
|
373
|
+
? previousReasoningEffort === undefined
|
|
374
|
+
? requestReasoningEffort
|
|
375
|
+
: (lastConfigurationEffort(messages, selectedModel.id) ?? requestReasoningEffort)
|
|
376
|
+
: undefined;
|
|
377
|
+
if (mode !== 'compact' &&
|
|
378
|
+
useEffortUpdates &&
|
|
379
|
+
effectiveReasoningEffort !== reasoningEffort) {
|
|
380
|
+
const update = {
|
|
381
|
+
role: 'provider',
|
|
382
|
+
content: '',
|
|
383
|
+
provider: 'OPENAI_RESPONSES',
|
|
384
|
+
providerModelId: selectedModel.id,
|
|
385
|
+
item: { type: 'configuration_update', reasoning: { effort: reasoningEffort } }
|
|
386
|
+
};
|
|
387
|
+
messages.push(update);
|
|
388
|
+
await store.append(sessionId, {
|
|
389
|
+
type: 'model.context',
|
|
390
|
+
payload: update,
|
|
391
|
+
executionId,
|
|
392
|
+
turnId
|
|
393
|
+
});
|
|
394
|
+
effectiveReasoningEffort = reasoningEffort;
|
|
395
|
+
}
|
|
396
|
+
if (mode !== 'compact' && subagents)
|
|
397
|
+
await subagents.beginParentExecution({
|
|
398
|
+
executionId,
|
|
399
|
+
modelId: selectedModel.id,
|
|
400
|
+
reasoningEffort,
|
|
401
|
+
models: executionModels,
|
|
402
|
+
emitTerminal: async (task) => emit({
|
|
403
|
+
type: 'subagent.completed',
|
|
404
|
+
agentId: task.agentId,
|
|
405
|
+
description: task.description,
|
|
406
|
+
status: task.status,
|
|
407
|
+
...(task.modelId === undefined ? {} : { modelId: task.modelId }),
|
|
408
|
+
...(task.modelName === undefined ? {} : { modelName: task.modelName }),
|
|
409
|
+
...(task.reasoningEffort === undefined
|
|
410
|
+
? {}
|
|
411
|
+
: { reasoningEffort: task.reasoningEffort }),
|
|
412
|
+
...(task.latestMessage === undefined
|
|
413
|
+
? {}
|
|
414
|
+
: { latestMessage: task.latestMessage }),
|
|
415
|
+
...(task.latestActivity === undefined
|
|
416
|
+
? {}
|
|
417
|
+
: { latestActivity: task.latestActivity }),
|
|
418
|
+
...(task.errorCode === undefined ? {} : { errorCode: task.errorCode }),
|
|
419
|
+
...(task.errorMessage === undefined ? {} : { errorMessage: task.errorMessage })
|
|
420
|
+
}),
|
|
421
|
+
startTurn: async (turn) => {
|
|
422
|
+
const child = await openSession(turn.sessionId);
|
|
423
|
+
return child.startSubagentTurn({
|
|
424
|
+
prompt: turn.prompt,
|
|
425
|
+
modelId: turn.modelId,
|
|
426
|
+
reasoningEffort: turn.reasoningEffort,
|
|
427
|
+
role: turn.role,
|
|
428
|
+
initialMailbox: turn.initialMailbox,
|
|
429
|
+
turnId: turn.turnId,
|
|
430
|
+
mcpExecutionScopeId: executionId,
|
|
431
|
+
...(turn.delivery ? { delivery: turn.delivery } : {}),
|
|
432
|
+
...(rolloutBudget === undefined ? {} : { sharedRolloutBudget: rolloutBudget })
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
if (mode !== 'compact' &&
|
|
437
|
+
(input.images?.length || hasRestoredUserImages) &&
|
|
438
|
+
!selectedModel.inputCapabilities.includes('IMAGE'))
|
|
439
|
+
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'Selected model does not support image input.');
|
|
440
|
+
const catalogContext = {
|
|
441
|
+
sessionId,
|
|
442
|
+
executionId,
|
|
443
|
+
...(sessionSource.type === 'subagent'
|
|
444
|
+
? internal.mcpExecutionScopeId === undefined
|
|
445
|
+
? {}
|
|
446
|
+
: { executionScopeId: internal.mcpExecutionScopeId }
|
|
447
|
+
: { claimExecutionScope: true })
|
|
448
|
+
};
|
|
449
|
+
const readMcpCatalog = async () => {
|
|
450
|
+
if (host.listMcpToolCatalog) {
|
|
451
|
+
const catalog = await host.listMcpToolCatalog(catalogContext);
|
|
452
|
+
assertMcpToolCatalog(catalog);
|
|
453
|
+
return catalog;
|
|
454
|
+
}
|
|
455
|
+
const definitions = (await host.listMcpTools?.(catalogContext)) ?? [];
|
|
456
|
+
return {
|
|
457
|
+
revision: createHash('sha256').update(JSON.stringify(definitions)).digest('hex'),
|
|
458
|
+
servers: [{ id: 'legacy', name: 'External MCP' }],
|
|
459
|
+
tools: definitions.map((definition) => ({
|
|
460
|
+
definition,
|
|
461
|
+
serverId: 'legacy',
|
|
462
|
+
rawName: definition.name,
|
|
463
|
+
sourceIdentity: `legacy:${executionId}`,
|
|
464
|
+
definitionRevision: createHash('sha256')
|
|
465
|
+
.update(JSON.stringify(definition))
|
|
466
|
+
.digest('hex'),
|
|
467
|
+
lifetime: 'execution',
|
|
468
|
+
exposure: 'deferred'
|
|
469
|
+
}))
|
|
470
|
+
};
|
|
471
|
+
};
|
|
472
|
+
const mcpCatalog = await readMcpCatalog();
|
|
473
|
+
const mcpRegistry = new DeferredMcpRegistry(discoveredMcpToolNames(messages));
|
|
474
|
+
const mcpTools = mcpCatalog.tools.map((tool) => tool.definition);
|
|
475
|
+
const extensions = (await host.listExecutionExtensions?.(catalogContext)) ?? {};
|
|
476
|
+
if (extensions.tools?.some((tool) => tool.name.startsWith('mcp__')))
|
|
477
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Host tools cannot use the MCP namespace.');
|
|
478
|
+
const selectedModelForTools = executionModels.get(input.modelId ?? executionDefaultModelId);
|
|
479
|
+
const builtinTools = BUILTIN_TOOL_DEFINITIONS.map((tool) => tool.name === 'agent_start'
|
|
480
|
+
? agentStartToolDefinitionWithModels([...executionModels.values()].map((configuration) => ({
|
|
481
|
+
id: configuration.id,
|
|
482
|
+
name: configuration.name,
|
|
483
|
+
reasoningEfforts: configuration.reasoningEfforts
|
|
484
|
+
})))
|
|
485
|
+
: tool);
|
|
486
|
+
const combinedTools = [...builtinTools, ...(extensions.tools ?? []), ...mcpTools];
|
|
487
|
+
if (new Set(combinedTools.map((tool) => tool.name)).size !== combinedTools.length)
|
|
488
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Tool names conflict.');
|
|
489
|
+
const toolEligible = (tool) => {
|
|
490
|
+
toolCallers(tool);
|
|
491
|
+
if (sessionSource.type === 'subagent' && tool.agentScope === 'ROOT_ONLY')
|
|
492
|
+
return false;
|
|
493
|
+
if (sessionSource.type === 'subagent' &&
|
|
494
|
+
(tool.name.startsWith('agent_') || tool.name === 'question'))
|
|
495
|
+
return false;
|
|
496
|
+
if (tool.name === 'tool_search')
|
|
497
|
+
return mcpRegistry.hasDeferred;
|
|
498
|
+
return tool.name === 'code_exec' || tool.name === 'code_exec_wait'
|
|
499
|
+
? selectedModelForTools.codeMode && description.capabilities.includes('code.execute')
|
|
500
|
+
: tool.name === 'question'
|
|
501
|
+
? mode === 'plan'
|
|
502
|
+
: tool.name === 'web_search'
|
|
503
|
+
? !selectedModelForTools.hostedWebSearch &&
|
|
504
|
+
description.capabilities.includes('web.search')
|
|
505
|
+
: tool.name === 'view_image'
|
|
506
|
+
? selectedModelForTools.inputCapabilities.includes('IMAGE')
|
|
507
|
+
: tool.name !== 'web_fetch' || description.capabilities.includes('web.fetch');
|
|
508
|
+
};
|
|
509
|
+
mcpRegistry.update(mcpCatalog, (tool) => toolEligible(tool.definition));
|
|
510
|
+
rebindMcpToolSearchOutputs(messages, mcpRegistry);
|
|
511
|
+
const availableTools = combinedTools.filter(toolEligible);
|
|
512
|
+
const instructionContext = await loadAgentInstructions({
|
|
513
|
+
home: description.homeDirectory,
|
|
514
|
+
workspace: instructionWorkspace,
|
|
515
|
+
availableTools: new Set(availableTools.map((tool) => tool.name)),
|
|
516
|
+
hostSkills: extensions.skills ?? [],
|
|
517
|
+
...(settings.workspaceMapping === undefined
|
|
518
|
+
? {}
|
|
519
|
+
: { workspaceDisplayPath: logicalWorkspace })
|
|
520
|
+
});
|
|
521
|
+
const instructionEntries = instructionContext?.entries ?? [];
|
|
522
|
+
const currentInstructionSnapshot = renderAgentInstructions(instructionEntries, false);
|
|
523
|
+
let agentInstructionInsertIndex = mode === 'compact'
|
|
524
|
+
? contextualInstructionInsertIndex(messages)
|
|
525
|
+
: (currentExecutionUserIndex ?? Math.max(0, messages.length - 1));
|
|
526
|
+
if (mode !== 'compact' &&
|
|
527
|
+
agentInstructionInsertIndex &&
|
|
528
|
+
messages[agentInstructionInsertIndex - 1]?.contextKind === 'environment')
|
|
529
|
+
agentInstructionInsertIndex--;
|
|
530
|
+
const baseTools = () => [...builtinTools, ...(extensions.tools ?? [])].filter((tool) => toolEligible(tool) &&
|
|
531
|
+
(tool.name !== 'skill' || (instructionContext?.skills.size ?? 0) > 0));
|
|
532
|
+
let executionTools = mcpRegistry.project(baseTools());
|
|
533
|
+
const restoreMcpDiscovery = () => {
|
|
534
|
+
mcpRegistry.restore(discoveredMcpToolNames(messages));
|
|
535
|
+
rebindMcpToolSearchOutputs(messages, mcpRegistry);
|
|
536
|
+
executionTools = mcpRegistry.project(baseTools());
|
|
537
|
+
};
|
|
538
|
+
const loadRetainedSessionResources = async () => {
|
|
539
|
+
const hostResources = (await host.listSessionResources?.(sessionId)) ?? {
|
|
540
|
+
processes: []
|
|
541
|
+
};
|
|
542
|
+
return {
|
|
543
|
+
...(hostResources.idleTtlMs === undefined
|
|
544
|
+
? {}
|
|
545
|
+
: { idleTtlMs: hostResources.idleTtlMs }),
|
|
546
|
+
processes: hostResources.processes,
|
|
547
|
+
...(hostResources.codeCells ? { codeCells: hostResources.codeCells } : {}),
|
|
548
|
+
subagents: subagents?.listSessionResources() ?? []
|
|
549
|
+
};
|
|
550
|
+
};
|
|
551
|
+
let currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
552
|
+
const previousContextualWorldState = contextualWorldState;
|
|
553
|
+
contextualWorldState = updateContextualWorldState(contextualWorldState, agentInstructionInsertIndex, {
|
|
554
|
+
instructionSnapshot: currentInstructionSnapshot,
|
|
555
|
+
instructionContent: renderAgentInstructions(instructionEntries, compactMayContainAgentInstructions ||
|
|
556
|
+
contextualWorldState.instructionSnapshot !== undefined),
|
|
557
|
+
resourceSnapshot: currentResourceSnapshot,
|
|
558
|
+
previousMayContainResources: (!contextualWorldState.initialized && compactMayContainRetainedResources) ||
|
|
559
|
+
(host.listSessionResources !== undefined &&
|
|
560
|
+
currentResourceSnapshot === undefined &&
|
|
561
|
+
messages
|
|
562
|
+
.slice(contextualWorldState.entries.findLast((entry) => entry.kind === 'resources')
|
|
563
|
+
?.index ?? 0)
|
|
564
|
+
.some((message) => message.role === 'tool_call' &&
|
|
565
|
+
['exec', 'code_exec', 'code_mode', 'agent_start'].includes(message.name ?? '')))
|
|
566
|
+
});
|
|
567
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
568
|
+
if (!isDeepStrictEqual(previousContextualWorldState, contextualWorldState))
|
|
569
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
570
|
+
const buildExecutionSystemPrompt = (availableTools = executionTools, promptMode = mode) => buildSystemPrompt({
|
|
571
|
+
mode: promptMode,
|
|
572
|
+
platform: description.platform,
|
|
573
|
+
...(description.architecture ? { architecture: description.architecture } : {}),
|
|
574
|
+
...(description.shell ? { shell: description.shell } : {}),
|
|
575
|
+
...(description.guaranteedCommands
|
|
576
|
+
? { guaranteedCommands: description.guaranteedCommands }
|
|
577
|
+
: {}),
|
|
578
|
+
workspace: logicalWorkspace,
|
|
579
|
+
tools: availableTools
|
|
580
|
+
.filter((tool) => !tool.name.startsWith('mcp__'))
|
|
581
|
+
.map((tool) => tool.name),
|
|
582
|
+
directTools: availableTools
|
|
583
|
+
.filter((tool) => !tool.name.startsWith('mcp__') &&
|
|
584
|
+
allowsDirectTool(tool, availableTools.some((candidate) => candidate.name === 'code_exec')))
|
|
585
|
+
.map((tool) => tool.name),
|
|
586
|
+
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
587
|
+
extension: [
|
|
588
|
+
settings.systemInstruction,
|
|
589
|
+
instructionContext?.skillCatalog,
|
|
590
|
+
sessionSource.type === 'subagent' ? childSubagentInstruction : undefined
|
|
591
|
+
]
|
|
592
|
+
.filter(Boolean)
|
|
593
|
+
.join('\n\n')
|
|
594
|
+
});
|
|
595
|
+
const syncMcpWorldState = async (index) => {
|
|
596
|
+
const snapshot = mcpRegistry.navigation();
|
|
597
|
+
if (contextualWorldState.mcpSnapshot === snapshot)
|
|
598
|
+
return;
|
|
599
|
+
contextualWorldState = {
|
|
600
|
+
...contextualWorldState,
|
|
601
|
+
mcpSnapshot: snapshot,
|
|
602
|
+
entries: [
|
|
603
|
+
...contextualWorldState.entries,
|
|
604
|
+
{
|
|
605
|
+
index,
|
|
606
|
+
kind: 'mcp',
|
|
607
|
+
content: snapshot ?? '<mcp_catalog>No deferred MCP tools remain.</mcp_catalog>'
|
|
608
|
+
}
|
|
609
|
+
]
|
|
610
|
+
};
|
|
611
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
612
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
613
|
+
};
|
|
614
|
+
if (mode !== 'compact')
|
|
615
|
+
await syncMcpWorldState(agentInstructionInsertIndex);
|
|
616
|
+
const initialSystemPrompt = mode === 'compact'
|
|
617
|
+
? buildExecutionSystemPrompt(executionTools, 'run')
|
|
618
|
+
: buildExecutionSystemPrompt();
|
|
619
|
+
let useManualCompactionFallback;
|
|
620
|
+
if (mode === 'compact') {
|
|
621
|
+
const compactSystemPrompt = initialSystemPrompt;
|
|
622
|
+
const compactHistory = [...messages];
|
|
623
|
+
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
624
|
+
const nativeMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
625
|
+
focus: input.prompt,
|
|
626
|
+
highDensityCompaction: selectedModel.highDensityCompaction
|
|
627
|
+
});
|
|
628
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), executionTools);
|
|
629
|
+
const compactInputTokens = selectedModel.contextWindowTokens - compactOverheadTokens;
|
|
630
|
+
if (compactInputTokens <= 0)
|
|
631
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
632
|
+
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
633
|
+
focus: input.prompt,
|
|
634
|
+
maxTokens: compactInputTokens
|
|
635
|
+
}), selectedModel.highDensityCompaction);
|
|
636
|
+
const useNative = shouldUseNativeCompaction({
|
|
637
|
+
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeMessages, executionTools),
|
|
638
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
639
|
+
latestUsage: lastServerUsage,
|
|
640
|
+
historyMessages: compactHistory,
|
|
641
|
+
appendedMessages: nativeMessages.slice(projectedHistory.length)
|
|
642
|
+
});
|
|
643
|
+
messages.splice(0, messages.length, ...(useNative ? nativeMessages : fallbackMessages()));
|
|
644
|
+
if (useNative) {
|
|
645
|
+
let available = true;
|
|
646
|
+
useManualCompactionFallback = () => {
|
|
647
|
+
if (!available)
|
|
648
|
+
return false;
|
|
649
|
+
available = false;
|
|
650
|
+
messages.splice(0, messages.length, ...fallbackMessages());
|
|
651
|
+
return true;
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
await store.append(sessionId, {
|
|
656
|
+
type: 'execution.header',
|
|
657
|
+
payload: {
|
|
658
|
+
promptVersion: MAR_AGENT_PROMPT_VERSION,
|
|
659
|
+
promptHash: createHash('sha256').update(initialSystemPrompt).digest('hex'),
|
|
660
|
+
modelId: selectedModel.id,
|
|
661
|
+
modelName: selectedModel.name,
|
|
662
|
+
reasoningEffort,
|
|
663
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
664
|
+
mode
|
|
665
|
+
},
|
|
666
|
+
executionId,
|
|
667
|
+
turnId
|
|
668
|
+
});
|
|
669
|
+
let lastServerContextTokens = lastServerUsage?.contextInputTokens;
|
|
670
|
+
const compactContext = async () => {
|
|
671
|
+
const current = messages.at(-1);
|
|
672
|
+
if (!current || messages.length < 2)
|
|
673
|
+
return false;
|
|
674
|
+
const retainCurrent = current.role === 'user' && current.contextKind !== 'environment';
|
|
675
|
+
let compactSummary = '';
|
|
676
|
+
const compactSystemPrompt = buildExecutionSystemPrompt(executionTools, 'run');
|
|
677
|
+
const compactHistory = retainCurrent ? messages.slice(0, -1) : messages;
|
|
678
|
+
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
679
|
+
const nativeCompactMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
680
|
+
highDensityCompaction: selectedModel.highDensityCompaction
|
|
681
|
+
});
|
|
682
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), executionTools);
|
|
683
|
+
const compactInputTokens = Math.max(0, selectedModel.contextWindowTokens - compactOverheadTokens);
|
|
684
|
+
if (compactInputTokens === 0)
|
|
685
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
686
|
+
let usingNativeMessages = shouldUseNativeCompaction({
|
|
687
|
+
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeCompactMessages, executionTools),
|
|
688
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
689
|
+
latestUsage: lastServerUsage,
|
|
690
|
+
historyMessages: compactHistory,
|
|
691
|
+
appendedMessages: nativeCompactMessages.slice(projectedHistory.length)
|
|
692
|
+
});
|
|
693
|
+
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
694
|
+
maxTokens: Math.max(1, compactInputTokens)
|
|
695
|
+
}), selectedModel.highDensityCompaction);
|
|
696
|
+
let compactMessages = usingNativeMessages ? nativeCompactMessages : fallbackMessages();
|
|
697
|
+
const compactionId = randomUUID();
|
|
698
|
+
await emit({ type: 'context.compacting', compactionId });
|
|
699
|
+
let latestUsage;
|
|
700
|
+
const compactionRetryState = { attempts: 0 };
|
|
701
|
+
const operation = createCompactionOperation(compactionId);
|
|
702
|
+
try {
|
|
703
|
+
while (true) {
|
|
704
|
+
compactSummary = '';
|
|
705
|
+
latestUsage = undefined;
|
|
706
|
+
try {
|
|
707
|
+
for await (const event of operation.start(selected, {
|
|
708
|
+
retryState: compactionRetryState,
|
|
709
|
+
system: compactSystemPrompt,
|
|
710
|
+
messages: compactMessages,
|
|
711
|
+
tools: executionTools,
|
|
712
|
+
toolChoice: 'none',
|
|
713
|
+
promptCacheKey: sessionId,
|
|
714
|
+
reasoningEffort: requestReasoningEffort ?? reasoningEffort,
|
|
715
|
+
onAttemptDiagnostic: recordModelAttempt('COMPACTION')
|
|
716
|
+
})) {
|
|
717
|
+
if (event.type === 'text.completed' &&
|
|
718
|
+
(event.phase ?? 'final_answer') === 'final_answer')
|
|
719
|
+
compactSummary = event.text.trim();
|
|
720
|
+
else if (event.type === 'usage') {
|
|
721
|
+
latestUsage = event.usage;
|
|
722
|
+
await emit({ type: 'usage.updated', ...publicModelUsage(event.usage) });
|
|
723
|
+
}
|
|
724
|
+
else if (event.type === 'client_tool.call')
|
|
725
|
+
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Compaction returned a tool call while tools were disabled.');
|
|
726
|
+
}
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
catch (error) {
|
|
730
|
+
if (await recoverModelStream(error, compactionRetryState, operation.signal)) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (isProviderContextOverflow(error) && usingNativeMessages) {
|
|
734
|
+
usingNativeMessages = false;
|
|
735
|
+
compactMessages = fallbackMessages();
|
|
736
|
+
compactionRetryState.attempts = 0;
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
if (isProviderContextOverflow(error))
|
|
740
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'The compaction request exceeds the model context window.', { cause: error });
|
|
741
|
+
throw error;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
finally {
|
|
746
|
+
await operation.dispose();
|
|
747
|
+
}
|
|
748
|
+
if (!compactSummary)
|
|
749
|
+
throw new MarAgentError('MAR_AGENT_COMPACT_FAILED', 'Automatic compact failed.');
|
|
750
|
+
rolloutBudget?.recordUsage(latestUsage);
|
|
751
|
+
const replacementHistory = buildCompactedHistory(compactSummary, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent ? current.content : undefined);
|
|
752
|
+
const compactRecord = await store.compact(sessionId, {
|
|
753
|
+
summary: compactSummary,
|
|
754
|
+
replacementHistory,
|
|
755
|
+
automatic: true,
|
|
756
|
+
environment: executionEnvironment,
|
|
757
|
+
modelId: selectedModel.id,
|
|
758
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
759
|
+
...(latestUsage === undefined ? {} : { usage: latestUsage }),
|
|
760
|
+
executionId,
|
|
761
|
+
turnId
|
|
762
|
+
});
|
|
763
|
+
contextGc.reset();
|
|
764
|
+
messages.splice(0, messages.length, environmentContextUpdate(executionEnvironment), ...compactedHistoryMessages(replacementHistory));
|
|
765
|
+
restoreMcpDiscovery();
|
|
766
|
+
projectedExecutionBudgetStage = undefined;
|
|
767
|
+
recordedEnvironment = executionEnvironment;
|
|
768
|
+
compactionUserMessages = replacementHistory
|
|
769
|
+
.filter((message) => message.kind === 'user_input')
|
|
770
|
+
.map((message) => message.content);
|
|
771
|
+
agentInstructionInsertIndex = Math.max(0, messages.length - 1);
|
|
772
|
+
currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
773
|
+
contextualWorldState = resetContextualWorldState(compactRecord.recordId, agentInstructionInsertIndex, {
|
|
774
|
+
instructionSnapshot: currentInstructionSnapshot,
|
|
775
|
+
instructionContent: renderAgentInstructions(instructionEntries, true),
|
|
776
|
+
resourceSnapshot: currentResourceSnapshot,
|
|
777
|
+
previousMayContainResources: compactSummary.includes('# Retained Session resources')
|
|
778
|
+
});
|
|
779
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
780
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
781
|
+
lastServerContextTokens = undefined;
|
|
782
|
+
lastServerUsage = undefined;
|
|
783
|
+
requestReasoningEffort = reasoningEffort;
|
|
784
|
+
effectiveReasoningEffort = reasoningEffort;
|
|
785
|
+
await emit({ type: 'context.compacted', compactionId });
|
|
786
|
+
return true;
|
|
787
|
+
};
|
|
788
|
+
const ensureContextBudget = async () => {
|
|
789
|
+
if (mode === 'compact' || lastServerContextTokens === undefined)
|
|
790
|
+
return;
|
|
791
|
+
const hardLimit = selectedModel.contextWindowTokens;
|
|
792
|
+
const compactLimit = Math.floor((hardLimit * AGENT_EXECUTION_POLICY.automaticCompactionPercent) / 100);
|
|
793
|
+
if (lastServerContextTokens < compactLimit)
|
|
794
|
+
return;
|
|
795
|
+
if (!(await compactContext()))
|
|
796
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Provider usage reached the compaction threshold but no history can be compacted.');
|
|
797
|
+
};
|
|
798
|
+
executionLoop = new ExecutionLoop({
|
|
799
|
+
mode,
|
|
800
|
+
sourceType: sessionSource.type,
|
|
801
|
+
signal: controller.signal,
|
|
802
|
+
model: selectedModel,
|
|
803
|
+
messages,
|
|
804
|
+
toolImages: currentExecutionToolImages,
|
|
805
|
+
rolloutBudget,
|
|
806
|
+
publish: emit,
|
|
807
|
+
appendContext: async (message) => {
|
|
808
|
+
await store.append(sessionId, {
|
|
809
|
+
type: 'model.context',
|
|
810
|
+
payload: message,
|
|
811
|
+
executionId,
|
|
812
|
+
turnId
|
|
813
|
+
});
|
|
814
|
+
},
|
|
815
|
+
prepareRound: async (pendingOutputContinuation) => {
|
|
816
|
+
await appendMailboxMessages();
|
|
817
|
+
appendExecutionBudgetEnvironment();
|
|
818
|
+
executionTools = mcpRegistry.project(baseTools());
|
|
819
|
+
if (mode !== 'compact')
|
|
820
|
+
await syncMcpWorldState(messages.length);
|
|
821
|
+
await ensureContextBudget();
|
|
822
|
+
if (mode !== 'compact')
|
|
823
|
+
await syncMcpWorldState(messages.length);
|
|
824
|
+
appendExecutionBudgetEnvironment();
|
|
825
|
+
if (mode !== 'compact') {
|
|
826
|
+
executionEnvironment = { ...currentEnvironment, ...currentLocalTimeContext() };
|
|
827
|
+
await recordEnvironment();
|
|
828
|
+
}
|
|
829
|
+
const toolsAllowed = mode !== 'compact' &&
|
|
830
|
+
(!rolloutBudget?.active || rolloutBudget.stage !== 'exhausted');
|
|
831
|
+
const roundTools = mode === 'compact' ? executionTools : toolsAllowed ? executionTools : [];
|
|
832
|
+
const codeModeEnabled = roundTools.some((tool) => tool.name === 'code_exec');
|
|
833
|
+
const residentTools = mcpRegistry.projectDirect(baseTools());
|
|
834
|
+
const requestTools = (() => {
|
|
835
|
+
if (selectedModel.protocol !== 'OPENAI_RESPONSES' ||
|
|
836
|
+
selectedModel.responsesEncoding === 'LITE')
|
|
837
|
+
return projectCodeModeTools(roundTools, residentTools);
|
|
838
|
+
const directNames = new Set(residentTools.map((tool) => tool.name));
|
|
839
|
+
// Discovery and caller policy are independent: keep nested declarations for active tools.
|
|
840
|
+
return projectCodeModeTools(roundTools, residentTools).filter((tool) => directNames.has(tool.name));
|
|
841
|
+
})();
|
|
842
|
+
const systemPrompt = mode === 'compact'
|
|
843
|
+
? buildExecutionSystemPrompt(roundTools, 'run')
|
|
844
|
+
: buildExecutionSystemPrompt(roundTools);
|
|
845
|
+
const requestContextMessages = pendingOutputContinuation === undefined
|
|
846
|
+
? messages
|
|
847
|
+
: [...messages, pendingOutputContinuation];
|
|
848
|
+
const modelMessages = mode === 'compact'
|
|
849
|
+
? normalizeMessagesForModel(requestContextMessages, { supportsImages: false })
|
|
850
|
+
: normalizeMessagesForModel(insertContextualWorldState(requestContextMessages, contextualWorldState.entries), {
|
|
851
|
+
supportsImages: selectedModel.inputCapabilities.includes('IMAGE')
|
|
852
|
+
});
|
|
853
|
+
const roundMcpExpectations = new Map(roundTools
|
|
854
|
+
.filter((tool) => tool.name.startsWith('mcp__'))
|
|
855
|
+
.map((tool) => [tool.name, mcpRegistry.expectedTool(tool.name)]));
|
|
856
|
+
const toolContext = {
|
|
857
|
+
host: host,
|
|
858
|
+
todo,
|
|
859
|
+
...(subagents === undefined ? {} : { subagents }),
|
|
860
|
+
mode,
|
|
861
|
+
sessionId,
|
|
862
|
+
executionId,
|
|
863
|
+
signal: controller.signal,
|
|
864
|
+
emit,
|
|
865
|
+
skills: instructionContext?.skills ?? new Map()
|
|
866
|
+
};
|
|
867
|
+
const recentImages = () => currentExecutionImages(modelInputImages, currentExecutionToolImages);
|
|
868
|
+
const toolScope = {
|
|
869
|
+
context: toolContext,
|
|
870
|
+
tools: roundTools,
|
|
871
|
+
expectations: roundMcpExpectations,
|
|
872
|
+
extensionToolNames: new Set((extensions.tools ?? []).map((tool) => tool.name)),
|
|
873
|
+
schedule: sessionRuntime.scheduleTool,
|
|
874
|
+
emit,
|
|
875
|
+
searchMcpTools: (arguments_, searchSignal) => mcpRegistry.expose(arguments_, {
|
|
876
|
+
signal: searchSignal,
|
|
877
|
+
base: baseTools(),
|
|
878
|
+
window: selectedModel.contextWindowTokens,
|
|
879
|
+
system: systemPrompt
|
|
880
|
+
}),
|
|
881
|
+
recentImages,
|
|
882
|
+
captureCodeContext: () => ({
|
|
883
|
+
...toolContext,
|
|
884
|
+
...(subagents ? { subagents: subagents.captureExecution() } : {}),
|
|
885
|
+
recentImages: recentImages()
|
|
886
|
+
}),
|
|
887
|
+
codeModeContext: async (call) => {
|
|
888
|
+
const stateSnapshot = call.name === 'code_exec' ? await store.readCodeModeState(sessionId) : [];
|
|
889
|
+
return {
|
|
890
|
+
retainSession: () => store.retainSessionLease(sessionId, sessionWriterOwner),
|
|
891
|
+
onSettled: async (result) => {
|
|
892
|
+
await store.append(sessionId, {
|
|
893
|
+
type: 'code.cell.completed',
|
|
894
|
+
payload: { ...result, callId: call.callId },
|
|
895
|
+
executionId,
|
|
896
|
+
turnId
|
|
897
|
+
});
|
|
898
|
+
},
|
|
899
|
+
supportsImages: selectedModel.inputCapabilities.includes('IMAGE'),
|
|
900
|
+
tools: roundTools.filter((tool) => allowsToolCaller(tool, 'programmatic')),
|
|
901
|
+
state: stateSnapshot,
|
|
902
|
+
commitState: (mutations) => store.commitCodeModeState(sessionId, mutations, {
|
|
903
|
+
executionId,
|
|
904
|
+
turnId,
|
|
905
|
+
expectedState: stateSnapshot
|
|
906
|
+
})
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
return {
|
|
911
|
+
request: {
|
|
912
|
+
system: systemPrompt,
|
|
913
|
+
messages: modelMessages.map((message) => projectCodeModeSearchResult(message, codeModeEnabled)),
|
|
914
|
+
tools: requestTools,
|
|
915
|
+
...(mode === 'compact'
|
|
916
|
+
? { toolChoice: 'none' }
|
|
917
|
+
: toolsAllowed
|
|
918
|
+
? {}
|
|
919
|
+
: { allowTools: false }),
|
|
920
|
+
promptCacheKey: sessionId,
|
|
921
|
+
reasoningEffort,
|
|
922
|
+
...(requestReasoningEffort === undefined ? {} : { requestReasoningEffort }),
|
|
923
|
+
...(modelInputImages?.length ? { images: modelInputImages } : {}),
|
|
924
|
+
onAttemptDiagnostic: recordModelAttempt(mode === 'compact' ? 'COMPACTION' : 'EXECUTION')
|
|
925
|
+
},
|
|
926
|
+
toolScope
|
|
927
|
+
};
|
|
928
|
+
},
|
|
929
|
+
startModel: async function* (request) {
|
|
930
|
+
if (manualCompactionId !== undefined && !manualCompactionStarted) {
|
|
931
|
+
manualCompactionStarted = true;
|
|
932
|
+
manualCompaction = createCompactionOperation(manualCompactionId);
|
|
933
|
+
await emit({ type: 'context.compacting', compactionId: manualCompactionId });
|
|
934
|
+
}
|
|
935
|
+
yield* manualCompaction
|
|
936
|
+
? manualCompaction.start(selected, request)
|
|
937
|
+
: selected.start(request, controller.signal);
|
|
938
|
+
},
|
|
939
|
+
recoverySignal: () => manualCompaction?.signal ?? controller.signal,
|
|
940
|
+
compactContext,
|
|
941
|
+
compactionFallback: useManualCompactionFallback,
|
|
942
|
+
observeContextTokens: (tokens) => {
|
|
943
|
+
lastServerContextTokens = tokens;
|
|
944
|
+
},
|
|
945
|
+
observeUsage: (usage) => {
|
|
946
|
+
if (usage !== undefined) {
|
|
947
|
+
lastServerContextTokens = usage.contextInputTokens;
|
|
948
|
+
lastServerUsage = { ...usage, historyMessages: [...messages] };
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
checkpoint: async (round, latestUsage) => {
|
|
952
|
+
if (mode !== 'compact' &&
|
|
953
|
+
sessionSource.type !== 'subagent' &&
|
|
954
|
+
latestUsage !== undefined) {
|
|
955
|
+
// Only a committed GC checkpoint may replace active context and invalidate continuation.
|
|
956
|
+
const committed = await contextGc.run({
|
|
957
|
+
store,
|
|
958
|
+
sessionId,
|
|
959
|
+
system: round.request.system,
|
|
960
|
+
tools: round.toolScope.tools,
|
|
961
|
+
modelId: selectedModel.id,
|
|
962
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
963
|
+
usage: latestUsage,
|
|
964
|
+
modelProtocol: selectedModel.protocol,
|
|
965
|
+
responsesConfigurationUpdates: usesResponsesConfigurationUpdates(selectedModel),
|
|
966
|
+
workspace: logicalWorkspace,
|
|
967
|
+
platform: description.platform,
|
|
968
|
+
getActiveProcessIds: async () => {
|
|
969
|
+
const resources = await host
|
|
970
|
+
.listSessionResources?.(sessionId)
|
|
971
|
+
.catch(() => undefined);
|
|
972
|
+
return new Set((resources?.processes ?? [])
|
|
973
|
+
.filter((process) => process.status === 'running')
|
|
974
|
+
.map((process) => process.processId));
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
if (committed) {
|
|
978
|
+
selected.resetContinuation?.();
|
|
979
|
+
const refreshed = await restoreMessages(store, sessionId, committed.records, {
|
|
980
|
+
includeImages: true,
|
|
981
|
+
currentTurnId: turnId,
|
|
982
|
+
projection: committed.projection
|
|
983
|
+
});
|
|
984
|
+
messages.splice(0, messages.length, ...refreshed.messages);
|
|
985
|
+
restoreMcpDiscovery();
|
|
986
|
+
projectedExecutionBudgetStage = undefined;
|
|
987
|
+
recordedEnvironment = refreshed.environmentState;
|
|
988
|
+
compactionUserMessages = [...refreshed.userMessages];
|
|
989
|
+
agentInstructionInsertIndex =
|
|
990
|
+
refreshed.currentTurnUserIndex ?? Math.max(0, messages.length - 1);
|
|
991
|
+
if (agentInstructionInsertIndex &&
|
|
992
|
+
messages[agentInstructionInsertIndex - 1]?.contextKind === 'environment')
|
|
993
|
+
agentInstructionInsertIndex--;
|
|
994
|
+
currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
995
|
+
contextualWorldState = resetContextualWorldState(latestContextualWorldStateGeneration(committed.records), agentInstructionInsertIndex, {
|
|
996
|
+
instructionSnapshot: currentInstructionSnapshot,
|
|
997
|
+
instructionContent: renderAgentInstructions(instructionEntries, committed.records.some((record) => compactSummaryFromCheckpoint(record) !== undefined)),
|
|
998
|
+
resourceSnapshot: currentResourceSnapshot,
|
|
999
|
+
previousMayContainResources: compactHistoryMayContainRetainedResources(committed.records)
|
|
1000
|
+
});
|
|
1001
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
1002
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
mailbox: {
|
|
1007
|
+
hasPending: () => mailbox.length > 0,
|
|
1008
|
+
append: appendMailboxMessages,
|
|
1009
|
+
close: () => {
|
|
1010
|
+
acceptsMailbox = false;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
const completed = await executionLoop.run();
|
|
1015
|
+
finalAnswer = completed.finalAnswer;
|
|
1016
|
+
const compactSummary = mode === 'compact' ? finalAnswer.trim() : '';
|
|
1017
|
+
if (manualCompaction) {
|
|
1018
|
+
manualCompaction.signal.throwIfAborted();
|
|
1019
|
+
await manualCompaction.dispose();
|
|
1020
|
+
}
|
|
1021
|
+
if (mode === 'compact')
|
|
1022
|
+
await store.compact(sessionId, {
|
|
1023
|
+
summary: compactSummary,
|
|
1024
|
+
replacementHistory: buildCompactedHistory(compactSummary, compactionUserMessages, compactUserTokenLimit),
|
|
1025
|
+
modelId: selectedModel.id,
|
|
1026
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1027
|
+
...(completed.usage === undefined ? {} : { usage: completed.usage }),
|
|
1028
|
+
executionId,
|
|
1029
|
+
turnId
|
|
1030
|
+
});
|
|
1031
|
+
if (mode === 'compact' && manualCompactionId !== undefined)
|
|
1032
|
+
await emit({ type: 'context.compacted', compactionId: manualCompactionId });
|
|
1033
|
+
await settleTitle();
|
|
1034
|
+
subagents?.endParentExecution(executionId);
|
|
1035
|
+
await emit({ type: 'execution.completed' });
|
|
1036
|
+
return {
|
|
1037
|
+
executionId,
|
|
1038
|
+
status: 'completed',
|
|
1039
|
+
finalAnswer: mode === 'compact' ? '' : finalAnswer
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
catch (error) {
|
|
1043
|
+
finalAnswer = executionLoop?.finalAnswer ?? finalAnswer;
|
|
1044
|
+
acceptsMailbox = false;
|
|
1045
|
+
await settleTitle();
|
|
1046
|
+
if (controller.signal.aborted) {
|
|
1047
|
+
subagents?.endParentExecution(executionId);
|
|
1048
|
+
await emit({ type: 'execution.cancelled' });
|
|
1049
|
+
return {
|
|
1050
|
+
executionId,
|
|
1051
|
+
status: 'cancelled',
|
|
1052
|
+
finalAnswer: mode === 'compact' ? '' : finalAnswer
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
const diagnostic = modelAttemptFailureDiagnostic(describeMarAgentError(error, 'MAR_AGENT_EXECUTION_FAILED'), exhaustedModelAttempt);
|
|
1056
|
+
subagents?.endParentExecution(executionId);
|
|
1057
|
+
await emit({ type: 'execution.failed', ...diagnostic });
|
|
1058
|
+
return {
|
|
1059
|
+
executionId,
|
|
1060
|
+
status: 'failed',
|
|
1061
|
+
finalAnswer: mode === 'compact' ? '' : finalAnswer,
|
|
1062
|
+
errorCode: diagnostic.code,
|
|
1063
|
+
errorMessage: diagnostic.message
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
finally {
|
|
1067
|
+
acceptsMailbox = false;
|
|
1068
|
+
if (ownsRolloutBudget)
|
|
1069
|
+
rolloutBudget.discard();
|
|
1070
|
+
await manualCompaction?.dispose();
|
|
1071
|
+
await selectedTurn?.close().catch(() => undefined);
|
|
1072
|
+
if (titleAdapter !== undefined && titleAdapter !== selectedAdapter)
|
|
1073
|
+
executionScopedAdapters.add(titleAdapter);
|
|
1074
|
+
try {
|
|
1075
|
+
await closeModelAdapters(executionScopedAdapters);
|
|
1076
|
+
}
|
|
1077
|
+
catch {
|
|
1078
|
+
// Execution cleanup is best effort.
|
|
1079
|
+
}
|
|
1080
|
+
finally {
|
|
1081
|
+
for (const adapter of executionScopedAdapters)
|
|
1082
|
+
activeExecutionAdapters.delete(adapter);
|
|
1083
|
+
}
|
|
1084
|
+
subagents?.endParentExecution(executionId);
|
|
1085
|
+
await releaseSession?.();
|
|
1086
|
+
active.delete(`${sessionId}:${executionId}`);
|
|
1087
|
+
queue.close();
|
|
1088
|
+
}
|
|
1089
|
+
})();
|
|
1090
|
+
const executionKey = `${sessionId}:${executionId}`;
|
|
1091
|
+
executionResults.set(executionKey, result);
|
|
1092
|
+
void result.then(() => executionResults.delete(executionKey), () => executionResults.delete(executionKey));
|
|
1093
|
+
return {
|
|
1094
|
+
executionId,
|
|
1095
|
+
turnId,
|
|
1096
|
+
[Symbol.asyncIterator]: () => queue[Symbol.asyncIterator](),
|
|
1097
|
+
result: () => {
|
|
1098
|
+
queue.discardIfUnobserved();
|
|
1099
|
+
return result;
|
|
1100
|
+
},
|
|
1101
|
+
cancel: () => controller.abort(new MarAgentError('MAR_AGENT_CANCELLED', 'Execution was cancelled.')),
|
|
1102
|
+
enqueueMessage: (message, delivery) => {
|
|
1103
|
+
if (!acceptsMailbox || controller.signal.aborted)
|
|
1104
|
+
return false;
|
|
1105
|
+
mailbox.push({ text: message, ...(delivery ? { delivery } : {}) });
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
};
|
|
1110
|
+
return {
|
|
1111
|
+
id: sessionId,
|
|
1112
|
+
run: (input) => execution('run', input),
|
|
1113
|
+
plan: (input) => execution('plan', input),
|
|
1114
|
+
compact: (input = {}) => execution('compact', {
|
|
1115
|
+
prompt: input.prompt ?? DEFAULT_COMPACTION_FOCUS,
|
|
1116
|
+
...input
|
|
1117
|
+
}),
|
|
1118
|
+
cancel: async (executionId) => active.get(`${sessionId}:${executionId}`)?.abort(),
|
|
1119
|
+
startSubagentTurn: (turn) => execution(turn.role === 'explore' ? 'plan' : 'run', {
|
|
1120
|
+
prompt: turn.prompt,
|
|
1121
|
+
modelId: turn.modelId,
|
|
1122
|
+
reasoningEffort: turn.reasoningEffort
|
|
1123
|
+
}, {
|
|
1124
|
+
publishHostEvents: false,
|
|
1125
|
+
inputSource: 'parent_agent',
|
|
1126
|
+
initialMailbox: turn.initialMailbox,
|
|
1127
|
+
turnId: turn.turnId,
|
|
1128
|
+
mcpExecutionScopeId: turn.mcpExecutionScopeId,
|
|
1129
|
+
...(turn.delivery ? { delivery: turn.delivery } : {}),
|
|
1130
|
+
...(turn.sharedRolloutBudget === undefined
|
|
1131
|
+
? {}
|
|
1132
|
+
: { sharedRolloutBudget: turn.sharedRolloutBudget })
|
|
1133
|
+
})
|
|
1134
|
+
};
|
|
1135
|
+
};
|
|
1136
|
+
return openSession;
|
|
1137
|
+
}
|
|
1138
|
+
function modelAttemptFailureDiagnostic(diagnostic, summary) {
|
|
1139
|
+
if (summary === undefined)
|
|
1140
|
+
return diagnostic;
|
|
1141
|
+
const prefix = `Model request failed after ${summary.attempts} attempts (${summary.retries} retries). `;
|
|
1142
|
+
const availableCharacters = Math.max(0, 1_000 - [...prefix].length);
|
|
1143
|
+
return {
|
|
1144
|
+
code: diagnostic.code,
|
|
1145
|
+
message: `${prefix}${[...diagnostic.message].slice(0, availableCharacters).join('')}`
|
|
1146
|
+
};
|
|
1147
|
+
}
|