@nathapp/nax-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/coding-tools/coding-tool-bash.d.ts +46 -0
- package/dist/coding-tools/coding-tool-bash.js +44 -0
- package/dist/coding-tools/coding-tool-extras.d.ts +35 -0
- package/dist/coding-tools/coding-tool-extras.js +56 -0
- package/dist/coding-tools/coding-tool-sandbox.d.ts +74 -0
- package/dist/coding-tools/coding-tool-sandbox.js +215 -0
- package/dist/coding-tools/coding-tool-support.d.ts +132 -0
- package/dist/coding-tools/coding-tool-support.js +159 -0
- package/dist/coding-tools/universal-coding-tools.d.ts +11 -0
- package/dist/coding-tools/universal-coding-tools.js +5 -0
- package/dist/command-interceptor/index.d.ts +55 -0
- package/dist/command-interceptor/index.js +60 -0
- package/dist/command-interceptor/shell.d.ts +36 -0
- package/dist/command-interceptor/shell.js +137 -0
- package/dist/command-safety/build.d.ts +19 -0
- package/dist/command-safety/build.js +47 -0
- package/dist/command-safety/guard.d.ts +32 -0
- package/dist/command-safety/guard.js +179 -0
- package/dist/command-safety/identifiers.d.ts +24 -0
- package/dist/command-safety/identifiers.js +20 -0
- package/dist/command-safety/index.d.ts +17 -0
- package/dist/command-safety/index.js +11 -0
- package/dist/command-safety/questions.d.ts +19 -0
- package/dist/command-safety/questions.js +60 -0
- package/dist/command-safety/row.d.ts +2 -0
- package/dist/command-safety/row.js +14 -0
- package/dist/command-safety/rule-scorer.d.ts +9 -0
- package/dist/command-safety/rule-scorer.js +391 -0
- package/dist/command-safety/shadow.d.ts +33 -0
- package/dist/command-safety/shadow.js +188 -0
- package/dist/command-safety/systemone-client.d.ts +16 -0
- package/dist/command-safety/systemone-client.js +92 -0
- package/dist/command-safety/tap.d.ts +37 -0
- package/dist/command-safety/tap.js +77 -0
- package/dist/command-safety/temp-only.d.ts +6 -0
- package/dist/command-safety/temp-only.js +215 -0
- package/dist/command-safety/tmp-write.d.ts +2 -0
- package/dist/command-safety/tmp-write.js +112 -0
- package/dist/command-safety/types.d.ts +185 -0
- package/dist/command-safety/types.js +21 -0
- package/dist/config/bash-approval.d.ts +33 -0
- package/dist/config/bash-approval.js +30 -0
- package/dist/config/catalog-overrides.d.ts +94 -0
- package/dist/config/catalog-overrides.js +7 -0
- package/dist/config/native-agent/index.d.ts +8 -0
- package/dist/config/native-agent/index.js +8 -0
- package/dist/config/schemas-sandbox.d.ts +31 -0
- package/dist/config/schemas-sandbox.js +45 -0
- package/dist/cost/core/index.d.ts +8 -0
- package/dist/cost/core/index.js +7 -0
- package/dist/cost/estimate.d.ts +34 -0
- package/dist/cost/estimate.js +65 -0
- package/dist/cost/model-spec.d.ts +28 -0
- package/dist/cost/model-spec.js +29 -0
- package/dist/cost/standard-types.d.ts +9 -0
- package/dist/cost/standard-types.js +1 -0
- package/dist/cost/usage-math.d.ts +18 -0
- package/dist/cost/usage-math.js +46 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +21 -0
- package/dist/infra/agent-logger.d.ts +22 -0
- package/dist/infra/agent-logger.js +19 -0
- package/dist/infra/credentials-config.d.ts +20 -0
- package/dist/infra/credentials-config.js +15 -0
- package/dist/infra/errors.d.ts +9 -0
- package/dist/infra/errors.js +11 -0
- package/dist/infra/index.d.ts +7 -0
- package/dist/infra/index.js +7 -0
- package/dist/infra/nax-error.d.ts +10 -0
- package/dist/infra/nax-error.js +16 -0
- package/dist/infra/spin-breaker/hash.d.ts +2 -0
- package/dist/infra/spin-breaker/hash.js +5 -0
- package/dist/infra/spin-breaker/index.d.ts +120 -0
- package/dist/infra/spin-breaker/index.js +340 -0
- package/dist/internal/agent-output-env.d.ts +44 -0
- package/dist/internal/agent-output-env.js +57 -0
- package/dist/internal/argv-exec.d.ts +58 -0
- package/dist/internal/argv-exec.js +224 -0
- package/dist/internal/bounded-io.d.ts +24 -0
- package/dist/internal/bounded-io.js +51 -0
- package/dist/internal/command-spec/index.d.ts +29 -0
- package/dist/internal/command-spec/index.js +36 -0
- package/dist/internal/describe-value-type.d.ts +8 -0
- package/dist/internal/describe-value-type.js +14 -0
- package/dist/internal/exec-framing.d.ts +18 -0
- package/dist/internal/exec-framing.js +22 -0
- package/dist/internal/file-lock.d.ts +91 -0
- package/dist/internal/file-lock.js +212 -0
- package/dist/internal/file-size.d.ts +2 -0
- package/dist/internal/file-size.js +12 -0
- package/dist/internal/git-add.d.ts +43 -0
- package/dist/internal/git-add.js +59 -0
- package/dist/internal/git-env.d.ts +59 -0
- package/dist/internal/git-env.js +93 -0
- package/dist/internal/git-exec.d.ts +58 -0
- package/dist/internal/git-exec.js +115 -0
- package/dist/internal/path-file-lock.d.ts +23 -0
- package/dist/internal/path-file-lock.js +25 -0
- package/dist/internal/process-alive.d.ts +42 -0
- package/dist/internal/process-alive.js +56 -0
- package/dist/internal/process-kill.d.ts +27 -0
- package/dist/internal/process-kill.js +54 -0
- package/dist/internal/realpath.d.ts +29 -0
- package/dist/internal/realpath.js +52 -0
- package/dist/internal/redact.d.ts +40 -0
- package/dist/internal/redact.js +161 -0
- package/dist/internal/shell-quote.d.ts +2 -0
- package/dist/internal/shell-quote.js +4 -0
- package/dist/internal/sort.d.ts +20 -0
- package/dist/internal/sort.js +20 -0
- package/dist/internal/strip-control-chars.d.ts +19 -0
- package/dist/internal/strip-control-chars.js +38 -0
- package/dist/internal/thenable.d.ts +10 -0
- package/dist/internal/thenable.js +15 -0
- package/dist/internal.d.ts +91 -0
- package/dist/internal.js +91 -0
- package/dist/native/adapter-deps.d.ts +46 -0
- package/dist/native/adapter-deps.js +43 -0
- package/dist/native/auth-types.d.ts +70 -0
- package/dist/native/auth-types.js +13 -0
- package/dist/native/auth.d.ts +133 -0
- package/dist/native/auth.js +362 -0
- package/dist/native/client.d.ts +50 -0
- package/dist/native/client.js +174 -0
- package/dist/native/complete.d.ts +33 -0
- package/dist/native/complete.js +88 -0
- package/dist/native/credentials/chained-store.d.ts +30 -0
- package/dist/native/credentials/chained-store.js +68 -0
- package/dist/native/credentials/change-guard.d.ts +51 -0
- package/dist/native/credentials/change-guard.js +136 -0
- package/dist/native/credentials/exec-source.d.ts +50 -0
- package/dist/native/credentials/exec-source.js +222 -0
- package/dist/native/credentials/fingerprint.d.ts +26 -0
- package/dist/native/credentials/fingerprint.js +174 -0
- package/dist/native/credentials/helper-process.d.ts +79 -0
- package/dist/native/credentials/helper-process.js +259 -0
- package/dist/native/credentials/helper-protocol.d.ts +36 -0
- package/dist/native/credentials/helper-protocol.js +79 -0
- package/dist/native/credentials/index.d.ts +60 -0
- package/dist/native/credentials/index.js +184 -0
- package/dist/native/errors.d.ts +34 -0
- package/dist/native/errors.js +109 -0
- package/dist/native/index.d.ts +25 -0
- package/dist/native/index.js +23 -0
- package/dist/native/model-resolver.d.ts +57 -0
- package/dist/native/model-resolver.js +73 -0
- package/dist/native/models.d.ts +116 -0
- package/dist/native/models.js +183 -0
- package/dist/native/session/ask-human.d.ts +15 -0
- package/dist/native/session/ask-human.js +22 -0
- package/dist/native/session/compaction.d.ts +94 -0
- package/dist/native/session/compaction.js +170 -0
- package/dist/native/session/handle-invalid-tool-call.d.ts +111 -0
- package/dist/native/session/handle-invalid-tool-call.js +159 -0
- package/dist/native/session/loop-events/cache-boundary.d.ts +11 -0
- package/dist/native/session/loop-events/cache-boundary.js +29 -0
- package/dist/native/session/loop-events/external-handler.d.ts +38 -0
- package/dist/native/session/loop-events/external-handler.js +193 -0
- package/dist/native/session/loop-events/index.d.ts +16 -0
- package/dist/native/session/loop-events/index.js +15 -0
- package/dist/native/session/loop-events/payload-guard.d.ts +9 -0
- package/dist/native/session/loop-events/payload-guard.js +31 -0
- package/dist/native/session/loop-events/registry.d.ts +84 -0
- package/dist/native/session/loop-events/registry.js +305 -0
- package/dist/native/session/loop-events/types.d.ts +251 -0
- package/dist/native/session/loop-events/types.js +14 -0
- package/dist/native/session/loop-handlers.d.ts +73 -0
- package/dist/native/session/loop-handlers.js +137 -0
- package/dist/native/session/nudge.d.ts +29 -0
- package/dist/native/session/nudge.js +35 -0
- package/dist/native/session/rate-provenance.d.ts +17 -0
- package/dist/native/session/rate-provenance.js +39 -0
- package/dist/native/session/session.d.ts +139 -0
- package/dist/native/session/session.js +208 -0
- package/dist/native/session/tool-input-exemplar.d.ts +2 -0
- package/dist/native/session/tool-input-exemplar.js +66 -0
- package/dist/native/session/tool-input-validation.d.ts +15 -0
- package/dist/native/session/tool-input-validation.js +146 -0
- package/dist/native/session/tool-mapping.d.ts +18 -0
- package/dist/native/session/tool-mapping.js +27 -0
- package/dist/native/session/tool-result.d.ts +37 -0
- package/dist/native/session/tool-result.js +25 -0
- package/dist/native/session/transcript-store.d.ts +77 -0
- package/dist/native/session/transcript-store.js +200 -0
- package/dist/native/session/truncation-handler.d.ts +47 -0
- package/dist/native/session/truncation-handler.js +83 -0
- package/dist/native/session/turn-accumulator.d.ts +45 -0
- package/dist/native/session/turn-accumulator.js +67 -0
- package/dist/native/session/turn-ask-human.d.ts +23 -0
- package/dist/native/session/turn-ask-human.js +41 -0
- package/dist/native/session/turn-compaction-step.d.ts +74 -0
- package/dist/native/session/turn-compaction-step.js +128 -0
- package/dist/native/session/turn-complete-step.d.ts +77 -0
- package/dist/native/session/turn-complete-step.js +159 -0
- package/dist/native/session/turn-end-event.d.ts +3 -0
- package/dist/native/session/turn-end-event.js +17 -0
- package/dist/native/session/turn-events.d.ts +63 -0
- package/dist/native/session/turn-events.js +48 -0
- package/dist/native/session/turn-loop-round-trip.d.ts +116 -0
- package/dist/native/session/turn-loop-round-trip.js +318 -0
- package/dist/native/session/turn-loop.d.ts +23 -0
- package/dist/native/session/turn-loop.js +250 -0
- package/dist/native/session/turn-result.d.ts +39 -0
- package/dist/native/session/turn-result.js +64 -0
- package/dist/native/session/turn-retry.d.ts +120 -0
- package/dist/native/session/turn-retry.js +182 -0
- package/dist/native/session/turn-tool-batch.d.ts +61 -0
- package/dist/native/session/turn-tool-batch.js +259 -0
- package/dist/native/session/turn-types.d.ts +164 -0
- package/dist/native/session/turn-types.js +36 -0
- package/dist/native/session-adapter.d.ts +56 -0
- package/dist/native/session-adapter.js +369 -0
- package/dist/native/session-affinity.d.ts +36 -0
- package/dist/native/session-affinity.js +43 -0
- package/dist/native/tier-providers.d.ts +18 -0
- package/dist/native/tier-providers.js +20 -0
- package/dist/permissions/approval-audit.d.ts +10 -0
- package/dist/permissions/approval-audit.js +22 -0
- package/dist/permissions/approvals-link.d.ts +20 -0
- package/dist/permissions/approvals-link.js +62 -0
- package/dist/permissions/approvals-store.d.ts +168 -0
- package/dist/permissions/approvals-store.js +259 -0
- package/dist/permissions/approvals-taint.d.ts +33 -0
- package/dist/permissions/approvals-taint.js +138 -0
- package/dist/permissions/ask-chain.d.ts +69 -0
- package/dist/permissions/ask-chain.js +32 -0
- package/dist/permissions/ask.d.ts +23 -0
- package/dist/permissions/ask.js +25 -0
- package/dist/permissions/bash-lex.d.ts +59 -0
- package/dist/permissions/bash-lex.js +279 -0
- package/dist/permissions/grammar.d.ts +12 -0
- package/dist/permissions/grammar.js +24 -0
- package/dist/permissions/index.d.ts +11 -0
- package/dist/permissions/index.js +9 -0
- package/dist/permissions/secret-spans.d.ts +19 -0
- package/dist/permissions/secret-spans.js +88 -0
- package/dist/permissions/types.d.ts +85 -0
- package/dist/permissions/types.js +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/node-glob.d.ts +3 -0
- package/dist/runtime/node-glob.js +83 -0
- package/dist/runtime/node-runtime.d.ts +3 -0
- package/dist/runtime/node-runtime.js +126 -0
- package/dist/runtime/slot.d.ts +11 -0
- package/dist/runtime/slot.js +17 -0
- package/dist/runtime/types.d.ts +51 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/which.d.ts +8 -0
- package/dist/runtime/which.js +32 -0
- package/dist/sandbox/argv-quote.d.ts +11 -0
- package/dist/sandbox/argv-quote.js +13 -0
- package/dist/sandbox/defaults.d.ts +27 -0
- package/dist/sandbox/defaults.js +47 -0
- package/dist/sandbox/git-guards.d.ts +64 -0
- package/dist/sandbox/git-guards.js +161 -0
- package/dist/sandbox/index.d.ts +11 -0
- package/dist/sandbox/index.js +10 -0
- package/dist/sandbox/launcher.d.ts +37 -0
- package/dist/sandbox/launcher.js +160 -0
- package/dist/sandbox/messages.d.ts +17 -0
- package/dist/sandbox/messages.js +46 -0
- package/dist/sandbox/policy-builder.d.ts +44 -0
- package/dist/sandbox/policy-builder.js +149 -0
- package/dist/sandbox/policy-inputs.d.ts +53 -0
- package/dist/sandbox/policy-inputs.js +76 -0
- package/dist/sandbox/probe.d.ts +8 -0
- package/dist/sandbox/probe.js +66 -0
- package/dist/sandbox/registry.d.ts +17 -0
- package/dist/sandbox/registry.js +57 -0
- package/dist/sandbox/session-tmp.d.ts +20 -0
- package/dist/sandbox/session-tmp.js +95 -0
- package/dist/sandbox/srt-backend.d.ts +21 -0
- package/dist/sandbox/srt-backend.js +99 -0
- package/dist/sandbox/types.d.ts +102 -0
- package/dist/sandbox/types.js +1 -0
- package/dist/session/adapter-failure.d.ts +60 -0
- package/dist/session/adapter-failure.js +11 -0
- package/dist/session/agent-stream-events.d.ts +103 -0
- package/dist/session/agent-stream-events.js +6 -0
- package/dist/session/interaction-handler.d.ts +53 -0
- package/dist/session/interaction-handler.js +2 -0
- package/dist/session/no-op-interaction-handler.d.ts +9 -0
- package/dist/session/no-op-interaction-handler.js +11 -0
- package/dist/session/protocol-types.d.ts +12 -0
- package/dist/session/protocol-types.js +1 -0
- package/dist/session/session-types.d.ts +456 -0
- package/dist/session/session-types.js +64 -0
- package/dist/session/tool-descriptor.d.ts +23 -0
- package/dist/session/tool-descriptor.js +5 -0
- package/dist/session/turn-deadline.d.ts +17 -0
- package/dist/session/turn-deadline.js +23 -0
- package/dist/tools/ask-request.d.ts +35 -0
- package/dist/tools/ask-request.js +57 -0
- package/dist/tools/bash-cwd.d.ts +82 -0
- package/dist/tools/bash-cwd.js +55 -0
- package/dist/tools/bash.d.ts +69 -0
- package/dist/tools/bash.js +283 -0
- package/dist/tools/delete.d.ts +57 -0
- package/dist/tools/delete.js +154 -0
- package/dist/tools/denial-redirect.d.ts +42 -0
- package/dist/tools/denial-redirect.js +266 -0
- package/dist/tools/deny-paths.d.ts +35 -0
- package/dist/tools/deny-paths.js +76 -0
- package/dist/tools/edit-region.d.ts +50 -0
- package/dist/tools/edit-region.js +90 -0
- package/dist/tools/edit.d.ts +25 -0
- package/dist/tools/edit.js +114 -0
- package/dist/tools/exec-allowlist-text.d.ts +18 -0
- package/dist/tools/exec-allowlist-text.js +24 -0
- package/dist/tools/exec-guard.d.ts +69 -0
- package/dist/tools/exec-guard.js +151 -0
- package/dist/tools/git-commit.d.ts +59 -0
- package/dist/tools/git-commit.js +220 -0
- package/dist/tools/git-flags/index.d.ts +10 -0
- package/dist/tools/git-flags/index.js +10 -0
- package/dist/tools/git.d.ts +88 -0
- package/dist/tools/git.js +397 -0
- package/dist/tools/glob.d.ts +29 -0
- package/dist/tools/glob.js +153 -0
- package/dist/tools/grep.d.ts +21 -0
- package/dist/tools/grep.js +162 -0
- package/dist/tools/index.d.ts +36 -0
- package/dist/tools/index.js +28 -0
- package/dist/tools/narrow-grants.d.ts +19 -0
- package/dist/tools/narrow-grants.js +54 -0
- package/dist/tools/nax-owned-writes.d.ts +135 -0
- package/dist/tools/nax-owned-writes.js +259 -0
- package/dist/tools/package-managers-table.d.ts +146 -0
- package/dist/tools/package-managers-table.js +325 -0
- package/dist/tools/package-managers-types.d.ts +36 -0
- package/dist/tools/package-managers-types.js +6 -0
- package/dist/tools/package-managers.d.ts +85 -0
- package/dist/tools/package-managers.js +391 -0
- package/dist/tools/path-list.d.ts +38 -0
- package/dist/tools/path-list.js +62 -0
- package/dist/tools/policy-bash-raw.d.ts +19 -0
- package/dist/tools/policy-bash-raw.js +210 -0
- package/dist/tools/policy-bash.d.ts +64 -0
- package/dist/tools/policy-bash.js +232 -0
- package/dist/tools/policy-command-branch.d.ts +32 -0
- package/dist/tools/policy-command-branch.js +63 -0
- package/dist/tools/policy-input.d.ts +2 -0
- package/dist/tools/policy-input.js +10 -0
- package/dist/tools/policy-match.d.ts +75 -0
- package/dist/tools/policy-match.js +117 -0
- package/dist/tools/policy-paths-branch.d.ts +97 -0
- package/dist/tools/policy-paths-branch.js +314 -0
- package/dist/tools/policy.d.ts +65 -0
- package/dist/tools/policy.js +232 -0
- package/dist/tools/protected-paths.d.ts +26 -0
- package/dist/tools/protected-paths.js +8 -0
- package/dist/tools/provider-adapt.d.ts +4 -0
- package/dist/tools/provider-adapt.js +32 -0
- package/dist/tools/provider-advertise.d.ts +39 -0
- package/dist/tools/provider-advertise.js +50 -0
- package/dist/tools/provider-grants.d.ts +36 -0
- package/dist/tools/provider-grants.js +72 -0
- package/dist/tools/provider-sanitize.d.ts +19 -0
- package/dist/tools/provider-sanitize.js +53 -0
- package/dist/tools/provider-types.d.ts +41 -0
- package/dist/tools/provider-types.js +26 -0
- package/dist/tools/read-continuation.d.ts +147 -0
- package/dist/tools/read-continuation.js +176 -0
- package/dist/tools/read-file.d.ts +32 -0
- package/dist/tools/read-file.js +85 -0
- package/dist/tools/read.d.ts +25 -0
- package/dist/tools/read.js +182 -0
- package/dist/tools/registry.d.ts +125 -0
- package/dist/tools/registry.js +67 -0
- package/dist/tools/request-capability.d.ts +13 -0
- package/dist/tools/request-capability.js +23 -0
- package/dist/tools/run-command-exec.d.ts +14 -0
- package/dist/tools/run-command-exec.js +161 -0
- package/dist/tools/run-command.d.ts +107 -0
- package/dist/tools/run-command.js +398 -0
- package/dist/tools/runtime-calltool.d.ts +146 -0
- package/dist/tools/runtime-calltool.js +223 -0
- package/dist/tools/runtime.d.ts +149 -0
- package/dist/tools/runtime.js +345 -0
- package/dist/tools/scratchpad.d.ts +20 -0
- package/dist/tools/scratchpad.js +197 -0
- package/dist/tools/spill.d.ts +81 -0
- package/dist/tools/spill.js +251 -0
- package/dist/tools/tool-audit.d.ts +171 -0
- package/dist/tools/tool-audit.js +183 -0
- package/dist/tools/truncate.d.ts +98 -0
- package/dist/tools/truncate.js +297 -0
- package/dist/tools/types.d.ts +145 -0
- package/dist/tools/types.js +24 -0
- package/dist/tools/verb-denial-argv-hint.d.ts +35 -0
- package/dist/tools/verb-denial-argv-hint.js +40 -0
- package/dist/tools/write.d.ts +9 -0
- package/dist/tools/write.js +45 -0
- package/package.json +54 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-batch tool-call loop of the native turn loop.
|
|
3
|
+
*
|
|
4
|
+
* One assistant message may carry several tool calls; this module answers every
|
|
5
|
+
* one of them, applying the six distinct rules the loop has accumulated. It is
|
|
6
|
+
* the largest move out of `turn-loop.ts` and the one with the most invariants,
|
|
7
|
+
* so it is extracted unchanged: the rules are the point, not the plumbing.
|
|
8
|
+
*
|
|
9
|
+
* The batch owns a mutable copy of the transcript for its duration and returns
|
|
10
|
+
* the final array; `interactions` and `codingToolsCalled` accumulate locally and
|
|
11
|
+
* come back as NEW entries, so the caller appends rather than the batch
|
|
12
|
+
* mutating turn-lifetime arrays it does not own.
|
|
13
|
+
*
|
|
14
|
+
* `spinWarned` is a snapshot: it is set by the spin breaker's `onSpinStop`
|
|
15
|
+
* callback during this batch only in tandem with a `terminate` outcome, which
|
|
16
|
+
* breaks the batch immediately — so no later call in the same batch needs the
|
|
17
|
+
* flipped value. The batch reports the resulting `spinStopped` back out.
|
|
18
|
+
*/
|
|
19
|
+
import { ASK_HUMAN_TOOL_NAME } from "./ask-human.js";
|
|
20
|
+
import { rewriteToolCallInput } from "./handle-invalid-tool-call.js";
|
|
21
|
+
import { withNudge } from "./nudge.js";
|
|
22
|
+
import { buildToolResult } from "./tool-result.js";
|
|
23
|
+
import { handleAskHumanCall } from "./turn-ask-human.js";
|
|
24
|
+
export async function runToolBatch(args) {
|
|
25
|
+
const { toolCalls, tools, codingToolNames, roundTrips, opts, deps, loopEvents, invalidCallBudget, spinBreaker, maxInteractions, spinWarned, interactionsSoFar, } = args;
|
|
26
|
+
let messages = [...args.messages];
|
|
27
|
+
const interactions = [];
|
|
28
|
+
const codingToolsCalled = [];
|
|
29
|
+
// The ask_human budget counts exchanges across the whole turn, not this
|
|
30
|
+
// batch: `interactionsSoFar` is the caller's count at dispatch, and each
|
|
31
|
+
// successful exchange below advances `recorded` so a second ask in the same
|
|
32
|
+
// batch sees the first one spent.
|
|
33
|
+
let recorded = interactionsSoFar;
|
|
34
|
+
let spinStopped = false;
|
|
35
|
+
// US-002: a cancelled turn signal short-circuits this batch. The check runs
|
|
36
|
+
// at the TOP of every iteration (before activity, before dispatch) so an
|
|
37
|
+
// already-aborted signal at batch start also answers this-and-later calls
|
|
38
|
+
// from the first iteration; an in-flight call (the one that triggered the
|
|
39
|
+
// abort) finishes on its own path, the check begins there.
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
const isTurnCancelled = () => deps.signal?.aborted === true;
|
|
42
|
+
function answerCancelledFrom(callIndex) {
|
|
43
|
+
cancelled = true;
|
|
44
|
+
for (const outstanding of toolCalls.slice(callIndex)) {
|
|
45
|
+
messages.push(buildToolResult({
|
|
46
|
+
toolCallId: outstanding.id,
|
|
47
|
+
content: "Not run: the turn was cancelled.",
|
|
48
|
+
isError: true,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const [callIndex, call] of toolCalls.entries()) {
|
|
53
|
+
// US-002: check the turn signal FIRST (before spinWarned) so a cancelled
|
|
54
|
+
// turn always synthesises results for every outstanding call. A batch
|
|
55
|
+
// dispatch that arrives with both a frozen `spinWarned` snapshot AND an
|
|
56
|
+
// aborted signal must preserve the one-result-per-id invariant — the
|
|
57
|
+
// cancelled branch is the stronger guarantee, so it wins when both hold.
|
|
58
|
+
// AC1 / AC7 / AC8.
|
|
59
|
+
if (isTurnCancelled()) {
|
|
60
|
+
answerCancelledFrom(callIndex);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (spinWarned) {
|
|
64
|
+
spinStopped = true;
|
|
65
|
+
// The terminal round trip is answer-only. Any subsequent tool call
|
|
66
|
+
// is neither executed nor answered; the fail-spin retry starts from
|
|
67
|
+
// a fresh session and deliberately drops this unanswered request.
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
deps.onActivity?.({ kind: "tool", toolName: call.name });
|
|
71
|
+
try {
|
|
72
|
+
if (call.name === ASK_HUMAN_TOOL_NAME) {
|
|
73
|
+
const question = String(call.input?.text ?? "");
|
|
74
|
+
// These push sites — and the spin notice below — are answers to a call no
|
|
75
|
+
// tool produced. They use the chokepoint and deliberately fire no
|
|
76
|
+
// `after_tool` event: a policy that shapes tool output has nothing to
|
|
77
|
+
// shape here.
|
|
78
|
+
const outcome = await handleAskHumanCall({
|
|
79
|
+
toolCallId: call.id,
|
|
80
|
+
question,
|
|
81
|
+
interactionsSoFar: recorded,
|
|
82
|
+
maxInteractions,
|
|
83
|
+
roundTrips,
|
|
84
|
+
interactionHandler: opts.interactionHandler,
|
|
85
|
+
});
|
|
86
|
+
if (outcome.exchange !== undefined) {
|
|
87
|
+
interactions.push(outcome.exchange);
|
|
88
|
+
recorded += 1;
|
|
89
|
+
}
|
|
90
|
+
messages.push(outcome.result);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const outcome = await loopEvents.dispatch("before_tool", { call, tools });
|
|
94
|
+
if (isTurnCancelled()) {
|
|
95
|
+
answerCancelledFrom(callIndex);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
// nax#2047 Task 4: a tripped invalid-call budget ends the batch with
|
|
99
|
+
// NO result — "a result nobody reads only grows the transcript". None
|
|
100
|
+
// of the four seam outcomes can express that (each answers the call),
|
|
101
|
+
// so the halt is read from the budget the repair handler counts into,
|
|
102
|
+
// and checked before the outcome is applied.
|
|
103
|
+
if (invalidCallBudget.exceeded)
|
|
104
|
+
break;
|
|
105
|
+
// The spin breaker's stop is a batch-level outcome (nax#2120): every
|
|
106
|
+
// OUTSTANDING call in this batch is answered, not just the triggering
|
|
107
|
+
// one, or the next `complete()` is sent a tool_call with no matching
|
|
108
|
+
// result, which strict providers reject. Answer-only — the loop
|
|
109
|
+
// continues so the model can close the turn out — and synthetic, so
|
|
110
|
+
// no `after_tool` handler sees it.
|
|
111
|
+
if (outcome.kind === "terminate") {
|
|
112
|
+
for (const outstanding of toolCalls.slice(callIndex)) {
|
|
113
|
+
messages.push(buildToolResult({
|
|
114
|
+
toolCallId: outstanding.id,
|
|
115
|
+
content: outcome.content,
|
|
116
|
+
isError: outcome.isError,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (outcome.kind === "block") {
|
|
122
|
+
// Answered on the tool's behalf: the call never runs. A blocked
|
|
123
|
+
// call may still carry the input to record in its place (the
|
|
124
|
+
// invalid-call repair's redacted call), written before the answer.
|
|
125
|
+
if (outcome.input !== undefined)
|
|
126
|
+
messages = rewriteToolCallInput(messages, call.id, outcome.input);
|
|
127
|
+
messages.push(buildToolResult({ toolCallId: call.id, content: outcome.content, isError: outcome.isError }));
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// `allow` and `nudge` may rewrite the call's input; the rewritten value
|
|
131
|
+
// is what the transcript records and what the tool is invoked with, so
|
|
132
|
+
// the model's own history stays a truthful account of what ran.
|
|
133
|
+
const rewritten = outcome.input;
|
|
134
|
+
const input = rewritten ?? call.input;
|
|
135
|
+
if (rewritten !== undefined)
|
|
136
|
+
messages = rewriteToolCallInput(messages, call.id, rewritten);
|
|
137
|
+
const nudgeText = outcome.kind === "nudge" ? outcome.text : undefined;
|
|
138
|
+
const kind = codingToolNames.has(call.name) ? "coding-tool" : "context-tool";
|
|
139
|
+
if (kind === "coding-tool")
|
|
140
|
+
codingToolsCalled.push(call.name);
|
|
141
|
+
const answer = await opts.interactionHandler.onInteraction(kind === "coding-tool"
|
|
142
|
+
? {
|
|
143
|
+
kind,
|
|
144
|
+
name: call.name,
|
|
145
|
+
// MUST be `input`, NOT `call.input`. #2162's US-002 added a
|
|
146
|
+
// `before_tool` `allow` outcome that may REWRITE the input;
|
|
147
|
+
// the merged line is `input: (input ?? {}) as Record<...>`
|
|
148
|
+
// where `input = rewritten ?? call.input` (turn-loop.ts:448).
|
|
149
|
+
// Using `call.input` here runs the tool on the model's
|
|
150
|
+
// original arguments while `rewriteToolCallInput` has already
|
|
151
|
+
// recorded the corrected ones — execution and transcript
|
|
152
|
+
// diverge, silently, with no test in this plan covering it.
|
|
153
|
+
input: (input ?? {}),
|
|
154
|
+
...(opts.turnId !== undefined ? { turnId: opts.turnId } : {}),
|
|
155
|
+
roundTrips,
|
|
156
|
+
toolCallId: call.id,
|
|
157
|
+
deferModelTruncation: true,
|
|
158
|
+
// US-002: forward the per-turn signal into the coding-tool
|
|
159
|
+
// request. The handler copies it onto the `ToolCallContext`
|
|
160
|
+
// and `runTool` copies it onto the tool's `ToolRunContext`, so
|
|
161
|
+
// an in-flight tool observes the turn's cancellation. Absent
|
|
162
|
+
// when no signal is in scope (the no-signal regression guard).
|
|
163
|
+
...(deps.signal !== undefined ? { signal: deps.signal } : {}),
|
|
164
|
+
// US-002 AC14: forward the per-turn onWaiting callback too.
|
|
165
|
+
// Without this forwarding the `onWaiting` field on the request
|
|
166
|
+
// is unreachable from native tool dispatch, leaving the
|
|
167
|
+
// handler's onWaiting-forwarding plumbing inert in the real
|
|
168
|
+
// native path. Absent when no watcher is in scope.
|
|
169
|
+
//
|
|
170
|
+
// US-004 AC1: the forwarded onWaiting ALSO emits awaiting_human
|
|
171
|
+
// activity through deps.onActivity — a bare forwarding of
|
|
172
|
+
// deps.onWaiting never reaches the activity hook, so the
|
|
173
|
+
// watchdog would still cancel a turn that is legitimately
|
|
174
|
+
// waiting on a human approval prompt.
|
|
175
|
+
//
|
|
176
|
+
// Activity is emitted FIRST so a throwing onWaiting does not
|
|
177
|
+
// suppress the watchdog beat. The onWaiting call is wrapped in
|
|
178
|
+
// try/catch because it is a notification, not a gate — the
|
|
179
|
+
// request proceeds either way.
|
|
180
|
+
...(deps.onWaiting !== undefined || deps.onActivity !== undefined
|
|
181
|
+
? {
|
|
182
|
+
onWaiting: () => {
|
|
183
|
+
deps.onActivity?.({ kind: "awaiting_human" });
|
|
184
|
+
try {
|
|
185
|
+
deps.onWaiting?.();
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// notification only — onWaiting throwing must not
|
|
189
|
+
// surface to the tool, the run, or the cancel logic
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
: {}),
|
|
194
|
+
}
|
|
195
|
+
: { kind, name: call.name, input });
|
|
196
|
+
const answerText = answer?.answer ?? "";
|
|
197
|
+
// Genuine execution: the result is shaped by `after_tool` BEFORE it
|
|
198
|
+
// enters the array, which is what makes the event safe by
|
|
199
|
+
// construction (no handler can rewrite history). `denied` is threaded
|
|
200
|
+
// through untouched — a refused Write is not a crashed Write
|
|
201
|
+
// (ADR-029 s5) — and `nudge` prefixes the surviving content.
|
|
202
|
+
// Model-facing truncation (US-003) is the LAST of those handlers, so it
|
|
203
|
+
// shapes whatever earlier handlers produced; the payload carries the
|
|
204
|
+
// tool identity and the pending nudge, whose bytes the handler reserves
|
|
205
|
+
// out of this result's budget before `withNudge` prepends it below.
|
|
206
|
+
const patch = await loopEvents.dispatch("after_tool", {
|
|
207
|
+
content: answerText,
|
|
208
|
+
denied: answer?.denied,
|
|
209
|
+
toolName: call.name,
|
|
210
|
+
callId: call.id,
|
|
211
|
+
...(nudgeText !== undefined ? { nudgeText } : {}),
|
|
212
|
+
});
|
|
213
|
+
const finalContent = withNudge(nudgeText, patch.content ?? answerText);
|
|
214
|
+
answer?.finalizeAudit?.(finalContent);
|
|
215
|
+
messages.push(buildToolResult({
|
|
216
|
+
toolCallId: call.id,
|
|
217
|
+
content: finalContent,
|
|
218
|
+
isError: patch.isError,
|
|
219
|
+
denied: answer?.denied,
|
|
220
|
+
}));
|
|
221
|
+
// The breaker observed the call through the seam, i.e. with whatever
|
|
222
|
+
// input a handler rewrote in place — so the result has to be noted
|
|
223
|
+
// against that same input, or the key misses and result-based
|
|
224
|
+
// repetition detection silently stops for rewritten calls.
|
|
225
|
+
spinBreaker?.noteResult(call.name, input, answerText);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
// A tool failure is data, not a turn failure: the existing pull-tool
|
|
229
|
+
// contract already surfaces a handler throw as status "error". The
|
|
230
|
+
// event still fires — a policy that bounds result size has to see the
|
|
231
|
+
// results that arrive as errors too.
|
|
232
|
+
const errorText = err instanceof Error ? err.message : String(err);
|
|
233
|
+
const patch = await loopEvents.dispatch("after_tool", {
|
|
234
|
+
content: errorText,
|
|
235
|
+
isError: true,
|
|
236
|
+
toolName: call.name,
|
|
237
|
+
callId: call.id,
|
|
238
|
+
});
|
|
239
|
+
messages.push(buildToolResult({
|
|
240
|
+
toolCallId: call.id,
|
|
241
|
+
content: patch.content ?? errorText,
|
|
242
|
+
isError: patch.isError ?? true,
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
messages,
|
|
248
|
+
interactions,
|
|
249
|
+
codingToolsCalled,
|
|
250
|
+
spinStopped,
|
|
251
|
+
budgetExceeded: invalidCallBudget.exceeded,
|
|
252
|
+
// US-002: true when this batch saw an aborted `deps.signal` between tool
|
|
253
|
+
// calls; the loop throws the abort reason instead of issuing another
|
|
254
|
+
// round trip. A batch that never consulted a signal — the normal
|
|
255
|
+
// pre-feature path — never sees an aborted signal, so this stays false
|
|
256
|
+
// and the result shape is unchanged.
|
|
257
|
+
cancelled: cancelled || isTurnCancelled(),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types and failure-usage ledger for the native turn loop.
|
|
3
|
+
*
|
|
4
|
+
* `runNativeTurn` (turn-loop.ts) carries this file's types as parameters; this
|
|
5
|
+
* file owns their shape. Splitting them out keeps turn-loop.ts focused on the
|
|
6
|
+
* algorithm and the file under the 600-line hard limit (see
|
|
7
|
+
* .nax/rules/project-conventions.md).
|
|
8
|
+
*
|
|
9
|
+
* The failure-usage ledger (`failureUsageByError` WeakMap +
|
|
10
|
+
* `recordNativeTurnFailureUsage` / `readNativeTurnFailureUsage`) also lives
|
|
11
|
+
* here: it is module-level state with a process-lifetime scope, and the
|
|
12
|
+
* loop's catch block only ever calls the write side through this file's
|
|
13
|
+
* public API. Adapter.ts reads through `readNativeTurnFailureUsage` to
|
|
14
|
+
* attribute round-trip spend to the error a failed turn threw (nax#1840).
|
|
15
|
+
*/
|
|
16
|
+
import type { ConversationMessage, ThinkingBlock, ToolCall } from "@nathapp/nax-ai";
|
|
17
|
+
import type { PricingRates, TokenUsage } from "#src/cost/standard-types";
|
|
18
|
+
import type { SpinBreaker } from "#src/infra/spin-breaker/index";
|
|
19
|
+
import type { TurnDeadline } from "#src/session/turn-deadline";
|
|
20
|
+
import type { TranscriptMessage as NativeTranscriptMessage, ResolvedCompaction } from "./compaction.ts";
|
|
21
|
+
import type { CompleteCallOptions, LoopEventRegistry, LoopHandlerContext, LoopHandlerSet } from "./loop-events/index.ts";
|
|
22
|
+
import type { toToolDefinitions } from "./tool-mapping.ts";
|
|
23
|
+
import type { TurnRetryConfig } from "./turn-retry.ts";
|
|
24
|
+
export interface NativeTurnResponse {
|
|
25
|
+
readonly text: string;
|
|
26
|
+
readonly toolCalls?: readonly ToolCall[];
|
|
27
|
+
readonly thinking?: readonly ThinkingBlock[];
|
|
28
|
+
readonly usage: TokenUsage;
|
|
29
|
+
readonly costUsd: number;
|
|
30
|
+
/**
|
|
31
|
+
* US-002: the per-1M rates that priced this round-trip's `costUsd`.
|
|
32
|
+
* `runNativeTurn` stamps the LAST round-trip's `rates` on the
|
|
33
|
+
* `TurnResult` it returns — each round-trip re-prices on its own usage,
|
|
34
|
+
* and the most recent decision is what affected the user's last-mile
|
|
35
|
+
* spend. Optional so existing test fakes that build the response shape
|
|
36
|
+
* by hand keep compiling; the adapter's `complete` closure always sets
|
|
37
|
+
* it because native prices unconditionally.
|
|
38
|
+
*/
|
|
39
|
+
readonly rates?: PricingRates;
|
|
40
|
+
}
|
|
41
|
+
/** What one summarization call returns. Usage and cost are surfaced, not swallowed. */
|
|
42
|
+
export interface NativeSummaryResponse {
|
|
43
|
+
readonly text: string;
|
|
44
|
+
readonly usage: TokenUsage;
|
|
45
|
+
readonly costUsd: number;
|
|
46
|
+
/** Per-1M rates that priced this summary call, when known. */
|
|
47
|
+
readonly rates?: PricingRates;
|
|
48
|
+
}
|
|
49
|
+
export interface TurnDeps {
|
|
50
|
+
complete(messages: readonly ConversationMessage[], tools: ReturnType<typeof toToolDefinitions>, options?: CompleteCallOptions): Promise<NativeTurnResponse>;
|
|
51
|
+
/**
|
|
52
|
+
* One model call, no tools, used only to summarize a dropped span. Separate
|
|
53
|
+
* from complete() because it must not advertise tools, must not count as a
|
|
54
|
+
* round trip, and its cost must be attributable.
|
|
55
|
+
*/
|
|
56
|
+
summarize?(messages: readonly NativeTranscriptMessage[], previousSummary?: string): Promise<NativeSummaryResponse>;
|
|
57
|
+
/** ResolvedModel.contextWindow. Absent disables compaction. */
|
|
58
|
+
contextWindow?: number;
|
|
59
|
+
/** Resolved settings. Absent disables compaction. */
|
|
60
|
+
compaction?: ResolvedCompaction;
|
|
61
|
+
/**
|
|
62
|
+
* Whole-turn wall-clock budget. Absent means unbounded — the adapter always
|
|
63
|
+
* supplies one for a real session; tests may omit it.
|
|
64
|
+
*/
|
|
65
|
+
deadline?: TurnDeadline;
|
|
66
|
+
/**
|
|
67
|
+
* Per-round-trip observability hook. Absent in unit tests; the adapter
|
|
68
|
+
* supplies one that forwards onto the runtime stream bus so the idle
|
|
69
|
+
* watchdog can see native sessions.
|
|
70
|
+
*/
|
|
71
|
+
onActivity?: (activity: import("./turn-events.ts").NativeTurnActivity) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Which rate card priced this turn (US-003, first half of #1817). Absent
|
|
74
|
+
* on tests that build TurnDeps by hand and do not care about the source.
|
|
75
|
+
* When set, propagates to the returned TurnResult as `pricingSource` so the
|
|
76
|
+
* dispatch layer can stamp the row without re-deriving the rate-card branch.
|
|
77
|
+
*/
|
|
78
|
+
pricingSource?: "catalog-rates" | "config-override";
|
|
79
|
+
/**
|
|
80
|
+
* nax#1870: bounded retry for a transport/overloaded fault thrown by
|
|
81
|
+
* deps.complete, resolved from `agent.native.transportRetry`. Absent
|
|
82
|
+
* disables retry — the pre-#1870 behaviour of rethrowing immediately.
|
|
83
|
+
*/
|
|
84
|
+
transportRetry?: TurnRetryConfig;
|
|
85
|
+
/**
|
|
86
|
+
* Injectable sleep for the transport-retry backoff, so tests never
|
|
87
|
+
* actually wait (forbidden-patterns-tests.md). Absent uses a real timer —
|
|
88
|
+
* a real session always wants to actually wait.
|
|
89
|
+
*/
|
|
90
|
+
sleep?: (ms: number) => Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Live repetition-breaker instance (nax#2013, session-lifetime since #2047). Absent disables the breaker.
|
|
93
|
+
*/
|
|
94
|
+
spinBreaker?: SpinBreaker;
|
|
95
|
+
/**
|
|
96
|
+
* The one per-turn abort signal (US-002). The adapter builds it as
|
|
97
|
+
* `AbortSignal.any` over the caller's `opts.signal`, the watchdog's
|
|
98
|
+
* `turnController.signal` and a whole-turn deadline timer, and hands it to
|
|
99
|
+
* the loop; the loop's batch consults it between tool calls so a cancelled
|
|
100
|
+
* turn stops dispatching subsequent native tool calls. Absent in tests that
|
|
101
|
+
* drive the loop without cancellation.
|
|
102
|
+
*/
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
/**
|
|
105
|
+
* The native batch forwards this onto every coding-tool `AdapterInteraction`
|
|
106
|
+
* (US-002). Tools that block on an external wait (e.g. a human approval)
|
|
107
|
+
* call it before the wait so the wiring layer can observe the activity and
|
|
108
|
+
* the idle watchdog does not time out the call. Absent when no watcher is
|
|
109
|
+
* in scope; tests that drive the loop without cancellation may omit it.
|
|
110
|
+
*/
|
|
111
|
+
onWaiting?: () => void;
|
|
112
|
+
/**
|
|
113
|
+
* The in-process `before_tool` / `after_tool` seam (nax#2151, US-002).
|
|
114
|
+
* Absent is the normal case for a real session: the loop then builds its own
|
|
115
|
+
* registry, so the built-in handlers (invalid-call repair, spin breaker) run
|
|
116
|
+
* regardless. Supplying one is how a caller adds handlers — or observes the
|
|
117
|
+
* genuine-result dispatch sites — without the loop owning them.
|
|
118
|
+
*
|
|
119
|
+
* Per-turn, like the rest of `TurnDeps`: the loop registers its built-ins on
|
|
120
|
+
* the registry it is given, because both of them reset with the turn.
|
|
121
|
+
*/
|
|
122
|
+
loopEvents?: LoopEventRegistry;
|
|
123
|
+
/**
|
|
124
|
+
* The run's plugin-contributed loop handlers (US-003), forwarded from
|
|
125
|
+
* `SendTurnOpts` by the adapter. Installed by `registerBuiltinLoopHandlers`
|
|
126
|
+
* between the built-in `before_tool` pair and the built-in truncation.
|
|
127
|
+
* Absent or empty is the normal case — most runs load no such plugin.
|
|
128
|
+
*/
|
|
129
|
+
loopHandlers?: LoopHandlerSet;
|
|
130
|
+
/**
|
|
131
|
+
* The read-only facts each plugin handler is handed (US-003), forwarded from
|
|
132
|
+
* `SendTurnOpts`. Read at dispatch, like the rest of the per-turn state.
|
|
133
|
+
*/
|
|
134
|
+
loopHandlerContext?: LoopHandlerContext;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* nax#1840: round trips completed before a turn fails still spent real money.
|
|
138
|
+
* `inputTokens`/`outputTokens`/`costUsd` are locals inside runNativeTurn and
|
|
139
|
+
* reach a caller only through the clean-exit return, so a throw at round trip
|
|
140
|
+
* N silently drops everything spent on round trips 1..N-1.
|
|
141
|
+
*
|
|
142
|
+
* Recorded against the thrown error's own identity (a WeakMap), never by
|
|
143
|
+
* mutating the error itself: session-adapter.ts's `isProtocolStreamError`
|
|
144
|
+
* guard and its "propagate a non-protocol error untouched" rule both depend
|
|
145
|
+
* on the error's own shape staying exactly what was thrown.
|
|
146
|
+
*/
|
|
147
|
+
export interface NativeTurnFailureUsage {
|
|
148
|
+
readonly tokenUsage: TokenUsage;
|
|
149
|
+
readonly costUsd: number;
|
|
150
|
+
}
|
|
151
|
+
/** Writes the spend a failed turn accumulated, keyed on the error's own identity. */
|
|
152
|
+
export declare function recordNativeTurnFailureUsage(err: object, usage: NativeTurnFailureUsage): void;
|
|
153
|
+
/** Reads back what the catch block recorded, if anything did. */
|
|
154
|
+
export declare function readNativeTurnFailureUsage(err: unknown): NativeTurnFailureUsage | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Translate a `TokenUsage`'s cache fields into the spread that the
|
|
157
|
+
* `usage`-kind activity beat takes. Absent stays absent (never 0): the
|
|
158
|
+
* caller distinguishes "no cache data" from "zero cache tokens" downstream
|
|
159
|
+
* (nax#2045).
|
|
160
|
+
*/
|
|
161
|
+
export declare function cacheUsageFields(usage: TokenUsage): {
|
|
162
|
+
cacheRead?: number;
|
|
163
|
+
cacheWrite?: number;
|
|
164
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types and failure-usage ledger for the native turn loop.
|
|
3
|
+
*
|
|
4
|
+
* `runNativeTurn` (turn-loop.ts) carries this file's types as parameters; this
|
|
5
|
+
* file owns their shape. Splitting them out keeps turn-loop.ts focused on the
|
|
6
|
+
* algorithm and the file under the 600-line hard limit (see
|
|
7
|
+
* .nax/rules/project-conventions.md).
|
|
8
|
+
*
|
|
9
|
+
* The failure-usage ledger (`failureUsageByError` WeakMap +
|
|
10
|
+
* `recordNativeTurnFailureUsage` / `readNativeTurnFailureUsage`) also lives
|
|
11
|
+
* here: it is module-level state with a process-lifetime scope, and the
|
|
12
|
+
* loop's catch block only ever calls the write side through this file's
|
|
13
|
+
* public API. Adapter.ts reads through `readNativeTurnFailureUsage` to
|
|
14
|
+
* attribute round-trip spend to the error a failed turn threw (nax#1840).
|
|
15
|
+
*/
|
|
16
|
+
const failureUsageByError = new WeakMap();
|
|
17
|
+
/** Writes the spend a failed turn accumulated, keyed on the error's own identity. */
|
|
18
|
+
export function recordNativeTurnFailureUsage(err, usage) {
|
|
19
|
+
failureUsageByError.set(err, usage);
|
|
20
|
+
}
|
|
21
|
+
/** Reads back what the catch block recorded, if anything did. */
|
|
22
|
+
export function readNativeTurnFailureUsage(err) {
|
|
23
|
+
return typeof err === "object" && err !== null ? failureUsageByError.get(err) : undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Translate a `TokenUsage`'s cache fields into the spread that the
|
|
27
|
+
* `usage`-kind activity beat takes. Absent stays absent (never 0): the
|
|
28
|
+
* caller distinguishes "no cache data" from "zero cache tokens" downstream
|
|
29
|
+
* (nax#2045).
|
|
30
|
+
*/
|
|
31
|
+
export function cacheUsageFields(usage) {
|
|
32
|
+
return {
|
|
33
|
+
...(usage.cacheReadTokens !== undefined ? { cacheRead: usage.cacheReadTokens } : {}),
|
|
34
|
+
...(usage.cacheWriteTokens !== undefined ? { cacheWrite: usage.cacheWriteTokens } : {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The native session adapter: openSession / sendTurn / closeSession over
|
|
3
|
+
* nax-ai, no subprocess. openSession/closeSession are transcript-file
|
|
4
|
+
* bookkeeping, and sendTurn maps the native turn loop (session/turn-loop.ts)
|
|
5
|
+
* over complete() — nax owns the conversation because nax-ai's client is
|
|
6
|
+
* stateless (ADR-027 section 10, ADR-028).
|
|
7
|
+
*/
|
|
8
|
+
import { type AgentSessionAdapter, type OpenSessionOpts, type SendTurnOpts, type SessionHandle, type TurnResult } from "#src/session/session-types";
|
|
9
|
+
import { type NativeCatalogOverrides } from "./client.ts";
|
|
10
|
+
export declare class NativeSessionAdapter implements AgentSessionAdapter {
|
|
11
|
+
private readonly catalogOverrides;
|
|
12
|
+
constructor(catalogOverrides?: NativeCatalogOverrides);
|
|
13
|
+
/**
|
|
14
|
+
* Can this agent authenticate to at least one provider?
|
|
15
|
+
*
|
|
16
|
+
* Deliberately not "is the provider this run needs satisfied": this method
|
|
17
|
+
* takes no provider, and it cannot get one. The registry receives the
|
|
18
|
+
* manager's config slice, and agentManagerConfigSelector excludes
|
|
19
|
+
* config.models by design (ADR-019). Probing every provider for a specific
|
|
20
|
+
* answer is not an alternative either — pi's resolve() may execute commands.
|
|
21
|
+
*
|
|
22
|
+
* So this prunes exactly one case: nothing stored anywhere and nothing
|
|
23
|
+
* ambient. That is the real failure — a user who has never run
|
|
24
|
+
* `nax auth login` and has no provider environment variables — and every
|
|
25
|
+
* native call is going to fail anyway. A wrong-provider credential still
|
|
26
|
+
* surfaces per request, through the typed mapping from ProtocolError.kind
|
|
27
|
+
* "auth" to availability / fail-auth.
|
|
28
|
+
*
|
|
29
|
+
* US-004: with `auth.source: "exec"` it answers true without asking anything.
|
|
30
|
+
* A helper's providers cannot be listed, so an empty credential file says
|
|
31
|
+
* nothing about whether this run can authenticate — and spawning the helper
|
|
32
|
+
* here would put a credential read before the run has any reason for one.
|
|
33
|
+
*
|
|
34
|
+
* Errors resolve to true. Pruning an agent that would have worked kills a
|
|
35
|
+
* run; the opposite costs one request-time error that is already handled.
|
|
36
|
+
*/
|
|
37
|
+
hasCredentials(): Promise<boolean>;
|
|
38
|
+
openSession(name: string, opts: OpenSessionOpts): Promise<SessionHandle>;
|
|
39
|
+
sendTurn(handle: SessionHandle, prompt: string, opts: SendTurnOpts): Promise<TurnResult>;
|
|
40
|
+
closeSession(handle: SessionHandle): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Run teardown addresses a session the process no longer has a handle for,
|
|
43
|
+
* by id string (execution/session-manager-runtime.ts). Without this the
|
|
44
|
+
* native maps were unreachable at teardown: every `keepOpen` session was
|
|
45
|
+
* removed from SessionManager._sessions by closeStory while its nine entries
|
|
46
|
+
* stayed behind for the process lifetime.
|
|
47
|
+
*
|
|
48
|
+
* The ACP contract takes a handle string and closeNativeSession takes a
|
|
49
|
+
* SessionHandle, but the maps are keyed by the session-name string both
|
|
50
|
+
* carry, so clear by name rather than synthesising a handle.
|
|
51
|
+
*/
|
|
52
|
+
closePhysicalSession(handle: string, _workdir?: string, _options?: {
|
|
53
|
+
force?: boolean;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
}
|