@nathapp/nax-agent 0.2.0 → 0.3.1
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 +36 -0
- package/README.md +22 -13
- package/dist/index.d.ts +15 -5
- package/dist/index.js +10 -2
- package/dist/infra/stderr-tail.d.ts +8 -0
- package/dist/infra/stderr-tail.js +48 -0
- package/dist/native/index.d.ts +1 -1
- package/dist/native/session/transcript-types.d.ts +16 -0
- package/dist/native/session/turn-types.d.ts +4 -5
- package/dist/native/session/turn-types.js +8 -8
- package/dist/permissions/ask-chain.d.ts +1 -1
- package/dist/permissions/ask.d.ts +6 -0
- package/dist/permissions/ask.js +6 -0
- package/dist/permissions/index.d.ts +1 -1
- package/dist/permissions/index.js +1 -1
- package/dist/session/agent-session-errors.d.ts +1 -1
- package/dist/session/agent-session-options.d.ts +0 -4
- package/dist/session/agent-session-options.js +7 -48
- package/dist/session/agent-session-resume.d.ts +3 -1
- package/dist/session/agent-session-resume.js +10 -8
- package/dist/session/agent-session-turn.d.ts +3 -7
- package/dist/session/agent-session-turn.js +14 -9
- package/dist/session/agent-session-types.d.ts +22 -22
- package/dist/session/agent-session.js +51 -90
- package/dist/session/native-backend-options.d.ts +24 -0
- package/dist/session/native-backend-options.js +81 -0
- package/dist/session/native-backend.d.ts +4 -0
- package/dist/session/native-backend.js +106 -0
- package/dist/session/session-ask-link.d.ts +12 -5
- package/dist/session/session-ask-link.js +3 -2
- package/dist/session/session-ask-port.d.ts +12 -0
- package/dist/session/session-ask-port.js +64 -0
- package/dist/session/session-backend.d.ts +79 -0
- package/dist/session/session-backend.js +1 -0
- package/dist/session/session-interaction.d.ts +2 -2
- package/dist/session/session-interaction.js +3 -6
- package/dist/session/session-tool-support.d.ts +5 -5
- package/dist/session/session-tool-support.js +12 -9
- package/dist/session/session-types.d.ts +12 -0
- package/dist/session/turn-event.d.ts +12 -0
- package/dist/session/turn-spend.d.ts +18 -0
- package/dist/session/turn-spend.js +9 -0
- package/dist/tools/ask-request.js +3 -1
- package/dist/tools/index.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ 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.3.1] - 2026-10-07
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `attachTurnSpend(err, spend)` and `readTurnSpend(err)`, with the `FailedTurnSpend` type: a backend attaches the spend a failed turn had already incurred to the error it throws, and the turn's `turn_end` reports it (#2367).
|
|
12
|
+
- `OpenSessionOpts.toolAudit` (optional `{ dir, header }`): the tool-audit ledger location and header for an S1 adapter that writes its own ledger (nax's ACP adapter, S4b). nax-agent itself does not read it; native takes its sink from coding-tool support.
|
|
13
|
+
- `resultBytes` (optional) on the `tool_result` turn event: the UTF-8 byte length of the full result before the preview cap.
|
|
14
|
+
- `ToolAuditHeader` is exported from the package entry.
|
|
15
|
+
- `AGENT_SESSION_RATE_LIMITED` error code (a backend's rate-limited turn).
|
|
16
|
+
- `tool_progress` turn event: a running tool's liveness beat (no content), for S1 callers such as nax's idle watchdog. The session facade does not forward it as a session event.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- `turn_end` of an errored, cancelled or timed-out turn carries `costSource` when the failed turn's spend says how it was priced (#2367).
|
|
21
|
+
|
|
22
|
+
## [0.3.0] - 2026-10-06
|
|
23
|
+
|
|
24
|
+
The backend seam for S4. Breaking: `createAgentSession` takes a `SessionBackend`. nax behaviour unchanged.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **Breaking:** `CreateAgentSessionOptions.backend` is a `SessionBackend` (was `"native"`). `model`, `credentials`, `catalogOverrides`, `loopHandlers`, `hostPorts`, `bashApproval` and `allowUnsandboxed` move into `nativeBackend({ ... })`. A native-only key at the top level is `AGENT_SESSION_INVALID_OPTIONS`.
|
|
29
|
+
- `resumeAgentSession` refuses a document written by another backend kind (`AGENT_SESSION_BACKEND_MISMATCH`); documents without a `backend` field are native.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- `SessionBackend`, `BackendOpenContext`, `OpenedBackend`, `BackendInfo`, `TurnContribution`, `SessionAskPort`, `ApprovalRequest`, and `nativeBackend` with `NativeBackendOptions`. `AgentSession.backend` reports the backend's kind and capabilities.
|
|
34
|
+
- The `ask` profile: every Write, Edit, Delete, GitCommit and Bash is approved through `answer()`; it requires `bashApproval: "gated"` and the sandbox floor of `full`.
|
|
35
|
+
- `ApprovalDecidedBy` gains `"profile"`; `usage` and `turn_end` gain `costSource` (`computed` | `reported` | `unpriced`; `CostSource`); `TurnResult` gains `costSource`.
|
|
36
|
+
- Error codes `AGENT_SESSION_BACKEND_UNAVAILABLE`, `AGENT_SESSION_AUTH_REQUIRED`, `AGENT_SESSION_CAPABILITY_UNSUPPORTED`, `AGENT_SESSION_BACKEND_MISMATCH`.
|
|
37
|
+
- `TranscriptDoc.backend` and `TranscriptDoc.acp` (`TranscriptAcpRecord`), optional and additive (schemaVersion stays 1).
|
|
38
|
+
- `TranscriptAcpRecord.costUsd`: the ACP agent's cumulative cost reading at the session's last priced turn, so a resumed ACP session prices its next turn from it.
|
|
39
|
+
- Backend kit on `.`: `redactSecrets`, `capStrings`, `killProcessGroup`, `isProcessAlive`, `TOOL_CALL_INPUT_BYTES`, `TOOL_RESULT_PREVIEW_BYTES`, `createStderrTail` (`StderrTail`), and `NaxError`, the base class of `AgentSessionError`, so a backend can throw codes outside `AgentSessionErrorCode` (S4 spec §5.7).
|
|
40
|
+
- `getLogger` on `.`: the logger the host installed with `setAgentLogger`, or a silent no-op, so a backend can log through the host's logger.
|
|
41
|
+
- `SessionAskPort.askQuestion(text, { signal })`: an extra abort source combined with the turn signal, as `ApprovalRequest.signal` is for approvals, so a backend can settle a question when its own request scope ends (S4 spec §6.3 step 5).
|
|
42
|
+
|
|
7
43
|
## [0.2.0] - 2026-10-05
|
|
8
44
|
|
|
9
45
|
The conversational session API for embedders. nax behaviour unchanged.
|
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ Three pieces of host knowledge are passed in as data or functions, because the p
|
|
|
42
42
|
`createAgentSession` gives an embedder (for example a long-running Node service) a multi-turn chat with a person in the loop. Events stream, tools come from the embedder, history lives in a store the embedder supplies, and a turn can be cancelled or answered with an approval.
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
|
-
import { createAgentSession, createFileTranscriptStore, type EmbedderTool } from "@nathapp/nax-agent";
|
|
45
|
+
import { createAgentSession, createFileTranscriptStore, type EmbedderTool, nativeBackend } from "@nathapp/nax-agent";
|
|
46
46
|
|
|
47
47
|
const lookupOrder: EmbedderTool = {
|
|
48
48
|
name: "lookup_order",
|
|
@@ -55,14 +55,11 @@ const lookupOrder: EmbedderTool = {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
const session = await createAgentSession({
|
|
58
|
-
backend: "
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
profile: "none", // "none" | "read" | "full"
|
|
62
|
-
instructions: "You are a support assistant.",
|
|
58
|
+
backend: nativeBackend({ model: "anthropic/claude-sonnet-5-5" }),
|
|
59
|
+
profile: "ask",
|
|
60
|
+
workdir: "/abs/project",
|
|
63
61
|
tools: [lookupOrder],
|
|
64
|
-
transcriptStore: createFileTranscriptStore("/
|
|
65
|
-
credentials: { kind: "memory", credentials: { anthropic: { kind: "api-key", key: process.env.ANTHROPIC_API_KEY! } } },
|
|
62
|
+
transcriptStore: createFileTranscriptStore("/abs/state/sessions"),
|
|
66
63
|
});
|
|
67
64
|
|
|
68
65
|
for await (const event of session.send("Where is order 42?")) {
|
|
@@ -73,18 +70,30 @@ for await (const event of session.send("Where is order 42?")) {
|
|
|
73
70
|
await session.close();
|
|
74
71
|
```
|
|
75
72
|
|
|
73
|
+
Profiles set what a session may do:
|
|
74
|
+
|
|
75
|
+
| Profile | Side effects |
|
|
76
|
+
|:--------|:-------------|
|
|
77
|
+
| `none` | no side effects; |
|
|
78
|
+
| `read` | read-only; |
|
|
79
|
+
| `ask` | every Write, Edit, Delete, GitCommit and Bash is put to `answer()`; |
|
|
80
|
+
| `full` | no prompts; `bashApproval` and the sandbox floor apply. |
|
|
81
|
+
|
|
82
|
+
`createAgentSession` takes a `SessionBackend`. `nativeBackend(opts)` takes `model`, `credentials`, `catalogOverrides`, `loopHandlers`, `hostPorts`, `bashApproval` and `allowUnsandboxed`. The ACP backend ships in `@nathapp/nax-agent-acp`.
|
|
83
|
+
|
|
84
|
+
`usage.costSource` is `computed` (native), `reported` or `unpriced`; never sum `unpriced` rows as cost.
|
|
85
|
+
|
|
76
86
|
- **One turn at a time.** `send()` claims the session's turn slot at once. A second `send()` while a turn runs throws `AGENT_SESSION_BUSY`. The returned iterable is single-use, and the turn starts on its first `next()`. Breaking out of the loop cancels the turn.
|
|
77
|
-
- **Events.** `turn_start`, `text_delta`, `thinking_delta`, `stream_reset`, `tool_call`, `tool_result`, `approval_requested`, `approval_resolved`, `question`, `usage`, `compaction` and `turn_end`.
|
|
87
|
+
- **Events.** `turn_start`, `text_delta`, `thinking_delta`, `stream_reset`, `tool_call`, `tool_result`, `approval_requested`, `approval_resolved`, `question`, `usage`, `compaction` and `turn_end`. Sessions do not compact, so `compaction` is not emitted and a conversation that outgrows the model's context window ends `errored`. Each carries `sessionId`, `turnId`, `at` and your `metadata`. `turn_end` is always last, and a failed turn arrives as `turn_end`, never as a throw.
|
|
78
88
|
- **Deltas are provisional.** `stream_reset` means the deltas of that round so far are void: the provider call was retried after a transient fault (up to 3 attempts; a rate-limit retry waits the provider's `retryAfter` silently, and `cancel()` ends the wait). `turn_end.output` and the stored transcript are authoritative. While your consumer lags, adjacent deltas are merged; control events are never merged or dropped.
|
|
79
89
|
- **Approvals and questions.** Answer them with `session.answer(requestId, { decision: "allow" | "deny" })` or `{ text }`. An unanswered one is denied after `approvalTimeoutMs` (default 600000, range 30000..3600000). `answer` returns `"accepted"`, `"expired"`, `"cancelled"` or `"unknown"`.
|
|
80
|
-
- **Profiles.** `none` gives your tools, a private scratchpad and `ask_human`. `read` adds Read, Glob, Grep and read-only Git over `workdir`. `full` adds writes and Bash, under the OS sandbox and `bashApproval` (default `"gated"`: every command is put to the person).
|
|
81
90
|
- **Credentials.** A session's `credentials` (`memory` or `exec`) and `catalogOverrides` give it its own client. Without them it uses the process-wide `configureCredentials` slot.
|
|
82
|
-
- **History and restarts.** The store holds one document per session, saved at the end of every turn. `close()` keeps it. After a restart, `resumeAgentSession(sessionId, options)` reopens it with the same options you created it with; pass `instructions` and `tools` again, since they are not stored. If the process died mid-turn, `session.lastTurn` is `{ turnId, status: "interrupted" }`, and that turn's message is not in history. A resume with a different model throws `AGENT_SESSION_MODEL_MISMATCH`; a different reasoning effort (`[high]`) is the same model. Do not open one session id twice at once: the store has no lock.
|
|
83
|
-
- **Errors.** Every error is an `AgentSessionError` with a code `AGENT_SESSION_*`: `INVALID_OPTIONS`, `EXISTS`, `BUSY`, `CLOSED`, `INVALID_ANSWER`, `NOT_FOUND`, `SCHEMA_UNSUPPORTED`, `MODEL_MISMATCH`, `SANDBOX_UNAVAILABLE` or `
|
|
91
|
+
- **History and restarts.** The store holds one document per session, saved at the end of every turn. `close()` keeps it. After a restart, `resumeAgentSession(sessionId, options)` reopens it with the same options you created it with; pass `instructions` and `tools` again, since they are not stored. If the process died mid-turn, `session.lastTurn` is `{ turnId, status: "interrupted" }`, and that turn's message is not in history. A resume with a different model throws `AGENT_SESSION_MODEL_MISMATCH`; a different reasoning effort (`[high]`) is the same model. Resuming with a different backend kind throws `AGENT_SESSION_BACKEND_MISMATCH`; a stored document with no `backend` field is native. Do not open one session id twice at once: the store has no lock.
|
|
92
|
+
- **Errors.** Every error is an `AgentSessionError` with a code `AGENT_SESSION_*`: `INVALID_OPTIONS`, `EXISTS`, `BUSY`, `CLOSED`, `INVALID_ANSWER`, `NOT_FOUND`, `SCHEMA_UNSUPPORTED`, `MODEL_MISMATCH`, `SANDBOX_UNAVAILABLE`, `TOOL_NAME_RESERVED`, `BACKEND_UNAVAILABLE`, `AUTH_REQUIRED`, `CAPABILITY_UNSUPPORTED` or `BACKEND_MISMATCH`. A stored document that cannot be read is a `NaxError` with `TRANSCRIPT_CORRUPT`.
|
|
84
93
|
|
|
85
94
|
## Status and roadmap
|
|
86
95
|
|
|
87
|
-
`0.x` may reshape `.` with a minor bump.
|
|
96
|
+
`0.x` may reshape `.` with a minor bump. `@nathapp/nax-agent-acp` provides an ACP backend for the same API (0.3.0). See [`CHANGELOG.md`](CHANGELOG.md).
|
|
88
97
|
|
|
89
98
|
Maintainers: see the [release procedure](https://github.com/nathapp-io/nax/blob/main/packages/nax-agent/RELEASING.md)
|
|
90
99
|
for the manual 0.1.0 publish and OTP step, trusted-publisher setup and subsequent tagged releases.
|
package/dist/index.d.ts
CHANGED
|
@@ -12,24 +12,34 @@ export { appendCommandSafetyRow, type BuildCommandShadowOptions, buildCommandSha
|
|
|
12
12
|
export { addTokenUsage, estimateCostUsd, inputClassTokens, type Pricing, type PricingRates, type PricingTier, priceCall, type TokenUsage, } from "#src/cost/core/index";
|
|
13
13
|
export { type ModelSpec, parseModelSpec, } from "#src/cost/model-spec";
|
|
14
14
|
export type { AgentLogger, CredentialAuthConfig, CredentialsConfig } from "#src/infra/index";
|
|
15
|
-
export { configureCredentials, setAgentLogger } from "#src/infra/index";
|
|
15
|
+
export { configureCredentials, getLogger, setAgentLogger } from "#src/infra/index";
|
|
16
|
+
export { createStderrTail, type StderrTail } from "#src/infra/stderr-tail";
|
|
17
|
+
export { isProcessAlive } from "#src/internal/process-alive";
|
|
18
|
+
export { killProcessGroup } from "#src/internal/process-kill";
|
|
19
|
+
export { capStrings, redactSecrets } from "#src/internal/redact";
|
|
20
|
+
export { NaxError } from "#src/infra/nax-error";
|
|
16
21
|
export type { CredentialSource } from "#src/native/credentials/session-source";
|
|
17
|
-
export { AuthCancelledError, type AuthEvent, type AuthInteraction, type AuthLink, type AuthMethod, type AuthOption, type AuthPrompt, type AuthResult, ambientShadows, anyAmbientCredential, authImportOutcomeLabel, createFileTranscriptStore, createMemoryTranscriptStore, credentialFilePath, DEFAULT_PI_AUTH_PATH, type ImportOutcome, importPiCredentials, listStoredProviders, MAX_RETAINED_TRANSCRIPTS, type MemoryTranscriptStore, NATIVE_AGENT, type NativeCatalogOverrides, type NativeCompleteContext, type NativeCompleteOptions, type NativeCompleteResult, NativeSessionAdapter, NativeSessionUnsupportedError, type NativeTierConfig, nativeComplete, nativeTierProviders, naxCredentialStore, newSessionKey, providersWithoutCredentials, pruneRetainedTranscripts, type ResolveResult, type ResolveStatus, removeStoredProvider, resolveNativeId, runLogin, type StoredEntry, servedAuth, type TranscriptDoc, type TranscriptStore, type TurnMarker, } from "#src/native/index";
|
|
22
|
+
export { AuthCancelledError, type AuthEvent, type AuthInteraction, type AuthLink, type AuthMethod, type AuthOption, type AuthPrompt, type AuthResult, ambientShadows, anyAmbientCredential, authImportOutcomeLabel, createFileTranscriptStore, createMemoryTranscriptStore, credentialFilePath, DEFAULT_PI_AUTH_PATH, type ImportOutcome, importPiCredentials, listStoredProviders, MAX_RETAINED_TRANSCRIPTS, type MemoryTranscriptStore, NATIVE_AGENT, type NativeCatalogOverrides, type NativeCompleteContext, type NativeCompleteOptions, type NativeCompleteResult, NativeSessionAdapter, NativeSessionUnsupportedError, type NativeTierConfig, nativeComplete, nativeTierProviders, naxCredentialStore, newSessionKey, providersWithoutCredentials, pruneRetainedTranscripts, type ResolveResult, type ResolveStatus, removeStoredProvider, resolveNativeId, runLogin, type StoredEntry, servedAuth, type TranscriptAcpRecord, type TranscriptDoc, type TranscriptStore, type TurnMarker, } from "#src/native/index";
|
|
18
23
|
export type { NativeSessionAdapterOptions } from "#src/native/session-adapter";
|
|
19
24
|
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";
|
|
20
|
-
export {
|
|
25
|
+
export { TOOL_CALL_INPUT_BYTES, TOOL_RESULT_PREVIEW_BYTES } from "#src/native/session/turn-event-emitter";
|
|
26
|
+
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";
|
|
21
27
|
export { type AgentGlobOptions, type AgentRuntime, type AgentSpawnOptions, type AgentSpawnResult, type AgentSpawnStdin, getAgentRuntime, nodeRuntime, setAgentRuntime, } from "#src/runtime/index";
|
|
22
28
|
export { buildSandboxPolicy, type CommandLauncher, type CommandLauncherOptions, createCommandLauncher, createSrtBackend, DISABLED_SANDBOX_STATE, 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, sandboxBackendFor, sandboxSentence, sessionTmpDir, sessionTmpDirUnder, strayCommonDirTripwire, unsandboxedSentence, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
|
|
23
29
|
export type { AdapterFailure } from "#src/session/adapter-failure";
|
|
24
30
|
export { createAgentSession, resumeAgentSession } from "#src/session/agent-session";
|
|
25
31
|
export { AgentSessionError, type AgentSessionErrorCode } from "#src/session/agent-session-errors";
|
|
26
|
-
export type { AgentSession, AgentSessionHostPorts, AgentSessionProfile, AnswerReply, AnswerStatus, ApprovalDecidedBy, CreateAgentSessionOptions, EmbedderTool, EmbedderToolContext, EmbedderToolResult, SessionEvent, SessionEventBase, SessionEventBody, TurnEndStatus, } from "#src/session/agent-session-types";
|
|
32
|
+
export type { AgentSession, AgentSessionHostPorts, AgentSessionProfile, AnswerReply, AnswerStatus, ApprovalDecidedBy, CostSource, CreateAgentSessionOptions, EmbedderTool, EmbedderToolContext, EmbedderToolResult, SessionEvent, SessionEventBase, SessionEventBody, TurnEndStatus, } from "#src/session/agent-session-types";
|
|
27
33
|
export type { AgentAwaitingHumanEvent, AgentCallEndedEvent, AgentCallStartedEvent, AgentMessageUpdateEvent, AgentProcessUpdateEvent, AgentStreamEvent, AgentStreamEventBase, AgentThinkingUpdateEvent, AgentToolCallUpdateEvent, AgentUsageUpdateEvent, } from "#src/session/agent-stream-events";
|
|
28
34
|
export { type AdapterInteraction, type AdapterInteractionResponse, type InteractionHandler, NO_OP_INTERACTION_HANDLER, } from "#src/session/interaction-handler";
|
|
35
|
+
export { nativeBackend } from "#src/session/native-backend";
|
|
36
|
+
export type { NativeBackendOptions } from "#src/session/native-backend-options";
|
|
29
37
|
export type { ProtocolIds } from "#src/session/protocol-types";
|
|
38
|
+
export type { ApprovalRequest, BackendInfo, BackendOpenContext, OpenedBackend, SessionAskPort, SessionBackend, TurnContribution, } from "#src/session/session-backend";
|
|
30
39
|
export { type AgentSessionAdapter, type AuthStamp, type InteractionExchange, type InvalidToolCallDetail, type OpenSessionOpts, type SendTurnOpts, type SessionHandle, type SessionModel, SessionTurnError, type TrackedSpawnDeadlineOptions, type TurnResult, } from "#src/session/session-types";
|
|
40
|
+
export { attachTurnSpend, type FailedTurnSpend, readTurnSpend } from "#src/session/turn-spend";
|
|
31
41
|
export type { JSONSchema, ToolDescriptor, } from "#src/session/tool-descriptor";
|
|
32
42
|
export { createTurnDeadline, type TurnDeadline, } from "#src/session/turn-deadline";
|
|
33
43
|
export type { TurnEvent, TurnEventSink } from "#src/session/turn-event";
|
|
34
|
-
export { adaptProviderTool, advertisedSchemaBytes, applyModelTruncationPolicy, BASH_TIMEOUT_MS, BASH_TOOL_NAME, buildCommitArgvs, buildGitArgv, buildGrepArgv, type CodingTool, type CodingToolName, type CodingToolOutcome, type CodingToolRuntime, classifyExec, compileToolPolicy, createBashTool, createCodingToolRuntime, createNoOpToolAuditSink, createRunCommandTool, createToolAuditSink, cutBufferToByteCap, DEFAULT_BASH_SHELL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_MAX_COUNT, DEFAULT_TOOL_MAX_BYTES, DEFAULT_TOOL_MAX_FILE_BYTES, type DeclaredCommandRequest, type DeclaredCommandResult, type DeclaredCommandRunner, deleteTool, EXEC_TOOL_NAME, type ExecTarget, editTool, expandMcpRuleGrants, expandProviderGrants, flushOpenToolAuditSinks, GIT_ESCAPE_FLAGS, GIT_READ_VERBS, getCodingTool, gitCommitTool, gitExcludePathspecsOf, gitIgnorePatternsOf, gitTool, globTool, grepTool, isKnownManager, listCodingTools, MAX_PROVIDER_DESCRIPTION_BYTES, MAX_PROVIDER_SCHEMA_BYTES, MCP_RULE_TOOL, MODEL_MAX_BYTES, MODEL_MAX_LINE_CHARS, MODEL_MAX_LINES, type ModelTruncationOptions, mcpRuleAdmits, type NormalizeInput, type NormalizeResult, namespacedToolName, narrowGrants, normalizeExec, normalizeManagerBinary, type PolicyVerdict, PROVIDER_ID_RE, type ProtectedPathsPolicy, type ProviderGrantEntry, type ProviderKind, type ProviderTool, partitionMcpRules, partitionNaxOwnedPaths, providerAttachesTo, READ_CEILING, RESERVED_TOOL_NAMES, type ReadFileSliceOptions, type ReadFileSliceResult, type RegisteredSink, type ResolvedProviderTools, readFileSlice, readTool, registerBuiltinCodingTools, registerBuiltinTool, registerCodingTool, registerToolAuditSink, requestCapabilityTool, resolveProviderTools, resolveWithin, SCRATCHPAD_DIR, SPILL_DIR, type SpillRequest, sanitizeProviderTools, scratchpadListTool, scratchpadReadTool, scratchpadWriteTool, spillRelativePath, substituteCommand, substituteCommandSpec, type ToolAuditSink, type ToolCallContext, type ToolCallRecord, type ToolGrant, type ToolPatternNarrowing, type ToolPolicy, type ToolPolicyOptions, type ToolProvider, type ToolResult, type ToolRunContext, type ToolScope, type TruncateForModelOptions, type TruncationDirection, type TruncationResult, truncateForModel, truncationDirectionFor, unregisterToolAuditSink, validateProviderId, writeSpill, writeTool, } from "#src/tools/index";
|
|
44
|
+
export { adaptProviderTool, advertisedSchemaBytes, applyModelTruncationPolicy, BASH_TIMEOUT_MS, BASH_TOOL_NAME, buildCommitArgvs, buildGitArgv, buildGrepArgv, type CodingTool, type CodingToolName, type CodingToolOutcome, type CodingToolRuntime, classifyExec, compileToolPolicy, createBashTool, createCodingToolRuntime, createNoOpToolAuditSink, createRunCommandTool, createToolAuditSink, cutBufferToByteCap, DEFAULT_BASH_SHELL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_MAX_COUNT, DEFAULT_TOOL_MAX_BYTES, DEFAULT_TOOL_MAX_FILE_BYTES, type DeclaredCommandRequest, type DeclaredCommandResult, type DeclaredCommandRunner, deleteTool, EXEC_TOOL_NAME, type ExecTarget, editTool, expandMcpRuleGrants, expandProviderGrants, flushOpenToolAuditSinks, GIT_ESCAPE_FLAGS, GIT_READ_VERBS, getCodingTool, gitCommitTool, gitExcludePathspecsOf, gitIgnorePatternsOf, gitTool, globTool, grepTool, isKnownManager, listCodingTools, MAX_PROVIDER_DESCRIPTION_BYTES, MAX_PROVIDER_SCHEMA_BYTES, MCP_RULE_TOOL, MODEL_MAX_BYTES, MODEL_MAX_LINE_CHARS, MODEL_MAX_LINES, type ModelTruncationOptions, mcpRuleAdmits, type NormalizeInput, type NormalizeResult, namespacedToolName, narrowGrants, normalizeExec, normalizeManagerBinary, type PolicyVerdict, PROVIDER_ID_RE, type ProtectedPathsPolicy, type ProviderGrantEntry, type ProviderKind, type ProviderTool, partitionMcpRules, partitionNaxOwnedPaths, providerAttachesTo, READ_CEILING, RESERVED_TOOL_NAMES, type ReadFileSliceOptions, type ReadFileSliceResult, type RegisteredSink, type ResolvedProviderTools, readFileSlice, readTool, registerBuiltinCodingTools, registerBuiltinTool, registerCodingTool, registerToolAuditSink, requestCapabilityTool, resolveProviderTools, resolveWithin, SCRATCHPAD_DIR, SPILL_DIR, type SpillRequest, sanitizeProviderTools, scratchpadListTool, scratchpadReadTool, scratchpadWriteTool, spillRelativePath, substituteCommand, substituteCommandSpec, type ToolAuditHeader, type ToolAuditSink, type ToolCallContext, type ToolCallRecord, type ToolGrant, type ToolPatternNarrowing, type ToolPolicy, type ToolPolicyOptions, type ToolProvider, type ToolResult, type ToolRunContext, type ToolScope, type TruncateForModelOptions, type TruncationDirection, type TruncationResult, truncateForModel, truncationDirectionFor, unregisterToolAuditSink, validateProviderId, writeSpill, writeTool, } from "#src/tools/index";
|
|
35
45
|
export { EMPTY_OWNED_PATHS_POLICY, type OwnedBashCandidate, type OwnedPathsPolicy, } from "#src/tools/owned-paths";
|
package/dist/index.js
CHANGED
|
@@ -10,15 +10,23 @@
|
|
|
10
10
|
export { appendCommandSafetyRow, buildCommandShadow, buildRequest, COMMAND_SAFETY_DIR, createCommandGuard, createCommandShadow, createSystemOneClient, detectTmpWrite, HARM_OPTIONS, HARM_QUESTION_ID, isTempOnly, openShadowTap, parseAnswer, QUESTION_IDS, QUESTION_SET_VERSION, RULE_SET_VERSION, SYSTEMONE_MODEL_LABEL, scoreGuard, scoreRules, shadowCacheKey, toMechanical, } from "#src/command-safety/index";
|
|
11
11
|
export { addTokenUsage, estimateCostUsd, inputClassTokens, priceCall, } from "#src/cost/core/index";
|
|
12
12
|
export { parseModelSpec, } from "#src/cost/model-spec";
|
|
13
|
-
export { configureCredentials, setAgentLogger } from "#src/infra/index";
|
|
13
|
+
export { configureCredentials, getLogger, setAgentLogger } from "#src/infra/index";
|
|
14
|
+
export { createStderrTail } from "#src/infra/stderr-tail";
|
|
15
|
+
export { isProcessAlive } from "#src/internal/process-alive";
|
|
16
|
+
export { killProcessGroup } from "#src/internal/process-kill";
|
|
17
|
+
export { capStrings, redactSecrets } from "#src/internal/redact";
|
|
18
|
+
export { NaxError } from "#src/infra/nax-error";
|
|
14
19
|
export { AuthCancelledError, ambientShadows, anyAmbientCredential, authImportOutcomeLabel, createFileTranscriptStore, createMemoryTranscriptStore, credentialFilePath, DEFAULT_PI_AUTH_PATH, importPiCredentials, listStoredProviders, MAX_RETAINED_TRANSCRIPTS, NATIVE_AGENT, NativeSessionAdapter, NativeSessionUnsupportedError, nativeComplete, nativeTierProviders, naxCredentialStore, newSessionKey, providersWithoutCredentials, pruneRetainedTranscripts, removeStoredProvider, resolveNativeId, runLogin, servedAuth, } from "#src/native/index";
|
|
15
|
-
export {
|
|
20
|
+
export { TOOL_CALL_INPUT_BYTES, TOOL_RESULT_PREVIEW_BYTES } from "#src/native/session/turn-event-emitter";
|
|
21
|
+
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";
|
|
16
22
|
export { getAgentRuntime, nodeRuntime, setAgentRuntime, } from "#src/runtime/index";
|
|
17
23
|
export { buildSandboxPolicy, createCommandLauncher, createSrtBackend, DISABLED_SANDBOX_STATE, defaultTempRoots, denialHintLine, LIKELY_SANDBOX_DENIAL, listCredentialFiles, listGitGuardFiles, listNaxEntries, probeSandbox, probeSandboxOnce, quoteArgvForShell, rawBashRefusalReason, resetSandboxBackend, resolveGitLayout, runTempRoots, runTmpRoot, sandboxBackendFor, sandboxSentence, sessionTmpDir, sessionTmpDirUnder, strayCommonDirTripwire, unsandboxedSentence, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
|
|
18
24
|
export { createAgentSession, resumeAgentSession } from "#src/session/agent-session";
|
|
19
25
|
export { AgentSessionError } from "#src/session/agent-session-errors";
|
|
20
26
|
export { NO_OP_INTERACTION_HANDLER, } from "#src/session/interaction-handler";
|
|
27
|
+
export { nativeBackend } from "#src/session/native-backend";
|
|
21
28
|
export { SessionTurnError, } from "#src/session/session-types";
|
|
29
|
+
export { attachTurnSpend, readTurnSpend } from "#src/session/turn-spend";
|
|
22
30
|
export { createTurnDeadline, } from "#src/session/turn-deadline";
|
|
23
31
|
export { adaptProviderTool, advertisedSchemaBytes, applyModelTruncationPolicy, BASH_TIMEOUT_MS, BASH_TOOL_NAME, buildCommitArgvs, buildGitArgv, buildGrepArgv, classifyExec, compileToolPolicy, createBashTool, createCodingToolRuntime, createNoOpToolAuditSink, createRunCommandTool, createToolAuditSink, cutBufferToByteCap, DEFAULT_BASH_SHELL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_MAX_COUNT, DEFAULT_TOOL_MAX_BYTES, DEFAULT_TOOL_MAX_FILE_BYTES, deleteTool, EXEC_TOOL_NAME, editTool, expandMcpRuleGrants, expandProviderGrants, flushOpenToolAuditSinks, GIT_ESCAPE_FLAGS, GIT_READ_VERBS, getCodingTool, gitCommitTool, gitExcludePathspecsOf, gitIgnorePatternsOf, gitTool, globTool, grepTool, isKnownManager, listCodingTools, MAX_PROVIDER_DESCRIPTION_BYTES, MAX_PROVIDER_SCHEMA_BYTES, MCP_RULE_TOOL, MODEL_MAX_BYTES, MODEL_MAX_LINE_CHARS, MODEL_MAX_LINES, mcpRuleAdmits, namespacedToolName, narrowGrants, normalizeExec, normalizeManagerBinary, PROVIDER_ID_RE, partitionMcpRules, partitionNaxOwnedPaths, providerAttachesTo, READ_CEILING, RESERVED_TOOL_NAMES, readFileSlice, readTool, registerBuiltinCodingTools, registerBuiltinTool, registerCodingTool, registerToolAuditSink, requestCapabilityTool, resolveProviderTools, resolveWithin, SCRATCHPAD_DIR, SPILL_DIR, sanitizeProviderTools, scratchpadListTool, scratchpadReadTool, scratchpadWriteTool, spillRelativePath, substituteCommand, substituteCommandSpec, truncateForModel, truncationDirectionFor, unregisterToolAuditSink, validateProviderId, writeSpill, writeTool, } from "#src/tools/index";
|
|
24
32
|
export { EMPTY_OWNED_PATHS_POLICY, } from "#src/tools/owned-paths";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bounded tail of a child process's stderr (S4 spec 5.6, 7). Backends keep
|
|
3
|
+
* the last bytes for error excerpts; excerpt() strips control characters,
|
|
4
|
+
* redacts caller-known secrets and known token shapes, and returns at most
|
|
5
|
+
* maxBytes from the end, so an error never carries a raw agent log.
|
|
6
|
+
*/
|
|
7
|
+
import { redactSecrets } from "#src/internal/redact";
|
|
8
|
+
const DEFAULT_CAPACITY = 65_536;
|
|
9
|
+
const DEFAULT_EXCERPT = 4096;
|
|
10
|
+
const MIN_SECRET_LENGTH = 4;
|
|
11
|
+
// C0 controls and DEL, except tab (\u0009) and newline (\u000A).
|
|
12
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control characters is the point of this regex
|
|
13
|
+
const CONTROL = /[\u0000-\u0008\u000B-\u001F\u007F]/g;
|
|
14
|
+
function lastBytes(text, maxBytes) {
|
|
15
|
+
const bytes = Buffer.from(text, "utf8");
|
|
16
|
+
if (bytes.byteLength <= maxBytes)
|
|
17
|
+
return text;
|
|
18
|
+
// A cut inside a multi-byte character decodes to U+FFFD; drop it.
|
|
19
|
+
return bytes
|
|
20
|
+
.subarray(bytes.byteLength - maxBytes)
|
|
21
|
+
.toString("utf8")
|
|
22
|
+
.replace(/^�+/, "");
|
|
23
|
+
}
|
|
24
|
+
function scrub(text, secrets) {
|
|
25
|
+
let out = text.replace(CONTROL, "");
|
|
26
|
+
for (const secret of secrets) {
|
|
27
|
+
if (secret.length >= MIN_SECRET_LENGTH)
|
|
28
|
+
out = out.split(secret).join("[REDACTED]");
|
|
29
|
+
}
|
|
30
|
+
return redactSecrets(out);
|
|
31
|
+
}
|
|
32
|
+
export function createStderrTail(capacityBytes = DEFAULT_CAPACITY) {
|
|
33
|
+
const decoder = new TextDecoder();
|
|
34
|
+
let buffer = "";
|
|
35
|
+
return {
|
|
36
|
+
push(chunk) {
|
|
37
|
+
buffer += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
|
|
38
|
+
// Known limitation: trimming at the raw capacity boundary can cut a
|
|
39
|
+
// caller secret in two, leaving the older half as a suffix in the buffer;
|
|
40
|
+
// excerpt() redacts only whole occurrences it sees. Capacity semantics are
|
|
41
|
+
// deliberate and stay as they are.
|
|
42
|
+
buffer = lastBytes(buffer, capacityBytes);
|
|
43
|
+
},
|
|
44
|
+
excerpt(opts = {}) {
|
|
45
|
+
return lastBytes(scrub(buffer, opts.secrets ?? []), opts.maxBytes ?? DEFAULT_EXCERPT);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
package/dist/native/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export { type ResolveResult, type ResolveStatus, resolveNativeId, } from "./mode
|
|
|
21
21
|
export { NATIVE_AGENT } from "./models.ts";
|
|
22
22
|
export { createMemoryTranscriptStore, type MemoryTranscriptStore } from "./session/memory-transcript-store.ts";
|
|
23
23
|
export { createFileTranscriptStore, MAX_RETAINED_TRANSCRIPTS, pruneRetainedTranscripts, } from "./session/transcript-store.ts";
|
|
24
|
-
export type { TranscriptDoc, TranscriptStore, TurnMarker } from "./session/transcript-types.ts";
|
|
24
|
+
export type { TranscriptAcpRecord, TranscriptDoc, TranscriptStore, TurnMarker } from "./session/transcript-types.ts";
|
|
25
25
|
export { NativeSessionAdapter } from "./session-adapter.ts";
|
|
26
26
|
export { newSessionKey } from "./session-affinity.ts";
|
|
27
27
|
export { type NativeTierConfig, nativeTierProviders } from "./tier-providers.ts";
|
|
@@ -10,9 +10,25 @@ export interface TurnMarker {
|
|
|
10
10
|
readonly turnId: string;
|
|
11
11
|
readonly state: "running" | "ended";
|
|
12
12
|
}
|
|
13
|
+
/** An ACP backend's record of the agent-side session (S4 spec 5.5). */
|
|
14
|
+
export interface TranscriptAcpRecord {
|
|
15
|
+
readonly agentSessionId: string;
|
|
16
|
+
readonly agent: string;
|
|
17
|
+
readonly agentVersion?: string;
|
|
18
|
+
readonly cwd: string;
|
|
19
|
+
/**
|
|
20
|
+
* The agent's cumulative cost reading (USD) at the end of the session's last
|
|
21
|
+
* priced turn. A resumed ACP session measures its next turn's cost from it,
|
|
22
|
+
* because the agent's running total survives a resume (S4-6 D6-a).
|
|
23
|
+
*/
|
|
24
|
+
readonly costUsd?: number;
|
|
25
|
+
}
|
|
13
26
|
export interface TranscriptDoc {
|
|
14
27
|
/** Absent means 1. nax-agent does not write it in S3-1. */
|
|
15
28
|
readonly schemaVersion?: 1;
|
|
29
|
+
/** Absent means "native". */
|
|
30
|
+
readonly backend?: string;
|
|
31
|
+
readonly acp?: TranscriptAcpRecord;
|
|
16
32
|
readonly owner?: string;
|
|
17
33
|
readonly model?: string;
|
|
18
34
|
readonly savedAt: string;
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
* algorithm and the file under the 600-line hard limit (see
|
|
7
7
|
* .nax/rules/project-conventions.md).
|
|
8
8
|
*
|
|
9
|
-
* The failure-usage ledger (`
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* public API. Adapter.ts reads through `readNativeTurnFailureUsage` to
|
|
9
|
+
* The failure-usage ledger's native API (`recordNativeTurnFailureUsage` /
|
|
10
|
+
* `readNativeTurnFailureUsage`) also lives here; the WeakMap itself lives in
|
|
11
|
+
* `#src/session/turn-spend`, shared with ACP backends (#2367). The loop's
|
|
12
|
+
* catch block only ever calls the write side through this file's public API. Adapter.ts reads through `readNativeTurnFailureUsage` to
|
|
14
13
|
* attribute round-trip spend to the error a failed turn threw (nax#1840).
|
|
15
14
|
*/
|
|
16
15
|
import type { ConversationMessage, ThinkingBlock, ToolCall } from "@nathapp/nax-ai";
|
|
@@ -6,21 +6,21 @@
|
|
|
6
6
|
* algorithm and the file under the 600-line hard limit (see
|
|
7
7
|
* .nax/rules/project-conventions.md).
|
|
8
8
|
*
|
|
9
|
-
* The failure-usage ledger (`
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* public API. Adapter.ts reads through `readNativeTurnFailureUsage` to
|
|
9
|
+
* The failure-usage ledger's native API (`recordNativeTurnFailureUsage` /
|
|
10
|
+
* `readNativeTurnFailureUsage`) also lives here; the WeakMap itself lives in
|
|
11
|
+
* `#src/session/turn-spend`, shared with ACP backends (#2367). The loop's
|
|
12
|
+
* catch block only ever calls the write side through this file's public API. Adapter.ts reads through `readNativeTurnFailureUsage` to
|
|
14
13
|
* attribute round-trip spend to the error a failed turn threw (nax#1840).
|
|
15
14
|
*/
|
|
16
|
-
|
|
15
|
+
import { attachTurnSpend, readTurnSpend } from "#src/session/turn-spend";
|
|
17
16
|
/** Writes the spend a failed turn accumulated, keyed on the error's own identity. */
|
|
18
17
|
export function recordNativeTurnFailureUsage(err, usage) {
|
|
19
|
-
|
|
18
|
+
attachTurnSpend(err, usage);
|
|
20
19
|
}
|
|
21
20
|
/** Reads back what the catch block recorded, if anything did. */
|
|
22
21
|
export function readNativeTurnFailureUsage(err) {
|
|
23
|
-
|
|
22
|
+
const spend = readTurnSpend(err);
|
|
23
|
+
return spend === undefined ? undefined : { tokenUsage: spend.tokenUsage, costUsd: spend.costUsd };
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Translate a `TokenUsage`'s cache fields into the spread that the
|
|
@@ -14,7 +14,7 @@ import type { AskRequest } from "./types.ts";
|
|
|
14
14
|
/** A link's answer. `abstain` means "no opinion, try the next link". */
|
|
15
15
|
export type AskDecision = "allow" | "deny" | "abstain";
|
|
16
16
|
/** Who actually decided. Carried into the ledger so it never has to be inferred. */
|
|
17
|
-
export type AskDecidedBy = "cache" | "model" | "human" | "timeout" | "unavailable" | "cancelled" | "unshowable";
|
|
17
|
+
export type AskDecidedBy = "cache" | "model" | "human" | "timeout" | "unavailable" | "cancelled" | "unshowable" | "profile";
|
|
18
18
|
/**
|
|
19
19
|
* Per-ask control (US-003), carried SEPARATELY from the `AskRequest` so the
|
|
20
20
|
* request the ledger records stays the pure request and a resolver can react
|
|
@@ -14,6 +14,12 @@ export declare const ASK_DENIED_REASON = "matched an ask rule requiring human ap
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const ASK_CANCELLED_REASON = "Not run: the turn was cancelled before anyone answered.";
|
|
16
16
|
export declare const ASK_UNSHOWABLE_REASON = "Not run: the command contains a secret that cannot be shown to the approver safely; pass it through an environment variable instead.";
|
|
17
|
+
/**
|
|
18
|
+
* The session profile's own policy refused the call (for example a tool the
|
|
19
|
+
* profile's ask rules put to a resolver that the profile itself denied). No
|
|
20
|
+
* person was asked and nobody timed out.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ASK_PROFILE_REASON = "denied by the session profile's policy";
|
|
17
23
|
/** Kept for compatibility with existing callers and tests. */
|
|
18
24
|
export declare const ASK_UNAVAILABLE_REASON = "matched an ask rule requiring human approval; no approval channel is configured for this run, so the call is refused";
|
|
19
25
|
/**
|
package/dist/permissions/ask.js
CHANGED
|
@@ -14,6 +14,12 @@ export const ASK_DENIED_REASON = "matched an ask rule requiring human approval;
|
|
|
14
14
|
*/
|
|
15
15
|
export const ASK_CANCELLED_REASON = "Not run: the turn was cancelled before anyone answered.";
|
|
16
16
|
export const ASK_UNSHOWABLE_REASON = "Not run: the command contains a secret that cannot be shown to the approver safely; pass it through an environment variable instead.";
|
|
17
|
+
/**
|
|
18
|
+
* The session profile's own policy refused the call (for example a tool the
|
|
19
|
+
* profile's ask rules put to a resolver that the profile itself denied). No
|
|
20
|
+
* person was asked and nobody timed out.
|
|
21
|
+
*/
|
|
22
|
+
export const ASK_PROFILE_REASON = "denied by the session profile's policy";
|
|
17
23
|
/** Kept for compatibility with existing callers and tests. */
|
|
18
24
|
export const ASK_UNAVAILABLE_REASON = ASK_NO_CHANNEL_REASON;
|
|
19
25
|
/**
|
|
@@ -2,7 +2,7 @@ export * from "./approval-audit.ts";
|
|
|
2
2
|
export * from "./approvals-link.ts";
|
|
3
3
|
export * from "./approvals-store.ts";
|
|
4
4
|
export * from "./approvals-taint.ts";
|
|
5
|
-
export { ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, headlessAskResolver, } from "./ask.ts";
|
|
5
|
+
export { ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, headlessAskResolver, } from "./ask.ts";
|
|
6
6
|
export * from "./ask-chain.ts";
|
|
7
7
|
export type { BashLexResult, BashRedirect, BashSegment, BashSegmentSeparator, BashToken } from "./bash-lex.ts";
|
|
8
8
|
export { lexBashCommand } from "./bash-lex.ts";
|
|
@@ -2,7 +2,7 @@ export * from "./approval-audit.js";
|
|
|
2
2
|
export * from "./approvals-link.js";
|
|
3
3
|
export * from "./approvals-store.js";
|
|
4
4
|
export * from "./approvals-taint.js";
|
|
5
|
-
export { ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, headlessAskResolver, } from "./ask.js";
|
|
5
|
+
export { ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, headlessAskResolver, } from "./ask.js";
|
|
6
6
|
export * from "./ask-chain.js";
|
|
7
7
|
export { lexBashCommand } from "./bash-lex.js";
|
|
8
8
|
export { parseRuleList, parseToolExpression } from "./grammar.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* or registerCodingTool's TOOL_NAME_RESERVED.
|
|
5
5
|
*/
|
|
6
6
|
import { NaxError } from "#src/infra/nax-error";
|
|
7
|
-
export type AgentSessionErrorCode = "AGENT_SESSION_INVALID_OPTIONS" | "AGENT_SESSION_EXISTS" | "AGENT_SESSION_BUSY" | "AGENT_SESSION_CLOSED" | "AGENT_SESSION_INVALID_ANSWER" | "AGENT_SESSION_NOT_FOUND" | "AGENT_SESSION_SCHEMA_UNSUPPORTED" | "AGENT_SESSION_MODEL_MISMATCH" | "AGENT_SESSION_SANDBOX_UNAVAILABLE" | "AGENT_SESSION_TOOL_NAME_RESERVED";
|
|
7
|
+
export type AgentSessionErrorCode = "AGENT_SESSION_INVALID_OPTIONS" | "AGENT_SESSION_EXISTS" | "AGENT_SESSION_BUSY" | "AGENT_SESSION_CLOSED" | "AGENT_SESSION_INVALID_ANSWER" | "AGENT_SESSION_NOT_FOUND" | "AGENT_SESSION_SCHEMA_UNSUPPORTED" | "AGENT_SESSION_MODEL_MISMATCH" | "AGENT_SESSION_SANDBOX_UNAVAILABLE" | "AGENT_SESSION_TOOL_NAME_RESERVED" | "AGENT_SESSION_BACKEND_UNAVAILABLE" | "AGENT_SESSION_AUTH_REQUIRED" | "AGENT_SESSION_RATE_LIMITED" | "AGENT_SESSION_CAPABILITY_UNSUPPORTED" | "AGENT_SESSION_BACKEND_MISMATCH";
|
|
8
8
|
export declare class AgentSessionError extends NaxError {
|
|
9
9
|
readonly code: AgentSessionErrorCode;
|
|
10
10
|
constructor(message: string, code: AgentSessionErrorCode, context?: Record<string, unknown>);
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import type { BashApprovalMode } from "#src/config/bash-approval";
|
|
2
1
|
import type { CreateAgentSessionOptions, EmbedderTool } from "./agent-session-types.ts";
|
|
3
2
|
export declare const DEFAULT_APPROVAL_TIMEOUT_MS = 600000;
|
|
4
3
|
export declare const DEFAULT_TURN_TIMEOUT_SECONDS = 3600;
|
|
5
4
|
export interface ResolvedAgentSessionOptions {
|
|
6
5
|
/** The caller's object, unchanged (tool objects keep their `this`). */
|
|
7
6
|
readonly raw: CreateAgentSessionOptions;
|
|
8
|
-
readonly provider: string;
|
|
9
7
|
readonly approvalTimeoutMs: number;
|
|
10
8
|
readonly turnTimeoutSeconds: number;
|
|
11
|
-
readonly bashApproval: BashApprovalMode;
|
|
12
|
-
readonly allowUnsandboxed: boolean;
|
|
13
9
|
readonly metadata: Readonly<Record<string, string>>;
|
|
14
10
|
readonly tools: readonly EmbedderTool[];
|
|
15
11
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Validates createAgentSession's options (spec 4.1, 7)
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Validates createAgentSession's shared options (spec 4.1, 7): the backend
|
|
3
|
+
* plus the options every backend reads. Native-only options live on
|
|
4
|
+
* `nativeBackend` (S4). zod checks the shape; the result keeps the caller's
|
|
5
|
+
* own objects (zod returns copies, which would detach a class-based tool's
|
|
6
|
+
* methods from `this`).
|
|
5
7
|
*/
|
|
6
8
|
import { isAbsolute } from "node:path";
|
|
7
9
|
import { z } from "zod";
|
|
8
|
-
import { parseNativeModel } from "#src/native/models";
|
|
9
10
|
import { ASK_HUMAN_TOOL_NAME } from "#src/native/session/ask-human";
|
|
10
11
|
import { RESERVED_TOOL_NAMES } from "#src/tools/registry";
|
|
11
12
|
import { AgentSessionError } from "./agent-session-errors.js";
|
|
@@ -21,7 +22,6 @@ function hasMethods(names) {
|
|
|
21
22
|
return (value) => isRecord(value) && names.every((name) => typeof value[name] === "function");
|
|
22
23
|
}
|
|
23
24
|
const isFunction = (value) => typeof value === "function";
|
|
24
|
-
const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
25
25
|
const EmbedderToolSchema = z.object({
|
|
26
26
|
name: z.string().regex(TOOL_NAME, "must be a letter, then letters, digits, _ or -, at most 64 characters"),
|
|
27
27
|
description: z.string().min(1),
|
|
@@ -31,13 +31,12 @@ const EmbedderToolSchema = z.object({
|
|
|
31
31
|
run: z.custom(isFunction, "must be a function"),
|
|
32
32
|
});
|
|
33
33
|
const OptionsSchema = z.strictObject({
|
|
34
|
-
backend: z.
|
|
34
|
+
backend: z.custom((value) => isRecord(value) && typeof value.kind === "string" && value.kind.length > 0 && typeof value.open === "function", "must be a SessionBackend (for example nativeBackend({ model }))"),
|
|
35
35
|
sessionId: z
|
|
36
36
|
.string()
|
|
37
37
|
.regex(SESSION_ID, "must be 1-128 letters, digits, '.', '_' or '-', starting with a letter or digit")
|
|
38
38
|
.optional(),
|
|
39
|
-
|
|
40
|
-
profile: z.enum(["none", "read", "full"]),
|
|
39
|
+
profile: z.enum(["none", "read", "ask", "full"]),
|
|
41
40
|
workdir: z
|
|
42
41
|
.string()
|
|
43
42
|
.refine((dir) => isAbsolute(dir), "must be an absolute path")
|
|
@@ -46,21 +45,6 @@ const OptionsSchema = z.strictObject({
|
|
|
46
45
|
tools: z.array(EmbedderToolSchema).optional(),
|
|
47
46
|
transcriptStore: z.custom(hasMethods(STORE_METHODS), `must implement ${STORE_METHODS.join(", ")}`),
|
|
48
47
|
approvalTimeoutMs: z.number().int().min(30_000).max(3_600_000).optional(),
|
|
49
|
-
bashApproval: z.enum(["raw", "gated", "escalate"]).optional(),
|
|
50
|
-
allowUnsandboxed: z.boolean().optional(),
|
|
51
|
-
credentials: z
|
|
52
|
-
.custom((value) => isRecord(value) && (value.kind === "memory" || value.kind === "exec"), "must be a memory or exec source")
|
|
53
|
-
.optional(),
|
|
54
|
-
catalogOverrides: z.array(z.custom(isRecord, "must be a catalog override object")).optional(),
|
|
55
|
-
loopHandlers: z.array(z.custom(isRecord, "must be a loop handler entry")).optional(),
|
|
56
|
-
hostPorts: z
|
|
57
|
-
.strictObject({
|
|
58
|
-
protectedPaths: z
|
|
59
|
-
.custom((value) => isRecord(value) && isStringArray(value.gitExcludePathspecs) && isStringArray(value.gitIgnorePatterns), "must be a protected-paths policy with gitExcludePathspecs and gitIgnorePatterns string arrays")
|
|
60
|
-
.optional(),
|
|
61
|
-
commandInterceptor: z.custom(hasMethods(["intercept"]), "must implement intercept").optional(),
|
|
62
|
-
})
|
|
63
|
-
.optional(),
|
|
64
48
|
metadata: z.record(z.string(), z.string()).optional(),
|
|
65
49
|
turnTimeoutSeconds: z.number().int().min(1).max(86_400).optional(),
|
|
66
50
|
});
|
|
@@ -73,11 +57,6 @@ function checkShape(input) {
|
|
|
73
57
|
path: "mcpServers",
|
|
74
58
|
});
|
|
75
59
|
}
|
|
76
|
-
if (isRecord(input) && isRecord(input.hostPorts) && "runDeclaredCommand" in input.hostPorts) {
|
|
77
|
-
throw invalid("hostPorts.runDeclaredCommand is deferred to a later release", {
|
|
78
|
-
path: "hostPorts.runDeclaredCommand",
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
60
|
const parsed = OptionsSchema.safeParse(input);
|
|
82
61
|
if (parsed.success)
|
|
83
62
|
return input;
|
|
@@ -89,15 +68,6 @@ function checkProfileRules(options) {
|
|
|
89
68
|
if (options.profile !== "none" && options.workdir === undefined) {
|
|
90
69
|
throw invalid(`workdir is required for profile "${options.profile}"`, { path: "workdir" });
|
|
91
70
|
}
|
|
92
|
-
if (options.profile !== "full" && options.bashApproval !== undefined) {
|
|
93
|
-
throw invalid('bashApproval applies to profile "full" only', { path: "bashApproval" });
|
|
94
|
-
}
|
|
95
|
-
if (options.profile !== "full" && options.allowUnsandboxed !== undefined) {
|
|
96
|
-
throw invalid('allowUnsandboxed applies to profile "full" only', { path: "allowUnsandboxed" });
|
|
97
|
-
}
|
|
98
|
-
if (options.allowUnsandboxed === true && (options.bashApproval ?? "gated") !== "gated") {
|
|
99
|
-
throw invalid('allowUnsandboxed requires bashApproval "gated"', { path: "allowUnsandboxed" });
|
|
100
|
-
}
|
|
101
71
|
}
|
|
102
72
|
function checkToolNames(tools) {
|
|
103
73
|
const reserved = new Set([...RESERVED_TOOL_NAMES, ASK_HUMAN_TOOL_NAME]);
|
|
@@ -111,14 +81,6 @@ function checkToolNames(tools) {
|
|
|
111
81
|
seen.add(tool.name);
|
|
112
82
|
}
|
|
113
83
|
}
|
|
114
|
-
function providerOf(model) {
|
|
115
|
-
try {
|
|
116
|
-
return parseNativeModel(model).provider;
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
throw invalid(`model: "${model}" is not "provider/model[effort]"`, { path: "model" });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
84
|
export function resolveAgentSessionOptions(input) {
|
|
123
85
|
const options = checkShape(input);
|
|
124
86
|
checkProfileRules(options);
|
|
@@ -126,11 +88,8 @@ export function resolveAgentSessionOptions(input) {
|
|
|
126
88
|
checkToolNames(tools);
|
|
127
89
|
return {
|
|
128
90
|
raw: options,
|
|
129
|
-
provider: providerOf(options.model),
|
|
130
91
|
approvalTimeoutMs: options.approvalTimeoutMs ?? DEFAULT_APPROVAL_TIMEOUT_MS,
|
|
131
92
|
turnTimeoutSeconds: options.turnTimeoutSeconds ?? DEFAULT_TURN_TIMEOUT_SECONDS,
|
|
132
|
-
bashApproval: options.bashApproval ?? "gated",
|
|
133
|
-
allowUnsandboxed: options.allowUnsandboxed === true,
|
|
134
93
|
metadata: options.metadata ?? {},
|
|
135
94
|
tools,
|
|
136
95
|
};
|
|
@@ -7,6 +7,8 @@ import type { CreateAgentSessionOptions } from "./agent-session-types.ts";
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function resumeInput(sessionId: string, options: CreateAgentSessionOptions): unknown;
|
|
9
9
|
/** The stored document a resume starts from. Throws when there is none or this session may not read it. */
|
|
10
|
-
export declare function loadResumable(store: TranscriptStore, sessionId: string
|
|
10
|
+
export declare function loadResumable(store: TranscriptStore, sessionId: string): Promise<TranscriptDoc>;
|
|
11
|
+
/** The stored document's backend (absent means native) must be the resuming backend's (S4 spec 5.5). */
|
|
12
|
+
export declare function checkBackendKind(doc: TranscriptDoc, sessionId: string, kind: string): void;
|
|
11
13
|
/** The turn a dead process left running (spec 6.4), or undefined. */
|
|
12
14
|
export declare function interruptedTurnOf(doc: TranscriptDoc): string | undefined;
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* resumeAgentSession's checks on the stored document (S3 spec 4.2, 6.4). They
|
|
3
3
|
* run before any backend opens: the id comes from the argument, the document
|
|
4
4
|
* exists, this build reads its schema, its messages are an array, and the
|
|
5
|
-
*
|
|
6
|
-
* (
|
|
5
|
+
* backend that wrote it is the one resuming (S4 spec 5.5). A backend's own
|
|
6
|
+
* model rule (an effort suffix is not a different model) runs in its `open`.
|
|
7
7
|
*/
|
|
8
8
|
import { NaxError } from "#src/infra/nax-error";
|
|
9
|
-
import { transcriptModelIdentity } from "#src/native/session/transcript-identity";
|
|
10
9
|
import { AgentSessionError } from "./agent-session-errors.js";
|
|
11
10
|
/**
|
|
12
11
|
* The options to validate for a resume: the argument is the session id. A
|
|
@@ -22,7 +21,7 @@ export function resumeInput(sessionId, options) {
|
|
|
22
21
|
return { ...options, sessionId };
|
|
23
22
|
}
|
|
24
23
|
/** The stored document a resume starts from. Throws when there is none or this session may not read it. */
|
|
25
|
-
export async function loadResumable(store, sessionId
|
|
24
|
+
export async function loadResumable(store, sessionId) {
|
|
26
25
|
const doc = await store.load(sessionId);
|
|
27
26
|
if (doc === null) {
|
|
28
27
|
throw new AgentSessionError(`Session "${sessionId}" has no document in the transcript store`, "AGENT_SESSION_NOT_FOUND", { sessionId });
|
|
@@ -34,12 +33,15 @@ export async function loadResumable(store, sessionId, model) {
|
|
|
34
33
|
if (!Array.isArray(doc.messages)) {
|
|
35
34
|
throw new NaxError(`transcript for session "${sessionId}" is unreadable: messages is not an array`, "TRANSCRIPT_CORRUPT", { stage: "agent-session", sessionId });
|
|
36
35
|
}
|
|
37
|
-
const resuming = transcriptModelIdentity(model);
|
|
38
|
-
if (doc.model !== undefined && doc.model !== resuming) {
|
|
39
|
-
throw new AgentSessionError(`Session "${sessionId}" was written by model "${doc.model}"; resume it with that model, not "${resuming}"`, "AGENT_SESSION_MODEL_MISMATCH", { sessionId });
|
|
40
|
-
}
|
|
41
36
|
return doc;
|
|
42
37
|
}
|
|
38
|
+
/** The stored document's backend (absent means native) must be the resuming backend's (S4 spec 5.5). */
|
|
39
|
+
export function checkBackendKind(doc, sessionId, kind) {
|
|
40
|
+
const stored = doc.backend ?? "native";
|
|
41
|
+
if (stored !== kind) {
|
|
42
|
+
throw new AgentSessionError(`Session "${sessionId}" was written by backend "${stored}"; it cannot be resumed with "${kind}"`, "AGENT_SESSION_BACKEND_MISMATCH", { sessionId, stored, kind });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
43
45
|
/** The turn a dead process left running (spec 6.4), or undefined. */
|
|
44
46
|
export function interruptedTurnOf(doc) {
|
|
45
47
|
const turn = doc.turn;
|