@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,11 +1,13 @@
|
|
|
1
1
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
2
2
|
import { resolveContextWindow } from '../../../compaction/context-window.js';
|
|
3
|
-
import { extractFromAssistantMessage } from '../../../compaction/extractor.js';
|
|
3
|
+
import { extractFromAssistantMessage, extractFromUserMessage, } from '../../../compaction/extractor.js';
|
|
4
|
+
import { estimateMessageTokens } from '../../../compaction/token-estimate.js';
|
|
4
5
|
import { AUTO_CONTINUATION_USER_MESSAGE } from '../../../constants/continuation.js';
|
|
5
6
|
import { DEFAULT_STRUCTURED_OUTPUT_RETRIES, STRUCTURED_OUTPUT_REPROMPT, } from '../../../constants/tools/index.js';
|
|
6
7
|
import { renderSkillsSection } from '../../../persona/assembler.js';
|
|
7
8
|
import { resolveProviderCapabilities } from '../../../provider/capabilities.js';
|
|
8
9
|
import { collectChatCompletion } from '../../../provider/collect-chat-completion.js';
|
|
10
|
+
import { renderToolSchema } from '../../../registry/tool/schema.js';
|
|
9
11
|
import { formatCompletionNotification } from '../../../scheduler/completion-inbox.js';
|
|
10
12
|
import { GENAI, NAMZU, agentIterationSpanName, parentContext, } from '../../../telemetry/attributes.js';
|
|
11
13
|
import { getTracer } from '../../../telemetry/runtime-accessors.js';
|
|
@@ -19,10 +21,11 @@ import { stableDigest } from '../../../utils/hash.js';
|
|
|
19
21
|
import { generateMessageId } from '../../../utils/id.js';
|
|
20
22
|
import { applyLifecycleHookResults } from '../plugin-hooks.js';
|
|
21
23
|
import { DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES, markProviderRejectedImage, projectRequestRichContent, } from '../request-rich-content.js';
|
|
22
|
-
import { formatSteeringNote } from '../steering.js';
|
|
24
|
+
import { formatSteeringNote, isOperatorUserMessage } from '../steering.js';
|
|
25
|
+
import { parseNativeCandidate } from './native-output.js';
|
|
23
26
|
import { runAdvisoryPhase } from './phases/advisory.js';
|
|
24
27
|
import { runIterationCheckpoint } from './phases/checkpoint.js';
|
|
25
|
-
import { measureContext, relieveOverflow, runCompactionCheck } from './phases/compaction.js';
|
|
28
|
+
import { activeContextWindow, measureContext, relieveOverflow, runCompactionCheck, } from './phases/compaction.js';
|
|
26
29
|
import { runPlanGate } from './phases/plan.js';
|
|
27
30
|
import { runToolReview } from './phases/tool-review.js';
|
|
28
31
|
import { refreshWorkingMemory } from './phases/working-memory.js';
|
|
@@ -121,8 +124,29 @@ export class IterationOrchestrator {
|
|
|
121
124
|
* sets it.
|
|
122
125
|
*/
|
|
123
126
|
stopDeferredForOutstandingWork = false;
|
|
127
|
+
/** One current input, independent of the compactable history array. */
|
|
128
|
+
latestUserMessage;
|
|
124
129
|
constructor(ctx) {
|
|
125
|
-
this.ctx =
|
|
130
|
+
this.ctx = {
|
|
131
|
+
...ctx,
|
|
132
|
+
onSteeringDelivered: (text) => {
|
|
133
|
+
this.rememberUserMessage(createRuntimeContextMessage(text, 'steering'));
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
ctx.checkpointMgr.setLatestUserMessageSource(() => this.latestUserMessage);
|
|
137
|
+
ctx.checkpointMgr.setStructuredReviewAttemptsSource?.(() => this.structuredReviewAttempts);
|
|
138
|
+
ctx.checkpointMgr.setNativeStructuredAttemptsSource?.(() => this.nativeStructuredAttempts);
|
|
139
|
+
if (ctx.structuredOutput?.mode === 'native') {
|
|
140
|
+
const limit = ctx.structuredOutput.maxRetries;
|
|
141
|
+
if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 0))
|
|
142
|
+
throw new RangeError('Native structuredOutput.maxRetries must be a nonnegative safe integer');
|
|
143
|
+
}
|
|
144
|
+
if (ctx.structuredOutput?.mode !== undefined &&
|
|
145
|
+
!['tool', 'native'].includes(ctx.structuredOutput.mode))
|
|
146
|
+
throw new RangeError('Unknown structuredOutput.mode');
|
|
147
|
+
const maxReviews = ctx.structuredOutput?.maxReviews;
|
|
148
|
+
if (maxReviews !== undefined && (!Number.isSafeInteger(maxReviews) || maxReviews < 0))
|
|
149
|
+
throw new RangeError('structuredOutput.maxReviews must be a nonnegative safe integer');
|
|
126
150
|
}
|
|
127
151
|
/**
|
|
128
152
|
* Check the exact post-budget request for tool-result shapes the active driver
|
|
@@ -198,6 +222,19 @@ export class IterationOrchestrator {
|
|
|
198
222
|
const { runConfig, runMgr } = this.ctx;
|
|
199
223
|
const { model } = runConfig;
|
|
200
224
|
const tracer = getTracer();
|
|
225
|
+
// Resume hydration happens after construction, before the loop starts.
|
|
226
|
+
this.latestUserMessage = this.ctx.checkpointMgr.restoredLatestUserMessage;
|
|
227
|
+
this.structuredReviewAttempts = this.ctx.checkpointMgr.restoredStructuredReviewAttempts ?? 0;
|
|
228
|
+
this.nativeStructuredAttempts = this.ctx.checkpointMgr.restoredNativeStructuredAttempts ?? 0;
|
|
229
|
+
if (!this.latestUserMessage) {
|
|
230
|
+
for (const message of runMgr.messages)
|
|
231
|
+
this.rememberUserMessage(message, false);
|
|
232
|
+
}
|
|
233
|
+
// The restored field can outlive the historical message it describes.
|
|
234
|
+
// Only known post-checkpoint arrivals may supersede it, never an old
|
|
235
|
+
// retained user turn encountered while scanning restored history.
|
|
236
|
+
for (const message of this.ctx.resumedInput ?? [])
|
|
237
|
+
this.rememberUserMessage(message);
|
|
201
238
|
// One context-overflow relief per *stuck point*, not per run.
|
|
202
239
|
//
|
|
203
240
|
// The latch exists so that a second overflow immediately after a
|
|
@@ -222,6 +259,22 @@ export class IterationOrchestrator {
|
|
|
222
259
|
// no post-loop block reaches.
|
|
223
260
|
try {
|
|
224
261
|
while (true) {
|
|
262
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
263
|
+
runMgr.setStopReason('cancelled');
|
|
264
|
+
runMgr.markCancelled();
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if (this.ctx.structuredOutput?.mode === 'native' &&
|
|
268
|
+
this.nativeStructuredAttempts > this.structuredOutputRetryLimit()) {
|
|
269
|
+
runMgr.setStopReason('structured_output_failed');
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
if (this.ctx.structuredOutput?.review &&
|
|
273
|
+
this.structuredReviewAttempts >
|
|
274
|
+
(this.ctx.structuredOutput.maxReviews ?? DEFAULT_ANSWER_REVIEW_LIMIT)) {
|
|
275
|
+
runMgr.setStopReason('answer_rejected');
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
225
278
|
// Read AND clear, in that order, in this one place.
|
|
226
279
|
//
|
|
227
280
|
// The flag is set by the previous iteration and read by this
|
|
@@ -265,6 +318,14 @@ export class IterationOrchestrator {
|
|
|
265
318
|
// run and been paid for; this is the seam a host with a live
|
|
266
319
|
// rate limit or a revoked tenant actually needs.
|
|
267
320
|
const veto = await this.beforeStep(runMgr.currentIteration + 1);
|
|
321
|
+
// The hook may settle because its run signal was aborted. Stop
|
|
322
|
+
// before interpreting that settlement as a policy refusal or
|
|
323
|
+
// counting an iteration that will never reach the provider.
|
|
324
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
325
|
+
runMgr.setStopReason('cancelled');
|
|
326
|
+
runMgr.markCancelled();
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
268
329
|
if (veto) {
|
|
269
330
|
// Namespaced. The un-namespaced keys elsewhere in this file are
|
|
270
331
|
// the frozen inventory LOG-22 exists to drain; a new call site
|
|
@@ -354,10 +415,6 @@ export class IterationOrchestrator {
|
|
|
354
415
|
// compaction preserves). No-op when no provider is configured.
|
|
355
416
|
await refreshWorkingMemory(this.ctx);
|
|
356
417
|
await runCompactionCheck(this.ctx);
|
|
357
|
-
// A context edit is a host-visible state transition, not a prelude
|
|
358
|
-
// whose events may wait behind the next network call. In particular,
|
|
359
|
-
// a slow or failing provider must not leave the host displaying the
|
|
360
|
-
// pre-compaction context after Run.messages already shrank.
|
|
361
418
|
yield* this.ctx.drainPending();
|
|
362
419
|
// Cache discipline: keep the tools param byte-stable even on the
|
|
363
420
|
// forced-final iteration and forbid tool use via tool_choice
|
|
@@ -373,9 +430,22 @@ export class IterationOrchestrator {
|
|
|
373
430
|
// Shape this step before calling the model. `stopWhen` decides
|
|
374
431
|
// whether to keep going; this decides HOW. No-op when the host
|
|
375
432
|
// supplied no hook.
|
|
433
|
+
const contextModelBeforePreparation = this.ctx.contextModel ?? model;
|
|
376
434
|
const step = await this.prepareStep(iterationNum);
|
|
435
|
+
stepModel = step.model ?? model;
|
|
436
|
+
await this.selectContextModel(stepModel);
|
|
437
|
+
// Preserve post-compaction preparation/recall semantics. A changed
|
|
438
|
+
// model needs a second check against its own window; never replay
|
|
439
|
+
// host preparation effects merely to rebuild its request guidance.
|
|
440
|
+
if (stepModel !== contextModelBeforePreparation)
|
|
441
|
+
await runCompactionCheck(this.ctx);
|
|
442
|
+
// Publish context edits before entering a possibly slow provider.
|
|
443
|
+
yield* this.ctx.drainPending();
|
|
377
444
|
const stepAllowedTools = step.allowedTools ?? this.ctx.allowedTools;
|
|
378
|
-
const llmTools = this.ctx.tools
|
|
445
|
+
const llmTools = this.ctx.tools
|
|
446
|
+
.toLLMTools(stepAllowedTools)
|
|
447
|
+
.filter((tool) => this.ctx.structuredOutput?.mode !== 'native' ||
|
|
448
|
+
tool.function.name !== STRUCTURED_OUTPUT_TOOL_NAME);
|
|
379
449
|
// The same list the request was built from now also bounds what
|
|
380
450
|
// may run. Narrowing only the request left the restriction
|
|
381
451
|
// presentational — the model was shown fewer tools and could
|
|
@@ -531,6 +601,18 @@ export class IterationOrchestrator {
|
|
|
531
601
|
};
|
|
532
602
|
const { response, messageId } = yield* streamProviderTurn(this.ctx.provider, {
|
|
533
603
|
model: stepModel,
|
|
604
|
+
...(this.ctx.structuredOutput?.mode === 'native'
|
|
605
|
+
? {
|
|
606
|
+
responseFormat: {
|
|
607
|
+
type: 'json_schema',
|
|
608
|
+
json_schema: {
|
|
609
|
+
name: 'structured_output',
|
|
610
|
+
schema: renderToolSchema(this.ctx.structuredOutput.schema),
|
|
611
|
+
strict: true,
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
}
|
|
615
|
+
: {}),
|
|
534
616
|
providerRoute: requestedRoute,
|
|
535
617
|
messages,
|
|
536
618
|
tools: llmTools.length > 0 ? llmTools : undefined,
|
|
@@ -646,7 +728,7 @@ export class IterationOrchestrator {
|
|
|
646
728
|
const contextFigures = this.ctx.compactionConfig
|
|
647
729
|
? (() => {
|
|
648
730
|
const measured = measureContext(this.ctx);
|
|
649
|
-
const window =
|
|
731
|
+
const window = activeContextWindow(this.ctx);
|
|
650
732
|
return {
|
|
651
733
|
contextTokens: measured.tokens,
|
|
652
734
|
contextMeasuredBy: measured.source,
|
|
@@ -780,6 +862,60 @@ export class IterationOrchestrator {
|
|
|
780
862
|
usageBefore,
|
|
781
863
|
costBefore,
|
|
782
864
|
});
|
|
865
|
+
if (this.ctx.structuredOutput?.mode === 'native') {
|
|
866
|
+
const candidate = await parseNativeCandidate(this.ctx.structuredOutput.schema, response, this.ctx.abortController.signal);
|
|
867
|
+
let outcome;
|
|
868
|
+
if (candidate.success)
|
|
869
|
+
outcome = await this.reviewStructuredOutput(candidate.value);
|
|
870
|
+
else {
|
|
871
|
+
this.nativeStructuredAttempts++;
|
|
872
|
+
runMgr.pushMessage(createRuntimeContextMessage('Return a complete JSON value matching the supplied response schema. Do not continue a partial JSON fragment.', 'structured-output'));
|
|
873
|
+
const checkpoint = await this.ctx.checkpointMgr.create(runMgr, iterationNum);
|
|
874
|
+
await this.ctx.emitEvent({
|
|
875
|
+
type: 'checkpoint_created',
|
|
876
|
+
runId: runMgr.id,
|
|
877
|
+
checkpointId: checkpoint.id,
|
|
878
|
+
iteration: iterationNum,
|
|
879
|
+
});
|
|
880
|
+
outcome =
|
|
881
|
+
this.nativeStructuredAttempts > this.structuredOutputRetryLimit()
|
|
882
|
+
? 'exhausted'
|
|
883
|
+
: 'retry';
|
|
884
|
+
}
|
|
885
|
+
await this.ctx.emitEvent({
|
|
886
|
+
type: 'iteration_completed',
|
|
887
|
+
runId: runMgr.id,
|
|
888
|
+
iteration: iterationNum,
|
|
889
|
+
hasToolCalls: false,
|
|
890
|
+
});
|
|
891
|
+
yield* this.ctx.drainPending();
|
|
892
|
+
if (this.ctx.abortController.signal.aborted || outcome === 'cancelled') {
|
|
893
|
+
runMgr.setStopReason('cancelled');
|
|
894
|
+
runMgr.markCancelled();
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
if (outcome === 'accepted') {
|
|
898
|
+
if (!forceFinalize) {
|
|
899
|
+
const changed = yield* this.holdForOutstandingWork(iterationNum, false);
|
|
900
|
+
const inbound = this.deliverInbound();
|
|
901
|
+
if (changed || inbound > 0)
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
905
|
+
runMgr.setStopReason('cancelled');
|
|
906
|
+
runMgr.markCancelled();
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
this.publishStructuredOutput();
|
|
910
|
+
runMgr.setStopReason('end_turn');
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
if (outcome === 'exhausted') {
|
|
914
|
+
runMgr.setStopReason(candidate.success ? 'answer_rejected' : 'structured_output_failed');
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
783
919
|
const hasContent = response.message.content !== null && response.message.content.length > 0;
|
|
784
920
|
// Auto-continuation on `stop_reason: max_tokens`. The
|
|
785
921
|
// model hit its per-call output cap mid-text (NOT
|
|
@@ -862,6 +998,11 @@ export class IterationOrchestrator {
|
|
|
862
998
|
// a loud stop rather than a loop.
|
|
863
999
|
if (!forceFinalize && this.ctx.reviewAnswer) {
|
|
864
1000
|
const review = await this.reviewAnswer(response.message.content ?? '');
|
|
1001
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1002
|
+
runMgr.setStopReason('cancelled');
|
|
1003
|
+
runMgr.markCancelled();
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
865
1006
|
if (review && !review.accept) {
|
|
866
1007
|
const attempt = ++this.answerReviewAttempts;
|
|
867
1008
|
const limit = this.ctx.maxAnswerReviews ?? DEFAULT_ANSWER_REVIEW_LIMIT;
|
|
@@ -988,12 +1129,34 @@ export class IterationOrchestrator {
|
|
|
988
1129
|
// run ends here rather than paying for another turn whose only
|
|
989
1130
|
// job would be to restate it — unless it shared its turn with
|
|
990
1131
|
// other calls, which relays instead. See the method.
|
|
991
|
-
|
|
1132
|
+
const structuredOutcome = await this.captureStructuredOutput(reviewOutcome.results, response);
|
|
1133
|
+
if (structuredOutcome === 'retry' ||
|
|
1134
|
+
structuredOutcome === 'exhausted' ||
|
|
1135
|
+
structuredOutcome === 'cancelled') {
|
|
1136
|
+
await this.ctx.emitEvent({
|
|
1137
|
+
type: 'iteration_completed',
|
|
1138
|
+
runId: runMgr.id,
|
|
1139
|
+
iteration: iterationNum,
|
|
1140
|
+
hasToolCalls: true,
|
|
1141
|
+
});
|
|
1142
|
+
yield* this.ctx.drainPending();
|
|
1143
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1144
|
+
runMgr.setStopReason('cancelled');
|
|
1145
|
+
runMgr.markCancelled();
|
|
1146
|
+
break;
|
|
1147
|
+
}
|
|
1148
|
+
if (structuredOutcome === 'retry')
|
|
1149
|
+
continue;
|
|
1150
|
+
runMgr.setStopReason(structuredOutcome === 'cancelled' ? 'cancelled' : 'answer_rejected');
|
|
1151
|
+
if (structuredOutcome === 'cancelled')
|
|
1152
|
+
runMgr.markCancelled();
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
if (structuredOutcome === 'accepted') {
|
|
992
1156
|
this.ctx.log.info('Structured output produced — ending run', {
|
|
993
1157
|
[NAMZU.RUN_ID]: runMgr.id,
|
|
994
1158
|
[NAMZU.ITERATION]: iterationNum,
|
|
995
1159
|
});
|
|
996
|
-
runMgr.setStopReason('end_turn');
|
|
997
1160
|
await this.ctx.emitEvent({
|
|
998
1161
|
type: 'iteration_completed',
|
|
999
1162
|
runId: runMgr.id,
|
|
@@ -1001,6 +1164,13 @@ export class IterationOrchestrator {
|
|
|
1001
1164
|
hasToolCalls: true,
|
|
1002
1165
|
});
|
|
1003
1166
|
yield* this.ctx.drainPending();
|
|
1167
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
1168
|
+
runMgr.setStopReason('cancelled');
|
|
1169
|
+
runMgr.markCancelled();
|
|
1170
|
+
break;
|
|
1171
|
+
}
|
|
1172
|
+
this.publishStructuredOutput();
|
|
1173
|
+
runMgr.setStopReason('end_turn');
|
|
1004
1174
|
break;
|
|
1005
1175
|
}
|
|
1006
1176
|
// A tool the author declared terminal settles the run with its
|
|
@@ -1406,18 +1576,39 @@ export class IterationOrchestrator {
|
|
|
1406
1576
|
* message becomes the reason, so an operator is not left with a run
|
|
1407
1577
|
* that stopped and no account of it.
|
|
1408
1578
|
*/
|
|
1579
|
+
stepContext(stepNumber, prepared) {
|
|
1580
|
+
const model = prepared.model ?? this.ctx.runConfig.model;
|
|
1581
|
+
const window = resolveContextWindow(this.ctx.compactionConfig?.contextWindowTokens, model, model === this.ctx.runConfig.model
|
|
1582
|
+
? this.ctx.providerContextWindow
|
|
1583
|
+
: model === this.ctx.contextModel
|
|
1584
|
+
? this.ctx.activeProviderContextWindow
|
|
1585
|
+
: undefined);
|
|
1586
|
+
const skills = prepared.skills ? renderSkillsSection([...prepared.skills]) : null;
|
|
1587
|
+
const preamble = [prepared.system, skills].filter(Boolean).join('\n\n');
|
|
1588
|
+
const preparedTokens = preamble ? estimateMessageTokens(createSystemMessage(preamble)) : 0;
|
|
1589
|
+
const responseReserve = Math.min(prepared.maxResponseTokens ??
|
|
1590
|
+
this.ctx.runConfig.maxResponseTokens ??
|
|
1591
|
+
Math.floor(window.tokens / 4), Math.floor(window.tokens / 4));
|
|
1592
|
+
return {
|
|
1593
|
+
runId: this.ctx.runMgr.id,
|
|
1594
|
+
stepNumber,
|
|
1595
|
+
messages: this.ctx.runMgr.messages,
|
|
1596
|
+
...(this.latestUserMessage ? { latestUserMessage: this.latestUserMessage } : {}),
|
|
1597
|
+
signal: this.ctx.abortController.signal,
|
|
1598
|
+
contextBudget: {
|
|
1599
|
+
windowTokens: window.tokens,
|
|
1600
|
+
remainingTokens: Math.max(0, Math.floor(window.tokens - measureContext(this.ctx).tokens - preparedTokens - responseReserve)),
|
|
1601
|
+
},
|
|
1602
|
+
steps: this.steps,
|
|
1603
|
+
prepared,
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1409
1606
|
async beforeStep(stepNumber) {
|
|
1410
1607
|
const configured = this.ctx.beforeStep;
|
|
1411
1608
|
if (!configured)
|
|
1412
1609
|
return undefined;
|
|
1413
1610
|
try {
|
|
1414
|
-
return (
|
|
1415
|
-
runId: this.ctx.runMgr.id,
|
|
1416
|
-
stepNumber,
|
|
1417
|
-
messages: this.ctx.runMgr.messages,
|
|
1418
|
-
steps: this.steps,
|
|
1419
|
-
prepared: {},
|
|
1420
|
-
})) ?? undefined);
|
|
1611
|
+
return (await configured(this.stepContext(stepNumber, {}))) ?? undefined;
|
|
1421
1612
|
}
|
|
1422
1613
|
catch (err) {
|
|
1423
1614
|
return { reason: `beforeStep threw: ${toErrorMessage(err)}` };
|
|
@@ -1435,15 +1626,10 @@ export class IterationOrchestrator {
|
|
|
1435
1626
|
let result = {};
|
|
1436
1627
|
for (const stage of stages) {
|
|
1437
1628
|
try {
|
|
1438
|
-
const decided = await stage(
|
|
1439
|
-
runId: this.ctx.runMgr.id,
|
|
1440
|
-
stepNumber,
|
|
1441
|
-
messages: this.ctx.runMgr.messages,
|
|
1442
|
-
steps: this.steps,
|
|
1443
|
-
prepared: result,
|
|
1444
|
-
});
|
|
1629
|
+
const decided = await stage(this.stepContext(stepNumber, result));
|
|
1445
1630
|
if (decided)
|
|
1446
1631
|
result = { ...result, ...decided };
|
|
1632
|
+
await this.selectContextModel(result.model ?? this.ctx.runConfig.model);
|
|
1447
1633
|
}
|
|
1448
1634
|
catch (err) {
|
|
1449
1635
|
// Skipped, and the rest still run: one broken concern must
|
|
@@ -1498,6 +1684,17 @@ export class IterationOrchestrator {
|
|
|
1498
1684
|
}
|
|
1499
1685
|
return prepared;
|
|
1500
1686
|
}
|
|
1687
|
+
async selectContextModel(model) {
|
|
1688
|
+
if (model !== (this.ctx.contextModel ?? this.ctx.runConfig.model)) {
|
|
1689
|
+
// A measurement from another tokenizer cannot price the new request.
|
|
1690
|
+
this.ctx.runMgr.clearLastPromptTokens();
|
|
1691
|
+
}
|
|
1692
|
+
this.ctx.contextModel = model;
|
|
1693
|
+
this.ctx.activeProviderContextWindow =
|
|
1694
|
+
model && model !== this.ctx.runConfig.model && !this.ctx.compactionConfig?.contextWindowTokens
|
|
1695
|
+
? await this.ctx.resolveModelContextWindow?.(model)
|
|
1696
|
+
: undefined;
|
|
1697
|
+
}
|
|
1501
1698
|
/** Steps completed so far, exposed on the returned `Run`. */
|
|
1502
1699
|
steps = [];
|
|
1503
1700
|
getSteps() {
|
|
@@ -1524,16 +1721,32 @@ export class IterationOrchestrator {
|
|
|
1524
1721
|
* empty drain must change nothing at all: a `continue` on nothing queued
|
|
1525
1722
|
* spends an iteration and a model call to say the same thing again.
|
|
1526
1723
|
*/
|
|
1724
|
+
rememberUserMessage(message, arriving = true) {
|
|
1725
|
+
if (!isOperatorUserMessage(message))
|
|
1726
|
+
return;
|
|
1727
|
+
this.latestUserMessage = message;
|
|
1728
|
+
// The hook field alone does not reach the model. Preserve arrivals in
|
|
1729
|
+
// the compaction state too, before their original message or attached
|
|
1730
|
+
// tool result can be shed. Initial history was already extracted at seed.
|
|
1731
|
+
const manager = this.ctx.workingStateManager;
|
|
1732
|
+
if (arriving && manager) {
|
|
1733
|
+
extractFromUserMessage(manager, message.content, !manager.getState().task);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1527
1736
|
deliverInbound() {
|
|
1528
1737
|
const queued = this.ctx.inboundMessages?.() ?? [];
|
|
1529
|
-
for (const message of queued)
|
|
1738
|
+
for (const message of queued) {
|
|
1530
1739
|
this.ctx.runMgr.pushMessage(message);
|
|
1740
|
+
this.rememberUserMessage(message);
|
|
1741
|
+
}
|
|
1531
1742
|
// The steering channel's remainder. `attachSteering` already took
|
|
1532
1743
|
// what it could carry on a tool result; anything still pending is
|
|
1533
1744
|
// guidance from a turn that had no result to attach it to.
|
|
1534
1745
|
const stranded = this.ctx.steering?.drain();
|
|
1535
1746
|
if (stranded) {
|
|
1536
|
-
|
|
1747
|
+
const message = createRuntimeContextMessage(formatSteeringNote(stranded), 'steering');
|
|
1748
|
+
this.ctx.runMgr.pushMessage(message);
|
|
1749
|
+
this.rememberUserMessage(createRuntimeContextMessage(stranded, 'steering'));
|
|
1537
1750
|
}
|
|
1538
1751
|
return queued.length + (stranded ? 1 : 0);
|
|
1539
1752
|
}
|
|
@@ -1611,7 +1824,10 @@ export class IterationOrchestrator {
|
|
|
1611
1824
|
}
|
|
1612
1825
|
/** Turns spent asking the model again for a valid structured output. */
|
|
1613
1826
|
structuredOutputAttempts = 0;
|
|
1827
|
+
nativeStructuredAttempts = 0;
|
|
1614
1828
|
structuredOutputDone = false;
|
|
1829
|
+
pendingStructuredOutput;
|
|
1830
|
+
structuredReviewAttempts = 0;
|
|
1615
1831
|
structuredOutputRetryLimit() {
|
|
1616
1832
|
return this.ctx.structuredOutput?.maxRetries ?? DEFAULT_STRUCTURED_OUTPUT_RETRIES;
|
|
1617
1833
|
}
|
|
@@ -1632,6 +1848,8 @@ export class IterationOrchestrator {
|
|
|
1632
1848
|
* avoid.
|
|
1633
1849
|
*/
|
|
1634
1850
|
terminalToolOutput(results, response) {
|
|
1851
|
+
if (this.ctx.structuredOutput?.mode === 'native')
|
|
1852
|
+
return undefined;
|
|
1635
1853
|
const terminal = results.filter((r) => this.ctx.tools.get(r.toolName)?.terminal === true);
|
|
1636
1854
|
if (terminal.length === 0)
|
|
1637
1855
|
return undefined;
|
|
@@ -1698,30 +1916,98 @@ export class IterationOrchestrator {
|
|
|
1698
1916
|
* doing work, and it is the bound the neighbour relies on for the
|
|
1699
1917
|
* identical pathology.
|
|
1700
1918
|
*/
|
|
1701
|
-
captureStructuredOutput(results, response) {
|
|
1702
|
-
if (!this.needsStructuredOutput())
|
|
1703
|
-
return
|
|
1919
|
+
async captureStructuredOutput(results, response) {
|
|
1920
|
+
if (!this.needsStructuredOutput() || this.ctx.structuredOutput?.mode === 'native')
|
|
1921
|
+
return 'absent';
|
|
1704
1922
|
const hit = results.find((r) => r.toolName === STRUCTURED_OUTPUT_TOOL_NAME && !r.isError);
|
|
1705
1923
|
if (!hit)
|
|
1706
|
-
return
|
|
1924
|
+
return 'absent';
|
|
1707
1925
|
const callCount = response.message.toolCalls?.length ?? 0;
|
|
1708
1926
|
if (callCount > 1) {
|
|
1709
1927
|
this.ctx.log.info('Structured output shared its turn — relaying instead of settling', {
|
|
1710
1928
|
[NAMZU.RUN_ID]: this.ctx.runMgr.id,
|
|
1711
1929
|
'namzu.runtime.calls_in_turn': callCount,
|
|
1712
1930
|
});
|
|
1713
|
-
return
|
|
1931
|
+
return 'absent';
|
|
1714
1932
|
}
|
|
1933
|
+
let parsed;
|
|
1715
1934
|
try {
|
|
1716
|
-
|
|
1935
|
+
parsed = JSON.parse(hit.output);
|
|
1717
1936
|
}
|
|
1718
1937
|
catch {
|
|
1719
1938
|
// The tool serializes its own validated input, so this is
|
|
1720
1939
|
// unreachable in practice; keep the raw text rather than losing it.
|
|
1721
|
-
this.ctx.
|
|
1940
|
+
if (this.ctx.structuredOutput?.review)
|
|
1941
|
+
throw new Error('Structured review requires an intact JSON tool result; check tool-output limits and result transformations');
|
|
1942
|
+
parsed = hit.output;
|
|
1722
1943
|
}
|
|
1944
|
+
return this.reviewStructuredOutput(parsed);
|
|
1945
|
+
}
|
|
1946
|
+
publishStructuredOutput() {
|
|
1947
|
+
this.ctx.runMgr.setStructuredOutput(this.pendingStructuredOutput);
|
|
1723
1948
|
this.structuredOutputDone = true;
|
|
1724
|
-
|
|
1949
|
+
}
|
|
1950
|
+
async reviewStructuredOutput(parsed) {
|
|
1951
|
+
if (this.ctx.abortController.signal.aborted)
|
|
1952
|
+
return 'cancelled';
|
|
1953
|
+
const reviewer = this.ctx.structuredOutput?.review;
|
|
1954
|
+
if (reviewer) {
|
|
1955
|
+
const signal = this.ctx.abortController.signal;
|
|
1956
|
+
if (signal.aborted)
|
|
1957
|
+
return 'cancelled';
|
|
1958
|
+
let onAbort = () => { };
|
|
1959
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
1960
|
+
onAbort = () => reject(signal.reason ?? new Error('Structured review cancelled'));
|
|
1961
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
1962
|
+
});
|
|
1963
|
+
let verdict;
|
|
1964
|
+
try {
|
|
1965
|
+
verdict = await Promise.race([
|
|
1966
|
+
Promise.resolve().then(() => reviewer(structuredClone(parsed), {
|
|
1967
|
+
runId: this.ctx.runMgr.id,
|
|
1968
|
+
iteration: this.ctx.runMgr.currentIteration,
|
|
1969
|
+
signal,
|
|
1970
|
+
messages: this.ctx.runMgr.messages,
|
|
1971
|
+
})),
|
|
1972
|
+
aborted,
|
|
1973
|
+
]);
|
|
1974
|
+
}
|
|
1975
|
+
catch (error) {
|
|
1976
|
+
if (signal.aborted)
|
|
1977
|
+
return 'cancelled';
|
|
1978
|
+
throw error;
|
|
1979
|
+
}
|
|
1980
|
+
finally {
|
|
1981
|
+
signal.removeEventListener('abort', onAbort);
|
|
1982
|
+
}
|
|
1983
|
+
if (signal.aborted)
|
|
1984
|
+
return 'cancelled';
|
|
1985
|
+
if (!verdict || typeof verdict.accept !== 'boolean')
|
|
1986
|
+
throw new Error('Structured reviewer returned an invalid verdict');
|
|
1987
|
+
if (!verdict.accept) {
|
|
1988
|
+
if (typeof verdict.feedback !== 'string' || verdict.feedback.trim().length === 0)
|
|
1989
|
+
throw new Error('Structured reviewer rejection requires feedback');
|
|
1990
|
+
this.structuredReviewAttempts++;
|
|
1991
|
+
this.ctx.runMgr.pushMessage(createRuntimeContextMessage(verdict.feedback, 'answer-review'));
|
|
1992
|
+
// Persist both the feedback and its consumed allowance before the
|
|
1993
|
+
// next request. This checkpoint is not an approval/park boundary.
|
|
1994
|
+
const checkpoint = await this.ctx.checkpointMgr.create(this.ctx.runMgr, this.ctx.runMgr.currentIteration);
|
|
1995
|
+
await this.ctx.emitEvent({
|
|
1996
|
+
type: 'checkpoint_created',
|
|
1997
|
+
runId: this.ctx.runMgr.id,
|
|
1998
|
+
checkpointId: checkpoint.id,
|
|
1999
|
+
iteration: this.ctx.runMgr.currentIteration,
|
|
2000
|
+
});
|
|
2001
|
+
if (signal.aborted)
|
|
2002
|
+
return 'cancelled';
|
|
2003
|
+
return this.structuredReviewAttempts >
|
|
2004
|
+
(this.ctx.structuredOutput?.maxReviews ?? DEFAULT_ANSWER_REVIEW_LIMIT)
|
|
2005
|
+
? 'exhausted'
|
|
2006
|
+
: 'retry';
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
this.pendingStructuredOutput = parsed;
|
|
2010
|
+
return 'accepted';
|
|
1725
2011
|
}
|
|
1726
2012
|
/**
|
|
1727
2013
|
* Ask the host whether this answer is good enough.
|
|
@@ -1742,6 +2028,7 @@ export class IterationOrchestrator {
|
|
|
1742
2028
|
return await this.ctx.reviewAnswer(answer, {
|
|
1743
2029
|
runId: this.ctx.runMgr.id,
|
|
1744
2030
|
iteration: this.ctx.runMgr.currentIteration,
|
|
2031
|
+
signal: this.ctx.abortController.signal,
|
|
1745
2032
|
messages: this.ctx.runMgr.messages,
|
|
1746
2033
|
});
|
|
1747
2034
|
}
|
|
@@ -1801,6 +2088,8 @@ export class IterationOrchestrator {
|
|
|
1801
2088
|
});
|
|
1802
2089
|
}
|
|
1803
2090
|
async requestFinalResponse(model, reason) {
|
|
2091
|
+
if (this.ctx.structuredOutput?.mode === 'native')
|
|
2092
|
+
return 'structured_output_failed';
|
|
1804
2093
|
const lastAssistant = [...this.ctx.runMgr.messages]
|
|
1805
2094
|
.reverse()
|
|
1806
2095
|
.find((m) => m.role === 'assistant');
|