apex-code 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -1
- package/README.md +7 -8
- package/dist/cli/agent-lifecycle.d.ts +24 -0
- package/dist/cli/agent-lifecycle.d.ts.map +1 -0
- package/dist/cli/agent-lifecycle.js +126 -0
- package/dist/cli/agent-lifecycle.js.map +1 -0
- package/dist/cli/args.d.ts +13 -12
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +80 -30
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -130
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -8
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +160 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +265 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/delegation/agents.d.ts.map +1 -1
- package/dist/core/delegation/agents.js +2 -1
- package/dist/core/delegation/agents.js.map +1 -1
- package/dist/core/delegation/runtime.d.ts +674 -1
- package/dist/core/delegation/runtime.d.ts.map +1 -1
- package/dist/core/delegation/runtime.js +1338 -66
- package/dist/core/delegation/runtime.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +3 -4
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/source-runtime.d.ts +4 -5
- package/dist/core/extensions/source-runtime.d.ts.map +1 -1
- package/dist/core/extensions/source-runtime.js +4 -5
- package/dist/core/extensions/source-runtime.js.map +1 -1
- package/dist/core/formatter-lifecycle.d.ts +2 -1
- package/dist/core/formatter-lifecycle.d.ts.map +1 -1
- package/dist/core/formatter-lifecycle.js +2 -1
- package/dist/core/formatter-lifecycle.js.map +1 -1
- package/dist/core/hooks/types.d.ts +2 -3
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js +2 -3
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/http-idle-timeout.d.ts +3 -5
- package/dist/core/http-idle-timeout.d.ts.map +1 -1
- package/dist/core/http-idle-timeout.js +3 -5
- package/dist/core/http-idle-timeout.js.map +1 -1
- package/dist/core/mcp/config.d.ts +18 -1
- package/dist/core/mcp/config.d.ts.map +1 -1
- package/dist/core/mcp/config.js +24 -7
- package/dist/core/mcp/config.js.map +1 -1
- package/dist/core/mcp/connector.d.ts +2 -3
- package/dist/core/mcp/connector.d.ts.map +1 -1
- package/dist/core/mcp/connector.js.map +1 -1
- package/dist/core/mcp/oauth/authorize.d.ts +2 -0
- package/dist/core/mcp/oauth/authorize.d.ts.map +1 -1
- package/dist/core/mcp/oauth/authorize.js +5 -2
- package/dist/core/mcp/oauth/authorize.js.map +1 -1
- package/dist/core/mcp/oauth/mcp-token.d.ts +4 -6
- package/dist/core/mcp/oauth/mcp-token.d.ts.map +1 -1
- package/dist/core/mcp/oauth/mcp-token.js +5 -7
- package/dist/core/mcp/oauth/mcp-token.js.map +1 -1
- package/dist/core/mcp/runtime.d.ts +1 -0
- package/dist/core/mcp/runtime.d.ts.map +1 -1
- package/dist/core/mcp/runtime.js +2 -1
- package/dist/core/mcp/runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +0 -15
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions/store.d.ts +6 -11
- package/dist/core/permissions/store.d.ts.map +1 -1
- package/dist/core/permissions/store.js +23 -51
- package/dist/core/permissions/store.js.map +1 -1
- package/dist/core/project-resources.d.ts +62 -0
- package/dist/core/project-resources.d.ts.map +1 -0
- package/dist/core/project-resources.js +42 -0
- package/dist/core/project-resources.js.map +1 -0
- package/dist/core/sdk.d.ts +62 -12
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +313 -44
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-share.d.ts +6 -8
- package/dist/core/session-share.d.ts.map +1 -1
- package/dist/core/session-share.js +9 -12
- package/dist/core/session-share.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -21
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -12
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +0 -47
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +8 -0
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +33 -3
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/web-fetch.d.ts.map +1 -1
- package/dist/core/tools/web-fetch.js +4 -8
- package/dist/core/tools/web-fetch.js.map +1 -1
- package/dist/core/tools/web-search-exa.d.ts +3 -6
- package/dist/core/tools/web-search-exa.d.ts.map +1 -1
- package/dist/core/tools/web-search-exa.js +5 -8
- package/dist/core/tools/web-search-exa.js.map +1 -1
- package/dist/core/trust-manager.d.ts +6 -5
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +42 -19
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/web-search-provider.d.ts +0 -10
- package/dist/core/web-search-provider.d.ts.map +1 -1
- package/dist/core/web-search-provider.js +2 -16
- package/dist/core/web-search-provider.js.map +1 -1
- package/dist/core/workspace/git-observer.d.ts +16 -0
- package/dist/core/workspace/git-observer.d.ts.map +1 -1
- package/dist/core/workspace/git-observer.js +8 -1
- package/dist/core/workspace/git-observer.js.map +1 -1
- package/dist/core/workspace/git-worktree-owner.d.ts +89 -0
- package/dist/core/workspace/git-worktree-owner.d.ts.map +1 -0
- package/dist/core/workspace/git-worktree-owner.js +240 -0
- package/dist/core/workspace/git-worktree-owner.js.map +1 -0
- package/dist/main.d.ts +0 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +22 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/server.d.ts +43 -1
- package/dist/modes/acp/server.d.ts.map +1 -1
- package/dist/modes/acp/server.js +78 -0
- package/dist/modes/acp/server.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +0 -29
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +38 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +110 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +0 -25
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +3 -52
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +0 -2
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +0 -2
- package/dist/utils/version-check.js.map +1 -1
- package/docs/settings.md +2 -7
- package/npm-shrinkwrap.json +5 -5
- package/package.json +2 -2
- package/dist/core/sandbox/bwrap-arguments.d.ts +0 -41
- package/dist/core/sandbox/bwrap-arguments.d.ts.map +0 -1
- package/dist/core/sandbox/bwrap-arguments.js +0 -136
- package/dist/core/sandbox/bwrap-arguments.js.map +0 -1
- package/dist/core/sandbox/child-entry.d.ts +0 -2
- package/dist/core/sandbox/child-entry.d.ts.map +0 -1
- package/dist/core/sandbox/child-entry.js +0 -24
- package/dist/core/sandbox/child-entry.js.map +0 -1
- package/dist/core/sandbox/cli-launch.d.ts +0 -162
- package/dist/core/sandbox/cli-launch.d.ts.map +0 -1
- package/dist/core/sandbox/cli-launch.js +0 -366
- package/dist/core/sandbox/cli-launch.js.map +0 -1
- package/dist/core/sandbox/cli-supervisor.d.ts +0 -31
- package/dist/core/sandbox/cli-supervisor.d.ts.map +0 -1
- package/dist/core/sandbox/cli-supervisor.js +0 -147
- package/dist/core/sandbox/cli-supervisor.js.map +0 -1
- package/dist/core/sandbox/default-hosts.d.ts +0 -28
- package/dist/core/sandbox/default-hosts.d.ts.map +0 -1
- package/dist/core/sandbox/default-hosts.js +0 -69
- package/dist/core/sandbox/default-hosts.js.map +0 -1
- package/dist/core/sandbox/full-access.d.ts +0 -28
- package/dist/core/sandbox/full-access.d.ts.map +0 -1
- package/dist/core/sandbox/full-access.js +0 -63
- package/dist/core/sandbox/full-access.js.map +0 -1
- package/dist/core/sandbox/git-identity.d.ts +0 -57
- package/dist/core/sandbox/git-identity.d.ts.map +0 -1
- package/dist/core/sandbox/git-identity.js +0 -78
- package/dist/core/sandbox/git-identity.js.map +0 -1
- package/dist/core/sandbox/host-approval.d.ts +0 -42
- package/dist/core/sandbox/host-approval.d.ts.map +0 -1
- package/dist/core/sandbox/host-approval.js +0 -99
- package/dist/core/sandbox/host-approval.js.map +0 -1
- package/dist/core/sandbox/linux-backend.d.ts +0 -48
- package/dist/core/sandbox/linux-backend.d.ts.map +0 -1
- package/dist/core/sandbox/linux-backend.js +0 -328
- package/dist/core/sandbox/linux-backend.js.map +0 -1
- package/dist/core/sandbox/macos-backend.d.ts +0 -30
- package/dist/core/sandbox/macos-backend.d.ts.map +0 -1
- package/dist/core/sandbox/macos-backend.js +0 -385
- package/dist/core/sandbox/macos-backend.js.map +0 -1
- package/dist/core/sandbox/network-proxy.d.ts +0 -38
- package/dist/core/sandbox/network-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/network-proxy.js +0 -153
- package/dist/core/sandbox/network-proxy.js.map +0 -1
- package/dist/core/sandbox/network-refusal.d.ts +0 -24
- package/dist/core/sandbox/network-refusal.d.ts.map +0 -1
- package/dist/core/sandbox/network-refusal.js +0 -72
- package/dist/core/sandbox/network-refusal.js.map +0 -1
- package/dist/core/sandbox/policy.d.ts +0 -40
- package/dist/core/sandbox/policy.d.ts.map +0 -1
- package/dist/core/sandbox/policy.js +0 -55
- package/dist/core/sandbox/policy.js.map +0 -1
- package/dist/core/sandbox/profiles.d.ts +0 -25
- package/dist/core/sandbox/profiles.d.ts.map +0 -1
- package/dist/core/sandbox/profiles.js +0 -23
- package/dist/core/sandbox/profiles.js.map +0 -1
- package/dist/core/sandbox/rpc/command-client.d.ts +0 -28
- package/dist/core/sandbox/rpc/command-client.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/command-client.js +0 -86
- package/dist/core/sandbox/rpc/command-client.js.map +0 -1
- package/dist/core/sandbox/rpc/command-proxy.d.ts +0 -48
- package/dist/core/sandbox/rpc/command-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/command-proxy.js +0 -120
- package/dist/core/sandbox/rpc/command-proxy.js.map +0 -1
- package/dist/core/sandbox/rpc/credential-client.d.ts +0 -20
- package/dist/core/sandbox/rpc/credential-client.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/credential-client.js +0 -170
- package/dist/core/sandbox/rpc/credential-client.js.map +0 -1
- package/dist/core/sandbox/rpc/credential-proxy.d.ts +0 -44
- package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/credential-proxy.js +0 -287
- package/dist/core/sandbox/rpc/credential-proxy.js.map +0 -1
- package/dist/core/sandbox/rpc/framing.d.ts +0 -35
- package/dist/core/sandbox/rpc/framing.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/framing.js +0 -114
- package/dist/core/sandbox/rpc/framing.js.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts +0 -47
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-helper.js +0 -222
- package/dist/core/sandbox/rpc/git-credential-helper.js.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +0 -66
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-proxy.js +0 -209
- package/dist/core/sandbox/rpc/git-credential-proxy.js.map +0 -1
- package/dist/core/sandbox/supervisor-temp.d.ts +0 -18
- package/dist/core/sandbox/supervisor-temp.d.ts.map +0 -1
- package/dist/core/sandbox/supervisor-temp.js +0 -21
- package/dist/core/sandbox/supervisor-temp.js.map +0 -1
- package/dist/core/sandbox/supervisor.d.ts +0 -62
- package/dist/core/sandbox/supervisor.d.ts.map +0 -1
- package/dist/core/sandbox/supervisor.js +0 -32
- package/dist/core/sandbox/supervisor.js.map +0 -1
- package/dist/core/sandbox/terminal-handoff.d.ts +0 -68
- package/dist/core/sandbox/terminal-handoff.d.ts.map +0 -1
- package/dist/core/sandbox/terminal-handoff.js +0 -221
- package/dist/core/sandbox/terminal-handoff.js.map +0 -1
- package/dist/core/sandbox/terminal-size.d.ts +0 -53
- package/dist/core/sandbox/terminal-size.d.ts.map +0 -1
- package/dist/core/sandbox/terminal-size.js +0 -126
- package/dist/core/sandbox/terminal-size.js.map +0 -1
- package/dist/core/sandbox/violations.d.ts +0 -23
- package/dist/core/sandbox/violations.d.ts.map +0 -1
- package/dist/core/sandbox/violations.js +0 -30
- package/dist/core/sandbox/violations.js.map +0 -1
package/dist/core/sdk.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { clampThinkingLevel, streamSimple } from "@earendil-works/pi-ai/compat";
|
|
3
|
-
import { Agent, setDefaultStreamFn } from "apex-code-agent-core";
|
|
3
|
+
import { Agent, createRunBudgetController, setDefaultStreamFn, } from "apex-code-agent-core";
|
|
4
4
|
import { getAgentDir } from "../config.js";
|
|
5
5
|
import { resolvePath } from "../utils/paths.js";
|
|
6
6
|
import { AgentSession } from "./agent-session.js";
|
|
@@ -8,6 +8,7 @@ import { formatNoModelsAvailableMessage } from "./auth-guidance.js";
|
|
|
8
8
|
import { AuthStorage } from "./auth-storage.js";
|
|
9
9
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
10
10
|
import { createAgentDefinitionResolver } from "./delegation/agents.js";
|
|
11
|
+
import { ChildRunRegistry, } from "./delegation/runtime.js";
|
|
11
12
|
import { loadHookRuntime } from "./hooks/loader.js";
|
|
12
13
|
import { createSessionMcpConnector } from "./mcp/connector.js";
|
|
13
14
|
import { createMcpRuntime } from "./mcp/runtime.js";
|
|
@@ -17,19 +18,16 @@ import { ModelRuntime } from "./model-runtime.js";
|
|
|
17
18
|
import { DerivedPermissionRuleStore } from "./permissions/store.js";
|
|
18
19
|
import { mergeProviderAttributionHeaders } from "./provider-attribution.js";
|
|
19
20
|
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
20
|
-
import { SANDBOX_ENFORCEMENT_MARKER_VALUE, SANDBOX_ENFORCEMENT_MARKER_VARIABLE } from "./sandbox/cli-launch.js";
|
|
21
|
-
import { createSandboxCredentialStore } from "./sandbox/rpc/credential-client.js";
|
|
22
21
|
import { getDefaultSessionDir, SessionManager } from "./session-manager.js";
|
|
23
22
|
import { SettingsManager } from "./settings-manager.js";
|
|
24
23
|
import { time } from "./timings.js";
|
|
25
24
|
import { createBackgroundShellRegistry } from "./tools/background-shell.js";
|
|
26
25
|
import { createAllToolDefinitions, createBashTool, createCodingTools, createDelegateToolDefinition, createEditTool, createFindTool, createGrepTool, createLsTool, createPowerShellTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
|
|
26
|
+
import { GitWorktreeWorkspaceOwner } from "./workspace/git-worktree-owner.js";
|
|
27
27
|
// Preserve the pre-0.81 fallback for extensions that construct Agent instances
|
|
28
28
|
// or invoke low-level agent loops without supplying streamFn. Agent core remains
|
|
29
29
|
// provider-agnostic and does not import pi-ai/compat itself.
|
|
30
30
|
setDefaultStreamFn(streamSimple);
|
|
31
|
-
export const SDK_SANDBOX_ENFORCEMENT_MARKER_VARIABLE = SANDBOX_ENFORCEMENT_MARKER_VARIABLE;
|
|
32
|
-
export const SDK_SANDBOX_ENFORCEMENT_MARKER_VALUE = SANDBOX_ENFORCEMENT_MARKER_VALUE;
|
|
33
31
|
// Re-exports
|
|
34
32
|
export * from "./agent-session-runtime.js";
|
|
35
33
|
export { withFileMutationQueue,
|
|
@@ -91,16 +89,6 @@ function extractFinalAssistantText(session) {
|
|
|
91
89
|
return "";
|
|
92
90
|
}
|
|
93
91
|
export async function createAgentSession(options = {}) {
|
|
94
|
-
const sandboxContract = options.sandbox ?? "none";
|
|
95
|
-
const markerPresent = process.env[SDK_SANDBOX_ENFORCEMENT_MARKER_VARIABLE] === SDK_SANDBOX_ENFORCEMENT_MARKER_VALUE;
|
|
96
|
-
if (sandboxContract === "required" && !markerPresent) {
|
|
97
|
-
throw new Error("SDK sandbox contract requires OS containment, but no enforcing supervisor marker is present.");
|
|
98
|
-
}
|
|
99
|
-
const sandboxDiagnostic = sandboxContract === "external"
|
|
100
|
-
? "Sandbox containment is external to the SDK; the SDK cannot verify OS containment."
|
|
101
|
-
: sandboxContract === "none"
|
|
102
|
-
? "No OS containment is asserted by the SDK sandbox contract."
|
|
103
|
-
: undefined;
|
|
104
92
|
const cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());
|
|
105
93
|
const agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();
|
|
106
94
|
let resourceLoader = options.resourceLoader;
|
|
@@ -110,6 +98,43 @@ export async function createAgentSession(options = {}) {
|
|
|
110
98
|
const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
|
|
111
99
|
const sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));
|
|
112
100
|
const backgroundShellRegistry = options.backgroundShellRegistry ?? createBackgroundShellRegistry();
|
|
101
|
+
// One resolved per-run budget policy: the caller's override when supplied,
|
|
102
|
+
// else the settings policy. Children built below inherit this resolved value
|
|
103
|
+
// so a child run carries the same per-run policy as its parent without
|
|
104
|
+
// re-reading settings (spec 2026-09-09, "Shared budgets"). Per-run only: it
|
|
105
|
+
// never creates a shared ceiling.
|
|
106
|
+
const runBudget = options.runBudget ?? settingsManager.getRunBudget();
|
|
107
|
+
// The root aggregate budget (spec 2026-09-09, "Shared budgets"): created
|
|
108
|
+
// ONLY when the caller explicitly configures `aggregateBudget` -- never
|
|
109
|
+
// derived from the per-run policy. One controller per root tree: the
|
|
110
|
+
// parent's own Agent consumes it (composed under its per-prompt controller),
|
|
111
|
+
// and buildChildSession forwards THE SAME instance to every child regardless
|
|
112
|
+
// of depth, so a grandchild's consumption lands on the root ledger. Its wall
|
|
113
|
+
// time starts here, at root session construction, and no descendant can
|
|
114
|
+
// reset it: descendants only consume.
|
|
115
|
+
const aggregateBudgetController = options.aggregateBudget
|
|
116
|
+
? createRunBudgetController(options.aggregateBudget)
|
|
117
|
+
: undefined;
|
|
118
|
+
// The shared ceiling this session consumes and hands to its delegated
|
|
119
|
+
// children: the root aggregate when configured, else a caller-supplied
|
|
120
|
+
// controller (which is how a delegated child receives its root's aggregate).
|
|
121
|
+
// With neither there is NO shared controller at all: every session keeps
|
|
122
|
+
// local-only budgets under its inherited per-run policy.
|
|
123
|
+
const sharedBudgetController = aggregateBudgetController ?? options.sharedBudgetController;
|
|
124
|
+
// The tree-facing usage snapshot: the aggregate controller's counters cover
|
|
125
|
+
// every accepted provider request, tool call, and maintenance request of the
|
|
126
|
+
// parent's own runs and of every descendant, so one read reports the tree.
|
|
127
|
+
const aggregateBudgetUsage = sharedBudgetController
|
|
128
|
+
? () => {
|
|
129
|
+
const usage = sharedBudgetController.usage();
|
|
130
|
+
return {
|
|
131
|
+
providerRequests: usage.providerRequests,
|
|
132
|
+
toolCalls: usage.toolCalls,
|
|
133
|
+
maintenanceRequests: usage.maintenanceRequests,
|
|
134
|
+
startedAtMs: usage.startedAt,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
: undefined;
|
|
113
138
|
if (!resourceLoader) {
|
|
114
139
|
resourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });
|
|
115
140
|
await resourceLoader.reload();
|
|
@@ -175,12 +200,11 @@ export async function createAgentSession(options = {}) {
|
|
|
175
200
|
thinkingLevel = clampThinkingLevel(model, thinkingLevel);
|
|
176
201
|
}
|
|
177
202
|
// OAuth-capable MCP servers resolve tokens through the session's own credential
|
|
178
|
-
// seam: direct and lock-serialized
|
|
179
|
-
//
|
|
180
|
-
// without `auth: "oauth"` never touch it.
|
|
203
|
+
// seam: direct and lock-serialized, fail-closed when no store applies
|
|
204
|
+
// (spec 2026-09-01-mcp-oauth). Servers without `auth: "oauth"` never touch it.
|
|
181
205
|
const mcpRuntime = createMcpRuntime(cwd, createSessionMcpConnector({
|
|
182
|
-
credentials: options.mcpCredentials ??
|
|
183
|
-
}), { projectTrusted: settingsManager.isProjectTrusted() });
|
|
206
|
+
credentials: options.mcpCredentials ?? AuthStorage.create(authPath),
|
|
207
|
+
}), { projectTrusted: settingsManager.isProjectTrusted(), agentDir });
|
|
184
208
|
// `web_search`, `lsp`, and `mcp` join the core four only when configured. All stay
|
|
185
209
|
// registered either way, so an explicit `--tools` selection still reaches them and an
|
|
186
210
|
// unconfigured call still explains itself. Activating an unconfigured tool would put a
|
|
@@ -235,10 +259,16 @@ export async function createAgentSession(options = {}) {
|
|
|
235
259
|
thinkingLevel,
|
|
236
260
|
tools: [],
|
|
237
261
|
},
|
|
238
|
-
//
|
|
239
|
-
// print, JSON, RPC, ACP, SDK) runs through
|
|
240
|
-
//
|
|
241
|
-
|
|
262
|
+
// The resolved budget policy from above (override or settings); every
|
|
263
|
+
// execution mode (interactive, print, JSON, RPC, ACP, SDK) runs through
|
|
264
|
+
// this session, so none counts on its own
|
|
265
|
+
// (spec 2026-09-01-tool-reliability-and-execution-budgets.md).
|
|
266
|
+
runBudget,
|
|
267
|
+
budgetScope: options.budgetScope ?? "prompt",
|
|
268
|
+
// The root aggregate when configured (the parent's own runs consume it,
|
|
269
|
+
// per-prompt local scope unchanged), else a caller-supplied shared
|
|
270
|
+
// controller, else nothing (spec 2026-09-09, "Shared budgets").
|
|
271
|
+
sharedBudgetController,
|
|
242
272
|
convertToLlm: convertToLlmWithBlockImages,
|
|
243
273
|
streamFn: async (model, context, options) => {
|
|
244
274
|
const providerRetrySettings = settingsManager.getProviderRetrySettings();
|
|
@@ -313,11 +343,13 @@ export async function createAgentSession(options = {}) {
|
|
|
313
343
|
// must read the *live* session (active tools can change after construction),
|
|
314
344
|
// not a snapshot frozen at this point.
|
|
315
345
|
const parentSessionRef = {};
|
|
346
|
+
const childRunRegistry = options.childRunRegistry ?? new ChildRunRegistry();
|
|
316
347
|
const customTools = options.customTools ? [...options.customTools] : [];
|
|
317
348
|
// A configured permission gate supplies the authority a child must derive, so
|
|
318
349
|
// discovery is enabled by default in real sessions. Callers that need fixture
|
|
319
350
|
// definitions may still provide an explicit resolver.
|
|
320
351
|
const delegation = options.delegation ?? (options.permissionGate ? {} : undefined);
|
|
352
|
+
let delegationRuntime;
|
|
321
353
|
if (delegation) {
|
|
322
354
|
const parentPermissionGate = options.permissionGate;
|
|
323
355
|
const resolveAgent = delegation.resolveAgent ??
|
|
@@ -326,8 +358,17 @@ export async function createAgentSession(options = {}) {
|
|
|
326
358
|
agentDir,
|
|
327
359
|
isProjectTrusted: () => settingsManager.isProjectTrusted(),
|
|
328
360
|
});
|
|
329
|
-
|
|
361
|
+
let worktreeOwner;
|
|
362
|
+
// One read of the delegation bound for this runtime; the policy snapshot
|
|
363
|
+
// below reports the same value it enforces instead of re-reading settings.
|
|
364
|
+
const delegationMaxDepth = settingsManager.getDelegationMaxDepth();
|
|
365
|
+
delegationRuntime = {
|
|
366
|
+
childRunRegistry,
|
|
330
367
|
resolveAgent,
|
|
368
|
+
// Concurrency cap (spec 2026-09-09, "Shared budgets"): the registry's
|
|
369
|
+
// admission path reads it from the runtime options. Undefined is
|
|
370
|
+
// unlimited.
|
|
371
|
+
maxConcurrentChildren: options.maxConcurrentChildren,
|
|
331
372
|
getParentCapabilities: () => {
|
|
332
373
|
const capabilities = new Set();
|
|
333
374
|
for (const name of parentSessionRef.current?.getActiveToolNames() ?? []) {
|
|
@@ -356,9 +397,23 @@ export async function createAgentSession(options = {}) {
|
|
|
356
397
|
// the (possibly delegated) session this createAgentSession call is
|
|
357
398
|
// building, via the same sessionManager this closure already captures.
|
|
358
399
|
getDelegationDepth: () => sessionManager.getDelegationDepth(),
|
|
359
|
-
maxDelegationDepth:
|
|
400
|
+
maxDelegationDepth: delegationMaxDepth,
|
|
360
401
|
getParentSessionDir: () => sessionManager.getSessionDir(),
|
|
361
|
-
|
|
402
|
+
// Child-run records carry the parent session id so durable records and
|
|
403
|
+
// protocol payloads tie each child to this session's own identity.
|
|
404
|
+
getParentSessionId: () => sessionManager.getSessionId(),
|
|
405
|
+
// Worktree isolation (spec 2026-09-09, "Parallel work and ownership"):
|
|
406
|
+
// the production workspace owner, constructed on the first worktree-
|
|
407
|
+
// isolated delegation only. Shared-read delegations never read this
|
|
408
|
+
// property (the runtime consults the owner only for isolation
|
|
409
|
+
// "worktree"), so they never construct an owner and never invoke git.
|
|
410
|
+
get workspaceOwner() {
|
|
411
|
+
if (worktreeOwner === undefined) {
|
|
412
|
+
worktreeOwner = new GitWorktreeWorkspaceOwner(cwd);
|
|
413
|
+
}
|
|
414
|
+
return worktreeOwner;
|
|
415
|
+
},
|
|
416
|
+
buildChildSession: async ({ definition, toolNames, capabilities, depth, sessionId, artifactDir, workspace, reattachSessionPath, timeoutMs, }) => {
|
|
362
417
|
if (!parentPermissionGate) {
|
|
363
418
|
throw new Error("delegate requires a permission gate configured on the parent session (ADR 0008).");
|
|
364
419
|
}
|
|
@@ -367,23 +422,77 @@ export async function createAgentSession(options = {}) {
|
|
|
367
422
|
if (!childModel) {
|
|
368
423
|
throw new Error(`Cannot delegate to "${definition.name}": no model is available for the child session.`);
|
|
369
424
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
425
|
+
// The derived policy snapshot (spec 2026-09-09, "Derive, do not
|
|
426
|
+
// reconstruct"): the exact values this construction used -- the
|
|
427
|
+
// ceiling-checked tool allowlist, the admitted capability set from
|
|
428
|
+
// the runtime's single admission projection (never a second
|
|
429
|
+
// classification, ADR 0010), the delegation bound it enforces, the
|
|
430
|
+
// child's model, and the budget wiring every child is built with
|
|
431
|
+
// (session-scoped own controller; aggregate only when a shared ceiling
|
|
432
|
+
// was configured at the root). It rides on the returned handle so the
|
|
433
|
+
// registry persists it on the child-run record.
|
|
434
|
+
const policy = {
|
|
435
|
+
tools: [...toolNames],
|
|
436
|
+
capabilities: [...capabilities].sort(),
|
|
437
|
+
maxDelegationDepth: delegationMaxDepth,
|
|
438
|
+
model: childModel.id,
|
|
439
|
+
budgetScope: "session",
|
|
440
|
+
aggregateBudget: sharedBudgetController !== undefined,
|
|
441
|
+
};
|
|
442
|
+
// An isolated child runs inside the workspace owner's prepared root
|
|
443
|
+
// (its linked worktree); a shared child keeps this session's cwd.
|
|
444
|
+
const childCwd = workspace?.root ?? cwd;
|
|
445
|
+
// The one reattachment seam (restart reconstruction): when the request
|
|
446
|
+
// carries the existing child session path, that transcript is OPENED
|
|
447
|
+
// rather than created; identity (header id, parentSession, depth) comes
|
|
448
|
+
// from the file's own header. Every other input below is derived
|
|
449
|
+
// exactly as for a fresh delegation -- permission store, model, tools,
|
|
450
|
+
// budget -- so there is no second construction path.
|
|
451
|
+
const childSessionManager = reattachSessionPath
|
|
452
|
+
? SessionManager.open(reattachSessionPath, artifactDir)
|
|
453
|
+
: artifactDir
|
|
454
|
+
? SessionManager.create(childCwd, artifactDir, {
|
|
455
|
+
id: sessionId,
|
|
456
|
+
parentSession: sessionManager.getSessionId(),
|
|
457
|
+
delegationDepth: depth,
|
|
458
|
+
})
|
|
459
|
+
: SessionManager.inMemory(childCwd, {
|
|
460
|
+
parentSession: sessionManager.getSessionId(),
|
|
461
|
+
delegationDepth: depth,
|
|
462
|
+
});
|
|
380
463
|
const derivedStore = new DerivedPermissionRuleStore({ parent: parentPermissionGate.store });
|
|
381
464
|
const { session: childSession } = await createAgentSession({
|
|
382
|
-
cwd,
|
|
465
|
+
cwd: childCwd,
|
|
383
466
|
agentDir,
|
|
384
467
|
model: childModel,
|
|
385
468
|
modelRuntime,
|
|
386
469
|
settingsManager,
|
|
470
|
+
// The parent's already-resolved per-run budget (override or settings),
|
|
471
|
+
// not a fresh settings read: every child run carries the same per-run
|
|
472
|
+
// policy as its parent (spec 2026-09-09, "Shared budgets").
|
|
473
|
+
//
|
|
474
|
+
// Session scope + the root aggregate: a resumed or follow-up child
|
|
475
|
+
// turn continues the same child budget (one controller per child
|
|
476
|
+
// Agent, created at its first turn), and every gate also answers
|
|
477
|
+
// to the tree's shared ceiling -- accepted consumption records to
|
|
478
|
+
// both the child's own controller and the aggregate. THE SAME
|
|
479
|
+
// aggregate instance reaches every descendant regardless of
|
|
480
|
+
// depth (a grandchild's parent forwards it onward), so there is
|
|
481
|
+
// exactly ONE aggregate per root tree and no child can reset it
|
|
482
|
+
// by resuming or spawning children (spec 2026-09-09, "Shared
|
|
483
|
+
// budgets"). Without an aggregate there is no shared controller:
|
|
484
|
+
// the child keeps local-only budgets under the inherited policy.
|
|
485
|
+
//
|
|
486
|
+
// A launch timeout (spec 2026-09-09, timeouts) overrides the
|
|
487
|
+
// child's OWN wall-time limit with the requested timeoutMs, so the
|
|
488
|
+
// existing AgentRunBudget wall-time gate enforces it mid-run; the
|
|
489
|
+
// parent policy's other limits still apply unchanged.
|
|
490
|
+
runBudget: timeoutMs === undefined ? runBudget : { ...runBudget, maxWallTimeMs: timeoutMs },
|
|
491
|
+
budgetScope: "session",
|
|
492
|
+
sharedBudgetController,
|
|
493
|
+
// The same per-parent admission cap applies to a child's own
|
|
494
|
+
// delegations (each runtime counts its direct children).
|
|
495
|
+
maxConcurrentChildren: options.maxConcurrentChildren,
|
|
387
496
|
sessionManager: childSessionManager,
|
|
388
497
|
resourceLoader,
|
|
389
498
|
tools: toolNames,
|
|
@@ -409,27 +518,188 @@ export async function createAgentSession(options = {}) {
|
|
|
409
518
|
// header on its next createAgentSession call) -- otherwise recursion
|
|
410
519
|
// would be silently capped at one level regardless of maxDelegationDepth.
|
|
411
520
|
delegation,
|
|
412
|
-
sandbox: sandboxContract,
|
|
413
521
|
});
|
|
414
522
|
await childSession.bindExtensions({});
|
|
523
|
+
let status = "idle";
|
|
524
|
+
let runPromise;
|
|
525
|
+
let lastTurnResult;
|
|
526
|
+
// The captured structured terminal outcome of the run in flight
|
|
527
|
+
// (`agent_end`'s stopReason). Budget refusals emit agent_end without
|
|
528
|
+
// an assistant message, so this is the only way the settlement below
|
|
529
|
+
// can see and name them.
|
|
530
|
+
let runStopReason;
|
|
531
|
+
const ensureOpen = () => {
|
|
532
|
+
if (status === "closed")
|
|
533
|
+
throw new Error("Child session is closed.");
|
|
534
|
+
};
|
|
535
|
+
const start = (input) => {
|
|
536
|
+
ensureOpen();
|
|
537
|
+
if (runPromise)
|
|
538
|
+
throw new Error("Child session is already running.");
|
|
539
|
+
status = "running";
|
|
540
|
+
runStopReason = undefined;
|
|
541
|
+
// Capture the run's structured terminal outcome: a budget refusal
|
|
542
|
+
// emits agent_end without producing an assistant message, so the
|
|
543
|
+
// message-based checks below cannot see it.
|
|
544
|
+
const unsubscribeStop = childSession.subscribe((event) => {
|
|
545
|
+
if (event.type === "agent_end")
|
|
546
|
+
runStopReason = event.stopReason;
|
|
547
|
+
});
|
|
548
|
+
const pending = childSession
|
|
549
|
+
.prompt(input)
|
|
550
|
+
.then(() => {
|
|
551
|
+
unsubscribeStop();
|
|
552
|
+
if (status === "closed") {
|
|
553
|
+
lastTurnResult = { outcome: "failed", output: "" };
|
|
554
|
+
throw new Error("Child session is closed.");
|
|
555
|
+
}
|
|
556
|
+
if (status === "interrupted") {
|
|
557
|
+
lastTurnResult = { outcome: "interrupted", output: extractFinalAssistantText(childSession) };
|
|
558
|
+
throw new Error("Child session is interrupted.");
|
|
559
|
+
}
|
|
560
|
+
const lastAssistant = [...childSession.agent.state.messages]
|
|
561
|
+
.reverse()
|
|
562
|
+
.find((message) => message.role === "assistant");
|
|
563
|
+
if (lastAssistant?.role === "assistant" &&
|
|
564
|
+
(lastAssistant.stopReason === "aborted" || lastAssistant.stopReason === "error")) {
|
|
565
|
+
status = "interrupted";
|
|
566
|
+
lastTurnResult = {
|
|
567
|
+
outcome: lastAssistant.stopReason === "aborted" ? "interrupted" : "failed",
|
|
568
|
+
output: lastAssistant.errorMessage || extractFinalAssistantText(childSession),
|
|
569
|
+
};
|
|
570
|
+
throw new Error(lastAssistant.errorMessage || "Child session was interrupted.");
|
|
571
|
+
}
|
|
572
|
+
status = "idle";
|
|
573
|
+
lastTurnResult = { outcome: "completed", output: extractFinalAssistantText(childSession) };
|
|
574
|
+
}, (error) => {
|
|
575
|
+
unsubscribeStop();
|
|
576
|
+
if (status !== "closed")
|
|
577
|
+
status = "interrupted";
|
|
578
|
+
lastTurnResult =
|
|
579
|
+
status === "closed"
|
|
580
|
+
? { outcome: "failed", output: "" }
|
|
581
|
+
: { outcome: "interrupted", output: extractFinalAssistantText(childSession) };
|
|
582
|
+
throw error;
|
|
583
|
+
})
|
|
584
|
+
.finally(() => {
|
|
585
|
+
runPromise = undefined;
|
|
586
|
+
});
|
|
587
|
+
runPromise = pending;
|
|
588
|
+
return pending;
|
|
589
|
+
};
|
|
590
|
+
const sendInput = (input) => {
|
|
591
|
+
ensureOpen();
|
|
592
|
+
if (runPromise) {
|
|
593
|
+
if (status !== "running")
|
|
594
|
+
throw new Error("Child session is still stopping.");
|
|
595
|
+
// A follow-up queued onto a live run settles through that run's
|
|
596
|
+
// own loop; only turns that settle here pass through the gate.
|
|
597
|
+
return childSession.followUp(input);
|
|
598
|
+
}
|
|
599
|
+
return start(input).then(() => requireVerifiedTurn());
|
|
600
|
+
};
|
|
601
|
+
const close = () => {
|
|
602
|
+
if (status === "closed")
|
|
603
|
+
return;
|
|
604
|
+
status = "closed";
|
|
605
|
+
childSession.dispose();
|
|
606
|
+
};
|
|
607
|
+
// Verification gate (spec 2026-09-09, "Verification at completion"):
|
|
608
|
+
// a child with configured verification policies may not settle a turn
|
|
609
|
+
// as successful unless the session's canonical tracker reports
|
|
610
|
+
// "verified". The tracker is the only verifier; no child-local one is
|
|
611
|
+
// introduced. With the "explicit" boundary the gate runs
|
|
612
|
+
// requestVerification once here; with the "post-turn" boundary the
|
|
613
|
+
// session already ran verification at its own turn boundary, so the
|
|
614
|
+
// gate only reads the status. Any other completion status --
|
|
615
|
+
// failed/unavailable/interrupted/continued-unverified -- fails the
|
|
616
|
+
// turn with the status named in the error.
|
|
617
|
+
const requireVerifiedTurn = async () => {
|
|
618
|
+
const policyIds = childSession.verificationPolicyIds();
|
|
619
|
+
if (policyIds.length === 0)
|
|
620
|
+
return;
|
|
621
|
+
const verificationStatus = childSession.verificationBoundary() === "explicit"
|
|
622
|
+
? await childSession.requestVerification()
|
|
623
|
+
: childSession.verificationStatus();
|
|
624
|
+
if (verificationStatus === "verified")
|
|
625
|
+
return;
|
|
626
|
+
const message = `Child verification failed: ${verificationStatus} (policies: ${policyIds.join(", ")}).`;
|
|
627
|
+
lastTurnResult = { outcome: "failed", output: message };
|
|
628
|
+
throw new Error(message);
|
|
629
|
+
};
|
|
415
630
|
return {
|
|
631
|
+
get status() {
|
|
632
|
+
return status;
|
|
633
|
+
},
|
|
634
|
+
latestResult: () => lastTurnResult,
|
|
635
|
+
usage: () => childSession.agent.budgetUsage(),
|
|
636
|
+
// The usage-rollup seam (spec 2026-09-09): the registry reads the
|
|
637
|
+
// child's own transcript file when one exists, and falls back to
|
|
638
|
+
// these in-memory entries only for a child that never persisted a
|
|
639
|
+
// transcript. Read-only; the child's SessionManager stays the owner.
|
|
640
|
+
sessionEntries: () => childSessionManager.getEntries(),
|
|
416
641
|
async run(task) {
|
|
417
642
|
const prompt = definition.systemPrompt
|
|
418
643
|
? `${definition.systemPrompt}\n\nTask: ${task}`
|
|
419
644
|
: `Task: ${task}`;
|
|
420
|
-
await
|
|
645
|
+
await start(prompt);
|
|
646
|
+
if (status === "closed" || status === "interrupted")
|
|
647
|
+
throw new Error(`Child session is ${status}.`);
|
|
648
|
+
// The launch timeout's settlement error path (spec 2026-09-09,
|
|
649
|
+
// timeouts): a run refused at the child's own wall-time gate never
|
|
650
|
+
// started meaningful work, so the delegation settles failed with
|
|
651
|
+
// the exhausted limit named, reusing the budget's existing
|
|
652
|
+
// exhaustedLimit vocabulary. Other budget refusals keep their
|
|
653
|
+
// existing semantics (the refusal is named in the child transcript
|
|
654
|
+
// and the prior result stands).
|
|
655
|
+
if (runStopReason?.kind === "budget-exhausted" && runStopReason.limit === "wall-time") {
|
|
656
|
+
const message = `Child run stopped before completing: the run's ${runStopReason.limit} budget was exhausted.`;
|
|
657
|
+
lastTurnResult = { outcome: "failed", output: message };
|
|
658
|
+
throw new Error(message);
|
|
659
|
+
}
|
|
660
|
+
// Delegated work cannot claim success when the child has a
|
|
661
|
+
// required verification boundary and verification did not pass.
|
|
662
|
+
// Use the session's canonical tracker rather than introducing
|
|
663
|
+
// a second child-only verifier.
|
|
664
|
+
await requireVerifiedTurn();
|
|
421
665
|
return { output: extractFinalAssistantText(childSession) };
|
|
422
666
|
},
|
|
423
|
-
|
|
424
|
-
|
|
667
|
+
wait: async () => {
|
|
668
|
+
while (runPromise)
|
|
669
|
+
await runPromise;
|
|
670
|
+
},
|
|
671
|
+
interrupt: () => {
|
|
672
|
+
ensureOpen();
|
|
673
|
+
if (status === "running") {
|
|
674
|
+
status = "interrupted";
|
|
675
|
+
void childSession.abort().catch(() => undefined);
|
|
676
|
+
}
|
|
425
677
|
},
|
|
678
|
+
close,
|
|
679
|
+
sendInput,
|
|
680
|
+
followUp: sendInput,
|
|
681
|
+
dispose: close,
|
|
682
|
+
// Construction linkage (spec 2026-09-09, policy/artifact
|
|
683
|
+
// linkage): the registry relays these onto the persisted child_run
|
|
684
|
+
// record and every status/wait payload derived from it.
|
|
685
|
+
policy,
|
|
426
686
|
};
|
|
427
687
|
},
|
|
428
688
|
};
|
|
429
689
|
customTools.push(createDelegateToolDefinition(delegationRuntime));
|
|
690
|
+
// Historical resume (restart reconstruction) reattaches a persisted child
|
|
691
|
+
// through THIS runtime's buildChildSession seam. Wiring it here -- not only
|
|
692
|
+
// at the first delegation -- is what makes resume work on a freshly
|
|
693
|
+
// reopened session before any new delegation has run.
|
|
694
|
+
childRunRegistry.setRuntimeOptions(delegationRuntime);
|
|
430
695
|
}
|
|
431
696
|
const session = new AgentSession({
|
|
697
|
+
childRunRegistry,
|
|
698
|
+
delegationRuntime,
|
|
432
699
|
agent,
|
|
700
|
+
// Root aggregate usage (spec 2026-09-09, "Shared budgets"): undefined
|
|
701
|
+
// when the tree has no aggregate budget.
|
|
702
|
+
aggregateBudgetUsage,
|
|
433
703
|
sessionManager,
|
|
434
704
|
settingsManager,
|
|
435
705
|
cwd,
|
|
@@ -466,9 +736,8 @@ export async function createAgentSession(options = {}) {
|
|
|
466
736
|
return {
|
|
467
737
|
session,
|
|
468
738
|
extensionsResult,
|
|
739
|
+
delegationRuntime,
|
|
469
740
|
modelFallbackMessage,
|
|
470
|
-
sandboxContract,
|
|
471
|
-
sandboxDiagnostic,
|
|
472
741
|
};
|
|
473
742
|
}
|
|
474
743
|
//# sourceMappingURL=sdk.js.map
|