@namzu/sdk 1.0.0 → 1.2.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 +253 -0
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +5 -0
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts +22 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +47 -14
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/__tests__/supervisor-ledger.test.d.ts +2 -0
- package/dist/agents/__tests__/supervisor-ledger.test.d.ts.map +1 -0
- package/dist/agents/__tests__/supervisor-ledger.test.js +131 -0
- package/dist/agents/__tests__/supervisor-ledger.test.js.map +1 -0
- 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 +4 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/config/runtime.d.ts +24 -0
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/runtime.js +9 -0
- package/dist/config/runtime.js.map +1 -1
- package/dist/connector/builtins/webhook.test.js +17 -0
- package/dist/connector/builtins/webhook.test.js.map +1 -1
- package/dist/connector/index.d.ts +1 -0
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +1 -0
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +4 -0
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/index.d.ts +1 -0
- package/dist/connector/mcp/index.d.ts.map +1 -1
- package/dist/connector/mcp/index.js +1 -0
- package/dist/connector/mcp/index.js.map +1 -1
- package/dist/connector/mcp/streamable-http.d.ts +22 -0
- package/dist/connector/mcp/streamable-http.d.ts.map +1 -0
- package/dist/connector/mcp/streamable-http.js +128 -0
- package/dist/connector/mcp/streamable-http.js.map +1 -0
- package/dist/connector/mcp/streamable-http.test.d.ts +2 -0
- package/dist/connector/mcp/streamable-http.test.d.ts.map +1 -0
- package/dist/connector/mcp/streamable-http.test.js +132 -0
- package/dist/connector/mcp/streamable-http.test.js.map +1 -0
- package/dist/{runtime/query → constants}/continuation.d.ts +5 -0
- package/dist/constants/continuation.d.ts.map +1 -0
- package/dist/{runtime/query → constants}/continuation.js +5 -0
- package/dist/constants/continuation.js.map +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +1 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +11 -0
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +30 -1
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/persona/assembler.d.ts.map +1 -1
- package/dist/persona/assembler.js +18 -9
- package/dist/persona/assembler.js.map +1 -1
- package/dist/provider/capabilities.d.ts +27 -0
- package/dist/provider/capabilities.d.ts.map +1 -0
- package/dist/provider/capabilities.js +29 -0
- package/dist/provider/capabilities.js.map +1 -0
- package/dist/provider/collect.d.ts.map +1 -1
- package/dist/provider/collect.js +4 -1
- package/dist/provider/collect.js.map +1 -1
- package/dist/provider/index.d.ts +2 -0
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +1 -0
- package/dist/provider/index.js.map +1 -1
- package/dist/public-runtime.d.ts +4 -3
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +3 -3
- package/dist/public-runtime.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +27 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +124 -21
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/registry/tool/execute.test.d.ts +9 -6
- package/dist/registry/tool/execute.test.d.ts.map +1 -1
- package/dist/registry/tool/execute.test.js +72 -10
- package/dist/registry/tool/execute.test.js.map +1 -1
- package/dist/registry/toolset/catalog.test.js +62 -0
- package/dist/registry/toolset/catalog.test.js.map +1 -1
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +8 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/runtime/query/__tests__/capability-negotiation.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/capability-negotiation.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/capability-negotiation.test.js +184 -0
- package/dist/runtime/query/__tests__/capability-negotiation.test.js.map +1 -0
- package/dist/runtime/query/__tests__/checkpoint-store.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/checkpoint-store.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/checkpoint-store.test.js +259 -0
- package/dist/runtime/query/__tests__/checkpoint-store.test.js.map +1 -0
- package/dist/runtime/query/__tests__/checkpoint.test.js +9 -3
- package/dist/runtime/query/__tests__/checkpoint.test.js.map +1 -1
- package/dist/runtime/query/__tests__/deferred-tools.test.js +43 -5
- package/dist/runtime/query/__tests__/deferred-tools.test.js.map +1 -1
- package/dist/runtime/query/__tests__/long-document-flow.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/long-document-flow.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/long-document-flow.test.js +154 -0
- package/dist/runtime/query/__tests__/long-document-flow.test.js.map +1 -0
- package/dist/runtime/query/__tests__/orphan-task-turn-end.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/orphan-task-turn-end.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/orphan-task-turn-end.test.js +110 -0
- package/dist/runtime/query/__tests__/orphan-task-turn-end.test.js.map +1 -0
- package/dist/runtime/query/__tests__/prompt.test.js +15 -11
- package/dist/runtime/query/__tests__/prompt.test.js.map +1 -1
- package/dist/runtime/query/checkpoint.d.ts +16 -2
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +21 -7
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/context.d.ts +7 -0
- package/dist/runtime/query/context.d.ts.map +1 -1
- package/dist/runtime/query/context.js +1 -0
- package/dist/runtime/query/context.js.map +1 -1
- package/dist/runtime/query/index.d.ts +29 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +98 -8
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +3 -55
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +260 -656
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.js +24 -2
- package/dist/runtime/query/iteration/phases/checkpoint.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +8 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +84 -3
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +13 -2
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js +53 -0
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js +73 -0
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js +120 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/tool-review.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +7 -2
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts +19 -0
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js +177 -0
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/working-memory.d.ts +31 -0
- package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/working-memory.js +81 -0
- package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts +35 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -0
- package/dist/runtime/query/iteration/stream-turn.js +341 -0
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -0
- package/dist/runtime/query/replay/list.d.ts +17 -1
- package/dist/runtime/query/replay/list.d.ts.map +1 -1
- package/dist/runtime/query/replay/list.js +21 -4
- package/dist/runtime/query/replay/list.js.map +1 -1
- package/dist/runtime/query/replay/prepare.d.ts +10 -0
- package/dist/runtime/query/replay/prepare.d.ts.map +1 -1
- package/dist/runtime/query/replay/prepare.js +20 -4
- package/dist/runtime/query/replay/prepare.js.map +1 -1
- package/dist/session/workspace/__tests__/shared-run.test.js +1 -1
- package/dist/session/workspace/__tests__/shared-run.test.js.map +1 -1
- package/dist/session/workspace/shared-run.js +1 -0
- package/dist/session/workspace/shared-run.js.map +1 -1
- package/dist/skills/loader.test.js +8 -8
- package/dist/skills/loader.test.js.map +1 -1
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +1 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/run/checkpoint-disk.d.ts +28 -0
- package/dist/store/run/checkpoint-disk.d.ts.map +1 -0
- package/dist/store/run/checkpoint-disk.js +55 -0
- package/dist/store/run/checkpoint-disk.js.map +1 -0
- package/dist/streaming/coalesce.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/payload-budget.test.js +48 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/read-file.test.js +9 -0
- package/dist/tools/builtins/__tests__/read-file.test.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +50 -2
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +32 -7
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts +2 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.js +114 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.js.map +1 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts +2 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.js +309 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.js.map +1 -0
- package/dist/tools/coordinator/index.d.ts +8 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +195 -15
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/types/agent/index.d.ts +1 -0
- package/dist/types/agent/index.d.ts.map +1 -1
- package/dist/types/agent/index.js +1 -0
- package/dist/types/agent/index.js.map +1 -1
- package/dist/types/agent/reactive.d.ts +15 -0
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +18 -0
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/agent/working-memory.d.ts +29 -0
- package/dist/types/agent/working-memory.d.ts.map +1 -0
- package/dist/types/agent/working-memory.js +2 -0
- package/dist/types/agent/working-memory.js.map +1 -0
- package/dist/types/common/index.d.ts +10 -0
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js +18 -0
- package/dist/types/common/index.js.map +1 -1
- package/dist/types/common/usage-merge.test.d.ts +2 -0
- package/dist/types/common/usage-merge.test.d.ts.map +1 -0
- package/dist/types/common/usage-merge.test.js +48 -0
- package/dist/types/common/usage-merge.test.js.map +1 -0
- package/dist/types/connector/mcp.d.ts +9 -2
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/hitl/index.d.ts +42 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js +11 -0
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +9 -0
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +18 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/interface.d.ts +10 -0
- package/dist/types/provider/interface.d.ts.map +1 -1
- package/dist/types/run/checkpoint-store.d.ts +64 -0
- package/dist/types/run/checkpoint-store.d.ts.map +1 -0
- package/dist/types/run/checkpoint-store.js +12 -0
- package/dist/types/run/checkpoint-store.js.map +1 -0
- package/dist/types/run/config.d.ts +27 -0
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +6 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/run/index.d.ts +1 -0
- package/dist/types/run/index.d.ts.map +1 -1
- package/dist/types/run/index.js +1 -0
- package/dist/types/run/index.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +25 -4
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/ReactiveAgent.ts +5 -0
- package/src/agents/SupervisorAgent.ts +56 -16
- package/src/agents/__tests__/supervisor-ledger.test.ts +185 -0
- package/src/bridge/a2a/mapper.ts +3 -0
- package/src/bridge/sse/mapper.ts +5 -0
- package/src/config/runtime.ts +9 -0
- package/src/connector/builtins/webhook.test.ts +21 -0
- package/src/connector/index.ts +1 -0
- package/src/connector/mcp/client.ts +4 -0
- package/src/connector/mcp/index.ts +1 -0
- package/src/connector/mcp/streamable-http.test.ts +169 -0
- package/src/connector/mcp/streamable-http.ts +152 -0
- package/src/{runtime/query → constants}/continuation.ts +5 -0
- package/src/constants/index.ts +1 -0
- package/src/manager/run/persistence.ts +34 -1
- package/src/persona/assembler.ts +18 -6
- package/src/provider/capabilities.ts +47 -0
- package/src/provider/collect.ts +4 -1
- package/src/provider/index.ts +5 -0
- package/src/public-runtime.ts +5 -0
- package/src/registry/tool/execute.test.ts +85 -10
- package/src/registry/tool/execute.ts +124 -21
- package/src/registry/toolset/catalog.test.ts +68 -0
- package/src/run/reporter.ts +9 -0
- package/src/runtime/query/__tests__/capability-negotiation.test.ts +248 -0
- package/src/runtime/query/__tests__/checkpoint-store.test.ts +322 -0
- package/src/runtime/query/__tests__/checkpoint.test.ts +15 -6
- package/src/runtime/query/__tests__/deferred-tools.test.ts +52 -5
- package/src/runtime/query/__tests__/long-document-flow.test.ts +180 -0
- package/src/runtime/query/__tests__/orphan-task-turn-end.test.ts +127 -0
- package/src/runtime/query/__tests__/prompt.test.ts +15 -11
- package/src/runtime/query/checkpoint.ts +23 -9
- package/src/runtime/query/context.ts +9 -0
- package/src/runtime/query/index.ts +148 -29
- package/src/runtime/query/iteration/index.ts +316 -831
- package/src/runtime/query/iteration/phases/checkpoint.ts +32 -2
- package/src/runtime/query/iteration/phases/compaction.ts +89 -3
- package/src/runtime/query/iteration/phases/context.ts +59 -3
- package/src/runtime/query/iteration/phases/hitl-abort-race.test.ts +86 -0
- package/src/runtime/query/iteration/phases/hitl-answer-question.test.ts +139 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +7 -3
- package/src/runtime/query/iteration/phases/working-memory-compaction.test.ts +215 -0
- package/src/runtime/query/iteration/phases/working-memory.ts +86 -0
- package/src/runtime/query/iteration/stream-turn.ts +396 -0
- package/src/runtime/query/replay/list.ts +38 -4
- package/src/runtime/query/replay/prepare.ts +37 -4
- package/src/session/workspace/__tests__/shared-run.test.ts +1 -1
- package/src/session/workspace/shared-run.ts +1 -0
- package/src/skills/loader.test.ts +8 -8
- package/src/store/index.ts +1 -0
- package/src/store/run/checkpoint-disk.ts +67 -0
- package/src/streaming/coalesce.test.ts +3 -3
- package/src/tools/builtins/__tests__/payload-budget.test.ts +63 -0
- package/src/tools/builtins/__tests__/read-file.test.ts +12 -0
- package/src/tools/builtins/read-file.ts +50 -2
- package/src/tools/builtins/search-tools.ts +38 -7
- package/src/tools/coordinator/__tests__/approve-plan.test.ts +139 -0
- package/src/tools/coordinator/__tests__/ask-user-question.test.ts +370 -0
- package/src/tools/coordinator/index.ts +227 -17
- package/src/types/agent/index.ts +1 -0
- package/src/types/agent/reactive.ts +17 -0
- package/src/types/agent/supervisor.ts +20 -0
- package/src/types/agent/working-memory.ts +29 -0
- package/src/types/common/index.ts +19 -0
- package/src/types/common/usage-merge.test.ts +53 -0
- package/src/types/connector/mcp.ts +14 -2
- package/src/types/hitl/index.ts +52 -1
- package/src/types/provider/chat.ts +10 -0
- package/src/types/provider/config.ts +18 -0
- package/src/types/provider/interface.ts +11 -0
- package/src/types/run/checkpoint-store.ts +72 -0
- package/src/types/run/config.ts +30 -0
- package/src/types/run/events.ts +13 -0
- package/src/types/run/index.ts +1 -0
- package/src/version.ts +26 -4
- package/dist/runtime/query/continuation.d.ts.map +0 -1
- package/dist/runtime/query/continuation.js.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { RunDiskStore } from '../../../store/run/disk.js'
|
|
2
2
|
import type { RunId } from '../../../types/ids/index.js'
|
|
3
|
+
import type { CheckpointRunScope, CheckpointStore } from '../../../types/run/checkpoint-store.js'
|
|
3
4
|
import type { CheckpointListEntry } from '../../../types/run/replay.js'
|
|
4
5
|
import type { Logger } from '../../../utils/logger.js'
|
|
5
|
-
import {
|
|
6
|
+
import { toCheckpointListEntry } from '../checkpoint.js'
|
|
6
7
|
|
|
7
8
|
export interface ListCheckpointsInput {
|
|
8
9
|
/** Directory that contains `<runId>/` for the target run. */
|
|
@@ -10,6 +11,15 @@ export interface ListCheckpointsInput {
|
|
|
10
11
|
/** Run whose checkpoints should be listed. */
|
|
11
12
|
runId: RunId
|
|
12
13
|
logger?: Logger
|
|
14
|
+
/**
|
|
15
|
+
* Optional store override (host-injected, e.g. Postgres). When set,
|
|
16
|
+
* `scope` is required — a scope-keyed backend cannot be addressed by
|
|
17
|
+
* `baseDir` — and `baseDir` is ignored. Absent ⇒ the disk layout under
|
|
18
|
+
* `baseDir` is read, exactly as before.
|
|
19
|
+
*/
|
|
20
|
+
checkpointStore?: CheckpointStore
|
|
21
|
+
/** Run scope for `checkpointStore`. Required when it is set. */
|
|
22
|
+
scope?: CheckpointRunScope
|
|
13
23
|
}
|
|
14
24
|
|
|
15
25
|
/**
|
|
@@ -19,14 +29,38 @@ export interface ListCheckpointsInput {
|
|
|
19
29
|
* pick a fork point — not the full `IterationCheckpoint` payload.
|
|
20
30
|
*
|
|
21
31
|
* Entries are returned in the order the underlying store returns them
|
|
22
|
-
* (
|
|
32
|
+
* (stores sort by `createdAt` ascending). Callers that want a
|
|
23
33
|
* specific order should sort client-side.
|
|
24
34
|
*
|
|
25
35
|
* See ses_005-deterministic-replay/design.md §3.1.
|
|
26
36
|
*/
|
|
27
37
|
export async function listCheckpoints(input: ListCheckpointsInput): Promise<CheckpointListEntry[]> {
|
|
38
|
+
const checkpoints = await listRawCheckpoints(input)
|
|
39
|
+
return checkpoints.map(toCheckpointListEntry)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function listRawCheckpoints(input: ListCheckpointsInput) {
|
|
43
|
+
if (input.checkpointStore) {
|
|
44
|
+
return input.checkpointStore.listCheckpoints(requireScope(input.scope, 'listCheckpoints'))
|
|
45
|
+
}
|
|
28
46
|
const store = new RunDiskStore({ baseDir: input.baseDir, logger: input.logger })
|
|
29
47
|
await store.initRun(input.runId)
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
return store.listCheckpoints()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Guard shared by the replay entry points: an injected {@link
|
|
53
|
+
* CheckpointStore} is scope-keyed, so the caller must say which run —
|
|
54
|
+
* across the full five-layer attribution — it is asking about.
|
|
55
|
+
*/
|
|
56
|
+
export function requireScope(
|
|
57
|
+
scope: CheckpointRunScope | undefined,
|
|
58
|
+
caller: string,
|
|
59
|
+
): CheckpointRunScope {
|
|
60
|
+
if (!scope) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`${caller}: \`checkpointStore\` was provided without \`scope\` — an injected store is keyed by tenantId/projectId/sessionId/runId, not by baseDir.`,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
return scope
|
|
32
66
|
}
|
|
@@ -4,9 +4,11 @@ import { RunDiskStore } from '../../../store/run/disk.js'
|
|
|
4
4
|
import type { CheckpointId, IterationCheckpoint } from '../../../types/hitl/index.js'
|
|
5
5
|
import type { RunId } from '../../../types/ids/index.js'
|
|
6
6
|
import type { Message } from '../../../types/message/index.js'
|
|
7
|
+
import type { CheckpointRunScope, CheckpointStore } from '../../../types/run/checkpoint-store.js'
|
|
7
8
|
import type { Mutation, ReplayAttribution } from '../../../types/run/replay.js'
|
|
8
9
|
import type { Logger } from '../../../utils/logger.js'
|
|
9
10
|
import { projectEmergencyToCheckpoint } from '../checkpoint.js'
|
|
11
|
+
import { requireScope } from './list.js'
|
|
10
12
|
import { applyMutations } from './mutate.js'
|
|
11
13
|
|
|
12
14
|
export type CheckpointSelector = CheckpointId | 'latest' | 'emergency'
|
|
@@ -27,6 +29,15 @@ export interface PrepareReplayInput {
|
|
|
27
29
|
*/
|
|
28
30
|
emergencyDir?: string
|
|
29
31
|
logger?: Logger
|
|
32
|
+
/**
|
|
33
|
+
* Optional store override (host-injected, e.g. Postgres). When set,
|
|
34
|
+
* `scope` is required and `baseDir` is ignored for checkpoint reads.
|
|
35
|
+
* The `'emergency'` selector still reads the on-disk dump under
|
|
36
|
+
* `emergencyDir` — emergency saves are process-local by nature.
|
|
37
|
+
*/
|
|
38
|
+
checkpointStore?: CheckpointStore
|
|
39
|
+
/** Run scope for `checkpointStore`. Required when it is set. */
|
|
40
|
+
scope?: CheckpointRunScope
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
export interface PreparedReplayState {
|
|
@@ -80,24 +91,46 @@ async function resolveCheckpoint(input: PrepareReplayInput): Promise<IterationCh
|
|
|
80
91
|
if (input.fromCheckpoint === 'emergency') {
|
|
81
92
|
return resolveEmergency(input)
|
|
82
93
|
}
|
|
83
|
-
|
|
84
|
-
await
|
|
94
|
+
|
|
95
|
+
const reader = await bindCheckpointReader(input)
|
|
85
96
|
|
|
86
97
|
if (input.fromCheckpoint === 'latest') {
|
|
87
|
-
const all = await
|
|
98
|
+
const all = await reader.list()
|
|
88
99
|
if (all.length === 0) {
|
|
89
100
|
throw new Error(`No checkpoints found for run ${input.runId} in ${input.baseDir}`)
|
|
90
101
|
}
|
|
91
102
|
return [...all].sort((a, b) => b.iteration - a.iteration)[0] as IterationCheckpoint
|
|
92
103
|
}
|
|
93
104
|
|
|
94
|
-
const checkpoint = await
|
|
105
|
+
const checkpoint = await reader.read(input.fromCheckpoint)
|
|
95
106
|
if (!checkpoint) {
|
|
96
107
|
throw new Error(`Checkpoint ${input.fromCheckpoint} not found for run ${input.runId}`)
|
|
97
108
|
}
|
|
98
109
|
return checkpoint
|
|
99
110
|
}
|
|
100
111
|
|
|
112
|
+
interface CheckpointReader {
|
|
113
|
+
list(): Promise<IterationCheckpoint[]>
|
|
114
|
+
read(id: CheckpointId): Promise<IterationCheckpoint | null>
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function bindCheckpointReader(input: PrepareReplayInput): Promise<CheckpointReader> {
|
|
118
|
+
if (input.checkpointStore) {
|
|
119
|
+
const store = input.checkpointStore
|
|
120
|
+
const scope = requireScope(input.scope, 'prepareReplayState')
|
|
121
|
+
return {
|
|
122
|
+
list: () => store.listCheckpoints(scope),
|
|
123
|
+
read: (id) => store.readCheckpoint(scope, id),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const store = new RunDiskStore({ baseDir: input.baseDir, logger: input.logger })
|
|
127
|
+
await store.initRun(input.runId)
|
|
128
|
+
return {
|
|
129
|
+
list: () => store.listCheckpoints(),
|
|
130
|
+
read: (id) => store.readCheckpoint(id),
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
101
134
|
async function resolveEmergency(input: PrepareReplayInput): Promise<IterationCheckpoint> {
|
|
102
135
|
if (!input.emergencyDir) {
|
|
103
136
|
throw new Error(
|
|
@@ -148,7 +148,7 @@ describe('SharedRunWorkspace', () => {
|
|
|
148
148
|
runtimeRoot: '/mnt/user-data/outputs/_work',
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
-
const big =
|
|
151
|
+
const big = `# Task Context\n\n${'A'.repeat(40_000)}`
|
|
152
152
|
const path = await workspace.writeTaskContext(big)
|
|
153
153
|
expect(path).toBe('/mnt/user-data/outputs/_work/01_task_context.md')
|
|
154
154
|
expect(workspace.refs().taskContextPath).toBe(path)
|
|
@@ -295,6 +295,7 @@ function ensureTrailingNewline(value: string): string {
|
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
async function writeJsonAtomic(path: string, value: unknown): Promise<void> {
|
|
298
|
+
await mkdir(dirnameFor(path), { recursive: true })
|
|
298
299
|
const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`
|
|
299
300
|
await writeFile(tmpPath, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
|
|
300
301
|
await rename(tmpPath, path)
|
|
@@ -16,11 +16,11 @@ describe('Agent Skills loader', () => {
|
|
|
16
16
|
const root = await mkdtemp(join(tmpdir(), 'namzu-skills-'))
|
|
17
17
|
const dir = await writeSkill(
|
|
18
18
|
root,
|
|
19
|
-
'
|
|
19
|
+
'delivery-briefing',
|
|
20
20
|
[
|
|
21
21
|
'---',
|
|
22
|
-
'name:
|
|
23
|
-
'description: Draft and edit grounded
|
|
22
|
+
'name: delivery-briefing',
|
|
23
|
+
'description: Draft and edit grounded delivery briefings.',
|
|
24
24
|
'license: MIT',
|
|
25
25
|
'compatibility: Requires filesystem tools',
|
|
26
26
|
'allowed-tools: read write edit',
|
|
@@ -36,8 +36,8 @@ describe('Agent Skills loader', () => {
|
|
|
36
36
|
const result = await loadSkill(dir, 'metadata')
|
|
37
37
|
|
|
38
38
|
expect(result.skill.metadata).toEqual({
|
|
39
|
-
name: '
|
|
40
|
-
description: 'Draft and edit grounded
|
|
39
|
+
name: 'delivery-briefing',
|
|
40
|
+
description: 'Draft and edit grounded delivery briefings.',
|
|
41
41
|
license: 'MIT',
|
|
42
42
|
compatibility: 'Requires filesystem tools',
|
|
43
43
|
allowedTools: 'read write edit',
|
|
@@ -53,11 +53,11 @@ describe('Agent Skills loader', () => {
|
|
|
53
53
|
const root = await mkdtemp(join(tmpdir(), 'namzu-skills-'))
|
|
54
54
|
const dir = await writeSkill(
|
|
55
55
|
root,
|
|
56
|
-
'
|
|
56
|
+
'structured-file-authoring',
|
|
57
57
|
[
|
|
58
58
|
'---',
|
|
59
|
-
'name:
|
|
60
|
-
'description: Create
|
|
59
|
+
'name: structured-file-authoring',
|
|
60
|
+
'description: Create structured files with bounded edit chunks.',
|
|
61
61
|
'---',
|
|
62
62
|
'Use skeleton-first writes.',
|
|
63
63
|
'',
|
package/src/store/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { InMemoryStore } from './InMemoryStore.js'
|
|
|
2
2
|
export type { Identifiable, Timestamped } from './InMemoryStore.js'
|
|
3
3
|
|
|
4
4
|
export { RunDiskStore } from './run/disk.js'
|
|
5
|
+
export { DiskCheckpointStore } from './run/checkpoint-disk.js'
|
|
5
6
|
|
|
6
7
|
export { ActivityStore } from './activity/memory.js'
|
|
7
8
|
export type { ActivityEvent, ActivityEventListener } from './activity/memory.js'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { CheckpointId, IterationCheckpoint } from '../../types/hitl/index.js'
|
|
2
|
+
import type { RunId } from '../../types/ids/index.js'
|
|
3
|
+
import type { CheckpointRunScope, CheckpointStore } from '../../types/run/checkpoint-store.js'
|
|
4
|
+
import type { RunStoreConfig } from '../../types/run/index.js'
|
|
5
|
+
import { RunDiskStore } from './disk.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Disk conformance layer for {@link CheckpointStore}: adapts the existing
|
|
9
|
+
* {@link RunDiskStore} checkpoint methods (which are bound to a single run
|
|
10
|
+
* directory via `initRun`) to the scope-keyed store contract.
|
|
11
|
+
*
|
|
12
|
+
* Path-addressed: `baseDir` already encodes project/session (it is the
|
|
13
|
+
* session's `runs/` directory), so only `scope.runId` / `scope.parentRunId`
|
|
14
|
+
* participate in directory resolution — `tenantId`/`projectId`/`sessionId`
|
|
15
|
+
* exist for backends that key by attribution instead of path.
|
|
16
|
+
*
|
|
17
|
+
* One `RunDiskStore` is bound (and its run directory created) per distinct
|
|
18
|
+
* `runId`, then cached, so repeated checkpoint operations against the same
|
|
19
|
+
* run don't re-run `initRun`.
|
|
20
|
+
*/
|
|
21
|
+
export class DiskCheckpointStore implements CheckpointStore {
|
|
22
|
+
private readonly config: RunStoreConfig
|
|
23
|
+
private readonly bound = new Map<RunId, Promise<RunDiskStore>>()
|
|
24
|
+
|
|
25
|
+
constructor(config: RunStoreConfig) {
|
|
26
|
+
this.config = config
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private bind(scope: CheckpointRunScope): Promise<RunDiskStore> {
|
|
30
|
+
const cached = this.bound.get(scope.runId)
|
|
31
|
+
if (cached) return cached
|
|
32
|
+
const promise = (async () => {
|
|
33
|
+
const store = new RunDiskStore(this.config)
|
|
34
|
+
await store.initRun(scope.runId, scope.parentRunId)
|
|
35
|
+
return store
|
|
36
|
+
})()
|
|
37
|
+
this.bound.set(scope.runId, promise)
|
|
38
|
+
// A failed bind must not poison the cache — the next call retries.
|
|
39
|
+
promise.catch(() => {
|
|
40
|
+
this.bound.delete(scope.runId)
|
|
41
|
+
})
|
|
42
|
+
return promise
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async writeCheckpoint(scope: CheckpointRunScope, checkpoint: IterationCheckpoint): Promise<void> {
|
|
46
|
+
const store = await this.bind(scope)
|
|
47
|
+
await store.writeCheckpoint(checkpoint)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async readCheckpoint(
|
|
51
|
+
scope: CheckpointRunScope,
|
|
52
|
+
checkpointId: CheckpointId,
|
|
53
|
+
): Promise<IterationCheckpoint | null> {
|
|
54
|
+
const store = await this.bind(scope)
|
|
55
|
+
return store.readCheckpoint(checkpointId)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async listCheckpoints(scope: CheckpointRunScope): Promise<IterationCheckpoint[]> {
|
|
59
|
+
const store = await this.bind(scope)
|
|
60
|
+
return store.listCheckpoints()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async deleteCheckpoint(scope: CheckpointRunScope, checkpointId: CheckpointId): Promise<void> {
|
|
64
|
+
const store = await this.bind(scope)
|
|
65
|
+
await store.deleteCheckpoint(checkpointId)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -117,14 +117,14 @@ describe('coalesce()', () => {
|
|
|
117
117
|
})
|
|
118
118
|
|
|
119
119
|
it('emits new event after window expires', async () => {
|
|
120
|
-
const events: RunEvent
|
|
120
|
+
const events: [RunEvent, RunEvent] = [
|
|
121
121
|
{ type: 'text_delta', runId: RID, iteration: 0, messageId: MID, text: 'a' },
|
|
122
122
|
{ type: 'text_delta', runId: RID, iteration: 0, messageId: MID, text: 'b' },
|
|
123
123
|
]
|
|
124
124
|
const stream: AsyncIterable<RunEvent> = (async function* () {
|
|
125
|
-
yield events[0]
|
|
125
|
+
yield events[0]
|
|
126
126
|
await new Promise((r) => setTimeout(r, 30))
|
|
127
|
-
yield events[1]
|
|
127
|
+
yield events[1]
|
|
128
128
|
})()
|
|
129
129
|
const result = await drain(coalesce(stream, { windowMs: 16 }))
|
|
130
130
|
expect(result).toHaveLength(2)
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
1
4
|
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import type { ToolContext } from '../../../types/tool/index.js'
|
|
2
6
|
import { EditTool } from '../edit.js'
|
|
3
7
|
import { getBuiltinTools } from '../index.js'
|
|
4
8
|
import { WriteFileTool } from '../write-file.js'
|
|
@@ -26,4 +30,63 @@ describe('filesystem tool payload budgeting', () => {
|
|
|
26
30
|
expect(names).toContain('edit')
|
|
27
31
|
expect(names).not.toContain('append')
|
|
28
32
|
})
|
|
33
|
+
|
|
34
|
+
it('assembles long documents with bounded write plus edit insert chunks', async () => {
|
|
35
|
+
const dir = mkdtempSync(join(tmpdir(), 'namzu-long-doc-'))
|
|
36
|
+
const ctx: ToolContext = {
|
|
37
|
+
runId: 'run_test' as ToolContext['runId'],
|
|
38
|
+
workingDirectory: dir,
|
|
39
|
+
abortSignal: new AbortController().signal,
|
|
40
|
+
env: {},
|
|
41
|
+
log: () => {},
|
|
42
|
+
}
|
|
43
|
+
const opening = '# Long document regression\n\n{{BODY}}\n'
|
|
44
|
+
const chunks = Array.from({ length: 6 }, (_, sectionIndex) => {
|
|
45
|
+
const lines = Array.from({ length: 45 }, (_, lineIndex) => {
|
|
46
|
+
const section = sectionIndex + 1
|
|
47
|
+
const line = lineIndex + 1
|
|
48
|
+
return `Section ${section}.${line}: this bounded paragraph proves long-form output grows through edit insertions rather than one oversized JSON tool argument.`
|
|
49
|
+
})
|
|
50
|
+
const chunk = [`## Section ${sectionIndex + 1}`, ...lines, ''].join('\n')
|
|
51
|
+
expect(chunk.length).toBeLessThan(12_000)
|
|
52
|
+
return chunk
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const writeResult = await WriteFileTool.execute(
|
|
56
|
+
{ path: 'outputs/regression-long-document.md', content: opening },
|
|
57
|
+
ctx,
|
|
58
|
+
)
|
|
59
|
+
expect(writeResult.success).toBe(true)
|
|
60
|
+
|
|
61
|
+
const firstEdit = await EditTool.execute(
|
|
62
|
+
{
|
|
63
|
+
path: 'outputs/regression-long-document.md',
|
|
64
|
+
oldStr: '{{BODY}}',
|
|
65
|
+
newStr: chunks[0],
|
|
66
|
+
replace_all: false,
|
|
67
|
+
},
|
|
68
|
+
ctx,
|
|
69
|
+
)
|
|
70
|
+
expect(firstEdit.success).toBe(true)
|
|
71
|
+
|
|
72
|
+
for (const chunk of chunks.slice(1)) {
|
|
73
|
+
const result = await EditTool.execute(
|
|
74
|
+
{
|
|
75
|
+
path: 'outputs/regression-long-document.md',
|
|
76
|
+
insertLine: 'end',
|
|
77
|
+
newStr: chunk,
|
|
78
|
+
replace_all: false,
|
|
79
|
+
},
|
|
80
|
+
ctx,
|
|
81
|
+
)
|
|
82
|
+
expect(result.success).toBe(true)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const final = readFileSync(join(dir, 'outputs/regression-long-document.md'), 'utf-8')
|
|
86
|
+
expect(final).not.toContain('{{BODY}}')
|
|
87
|
+
expect(final.split('\n').length).toBeGreaterThan(250)
|
|
88
|
+
expect(final).toContain('## Section 1')
|
|
89
|
+
expect(final).toContain('## Section 6')
|
|
90
|
+
expect(final).toContain('Section 6.45')
|
|
91
|
+
})
|
|
29
92
|
})
|
|
@@ -28,4 +28,16 @@ describe('ReadFileTool', () => {
|
|
|
28
28
|
expect(result.success).toBe(true)
|
|
29
29
|
expect(result.output).toBe('2\ttwo\n3\tthree')
|
|
30
30
|
})
|
|
31
|
+
|
|
32
|
+
it('guides binary Office documents through extractor tooling', async () => {
|
|
33
|
+
const dir = mkdtempSync(join(tmpdir(), 'namzu-read-'))
|
|
34
|
+
writeFileSync(join(dir, 'transcript.docx'), Buffer.from('PK\x03\x04binary-docx'))
|
|
35
|
+
|
|
36
|
+
const result = await ReadFileTool.execute({ path: 'transcript.docx' }, makeContext(dir))
|
|
37
|
+
|
|
38
|
+
expect(result.success).toBe(false)
|
|
39
|
+
expect(result.output).toContain('DOCX document package')
|
|
40
|
+
expect(result.output).toContain('python-docx')
|
|
41
|
+
expect(result.data).toMatchObject({ binary: true })
|
|
42
|
+
})
|
|
31
43
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
2
|
+
import { extname, resolve } from 'node:path'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
import { defineTool } from '../defineTool.js'
|
|
5
5
|
|
|
@@ -35,6 +35,18 @@ export const ReadFileTool = defineTool({
|
|
|
35
35
|
// Sandbox-aware: route through sandbox.readFile() when available
|
|
36
36
|
if (context.sandbox) {
|
|
37
37
|
const buffer = await context.sandbox.readFile(input.path)
|
|
38
|
+
const binaryGuidance = describeStructuredBinaryRead(input.path, buffer)
|
|
39
|
+
if (binaryGuidance) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
output: binaryGuidance,
|
|
43
|
+
data: {
|
|
44
|
+
path: input.path,
|
|
45
|
+
sandboxed: true,
|
|
46
|
+
binary: true,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
38
50
|
const content = buffer.toString('utf-8')
|
|
39
51
|
const lines = content.split('\n')
|
|
40
52
|
|
|
@@ -58,7 +70,19 @@ export const ReadFileTool = defineTool({
|
|
|
58
70
|
}
|
|
59
71
|
|
|
60
72
|
const filePath = resolve(context.workingDirectory, input.path)
|
|
61
|
-
const
|
|
73
|
+
const buffer = await readFile(filePath)
|
|
74
|
+
const binaryGuidance = describeStructuredBinaryRead(filePath, buffer)
|
|
75
|
+
if (binaryGuidance) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
output: binaryGuidance,
|
|
79
|
+
data: {
|
|
80
|
+
path: filePath,
|
|
81
|
+
binary: true,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const content = buffer.toString('utf-8')
|
|
62
86
|
const lines = content.split('\n')
|
|
63
87
|
|
|
64
88
|
const { start, end } = resolveReadWindow(input, lines.length)
|
|
@@ -80,6 +104,30 @@ export const ReadFileTool = defineTool({
|
|
|
80
104
|
},
|
|
81
105
|
})
|
|
82
106
|
|
|
107
|
+
function describeStructuredBinaryRead(path: string, buffer: Buffer): string | null {
|
|
108
|
+
const ext = extname(path).toLowerCase()
|
|
109
|
+
if (ext === '.docx') return buildStructuredBinaryGuidance(path, 'DOCX', 'python-docx')
|
|
110
|
+
if (ext === '.pptx') return buildStructuredBinaryGuidance(path, 'PPTX', 'python-pptx')
|
|
111
|
+
if (ext === '.xlsx') return buildStructuredBinaryGuidance(path, 'XLSX', 'openpyxl')
|
|
112
|
+
if (ext === '.pdf' || startsWithPdfHeader(buffer)) {
|
|
113
|
+
return buildStructuredBinaryGuidance(path, 'PDF', 'pdftotext or PyMuPDF')
|
|
114
|
+
}
|
|
115
|
+
return null
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function startsWithPdfHeader(buffer: Buffer): boolean {
|
|
119
|
+
return buffer.length >= 4 && buffer.subarray(0, 4).toString('utf8') === '%PDF'
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function buildStructuredBinaryGuidance(path: string, format: string, extractor: string): string {
|
|
123
|
+
return [
|
|
124
|
+
`The file "${path}" is a ${format} document package, not UTF-8 text.`,
|
|
125
|
+
'Do not use the read/cat tools as evidence for this raw file.',
|
|
126
|
+
`Extract its text with shell/Python tooling already available in the sandbox (${extractor}), write the extracted text or summary under scratch, then read that text file.`,
|
|
127
|
+
'If extraction fails, report the exact filename and extraction error instead of claiming the attachment is unavailable.',
|
|
128
|
+
].join('\n')
|
|
129
|
+
}
|
|
130
|
+
|
|
83
131
|
function resolveReadWindow(
|
|
84
132
|
input: z.infer<typeof inputSchema>,
|
|
85
133
|
totalLines: number,
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import { toolDiscoveryHint } from '../../registry/tool/execute.js'
|
|
2
3
|
import { defineTool } from '../defineTool.js'
|
|
3
4
|
|
|
4
5
|
const inputSchema = z.object({
|
|
5
6
|
query: z.string().describe('Tool name or capability keyword to search for'),
|
|
6
7
|
})
|
|
7
8
|
|
|
9
|
+
// Activate only the best-ranked matches. Top-5 is the literature's sweet
|
|
10
|
+
// spot (retrieval at k=5 matches oracle toolsets) and bounds how much
|
|
11
|
+
// schema weight a single search can add to every subsequent iteration —
|
|
12
|
+
// each activation also busts the prompt-cache prefix once.
|
|
13
|
+
const ACTIVATION_TOP_K = 5
|
|
14
|
+
|
|
15
|
+
// Near-misses are reported name+hint WITHOUT activating, so a retrieval
|
|
16
|
+
// miss becomes one cheap re-query instead of a dead end (the fixed-top-k
|
|
17
|
+
// hard-tail failure mode: the right tool ranked 6th-10th).
|
|
18
|
+
const NEAR_MISS_LIMIT = 5
|
|
19
|
+
|
|
8
20
|
export const SearchToolsTool = defineTool({
|
|
9
21
|
name: 'search_tools',
|
|
10
22
|
description:
|
|
@@ -28,27 +40,46 @@ export const SearchToolsTool = defineTool({
|
|
|
28
40
|
|
|
29
41
|
const allowed =
|
|
30
42
|
context.allowedTools && context.allowedTools.length > 0 ? new Set(context.allowedTools) : null
|
|
31
|
-
|
|
43
|
+
// `searchDeferred` returns a ranked list (score-descending), so slicing
|
|
44
|
+
// the head is a true top-k activation, not an arbitrary subset.
|
|
45
|
+
const ranked = context.toolRegistry
|
|
32
46
|
.searchDeferred(input.query)
|
|
33
47
|
.filter((tool) => !allowed || allowed.has(tool.name))
|
|
34
48
|
|
|
35
|
-
if (
|
|
49
|
+
if (ranked.length === 0) {
|
|
36
50
|
return {
|
|
37
51
|
success: true,
|
|
38
52
|
output: `No deferred tools matching "${input.query}". All matching tools are already active.`,
|
|
39
53
|
}
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
|
|
56
|
+
const activated = ranked.slice(0, ACTIVATION_TOP_K)
|
|
57
|
+
const nearMisses = ranked.slice(ACTIVATION_TOP_K, ACTIVATION_TOP_K + NEAR_MISS_LIMIT)
|
|
58
|
+
|
|
59
|
+
context.toolRegistry.activate(activated.map((t) => t.name))
|
|
43
60
|
|
|
44
|
-
const descriptions =
|
|
61
|
+
const descriptions = activated.map((t) => `- ${t.name}: ${t.description}`).join('\n')
|
|
62
|
+
const sections = [`Activated ${activated.length} tool(s):\n${descriptions}`]
|
|
63
|
+
|
|
64
|
+
if (nearMisses.length > 0) {
|
|
65
|
+
const hints = nearMisses
|
|
66
|
+
.map((t) => {
|
|
67
|
+
const hint = toolDiscoveryHint(t.description)
|
|
68
|
+
return hint.length > 0 ? `- ${t.name}: ${hint}` : `- ${t.name}`
|
|
69
|
+
})
|
|
70
|
+
.join('\n')
|
|
71
|
+
sections.push(
|
|
72
|
+
`Also matched but NOT loaded (search again with a more specific query, e.g. the tool name, to load one of these):\n${hints}`,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
45
75
|
|
|
46
76
|
return {
|
|
47
77
|
success: true,
|
|
48
|
-
output:
|
|
78
|
+
output: sections.join('\n\n'),
|
|
49
79
|
data: {
|
|
50
|
-
activated:
|
|
51
|
-
count:
|
|
80
|
+
activated: activated.map((t) => t.name),
|
|
81
|
+
count: activated.length,
|
|
82
|
+
nearMisses: nearMisses.map((t) => t.name),
|
|
52
83
|
},
|
|
53
84
|
}
|
|
54
85
|
},
|