@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,6 +1,10 @@
|
|
|
1
1
|
import { type Span, SpanStatusCode } from '@opentelemetry/api'
|
|
2
2
|
import { resolveContextWindow } from '../../../compaction/context-window.js'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
extractFromAssistantMessage,
|
|
5
|
+
extractFromUserMessage,
|
|
6
|
+
} from '../../../compaction/extractor.js'
|
|
7
|
+
import { estimateMessageTokens } from '../../../compaction/token-estimate.js'
|
|
4
8
|
import { AUTO_CONTINUATION_USER_MESSAGE } from '../../../constants/continuation.js'
|
|
5
9
|
import {
|
|
6
10
|
DEFAULT_STRUCTURED_OUTPUT_RETRIES,
|
|
@@ -9,6 +13,7 @@ import {
|
|
|
9
13
|
import { renderSkillsSection } from '../../../persona/assembler.js'
|
|
10
14
|
import { resolveProviderCapabilities } from '../../../provider/capabilities.js'
|
|
11
15
|
import { collectChatCompletion } from '../../../provider/collect-chat-completion.js'
|
|
16
|
+
import { renderToolSchema } from '../../../registry/tool/schema.js'
|
|
12
17
|
import { formatCompletionNotification } from '../../../scheduler/completion-inbox.js'
|
|
13
18
|
import {
|
|
14
19
|
GENAI,
|
|
@@ -24,6 +29,7 @@ import { NamzuError } from '../../../types/errors/index.js'
|
|
|
24
29
|
import type { MessageId } from '../../../types/ids/index.js'
|
|
25
30
|
import {
|
|
26
31
|
type Message,
|
|
32
|
+
type UserMessage,
|
|
27
33
|
createAssistantMessage,
|
|
28
34
|
createRuntimeContextMessage,
|
|
29
35
|
createSystemMessage,
|
|
@@ -33,6 +39,7 @@ import { classifyProviderError } from '../../../types/provider/errors.js'
|
|
|
33
39
|
import type { ChatCompletionResponse } from '../../../types/provider/index.js'
|
|
34
40
|
import type { AnswerReview } from '../../../types/run/answer-review.js'
|
|
35
41
|
import type {
|
|
42
|
+
PrepareStepContext,
|
|
36
43
|
PrepareStepResult,
|
|
37
44
|
RunEvent,
|
|
38
45
|
StepFailure,
|
|
@@ -54,10 +61,16 @@ import {
|
|
|
54
61
|
markProviderRejectedImage,
|
|
55
62
|
projectRequestRichContent,
|
|
56
63
|
} from '../request-rich-content.js'
|
|
57
|
-
import { formatSteeringNote } from '../steering.js'
|
|
64
|
+
import { formatSteeringNote, isOperatorUserMessage } from '../steering.js'
|
|
65
|
+
import { parseNativeCandidate } from './native-output.js'
|
|
58
66
|
import { runAdvisoryPhase } from './phases/advisory.js'
|
|
59
67
|
import { runIterationCheckpoint } from './phases/checkpoint.js'
|
|
60
|
-
import {
|
|
68
|
+
import {
|
|
69
|
+
activeContextWindow,
|
|
70
|
+
measureContext,
|
|
71
|
+
relieveOverflow,
|
|
72
|
+
runCompactionCheck,
|
|
73
|
+
} from './phases/compaction.js'
|
|
61
74
|
import type { IterationContext } from './phases/index.js'
|
|
62
75
|
import { runPlanGate } from './phases/plan.js'
|
|
63
76
|
import { runToolReview } from './phases/tool-review.js'
|
|
@@ -168,9 +181,34 @@ export class IterationOrchestrator {
|
|
|
168
181
|
* sets it.
|
|
169
182
|
*/
|
|
170
183
|
private stopDeferredForOutstandingWork = false
|
|
184
|
+
/** One current input, independent of the compactable history array. */
|
|
185
|
+
private latestUserMessage: UserMessage | undefined
|
|
171
186
|
|
|
172
187
|
constructor(ctx: IterationContext) {
|
|
173
|
-
this.ctx =
|
|
188
|
+
this.ctx = {
|
|
189
|
+
...ctx,
|
|
190
|
+
onSteeringDelivered: (text) => {
|
|
191
|
+
this.rememberUserMessage(createRuntimeContextMessage(text, 'steering'))
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
ctx.checkpointMgr.setLatestUserMessageSource(() => this.latestUserMessage)
|
|
195
|
+
ctx.checkpointMgr.setStructuredReviewAttemptsSource?.(() => this.structuredReviewAttempts)
|
|
196
|
+
ctx.checkpointMgr.setNativeStructuredAttemptsSource?.(() => this.nativeStructuredAttempts)
|
|
197
|
+
if (ctx.structuredOutput?.mode === 'native') {
|
|
198
|
+
const limit = ctx.structuredOutput.maxRetries
|
|
199
|
+
if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 0))
|
|
200
|
+
throw new RangeError(
|
|
201
|
+
'Native structuredOutput.maxRetries must be a nonnegative safe integer',
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
if (
|
|
205
|
+
ctx.structuredOutput?.mode !== undefined &&
|
|
206
|
+
!['tool', 'native'].includes(ctx.structuredOutput.mode)
|
|
207
|
+
)
|
|
208
|
+
throw new RangeError('Unknown structuredOutput.mode')
|
|
209
|
+
const maxReviews = ctx.structuredOutput?.maxReviews
|
|
210
|
+
if (maxReviews !== undefined && (!Number.isSafeInteger(maxReviews) || maxReviews < 0))
|
|
211
|
+
throw new RangeError('structuredOutput.maxReviews must be a nonnegative safe integer')
|
|
174
212
|
}
|
|
175
213
|
|
|
176
214
|
/**
|
|
@@ -252,6 +290,17 @@ export class IterationOrchestrator {
|
|
|
252
290
|
const { runConfig, runMgr } = this.ctx
|
|
253
291
|
const { model } = runConfig
|
|
254
292
|
const tracer = getTracer()
|
|
293
|
+
// Resume hydration happens after construction, before the loop starts.
|
|
294
|
+
this.latestUserMessage = this.ctx.checkpointMgr.restoredLatestUserMessage
|
|
295
|
+
this.structuredReviewAttempts = this.ctx.checkpointMgr.restoredStructuredReviewAttempts ?? 0
|
|
296
|
+
this.nativeStructuredAttempts = this.ctx.checkpointMgr.restoredNativeStructuredAttempts ?? 0
|
|
297
|
+
if (!this.latestUserMessage) {
|
|
298
|
+
for (const message of runMgr.messages) this.rememberUserMessage(message, false)
|
|
299
|
+
}
|
|
300
|
+
// The restored field can outlive the historical message it describes.
|
|
301
|
+
// Only known post-checkpoint arrivals may supersede it, never an old
|
|
302
|
+
// retained user turn encountered while scanning restored history.
|
|
303
|
+
for (const message of this.ctx.resumedInput ?? []) this.rememberUserMessage(message)
|
|
255
304
|
|
|
256
305
|
// One context-overflow relief per *stuck point*, not per run.
|
|
257
306
|
//
|
|
@@ -278,6 +327,26 @@ export class IterationOrchestrator {
|
|
|
278
327
|
// no post-loop block reaches.
|
|
279
328
|
try {
|
|
280
329
|
while (true) {
|
|
330
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
331
|
+
runMgr.setStopReason('cancelled')
|
|
332
|
+
runMgr.markCancelled()
|
|
333
|
+
break
|
|
334
|
+
}
|
|
335
|
+
if (
|
|
336
|
+
this.ctx.structuredOutput?.mode === 'native' &&
|
|
337
|
+
this.nativeStructuredAttempts > this.structuredOutputRetryLimit()
|
|
338
|
+
) {
|
|
339
|
+
runMgr.setStopReason('structured_output_failed')
|
|
340
|
+
break
|
|
341
|
+
}
|
|
342
|
+
if (
|
|
343
|
+
this.ctx.structuredOutput?.review &&
|
|
344
|
+
this.structuredReviewAttempts >
|
|
345
|
+
(this.ctx.structuredOutput.maxReviews ?? DEFAULT_ANSWER_REVIEW_LIMIT)
|
|
346
|
+
) {
|
|
347
|
+
runMgr.setStopReason('answer_rejected')
|
|
348
|
+
break
|
|
349
|
+
}
|
|
281
350
|
// Read AND clear, in that order, in this one place.
|
|
282
351
|
//
|
|
283
352
|
// The flag is set by the previous iteration and read by this
|
|
@@ -325,6 +394,14 @@ export class IterationOrchestrator {
|
|
|
325
394
|
// run and been paid for; this is the seam a host with a live
|
|
326
395
|
// rate limit or a revoked tenant actually needs.
|
|
327
396
|
const veto = await this.beforeStep(runMgr.currentIteration + 1)
|
|
397
|
+
// The hook may settle because its run signal was aborted. Stop
|
|
398
|
+
// before interpreting that settlement as a policy refusal or
|
|
399
|
+
// counting an iteration that will never reach the provider.
|
|
400
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
401
|
+
runMgr.setStopReason('cancelled')
|
|
402
|
+
runMgr.markCancelled()
|
|
403
|
+
break
|
|
404
|
+
}
|
|
328
405
|
if (veto) {
|
|
329
406
|
// Namespaced. The un-namespaced keys elsewhere in this file are
|
|
330
407
|
// the frozen inventory LOG-22 exists to drain; a new call site
|
|
@@ -431,10 +508,6 @@ export class IterationOrchestrator {
|
|
|
431
508
|
// compaction preserves). No-op when no provider is configured.
|
|
432
509
|
await refreshWorkingMemory(this.ctx)
|
|
433
510
|
await runCompactionCheck(this.ctx)
|
|
434
|
-
// A context edit is a host-visible state transition, not a prelude
|
|
435
|
-
// whose events may wait behind the next network call. In particular,
|
|
436
|
-
// a slow or failing provider must not leave the host displaying the
|
|
437
|
-
// pre-compaction context after Run.messages already shrank.
|
|
438
511
|
yield* this.ctx.drainPending()
|
|
439
512
|
|
|
440
513
|
// Cache discipline: keep the tools param byte-stable even on the
|
|
@@ -452,10 +525,25 @@ export class IterationOrchestrator {
|
|
|
452
525
|
// Shape this step before calling the model. `stopWhen` decides
|
|
453
526
|
// whether to keep going; this decides HOW. No-op when the host
|
|
454
527
|
// supplied no hook.
|
|
528
|
+
const contextModelBeforePreparation = this.ctx.contextModel ?? model
|
|
455
529
|
const step = await this.prepareStep(iterationNum)
|
|
530
|
+
stepModel = step.model ?? model
|
|
531
|
+
await this.selectContextModel(stepModel)
|
|
532
|
+
// Preserve post-compaction preparation/recall semantics. A changed
|
|
533
|
+
// model needs a second check against its own window; never replay
|
|
534
|
+
// host preparation effects merely to rebuild its request guidance.
|
|
535
|
+
if (stepModel !== contextModelBeforePreparation) await runCompactionCheck(this.ctx)
|
|
536
|
+
// Publish context edits before entering a possibly slow provider.
|
|
537
|
+
yield* this.ctx.drainPending()
|
|
456
538
|
|
|
457
539
|
const stepAllowedTools = step.allowedTools ?? this.ctx.allowedTools
|
|
458
|
-
const llmTools = this.ctx.tools
|
|
540
|
+
const llmTools = this.ctx.tools
|
|
541
|
+
.toLLMTools(stepAllowedTools)
|
|
542
|
+
.filter(
|
|
543
|
+
(tool) =>
|
|
544
|
+
this.ctx.structuredOutput?.mode !== 'native' ||
|
|
545
|
+
tool.function.name !== STRUCTURED_OUTPUT_TOOL_NAME,
|
|
546
|
+
)
|
|
459
547
|
// The same list the request was built from now also bounds what
|
|
460
548
|
// may run. Narrowing only the request left the restriction
|
|
461
549
|
// presentational — the model was shown fewer tools and could
|
|
@@ -632,6 +720,18 @@ export class IterationOrchestrator {
|
|
|
632
720
|
this.ctx.provider,
|
|
633
721
|
{
|
|
634
722
|
model: stepModel,
|
|
723
|
+
...(this.ctx.structuredOutput?.mode === 'native'
|
|
724
|
+
? {
|
|
725
|
+
responseFormat: {
|
|
726
|
+
type: 'json_schema' as const,
|
|
727
|
+
json_schema: {
|
|
728
|
+
name: 'structured_output',
|
|
729
|
+
schema: renderToolSchema(this.ctx.structuredOutput.schema),
|
|
730
|
+
strict: true,
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
}
|
|
734
|
+
: {}),
|
|
635
735
|
providerRoute: requestedRoute,
|
|
636
736
|
messages,
|
|
637
737
|
tools: llmTools.length > 0 ? llmTools : undefined,
|
|
@@ -771,11 +871,7 @@ export class IterationOrchestrator {
|
|
|
771
871
|
const contextFigures = this.ctx.compactionConfig
|
|
772
872
|
? (() => {
|
|
773
873
|
const measured = measureContext(this.ctx)
|
|
774
|
-
const window =
|
|
775
|
-
this.ctx.compactionConfig?.contextWindowTokens,
|
|
776
|
-
runConfig.model,
|
|
777
|
-
this.ctx.providerContextWindow,
|
|
778
|
-
)
|
|
874
|
+
const window = activeContextWindow(this.ctx)
|
|
779
875
|
return {
|
|
780
876
|
contextTokens: measured.tokens,
|
|
781
877
|
contextMeasuredBy: measured.source,
|
|
@@ -932,6 +1028,70 @@ export class IterationOrchestrator {
|
|
|
932
1028
|
costBefore,
|
|
933
1029
|
})
|
|
934
1030
|
|
|
1031
|
+
if (this.ctx.structuredOutput?.mode === 'native') {
|
|
1032
|
+
const candidate = await parseNativeCandidate(
|
|
1033
|
+
this.ctx.structuredOutput.schema,
|
|
1034
|
+
response,
|
|
1035
|
+
this.ctx.abortController.signal,
|
|
1036
|
+
)
|
|
1037
|
+
let outcome: 'accepted' | 'retry' | 'exhausted' | 'cancelled'
|
|
1038
|
+
if (candidate.success) outcome = await this.reviewStructuredOutput(candidate.value)
|
|
1039
|
+
else {
|
|
1040
|
+
this.nativeStructuredAttempts++
|
|
1041
|
+
runMgr.pushMessage(
|
|
1042
|
+
createRuntimeContextMessage(
|
|
1043
|
+
'Return a complete JSON value matching the supplied response schema. Do not continue a partial JSON fragment.',
|
|
1044
|
+
'structured-output',
|
|
1045
|
+
),
|
|
1046
|
+
)
|
|
1047
|
+
const checkpoint = await this.ctx.checkpointMgr.create(runMgr, iterationNum)
|
|
1048
|
+
await this.ctx.emitEvent({
|
|
1049
|
+
type: 'checkpoint_created',
|
|
1050
|
+
runId: runMgr.id,
|
|
1051
|
+
checkpointId: checkpoint.id,
|
|
1052
|
+
iteration: iterationNum,
|
|
1053
|
+
})
|
|
1054
|
+
outcome =
|
|
1055
|
+
this.nativeStructuredAttempts > this.structuredOutputRetryLimit()
|
|
1056
|
+
? 'exhausted'
|
|
1057
|
+
: 'retry'
|
|
1058
|
+
}
|
|
1059
|
+
await this.ctx.emitEvent({
|
|
1060
|
+
type: 'iteration_completed',
|
|
1061
|
+
runId: runMgr.id,
|
|
1062
|
+
iteration: iterationNum,
|
|
1063
|
+
hasToolCalls: false,
|
|
1064
|
+
})
|
|
1065
|
+
yield* this.ctx.drainPending()
|
|
1066
|
+
if (this.ctx.abortController.signal.aborted || outcome === 'cancelled') {
|
|
1067
|
+
runMgr.setStopReason('cancelled')
|
|
1068
|
+
runMgr.markCancelled()
|
|
1069
|
+
break
|
|
1070
|
+
}
|
|
1071
|
+
if (outcome === 'accepted') {
|
|
1072
|
+
if (!forceFinalize) {
|
|
1073
|
+
const changed = yield* this.holdForOutstandingWork(iterationNum, false)
|
|
1074
|
+
const inbound = this.deliverInbound()
|
|
1075
|
+
if (changed || inbound > 0) continue
|
|
1076
|
+
}
|
|
1077
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1078
|
+
runMgr.setStopReason('cancelled')
|
|
1079
|
+
runMgr.markCancelled()
|
|
1080
|
+
break
|
|
1081
|
+
}
|
|
1082
|
+
this.publishStructuredOutput()
|
|
1083
|
+
runMgr.setStopReason('end_turn')
|
|
1084
|
+
break
|
|
1085
|
+
}
|
|
1086
|
+
if (outcome === 'exhausted') {
|
|
1087
|
+
runMgr.setStopReason(
|
|
1088
|
+
candidate.success ? 'answer_rejected' : 'structured_output_failed',
|
|
1089
|
+
)
|
|
1090
|
+
break
|
|
1091
|
+
}
|
|
1092
|
+
continue
|
|
1093
|
+
}
|
|
1094
|
+
|
|
935
1095
|
const hasContent =
|
|
936
1096
|
response.message.content !== null && response.message.content.length > 0
|
|
937
1097
|
|
|
@@ -1022,6 +1182,11 @@ export class IterationOrchestrator {
|
|
|
1022
1182
|
// a loud stop rather than a loop.
|
|
1023
1183
|
if (!forceFinalize && this.ctx.reviewAnswer) {
|
|
1024
1184
|
const review = await this.reviewAnswer(response.message.content ?? '')
|
|
1185
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1186
|
+
runMgr.setStopReason('cancelled')
|
|
1187
|
+
runMgr.markCancelled()
|
|
1188
|
+
break
|
|
1189
|
+
}
|
|
1025
1190
|
if (review && !review.accept) {
|
|
1026
1191
|
const attempt = ++this.answerReviewAttempts
|
|
1027
1192
|
const limit = this.ctx.maxAnswerReviews ?? DEFAULT_ANSWER_REVIEW_LIMIT
|
|
@@ -1159,12 +1324,39 @@ export class IterationOrchestrator {
|
|
|
1159
1324
|
// run ends here rather than paying for another turn whose only
|
|
1160
1325
|
// job would be to restate it — unless it shared its turn with
|
|
1161
1326
|
// other calls, which relays instead. See the method.
|
|
1162
|
-
|
|
1327
|
+
const structuredOutcome = await this.captureStructuredOutput(
|
|
1328
|
+
reviewOutcome.results,
|
|
1329
|
+
response,
|
|
1330
|
+
)
|
|
1331
|
+
if (
|
|
1332
|
+
structuredOutcome === 'retry' ||
|
|
1333
|
+
structuredOutcome === 'exhausted' ||
|
|
1334
|
+
structuredOutcome === 'cancelled'
|
|
1335
|
+
) {
|
|
1336
|
+
await this.ctx.emitEvent({
|
|
1337
|
+
type: 'iteration_completed',
|
|
1338
|
+
runId: runMgr.id,
|
|
1339
|
+
iteration: iterationNum,
|
|
1340
|
+
hasToolCalls: true,
|
|
1341
|
+
})
|
|
1342
|
+
yield* this.ctx.drainPending()
|
|
1343
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1344
|
+
runMgr.setStopReason('cancelled')
|
|
1345
|
+
runMgr.markCancelled()
|
|
1346
|
+
break
|
|
1347
|
+
}
|
|
1348
|
+
if (structuredOutcome === 'retry') continue
|
|
1349
|
+
runMgr.setStopReason(
|
|
1350
|
+
structuredOutcome === 'cancelled' ? 'cancelled' : 'answer_rejected',
|
|
1351
|
+
)
|
|
1352
|
+
if (structuredOutcome === 'cancelled') runMgr.markCancelled()
|
|
1353
|
+
break
|
|
1354
|
+
}
|
|
1355
|
+
if (structuredOutcome === 'accepted') {
|
|
1163
1356
|
this.ctx.log.info('Structured output produced — ending run', {
|
|
1164
1357
|
[NAMZU.RUN_ID]: runMgr.id,
|
|
1165
1358
|
[NAMZU.ITERATION]: iterationNum,
|
|
1166
1359
|
})
|
|
1167
|
-
runMgr.setStopReason('end_turn')
|
|
1168
1360
|
await this.ctx.emitEvent({
|
|
1169
1361
|
type: 'iteration_completed',
|
|
1170
1362
|
runId: runMgr.id,
|
|
@@ -1172,6 +1364,13 @@ export class IterationOrchestrator {
|
|
|
1172
1364
|
hasToolCalls: true,
|
|
1173
1365
|
})
|
|
1174
1366
|
yield* this.ctx.drainPending()
|
|
1367
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1368
|
+
runMgr.setStopReason('cancelled')
|
|
1369
|
+
runMgr.markCancelled()
|
|
1370
|
+
break
|
|
1371
|
+
}
|
|
1372
|
+
this.publishStructuredOutput()
|
|
1373
|
+
runMgr.setStopReason('end_turn')
|
|
1175
1374
|
break
|
|
1176
1375
|
}
|
|
1177
1376
|
|
|
@@ -1603,19 +1802,51 @@ export class IterationOrchestrator {
|
|
|
1603
1802
|
* message becomes the reason, so an operator is not left with a run
|
|
1604
1803
|
* that stopped and no account of it.
|
|
1605
1804
|
*/
|
|
1805
|
+
private stepContext(stepNumber: number, prepared: PrepareStepResult): PrepareStepContext {
|
|
1806
|
+
const model = prepared.model ?? this.ctx.runConfig.model
|
|
1807
|
+
const window = resolveContextWindow(
|
|
1808
|
+
this.ctx.compactionConfig?.contextWindowTokens,
|
|
1809
|
+
model,
|
|
1810
|
+
model === this.ctx.runConfig.model
|
|
1811
|
+
? this.ctx.providerContextWindow
|
|
1812
|
+
: model === this.ctx.contextModel
|
|
1813
|
+
? this.ctx.activeProviderContextWindow
|
|
1814
|
+
: undefined,
|
|
1815
|
+
)
|
|
1816
|
+
const skills = prepared.skills ? renderSkillsSection([...prepared.skills]) : null
|
|
1817
|
+
const preamble = [prepared.system, skills].filter(Boolean).join('\n\n')
|
|
1818
|
+
const preparedTokens = preamble ? estimateMessageTokens(createSystemMessage(preamble)) : 0
|
|
1819
|
+
const responseReserve = Math.min(
|
|
1820
|
+
prepared.maxResponseTokens ??
|
|
1821
|
+
this.ctx.runConfig.maxResponseTokens ??
|
|
1822
|
+
Math.floor(window.tokens / 4),
|
|
1823
|
+
Math.floor(window.tokens / 4),
|
|
1824
|
+
)
|
|
1825
|
+
return {
|
|
1826
|
+
runId: this.ctx.runMgr.id,
|
|
1827
|
+
stepNumber,
|
|
1828
|
+
messages: this.ctx.runMgr.messages,
|
|
1829
|
+
...(this.latestUserMessage ? { latestUserMessage: this.latestUserMessage } : {}),
|
|
1830
|
+
signal: this.ctx.abortController.signal,
|
|
1831
|
+
contextBudget: {
|
|
1832
|
+
windowTokens: window.tokens,
|
|
1833
|
+
remainingTokens: Math.max(
|
|
1834
|
+
0,
|
|
1835
|
+
Math.floor(
|
|
1836
|
+
window.tokens - measureContext(this.ctx).tokens - preparedTokens - responseReserve,
|
|
1837
|
+
),
|
|
1838
|
+
),
|
|
1839
|
+
},
|
|
1840
|
+
steps: this.steps,
|
|
1841
|
+
prepared,
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1606
1845
|
private async beforeStep(stepNumber: number): Promise<StepVeto | undefined> {
|
|
1607
1846
|
const configured = this.ctx.beforeStep
|
|
1608
1847
|
if (!configured) return undefined
|
|
1609
1848
|
try {
|
|
1610
|
-
return (
|
|
1611
|
-
(await configured({
|
|
1612
|
-
runId: this.ctx.runMgr.id,
|
|
1613
|
-
stepNumber,
|
|
1614
|
-
messages: this.ctx.runMgr.messages,
|
|
1615
|
-
steps: this.steps,
|
|
1616
|
-
prepared: {},
|
|
1617
|
-
})) ?? undefined
|
|
1618
|
-
)
|
|
1849
|
+
return (await configured(this.stepContext(stepNumber, {}))) ?? undefined
|
|
1619
1850
|
} catch (err) {
|
|
1620
1851
|
return { reason: `beforeStep threw: ${toErrorMessage(err)}` }
|
|
1621
1852
|
}
|
|
@@ -1641,14 +1872,9 @@ export class IterationOrchestrator {
|
|
|
1641
1872
|
let result: PrepareStepResult = {}
|
|
1642
1873
|
for (const stage of stages) {
|
|
1643
1874
|
try {
|
|
1644
|
-
const decided = await stage(
|
|
1645
|
-
runId: this.ctx.runMgr.id,
|
|
1646
|
-
stepNumber,
|
|
1647
|
-
messages: this.ctx.runMgr.messages,
|
|
1648
|
-
steps: this.steps,
|
|
1649
|
-
prepared: result,
|
|
1650
|
-
})
|
|
1875
|
+
const decided = await stage(this.stepContext(stepNumber, result))
|
|
1651
1876
|
if (decided) result = { ...result, ...decided }
|
|
1877
|
+
await this.selectContextModel(result.model ?? this.ctx.runConfig.model)
|
|
1652
1878
|
} catch (err) {
|
|
1653
1879
|
// Skipped, and the rest still run: one broken concern must
|
|
1654
1880
|
// not silently disable the others it was declared beside.
|
|
@@ -1710,6 +1936,18 @@ export class IterationOrchestrator {
|
|
|
1710
1936
|
return prepared
|
|
1711
1937
|
}
|
|
1712
1938
|
|
|
1939
|
+
private async selectContextModel(model: string | undefined): Promise<void> {
|
|
1940
|
+
if (model !== (this.ctx.contextModel ?? this.ctx.runConfig.model)) {
|
|
1941
|
+
// A measurement from another tokenizer cannot price the new request.
|
|
1942
|
+
this.ctx.runMgr.clearLastPromptTokens()
|
|
1943
|
+
}
|
|
1944
|
+
this.ctx.contextModel = model
|
|
1945
|
+
this.ctx.activeProviderContextWindow =
|
|
1946
|
+
model && model !== this.ctx.runConfig.model && !this.ctx.compactionConfig?.contextWindowTokens
|
|
1947
|
+
? await this.ctx.resolveModelContextWindow?.(model)
|
|
1948
|
+
: undefined
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1713
1951
|
/** Steps completed so far, exposed on the returned `Run`. */
|
|
1714
1952
|
private readonly steps: StepResult[] = []
|
|
1715
1953
|
|
|
@@ -1738,18 +1976,33 @@ export class IterationOrchestrator {
|
|
|
1738
1976
|
* empty drain must change nothing at all: a `continue` on nothing queued
|
|
1739
1977
|
* spends an iteration and a model call to say the same thing again.
|
|
1740
1978
|
*/
|
|
1979
|
+
private rememberUserMessage(message: Message, arriving = true): void {
|
|
1980
|
+
if (!isOperatorUserMessage(message)) return
|
|
1981
|
+
this.latestUserMessage = message
|
|
1982
|
+
// The hook field alone does not reach the model. Preserve arrivals in
|
|
1983
|
+
// the compaction state too, before their original message or attached
|
|
1984
|
+
// tool result can be shed. Initial history was already extracted at seed.
|
|
1985
|
+
const manager = this.ctx.workingStateManager
|
|
1986
|
+
if (arriving && manager) {
|
|
1987
|
+
extractFromUserMessage(manager, message.content, !manager.getState().task)
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1741
1991
|
private deliverInbound(): number {
|
|
1742
1992
|
const queued = this.ctx.inboundMessages?.() ?? []
|
|
1743
|
-
for (const message of queued)
|
|
1993
|
+
for (const message of queued) {
|
|
1994
|
+
this.ctx.runMgr.pushMessage(message)
|
|
1995
|
+
this.rememberUserMessage(message)
|
|
1996
|
+
}
|
|
1744
1997
|
|
|
1745
1998
|
// The steering channel's remainder. `attachSteering` already took
|
|
1746
1999
|
// what it could carry on a tool result; anything still pending is
|
|
1747
2000
|
// guidance from a turn that had no result to attach it to.
|
|
1748
2001
|
const stranded = this.ctx.steering?.drain()
|
|
1749
2002
|
if (stranded) {
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
)
|
|
2003
|
+
const message = createRuntimeContextMessage(formatSteeringNote(stranded), 'steering')
|
|
2004
|
+
this.ctx.runMgr.pushMessage(message)
|
|
2005
|
+
this.rememberUserMessage(createRuntimeContextMessage(stranded, 'steering'))
|
|
1753
2006
|
}
|
|
1754
2007
|
|
|
1755
2008
|
return queued.length + (stranded ? 1 : 0)
|
|
@@ -1856,7 +2109,10 @@ export class IterationOrchestrator {
|
|
|
1856
2109
|
|
|
1857
2110
|
/** Turns spent asking the model again for a valid structured output. */
|
|
1858
2111
|
private structuredOutputAttempts = 0
|
|
2112
|
+
private nativeStructuredAttempts = 0
|
|
1859
2113
|
private structuredOutputDone = false
|
|
2114
|
+
private pendingStructuredOutput: unknown
|
|
2115
|
+
private structuredReviewAttempts = 0
|
|
1860
2116
|
|
|
1861
2117
|
private structuredOutputRetryLimit(): number {
|
|
1862
2118
|
return this.ctx.structuredOutput?.maxRetries ?? DEFAULT_STRUCTURED_OUTPUT_RETRIES
|
|
@@ -1883,6 +2139,7 @@ export class IterationOrchestrator {
|
|
|
1883
2139
|
results: readonly ToolCallOutcome[],
|
|
1884
2140
|
response: ChatCompletionResponse,
|
|
1885
2141
|
): ToolCallOutcome | undefined {
|
|
2142
|
+
if (this.ctx.structuredOutput?.mode === 'native') return undefined
|
|
1886
2143
|
const terminal = results.filter((r) => this.ctx.tools.get(r.toolName)?.terminal === true)
|
|
1887
2144
|
if (terminal.length === 0) return undefined
|
|
1888
2145
|
|
|
@@ -1951,13 +2208,14 @@ export class IterationOrchestrator {
|
|
|
1951
2208
|
* doing work, and it is the bound the neighbour relies on for the
|
|
1952
2209
|
* identical pathology.
|
|
1953
2210
|
*/
|
|
1954
|
-
private captureStructuredOutput(
|
|
2211
|
+
private async captureStructuredOutput(
|
|
1955
2212
|
results: readonly ToolCallOutcome[],
|
|
1956
2213
|
response: ChatCompletionResponse,
|
|
1957
|
-
):
|
|
1958
|
-
if (!this.needsStructuredOutput()
|
|
2214
|
+
): Promise<'absent' | 'accepted' | 'retry' | 'exhausted' | 'cancelled'> {
|
|
2215
|
+
if (!this.needsStructuredOutput() || this.ctx.structuredOutput?.mode === 'native')
|
|
2216
|
+
return 'absent'
|
|
1959
2217
|
const hit = results.find((r) => r.toolName === STRUCTURED_OUTPUT_TOOL_NAME && !r.isError)
|
|
1960
|
-
if (!hit) return
|
|
2218
|
+
if (!hit) return 'absent'
|
|
1961
2219
|
|
|
1962
2220
|
const callCount = response.message.toolCalls?.length ?? 0
|
|
1963
2221
|
if (callCount > 1) {
|
|
@@ -1965,18 +2223,90 @@ export class IterationOrchestrator {
|
|
|
1965
2223
|
[NAMZU.RUN_ID]: this.ctx.runMgr.id,
|
|
1966
2224
|
'namzu.runtime.calls_in_turn': callCount,
|
|
1967
2225
|
})
|
|
1968
|
-
return
|
|
2226
|
+
return 'absent'
|
|
1969
2227
|
}
|
|
1970
2228
|
|
|
2229
|
+
let parsed: unknown
|
|
1971
2230
|
try {
|
|
1972
|
-
|
|
2231
|
+
parsed = JSON.parse(hit.output)
|
|
1973
2232
|
} catch {
|
|
1974
2233
|
// The tool serializes its own validated input, so this is
|
|
1975
2234
|
// unreachable in practice; keep the raw text rather than losing it.
|
|
1976
|
-
this.ctx.
|
|
2235
|
+
if (this.ctx.structuredOutput?.review)
|
|
2236
|
+
throw new Error(
|
|
2237
|
+
'Structured review requires an intact JSON tool result; check tool-output limits and result transformations',
|
|
2238
|
+
)
|
|
2239
|
+
parsed = hit.output
|
|
1977
2240
|
}
|
|
2241
|
+
return this.reviewStructuredOutput(parsed)
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
private publishStructuredOutput(): void {
|
|
2245
|
+
this.ctx.runMgr.setStructuredOutput(this.pendingStructuredOutput)
|
|
1978
2246
|
this.structuredOutputDone = true
|
|
1979
|
-
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
private async reviewStructuredOutput(
|
|
2250
|
+
parsed: unknown,
|
|
2251
|
+
): Promise<'accepted' | 'retry' | 'exhausted' | 'cancelled'> {
|
|
2252
|
+
if (this.ctx.abortController.signal.aborted) return 'cancelled'
|
|
2253
|
+
const reviewer = this.ctx.structuredOutput?.review
|
|
2254
|
+
if (reviewer) {
|
|
2255
|
+
const signal = this.ctx.abortController.signal
|
|
2256
|
+
if (signal.aborted) return 'cancelled'
|
|
2257
|
+
let onAbort: () => void = () => {}
|
|
2258
|
+
const aborted = new Promise<never>((_resolve, reject) => {
|
|
2259
|
+
onAbort = () => reject(signal.reason ?? new Error('Structured review cancelled'))
|
|
2260
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
2261
|
+
})
|
|
2262
|
+
let verdict: AnswerReview
|
|
2263
|
+
try {
|
|
2264
|
+
verdict = await Promise.race([
|
|
2265
|
+
Promise.resolve().then(() =>
|
|
2266
|
+
reviewer(structuredClone(parsed), {
|
|
2267
|
+
runId: this.ctx.runMgr.id,
|
|
2268
|
+
iteration: this.ctx.runMgr.currentIteration,
|
|
2269
|
+
signal,
|
|
2270
|
+
messages: this.ctx.runMgr.messages,
|
|
2271
|
+
}),
|
|
2272
|
+
),
|
|
2273
|
+
aborted,
|
|
2274
|
+
])
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
if (signal.aborted) return 'cancelled'
|
|
2277
|
+
throw error
|
|
2278
|
+
} finally {
|
|
2279
|
+
signal.removeEventListener('abort', onAbort)
|
|
2280
|
+
}
|
|
2281
|
+
if (signal.aborted) return 'cancelled'
|
|
2282
|
+
if (!verdict || typeof verdict.accept !== 'boolean')
|
|
2283
|
+
throw new Error('Structured reviewer returned an invalid verdict')
|
|
2284
|
+
if (!verdict.accept) {
|
|
2285
|
+
if (typeof verdict.feedback !== 'string' || verdict.feedback.trim().length === 0)
|
|
2286
|
+
throw new Error('Structured reviewer rejection requires feedback')
|
|
2287
|
+
this.structuredReviewAttempts++
|
|
2288
|
+
this.ctx.runMgr.pushMessage(createRuntimeContextMessage(verdict.feedback, 'answer-review'))
|
|
2289
|
+
// Persist both the feedback and its consumed allowance before the
|
|
2290
|
+
// next request. This checkpoint is not an approval/park boundary.
|
|
2291
|
+
const checkpoint = await this.ctx.checkpointMgr.create(
|
|
2292
|
+
this.ctx.runMgr,
|
|
2293
|
+
this.ctx.runMgr.currentIteration,
|
|
2294
|
+
)
|
|
2295
|
+
await this.ctx.emitEvent({
|
|
2296
|
+
type: 'checkpoint_created',
|
|
2297
|
+
runId: this.ctx.runMgr.id,
|
|
2298
|
+
checkpointId: checkpoint.id,
|
|
2299
|
+
iteration: this.ctx.runMgr.currentIteration,
|
|
2300
|
+
})
|
|
2301
|
+
if (signal.aborted) return 'cancelled'
|
|
2302
|
+
return this.structuredReviewAttempts >
|
|
2303
|
+
(this.ctx.structuredOutput?.maxReviews ?? DEFAULT_ANSWER_REVIEW_LIMIT)
|
|
2304
|
+
? 'exhausted'
|
|
2305
|
+
: 'retry'
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
this.pendingStructuredOutput = parsed
|
|
2309
|
+
return 'accepted'
|
|
1980
2310
|
}
|
|
1981
2311
|
|
|
1982
2312
|
/**
|
|
@@ -1997,6 +2327,7 @@ export class IterationOrchestrator {
|
|
|
1997
2327
|
return await this.ctx.reviewAnswer(answer, {
|
|
1998
2328
|
runId: this.ctx.runMgr.id,
|
|
1999
2329
|
iteration: this.ctx.runMgr.currentIteration,
|
|
2330
|
+
signal: this.ctx.abortController.signal,
|
|
2000
2331
|
messages: this.ctx.runMgr.messages,
|
|
2001
2332
|
})
|
|
2002
2333
|
} catch (err) {
|
|
@@ -2059,6 +2390,8 @@ export class IterationOrchestrator {
|
|
|
2059
2390
|
model: string,
|
|
2060
2391
|
reason: StopReason,
|
|
2061
2392
|
): Promise<StopReason | undefined> {
|
|
2393
|
+
if (this.ctx.structuredOutput?.mode === 'native') return 'structured_output_failed'
|
|
2394
|
+
|
|
2062
2395
|
const lastAssistant = [...this.ctx.runMgr.messages]
|
|
2063
2396
|
.reverse()
|
|
2064
2397
|
.find((m) => m.role === 'assistant')
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { z } from 'zod'
|
|
2
|
+
import type { ChatCompletionResponse } from '../../../types/provider/index.js'
|
|
3
|
+
import { cloneJsonValue } from '../../../utils/json-snapshot.js'
|
|
4
|
+
|
|
5
|
+
/** Native constraints are transport assistance; local validation still owns acceptance. */
|
|
6
|
+
export async function parseNativeCandidate(
|
|
7
|
+
schema: z.ZodType,
|
|
8
|
+
response: ChatCompletionResponse,
|
|
9
|
+
signal: AbortSignal,
|
|
10
|
+
): Promise<{ success: true; value: unknown } | { success: false }> {
|
|
11
|
+
signal.throwIfAborted()
|
|
12
|
+
if (response.finishReason !== 'stop' || response.message.toolCalls?.length)
|
|
13
|
+
return { success: false }
|
|
14
|
+
let input: unknown
|
|
15
|
+
try {
|
|
16
|
+
input = JSON.parse(response.message.content ?? '')
|
|
17
|
+
} catch {
|
|
18
|
+
return { success: false }
|
|
19
|
+
}
|
|
20
|
+
let abort!: () => void
|
|
21
|
+
const cancelled = new Promise<never>((_resolve, reject) => {
|
|
22
|
+
abort = () => reject(signal.reason ?? new Error('Native output validation cancelled'))
|
|
23
|
+
signal.addEventListener('abort', abort, { once: true })
|
|
24
|
+
})
|
|
25
|
+
try {
|
|
26
|
+
const parsed = await Promise.race([schema.safeParseAsync(input), cancelled])
|
|
27
|
+
signal.throwIfAborted()
|
|
28
|
+
if (!parsed.success) return { success: false }
|
|
29
|
+
// Match the serialized result contract of output-tool mode. Never rerun transforms.
|
|
30
|
+
const value = cloneJsonValue(parsed.data, false)
|
|
31
|
+
return { success: true, value }
|
|
32
|
+
} finally {
|
|
33
|
+
signal.removeEventListener('abort', abort)
|
|
34
|
+
}
|
|
35
|
+
}
|