@nathapp/nax-agent 0.91.7-canary.1 → 0.91.7-canary.2
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 +4 -0
- package/dist/coding-tools/coding-tool-extras.d.ts +42 -0
- package/dist/coding-tools/coding-tool-extras.js +31 -0
- package/dist/coding-tools/coding-tool-support.d.ts +6 -0
- package/dist/coding-tools/coding-tool-support.js +7 -1
- package/dist/config/catalog-overrides.d.ts +5 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/mcp/connect.js +26 -3
- package/dist/mcp/types.d.ts +7 -0
- package/dist/native/models.js +1 -0
- package/dist/permissions/approval-memory.d.ts +18 -0
- package/dist/permissions/approval-memory.js +88 -0
- package/dist/permissions/index.d.ts +1 -0
- package/dist/permissions/index.js +1 -0
- package/dist/permissions/types.d.ts +6 -0
- package/dist/sandbox/launcher.js +3 -0
- package/dist/sandbox/types.d.ts +2 -0
- package/dist/session/agent-session-command.d.ts +19 -0
- package/dist/session/agent-session-command.js +38 -0
- package/dist/session/agent-session-types.d.ts +9 -0
- package/dist/session/agent-session.js +49 -1
- package/dist/session/native-backend-options.d.ts +18 -2
- package/dist/session/native-backend-options.js +26 -3
- package/dist/session/native-backend.js +42 -4
- package/dist/session/session-ask-link.d.ts +6 -0
- package/dist/session/session-ask-link.js +5 -0
- package/dist/session/session-ask-port.js +4 -0
- package/dist/session/session-backend.d.ts +21 -1
- package/dist/session/session-tool-support.d.ts +39 -3
- package/dist/session/session-tool-support.js +54 -10
- package/dist/session-store/index.d.ts +3 -0
- package/dist/session-store/index.js +3 -0
- package/dist/session-store/session-lock-guard.d.ts +6 -0
- package/dist/session-store/session-lock-guard.js +85 -0
- package/dist/session-store/session-lock.d.ts +39 -0
- package/dist/session-store/session-lock.js +175 -0
- package/dist/session-store/session-meta.d.ts +27 -0
- package/dist/session-store/session-meta.js +20 -0
- package/dist/session-store/storage.d.ts +39 -0
- package/dist/session-store/storage.js +164 -0
- package/dist/tools/ask-request.d.ts +18 -0
- package/dist/tools/ask-request.js +30 -0
- package/dist/tools/bash.d.ts +9 -0
- package/dist/tools/bash.js +61 -16
- package/dist/tools/git.js +10 -3
- package/dist/tools/provider-advertise.d.ts +7 -0
- package/dist/tools/provider-advertise.js +13 -1
- package/dist/tools/provider-types.d.ts +6 -0
- package/dist/tools/run-command-exec.js +12 -0
- package/dist/tools/run-command-surface.d.ts +28 -0
- package/dist/tools/run-command-surface.js +109 -0
- package/dist/tools/run-command.d.ts +17 -16
- package/dist/tools/run-command.js +48 -68
- package/dist/tools/runtime-calltool.d.ts +100 -0
- package/dist/tools/runtime-calltool.js +112 -3
- package/dist/tools/runtime.d.ts +11 -0
- package/dist/tools/runtime.js +36 -18
- package/dist/tools/types.d.ts +8 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,10 @@ All notable changes to `@nathapp/nax-agent` are recorded here. The format follow
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). While the version is `0.x`, a minor
|
|
5
5
|
release may change the public API.
|
|
6
6
|
|
|
7
|
+
## [0.91.7-canary.2] - 2026-10-26
|
|
8
|
+
|
|
9
|
+
- No changes in this package. Released in lockstep with the other nax packages.
|
|
10
|
+
|
|
7
11
|
## [0.91.7-canary.1] - 2026-10-24
|
|
8
12
|
|
|
9
13
|
- No changes in this package. Released in lockstep with the other nax packages.
|
|
@@ -31,5 +31,47 @@ export interface DeclaredCommandToolsArgs {
|
|
|
31
31
|
readonly runDeclaredCommand?: DeclaredCommandRunner;
|
|
32
32
|
/** P4: how Bash and Exec-branch commands run; absent = direct spawn (tests). */
|
|
33
33
|
readonly launcher?: CommandLauncher;
|
|
34
|
+
/**
|
|
35
|
+
* US-003/US-008: whether this session offers the per-call `unsandboxed`
|
|
36
|
+
* argument — on Bash (`createBashTool`) and on RunCommand's argv branch
|
|
37
|
+
* (`createRunCommandTool`'s `exec` option, US-008). Advertisement only:
|
|
38
|
+
* RunCommand's DECLARED-command branch has no argv to unwrap and refuses the
|
|
39
|
+
* flag by name.
|
|
40
|
+
*/
|
|
41
|
+
readonly unsandboxedCommands?: boolean;
|
|
34
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* US-003: `unsandboxedCommands` as a spreadable field — present only when the
|
|
45
|
+
* session opted in, so "off" and "absent" stay one shape all the way down to
|
|
46
|
+
* `createBashTool` and to RunCommand's `exec` option (US-008).
|
|
47
|
+
*
|
|
48
|
+
* A helper rather than an inline `cond ? { field } : {}` spread because
|
|
49
|
+
* `buildDeclaredCommandTools` and `buildCodingToolSupport` both sit at their
|
|
50
|
+
* cognitive-complexity baseline and a ternary inside either one would raise it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function unsandboxedToolOptions(args: {
|
|
53
|
+
readonly unsandboxedCommands?: boolean;
|
|
54
|
+
}): {
|
|
55
|
+
readonly unsandboxedCommands?: true;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* US-005: the same option as the RUNTIME's field — whether a `Bash`/`Exec`
|
|
59
|
+
* call may run outside the sandbox at all, plus the Bash approval mode that
|
|
60
|
+
* decides how an enabled request is routed.
|
|
61
|
+
*
|
|
62
|
+
* Absent when the session did not opt in, so "off" and "absent" stay one shape
|
|
63
|
+
* all the way to `createCodingToolRuntime` (absent means disabled). A helper
|
|
64
|
+
* for the same reason as `unsandboxedToolOptions`: `buildCodingToolSupport`
|
|
65
|
+
* sits at its cognitive-complexity baseline and a ternary inside it would
|
|
66
|
+
* raise it.
|
|
67
|
+
*/
|
|
68
|
+
export declare function unsandboxedRuntimeOption(args: {
|
|
69
|
+
readonly unsandboxedCommands?: boolean;
|
|
70
|
+
readonly bashApproval: BashApprovalMode;
|
|
71
|
+
}): {
|
|
72
|
+
readonly unsandboxed?: {
|
|
73
|
+
readonly enabled: boolean;
|
|
74
|
+
readonly bashApproval: BashApprovalMode;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
35
77
|
export declare function buildDeclaredCommandTools(args: DeclaredCommandToolsArgs): CodingTool[];
|
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
import { createBashTool, createRunCommandTool, } from "#src/tools/index";
|
|
2
|
+
/**
|
|
3
|
+
* US-003: `unsandboxedCommands` as a spreadable field — present only when the
|
|
4
|
+
* session opted in, so "off" and "absent" stay one shape all the way down to
|
|
5
|
+
* `createBashTool` and to RunCommand's `exec` option (US-008).
|
|
6
|
+
*
|
|
7
|
+
* A helper rather than an inline `cond ? { field } : {}` spread because
|
|
8
|
+
* `buildDeclaredCommandTools` and `buildCodingToolSupport` both sit at their
|
|
9
|
+
* cognitive-complexity baseline and a ternary inside either one would raise it.
|
|
10
|
+
*/
|
|
11
|
+
export function unsandboxedToolOptions(args) {
|
|
12
|
+
return args.unsandboxedCommands === true ? { unsandboxedCommands: true } : {};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* US-005: the same option as the RUNTIME's field — whether a `Bash`/`Exec`
|
|
16
|
+
* call may run outside the sandbox at all, plus the Bash approval mode that
|
|
17
|
+
* decides how an enabled request is routed.
|
|
18
|
+
*
|
|
19
|
+
* Absent when the session did not opt in, so "off" and "absent" stay one shape
|
|
20
|
+
* all the way to `createCodingToolRuntime` (absent means disabled). A helper
|
|
21
|
+
* for the same reason as `unsandboxedToolOptions`: `buildCodingToolSupport`
|
|
22
|
+
* sits at its cognitive-complexity baseline and a ternary inside it would
|
|
23
|
+
* raise it.
|
|
24
|
+
*/
|
|
25
|
+
export function unsandboxedRuntimeOption(args) {
|
|
26
|
+
return args.unsandboxedCommands === true ? { unsandboxed: { enabled: true, bashApproval: args.bashApproval } } : {};
|
|
27
|
+
}
|
|
2
28
|
export function buildDeclaredCommandTools(args) {
|
|
3
29
|
return [
|
|
4
30
|
...(args.declaredCommands.size > 0 || args.allowExec
|
|
@@ -31,6 +57,10 @@ export function buildDeclaredCommandTools(args) {
|
|
|
31
57
|
patterns: args.execGrant?.patterns ?? [],
|
|
32
58
|
...(args.packageName !== undefined ? { packageName: args.packageName } : {}),
|
|
33
59
|
...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
|
|
60
|
+
// US-008: the same option Bash takes, forwarded to the argv
|
|
61
|
+
// branch's advertisement through the same helper — one
|
|
62
|
+
// shape for "off" and "absent" on both tools.
|
|
63
|
+
...unsandboxedToolOptions(args),
|
|
34
64
|
},
|
|
35
65
|
}
|
|
36
66
|
: {}),
|
|
@@ -49,6 +79,7 @@ export function buildDeclaredCommandTools(args) {
|
|
|
49
79
|
bashApproval: args.bashApproval,
|
|
50
80
|
...(args.humanApproval === true ? { humanApproval: true } : {}),
|
|
51
81
|
...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
|
|
82
|
+
...unsandboxedToolOptions(args),
|
|
52
83
|
}),
|
|
53
84
|
]
|
|
54
85
|
: []),
|
|
@@ -142,6 +142,12 @@ export declare function buildCodingToolSupport(args: {
|
|
|
142
142
|
commandShadow?: CommandShadow;
|
|
143
143
|
/** P4: resolved by resolveCodingToolSupport (async); data only here. */
|
|
144
144
|
launcher?: CommandLauncher;
|
|
145
|
+
/**
|
|
146
|
+
* US-003: whether this session offers Bash's per-call `unsandboxed` argument
|
|
147
|
+
* (the session profile's `allowUnsandboxedCommands`). Advertisement only —
|
|
148
|
+
* the runtime's own reading of the field is a later story.
|
|
149
|
+
*/
|
|
150
|
+
unsandboxedCommands?: boolean;
|
|
145
151
|
/** US-001: forwarded into ToolRunContext so Bash/Exec can SIGKILL on cancel. */
|
|
146
152
|
abortSignal?: AbortSignal;
|
|
147
153
|
/**
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { getSafeLogger, NaxError } from "#src/infra/index";
|
|
12
12
|
import { advertisedSchemaBytes, BASH_TOOL_NAME, compileToolPolicy, createCodingToolRuntime, createNoOpToolAuditSink, createToolAuditSink, EXEC_TOOL_NAME, } from "#src/tools/index";
|
|
13
13
|
import { resolveBashSupport } from "./coding-tool-bash.js";
|
|
14
|
-
import { buildDeclaredCommandTools } from "./coding-tool-extras.js";
|
|
14
|
+
import { buildDeclaredCommandTools, unsandboxedRuntimeOption, unsandboxedToolOptions } from "./coding-tool-extras.js";
|
|
15
15
|
import { isTempConfined, rawScreenOptionsFor } from "./coding-tool-sandbox.js";
|
|
16
16
|
export function buildCodingToolSupport(args) {
|
|
17
17
|
if (args.declared.length === 0)
|
|
@@ -119,9 +119,15 @@ export function buildCodingToolSupport(args) {
|
|
|
119
119
|
...(args.stripEnvVars !== undefined ? { stripEnvVars: args.stripEnvVars } : {}),
|
|
120
120
|
...(args.shell !== undefined ? { shell: args.shell } : {}),
|
|
121
121
|
...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
|
|
122
|
+
...unsandboxedToolOptions(args),
|
|
122
123
|
}),
|
|
123
124
|
],
|
|
124
125
|
...(args.providerIdByTool !== undefined ? { providerIdByTool: args.providerIdByTool } : {}),
|
|
126
|
+
// US-005: the escape option reaches the RUNTIME too, not just the Bash
|
|
127
|
+
// schema — with the locally resolved mode, so a caller that left
|
|
128
|
+
// `bashApproval` unset cannot enable an escape under a mode it did not
|
|
129
|
+
// choose.
|
|
130
|
+
...unsandboxedRuntimeOption({ unsandboxedCommands: args.unsandboxedCommands, bashApproval }),
|
|
125
131
|
});
|
|
126
132
|
const tools = runtime.advertised(advertised);
|
|
127
133
|
// The fixed per-hop cost of advertising provider tools: their schemas enter
|
|
@@ -91,6 +91,11 @@ export interface CatalogModelOverride {
|
|
|
91
91
|
* `protocol: "openai-completions"` (nax-ai `assertOverrideModelRouting`).
|
|
92
92
|
*/
|
|
93
93
|
openRouterRouting?: OpenRouterRouting;
|
|
94
|
+
/**
|
|
95
|
+
* Thinking wire format for an `openai-completions` model (nax#2696).
|
|
96
|
+
* Mirrored from nax-ai's ThinkingFormat; omit to inherit the provider's format.
|
|
97
|
+
*/
|
|
98
|
+
thinkingFormat?: "openai" | "qwen" | "qwen-chat-template" | "deepseek" | "zai";
|
|
94
99
|
}
|
|
95
100
|
/** Provider-scoped catalog overrides — maps 1:1 onto nax-ai's `ProviderOverride[]`. */
|
|
96
101
|
export interface ProviderCatalogOverride {
|
package/dist/index.d.ts
CHANGED
|
@@ -24,13 +24,14 @@ export { AuthCancelledError, type AuthEvent, type AuthInteraction, type AuthLink
|
|
|
24
24
|
export type { NativeSessionAdapterOptions } from "#src/native/session-adapter";
|
|
25
25
|
export type { AfterResponsePatch, AfterResponsePayload, AfterToolPatch, AfterToolPayload, BeforeCompactionPatch, BeforeCompactionPayload, BeforeRequestPatch, BeforeRequestPayload, BeforeToolOutcome, BeforeToolPayload, BeforeTurnEndPatch, BeforeTurnEndPayload, BeforeTurnPatch, BeforeTurnPayload, CompleteCallOptions, ExternalHandlerOf, LoopEvent, LoopEventMap, LoopHandlerContext, LoopHandlerEntry, LoopHandlerSet, PatchOf, PayloadOf, TransformContextPatch, TransformContextPayload, } from "#src/native/session/loop-events/types";
|
|
26
26
|
export { displayToolInput, TOOL_CALL_INPUT_BYTES, TOOL_RESULT_PREVIEW_BYTES, toolResultPreview, } from "#src/native/session/turn-event-emitter";
|
|
27
|
-
export { type ApprovalAuditRow, type ApprovalEntry, type ApprovalsFile, type ApprovalsFileRead, type ApprovalsFileState, type ApprovalsTaint, ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, type AskControl, type AskDecidedBy, type AskDecision, type AskLink, type AskLinkOutcome, type AskRequest, type AskResolver, type AskVerdict, appendApproval, appendApprovalAudit, approvalId, approvalsPath, type BashLexResult, type BashRedirect, type BashSegment, type BashSegmentSeparator, type BashToken, type ClearTaintOutcome, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, type MaskResult, maskForPrompt, type PrepareApprovalsStoreOptions, parseRuleList, parseToolExpression, prepareApprovalsStore, type RemovalDecision, type RemovalResult, type ResolvedPermissions, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, type SecretSpan, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
|
|
27
|
+
export { type ApprovalAuditRow, type ApprovalEntry, type ApprovalMemoryDecision, type ApprovalMemoryRequest, approvalMemoryApplies, approvalMemoryKey, type ApprovalsFile, type ApprovalsFileRead, type ApprovalsFileState, type ApprovalsTaint, ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, type AskControl, type AskDecidedBy, type AskDecision, type AskLink, type AskLinkOutcome, type AskRequest, type AskResolver, type AskVerdict, appendApproval, appendApprovalAudit, approvalId, approvalsPath, type BashLexResult, type BashRedirect, type BashSegment, type BashSegmentSeparator, type BashToken, type ClearTaintOutcome, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, type MaskResult, maskForPrompt, type PrepareApprovalsStoreOptions, parseRuleList, parseToolExpression, prepareApprovalsStore, type RemovalDecision, type RemovalResult, type ResolvedPermissions, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, type SecretSpan, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
|
|
28
28
|
export { type AgentGlobOptions, type AgentRuntime, type AgentSpawnOptions, type AgentSpawnResult, type AgentSpawnStdin, getAgentRuntime, nodeRuntime, setAgentRuntime, } from "#src/runtime/index";
|
|
29
29
|
export { buildSandboxPolicy, type CommandLauncher, type CommandLauncherOptions, createCommandLauncher, createSrtBackend, DISABLED_SANDBOX_STATE, SANDBOXED_ENV, defaultTempRoots, denialHintLine, type GitLayout, type LaunchRequest, type LaunchResult, type LaunchSpec, LIKELY_SANDBOX_DENIAL, listCredentialFiles, listGitGuardFiles, listNaxEntries, type ProbeResult, probeSandbox, probeSandboxOnce, quoteArgvForShell, rawBashRefusalReason, resetSandboxBackend, resolveGitLayout, runTempRoots, runTmpRoot, type SandboxBackend, type SandboxBackendName, type SandboxNetworkPolicy, type SandboxPolicy, type SandboxPolicyInput, type SandboxRecord, type SandboxState, type SandboxWrapRequest, type SessionSandbox, sessionSandboxFrom, sandboxBackendFor, sandboxSentence, sessionTmpDir, sessionTmpDirUnder, strayCommonDirTripwire, unsandboxedSentence, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
|
|
30
|
+
export { createSessionStorage, defaultSessionsDir, processAlive, LIST_PAGE_SIZE, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, SESSION_ID_PATTERN, SESSION_META_MODES, type SessionMeta, type SessionMetaMode, type SessionListEntry, type SessionListPage, type SessionLockHolder, type SessionLockHolderState, type SessionStorage, type SessionStorageDeps, } from "#src/session-store/index";
|
|
30
31
|
export type { AdapterFailure } from "#src/session/adapter-failure";
|
|
31
32
|
export { createAgentSession, resumeAgentSession } from "#src/session/agent-session";
|
|
32
33
|
export { AgentSessionError, type AgentSessionErrorCode } from "#src/session/agent-session-errors";
|
|
33
|
-
export type { AgentSession, AgentSessionHostPorts, AgentSessionProfile, AnswerReply, AnswerStatus, ApprovalDecidedBy, CostSource, CreateAgentSessionOptions, EmbedderTool, EmbedderToolContext, EmbedderToolResult, SessionEvent, SessionEventBase, SessionEventBody, TurnEndStatus, } from "#src/session/agent-session-types";
|
|
34
|
+
export type { AgentSession, AgentSessionHostPorts, AgentSessionProfile, AnswerReply, AnswerStatus, ApprovalDecidedBy, CostSource, CommandRunResult, CreateAgentSessionOptions, EmbedderTool, EmbedderToolContext, EmbedderToolResult, SessionEvent, SessionEventBase, SessionEventBody, TurnEndStatus, } from "#src/session/agent-session-types";
|
|
34
35
|
export type { AgentAwaitingHumanEvent, AgentCallEndedEvent, AgentCallStartedEvent, AgentMessageUpdateEvent, AgentProcessUpdateEvent, AgentStreamEvent, AgentStreamEventBase, AgentThinkingUpdateEvent, AgentToolCallUpdateEvent, AgentUsageUpdateEvent, } from "#src/session/agent-stream-events";
|
|
35
36
|
export { type AdapterInteraction, type AdapterInteractionResponse, type InteractionHandler, NO_OP_INTERACTION_HANDLER, } from "#src/session/interaction-handler";
|
|
36
37
|
export { nativeBackend } from "#src/session/native-backend";
|
package/dist/index.js
CHANGED
|
@@ -19,9 +19,10 @@ export { NaxError } from "#src/infra/nax-error";
|
|
|
19
19
|
export { createTerminalAuthInteraction, PLAIN_STYLE, PromptCancelledError, } from "#src/terminal-auth/index";
|
|
20
20
|
export { AuthCancelledError, ambientShadows, anyAmbientCredential, authImportOutcomeLabel, createFileTranscriptStore, createMemoryTranscriptStore, credentialFilePath, DEFAULT_PI_AUTH_PATH, importPiCredentials, listProviderModels, listStoredProviders, loginProviderIds, MAX_RETAINED_TRANSCRIPTS, NATIVE_AGENT, NativeSessionAdapter, NativeSessionUnsupportedError, nativeComplete, nativeTierProviders, naxCredentialStore, newSessionKey, providersWithoutCredentials, pruneRetainedTranscripts, removeStoredProvider, resolveNativeId, runLogin, servedAuth, } from "#src/native/index";
|
|
21
21
|
export { displayToolInput, TOOL_CALL_INPUT_BYTES, TOOL_RESULT_PREVIEW_BYTES, toolResultPreview, } from "#src/native/session/turn-event-emitter";
|
|
22
|
-
export { ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, appendApproval, appendApprovalAudit, approvalId, approvalsPath, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, maskForPrompt, parseRuleList, parseToolExpression, prepareApprovalsStore, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
|
|
22
|
+
export { approvalMemoryApplies, approvalMemoryKey, ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, appendApproval, appendApprovalAudit, approvalId, approvalsPath, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, maskForPrompt, parseRuleList, parseToolExpression, prepareApprovalsStore, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
|
|
23
23
|
export { getAgentRuntime, nodeRuntime, setAgentRuntime, } from "#src/runtime/index";
|
|
24
24
|
export { buildSandboxPolicy, createCommandLauncher, createSrtBackend, DISABLED_SANDBOX_STATE, SANDBOXED_ENV, defaultTempRoots, denialHintLine, LIKELY_SANDBOX_DENIAL, listCredentialFiles, listGitGuardFiles, listNaxEntries, probeSandbox, probeSandboxOnce, quoteArgvForShell, rawBashRefusalReason, resetSandboxBackend, resolveGitLayout, runTempRoots, runTmpRoot, sessionSandboxFrom, sandboxBackendFor, sandboxSentence, sessionTmpDir, sessionTmpDirUnder, strayCommonDirTripwire, unsandboxedSentence, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
|
|
25
|
+
export { createSessionStorage, defaultSessionsDir, processAlive, LIST_PAGE_SIZE, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, SESSION_ID_PATTERN, SESSION_META_MODES, } from "#src/session-store/index";
|
|
25
26
|
export { createAgentSession, resumeAgentSession } from "#src/session/agent-session";
|
|
26
27
|
export { AgentSessionError } from "#src/session/agent-session-errors";
|
|
27
28
|
export { NO_OP_INTERACTION_HANDLER, } from "#src/session/interaction-handler";
|
package/dist/mcp/connect.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* once the process is gone. A failed connect is closed the same way.
|
|
7
7
|
*/
|
|
8
8
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
|
-
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { ErrorCode, ListToolsResultSchema, McpError, ToolSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { z } from "zod";
|
|
10
11
|
import { McpCallError, McpConnectError } from "#src/mcp/errors";
|
|
11
12
|
import { resultText } from "#src/mcp/result-text";
|
|
12
13
|
import { waitForStdioExit } from "#src/mcp/stdio-close";
|
|
@@ -53,13 +54,35 @@ function toolInfo(raw) {
|
|
|
53
54
|
if (!isRaw(raw) || typeof raw.name !== "string" || raw.name.length === 0)
|
|
54
55
|
return undefined;
|
|
55
56
|
const inputSchema = isRaw(raw.inputSchema) ? { ...raw.inputSchema } : {};
|
|
56
|
-
|
|
57
|
+
const readOnly = isRaw(raw.annotations) && raw.annotations.readOnlyHint === true;
|
|
58
|
+
return {
|
|
59
|
+
name: raw.name,
|
|
60
|
+
description: typeof raw.description === "string" ? raw.description : "",
|
|
61
|
+
inputSchema,
|
|
62
|
+
...(readOnly ? { readOnly: true } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The SDK's own tools/list schema, except that a tool's `annotations` are not
|
|
67
|
+
* type-checked: the SDK would reject the WHOLE page over one server's
|
|
68
|
+
* `readOnlyHint: "yes"`, which would cost the connection every tool. `toolInfo`
|
|
69
|
+
* reads the hint strictly (`=== true`), so a malformed one just means "not
|
|
70
|
+
* read-only" and every other field is still validated.
|
|
71
|
+
*/
|
|
72
|
+
const LenientListToolsSchema = ListToolsResultSchema.extend({
|
|
73
|
+
tools: z.array(ToolSchema.extend({ annotations: z.record(z.string(), z.unknown()).optional() })),
|
|
74
|
+
});
|
|
75
|
+
async function listPage(client, cursor, signal, timeout) {
|
|
76
|
+
const page = await client.request({ method: "tools/list", ...(cursor !== undefined ? { params: { cursor } } : {}) }, LenientListToolsSchema, { signal, timeout });
|
|
77
|
+
// What Client.listTools does after its own request: the SDK reads these caches in callTool.
|
|
78
|
+
client["cacheToolMetadata"](page.tools);
|
|
79
|
+
return page;
|
|
57
80
|
}
|
|
58
81
|
async function listAll(client, signal, timeout) {
|
|
59
82
|
const tools = [];
|
|
60
83
|
let cursor;
|
|
61
84
|
do {
|
|
62
|
-
const page = await client
|
|
85
|
+
const page = await listPage(client, cursor, signal, timeout);
|
|
63
86
|
for (const raw of page.tools ?? []) {
|
|
64
87
|
const info = toolInfo(raw);
|
|
65
88
|
if (info !== undefined)
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -15,6 +15,13 @@ export interface McpToolInfo {
|
|
|
15
15
|
readonly name: string;
|
|
16
16
|
readonly description: string;
|
|
17
17
|
readonly inputSchema: JSONSchema;
|
|
18
|
+
/**
|
|
19
|
+
* Present (as `true`) only when the server annotated the tool
|
|
20
|
+
* `readOnlyHint: true`. Absent in every other case, so an unannotated tool
|
|
21
|
+
* keeps its `{ name, description, inputSchema }` shape. Trusted as the server
|
|
22
|
+
* states it; the lock pins input schemas, not this hint.
|
|
23
|
+
*/
|
|
24
|
+
readonly readOnly?: true;
|
|
18
25
|
}
|
|
19
26
|
export interface McpCallResult {
|
|
20
27
|
readonly text: string;
|
package/dist/native/models.js
CHANGED
|
@@ -117,6 +117,7 @@ export function toProviderOverrides(overrides) {
|
|
|
117
117
|
// Omitted when the override declares none: nax-ai then falls back to the
|
|
118
118
|
// template sibling's ceiling, which is the only honest value available.
|
|
119
119
|
...(model.maxTokens !== undefined ? { maxTokens: model.maxTokens } : {}),
|
|
120
|
+
...(model.thinkingFormat !== undefined ? { thinkingFormat: model.thinkingFormat } : {}),
|
|
120
121
|
supportsTools: model.supportsTools,
|
|
121
122
|
thinkingLevels: model.thinkingLevels,
|
|
122
123
|
// nax#2191: forwarded verbatim. nax-ai's `assertOverrideModelRouting`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Shared session approval-memory policy, ported from the ACP server (nax#2553). */
|
|
2
|
+
export interface ApprovalMemoryRequest {
|
|
3
|
+
readonly tool: string;
|
|
4
|
+
readonly command?: string;
|
|
5
|
+
}
|
|
6
|
+
export type ApprovalMemoryDecision = "allow" | "deny";
|
|
7
|
+
/**
|
|
8
|
+
* Tool key, or execute tool plus command/subcommand. Unsafe, masked, wrapper and
|
|
9
|
+
* flag-second-word requests have no key. A key alone never authorizes a command:
|
|
10
|
+
* callers must also check approvalMemoryApplies against the remembered decision.
|
|
11
|
+
*/
|
|
12
|
+
export declare function approvalMemoryKey(request: ApprovalMemoryRequest): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Whether a decision found under this request's key may answer without asking.
|
|
15
|
+
* Allows cover only simple commands with plain, non-flag words after the key;
|
|
16
|
+
* denies cover their matching key regardless. Does not validate key eligibility.
|
|
17
|
+
*/
|
|
18
|
+
export declare function approvalMemoryApplies(request: ApprovalMemoryRequest, decision: ApprovalMemoryDecision): boolean;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** Keep aligned with the ACP display's execute tools, without depending on that transport. */
|
|
2
|
+
const APPROVAL_EXECUTE_TOOLS = new Set(["Bash", "RunCommand", "Git", "GitCommit"]);
|
|
3
|
+
/** Chaining, pipes, substitution, subshells, redirection and line breaks. */
|
|
4
|
+
const SHELL_METACHARACTERS = /[;&|`$()<>\n\r]/;
|
|
5
|
+
/** First words that run another command or arbitrary code. */
|
|
6
|
+
const WRAPPERS = new Set([
|
|
7
|
+
"sh",
|
|
8
|
+
"bash",
|
|
9
|
+
"zsh",
|
|
10
|
+
"dash",
|
|
11
|
+
"ksh",
|
|
12
|
+
"fish",
|
|
13
|
+
"env",
|
|
14
|
+
"xargs",
|
|
15
|
+
"sudo",
|
|
16
|
+
"doas",
|
|
17
|
+
"su",
|
|
18
|
+
"command",
|
|
19
|
+
"builtin",
|
|
20
|
+
"eval",
|
|
21
|
+
"exec",
|
|
22
|
+
"source",
|
|
23
|
+
".",
|
|
24
|
+
"nohup",
|
|
25
|
+
"time",
|
|
26
|
+
"timeout",
|
|
27
|
+
"nice",
|
|
28
|
+
"ionice",
|
|
29
|
+
"stdbuf",
|
|
30
|
+
"watch",
|
|
31
|
+
"find",
|
|
32
|
+
"node",
|
|
33
|
+
"bun",
|
|
34
|
+
"deno",
|
|
35
|
+
"npx",
|
|
36
|
+
"bunx",
|
|
37
|
+
"pnpx",
|
|
38
|
+
"python",
|
|
39
|
+
"python3",
|
|
40
|
+
"perl",
|
|
41
|
+
"ruby",
|
|
42
|
+
"php",
|
|
43
|
+
"uv",
|
|
44
|
+
"uvx",
|
|
45
|
+
]);
|
|
46
|
+
/** A plain command name or path: no quotes, escapes, globs or expansions the shell would rewrite. */
|
|
47
|
+
const PLAIN_WORD = /^[A-Za-z0-9._/-]+$/;
|
|
48
|
+
/** The masking prefix S3 puts in place of a secret in a shown command. */
|
|
49
|
+
const MASK_MARKER = "[REDACTED";
|
|
50
|
+
/**
|
|
51
|
+
* Tool key, or execute tool plus command/subcommand. Unsafe, masked, wrapper and
|
|
52
|
+
* flag-second-word requests have no key. A key alone never authorizes a command:
|
|
53
|
+
* callers must also check approvalMemoryApplies against the remembered decision.
|
|
54
|
+
*/
|
|
55
|
+
export function approvalMemoryKey(request) {
|
|
56
|
+
if (!APPROVAL_EXECUTE_TOOLS.has(request.tool))
|
|
57
|
+
return request.tool;
|
|
58
|
+
const command = request.command ?? "";
|
|
59
|
+
if (command.includes(MASK_MARKER))
|
|
60
|
+
return undefined;
|
|
61
|
+
const [first = "", second] = command.trim().split(/\s+/);
|
|
62
|
+
if (!PLAIN_WORD.test(first))
|
|
63
|
+
return undefined;
|
|
64
|
+
const name = first.slice(first.lastIndexOf("/") + 1).toLowerCase();
|
|
65
|
+
if (name === "" || WRAPPERS.has(name))
|
|
66
|
+
return undefined;
|
|
67
|
+
if (second === undefined)
|
|
68
|
+
return `${request.tool}:${first}`;
|
|
69
|
+
// A flag can change what the command does (`rm -f`, `git -C repo`): remembering the bare command would
|
|
70
|
+
// approve every later invocation of it, so a flag second word is never remembered (nax#2553).
|
|
71
|
+
if (second.startsWith("-"))
|
|
72
|
+
return undefined;
|
|
73
|
+
return PLAIN_WORD.test(second) ? `${request.tool}:${first} ${second}` : undefined;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether a decision found under this request's key may answer without asking.
|
|
77
|
+
* Allows cover only simple commands with plain, non-flag words after the key;
|
|
78
|
+
* denies cover their matching key regardless. Does not validate key eligibility.
|
|
79
|
+
*/
|
|
80
|
+
export function approvalMemoryApplies(request, decision) {
|
|
81
|
+
if (decision === "deny" || !APPROVAL_EXECUTE_TOOLS.has(request.tool))
|
|
82
|
+
return true;
|
|
83
|
+
const command = request.command ?? "";
|
|
84
|
+
if (SHELL_METACHARACTERS.test(command))
|
|
85
|
+
return false;
|
|
86
|
+
const rest = command.trim().split(/\s+/).slice(2);
|
|
87
|
+
return rest.every((word) => PLAIN_WORD.test(word) && !word.startsWith("-"));
|
|
88
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from "./approval-audit.ts";
|
|
2
|
+
export { type ApprovalMemoryDecision, type ApprovalMemoryRequest, approvalMemoryApplies, approvalMemoryKey, } from "./approval-memory.ts";
|
|
2
3
|
export * from "./approvals-link.ts";
|
|
3
4
|
export * from "./approvals-store.ts";
|
|
4
5
|
export * from "./approvals-taint.ts";
|
|
@@ -36,6 +36,12 @@ export interface AskRequest {
|
|
|
36
36
|
* hide shell syntax (review #9). The human link denies without prompting.
|
|
37
37
|
*/
|
|
38
38
|
readonly unshowable?: true;
|
|
39
|
+
/**
|
|
40
|
+
* US-004: the call wants to run OUTSIDE the OS sandbox (the sandbox is never
|
|
41
|
+
* turned off for the whole session). A host that keys on it can offer a
|
|
42
|
+
* distinct decision; one that ignores it shows the ordinary approval prompt.
|
|
43
|
+
*/
|
|
44
|
+
readonly unsandboxed?: true;
|
|
39
45
|
/** The permitted root -- where the shell actually starts (src/tools/bash.ts:165). */
|
|
40
46
|
readonly root?: string;
|
|
41
47
|
/** The verdict's original reason, NOT rewritten as `matched ask rule "..."`. */
|
package/dist/sandbox/launcher.js
CHANGED
|
@@ -137,6 +137,9 @@ export function createCommandLauncher(opts) {
|
|
|
137
137
|
state,
|
|
138
138
|
async run(req) {
|
|
139
139
|
const tmpDir = env.tmpDir !== undefined && (await ensureTmpDir(env.tmpDir)) ? env.tmpDir : undefined;
|
|
140
|
+
if (req.unwrapped === true) {
|
|
141
|
+
return runUnwrapped(req, { backend: "none", wrapped: false, reason: "requested" }, { ...env, tmpDir });
|
|
142
|
+
}
|
|
140
143
|
if (state.kind === "disabled")
|
|
141
144
|
return runUnwrapped(req, { backend: "none", wrapped: false }, { ...env, tmpDir });
|
|
142
145
|
if (state.kind === "unavailable") {
|
package/dist/sandbox/types.d.ts
CHANGED
|
@@ -112,6 +112,8 @@ export interface LaunchRequest {
|
|
|
112
112
|
readonly stripEnvVars: readonly string[];
|
|
113
113
|
/** The CALLER's own overlay (Exec's Yarn no-scripts env). Never the backend's. */
|
|
114
114
|
readonly env?: Readonly<Record<string, string>>;
|
|
115
|
+
/** Explicitly run this command outside the sandbox without changing launcher state. */
|
|
116
|
+
readonly unwrapped?: true;
|
|
115
117
|
/** Aborts the run: forwarded to runArgv, which SIGKILLs the process group. US-001. */
|
|
116
118
|
readonly signal?: AbortSignal;
|
|
117
119
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ClaimedTurn, LiveTurn, TurnRunContext } from "./agent-session-turn.ts";
|
|
2
|
+
import type { CommandRunResult, SessionEvent } from "./agent-session-types.ts";
|
|
3
|
+
import type { OpenedBackend } from "./session-backend.ts";
|
|
4
|
+
interface CommandHooks {
|
|
5
|
+
onStart(live: LiveTurn): void;
|
|
6
|
+
onSettle(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface ClaimedCommand extends Pick<ClaimedTurn, "turnId" | "settled" | "cancel"> {
|
|
9
|
+
readonly result: Promise<CommandRunResult>;
|
|
10
|
+
}
|
|
11
|
+
/** Claim synchronously, but invoke callbacks only after the facade installs the claim. */
|
|
12
|
+
export declare function claimCommand(options: {
|
|
13
|
+
ctx: TurnRunContext;
|
|
14
|
+
run: NonNullable<OpenedBackend["runCommand"]>;
|
|
15
|
+
command: string;
|
|
16
|
+
onEvent(event: SessionEvent): void;
|
|
17
|
+
hooks: CommandHooks;
|
|
18
|
+
}): ClaimedCommand;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { NaxError } from "#src/infra/nax-error";
|
|
2
|
+
import { displayToolInput, toolResultPreview } from "#src/native/session/turn-event-emitter";
|
|
3
|
+
import { _agentSessionDeps } from "./agent-session-deps.js";
|
|
4
|
+
/** Claim synchronously, but invoke callbacks only after the facade installs the claim. */
|
|
5
|
+
export function claimCommand(options) {
|
|
6
|
+
const { ctx, run, command, onEvent, hooks } = options;
|
|
7
|
+
const turnId = _agentSessionDeps.randomUUID();
|
|
8
|
+
const callId = _agentSessionDeps.randomUUID();
|
|
9
|
+
const controller = new AbortController();
|
|
10
|
+
const emit = (body) => onEvent({
|
|
11
|
+
sessionId: ctx.sessionId,
|
|
12
|
+
turnId,
|
|
13
|
+
at: new Date(_agentSessionDeps.now()).toISOString(),
|
|
14
|
+
metadata: ctx.metadata,
|
|
15
|
+
...body,
|
|
16
|
+
});
|
|
17
|
+
const abort = (code, reason) => controller.abort(new NaxError(reason, code, { stage: "agent-session" }));
|
|
18
|
+
const result = Promise.resolve().then(async () => {
|
|
19
|
+
const timer = _agentSessionDeps.setTimeout(() => abort("AGENT_SESSION_TURN_TIMEOUT", "turn deadline"), ctx.turnTimeoutSeconds * 1000);
|
|
20
|
+
try {
|
|
21
|
+
hooks.onStart({ turnId, signal: controller.signal, emit });
|
|
22
|
+
emit({ type: "tool_call", name: "Bash", input: displayToolInput({ command }), callId });
|
|
23
|
+
const outcome = await run({ command, callId, signal: controller.signal });
|
|
24
|
+
emit({ type: "tool_result", callId, isError: outcome.isError, preview: toolResultPreview(outcome.content) });
|
|
25
|
+
return outcome;
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
_agentSessionDeps.clearTimeout(timer);
|
|
29
|
+
hooks.onSettle();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
turnId,
|
|
34
|
+
result,
|
|
35
|
+
settled: result.then(() => { }, () => { }),
|
|
36
|
+
cancel: (reason) => abort("AGENT_SESSION_CANCELLED", reason),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -117,6 +117,8 @@ export type SessionEventBody = {
|
|
|
117
117
|
readonly command?: string;
|
|
118
118
|
readonly reason: string;
|
|
119
119
|
readonly expiresAt: string;
|
|
120
|
+
/** US-004: the call wants to run outside the OS sandbox. Absent on every ordinary ask. */
|
|
121
|
+
readonly unsandboxed?: true;
|
|
120
122
|
/** `false`: decided already (by the profile); informational. Absent: a person's answer is awaited. */
|
|
121
123
|
readonly answerable?: false;
|
|
122
124
|
} | {
|
|
@@ -167,7 +169,14 @@ export type AnswerReply = {
|
|
|
167
169
|
readonly text: string;
|
|
168
170
|
};
|
|
169
171
|
export type AnswerStatus = "accepted" | "expired" | "cancelled" | "unknown";
|
|
172
|
+
export interface CommandRunResult {
|
|
173
|
+
/** The Bash tool's result text as the model would see it (capped by the tool runtime). */
|
|
174
|
+
readonly content: string;
|
|
175
|
+
readonly isError: boolean;
|
|
176
|
+
}
|
|
170
177
|
export interface AgentSession {
|
|
178
|
+
/** Run through the session's Bash tool without a model turn. The facade always provides this method. */
|
|
179
|
+
runCommand?(command: string, onEvent: (event: SessionEvent) => void): Promise<CommandRunResult>;
|
|
171
180
|
readonly id: string;
|
|
172
181
|
/** The backend that opened this session (`kind` and its capability summary). */
|
|
173
182
|
readonly backend: BackendInfo;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { claimCommand } from "./agent-session-command.js";
|
|
1
2
|
import { _agentSessionDeps } from "./agent-session-deps.js";
|
|
2
3
|
import { AgentSessionError } from "./agent-session-errors.js";
|
|
3
4
|
import { resolveAgentSessionOptions } from "./agent-session-options.js";
|
|
@@ -7,6 +8,17 @@ import { createPendingAskTable } from "./pending-asks.js";
|
|
|
7
8
|
import { createSessionAskPort } from "./session-ask-port.js";
|
|
8
9
|
/** The handler's turn signal between turns: never aborts. */
|
|
9
10
|
const IDLE_SIGNAL = new AbortController().signal;
|
|
11
|
+
/**
|
|
12
|
+
* The sandbox state as the embedder sees it: a frozen COPY, down to the
|
|
13
|
+
* `network` list an `available` state carries. Copying keeps the backend's own
|
|
14
|
+
* record out of the embedder's reach; freezing keeps the embedder from editing
|
|
15
|
+
* the record of what its commands ran under (US-001).
|
|
16
|
+
*/
|
|
17
|
+
function frozenSandbox(state) {
|
|
18
|
+
if (state.kind !== "available" || typeof state.network === "string")
|
|
19
|
+
return Object.freeze({ ...state });
|
|
20
|
+
return Object.freeze({ ...state, network: Object.freeze([...state.network]) });
|
|
21
|
+
}
|
|
10
22
|
class FacadeAgentSession {
|
|
11
23
|
parts;
|
|
12
24
|
active;
|
|
@@ -21,7 +33,13 @@ class FacadeAgentSession {
|
|
|
21
33
|
}
|
|
22
34
|
get backend() {
|
|
23
35
|
const info = this.parts.opened.info;
|
|
24
|
-
|
|
36
|
+
// US-001: the sandbox state rides through the facade frozen, so an embedder
|
|
37
|
+
// cannot edit the record of what its commands ran under.
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
kind: info.kind,
|
|
40
|
+
capabilities: Object.freeze({ ...info.capabilities }),
|
|
41
|
+
...(info.sandbox !== undefined ? { sandbox: frozenSandbox(info.sandbox) } : {}),
|
|
42
|
+
});
|
|
25
43
|
}
|
|
26
44
|
get lastTurn() {
|
|
27
45
|
return this.last;
|
|
@@ -49,6 +67,36 @@ class FacadeAgentSession {
|
|
|
49
67
|
this.active = turn;
|
|
50
68
|
return turn.iterable;
|
|
51
69
|
}
|
|
70
|
+
async runCommand(command, onEvent) {
|
|
71
|
+
const code = this.closing !== undefined
|
|
72
|
+
? "AGENT_SESSION_CLOSED"
|
|
73
|
+
: this.active !== undefined
|
|
74
|
+
? "AGENT_SESSION_BUSY"
|
|
75
|
+
: this.parts.opened.runCommand === undefined
|
|
76
|
+
? "AGENT_SESSION_CAPABILITY_UNSUPPORTED"
|
|
77
|
+
: undefined;
|
|
78
|
+
const run = this.parts.opened.runCommand;
|
|
79
|
+
if (code !== undefined || run === undefined) {
|
|
80
|
+
throw new AgentSessionError(`Session "${this.id}" cannot run a command`, code ?? "AGENT_SESSION_CAPABILITY_UNSUPPORTED", { sessionId: this.id });
|
|
81
|
+
}
|
|
82
|
+
const claim = claimCommand({
|
|
83
|
+
ctx: this.parts.ctx,
|
|
84
|
+
command,
|
|
85
|
+
onEvent,
|
|
86
|
+
run: (request) => run.call(this.parts.opened, request),
|
|
87
|
+
hooks: {
|
|
88
|
+
onStart: (live) => {
|
|
89
|
+
this.parts.slot.turn = live;
|
|
90
|
+
},
|
|
91
|
+
onSettle: () => {
|
|
92
|
+
this.parts.slot.turn = undefined;
|
|
93
|
+
this.active = undefined;
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
this.active = claim;
|
|
98
|
+
return claim.result;
|
|
99
|
+
}
|
|
52
100
|
answer(requestId, reply) {
|
|
53
101
|
return this.parts.table.answer(requestId, reply);
|
|
54
102
|
}
|
|
@@ -2,17 +2,30 @@ import type { BashApprovalMode } from "#src/config/bash-approval";
|
|
|
2
2
|
import type { NativeCatalogOverrides } from "#src/native/client";
|
|
3
3
|
import type { CredentialSource } from "#src/native/credentials/session-source";
|
|
4
4
|
import type { LoopHandlerSet } from "#src/native/session/loop-events/types";
|
|
5
|
+
import type { ToolProvider } from "#src/tools/provider-types";
|
|
5
6
|
import type { AgentSessionHostPorts, AgentSessionProfile } from "./agent-session-types.ts";
|
|
6
7
|
export interface NativeBackendOptions {
|
|
7
8
|
readonly model: string;
|
|
9
|
+
/** Static or discovered tool providers attached to this session's profile and stage. */
|
|
10
|
+
readonly toolProviders?: readonly ToolProvider[];
|
|
8
11
|
/** Repository instruction basename; defaults to AGENTS.md. */
|
|
9
12
|
readonly instructionFileName?: string;
|
|
10
13
|
readonly credentials?: CredentialSource;
|
|
11
14
|
readonly catalogOverrides?: NativeCatalogOverrides;
|
|
12
15
|
readonly loopHandlers?: LoopHandlerSet;
|
|
16
|
+
/** Copied into every turn's loop-handler context as `role` (for example "tui"). */
|
|
17
|
+
readonly loopHandlerRole?: string;
|
|
13
18
|
readonly hostPorts?: AgentSessionHostPorts;
|
|
14
19
|
readonly bashApproval?: BashApprovalMode;
|
|
15
20
|
readonly allowUnsandboxed?: boolean;
|
|
21
|
+
/** Narrow the declared tools to these names (built-in names, `<provider>__<tool>`, or `<provider>__*`); scratchpad tools are always kept. */
|
|
22
|
+
readonly allowedTools?: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* US-001: offer the Bash/Exec tools' `unsandboxed` argument, so a model can ask
|
|
25
|
+
* for one command to run outside the OS sandbox. Refused by the tool-less
|
|
26
|
+
* profiles, which have no shell to unwrap.
|
|
27
|
+
*/
|
|
28
|
+
readonly allowUnsandboxedCommands?: boolean;
|
|
16
29
|
/** Keep a resumed or continued conversation when the model differs (ACP server model switch, S5-3). */
|
|
17
30
|
readonly carryHistoryAcrossModels?: boolean;
|
|
18
31
|
/**
|
|
@@ -34,7 +47,10 @@ export interface ResolvedNativeOptions {
|
|
|
34
47
|
readonly provider: string;
|
|
35
48
|
}
|
|
36
49
|
export declare function parseNativeBackendOptions(input: unknown): ResolvedNativeOptions;
|
|
37
|
-
|
|
50
|
+
/** The profile's resolved knobs: the validator's answer, consumed as data. */
|
|
51
|
+
export interface ResolvedProfileRules {
|
|
38
52
|
readonly bashApproval: BashApprovalMode;
|
|
39
53
|
readonly allowUnsandboxed: boolean;
|
|
40
|
-
|
|
54
|
+
readonly allowUnsandboxedCommands: boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare function nativeProfileRules(profile: AgentSessionProfile, raw: NativeBackendOptions): ResolvedProfileRules;
|