@namzu/sdk 36.0.0 → 37.0.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 +180 -0
- package/README.md +68 -41
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +2 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +2 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/compaction/extractor.d.ts +1 -1
- package/dist/compaction/extractor.d.ts.map +1 -1
- package/dist/compaction/extractor.js +15 -7
- package/dist/compaction/extractor.js.map +1 -1
- package/dist/compaction/manager.d.ts +2 -0
- package/dist/compaction/manager.d.ts.map +1 -1
- package/dist/compaction/manager.js +12 -1
- package/dist/compaction/manager.js.map +1 -1
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +82 -15
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/contracts/schemas.d.ts +10 -10
- package/dist/eval/harness-verification.d.ts +63 -0
- package/dist/eval/harness-verification.d.ts.map +1 -0
- package/dist/eval/harness-verification.js +165 -0
- package/dist/eval/harness-verification.js.map +1 -0
- package/dist/eval/index.d.ts +2 -0
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/index.js +1 -0
- package/dist/eval/index.js.map +1 -1
- package/dist/execution/code-runtime/json-value.d.ts +10 -0
- package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
- package/dist/execution/code-runtime/json-value.js +89 -0
- package/dist/execution/code-runtime/json-value.js.map +1 -0
- package/dist/execution/code-runtime/worker-program.d.ts +8 -0
- package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
- package/dist/execution/code-runtime/worker-program.js +240 -0
- package/dist/execution/code-runtime/worker-program.js.map +1 -0
- package/dist/execution/code-runtime/worker.d.ts +22 -0
- package/dist/execution/code-runtime/worker.d.ts.map +1 -1
- package/dist/execution/code-runtime/worker.js +148 -111
- package/dist/execution/code-runtime/worker.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +12 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +306 -37
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +2 -0
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +6 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/provider/capabilities.d.ts +3 -1
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +13 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +2 -0
- package/dist/provider/fallback.js.map +1 -1
- package/dist/public-runtime.d.ts +3 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +2 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +1 -1
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +1 -1
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +1 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/execute.d.ts +3 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +11 -80
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/run/command-gate.d.ts.map +1 -1
- package/dist/run/command-gate.js +65 -12
- package/dist/run/command-gate.js.map +1 -1
- package/dist/run/index.d.ts +2 -0
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +1 -0
- package/dist/run/index.js.map +1 -1
- package/dist/run/memory-promoter.d.ts +3 -35
- package/dist/run/memory-promoter.d.ts.map +1 -1
- package/dist/run/memory-promoter.js +32 -40
- package/dist/run/memory-promoter.js.map +1 -1
- package/dist/run/memory-recall.d.ts +25 -0
- package/dist/run/memory-recall.d.ts.map +1 -0
- package/dist/run/memory-recall.js +228 -0
- package/dist/run/memory-recall.js.map +1 -0
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +1 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/run/token-budget.d.ts +2 -0
- package/dist/run/token-budget.d.ts.map +1 -1
- package/dist/run/token-budget.js +4 -0
- package/dist/run/token-budget.js.map +1 -1
- package/dist/run/workspace-fingerprint.d.ts +10 -3
- package/dist/run/workspace-fingerprint.d.ts.map +1 -1
- package/dist/run/workspace-fingerprint.js +17 -8
- package/dist/run/workspace-fingerprint.js.map +1 -1
- package/dist/runtime/query/checkpoint.d.ts +14 -0
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +82 -1
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +5 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +70 -14
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +5 -8
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +54 -7
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +10 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +325 -36
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/native-output.d.ts +10 -0
- package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
- package/dist/runtime/query/iteration/native-output.js +32 -0
- package/dist/runtime/query/iteration/native-output.js.map +1 -0
- package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js +18 -13
- package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +32 -11
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +9 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
- package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +2 -0
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +6 -2
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js +17 -2
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tool-call-budget.d.ts +19 -0
- package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
- package/dist/runtime/query/tool-call-budget.js +110 -0
- package/dist/runtime/query/tool-call-budget.js.map +1 -0
- package/dist/runtime/query/tooling.d.ts +2 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +4 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +1 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/handoff/capacity.d.ts +2 -2
- package/dist/session/handoff/capacity.d.ts.map +1 -1
- package/dist/session/handoff/capacity.js +3 -2
- package/dist/session/handoff/capacity.js.map +1 -1
- package/dist/store/memory/disk.d.ts +6 -2
- package/dist/store/memory/disk.d.ts.map +1 -1
- package/dist/store/memory/disk.js +42 -25
- package/dist/store/memory/disk.js.map +1 -1
- package/dist/store/memory/index.d.ts +4 -0
- package/dist/store/memory/index.d.ts.map +1 -1
- package/dist/store/memory/index.js +55 -19
- package/dist/store/memory/index.js.map +1 -1
- package/dist/store/memory/memory.d.ts +3 -2
- package/dist/store/memory/memory.d.ts.map +1 -1
- package/dist/store/memory/memory.js +11 -2
- package/dist/store/memory/memory.js.map +1 -1
- package/dist/store/memory/operation-lock.d.ts +11 -0
- package/dist/store/memory/operation-lock.d.ts.map +1 -0
- package/dist/store/memory/operation-lock.js +94 -0
- package/dist/store/memory/operation-lock.js.map +1 -0
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +60 -10
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/run-code.d.ts +6 -0
- package/dist/tools/builtins/run-code.d.ts.map +1 -1
- package/dist/tools/builtins/run-code.js +15 -4
- package/dist/tools/builtins/run-code.js.map +1 -1
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +14 -2
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/defineTool.d.ts +2 -0
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +3 -0
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/memory/delete.d.ts +4 -0
- package/dist/tools/memory/delete.d.ts.map +1 -0
- package/dist/tools/memory/delete.js +26 -0
- package/dist/tools/memory/delete.js.map +1 -0
- package/dist/tools/memory/index.d.ts +2 -0
- package/dist/tools/memory/index.d.ts.map +1 -1
- package/dist/tools/memory/index.js +6 -0
- package/dist/tools/memory/index.js.map +1 -1
- package/dist/tools/memory/save.d.ts.map +1 -1
- package/dist/tools/memory/save.js +3 -2
- package/dist/tools/memory/save.js.map +1 -1
- package/dist/tools/memory/search.d.ts.map +1 -1
- package/dist/tools/memory/search.js +12 -5
- package/dist/tools/memory/search.js.map +1 -1
- package/dist/tools/memory/update.d.ts +4 -0
- package/dist/tools/memory/update.d.ts.map +1 -0
- package/dist/tools/memory/update.js +47 -0
- package/dist/tools/memory/update.js.map +1 -0
- package/dist/types/agent/scheduler.d.ts +5 -0
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +10 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/computer-use/index.d.ts +6 -0
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/dist/types/computer-use/index.js.map +1 -1
- package/dist/types/errors/catalog.js +1 -1
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/hitl/index.d.ts +11 -1
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/memory/index.d.ts +14 -1
- package/dist/types/memory/index.d.ts.map +1 -1
- package/dist/types/project/entity.d.ts +1 -0
- package/dist/types/project/entity.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +2 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/model.d.ts +4 -0
- package/dist/types/provider/model.d.ts.map +1 -1
- package/dist/types/run/answer-review.d.ts +2 -0
- package/dist/types/run/answer-review.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +9 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/run/prepare-step.d.ts +19 -1
- package/dist/types/run/prepare-step.d.ts.map +1 -1
- package/dist/types/structured-output/index.d.ts +8 -2
- package/dist/types/structured-output/index.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +15 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/utils/json-snapshot.d.ts +3 -0
- package/dist/utils/json-snapshot.d.ts.map +1 -0
- package/dist/utils/json-snapshot.js +79 -0
- package/dist/utils/json-snapshot.js.map +1 -0
- package/package.json +4 -2
- package/src/bridge/a2a/mapper.ts +2 -0
- package/src/bridge/sse/mapper.ts +2 -0
- package/src/compaction/extractor.ts +21 -8
- package/src/compaction/manager.ts +11 -1
- package/src/compaction/verifier.ts +80 -18
- package/src/eval/harness-verification.ts +270 -0
- package/src/eval/index.ts +10 -0
- package/src/execution/code-runtime/json-value.ts +82 -0
- package/src/execution/code-runtime/worker-program.ts +239 -0
- package/src/execution/code-runtime/worker.ts +164 -111
- package/src/manager/agent/lifecycle.ts +340 -45
- package/src/manager/run/persistence.ts +7 -0
- package/src/provider/capabilities.ts +25 -1
- package/src/provider/fallback.ts +2 -0
- package/src/public-runtime.ts +4 -0
- package/src/public-tools.ts +5 -1
- package/src/public-types.ts +1 -0
- package/src/registry/tool/execute.ts +17 -79
- package/src/run/command-gate.ts +61 -13
- package/src/run/index.ts +2 -0
- package/src/run/memory-promoter.ts +32 -40
- package/src/run/memory-recall.ts +254 -0
- package/src/run/reporter.ts +1 -0
- package/src/run/token-budget.ts +4 -0
- package/src/run/workspace-fingerprint.ts +17 -8
- package/src/runtime/query/checkpoint.ts +96 -2
- package/src/runtime/query/executor.ts +77 -14
- package/src/runtime/query/index.ts +73 -16
- package/src/runtime/query/iteration/index.ts +377 -44
- package/src/runtime/query/iteration/native-output.ts +35 -0
- package/src/runtime/query/iteration/phases/advisory.ts +21 -11
- package/src/runtime/query/iteration/phases/compaction.ts +36 -14
- package/src/runtime/query/iteration/phases/context.ts +9 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
- package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
- package/src/runtime/query/iteration/stream-turn.ts +2 -0
- package/src/runtime/query/steering.ts +19 -2
- package/src/runtime/query/tool-call-budget.ts +115 -0
- package/src/runtime/query/tooling.ts +6 -0
- package/src/scheduler/local.ts +1 -0
- package/src/session/handoff/capacity.ts +7 -3
- package/src/store/memory/disk.ts +52 -30
- package/src/store/memory/index.ts +75 -27
- package/src/store/memory/memory.ts +18 -6
- package/src/store/memory/operation-lock.ts +99 -0
- package/src/tools/builtins/computer-use.ts +61 -7
- package/src/tools/builtins/run-code.ts +24 -5
- package/src/tools/builtins/search-tools.ts +18 -3
- package/src/tools/defineTool.ts +5 -0
- package/src/tools/memory/delete.ts +29 -0
- package/src/tools/memory/index.ts +6 -0
- package/src/tools/memory/save.ts +4 -2
- package/src/tools/memory/search.ts +12 -5
- package/src/tools/memory/update.ts +50 -0
- package/src/types/agent/scheduler.ts +6 -0
- package/src/types/agent/task.ts +13 -0
- package/src/types/computer-use/index.ts +6 -0
- package/src/types/errors/catalog.ts +1 -1
- package/src/types/hitl/index.ts +11 -1
- package/src/types/memory/index.ts +16 -1
- package/src/types/project/entity.ts +1 -0
- package/src/types/provider/config.ts +2 -0
- package/src/types/provider/model.ts +4 -0
- package/src/types/run/answer-review.ts +2 -0
- package/src/types/run/events.ts +10 -0
- package/src/types/run/prepare-step.ts +19 -1
- package/src/types/structured-output/index.ts +15 -2
- package/src/types/tool/index.ts +16 -0
- package/src/utils/json-snapshot.ts +76 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A
|
|
2
|
+
* A change detector for Git-visible workspace state.
|
|
3
3
|
*
|
|
4
4
|
* It exists to answer one question, asked between two attempts at the same
|
|
5
5
|
* verification: **did anything happen since it last failed?** A verify-then-fix
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* ## What is hashed, and why each part
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* Four sources, because no one of them is complete:
|
|
14
14
|
*
|
|
15
15
|
* 1. **`git status --porcelain`** — which paths differ from the index at all.
|
|
16
16
|
* Cheap, and it catches additions, deletions and mode changes. On its own
|
|
@@ -23,6 +23,13 @@
|
|
|
23
23
|
* 3. **Untracked file contents**, which no `git diff` covers. A new file is
|
|
24
24
|
* named by `status` but its CONTENT is not, so successive edits to a
|
|
25
25
|
* brand-new file would otherwise look like no change at all.
|
|
26
|
+
* 4. **`git rev-parse HEAD`** — the committed baseline. Two clean checkouts
|
|
27
|
+
* can contain different code while all three sources above are empty.
|
|
28
|
+
* Commit identity also covers verification that inspects Git history.
|
|
29
|
+
*
|
|
30
|
+
* Ignored files, external services and other command inputs are not covered.
|
|
31
|
+
* Reads are not an atomic snapshot. Matching hashes are an optimization hint,
|
|
32
|
+
* not proof that a command must produce the same result.
|
|
26
33
|
*
|
|
27
34
|
* ### Symlinks are recorded as their target, not read through
|
|
28
35
|
*
|
|
@@ -131,7 +138,7 @@ async function untrackedEntry(cwd: string, rel: string, fs: FingerprintFs): Prom
|
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
/**
|
|
134
|
-
* A hash of the
|
|
141
|
+
* A hash of the commit and Git-visible working state, or `null` when it cannot be
|
|
135
142
|
* established.
|
|
136
143
|
*
|
|
137
144
|
* **`null` is never "unchanged".** It means "I cannot tell", and the caller
|
|
@@ -152,15 +159,17 @@ export async function fingerprintWorkspace(
|
|
|
152
159
|
} catch {
|
|
153
160
|
return null
|
|
154
161
|
}
|
|
155
|
-
// A
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
if (result.exitCode !== 0) return null
|
|
162
|
+
// A terminated process may handle its signal and exit zero. Its
|
|
163
|
+
// retained output still cannot establish a complete fingerprint.
|
|
164
|
+
if (result.exitCode !== 0 || result.termination !== undefined) return null
|
|
159
165
|
if (result.stdoutTruncated === true || result.stderrTruncated === true) return null
|
|
160
166
|
if (Buffer.byteLength(result.stdout, 'utf8') > maxBytes) return null
|
|
161
167
|
return result.stdout
|
|
162
168
|
}
|
|
163
169
|
|
|
170
|
+
const head = await git(['rev-parse', '--verify', 'HEAD'])
|
|
171
|
+
if (head === null) return null
|
|
172
|
+
|
|
164
173
|
const status = await git(['status', '--porcelain'])
|
|
165
174
|
if (status === null) return null
|
|
166
175
|
|
|
@@ -170,7 +179,7 @@ export async function fingerprintWorkspace(
|
|
|
170
179
|
const untracked = await git(['ls-files', '--others', '--exclude-standard', '-z'])
|
|
171
180
|
if (untracked === null) return null
|
|
172
181
|
|
|
173
|
-
const parts = [`status ${status}`, `diff ${diff}`]
|
|
182
|
+
const parts = [`head ${head}`, `status ${status}`, `diff ${diff}`]
|
|
174
183
|
// Split on NUL, which is what `-z` is for: a path may contain a newline,
|
|
175
184
|
// and splitting on one would turn a single strange filename into two
|
|
176
185
|
// ordinary-looking ones.
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
IterationCheckpoint,
|
|
11
11
|
PendingDecision,
|
|
12
12
|
} from '../../types/hitl/index.js'
|
|
13
|
-
import type { AssistantMessage } from '../../types/message/index.js'
|
|
13
|
+
import type { AssistantMessage, UserMessage } from '../../types/message/index.js'
|
|
14
14
|
import type {
|
|
15
15
|
CheckpointRunScope,
|
|
16
16
|
CheckpointStore,
|
|
@@ -20,7 +20,53 @@ import type { EmergencySaveData } from '../../types/run/emergency.js'
|
|
|
20
20
|
import type { CheckpointListEntry } from '../../types/run/replay.js'
|
|
21
21
|
import { ZERO_COST } from '../../utils/cost.js'
|
|
22
22
|
import { buildToolResultHashes } from '../../utils/hash.js'
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
asCheckpointId,
|
|
25
|
+
asEmergencySaveId,
|
|
26
|
+
asGoalId,
|
|
27
|
+
generateCheckpointId,
|
|
28
|
+
} from '../../utils/id.js'
|
|
29
|
+
|
|
30
|
+
/** Keep intent text/provenance without copying attachment payloads into a second slot. */
|
|
31
|
+
function snapshotUserIntent(value: unknown): UserMessage {
|
|
32
|
+
const invalid = (): never => {
|
|
33
|
+
throw new Error('Checkpoint latestUserMessage has invalid operator intent or provenance')
|
|
34
|
+
}
|
|
35
|
+
if (!value || typeof value !== 'object') return invalid()
|
|
36
|
+
const message = value as Record<string, unknown>
|
|
37
|
+
if (message.role !== 'user' || typeof message.content !== 'string') return invalid()
|
|
38
|
+
const result: UserMessage = { role: 'user', content: message.content }
|
|
39
|
+
if (message.timestamp !== undefined) {
|
|
40
|
+
if (typeof message.timestamp !== 'number' || !Number.isFinite(message.timestamp))
|
|
41
|
+
return invalid()
|
|
42
|
+
result.timestamp = message.timestamp
|
|
43
|
+
}
|
|
44
|
+
if (message.source === undefined) return result
|
|
45
|
+
if (!message.source || typeof message.source !== 'object') return invalid()
|
|
46
|
+
const source = message.source as Record<string, unknown>
|
|
47
|
+
if (source.type === 'runtime-context' && source.kind === 'steering') {
|
|
48
|
+
result.source = { type: 'runtime-context', kind: 'steering' }
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
source.type !== 'goal-round' ||
|
|
53
|
+
typeof source.goalId !== 'string' ||
|
|
54
|
+
typeof source.objective !== 'string' ||
|
|
55
|
+
![source.goalRevision, source.round, source.maxGoalRounds].every(
|
|
56
|
+
(value) => typeof value === 'number' && Number.isInteger(value) && value > 0,
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
return invalid()
|
|
60
|
+
result.source = {
|
|
61
|
+
type: 'goal-round',
|
|
62
|
+
goalId: asGoalId(source.goalId),
|
|
63
|
+
objective: source.objective,
|
|
64
|
+
goalRevision: source.goalRevision as number,
|
|
65
|
+
round: source.round as number,
|
|
66
|
+
maxGoalRounds: source.maxGoalRounds as number,
|
|
67
|
+
}
|
|
68
|
+
return result
|
|
69
|
+
}
|
|
24
70
|
|
|
25
71
|
/**
|
|
26
72
|
* Projection from a full checkpoint payload to the public listing entry.
|
|
@@ -166,6 +212,12 @@ export class CheckpointManager {
|
|
|
166
212
|
* activity, and the record of everything before the resume is gone.
|
|
167
213
|
*/
|
|
168
214
|
private workingStateSource?: () => WorkingStateSnapshot | undefined
|
|
215
|
+
private latestUserMessageSource?: () => UserMessage | undefined
|
|
216
|
+
private restoredUserMessage?: UserMessage
|
|
217
|
+
private structuredReviewAttemptsSource?: () => number
|
|
218
|
+
private restoredReviewAttempts = 0
|
|
219
|
+
private nativeStructuredAttemptsSource?: () => number
|
|
220
|
+
private restoredNativeAttempts = 0
|
|
169
221
|
|
|
170
222
|
/**
|
|
171
223
|
* The most recent checkpoint this manager wrote, if any.
|
|
@@ -237,6 +289,30 @@ export class CheckpointManager {
|
|
|
237
289
|
this.workingStateSource = source
|
|
238
290
|
}
|
|
239
291
|
|
|
292
|
+
/** One current intent snapshot, including checkpoints created by tool/HITL paths. */
|
|
293
|
+
setLatestUserMessageSource(source: () => UserMessage | undefined): void {
|
|
294
|
+
this.latestUserMessageSource = source
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
get restoredLatestUserMessage(): UserMessage | undefined {
|
|
298
|
+
return this.restoredUserMessage
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
setNativeStructuredAttemptsSource(source: () => number): void {
|
|
302
|
+
this.nativeStructuredAttemptsSource = source
|
|
303
|
+
}
|
|
304
|
+
get restoredNativeStructuredAttempts(): number {
|
|
305
|
+
return this.restoredNativeAttempts
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
setStructuredReviewAttemptsSource(source: () => number): void {
|
|
309
|
+
this.structuredReviewAttemptsSource = source
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
get restoredStructuredReviewAttempts(): number {
|
|
313
|
+
return this.restoredReviewAttempts
|
|
314
|
+
}
|
|
315
|
+
|
|
240
316
|
/**
|
|
241
317
|
* The run's root span, so every checkpoint records the trace it was
|
|
242
318
|
* taken inside and a resume can join it rather than starting a second,
|
|
@@ -260,6 +336,7 @@ export class CheckpointManager {
|
|
|
260
336
|
// fact, and naming it after the earlier one would make it wrong in
|
|
261
337
|
// exactly the way that is hard to notice.
|
|
262
338
|
this.runCreatedAt ??= runMgr.getSession().startedAt ?? Date.now()
|
|
339
|
+
const latestUserMessage = this.latestUserMessageSource?.() ?? this.restoredUserMessage
|
|
263
340
|
|
|
264
341
|
const checkpoint: IterationCheckpoint = {
|
|
265
342
|
id: generateCheckpointId(),
|
|
@@ -267,6 +344,11 @@ export class CheckpointManager {
|
|
|
267
344
|
runCreatedAt: this.runCreatedAt,
|
|
268
345
|
iteration,
|
|
269
346
|
messages: [...runMgr.messages],
|
|
347
|
+
nativeStructuredAttempts:
|
|
348
|
+
this.nativeStructuredAttemptsSource?.() ?? this.restoredNativeAttempts,
|
|
349
|
+
structuredReviewAttempts:
|
|
350
|
+
this.structuredReviewAttemptsSource?.() ?? this.restoredReviewAttempts,
|
|
351
|
+
...(latestUserMessage ? { latestUserMessage: snapshotUserIntent(latestUserMessage) } : {}),
|
|
270
352
|
tokenUsage: { ...runMgr.tokenUsage },
|
|
271
353
|
budgetBinding: runMgr.budget?.binding,
|
|
272
354
|
budgetAccountId: runMgr.budget?.accountId,
|
|
@@ -457,6 +539,18 @@ export class CheckpointManager {
|
|
|
457
539
|
// its origin's age. A guard that no input can trip would have read as
|
|
458
540
|
// protection and been none.
|
|
459
541
|
this.runCreatedAt ??= checkpoint.runCreatedAt
|
|
542
|
+
const nativeAttempts = checkpoint.nativeStructuredAttempts ?? 0
|
|
543
|
+
if (!Number.isSafeInteger(nativeAttempts) || nativeAttempts < 0)
|
|
544
|
+
throw new Error('Invalid nativeStructuredAttempts in checkpoint')
|
|
545
|
+
this.restoredNativeAttempts = nativeAttempts
|
|
546
|
+
const reviewAttempts = checkpoint.structuredReviewAttempts ?? 0
|
|
547
|
+
if (!Number.isSafeInteger(reviewAttempts) || reviewAttempts < 0)
|
|
548
|
+
throw new Error('Checkpoint structuredReviewAttempts must be a nonnegative safe integer')
|
|
549
|
+
this.restoredReviewAttempts = reviewAttempts
|
|
550
|
+
this.restoredUserMessage =
|
|
551
|
+
checkpoint.latestUserMessage === undefined
|
|
552
|
+
? undefined
|
|
553
|
+
: snapshotUserIntent(checkpoint.latestUserMessage)
|
|
460
554
|
|
|
461
555
|
return checkpoint
|
|
462
556
|
}
|
|
@@ -50,6 +50,7 @@ import type { Logger } from '../../utils/logger.js'
|
|
|
50
50
|
import { compressShellOutput } from '../../utils/shell-compress.js'
|
|
51
51
|
import { type BackgroundJobRegistry, type JobProcess, bindOwner } from '../jobs/registry.js'
|
|
52
52
|
import type { ToolResultObservation } from './project-instructions.js'
|
|
53
|
+
import { ToolCallBudget, assertMaxToolCalls } from './tool-call-budget.js'
|
|
53
54
|
import {
|
|
54
55
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS,
|
|
55
56
|
type ToolOutputBudgetResult,
|
|
@@ -356,6 +357,10 @@ export interface ToolExecutorConfig {
|
|
|
356
357
|
toolRetryBackoff?: Partial<BackoffPolicy>
|
|
357
358
|
/** Max concurrently-executing concurrency-safe tools. */
|
|
358
359
|
maxToolConcurrency?: number
|
|
360
|
+
/** Per-run cumulative attempt admission limit; unset is unlimited. */
|
|
361
|
+
maxToolCalls?: number
|
|
362
|
+
/** Complete strict event replay for restoring a configured call budget. */
|
|
363
|
+
readToolCallBudgetEvents?: () => Promise<readonly RunEvent[]>
|
|
359
364
|
|
|
360
365
|
/**
|
|
361
366
|
* Builds the durable-pause seam handed to one tool call.
|
|
@@ -492,6 +497,7 @@ export class ToolExecutor {
|
|
|
492
497
|
private workingStateManager?: WorkingStateManager
|
|
493
498
|
private probes: ProbeEnforcement
|
|
494
499
|
private parentSpan?: Span
|
|
500
|
+
private readonly toolCallBudget?: ToolCallBudget
|
|
495
501
|
private readonly preparedBatches = new WeakSet<PreparedToolBatch>()
|
|
496
502
|
/** Set per turn by the orchestrator; see {@link setStepAllowedTools}. */
|
|
497
503
|
private stepAllowedTools?: readonly string[]
|
|
@@ -517,6 +523,15 @@ export class ToolExecutor {
|
|
|
517
523
|
log: Logger,
|
|
518
524
|
probes: ProbeEnforcement = defaultProbeRegistry,
|
|
519
525
|
) {
|
|
526
|
+
assertMaxToolCalls(config.maxToolCalls)
|
|
527
|
+
if (config.maxToolCalls !== undefined) {
|
|
528
|
+
this.toolCallBudget = new ToolCallBudget(
|
|
529
|
+
config.maxToolCalls,
|
|
530
|
+
config.runId,
|
|
531
|
+
emitEvent,
|
|
532
|
+
config.readToolCallBudgetEvents,
|
|
533
|
+
)
|
|
534
|
+
}
|
|
520
535
|
this.config = config
|
|
521
536
|
this.activityStore = activityStore
|
|
522
537
|
this.emitEvent = emitEvent
|
|
@@ -730,6 +745,18 @@ export class ToolExecutor {
|
|
|
730
745
|
if (owned && !this.preparedBatches.has(owned)) {
|
|
731
746
|
throw new Error('Prepared tool batch is not owned by this executor.')
|
|
732
747
|
}
|
|
748
|
+
const refusal = this.toolCallBudget
|
|
749
|
+
? await this.toolCallBudget.admit(
|
|
750
|
+
toolCalls.filter((call) => prior?.get(call.id) === undefined).length,
|
|
751
|
+
'batch',
|
|
752
|
+
this.config.abortSignal,
|
|
753
|
+
)
|
|
754
|
+
: undefined
|
|
755
|
+
if (refusal) {
|
|
756
|
+
const refused = new Map(denials)
|
|
757
|
+
for (const call of toolCalls) if (!refused.has(call.id)) refused.set(call.id, refusal)
|
|
758
|
+
return await this.runBatch(toolCalls, refused, prior, owned)
|
|
759
|
+
}
|
|
733
760
|
return await this.runBatch(toolCalls, denials, prior, owned)
|
|
734
761
|
} finally {
|
|
735
762
|
// Cleared so a later single execution outside a batch resolves
|
|
@@ -779,6 +806,24 @@ export class ToolExecutor {
|
|
|
779
806
|
const results: ToolCallOutcome[] = new Array(toolCalls.length)
|
|
780
807
|
const parallel: Promise<void>[] = []
|
|
781
808
|
let serial: Promise<void> = Promise.resolve()
|
|
809
|
+
let barrier: Promise<void> | undefined
|
|
810
|
+
const schedule = (run: () => Promise<void>, safe: boolean, isBarrier: boolean): void => {
|
|
811
|
+
if (isBarrier) {
|
|
812
|
+
// Settle the entire preceding segment, even when host plumbing
|
|
813
|
+
// rejects. A rejected host operation prevents dependent execution.
|
|
814
|
+
barrier = Promise.allSettled([...parallel, serial]).then(async (settled) => {
|
|
815
|
+
const failed = settled.find((entry) => entry.status === 'rejected')
|
|
816
|
+
if (failed?.status === 'rejected') throw failed.reason
|
|
817
|
+
await run()
|
|
818
|
+
})
|
|
819
|
+
parallel.length = 0
|
|
820
|
+
serial = barrier
|
|
821
|
+
} else if (safe) {
|
|
822
|
+
parallel.push(barrier ? barrier.then(run) : run())
|
|
823
|
+
} else {
|
|
824
|
+
serial = serial.then(run)
|
|
825
|
+
}
|
|
826
|
+
}
|
|
782
827
|
// Bounded fan-out. A model emitting fifty parallel reads used to open
|
|
783
828
|
// fifty file handles and fifty activity records simultaneously; the
|
|
784
829
|
// gate keeps that at a working-set size while preserving completion
|
|
@@ -786,6 +831,8 @@ export class ToolExecutor {
|
|
|
786
831
|
const gate = new Semaphore(this.config.maxToolConcurrency ?? DEFAULT_TOOL_CONCURRENCY)
|
|
787
832
|
toolCalls.forEach((toolCall, i) => {
|
|
788
833
|
const preparedCall = preparedBatch?.calls.get(toolCall.id)
|
|
834
|
+
const tool = this.config.tools.get(preparedCall?.toolName ?? toolCall.function.name)
|
|
835
|
+
const isBarrier = tool?.executionBarrier === true
|
|
789
836
|
const recovered = prior?.get(toolCall.id)
|
|
790
837
|
if (recovered !== undefined) {
|
|
791
838
|
// This call already ran, in a process that died before the
|
|
@@ -798,19 +845,21 @@ export class ToolExecutor {
|
|
|
798
845
|
output: recovered.result,
|
|
799
846
|
isError: recovered.isError,
|
|
800
847
|
}
|
|
848
|
+
if (isBarrier) schedule(async () => {}, true, true)
|
|
801
849
|
return
|
|
802
850
|
}
|
|
803
851
|
|
|
804
852
|
const denialReason = denials?.get(toolCall.id)
|
|
805
853
|
if (denialReason !== undefined) {
|
|
806
854
|
// Denied calls never touch the tool; they still get a result
|
|
807
|
-
// message so the assistant turn stays fully answered.
|
|
808
|
-
//
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
855
|
+
// message so the assistant turn stays fully answered. They can
|
|
856
|
+
// overlap other calls within a segment, respecting its barriers.
|
|
857
|
+
schedule(
|
|
858
|
+
async () => {
|
|
859
|
+
results[i] = await this.recordDenial(toolCall, denialReason, preparedCall)
|
|
860
|
+
},
|
|
861
|
+
true,
|
|
862
|
+
isBarrier,
|
|
814
863
|
)
|
|
815
864
|
return
|
|
816
865
|
}
|
|
@@ -868,13 +917,8 @@ export class ToolExecutor {
|
|
|
868
917
|
} catch {
|
|
869
918
|
// non-JSON args → treat as unsafe (serialize), the conservative path
|
|
870
919
|
}
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
this.config.tools
|
|
874
|
-
.get(preparedToolName ?? toolCall.function.name)
|
|
875
|
-
?.isConcurrencySafe?.(input) === true
|
|
876
|
-
if (safe) parallel.push(gated())
|
|
877
|
-
else serial = serial.then(run)
|
|
920
|
+
const safe = tool?.isConcurrencySafe?.(input) === true
|
|
921
|
+
schedule(safe ? gated : run, safe, isBarrier)
|
|
878
922
|
})
|
|
879
923
|
await Promise.all([...parallel, serial])
|
|
880
924
|
|
|
@@ -942,8 +986,14 @@ export class ToolExecutor {
|
|
|
942
986
|
// retained closure must be observationally inert after its invocation
|
|
943
987
|
// ends, not merely unable to finish the registry call it already started.
|
|
944
988
|
signal.throwIfAborted()
|
|
989
|
+
// Preparation detaches input synchronously before its first await.
|
|
990
|
+
// Admission must not add an earlier yield where the caller can mutate it.
|
|
945
991
|
const preparedCall = await this.prepareNestedCall(name, input, signal)
|
|
946
992
|
signal.throwIfAborted()
|
|
993
|
+
if (this.toolCallBudget) {
|
|
994
|
+
const refusal = await this.toolCallBudget.admit(1, 'nested', signal)
|
|
995
|
+
if (refusal) return { success: false, output: '', error: refusal }
|
|
996
|
+
}
|
|
947
997
|
const preparedInput = preparedCall.input
|
|
948
998
|
|
|
949
999
|
const parent = context.toolUseId
|
|
@@ -1550,6 +1600,19 @@ export class ToolExecutor {
|
|
|
1550
1600
|
break
|
|
1551
1601
|
}
|
|
1552
1602
|
|
|
1603
|
+
let refusal: string | undefined
|
|
1604
|
+
try {
|
|
1605
|
+
if (this.toolCallBudget)
|
|
1606
|
+
refusal = await this.toolCallBudget.admit(1, 'retry', this.config.abortSignal)
|
|
1607
|
+
} catch (error) {
|
|
1608
|
+
if (this.config.abortSignal.aborted) break
|
|
1609
|
+
throw error
|
|
1610
|
+
}
|
|
1611
|
+
if (refusal) {
|
|
1612
|
+
result = { success: false, output: '', error: refusal }
|
|
1613
|
+
post = { override: null, retry: false }
|
|
1614
|
+
break
|
|
1615
|
+
}
|
|
1553
1616
|
result = await this.runOnce(toolName, input, toolContext, prepared)
|
|
1554
1617
|
post = await this.runPostToolHook(toolName, input, result)
|
|
1555
1618
|
}
|
|
@@ -149,8 +149,9 @@ import {
|
|
|
149
149
|
resolveSandboxTeardownTimeoutMs,
|
|
150
150
|
teardownSandbox,
|
|
151
151
|
} from './sandbox-lifecycle.js'
|
|
152
|
-
import { SteeringBinding, type SteeringChannel } from './steering.js'
|
|
152
|
+
import { SteeringBinding, type SteeringChannel, isOperatorUserMessage } from './steering.js'
|
|
153
153
|
import { resolveQueryBudget } from './token-budget.js'
|
|
154
|
+
import { assertMaxToolCalls } from './tool-call-budget.js'
|
|
154
155
|
import { ToolGrantSet } from './tool-grants.js'
|
|
155
156
|
import { createToolPause } from './tool-pause.js'
|
|
156
157
|
import { ToolingBootstrap } from './tooling.js'
|
|
@@ -349,6 +350,8 @@ export interface QueryParams {
|
|
|
349
350
|
|
|
350
351
|
/** Max concurrently-executing concurrency-safe tools in one batch. */
|
|
351
352
|
maxToolConcurrency?: number
|
|
353
|
+
/** Per-run cumulative tool attempt limit, including nested calls and retries. Unset is unlimited. Re-supply on resume; durable reservations are never refunded. */
|
|
354
|
+
maxToolCalls?: number
|
|
352
355
|
|
|
353
356
|
/**
|
|
354
357
|
* Model-visible size cap for a single tool result. Over-budget output is
|
|
@@ -450,14 +453,9 @@ export interface QueryParams {
|
|
|
450
453
|
beforeStep?: BeforeStep
|
|
451
454
|
|
|
452
455
|
/**
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* Both leaf pieces already shipped and neither was reachable:
|
|
457
|
-
* `createStructuredOutputTool` is excluded from the default builtin set,
|
|
458
|
-
* and `StructuredOutputConfig` had no field on QueryParams at all. A host
|
|
459
|
-
* needing a typed result had to register the tool by hand and hope —
|
|
460
|
-
* nothing forced the call, and nothing stopped the loop when it came.
|
|
456
|
+
* Produce a locally validated structured result. Defaults to an output tool;
|
|
457
|
+
* mode:'native' requests JSON Schema from an explicitly capable driver.
|
|
458
|
+
* Host review and bounded corrections apply before publication.
|
|
461
459
|
*/
|
|
462
460
|
structuredOutput?: StructuredOutputConfig
|
|
463
461
|
|
|
@@ -1027,6 +1025,19 @@ function withoutOwnedResumeTurn(
|
|
|
1027
1025
|
}
|
|
1028
1026
|
|
|
1029
1027
|
export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run> {
|
|
1028
|
+
assertMaxToolCalls(params.maxToolCalls)
|
|
1029
|
+
// Required types do not protect JavaScript callers. Reject missing scope
|
|
1030
|
+
// before opening a budget or persisting a run without its owning identity.
|
|
1031
|
+
const missingFields = (['sessionId', 'topicId', 'projectId', 'tenantId'] as const).filter(
|
|
1032
|
+
(field) => !params[field],
|
|
1033
|
+
)
|
|
1034
|
+
if (missingFields.length > 0) {
|
|
1035
|
+
throw new NamzuError({
|
|
1036
|
+
code: 'invalid_config',
|
|
1037
|
+
message: `query requires sessionId, topicId, projectId, and tenantId; missing: ${missingFields.join(', ')}.`,
|
|
1038
|
+
details: { missingFields },
|
|
1039
|
+
})
|
|
1040
|
+
}
|
|
1030
1041
|
const selectedResumeState = selectedResumeStates.get(params)
|
|
1031
1042
|
selectedResumeStates.delete(params)
|
|
1032
1043
|
// Resolved at the DOOR, before a run id exists or a logger is built.
|
|
@@ -1154,6 +1165,8 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
1154
1165
|
runConfig.timeoutMs,
|
|
1155
1166
|
log,
|
|
1156
1167
|
)
|
|
1168
|
+
const modelContextWindows = new Map<string, number | undefined>()
|
|
1169
|
+
if (runConfig.model) modelContextWindows.set(runConfig.model, providerContextWindow)
|
|
1157
1170
|
|
|
1158
1171
|
// The mode this conversation was left in, when the run config names none.
|
|
1159
1172
|
// Read once, before the loop exists, for the same reason the context
|
|
@@ -1556,7 +1569,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
1556
1569
|
// invalidate the whole prompt cache for the rest of the run — the same
|
|
1557
1570
|
// reason the forced-final turn keeps its tools array and uses
|
|
1558
1571
|
// `toolChoice: 'none'` instead of dropping it.
|
|
1559
|
-
if (
|
|
1572
|
+
if (
|
|
1573
|
+
params.structuredOutput &&
|
|
1574
|
+
params.structuredOutput.mode !== 'native' &&
|
|
1575
|
+
!params.tools.has(STRUCTURED_OUTPUT_TOOL_NAME)
|
|
1576
|
+
) {
|
|
1560
1577
|
params.tools.register(createStructuredOutputTool(params.structuredOutput.schema))
|
|
1561
1578
|
}
|
|
1562
1579
|
|
|
@@ -1718,6 +1735,13 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
1718
1735
|
...(params.toolRetryBackoff !== undefined
|
|
1719
1736
|
? { toolRetryBackoff: params.toolRetryBackoff }
|
|
1720
1737
|
: {}),
|
|
1738
|
+
...(params.maxToolCalls !== undefined
|
|
1739
|
+
? {
|
|
1740
|
+
maxToolCalls: params.maxToolCalls,
|
|
1741
|
+
readToolCallBudgetEvents: () =>
|
|
1742
|
+
ctx.runMgr.getRunStore().readEvents({ integrity: 'strict' }),
|
|
1743
|
+
}
|
|
1744
|
+
: {}),
|
|
1721
1745
|
...(params.maxToolConcurrency !== undefined
|
|
1722
1746
|
? { maxToolConcurrency: params.maxToolConcurrency }
|
|
1723
1747
|
: {}),
|
|
@@ -1970,11 +1994,27 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
1970
1994
|
...(params.repeatCallAdvisory === false ? {} : { repeatCalls: new RepeatCallTracker() }),
|
|
1971
1995
|
compactionConfig,
|
|
1972
1996
|
...(params.inboundMessages ? { inboundMessages: params.inboundMessages } : {}),
|
|
1997
|
+
...(params.resumeFromCheckpoint ? { resumedInput: queuedForThisRun } : {}),
|
|
1973
1998
|
...(params.waitForInbound ? { waitForInbound: params.waitForInbound } : {}),
|
|
1974
1999
|
...(params.projectInstructionContext
|
|
1975
2000
|
? { projectInstructionContext: params.projectInstructionContext }
|
|
1976
2001
|
: {}),
|
|
1977
2002
|
...(providerContextWindow !== undefined ? { providerContextWindow } : {}),
|
|
2003
|
+
resolveModelContextWindow: async (model) => {
|
|
2004
|
+
if (!modelContextWindows.has(model)) {
|
|
2005
|
+
modelContextWindows.set(
|
|
2006
|
+
model,
|
|
2007
|
+
await resolveProviderContextWindow(
|
|
2008
|
+
resilientProvider,
|
|
2009
|
+
model,
|
|
2010
|
+
ctx.abortController.signal,
|
|
2011
|
+
runConfig.timeoutMs,
|
|
2012
|
+
log,
|
|
2013
|
+
),
|
|
2014
|
+
)
|
|
2015
|
+
}
|
|
2016
|
+
return modelContextWindows.get(model)
|
|
2017
|
+
},
|
|
1978
2018
|
workingStateManager,
|
|
1979
2019
|
taskRouter: params.taskRouter,
|
|
1980
2020
|
contextReducer: params.contextReducer,
|
|
@@ -2333,7 +2373,6 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
2333
2373
|
}
|
|
2334
2374
|
} else {
|
|
2335
2375
|
pushSystemMessages()
|
|
2336
|
-
let isFirstUserMessage = true
|
|
2337
2376
|
for (const msg of initialMessages) {
|
|
2338
2377
|
if (msg.role === 'system') {
|
|
2339
2378
|
// A fresh run rebuilds its current static/dynamic prompt above,
|
|
@@ -2351,11 +2390,18 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
2351
2390
|
continue
|
|
2352
2391
|
}
|
|
2353
2392
|
ctx.runMgr.pushMessage(msg)
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
// Fresh and continuation histories seed the same operator state.
|
|
2396
|
+
// A worker report or project-policy message may have role `user`,
|
|
2397
|
+
// but it must not become the task or an operator requirement.
|
|
2398
|
+
// Resume restores this state and adopts only its newer queue arrivals.
|
|
2399
|
+
if (!params.resumeFromCheckpoint && workingStateManager) {
|
|
2400
|
+
let isFirstUserMessage = true
|
|
2401
|
+
for (const message of initialMessages) {
|
|
2402
|
+
if (!isOperatorUserMessage(message) || !message.content.trim()) continue
|
|
2403
|
+
extractFromUserMessage(workingStateManager, message.content, isFirstUserMessage)
|
|
2404
|
+
isFirstUserMessage = false
|
|
2359
2405
|
}
|
|
2360
2406
|
}
|
|
2361
2407
|
|
|
@@ -2713,6 +2759,16 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
2713
2759
|
ctx.log,
|
|
2714
2760
|
)
|
|
2715
2761
|
|
|
2762
|
+
if (outputVerdict.blocked || outputVerdict.rewritten !== undefined) {
|
|
2763
|
+
ctx.runMgr.clearStructuredOutput()
|
|
2764
|
+
if (
|
|
2765
|
+
params.structuredOutput &&
|
|
2766
|
+
outputVerdict.rewritten !== undefined &&
|
|
2767
|
+
ctx.runMgr.stopReason === 'end_turn'
|
|
2768
|
+
)
|
|
2769
|
+
ctx.runMgr.setStopReason('output_guardrail')
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2716
2772
|
if (outputVerdict.blocked) {
|
|
2717
2773
|
await eventTranslator.emitEvent({
|
|
2718
2774
|
type: 'guardrail_triggered',
|
|
@@ -2773,6 +2829,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
2773
2829
|
}
|
|
2774
2830
|
}
|
|
2775
2831
|
}
|
|
2832
|
+
if (ctx.abortController.signal.aborted) ctx.runMgr.markCancelled()
|
|
2776
2833
|
yield* resultAssembler.completeRun(rootSpan)
|
|
2777
2834
|
} catch (err) {
|
|
2778
2835
|
// A failed run still spent its steps; report them.
|