@namzu/sdk 0.6.0 → 1.1.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 +529 -0
- package/dist/advisory/executor.d.ts.map +1 -1
- package/dist/advisory/executor.js +9 -2
- package/dist/advisory/executor.js.map +1 -1
- package/dist/advisory/executor.test.d.ts +2 -1
- package/dist/advisory/executor.test.d.ts.map +1 -1
- package/dist/advisory/executor.test.js +7 -4
- package/dist/advisory/executor.test.js.map +1 -1
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +7 -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 +54 -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/sse/mapper.test.js +2 -2
- 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/constants/compaction/index.d.ts.map +1 -1
- package/dist/constants/compaction/index.js +8 -3
- package/dist/constants/compaction/index.js.map +1 -1
- package/dist/constants/sandbox/index.d.ts +21 -0
- package/dist/constants/sandbox/index.d.ts.map +1 -1
- package/dist/constants/sandbox/index.js +30 -0
- package/dist/constants/sandbox/index.js.map +1 -1
- package/dist/constants/tools/index.d.ts.map +1 -1
- package/dist/constants/tools/index.js +33 -2
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +35 -5
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/persona/assembler.d.ts +1 -0
- package/dist/persona/assembler.d.ts.map +1 -1
- package/dist/persona/assembler.js +37 -6
- package/dist/persona/assembler.js.map +1 -1
- 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/collect.test.js +2 -2
- package/dist/public-runtime.d.ts +6 -5
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +6 -5
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +2 -0
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +2 -0
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +3 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.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 +192 -7
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/registry/tool/execute.test.d.ts +9 -4
- package/dist/registry/tool/execute.test.d.ts.map +1 -1
- package/dist/registry/tool/execute.test.js +178 -7
- package/dist/registry/tool/execute.test.js.map +1 -1
- package/dist/registry/toolset/catalog.d.ts +42 -0
- package/dist/registry/toolset/catalog.d.ts.map +1 -0
- package/dist/registry/toolset/catalog.js +217 -0
- package/dist/registry/toolset/catalog.js.map +1 -0
- package/dist/registry/toolset/catalog.test.d.ts +2 -0
- package/dist/registry/toolset/catalog.test.d.ts.map +1 -0
- package/dist/registry/toolset/catalog.test.js +147 -0
- package/dist/registry/toolset/catalog.test.js.map +1 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.js +185 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.js.map +1 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.js +98 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.js.map +1 -0
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js +38 -3
- package/dist/runtime/query/__tests__/executor-plugin-hooks.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__/prompt.test.js +51 -2
- package/dist/runtime/query/__tests__/prompt.test.js.map +1 -1
- package/dist/runtime/query/__tests__/stream-recovery.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/stream-recovery.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/stream-recovery.test.js +126 -0
- package/dist/runtime/query/__tests__/stream-recovery.test.js.map +1 -0
- package/dist/runtime/query/continuation.d.ts +16 -0
- package/dist/runtime/query/continuation.d.ts.map +1 -0
- package/dist/runtime/query/continuation.js +16 -0
- package/dist/runtime/query/continuation.js.map +1 -0
- package/dist/runtime/query/executor.d.ts +3 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +71 -3
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +9 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +42 -5
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +24 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +326 -66
- 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 +2 -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 +22 -0
- 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/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +21 -1
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +1 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +1 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +32 -1
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/session/workspace/__tests__/shared-run.test.d.ts +2 -0
- package/dist/session/workspace/__tests__/shared-run.test.d.ts.map +1 -0
- package/dist/session/workspace/__tests__/shared-run.test.js +147 -0
- package/dist/session/workspace/__tests__/shared-run.test.js.map +1 -0
- package/dist/session/workspace/index.d.ts +2 -0
- package/dist/session/workspace/index.d.ts.map +1 -1
- package/dist/session/workspace/index.js +1 -0
- package/dist/session/workspace/index.js.map +1 -1
- package/dist/session/workspace/shared-run.d.ts +81 -0
- package/dist/session/workspace/shared-run.d.ts.map +1 -0
- package/dist/session/workspace/shared-run.js +252 -0
- package/dist/session/workspace/shared-run.js.map +1 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +36 -6
- package/dist/skills/loader.js.map +1 -1
- package/dist/skills/loader.test.d.ts +2 -0
- package/dist/skills/loader.test.d.ts.map +1 -0
- package/dist/skills/loader.test.js +65 -0
- package/dist/skills/loader.test.js.map +1 -0
- package/dist/streaming/coalesce.test.js +1 -1
- package/dist/streaming/coalesce.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/edit.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/edit.test.js +38 -0
- package/dist/tools/builtins/__tests__/edit.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.js +70 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/read-file.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/read-file.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/read-file.test.js +33 -0
- package/dist/tools/builtins/__tests__/read-file.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.js +52 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/write-file.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/write-file.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/write-file.test.js +74 -0
- package/dist/tools/builtins/__tests__/write-file.test.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +40 -7
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts +5 -2
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +114 -18
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/index.d.ts +1 -0
- package/dist/tools/builtins/index.d.ts.map +1 -1
- package/dist/tools/builtins/index.js +13 -13
- package/dist/tools/builtins/index.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts +1 -0
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +73 -10
- 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 +35 -7
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/builtins/verify-outputs.d.ts +5 -0
- package/dist/tools/builtins/verify-outputs.d.ts.map +1 -0
- package/dist/tools/builtins/verify-outputs.js +103 -0
- package/dist/tools/builtins/verify-outputs.js.map +1 -0
- package/dist/tools/builtins/write-file.d.ts +3 -2
- package/dist/tools/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +72 -12
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/coordinator/__tests__/agent.test.d.ts +15 -0
- package/dist/tools/coordinator/__tests__/agent.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/agent.test.js +142 -0
- package/dist/tools/coordinator/__tests__/agent.test.js.map +1 -0
- 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/__tests__/task-list.test.d.ts +13 -0
- package/dist/tools/coordinator/__tests__/task-list.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/task-list.test.js +162 -0
- package/dist/tools/coordinator/__tests__/task-list.test.js.map +1 -0
- package/dist/tools/coordinator/agent.d.ts +34 -0
- package/dist/tools/coordinator/agent.d.ts.map +1 -0
- package/dist/tools/coordinator/agent.js +107 -0
- package/dist/tools/coordinator/agent.js.map +1 -0
- package/dist/tools/coordinator/index.d.ts +15 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +305 -35
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/types/agent/base.d.ts +8 -0
- package/dist/types/agent/base.d.ts.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 +38 -0
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +32 -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/message/index.d.ts +22 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +7 -2
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +11 -9
- package/dist/types/provider/chat.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/sandbox/index.d.ts +193 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/skills/index.d.ts +2 -0
- package/dist/types/skills/index.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +22 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/toolset/index.d.ts +71 -0
- package/dist/types/toolset/index.d.ts.map +1 -0
- package/dist/types/toolset/index.js +2 -0
- package/dist/types/toolset/index.js.map +1 -0
- package/dist/types/workspace/index.d.ts +1 -0
- package/dist/types/workspace/index.d.ts.map +1 -1
- package/dist/types/workspace/shared-run.d.ts +61 -0
- package/dist/types/workspace/shared-run.d.ts.map +1 -0
- package/dist/types/workspace/shared-run.js +2 -0
- package/dist/types/workspace/shared-run.js.map +1 -0
- package/dist/verification/index.d.ts +1 -0
- package/dist/verification/index.d.ts.map +1 -1
- package/dist/verification/index.js +1 -0
- package/dist/verification/index.js.map +1 -1
- package/dist/verification/presets.d.ts +53 -0
- package/dist/verification/presets.d.ts.map +1 -0
- package/dist/verification/presets.js +70 -0
- package/dist/verification/presets.js.map +1 -0
- package/dist/verification/presets.test.d.ts +16 -0
- package/dist/verification/presets.test.d.ts.map +1 -0
- package/dist/verification/presets.test.js +79 -0
- package/dist/verification/presets.test.js.map +1 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +25 -4
- package/dist/version.js.map +1 -1
- package/package.json +3 -2
- package/src/advisory/executor.test.ts +7 -4
- package/src/advisory/executor.ts +11 -2
- package/src/agents/ReactiveAgent.ts +7 -0
- package/src/agents/SupervisorAgent.ts +63 -16
- package/src/agents/__tests__/supervisor-ledger.test.ts +185 -0
- package/src/bridge/sse/mapper.test.ts +2 -2
- 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/constants/compaction/index.ts +8 -3
- package/src/constants/sandbox/index.ts +37 -0
- package/src/constants/tools/index.ts +33 -2
- package/src/manager/run/persistence.ts +34 -6
- package/src/persona/assembler.ts +43 -8
- package/src/provider/collect.test.ts +2 -2
- package/src/provider/collect.ts +4 -1
- package/src/public-runtime.ts +15 -1
- package/src/public-tools.ts +2 -0
- package/src/public-types.ts +7 -0
- package/src/registry/index.ts +7 -0
- package/src/registry/tool/execute.test.ts +211 -7
- package/src/registry/tool/execute.ts +199 -11
- package/src/registry/toolset/catalog.test.ts +165 -0
- package/src/registry/toolset/catalog.ts +283 -0
- package/src/runtime/query/__tests__/deferred-tools.test.ts +230 -0
- package/src/runtime/query/__tests__/executor-concurrency.test.ts +122 -0
- package/src/runtime/query/__tests__/executor-plugin-hooks.test.ts +48 -3
- package/src/runtime/query/__tests__/long-document-flow.test.ts +180 -0
- package/src/runtime/query/__tests__/prompt.test.ts +55 -2
- package/src/runtime/query/__tests__/stream-recovery.test.ts +156 -0
- package/src/runtime/query/continuation.ts +16 -0
- package/src/runtime/query/executor.ts +82 -13
- package/src/runtime/query/index.ts +58 -5
- package/src/runtime/query/iteration/index.ts +361 -74
- package/src/runtime/query/iteration/phases/checkpoint.ts +7 -2
- package/src/runtime/query/iteration/phases/compaction.ts +89 -3
- package/src/runtime/query/iteration/phases/context.ts +68 -0
- 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/prompt.ts +17 -1
- package/src/runtime/query/tooling.ts +2 -0
- package/src/sandbox/provider/local.ts +33 -0
- package/src/session/workspace/__tests__/shared-run.test.ts +181 -0
- package/src/session/workspace/index.ts +6 -0
- package/src/session/workspace/shared-run.ts +317 -0
- package/src/skills/loader.test.ts +89 -0
- package/src/skills/loader.ts +37 -6
- package/src/streaming/coalesce.test.ts +4 -4
- package/src/tools/builtins/__tests__/edit.test.ts +57 -0
- package/src/tools/builtins/__tests__/payload-budget.test.ts +92 -0
- package/src/tools/builtins/__tests__/read-file.test.ts +43 -0
- package/src/tools/builtins/__tests__/verify-outputs.test.ts +71 -0
- package/src/tools/builtins/__tests__/write-file.test.ts +97 -0
- package/src/tools/builtins/bash.ts +48 -7
- package/src/tools/builtins/edit.ts +162 -27
- package/src/tools/builtins/index.ts +13 -13
- package/src/tools/builtins/read-file.ts +81 -10
- package/src/tools/builtins/search-tools.ts +42 -7
- package/src/tools/builtins/verify-outputs.ts +126 -0
- package/src/tools/builtins/write-file.ts +83 -14
- package/src/tools/coordinator/__tests__/agent.test.ts +172 -0
- 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/__tests__/task-list.test.ts +182 -0
- package/src/tools/coordinator/agent.ts +157 -0
- package/src/tools/coordinator/index.ts +355 -39
- package/src/types/agent/base.ts +8 -0
- package/src/types/agent/index.ts +1 -0
- package/src/types/agent/reactive.ts +42 -0
- package/src/types/agent/supervisor.ts +36 -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/message/index.ts +32 -2
- package/src/types/provider/chat.ts +12 -9
- package/src/types/run/events.ts +6 -0
- package/src/types/sandbox/index.ts +219 -0
- package/src/types/skills/index.ts +4 -0
- package/src/types/tool/index.ts +24 -0
- package/src/types/toolset/index.ts +86 -0
- package/src/types/workspace/index.ts +9 -0
- package/src/types/workspace/shared-run.ts +65 -0
- package/src/verification/index.ts +1 -0
- package/src/verification/presets.test.ts +112 -0
- package/src/verification/presets.ts +72 -0
- package/src/version.ts +26 -4
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { dirname, join, normalize, relative, sep } from 'node:path'
|
|
3
|
+
import { posix } from 'node:path'
|
|
4
|
+
import type {
|
|
5
|
+
SharedRunWorkspaceAgentRecord,
|
|
6
|
+
SharedRunWorkspaceManifest,
|
|
7
|
+
SharedRunWorkspacePlan,
|
|
8
|
+
SharedRunWorkspaceRefs,
|
|
9
|
+
SharedRunWorkspaceSource,
|
|
10
|
+
} from '../../types/workspace/shared-run.js'
|
|
11
|
+
|
|
12
|
+
export interface SharedRunWorkspaceConfig {
|
|
13
|
+
/**
|
|
14
|
+
* Host-visible `_work` directory. The runtime creates and mutates files
|
|
15
|
+
* here before/while agents execute.
|
|
16
|
+
*/
|
|
17
|
+
hostRoot: string
|
|
18
|
+
/**
|
|
19
|
+
* Agent-visible `_work` directory. In container sandboxes this is usually
|
|
20
|
+
* `/mnt/user-data/outputs/_work`; in local mode it can be the same
|
|
21
|
+
* relative path agents receive in their runtime notes.
|
|
22
|
+
*/
|
|
23
|
+
runtimeRoot?: string
|
|
24
|
+
label?: string
|
|
25
|
+
now?: Date
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RegisterSharedRunPlanInput {
|
|
29
|
+
id?: string
|
|
30
|
+
briefText: string
|
|
31
|
+
status?: SharedRunWorkspacePlan['status']
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class SharedRunWorkspace {
|
|
35
|
+
readonly hostRoot: string
|
|
36
|
+
readonly runtimeRoot: string
|
|
37
|
+
private manifestWriteQueue: Promise<void> = Promise.resolve()
|
|
38
|
+
|
|
39
|
+
private constructor(private readonly config: Required<SharedRunWorkspaceConfig>) {
|
|
40
|
+
this.hostRoot = config.hostRoot
|
|
41
|
+
this.runtimeRoot = trimTrailingSlash(config.runtimeRoot)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static async create(config: SharedRunWorkspaceConfig): Promise<SharedRunWorkspace> {
|
|
45
|
+
const workspace = new SharedRunWorkspace({
|
|
46
|
+
hostRoot: config.hostRoot,
|
|
47
|
+
runtimeRoot: config.runtimeRoot ?? config.hostRoot,
|
|
48
|
+
label: config.label ?? '',
|
|
49
|
+
now: config.now ?? new Date(),
|
|
50
|
+
})
|
|
51
|
+
await workspace.ensure()
|
|
52
|
+
return workspace
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
refs(): SharedRunWorkspaceRefs {
|
|
56
|
+
return {
|
|
57
|
+
rootPath: this.runtimePath(),
|
|
58
|
+
manifestPath: this.runtimePath('manifest.json'),
|
|
59
|
+
sharedContextPath: this.runtimePath('02_shared_context.md'),
|
|
60
|
+
sourceInventoryPath: this.runtimePath('sources', 'inventory.md'),
|
|
61
|
+
supervisorBriefPath: this.runtimePath('00_supervisor_brief.md'),
|
|
62
|
+
taskContextPath: this.runtimePath('01_task_context.md'),
|
|
63
|
+
agentsPath: this.runtimePath('agents'),
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
hostPath(...segments: string[]): string {
|
|
68
|
+
return safeJoin(this.hostRoot, segments)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
runtimePath(...segments: string[]): string {
|
|
72
|
+
if (segments.length === 0) return this.runtimeRoot
|
|
73
|
+
return posix.join(this.runtimeRoot, ...segments.map((segment) => segment.split(sep).join('/')))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async ensure(): Promise<void> {
|
|
77
|
+
await Promise.all([
|
|
78
|
+
mkdir(this.hostPath('sources'), { recursive: true }),
|
|
79
|
+
mkdir(this.hostPath('plans', 'root'), { recursive: true }),
|
|
80
|
+
mkdir(this.hostPath('agents'), { recursive: true }),
|
|
81
|
+
])
|
|
82
|
+
await this.writeManifest((manifest) => manifest)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async readManifest(): Promise<SharedRunWorkspaceManifest> {
|
|
86
|
+
const content = await readFile(this.hostPath('manifest.json'), 'utf8').catch(() => '')
|
|
87
|
+
if (!content.trim()) return this.initialManifest()
|
|
88
|
+
return JSON.parse(content) as SharedRunWorkspaceManifest
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async writeManifest(
|
|
92
|
+
update: (manifest: SharedRunWorkspaceManifest) => SharedRunWorkspaceManifest,
|
|
93
|
+
): Promise<SharedRunWorkspaceManifest> {
|
|
94
|
+
const operation = this.manifestWriteQueue
|
|
95
|
+
.catch(() => undefined)
|
|
96
|
+
.then(async () => {
|
|
97
|
+
const current = await this.readManifest().catch(() => this.initialManifest())
|
|
98
|
+
const next = update({
|
|
99
|
+
...current,
|
|
100
|
+
updatedAt: this.nowIso(),
|
|
101
|
+
})
|
|
102
|
+
await writeJsonAtomic(this.hostPath('manifest.json'), next)
|
|
103
|
+
return next
|
|
104
|
+
})
|
|
105
|
+
this.manifestWriteQueue = operation.then(
|
|
106
|
+
() => undefined,
|
|
107
|
+
() => undefined,
|
|
108
|
+
)
|
|
109
|
+
return operation
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async writeSourceInventory(sources: readonly SharedRunWorkspaceSource[]): Promise<string> {
|
|
113
|
+
const lines = [
|
|
114
|
+
'# Source Inventory',
|
|
115
|
+
'',
|
|
116
|
+
sources.length
|
|
117
|
+
? 'These are the canonical input references for this run. Prefer this inventory and targeted source reads over rediscovering uploads in every worker.'
|
|
118
|
+
: 'No user-uploaded source files were registered for this run.',
|
|
119
|
+
'',
|
|
120
|
+
...sources.map((source) =>
|
|
121
|
+
[
|
|
122
|
+
`## ${source.label}`,
|
|
123
|
+
'',
|
|
124
|
+
`- id: ${source.id}`,
|
|
125
|
+
`- path: ${source.path}`,
|
|
126
|
+
source.kind ? `- kind: ${source.kind}` : null,
|
|
127
|
+
typeof source.sizeBytes === 'number' ? `- sizeBytes: ${source.sizeBytes}` : null,
|
|
128
|
+
'',
|
|
129
|
+
]
|
|
130
|
+
.filter((line): line is string => line !== null)
|
|
131
|
+
.join('\n'),
|
|
132
|
+
),
|
|
133
|
+
]
|
|
134
|
+
const content = `${lines.join('\n').trimEnd()}\n`
|
|
135
|
+
await writeFile(this.hostPath('sources', 'inventory.md'), content, 'utf8')
|
|
136
|
+
await this.writeManifest((manifest) => ({
|
|
137
|
+
...manifest,
|
|
138
|
+
sources: [...sources],
|
|
139
|
+
}))
|
|
140
|
+
return this.runtimePath('sources', 'inventory.md')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Write the canonical task-context file (`_work/01_task_context.md`).
|
|
145
|
+
* This is the single place the original user request lives in full; child
|
|
146
|
+
* workers read this path instead of receiving the request inline in their
|
|
147
|
+
* prompts.
|
|
148
|
+
*/
|
|
149
|
+
async writeTaskContext(text: string): Promise<string> {
|
|
150
|
+
const relativePath = ['01_task_context.md']
|
|
151
|
+
await mkdir(dirnameFor(this.hostPath(...relativePath)), { recursive: true })
|
|
152
|
+
await writeFile(this.hostPath(...relativePath), ensureTrailingNewline(text), 'utf8')
|
|
153
|
+
return this.runtimePath(...relativePath)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Write the shared coordination packet (`_work/02_shared_context.md`).
|
|
158
|
+
* This is intentionally smaller and more operational than the task context:
|
|
159
|
+
* workers read it first, then open the full task context or source inventory
|
|
160
|
+
* only when their assignment needs raw wording or source-file details.
|
|
161
|
+
*/
|
|
162
|
+
async writeSharedContext(text: string): Promise<string> {
|
|
163
|
+
const relativePath = ['02_shared_context.md']
|
|
164
|
+
await mkdir(dirnameFor(this.hostPath(...relativePath)), { recursive: true })
|
|
165
|
+
await writeFile(this.hostPath(...relativePath), ensureTrailingNewline(text), 'utf8')
|
|
166
|
+
return this.runtimePath(...relativePath)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Write a per-worker brief at `agents/<agentId>/<taskId>/00_brief.md`.
|
|
171
|
+
* Returns the runtime-visible path. Pair with `registerAgentWork` so the
|
|
172
|
+
* agent record and the brief sit under the same scratch directory.
|
|
173
|
+
*/
|
|
174
|
+
async writeAgentBrief(input: {
|
|
175
|
+
agentId: string
|
|
176
|
+
taskId?: string
|
|
177
|
+
briefText: string
|
|
178
|
+
}): Promise<string> {
|
|
179
|
+
const taskPart = input.taskId ?? 'pending'
|
|
180
|
+
const relativePath = ['agents', input.agentId, taskPart, '00_brief.md']
|
|
181
|
+
await mkdir(dirnameFor(this.hostPath(...relativePath)), { recursive: true })
|
|
182
|
+
await writeFile(this.hostPath(...relativePath), ensureTrailingNewline(input.briefText), 'utf8')
|
|
183
|
+
return this.runtimePath(...relativePath)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Append a section to an existing per-worker brief, creating the file if
|
|
188
|
+
* it doesn't yet exist. Use for follow-up turns / continue flows so the
|
|
189
|
+
* brief stays authoritative across resumes — workers re-reading the brief
|
|
190
|
+
* on every entry will see the latest assignment delta, not just the seed
|
|
191
|
+
* text from initial dispatch.
|
|
192
|
+
*/
|
|
193
|
+
async appendAgentBrief(input: {
|
|
194
|
+
agentId: string
|
|
195
|
+
taskId?: string
|
|
196
|
+
sectionText: string
|
|
197
|
+
}): Promise<string> {
|
|
198
|
+
const taskPart = input.taskId ?? 'pending'
|
|
199
|
+
const relativePath = ['agents', input.agentId, taskPart, '00_brief.md']
|
|
200
|
+
await mkdir(dirnameFor(this.hostPath(...relativePath)), { recursive: true })
|
|
201
|
+
const target = this.hostPath(...relativePath)
|
|
202
|
+
const existing = await readFile(target, 'utf8').catch(() => '')
|
|
203
|
+
const trimmedExisting = existing.replace(/\n*$/, '')
|
|
204
|
+
const next = trimmedExisting
|
|
205
|
+
? `${trimmedExisting}\n\n${ensureTrailingNewline(input.sectionText)}`
|
|
206
|
+
: ensureTrailingNewline(input.sectionText)
|
|
207
|
+
await writeFile(target, next, 'utf8')
|
|
208
|
+
return this.runtimePath(...relativePath)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async seedSupervisorBrief(input: RegisterSharedRunPlanInput): Promise<string> {
|
|
212
|
+
const id = input.id ?? 'root'
|
|
213
|
+
const relativePath =
|
|
214
|
+
id === 'root' ? ['00_supervisor_brief.md'] : ['plans', id, 'supervisor_brief.md']
|
|
215
|
+
await mkdir(dirnameFor(this.hostPath(...relativePath)), { recursive: true })
|
|
216
|
+
await writeFile(this.hostPath(...relativePath), ensureTrailingNewline(input.briefText), 'utf8')
|
|
217
|
+
const briefPath = this.runtimePath(...relativePath)
|
|
218
|
+
const now = this.nowIso()
|
|
219
|
+
await this.writeManifest((manifest) => ({
|
|
220
|
+
...manifest,
|
|
221
|
+
plans: upsertBy(manifest.plans, (plan) => plan.id, {
|
|
222
|
+
id,
|
|
223
|
+
briefPath,
|
|
224
|
+
status: input.status ?? 'seeded',
|
|
225
|
+
updatedAt: now,
|
|
226
|
+
}),
|
|
227
|
+
}))
|
|
228
|
+
return briefPath
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async registerAgentWork(input: {
|
|
232
|
+
agentId: string
|
|
233
|
+
taskId?: string
|
|
234
|
+
status?: SharedRunWorkspaceAgentRecord['status']
|
|
235
|
+
}): Promise<string> {
|
|
236
|
+
const taskPart = input.taskId ?? 'pending'
|
|
237
|
+
const relativePath = ['agents', input.agentId, taskPart]
|
|
238
|
+
await mkdir(this.hostPath(...relativePath), { recursive: true })
|
|
239
|
+
const workPath = this.runtimePath(...relativePath)
|
|
240
|
+
const now = this.nowIso()
|
|
241
|
+
await this.writeManifest((manifest) => ({
|
|
242
|
+
...manifest,
|
|
243
|
+
agents: upsertBy(manifest.agents, (record) => `${record.agentId}:${record.taskId ?? ''}`, {
|
|
244
|
+
agentId: input.agentId,
|
|
245
|
+
...(input.taskId ? { taskId: input.taskId } : {}),
|
|
246
|
+
workPath,
|
|
247
|
+
status: input.status ?? 'assigned',
|
|
248
|
+
updatedAt: now,
|
|
249
|
+
}),
|
|
250
|
+
}))
|
|
251
|
+
return workPath
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private initialManifest(): SharedRunWorkspaceManifest {
|
|
255
|
+
const now = this.config.now.toISOString()
|
|
256
|
+
return {
|
|
257
|
+
schemaVersion: 1,
|
|
258
|
+
kind: 'shared-run-workspace',
|
|
259
|
+
createdAt: now,
|
|
260
|
+
updatedAt: now,
|
|
261
|
+
...(this.config.label ? { label: this.config.label } : {}),
|
|
262
|
+
paths: {
|
|
263
|
+
root: this.runtimePath(),
|
|
264
|
+
manifest: this.runtimePath('manifest.json'),
|
|
265
|
+
sharedContext: this.runtimePath('02_shared_context.md'),
|
|
266
|
+
sources: this.runtimePath('sources'),
|
|
267
|
+
plans: this.runtimePath('plans'),
|
|
268
|
+
agents: this.runtimePath('agents'),
|
|
269
|
+
},
|
|
270
|
+
sources: [],
|
|
271
|
+
plans: [],
|
|
272
|
+
agents: [],
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private nowIso(): string {
|
|
277
|
+
return new Date().toISOString()
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function safeJoin(root: string, segments: readonly string[]): string {
|
|
282
|
+
const fullPath = normalize(join(root, ...segments))
|
|
283
|
+
const rel = relative(root, fullPath)
|
|
284
|
+
if (rel === '' || (!rel.startsWith('..') && !rel.includes(`..${sep}`))) return fullPath
|
|
285
|
+
throw new Error(`SharedRunWorkspace path escapes root: ${segments.join('/')}`)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function trimTrailingSlash(value: string): string {
|
|
289
|
+
if (value === '/') return value
|
|
290
|
+
return value.replace(/\/+$/, '')
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function ensureTrailingNewline(value: string): string {
|
|
294
|
+
return value.endsWith('\n') ? value : `${value}\n`
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function writeJsonAtomic(path: string, value: unknown): Promise<void> {
|
|
298
|
+
await mkdir(dirnameFor(path), { recursive: true })
|
|
299
|
+
const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`
|
|
300
|
+
await writeFile(tmpPath, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
|
|
301
|
+
await rename(tmpPath, path)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function dirnameFor(path: string): string {
|
|
305
|
+
return dirname(path)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function upsertBy<T>(items: readonly T[], key: (item: T) => string, next: T): T[] {
|
|
309
|
+
const nextKey = key(next)
|
|
310
|
+
let replaced = false
|
|
311
|
+
const updated = items.map((item) => {
|
|
312
|
+
if (key(item) !== nextKey) return item
|
|
313
|
+
replaced = true
|
|
314
|
+
return next
|
|
315
|
+
})
|
|
316
|
+
return replaced ? updated : [...updated, next]
|
|
317
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import { discoverSkills, loadSkill } from './loader.js'
|
|
6
|
+
|
|
7
|
+
async function writeSkill(parent: string, name: string, content: string): Promise<string> {
|
|
8
|
+
const dir = join(parent, name)
|
|
9
|
+
await mkdir(dir, { recursive: true })
|
|
10
|
+
await writeFile(join(dir, 'SKILL.md'), content, 'utf8')
|
|
11
|
+
return dir
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('Agent Skills loader', () => {
|
|
15
|
+
it('parses standard Agent Skills frontmatter fields', async () => {
|
|
16
|
+
const root = await mkdtemp(join(tmpdir(), 'namzu-skills-'))
|
|
17
|
+
const dir = await writeSkill(
|
|
18
|
+
root,
|
|
19
|
+
'delivery-briefing',
|
|
20
|
+
[
|
|
21
|
+
'---',
|
|
22
|
+
'name: delivery-briefing',
|
|
23
|
+
'description: Draft and edit grounded delivery briefings.',
|
|
24
|
+
'license: MIT',
|
|
25
|
+
'compatibility: Requires filesystem tools',
|
|
26
|
+
'allowed-tools: read write edit',
|
|
27
|
+
'metadata:',
|
|
28
|
+
' owner: vandal',
|
|
29
|
+
' version: "1.0"',
|
|
30
|
+
'---',
|
|
31
|
+
'Use grounded sources before drafting.',
|
|
32
|
+
'',
|
|
33
|
+
].join('\n'),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const result = await loadSkill(dir, 'metadata')
|
|
37
|
+
|
|
38
|
+
expect(result.skill.metadata).toEqual({
|
|
39
|
+
name: 'delivery-briefing',
|
|
40
|
+
description: 'Draft and edit grounded delivery briefings.',
|
|
41
|
+
license: 'MIT',
|
|
42
|
+
compatibility: 'Requires filesystem tools',
|
|
43
|
+
allowedTools: 'read write edit',
|
|
44
|
+
metadata: {
|
|
45
|
+
owner: 'vandal',
|
|
46
|
+
version: '1.0',
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
expect(result.skill.body).toBeUndefined()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('loads the body only when the requested disclosure level is full', async () => {
|
|
53
|
+
const root = await mkdtemp(join(tmpdir(), 'namzu-skills-'))
|
|
54
|
+
const dir = await writeSkill(
|
|
55
|
+
root,
|
|
56
|
+
'structured-file-authoring',
|
|
57
|
+
[
|
|
58
|
+
'---',
|
|
59
|
+
'name: structured-file-authoring',
|
|
60
|
+
'description: Create structured files with bounded edit chunks.',
|
|
61
|
+
'---',
|
|
62
|
+
'Use skeleton-first writes.',
|
|
63
|
+
'',
|
|
64
|
+
].join('\n'),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const metadataOnly = await loadSkill(dir, 'metadata')
|
|
68
|
+
const full = await loadSkill(dir, 'full')
|
|
69
|
+
|
|
70
|
+
expect(metadataOnly.skill.body).toBeUndefined()
|
|
71
|
+
expect(full.skill.body).toBe('Use skeleton-first writes.')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('discovers one-level skill directories deterministically', async () => {
|
|
75
|
+
const root = await mkdtemp(join(tmpdir(), 'namzu-skills-'))
|
|
76
|
+
const a = await writeSkill(
|
|
77
|
+
root,
|
|
78
|
+
'a-skill',
|
|
79
|
+
['---', 'name: a-skill', 'description: A skill.', '---', 'A'].join('\n'),
|
|
80
|
+
)
|
|
81
|
+
const b = await writeSkill(
|
|
82
|
+
root,
|
|
83
|
+
'b-skill',
|
|
84
|
+
['---', 'name: b-skill', 'description: B skill.', '---', 'B'].join('\n'),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
expect(await discoverSkills(root)).toEqual([a, b])
|
|
88
|
+
})
|
|
89
|
+
})
|
package/src/skills/loader.ts
CHANGED
|
@@ -41,14 +41,29 @@ function parseSkillMd(raw: string, dirPath: string): ParsedSkillMd {
|
|
|
41
41
|
function parseFlatYaml(raw: string, dirPath: string): SkillMetadata {
|
|
42
42
|
const lines = raw.split('\n')
|
|
43
43
|
const kv: Record<string, string> = {}
|
|
44
|
+
const metadata: Record<string, string> = {}
|
|
45
|
+
let section: 'metadata' | undefined
|
|
44
46
|
|
|
45
47
|
for (const line of lines) {
|
|
48
|
+
if (!line.trim() || line.trimStart().startsWith('#')) continue
|
|
49
|
+
|
|
50
|
+
if (/^\s/.test(line)) {
|
|
51
|
+
if (section !== 'metadata') continue
|
|
52
|
+
const colonIdx = line.indexOf(':')
|
|
53
|
+
if (colonIdx === -1) continue
|
|
54
|
+
const key = line.slice(0, colonIdx).trim()
|
|
55
|
+
const value = normalizeYamlScalar(line.slice(colonIdx + 1).trim())
|
|
56
|
+
if (key && value) metadata[key] = value
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
46
60
|
const colonIdx = line.indexOf(':')
|
|
47
61
|
if (colonIdx === -1) continue
|
|
48
62
|
const key = line.slice(0, colonIdx).trim()
|
|
49
|
-
const value = line.slice(colonIdx + 1).trim()
|
|
63
|
+
const value = normalizeYamlScalar(line.slice(colonIdx + 1).trim())
|
|
50
64
|
|
|
51
|
-
|
|
65
|
+
section = key === 'metadata' ? 'metadata' : undefined
|
|
66
|
+
if (value) kv[key] = value
|
|
52
67
|
}
|
|
53
68
|
|
|
54
69
|
if (!kv.name) {
|
|
@@ -61,19 +76,35 @@ function parseFlatYaml(raw: string, dirPath: string): SkillMetadata {
|
|
|
61
76
|
validateSkillName(kv.name, dirPath)
|
|
62
77
|
validateDescription(kv.description, dirPath)
|
|
63
78
|
|
|
64
|
-
const
|
|
79
|
+
const skillMetadata: SkillMetadata = {
|
|
65
80
|
name: kv.name,
|
|
66
81
|
description: kv.description,
|
|
67
82
|
}
|
|
68
83
|
|
|
84
|
+
if (kv.license) {
|
|
85
|
+
skillMetadata.license = kv.license
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
if (kv.compatibility) {
|
|
70
89
|
if (kv.compatibility.length > 500) {
|
|
71
90
|
throw new Error(`SKILL.md at "${dirPath}": compatibility exceeds 500 characters`)
|
|
72
91
|
}
|
|
73
|
-
|
|
92
|
+
skillMetadata.compatibility = kv.compatibility
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (kv['allowed-tools']) {
|
|
96
|
+
skillMetadata.allowedTools = kv['allowed-tools']
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (Object.keys(metadata).length > 0) {
|
|
100
|
+
skillMetadata.metadata = metadata
|
|
74
101
|
}
|
|
75
102
|
|
|
76
|
-
return
|
|
103
|
+
return skillMetadata
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function normalizeYamlScalar(value: string): string {
|
|
107
|
+
return value.replace(/^["']|["']$/g, '').trim()
|
|
77
108
|
}
|
|
78
109
|
|
|
79
110
|
const SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
|
|
@@ -164,5 +195,5 @@ export async function discoverSkills(parentDir: string): Promise<string[]> {
|
|
|
164
195
|
logger.debug('Skills directory not found', { parentDir })
|
|
165
196
|
}
|
|
166
197
|
|
|
167
|
-
return dirs
|
|
198
|
+
return dirs.sort()
|
|
168
199
|
}
|
|
@@ -98,7 +98,7 @@ describe('coalesce()', () => {
|
|
|
98
98
|
iteration: 0,
|
|
99
99
|
messageId: MID,
|
|
100
100
|
toolUseId: TUID,
|
|
101
|
-
toolName: '
|
|
101
|
+
toolName: 'read',
|
|
102
102
|
},
|
|
103
103
|
{ type: 'text_delta', runId: RID, iteration: 0, messageId: MID, text: 'c' },
|
|
104
104
|
]
|
|
@@ -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)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import type { ToolContext } from '../../../types/tool/index.js'
|
|
6
|
+
import { EditTool } from '../edit.js'
|
|
7
|
+
|
|
8
|
+
function makeContext(workingDirectory: string): ToolContext {
|
|
9
|
+
return {
|
|
10
|
+
runId: 'run_test' as ToolContext['runId'],
|
|
11
|
+
workingDirectory,
|
|
12
|
+
abortSignal: new AbortController().signal,
|
|
13
|
+
env: {},
|
|
14
|
+
log: () => {},
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('EditTool', () => {
|
|
19
|
+
it('accepts oldStr/newStr aliases for string replacement', async () => {
|
|
20
|
+
const dir = mkdtempSync(join(tmpdir(), 'namzu-edit-'))
|
|
21
|
+
writeFileSync(join(dir, 'doc.md'), 'alpha\nbeta\n')
|
|
22
|
+
|
|
23
|
+
const result = await EditTool.execute(
|
|
24
|
+
{ path: 'doc.md', oldStr: 'beta', newStr: 'gamma', replace_all: false },
|
|
25
|
+
makeContext(dir),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
expect(result.success).toBe(true)
|
|
29
|
+
expect(readFileSync(join(dir, 'doc.md'), 'utf-8')).toBe('alpha\ngamma\n')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('inserts content after a 1-indexed line number', async () => {
|
|
33
|
+
const dir = mkdtempSync(join(tmpdir(), 'namzu-edit-'))
|
|
34
|
+
writeFileSync(join(dir, 'doc.md'), 'alpha\nbeta\n')
|
|
35
|
+
|
|
36
|
+
const result = await EditTool.execute(
|
|
37
|
+
{ path: 'doc.md', insertLine: 1, newStr: 'inserted', replace_all: false },
|
|
38
|
+
makeContext(dir),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
expect(result.success).toBe(true)
|
|
42
|
+
expect(readFileSync(join(dir, 'doc.md'), 'utf-8')).toBe('alpha\ninserted\nbeta\n')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('inserts content at the end with insertLine=end', async () => {
|
|
46
|
+
const dir = mkdtempSync(join(tmpdir(), 'namzu-edit-'))
|
|
47
|
+
writeFileSync(join(dir, 'doc.md'), 'alpha\n')
|
|
48
|
+
|
|
49
|
+
const result = await EditTool.execute(
|
|
50
|
+
{ path: 'doc.md', insertLine: 'end', newStr: 'omega', replace_all: false },
|
|
51
|
+
makeContext(dir),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
expect(result.success).toBe(true)
|
|
55
|
+
expect(readFileSync(join(dir, 'doc.md'), 'utf-8')).toBe('alpha\nomega\n')
|
|
56
|
+
})
|
|
57
|
+
})
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import type { ToolContext } from '../../../types/tool/index.js'
|
|
6
|
+
import { EditTool } from '../edit.js'
|
|
7
|
+
import { getBuiltinTools } from '../index.js'
|
|
8
|
+
import { WriteFileTool } from '../write-file.js'
|
|
9
|
+
|
|
10
|
+
describe('filesystem tool payload budgeting', () => {
|
|
11
|
+
it('does not hard-fail oversized write/edit payloads at schema validation', () => {
|
|
12
|
+
const oversized = 'x'.repeat(12_500)
|
|
13
|
+
|
|
14
|
+
expect(() =>
|
|
15
|
+
WriteFileTool.inputSchema.parse({ path: 'outputs/long.md', content: oversized }),
|
|
16
|
+
).not.toThrow()
|
|
17
|
+
expect(() =>
|
|
18
|
+
EditTool.inputSchema.parse({
|
|
19
|
+
path: 'outputs/long.md',
|
|
20
|
+
oldStr: '{{SECTION}}',
|
|
21
|
+
newStr: oversized,
|
|
22
|
+
replace_all: false,
|
|
23
|
+
}),
|
|
24
|
+
).not.toThrow()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('keeps append out of the default builtin toolset', () => {
|
|
28
|
+
const names = getBuiltinTools().map((tool) => tool.name)
|
|
29
|
+
|
|
30
|
+
expect(names).toContain('edit')
|
|
31
|
+
expect(names).not.toContain('append')
|
|
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
|
+
})
|
|
92
|
+
})
|