@namzu/sdk 3.1.0 → 3.3.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 +221 -0
- package/dist/advisory/__tests__/consultation-context.test.d.ts +2 -0
- package/dist/advisory/__tests__/consultation-context.test.d.ts.map +1 -0
- package/dist/advisory/__tests__/consultation-context.test.js +124 -0
- package/dist/advisory/__tests__/consultation-context.test.js.map +1 -0
- package/dist/advisory/context.d.ts +25 -0
- package/dist/advisory/context.d.ts.map +1 -1
- package/dist/advisory/context.js +18 -0
- package/dist/advisory/context.js.map +1 -1
- package/dist/advisory/executor.d.ts.map +1 -1
- package/dist/advisory/executor.js +25 -3
- package/dist/advisory/executor.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +6 -0
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/__tests__/supervisor-hands-down-hitl.test.d.ts +2 -0
- package/dist/agents/__tests__/supervisor-hands-down-hitl.test.d.ts.map +1 -0
- package/dist/agents/__tests__/supervisor-hands-down-hitl.test.js +112 -0
- package/dist/agents/__tests__/supervisor-hands-down-hitl.test.js.map +1 -0
- package/dist/compaction/__tests__/context-reducer.test.d.ts +2 -0
- package/dist/compaction/__tests__/context-reducer.test.d.ts.map +1 -0
- package/dist/compaction/__tests__/context-reducer.test.js +197 -0
- package/dist/compaction/__tests__/context-reducer.test.js.map +1 -0
- package/dist/compaction/factory.d.ts +7 -0
- package/dist/compaction/factory.d.ts.map +1 -1
- package/dist/compaction/factory.js +7 -0
- package/dist/compaction/factory.js.map +1 -1
- package/dist/compaction/index.d.ts +2 -0
- package/dist/compaction/index.d.ts.map +1 -1
- package/dist/compaction/index.js +1 -0
- package/dist/compaction/index.js.map +1 -1
- package/dist/compaction/interface.d.ts +13 -0
- package/dist/compaction/interface.d.ts.map +1 -1
- package/dist/compaction/managers/null.d.ts +3 -0
- package/dist/compaction/managers/null.d.ts.map +1 -1
- package/dist/compaction/managers/null.js +3 -0
- package/dist/compaction/managers/null.js.map +1 -1
- package/dist/compaction/managers/slidingWindow.d.ts +6 -0
- package/dist/compaction/managers/slidingWindow.d.ts.map +1 -1
- package/dist/compaction/managers/slidingWindow.js +6 -0
- package/dist/compaction/managers/slidingWindow.js.map +1 -1
- package/dist/compaction/managers/structured.d.ts +10 -0
- package/dist/compaction/managers/structured.d.ts.map +1 -1
- package/dist/compaction/managers/structured.js +10 -0
- package/dist/compaction/managers/structured.js.map +1 -1
- package/dist/compaction/reducer.d.ts +86 -0
- package/dist/compaction/reducer.d.ts.map +1 -0
- package/dist/compaction/reducer.js +77 -0
- package/dist/compaction/reducer.js.map +1 -0
- package/dist/connector/builtins/__tests__/oauth2-auth.test.d.ts +2 -0
- package/dist/connector/builtins/__tests__/oauth2-auth.test.d.ts.map +1 -0
- package/dist/connector/builtins/__tests__/oauth2-auth.test.js +54 -0
- package/dist/connector/builtins/__tests__/oauth2-auth.test.js.map +1 -0
- package/dist/connector/builtins/http.d.ts.map +1 -1
- package/dist/connector/builtins/http.js +24 -2
- package/dist/connector/builtins/http.js.map +1 -1
- package/dist/connector/builtins/http.test.js +18 -2
- package/dist/connector/builtins/http.test.js.map +1 -1
- package/dist/connector/index.d.ts +3 -2
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +2 -1
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/__tests__/prompt-as-tool.test.d.ts +2 -0
- package/dist/connector/mcp/__tests__/prompt-as-tool.test.d.ts.map +1 -0
- package/dist/connector/mcp/__tests__/prompt-as-tool.test.js +122 -0
- package/dist/connector/mcp/__tests__/prompt-as-tool.test.js.map +1 -0
- package/dist/connector/mcp/__tests__/prompts-and-lifecycle.test.d.ts +2 -0
- package/dist/connector/mcp/__tests__/prompts-and-lifecycle.test.d.ts.map +1 -0
- package/dist/connector/mcp/__tests__/prompts-and-lifecycle.test.js +214 -0
- package/dist/connector/mcp/__tests__/prompts-and-lifecycle.test.js.map +1 -0
- package/dist/connector/mcp/client.d.ts +52 -1
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +86 -0
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/discovery.d.ts +27 -2
- package/dist/connector/mcp/discovery.d.ts.map +1 -1
- package/dist/connector/mcp/discovery.js +58 -5
- package/dist/connector/mcp/discovery.js.map +1 -1
- package/dist/connector/mcp/index.d.ts +4 -3
- package/dist/connector/mcp/index.d.ts.map +1 -1
- package/dist/connector/mcp/index.js +3 -2
- package/dist/connector/mcp/index.js.map +1 -1
- package/dist/connector/mcp/policy.d.ts +17 -0
- package/dist/connector/mcp/policy.d.ts.map +1 -1
- package/dist/connector/mcp/policy.js +18 -7
- package/dist/connector/mcp/policy.js.map +1 -1
- package/dist/connector/mcp/prompt-adapter.d.ts +39 -0
- package/dist/connector/mcp/prompt-adapter.d.ts.map +1 -0
- package/dist/connector/mcp/prompt-adapter.js +113 -0
- package/dist/connector/mcp/prompt-adapter.js.map +1 -0
- package/dist/connector/mcp/server.d.ts +42 -1
- package/dist/connector/mcp/server.d.ts.map +1 -1
- package/dist/connector/mcp/server.js +77 -4
- package/dist/connector/mcp/server.js.map +1 -1
- package/dist/manager/agent/__tests__/depth-limit-authority.test.d.ts +2 -0
- package/dist/manager/agent/__tests__/depth-limit-authority.test.d.ts.map +1 -0
- package/dist/manager/agent/__tests__/depth-limit-authority.test.js +58 -0
- package/dist/manager/agent/__tests__/depth-limit-authority.test.js.map +1 -0
- package/dist/manager/agent/__tests__/hitl-across-spawn.test.d.ts +2 -0
- package/dist/manager/agent/__tests__/hitl-across-spawn.test.d.ts.map +1 -0
- package/dist/manager/agent/__tests__/hitl-across-spawn.test.js +226 -0
- package/dist/manager/agent/__tests__/hitl-across-spawn.test.js.map +1 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +13 -0
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/plugin/__tests__/discovery-scopes.test.d.ts +2 -0
- package/dist/plugin/__tests__/discovery-scopes.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/discovery-scopes.test.js +97 -0
- package/dist/plugin/__tests__/discovery-scopes.test.js.map +1 -0
- package/dist/plugin/__tests__/enable-contributions.test.js +5 -1
- package/dist/plugin/__tests__/enable-contributions.test.js.map +1 -1
- package/dist/plugin/__tests__/mcp-admission.test.d.ts +2 -0
- package/dist/plugin/__tests__/mcp-admission.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/mcp-admission.test.js +227 -0
- package/dist/plugin/__tests__/mcp-admission.test.js.map +1 -0
- package/dist/plugin/lifecycle.d.ts +41 -0
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +39 -1
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/loader.d.ts +39 -3
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +37 -4
- package/dist/plugin/loader.js.map +1 -1
- package/dist/public-runtime.d.ts +4 -2
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +5 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -2
- package/dist/public-types.d.ts.map +1 -1
- package/dist/rag/__tests__/namespace-isolation.test.d.ts +2 -0
- package/dist/rag/__tests__/namespace-isolation.test.d.ts.map +1 -0
- package/dist/rag/__tests__/namespace-isolation.test.js +80 -0
- package/dist/rag/__tests__/namespace-isolation.test.js.map +1 -0
- package/dist/rag/ingestion.d.ts.map +1 -1
- package/dist/rag/ingestion.js +1 -0
- package/dist/rag/ingestion.js.map +1 -1
- package/dist/rag/retriever.d.ts.map +1 -1
- package/dist/rag/retriever.js +2 -0
- package/dist/rag/retriever.js.map +1 -1
- package/dist/rag/vector-store.d.ts.map +1 -1
- package/dist/rag/vector-store.js +6 -0
- package/dist/rag/vector-store.js.map +1 -1
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +113 -109
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/runtime/query/__tests__/per-step-skills.test.d.ts +10 -0
- package/dist/runtime/query/__tests__/per-step-skills.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/per-step-skills.test.js +122 -0
- package/dist/runtime/query/__tests__/per-step-skills.test.js.map +1 -0
- package/dist/runtime/query/__tests__/per-step-tool-choice.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/per-step-tool-choice.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/per-step-tool-choice.test.js +153 -0
- package/dist/runtime/query/__tests__/per-step-tool-choice.test.js.map +1 -0
- package/dist/runtime/query/__tests__/resume-run.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/resume-run.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/resume-run.test.js +211 -0
- package/dist/runtime/query/__tests__/resume-run.test.js.map +1 -0
- package/dist/runtime/query/index.d.ts +10 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +26 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +50 -33
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction-model-routing.test.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/compaction-model-routing.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/compaction-model-routing.test.js +96 -0
- package/dist/runtime/query/iteration/phases/compaction-model-routing.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +95 -5
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context-reducer-dispatch.test.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/context-reducer-dispatch.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/context-reducer-dispatch.test.js +180 -0
- package/dist/runtime/query/iteration/phases/context-reducer-dispatch.test.js.map +1 -0
- 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/resume-run.d.ts +70 -0
- package/dist/runtime/query/resume-run.d.ts.map +1 -0
- package/dist/runtime/query/resume-run.js +46 -0
- package/dist/runtime/query/resume-run.js.map +1 -0
- package/dist/telemetry/__tests__/model-call-span.test.d.ts +2 -0
- package/dist/telemetry/__tests__/model-call-span.test.d.ts.map +1 -0
- package/dist/telemetry/__tests__/model-call-span.test.js +152 -0
- package/dist/telemetry/__tests__/model-call-span.test.js.map +1 -0
- package/dist/telemetry/__tests__/span-closure.test.d.ts +2 -0
- package/dist/telemetry/__tests__/span-closure.test.d.ts.map +1 -0
- package/dist/telemetry/__tests__/span-closure.test.js +124 -0
- package/dist/telemetry/__tests__/span-closure.test.js.map +1 -0
- package/dist/tools/advisory/index.js +1 -1
- package/dist/tools/advisory/index.js.map +1 -1
- package/dist/tools/coordinator/__tests__/plan-dependencies.test.d.ts +2 -0
- package/dist/tools/coordinator/__tests__/plan-dependencies.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/plan-dependencies.test.js +126 -0
- package/dist/tools/coordinator/__tests__/plan-dependencies.test.js.map +1 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +13 -1
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/coordinator/plan-dependencies.d.ts +43 -0
- package/dist/tools/coordinator/plan-dependencies.d.ts.map +1 -0
- package/dist/tools/coordinator/plan-dependencies.js +148 -0
- package/dist/tools/coordinator/plan-dependencies.js.map +1 -0
- package/dist/types/agent/base.d.ts +26 -0
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +15 -0
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +17 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/connector/core.d.ts +34 -0
- package/dist/types/connector/core.d.ts.map +1 -1
- package/dist/types/connector/definition.d.ts +10 -0
- package/dist/types/connector/definition.d.ts.map +1 -1
- package/dist/types/connector/mcp.d.ts +13 -0
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/rag/retrieval.d.ts +16 -0
- package/dist/types/rag/retrieval.d.ts.map +1 -1
- package/dist/types/rag/storage.d.ts +9 -0
- package/dist/types/rag/storage.d.ts.map +1 -1
- package/dist/types/rag/vector.d.ts +11 -0
- package/dist/types/rag/vector.d.ts.map +1 -1
- package/dist/types/router/task-router.d.ts +19 -0
- package/dist/types/router/task-router.d.ts.map +1 -1
- package/dist/types/run/prepare-step.d.ts +56 -3
- package/dist/types/run/prepare-step.d.ts.map +1 -1
- package/dist/types/toolset/index.d.ts +22 -0
- package/dist/types/toolset/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/advisory/__tests__/consultation-context.test.ts +191 -0
- package/src/advisory/context.ts +32 -0
- package/src/advisory/executor.ts +30 -3
- package/src/agents/SupervisorAgent.ts +6 -0
- package/src/agents/__tests__/supervisor-hands-down-hitl.test.ts +131 -0
- package/src/compaction/__tests__/context-reducer.test.ts +239 -0
- package/src/compaction/factory.ts +7 -0
- package/src/compaction/index.ts +8 -0
- package/src/compaction/interface.ts +13 -0
- package/src/compaction/managers/null.ts +3 -0
- package/src/compaction/managers/slidingWindow.ts +6 -0
- package/src/compaction/managers/structured.ts +10 -0
- package/src/compaction/reducer.ts +154 -0
- package/src/connector/builtins/__tests__/oauth2-auth.test.ts +73 -0
- package/src/connector/builtins/http.test.ts +28 -2
- package/src/connector/builtins/http.ts +26 -2
- package/src/connector/index.ts +7 -2
- package/src/connector/mcp/__tests__/prompt-as-tool.test.ts +157 -0
- package/src/connector/mcp/__tests__/prompts-and-lifecycle.test.ts +286 -0
- package/src/connector/mcp/client.ts +95 -0
- package/src/connector/mcp/discovery.ts +67 -5
- package/src/connector/mcp/index.ts +8 -3
- package/src/connector/mcp/policy.ts +23 -8
- package/src/connector/mcp/prompt-adapter.ts +139 -0
- package/src/connector/mcp/server.ts +101 -3
- package/src/manager/agent/__tests__/depth-limit-authority.test.ts +74 -0
- package/src/manager/agent/__tests__/hitl-across-spawn.test.ts +273 -0
- package/src/manager/agent/lifecycle.ts +12 -0
- package/src/plugin/__tests__/discovery-scopes.test.ts +133 -0
- package/src/plugin/__tests__/enable-contributions.test.ts +5 -1
- package/src/plugin/__tests__/mcp-admission.test.ts +286 -0
- package/src/plugin/lifecycle.ts +68 -1
- package/src/plugin/loader.ts +57 -3
- package/src/public-runtime.ts +10 -0
- package/src/public-types.ts +5 -0
- package/src/rag/__tests__/namespace-isolation.test.ts +109 -0
- package/src/rag/ingestion.ts +1 -0
- package/src/rag/retriever.ts +2 -0
- package/src/rag/vector-store.ts +5 -0
- package/src/registry/tool/execute.ts +123 -119
- package/src/runtime/query/__tests__/per-step-skills.test.ts +154 -0
- package/src/runtime/query/__tests__/per-step-tool-choice.test.ts +180 -0
- package/src/runtime/query/__tests__/resume-run.test.ts +262 -0
- package/src/runtime/query/index.ts +39 -0
- package/src/runtime/query/iteration/index.ts +55 -34
- package/src/runtime/query/iteration/phases/compaction-model-routing.test.ts +125 -0
- package/src/runtime/query/iteration/phases/compaction.ts +106 -5
- package/src/runtime/query/iteration/phases/context-reducer-dispatch.test.ts +238 -0
- package/src/runtime/query/iteration/phases/context.ts +11 -0
- package/src/runtime/query/resume-run.ts +93 -0
- package/src/telemetry/__tests__/model-call-span.test.ts +195 -0
- package/src/telemetry/__tests__/span-closure.test.ts +153 -0
- package/src/tools/advisory/index.ts +1 -1
- package/src/tools/coordinator/__tests__/plan-dependencies.test.ts +186 -0
- package/src/tools/coordinator/index.ts +14 -1
- package/src/tools/coordinator/plan-dependencies.ts +175 -0
- package/src/types/agent/base.ts +27 -0
- package/src/types/agent/supervisor.ts +15 -0
- package/src/types/agent/task.ts +18 -0
- package/src/types/connector/core.ts +34 -0
- package/src/types/connector/definition.ts +10 -0
- package/src/types/connector/mcp.ts +14 -0
- package/src/types/rag/retrieval.ts +16 -0
- package/src/types/rag/storage.ts +9 -0
- package/src/types/rag/vector.ts +11 -0
- package/src/types/router/task-router.ts +19 -0
- package/src/types/run/prepare-step.ts +58 -3
- package/src/types/toolset/index.ts +22 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { mkdtemp, rm } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
import { MockLLMProvider } from '../../../provider/mock.js'
|
|
7
|
+
import { ToolRegistry } from '../../../registry/tool/execute.js'
|
|
8
|
+
import type { CheckpointId, IterationCheckpoint } from '../../../types/hitl/index.js'
|
|
9
|
+
import type { RunId, SessionId, TenantId } from '../../../types/ids/index.js'
|
|
10
|
+
import { createUserMessage } from '../../../types/message/index.js'
|
|
11
|
+
import type { CheckpointRunScope, CheckpointStore } from '../../../types/run/checkpoint-store.js'
|
|
12
|
+
import type { ProjectId, ThreadId } from '../../../types/session/ids.js'
|
|
13
|
+
import { resumeRun } from '../resume-run.js'
|
|
14
|
+
import type { RunStateScope } from '../run-state.js'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The pieces of a cross-process resume all existed and nothing joined them.
|
|
18
|
+
* `CheckpointManager` wrote the history, budgets, working state and any
|
|
19
|
+
* park; `loadRunState` read them back; `query` accepted `runId` +
|
|
20
|
+
* `resumeFromCheckpoint` and restored all of it. But `resumeFromCheckpoint`
|
|
21
|
+
* had no caller anywhere outside `packages/sdk/src`, so the whole path
|
|
22
|
+
* shipped untravelled — every host was expected to write the same wiring
|
|
23
|
+
* and none did.
|
|
24
|
+
*
|
|
25
|
+
* These cover the join, and especially its two refusals: a resume must not
|
|
26
|
+
* quietly become a fresh run under a recycled id, and it must not step past
|
|
27
|
+
* a park without the answer that park is waiting for.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const SCOPE: RunStateScope = {
|
|
31
|
+
tenantId: 'tnt_resume' as TenantId,
|
|
32
|
+
projectId: 'prj_resume' as ProjectId,
|
|
33
|
+
sessionId: 'ses_resume' as SessionId,
|
|
34
|
+
runId: 'run_resume' as RunId,
|
|
35
|
+
threadId: 'thd_resume' as ThreadId,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const ZERO_USAGE = {
|
|
39
|
+
promptTokens: 0,
|
|
40
|
+
completionTokens: 0,
|
|
41
|
+
totalTokens: 0,
|
|
42
|
+
cachedTokens: 0,
|
|
43
|
+
cacheWriteTokens: 0,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const ZERO_COST = {
|
|
47
|
+
inputCostPer1M: 0,
|
|
48
|
+
outputCostPer1M: 0,
|
|
49
|
+
totalCost: 0,
|
|
50
|
+
cacheDiscount: 0,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class InMemoryCheckpointStore implements CheckpointStore {
|
|
54
|
+
readonly rows = new Map<string, IterationCheckpoint>()
|
|
55
|
+
|
|
56
|
+
private key(scope: CheckpointRunScope, id: CheckpointId): string {
|
|
57
|
+
return [scope.tenantId, scope.projectId, scope.sessionId, scope.runId, id].join('/')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async writeCheckpoint(scope: CheckpointRunScope, checkpoint: IterationCheckpoint): Promise<void> {
|
|
61
|
+
this.rows.set(this.key(scope, checkpoint.id), checkpoint)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async readCheckpoint(
|
|
65
|
+
scope: CheckpointRunScope,
|
|
66
|
+
id: CheckpointId,
|
|
67
|
+
): Promise<IterationCheckpoint | null> {
|
|
68
|
+
return this.rows.get(this.key(scope, id)) ?? null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async listCheckpoints(scope: CheckpointRunScope): Promise<IterationCheckpoint[]> {
|
|
72
|
+
const prefix = `${[scope.tenantId, scope.projectId, scope.sessionId, scope.runId].join('/')}/`
|
|
73
|
+
return [...this.rows.entries()]
|
|
74
|
+
.filter(([key]) => key.startsWith(prefix))
|
|
75
|
+
.map(([, cp]) => cp)
|
|
76
|
+
.sort((a, b) => a.createdAt - b.createdAt)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async deleteCheckpoint(scope: CheckpointRunScope, id: CheckpointId): Promise<void> {
|
|
80
|
+
this.rows.delete(this.key(scope, id))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function checkpoint(overrides: Partial<IterationCheckpoint> = {}): IterationCheckpoint {
|
|
85
|
+
return {
|
|
86
|
+
id: 'ckpt_1' as CheckpointId,
|
|
87
|
+
runId: SCOPE.runId,
|
|
88
|
+
iteration: 2,
|
|
89
|
+
messages: [createUserMessage('the work so far')],
|
|
90
|
+
tokenUsage: { ...ZERO_USAGE, promptTokens: 120, totalTokens: 120 },
|
|
91
|
+
costInfo: { ...ZERO_COST, totalCost: 0.4 },
|
|
92
|
+
guardState: { iterationCount: 2, elapsedMs: 9_000 },
|
|
93
|
+
createdAt: Date.now(),
|
|
94
|
+
...overrides,
|
|
95
|
+
} as IterationCheckpoint
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let workdirs: string[] = []
|
|
99
|
+
|
|
100
|
+
afterEach(async () => {
|
|
101
|
+
await Promise.all(workdirs.map((d) => rm(d, { recursive: true, force: true })))
|
|
102
|
+
workdirs = []
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
async function mkWorkdir(): Promise<string> {
|
|
106
|
+
const dir = await mkdtemp(join(tmpdir(), 'namzu-resume-run-'))
|
|
107
|
+
workdirs.push(dir)
|
|
108
|
+
return dir
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function baseParams(store: CheckpointStore) {
|
|
112
|
+
return {
|
|
113
|
+
scope: SCOPE,
|
|
114
|
+
checkpointStore: store,
|
|
115
|
+
provider: new MockLLMProvider({ turns: [{ text: 'continued' }] }),
|
|
116
|
+
tools: new ToolRegistry(),
|
|
117
|
+
runConfig: {
|
|
118
|
+
model: 'mock-model',
|
|
119
|
+
timeoutMs: 30_000,
|
|
120
|
+
tokenBudget: 100_000,
|
|
121
|
+
maxIterations: 2,
|
|
122
|
+
maxResponseTokens: 256,
|
|
123
|
+
},
|
|
124
|
+
agentId: 'agent_resume',
|
|
125
|
+
agentName: 'Resume Agent',
|
|
126
|
+
workingDirectory: await mkWorkdir(),
|
|
127
|
+
sessionId: SCOPE.sessionId,
|
|
128
|
+
threadId: SCOPE.threadId,
|
|
129
|
+
projectId: SCOPE.projectId,
|
|
130
|
+
tenantId: SCOPE.tenantId,
|
|
131
|
+
// Required by the contract, and rightly so: a resume that lands on a
|
|
132
|
+
// park has to have somewhere to ask.
|
|
133
|
+
resumeHandler: async () => ({ action: 'continue' as const }),
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
describe('a run is picked back up from its store', () => {
|
|
138
|
+
it('continues the same run id rather than starting a new one', async () => {
|
|
139
|
+
const store = new InMemoryCheckpointStore()
|
|
140
|
+
await store.writeCheckpoint(SCOPE, checkpoint())
|
|
141
|
+
|
|
142
|
+
const outcome = await resumeRun(await baseParams(store))
|
|
143
|
+
|
|
144
|
+
expect(outcome.resumed).toBe(true)
|
|
145
|
+
if (!outcome.resumed) return
|
|
146
|
+
// The whole point: a resume is the same run in a different process,
|
|
147
|
+
// so its id, budgets and trace all have to carry across.
|
|
148
|
+
expect(outcome.run.id).toBe(SCOPE.runId)
|
|
149
|
+
expect(outcome.state.checkpointId).toBe('ckpt_1')
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('carries the spent budget forward instead of granting a fresh one', async () => {
|
|
153
|
+
const store = new InMemoryCheckpointStore()
|
|
154
|
+
await store.writeCheckpoint(SCOPE, checkpoint())
|
|
155
|
+
|
|
156
|
+
const outcome = await resumeRun(await baseParams(store))
|
|
157
|
+
|
|
158
|
+
expect(outcome.resumed).toBe(true)
|
|
159
|
+
if (!outcome.resumed) return
|
|
160
|
+
// A run recalled at 120 tokens must not come back at zero — the
|
|
161
|
+
// budget belongs to the run, not to the process hosting it.
|
|
162
|
+
expect(outcome.run.tokenUsage.totalTokens).toBeGreaterThanOrEqual(120)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('picks the newest checkpoint when the caller names none', async () => {
|
|
166
|
+
const store = new InMemoryCheckpointStore()
|
|
167
|
+
await store.writeCheckpoint(SCOPE, checkpoint({ id: 'ckpt_old' as CheckpointId, createdAt: 1 }))
|
|
168
|
+
await store.writeCheckpoint(
|
|
169
|
+
SCOPE,
|
|
170
|
+
checkpoint({ id: 'ckpt_new' as CheckpointId, createdAt: 2_000 }),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
const outcome = await resumeRun(await baseParams(store))
|
|
174
|
+
|
|
175
|
+
expect(outcome.resumed).toBe(true)
|
|
176
|
+
if (!outcome.resumed) return
|
|
177
|
+
expect(outcome.state.checkpointId).toBe('ckpt_new')
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('honours an explicitly named checkpoint', async () => {
|
|
181
|
+
const store = new InMemoryCheckpointStore()
|
|
182
|
+
await store.writeCheckpoint(SCOPE, checkpoint({ id: 'ckpt_old' as CheckpointId, createdAt: 1 }))
|
|
183
|
+
await store.writeCheckpoint(
|
|
184
|
+
SCOPE,
|
|
185
|
+
checkpoint({ id: 'ckpt_new' as CheckpointId, createdAt: 2_000 }),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
const outcome = await resumeRun({
|
|
189
|
+
...(await baseParams(store)),
|
|
190
|
+
checkpointId: 'ckpt_old' as CheckpointId,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
expect(outcome.resumed).toBe(true)
|
|
194
|
+
if (!outcome.resumed) return
|
|
195
|
+
expect(outcome.state.checkpointId).toBe('ckpt_old')
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe('it refuses rather than guessing', () => {
|
|
200
|
+
it('reports no checkpoint instead of silently starting fresh', async () => {
|
|
201
|
+
const outcome = await resumeRun(await baseParams(new InMemoryCheckpointStore()))
|
|
202
|
+
|
|
203
|
+
// Starting a new run here would be the worst outcome: a different
|
|
204
|
+
// run wearing a recycled id, with the original's budget reset.
|
|
205
|
+
expect(outcome).toEqual({ resumed: false, reason: 'no-checkpoint' })
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('hands back the outstanding question instead of resuming past it', async () => {
|
|
209
|
+
const store = new InMemoryCheckpointStore()
|
|
210
|
+
await store.writeCheckpoint(
|
|
211
|
+
SCOPE,
|
|
212
|
+
checkpoint({
|
|
213
|
+
pending: {
|
|
214
|
+
request: {
|
|
215
|
+
type: 'tool_review',
|
|
216
|
+
runId: SCOPE.runId,
|
|
217
|
+
checkpointId: 'ckpt_1' as CheckpointId,
|
|
218
|
+
toolCalls: [{ id: 'call_1', name: 'write', input: {} }],
|
|
219
|
+
},
|
|
220
|
+
parkedAt: Date.now(),
|
|
221
|
+
deadlineAt: Date.now() + 60_000,
|
|
222
|
+
},
|
|
223
|
+
} as unknown as Partial<IterationCheckpoint>),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
const outcome = await resumeRun(await baseParams(store))
|
|
227
|
+
|
|
228
|
+
expect(outcome.resumed).toBe(false)
|
|
229
|
+
if (outcome.resumed || outcome.reason !== 'awaiting-decision') {
|
|
230
|
+
throw new Error(`expected awaiting-decision, got ${JSON.stringify(outcome)}`)
|
|
231
|
+
}
|
|
232
|
+
// The host needs the request itself to put in front of a person.
|
|
233
|
+
expect(outcome.pending.request.type).toBe('tool_review')
|
|
234
|
+
expect(outcome.state.runId).toBe(SCOPE.runId)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('treats an already-answered park as an ordinary resume', async () => {
|
|
238
|
+
const store = new InMemoryCheckpointStore()
|
|
239
|
+
await store.writeCheckpoint(
|
|
240
|
+
SCOPE,
|
|
241
|
+
checkpoint({
|
|
242
|
+
pending: {
|
|
243
|
+
request: {
|
|
244
|
+
type: 'tool_review',
|
|
245
|
+
runId: SCOPE.runId,
|
|
246
|
+
checkpointId: 'ckpt_1' as CheckpointId,
|
|
247
|
+
toolCalls: [{ id: 'call_1', name: 'write', input: {} }],
|
|
248
|
+
},
|
|
249
|
+
parkedAt: Date.now(),
|
|
250
|
+
deadlineAt: Date.now() + 60_000,
|
|
251
|
+
resolvedAt: Date.now(),
|
|
252
|
+
},
|
|
253
|
+
} as unknown as Partial<IterationCheckpoint>),
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
const outcome = await resumeRun(await baseParams(store))
|
|
257
|
+
|
|
258
|
+
// `resolvedAt` is what makes a park answered. Blocking on one that
|
|
259
|
+
// already has its answer would strand the run permanently.
|
|
260
|
+
expect(outcome.resumed).toBe(true)
|
|
261
|
+
})
|
|
262
|
+
})
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
import { findDanglingMessages, removeDanglingMessages } from '../../compaction/dangling.js'
|
|
10
10
|
import { extractFromUserMessage } from '../../compaction/extractor.js'
|
|
11
11
|
import { WorkingStateManager } from '../../compaction/manager.js'
|
|
12
|
+
import type { ContextReducer } from '../../compaction/reducer.js'
|
|
13
|
+
import { serializeState as serializeWorkingState } from '../../compaction/serializer.js'
|
|
12
14
|
import { restoreWorkingState, snapshotWorkingState } from '../../compaction/wire.js'
|
|
13
15
|
import type { CompactionConfig } from '../../config/runtime.js'
|
|
14
16
|
import { TOOL_OUTPUT_DIR_NAME } from '../../constants/tools/index.js'
|
|
@@ -421,6 +423,16 @@ export interface QueryParams {
|
|
|
421
423
|
*/
|
|
422
424
|
workingMemoryProvider?: WorkingMemoryProvider
|
|
423
425
|
|
|
426
|
+
/**
|
|
427
|
+
* Replace context reduction for this run.
|
|
428
|
+
*
|
|
429
|
+
* Outranks `compactionConfig.strategy`, and the built-in structured pass
|
|
430
|
+
* does not also run: two mechanisms editing one history in the same pass
|
|
431
|
+
* cannot both be reasoned about. See `ContextReducer` for the invariants a
|
|
432
|
+
* reducer is expected to keep.
|
|
433
|
+
*/
|
|
434
|
+
contextReducer?: ContextReducer
|
|
435
|
+
|
|
424
436
|
agentBus?: import('../../bus/index.js').AgentBus
|
|
425
437
|
|
|
426
438
|
verificationGate?: VerificationGateConfig
|
|
@@ -752,6 +764,31 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
752
764
|
params.advisory.budget,
|
|
753
765
|
)
|
|
754
766
|
|
|
767
|
+
// What the run looks like when the MODEL consults an advisor, as
|
|
768
|
+
// opposed to when a trigger does. The trigger path has always passed
|
|
769
|
+
// this; the tool path passed an empty context, so an advisor the model
|
|
770
|
+
// asked for help saw the question and nothing else.
|
|
771
|
+
//
|
|
772
|
+
// `includeToolCatalog` and `useCompactedContext` are read here and
|
|
773
|
+
// nowhere else. Both were declared on `AdvisoryConfig` /
|
|
774
|
+
// `AdvisorDefinition` and consulted by nothing, so a host who turned
|
|
775
|
+
// the catalogue off still paid for it in every advisory prompt.
|
|
776
|
+
const advisoryConfig = params.advisory
|
|
777
|
+
advisoryCtx.setCallContextProvider(() => {
|
|
778
|
+
const summary =
|
|
779
|
+
workingStateManager && advisoryConfig.advisors.some((a) => a.useCompactedContext)
|
|
780
|
+
? serializeWorkingState(workingStateManager.getState())
|
|
781
|
+
: undefined
|
|
782
|
+
return {
|
|
783
|
+
messages: ctx.runMgr.messages,
|
|
784
|
+
...(summary !== undefined ? { workingStateSummary: summary } : {}),
|
|
785
|
+
...(advisoryConfig.includeToolCatalog
|
|
786
|
+
? { toolCatalog: params.tools.toLLMTools(effectiveAllowedTools) }
|
|
787
|
+
: {}),
|
|
788
|
+
iteration: ctx.runMgr.currentIteration,
|
|
789
|
+
}
|
|
790
|
+
})
|
|
791
|
+
|
|
755
792
|
if (params.advisory.enableAgentTool) {
|
|
756
793
|
const advisoryTools = buildAdvisoryTools({ advisoryCtx })
|
|
757
794
|
const overrides = params.runtimeToolOverrides
|
|
@@ -800,6 +837,8 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
|
|
|
800
837
|
toolGrants: new ToolGrantSet(),
|
|
801
838
|
compactionConfig: params.compactionConfig,
|
|
802
839
|
workingStateManager,
|
|
840
|
+
taskRouter: params.taskRouter,
|
|
841
|
+
contextReducer: params.contextReducer,
|
|
803
842
|
workingMemoryProvider: params.workingMemoryProvider,
|
|
804
843
|
advisoryCtx,
|
|
805
844
|
agentBus: params.agentBus,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
DEFAULT_STRUCTURED_OUTPUT_RETRIES,
|
|
6
6
|
STRUCTURED_OUTPUT_REPROMPT,
|
|
7
7
|
} from '../../../constants/tools/index.js'
|
|
8
|
+
import { renderSkillsSection } from '../../../persona/assembler.js'
|
|
8
9
|
import { collect } from '../../../provider/collect.js'
|
|
9
10
|
import {
|
|
10
11
|
GENAI,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
createSystemMessage,
|
|
22
23
|
createUserMessage,
|
|
23
24
|
} from '../../../types/message/index.js'
|
|
25
|
+
import type { ToolChoice } from '../../../types/provider/chat.js'
|
|
24
26
|
import { classifyProviderError } from '../../../types/provider/errors.js'
|
|
25
27
|
import type { ChatCompletionResponse } from '../../../types/provider/index.js'
|
|
26
28
|
import type { AnswerReview } from '../../../types/run/answer-review.js'
|
|
@@ -30,6 +32,7 @@ import type {
|
|
|
30
32
|
StepResult,
|
|
31
33
|
StopReason,
|
|
32
34
|
} from '../../../types/run/index.js'
|
|
35
|
+
import type { Skill } from '../../../types/skills/index.js'
|
|
33
36
|
import type { LLMToolSchema, ToolRegistryContract } from '../../../types/tool/index.js'
|
|
34
37
|
import { toErrorMessage } from '../../../utils/error.js'
|
|
35
38
|
import { generateMessageId } from '../../../utils/id.js'
|
|
@@ -150,23 +153,27 @@ export class IterationOrchestrator {
|
|
|
150
153
|
{},
|
|
151
154
|
parentContext(this.ctx.rootSpan),
|
|
152
155
|
)
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
try {
|
|
157
|
+
// Tool spans for this turn belong under this iteration. Inside
|
|
158
|
+
// the try rather than before it: a throw from any of these left
|
|
159
|
+
// the span open, and an iteration span that never ends is a
|
|
160
|
+
// trace that never closes — the export is incomplete for exactly
|
|
161
|
+
// the run that failed.
|
|
162
|
+
this.ctx.toolExecutor.setParentSpan(iterSpan)
|
|
155
163
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
iterSpan.setAttributes({
|
|
165
|
+
[NAMZU.ITERATION]: iterationNum,
|
|
166
|
+
[NAMZU.RUN_ID]: runMgr.id,
|
|
167
|
+
[GENAI.REQUEST_MODEL]: model,
|
|
168
|
+
})
|
|
161
169
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
170
|
+
await this.ctx.emitEvent({
|
|
171
|
+
type: 'iteration_started',
|
|
172
|
+
runId: runMgr.id,
|
|
173
|
+
iteration: iterationNum,
|
|
174
|
+
})
|
|
175
|
+
yield* this.ctx.drainPending()
|
|
168
176
|
|
|
169
|
-
try {
|
|
170
177
|
if (this.ctx.pluginManager) {
|
|
171
178
|
const hookResults = await this.ctx.pluginManager.executeHooks(
|
|
172
179
|
'iteration_start',
|
|
@@ -225,8 +232,17 @@ export class IterationOrchestrator {
|
|
|
225
232
|
// exactly this reason. Shallow is enough: the defect is array
|
|
226
233
|
// mutation, and per-iteration this is trivial next to the model
|
|
227
234
|
// call it precedes.
|
|
228
|
-
|
|
229
|
-
|
|
235
|
+
// A step's skills and its guidance ride the same ephemeral
|
|
236
|
+
// trailing system message. Appending leaves the cached prefix
|
|
237
|
+
// intact; rewriting the run's own prompt to carry a phase's
|
|
238
|
+
// skills would invalidate it on every iteration.
|
|
239
|
+
// `renderSkillsSection` already answers null for an empty list, so
|
|
240
|
+
// there is no length check here — a second guard for the same
|
|
241
|
+
// case is one more thing to keep in agreement with the first.
|
|
242
|
+
const stepSkills = step.skills ? renderSkillsSection([...step.skills]) : null
|
|
243
|
+
const stepPreamble = [step.system, stepSkills].filter(Boolean).join('\n\n')
|
|
244
|
+
const messages = stepPreamble
|
|
245
|
+
? [...baseMessages, createSystemMessage(stepPreamble)]
|
|
230
246
|
: [...baseMessages]
|
|
231
247
|
|
|
232
248
|
if (this.ctx.pluginManager) {
|
|
@@ -269,7 +285,17 @@ export class IterationOrchestrator {
|
|
|
269
285
|
messages,
|
|
270
286
|
tools: llmTools.length > 0 ? llmTools : undefined,
|
|
271
287
|
...(enforceToolInputSchema ? { enforceToolInputSchema } : {}),
|
|
272
|
-
|
|
288
|
+
// The forced-final turn wins: a step that asked to force a
|
|
289
|
+
// tool cannot override the loop's own decision to stop
|
|
290
|
+
// asking for them. Otherwise the step's choice applies —
|
|
291
|
+
// and only to this step, because the next one is prepared
|
|
292
|
+
// from scratch.
|
|
293
|
+
toolChoice:
|
|
294
|
+
forceFinalize && llmTools.length > 0
|
|
295
|
+
? 'none'
|
|
296
|
+
: llmTools.length > 0
|
|
297
|
+
? step.toolChoice
|
|
298
|
+
: undefined,
|
|
273
299
|
temperature: step.temperature ?? runConfig.temperature,
|
|
274
300
|
maxTokens: step.maxResponseTokens ?? runConfig.maxResponseTokens,
|
|
275
301
|
cacheControl: { type: 'auto' },
|
|
@@ -446,7 +472,6 @@ export class IterationOrchestrator {
|
|
|
446
472
|
hasToolCalls: false,
|
|
447
473
|
})
|
|
448
474
|
yield* this.ctx.drainPending()
|
|
449
|
-
iterSpan.end()
|
|
450
475
|
continue
|
|
451
476
|
}
|
|
452
477
|
|
|
@@ -464,7 +489,6 @@ export class IterationOrchestrator {
|
|
|
464
489
|
attempts: attempt - 1,
|
|
465
490
|
})
|
|
466
491
|
runMgr.setStopReason('structured_output_failed')
|
|
467
|
-
iterSpan.end()
|
|
468
492
|
break
|
|
469
493
|
}
|
|
470
494
|
this.ctx.log.info('Re-prompting for structured output', {
|
|
@@ -480,7 +504,6 @@ export class IterationOrchestrator {
|
|
|
480
504
|
hasToolCalls: false,
|
|
481
505
|
})
|
|
482
506
|
yield* this.ctx.drainPending()
|
|
483
|
-
iterSpan.end()
|
|
484
507
|
continue
|
|
485
508
|
}
|
|
486
509
|
|
|
@@ -509,7 +532,6 @@ export class IterationOrchestrator {
|
|
|
509
532
|
limit,
|
|
510
533
|
})
|
|
511
534
|
runMgr.setStopReason('answer_rejected')
|
|
512
|
-
iterSpan.end()
|
|
513
535
|
break
|
|
514
536
|
}
|
|
515
537
|
this.ctx.log.info('Answer rejected — returning it to the model', {
|
|
@@ -525,7 +547,6 @@ export class IterationOrchestrator {
|
|
|
525
547
|
hasToolCalls: false,
|
|
526
548
|
})
|
|
527
549
|
yield* this.ctx.drainPending()
|
|
528
|
-
iterSpan.end()
|
|
529
550
|
continue
|
|
530
551
|
}
|
|
531
552
|
}
|
|
@@ -553,11 +574,9 @@ export class IterationOrchestrator {
|
|
|
553
574
|
if (this.ctx.abortController.signal.aborted) {
|
|
554
575
|
runMgr.setStopReason('cancelled')
|
|
555
576
|
runMgr.markCancelled()
|
|
556
|
-
iterSpan.end()
|
|
557
577
|
break
|
|
558
578
|
}
|
|
559
579
|
runMgr.setStopReason('end_turn')
|
|
560
|
-
iterSpan.end()
|
|
561
580
|
break
|
|
562
581
|
}
|
|
563
582
|
|
|
@@ -579,12 +598,10 @@ export class IterationOrchestrator {
|
|
|
579
598
|
})
|
|
580
599
|
|
|
581
600
|
if (reviewOutcome.decision === 'stop') {
|
|
582
|
-
iterSpan.end()
|
|
583
601
|
return
|
|
584
602
|
}
|
|
585
603
|
|
|
586
604
|
if (reviewOutcome.decision === 'rejected') {
|
|
587
|
-
iterSpan.end()
|
|
588
605
|
continue
|
|
589
606
|
}
|
|
590
607
|
|
|
@@ -604,7 +621,6 @@ export class IterationOrchestrator {
|
|
|
604
621
|
hasToolCalls: true,
|
|
605
622
|
})
|
|
606
623
|
yield* this.ctx.drainPending()
|
|
607
|
-
iterSpan.end()
|
|
608
624
|
break
|
|
609
625
|
}
|
|
610
626
|
|
|
@@ -631,7 +647,6 @@ export class IterationOrchestrator {
|
|
|
631
647
|
hasToolCalls: true,
|
|
632
648
|
})
|
|
633
649
|
yield* this.ctx.drainPending()
|
|
634
|
-
iterSpan.end()
|
|
635
650
|
break
|
|
636
651
|
}
|
|
637
652
|
|
|
@@ -651,13 +666,11 @@ export class IterationOrchestrator {
|
|
|
651
666
|
hasToolCalls: true,
|
|
652
667
|
})
|
|
653
668
|
yield* this.ctx.drainPending()
|
|
654
|
-
iterSpan.end()
|
|
655
669
|
break
|
|
656
670
|
}
|
|
657
671
|
|
|
658
672
|
const checkpointSignal = yield* runIterationCheckpoint(this.ctx, iterationNum)
|
|
659
673
|
if (checkpointSignal === 'stop') {
|
|
660
|
-
iterSpan.end()
|
|
661
674
|
return
|
|
662
675
|
}
|
|
663
676
|
|
|
@@ -680,7 +693,6 @@ export class IterationOrchestrator {
|
|
|
680
693
|
hasToolCalls: true,
|
|
681
694
|
})
|
|
682
695
|
yield* this.ctx.drainPending()
|
|
683
|
-
iterSpan.end()
|
|
684
696
|
} catch (err) {
|
|
685
697
|
// A Stop that aborted the in-flight turn surfaces here as a
|
|
686
698
|
// thrown abort (the provider stream was raced against the run
|
|
@@ -692,7 +704,6 @@ export class IterationOrchestrator {
|
|
|
692
704
|
if (this.ctx.abortController.signal.aborted) {
|
|
693
705
|
runMgr.setStopReason('cancelled')
|
|
694
706
|
runMgr.markCancelled()
|
|
695
|
-
iterSpan.end()
|
|
696
707
|
break
|
|
697
708
|
}
|
|
698
709
|
|
|
@@ -722,7 +733,6 @@ export class IterationOrchestrator {
|
|
|
722
733
|
if (iterationActivity) {
|
|
723
734
|
this.ctx.activityStore.complete(iterationActivity.id)
|
|
724
735
|
}
|
|
725
|
-
iterSpan.end()
|
|
726
736
|
continue
|
|
727
737
|
}
|
|
728
738
|
}
|
|
@@ -736,8 +746,13 @@ export class IterationOrchestrator {
|
|
|
736
746
|
message: toErrorMessage(err),
|
|
737
747
|
})
|
|
738
748
|
iterSpan.recordException(err instanceof Error ? err : new Error(String(err)))
|
|
739
|
-
iterSpan.end()
|
|
740
749
|
throw err
|
|
750
|
+
} finally {
|
|
751
|
+
// The only place the iteration span ends. It used to be ended at each of
|
|
752
|
+
// seventeen exits, which is a rule every future edit has to
|
|
753
|
+
// remember; a generator abandoned by its consumer never reached
|
|
754
|
+
// any of them.
|
|
755
|
+
iterSpan.end()
|
|
741
756
|
}
|
|
742
757
|
}
|
|
743
758
|
}
|
|
@@ -752,8 +767,10 @@ export class IterationOrchestrator {
|
|
|
752
767
|
*/
|
|
753
768
|
private async prepareStep(stepNumber: number): Promise<{
|
|
754
769
|
allowedTools?: string[]
|
|
770
|
+
toolChoice?: ToolChoice
|
|
755
771
|
model?: string
|
|
756
772
|
system?: string
|
|
773
|
+
skills?: readonly Skill[]
|
|
757
774
|
temperature?: number
|
|
758
775
|
maxResponseTokens?: number
|
|
759
776
|
}> {
|
|
@@ -789,8 +806,10 @@ export class IterationOrchestrator {
|
|
|
789
806
|
|
|
790
807
|
const prepared: {
|
|
791
808
|
allowedTools?: string[]
|
|
809
|
+
toolChoice?: ToolChoice
|
|
792
810
|
model?: string
|
|
793
811
|
system?: string
|
|
812
|
+
skills?: readonly Skill[]
|
|
794
813
|
temperature?: number
|
|
795
814
|
maxResponseTokens?: number
|
|
796
815
|
} = {}
|
|
@@ -809,8 +828,10 @@ export class IterationOrchestrator {
|
|
|
809
828
|
}
|
|
810
829
|
prepared.allowedTools = known
|
|
811
830
|
}
|
|
831
|
+
if (result.toolChoice !== undefined) prepared.toolChoice = result.toolChoice
|
|
812
832
|
if (result.model !== undefined) prepared.model = result.model
|
|
813
833
|
if (result.system !== undefined) prepared.system = result.system
|
|
834
|
+
if (result.skills !== undefined) prepared.skills = result.skills
|
|
814
835
|
if (result.temperature !== undefined) prepared.temperature = result.temperature
|
|
815
836
|
if (result.maxResponseTokens !== undefined) {
|
|
816
837
|
prepared.maxResponseTokens = result.maxResponseTokens
|