@namzu/sdk 35.0.0 → 37.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +218 -0
- package/README.md +68 -41
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +2 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +2 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/compaction/extractor.d.ts +1 -1
- package/dist/compaction/extractor.d.ts.map +1 -1
- package/dist/compaction/extractor.js +15 -7
- package/dist/compaction/extractor.js.map +1 -1
- package/dist/compaction/manager.d.ts +2 -0
- package/dist/compaction/manager.d.ts.map +1 -1
- package/dist/compaction/manager.js +12 -1
- package/dist/compaction/manager.js.map +1 -1
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +82 -15
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/contracts/schemas.d.ts +10 -10
- package/dist/eval/harness-verification.d.ts +63 -0
- package/dist/eval/harness-verification.d.ts.map +1 -0
- package/dist/eval/harness-verification.js +165 -0
- package/dist/eval/harness-verification.js.map +1 -0
- package/dist/eval/index.d.ts +2 -0
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/index.js +1 -0
- package/dist/eval/index.js.map +1 -1
- package/dist/execution/code-runtime/json-value.d.ts +10 -0
- package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
- package/dist/execution/code-runtime/json-value.js +89 -0
- package/dist/execution/code-runtime/json-value.js.map +1 -0
- package/dist/execution/code-runtime/worker-program.d.ts +8 -0
- package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
- package/dist/execution/code-runtime/worker-program.js +240 -0
- package/dist/execution/code-runtime/worker-program.js.map +1 -0
- package/dist/execution/code-runtime/worker.d.ts +22 -0
- package/dist/execution/code-runtime/worker.d.ts.map +1 -1
- package/dist/execution/code-runtime/worker.js +148 -111
- package/dist/execution/code-runtime/worker.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +12 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +306 -37
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +2 -0
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +6 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/provider/capabilities.d.ts +3 -1
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +13 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +2 -0
- package/dist/provider/fallback.js.map +1 -1
- package/dist/provider/token-budget.d.ts.map +1 -1
- package/dist/provider/token-budget.js +56 -8
- package/dist/provider/token-budget.js.map +1 -1
- package/dist/public-runtime.d.ts +5 -3
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +3 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +1 -1
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +1 -1
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +1 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/execute.d.ts +3 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +11 -80
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/run/command-gate.d.ts.map +1 -1
- package/dist/run/command-gate.js +65 -12
- package/dist/run/command-gate.js.map +1 -1
- package/dist/run/index.d.ts +2 -0
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +1 -0
- package/dist/run/index.js.map +1 -1
- package/dist/run/memory-promoter.d.ts +3 -35
- package/dist/run/memory-promoter.d.ts.map +1 -1
- package/dist/run/memory-promoter.js +32 -40
- package/dist/run/memory-promoter.js.map +1 -1
- package/dist/run/memory-recall.d.ts +25 -0
- package/dist/run/memory-recall.d.ts.map +1 -0
- package/dist/run/memory-recall.js +228 -0
- package/dist/run/memory-recall.js.map +1 -0
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +1 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/run/token-budget.d.ts +2 -0
- package/dist/run/token-budget.d.ts.map +1 -1
- package/dist/run/token-budget.js +4 -0
- package/dist/run/token-budget.js.map +1 -1
- package/dist/run/workspace-fingerprint.d.ts +10 -3
- package/dist/run/workspace-fingerprint.d.ts.map +1 -1
- package/dist/run/workspace-fingerprint.js +17 -8
- package/dist/run/workspace-fingerprint.js.map +1 -1
- package/dist/runtime/query/checkpoint.d.ts +14 -0
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +82 -1
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +6 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +120 -24
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +12 -8
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +55 -7
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +13 -3
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +356 -42
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/native-output.d.ts +10 -0
- package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
- package/dist/runtime/query/iteration/native-output.js +32 -0
- package/dist/runtime/query/iteration/native-output.js.map +1 -0
- package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js +18 -13
- package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +32 -11
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +11 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
- package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +12 -5
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +14 -4
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +6 -2
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js +17 -2
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tool-call-budget.d.ts +19 -0
- package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
- package/dist/runtime/query/tool-call-budget.js +110 -0
- package/dist/runtime/query/tool-call-budget.js.map +1 -0
- package/dist/runtime/query/tooling.d.ts +2 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +4 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/file-walk-program.d.ts +3 -0
- package/dist/sandbox/file-walk-program.d.ts.map +1 -0
- package/dist/sandbox/file-walk-program.js +94 -0
- package/dist/sandbox/file-walk-program.js.map +1 -0
- package/dist/sandbox/file-walk.d.ts +12 -0
- package/dist/sandbox/file-walk.d.ts.map +1 -0
- package/dist/sandbox/file-walk.js +429 -0
- package/dist/sandbox/file-walk.js.map +1 -0
- package/dist/sandbox/index.d.ts +2 -0
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +1 -0
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +9 -0
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts +3 -2
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +29 -15
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +1 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/handoff/capacity.d.ts +2 -2
- package/dist/session/handoff/capacity.d.ts.map +1 -1
- package/dist/session/handoff/capacity.js +3 -2
- package/dist/session/handoff/capacity.js.map +1 -1
- package/dist/store/memory/disk.d.ts +6 -2
- package/dist/store/memory/disk.d.ts.map +1 -1
- package/dist/store/memory/disk.js +42 -25
- package/dist/store/memory/disk.js.map +1 -1
- package/dist/store/memory/index.d.ts +4 -0
- package/dist/store/memory/index.d.ts.map +1 -1
- package/dist/store/memory/index.js +55 -19
- package/dist/store/memory/index.js.map +1 -1
- package/dist/store/memory/memory.d.ts +3 -2
- package/dist/store/memory/memory.d.ts.map +1 -1
- package/dist/store/memory/memory.js +11 -2
- package/dist/store/memory/memory.js.map +1 -1
- package/dist/store/memory/operation-lock.d.ts +11 -0
- package/dist/store/memory/operation-lock.d.ts.map +1 -0
- package/dist/store/memory/operation-lock.js +94 -0
- package/dist/store/memory/operation-lock.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +215 -59
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +60 -10
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/glob.d.ts +2 -1
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +95 -103
- package/dist/tools/builtins/glob.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +155 -111
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/ls.js +2 -2
- package/dist/tools/builtins/ls.js.map +1 -1
- package/dist/tools/builtins/run-code.d.ts +6 -0
- package/dist/tools/builtins/run-code.d.ts.map +1 -1
- package/dist/tools/builtins/run-code.js +15 -4
- package/dist/tools/builtins/run-code.js.map +1 -1
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +14 -2
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/defineTool.d.ts +2 -0
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +3 -0
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/memory/delete.d.ts +4 -0
- package/dist/tools/memory/delete.d.ts.map +1 -0
- package/dist/tools/memory/delete.js +26 -0
- package/dist/tools/memory/delete.js.map +1 -0
- package/dist/tools/memory/index.d.ts +2 -0
- package/dist/tools/memory/index.d.ts.map +1 -1
- package/dist/tools/memory/index.js +6 -0
- package/dist/tools/memory/index.js.map +1 -1
- package/dist/tools/memory/save.d.ts.map +1 -1
- package/dist/tools/memory/save.js +3 -2
- package/dist/tools/memory/save.js.map +1 -1
- package/dist/tools/memory/search.d.ts.map +1 -1
- package/dist/tools/memory/search.js +12 -5
- package/dist/tools/memory/search.js.map +1 -1
- package/dist/tools/memory/update.d.ts +4 -0
- package/dist/tools/memory/update.d.ts.map +1 -0
- package/dist/tools/memory/update.js +47 -0
- package/dist/tools/memory/update.js.map +1 -0
- package/dist/types/agent/scheduler.d.ts +5 -0
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +10 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/computer-use/index.d.ts +6 -0
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/dist/types/computer-use/index.js.map +1 -1
- package/dist/types/errors/catalog.js +1 -1
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/hitl/index.d.ts +11 -1
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/memory/index.d.ts +14 -1
- package/dist/types/memory/index.d.ts.map +1 -1
- package/dist/types/project/entity.d.ts +1 -0
- package/dist/types/project/entity.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +2 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/model.d.ts +4 -0
- package/dist/types/provider/model.d.ts.map +1 -1
- package/dist/types/run/answer-review.d.ts +2 -0
- package/dist/types/run/answer-review.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +9 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/run/prepare-step.d.ts +19 -1
- package/dist/types/run/prepare-step.d.ts.map +1 -1
- package/dist/types/sandbox/index.d.ts +20 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/structured-output/index.d.ts +8 -2
- package/dist/types/structured-output/index.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +15 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/utils/json-snapshot.d.ts +3 -0
- package/dist/utils/json-snapshot.d.ts.map +1 -0
- package/dist/utils/json-snapshot.js +79 -0
- package/dist/utils/json-snapshot.js.map +1 -0
- package/package.json +8 -1
- package/src/bridge/a2a/mapper.ts +2 -0
- package/src/bridge/sse/mapper.ts +2 -0
- package/src/compaction/extractor.ts +21 -8
- package/src/compaction/manager.ts +11 -1
- package/src/compaction/verifier.ts +80 -18
- package/src/eval/harness-verification.ts +270 -0
- package/src/eval/index.ts +10 -0
- package/src/execution/code-runtime/json-value.ts +82 -0
- package/src/execution/code-runtime/worker-program.ts +239 -0
- package/src/execution/code-runtime/worker.ts +164 -111
- package/src/manager/agent/lifecycle.ts +340 -45
- package/src/manager/run/persistence.ts +7 -0
- package/src/provider/capabilities.ts +25 -1
- package/src/provider/fallback.ts +2 -0
- package/src/provider/token-budget.ts +52 -8
- package/src/public-runtime.ts +6 -1
- package/src/public-tools.ts +5 -1
- package/src/public-types.ts +1 -0
- package/src/registry/tool/execute.ts +17 -79
- package/src/run/command-gate.ts +61 -13
- package/src/run/index.ts +2 -0
- package/src/run/memory-promoter.ts +32 -40
- package/src/run/memory-recall.ts +254 -0
- package/src/run/reporter.ts +1 -0
- package/src/run/token-budget.ts +4 -0
- package/src/run/workspace-fingerprint.ts +17 -8
- package/src/runtime/query/checkpoint.ts +96 -2
- package/src/runtime/query/executor.ts +131 -28
- package/src/runtime/query/index.ts +81 -16
- package/src/runtime/query/iteration/index.ts +406 -53
- package/src/runtime/query/iteration/native-output.ts +35 -0
- package/src/runtime/query/iteration/phases/advisory.ts +21 -11
- package/src/runtime/query/iteration/phases/compaction.ts +36 -14
- package/src/runtime/query/iteration/phases/context.ts +11 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
- package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
- package/src/runtime/query/iteration/stream-turn.ts +11 -5
- package/src/runtime/query/prompt.ts +21 -4
- package/src/runtime/query/steering.ts +19 -2
- package/src/runtime/query/tool-call-budget.ts +115 -0
- package/src/runtime/query/tooling.ts +6 -0
- package/src/sandbox/file-walk-program.ts +93 -0
- package/src/sandbox/file-walk.ts +463 -0
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/provider/local.ts +13 -0
- package/src/scheduler/completion-inbox.ts +29 -19
- package/src/scheduler/local.ts +1 -0
- package/src/session/handoff/capacity.ts +7 -3
- package/src/store/memory/disk.ts +52 -30
- package/src/store/memory/index.ts +75 -27
- package/src/store/memory/memory.ts +18 -6
- package/src/store/memory/operation-lock.ts +99 -0
- package/src/tools/builtins/bash.ts +230 -58
- package/src/tools/builtins/computer-use.ts +61 -7
- package/src/tools/builtins/glob.ts +104 -122
- package/src/tools/builtins/grep.ts +166 -132
- package/src/tools/builtins/ls.ts +2 -2
- package/src/tools/builtins/run-code.ts +24 -5
- package/src/tools/builtins/search-tools.ts +18 -3
- package/src/tools/defineTool.ts +5 -0
- package/src/tools/memory/delete.ts +29 -0
- package/src/tools/memory/index.ts +6 -0
- package/src/tools/memory/save.ts +4 -2
- package/src/tools/memory/search.ts +12 -5
- package/src/tools/memory/update.ts +50 -0
- package/src/types/agent/scheduler.ts +6 -0
- package/src/types/agent/task.ts +13 -0
- package/src/types/computer-use/index.ts +6 -0
- package/src/types/errors/catalog.ts +1 -1
- package/src/types/hitl/index.ts +11 -1
- package/src/types/memory/index.ts +16 -1
- package/src/types/project/entity.ts +1 -0
- package/src/types/provider/config.ts +2 -0
- package/src/types/provider/model.ts +4 -0
- package/src/types/run/answer-review.ts +2 -0
- package/src/types/run/events.ts +10 -0
- package/src/types/run/prepare-step.ts +19 -1
- package/src/types/sandbox/index.ts +21 -0
- package/src/types/structured-output/index.ts +15 -2
- package/src/types/tool/index.ts +16 -0
- package/src/utils/json-snapshot.ts +76 -0
|
@@ -49,8 +49,44 @@ export function withTokenBudget(provider: LLMProvider, budget: TokenBudget): LLM
|
|
|
49
49
|
let completed = false
|
|
50
50
|
let outputObserved = false
|
|
51
51
|
let uncertainRetry = false
|
|
52
|
+
let contacted = false
|
|
53
|
+
let abandoned = false
|
|
54
|
+
let iterator: AsyncIterator<StreamChunk> | undefined
|
|
55
|
+
let onAbort: (() => void) | undefined
|
|
56
|
+
const signal = params.signal
|
|
57
|
+
const cancellation = signal
|
|
58
|
+
? new Promise<never>((_resolve, reject) => {
|
|
59
|
+
onAbort = () => {
|
|
60
|
+
abandoned = true
|
|
61
|
+
reject(signal.reason)
|
|
62
|
+
}
|
|
63
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
64
|
+
})
|
|
65
|
+
: undefined
|
|
66
|
+
// Admission persistence can have outlived the caller's authority. The
|
|
67
|
+
// check below may reject before the first pull attaches a race handler.
|
|
68
|
+
cancellation?.catch(() => {})
|
|
52
69
|
try {
|
|
53
|
-
|
|
70
|
+
signal?.throwIfAborted()
|
|
71
|
+
contacted = true
|
|
72
|
+
iterator = provider.chatStream(params)[Symbol.asyncIterator]()
|
|
73
|
+
for (;;) {
|
|
74
|
+
signal?.throwIfAborted()
|
|
75
|
+
const next = iterator.next()
|
|
76
|
+
// Observe an already-issued pull even after cancellation wins the
|
|
77
|
+
// race. A late usage frame is evidence of spend, not permission to
|
|
78
|
+
// reopen the account or to request another frame.
|
|
79
|
+
void next
|
|
80
|
+
.then(async (result) => {
|
|
81
|
+
if (!result.done && result.value.usage) {
|
|
82
|
+
usage = usage ? mergeTokenUsage(usage, result.value.usage) : { ...result.value.usage }
|
|
83
|
+
if (abandoned) await budget.failRequest(requestId, usage)
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
.catch(() => {})
|
|
87
|
+
const result = await (cancellation ? Promise.race([next, cancellation]) : next)
|
|
88
|
+
if (result.done) break
|
|
89
|
+
const chunk = result.value
|
|
54
90
|
const recovery = chunk.retry ?? chunk.fallback
|
|
55
91
|
if (
|
|
56
92
|
recovery &&
|
|
@@ -71,9 +107,6 @@ export function withTokenBudget(provider: LLMProvider, budget: TokenBudget): LLM
|
|
|
71
107
|
})
|
|
72
108
|
}
|
|
73
109
|
if (Object.keys(chunk.delta).length > 0) outputObserved = true
|
|
74
|
-
if (chunk.usage) {
|
|
75
|
-
usage = usage ? mergeTokenUsage(usage, chunk.usage) : { ...chunk.usage }
|
|
76
|
-
}
|
|
77
110
|
if (chunk.error) throw new Error(chunk.error)
|
|
78
111
|
yield chunk
|
|
79
112
|
}
|
|
@@ -88,16 +121,27 @@ export function withTokenBudget(provider: LLMProvider, budget: TokenBudget): LLM
|
|
|
88
121
|
// A typed rejection before any generation differs from a lost reply.
|
|
89
122
|
// In particular a context-overflow retry must not reset or poison spend.
|
|
90
123
|
if (
|
|
91
|
-
!
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
!contacted ||
|
|
125
|
+
(!abandoned &&
|
|
126
|
+
!outputObserved &&
|
|
127
|
+
usage === undefined &&
|
|
128
|
+
!uncertainRetry &&
|
|
129
|
+
rejectedBeforeGeneration(error))
|
|
95
130
|
) {
|
|
96
131
|
await budget.finishRequest(requestId, { ...EMPTY_TOKEN_USAGE })
|
|
97
132
|
completed = true
|
|
98
133
|
}
|
|
99
134
|
throw error
|
|
100
135
|
} finally {
|
|
136
|
+
abandoned = !completed
|
|
137
|
+
if (onAbort) signal?.removeEventListener('abort', onAbort)
|
|
138
|
+
// A blocked async generator queues return() behind its pending next().
|
|
139
|
+
// Waiting for it would also delay the durable unknown-spend marker.
|
|
140
|
+
try {
|
|
141
|
+
void iterator?.return?.().catch(() => {})
|
|
142
|
+
} catch {
|
|
143
|
+
// Cleanup cannot replace the provider outcome.
|
|
144
|
+
}
|
|
101
145
|
if (!completed) await budget.failRequest(requestId, usage)
|
|
102
146
|
}
|
|
103
147
|
}
|
package/src/public-runtime.ts
CHANGED
|
@@ -380,6 +380,8 @@ export type {
|
|
|
380
380
|
// nothing.
|
|
381
381
|
export { RUN_MEMORY_TAG, createMemoryPromoter } from './run/index.js'
|
|
382
382
|
export type { MemoryPromoterOptions } from './run/index.js'
|
|
383
|
+
export { createMemoryRecallStep } from './run/memory-recall.js'
|
|
384
|
+
export type { MemoryRecallOptions } from './run/memory-recall.js'
|
|
383
385
|
|
|
384
386
|
// ─── personas, skills, advisory ──────────────────────────────────────────
|
|
385
387
|
|
|
@@ -649,8 +651,9 @@ export {
|
|
|
649
651
|
LocalSandboxProvider,
|
|
650
652
|
missingIsolation,
|
|
651
653
|
SandboxProviderFactory,
|
|
654
|
+
walkFilesViaExec,
|
|
652
655
|
} from './sandbox/index.js'
|
|
653
|
-
export type { LocalSandboxProviderOptions } from './sandbox/index.js'
|
|
656
|
+
export type { LocalSandboxProviderOptions, SandboxFileWalkExec } from './sandbox/index.js'
|
|
654
657
|
|
|
655
658
|
// The classified provider-failure surface: a driver states what went wrong
|
|
656
659
|
// first-hand, and the run boundary reads it to choose between a pause and a
|
|
@@ -1110,6 +1113,8 @@ export { anyOf, hasToolCall, stepCountIs } from './types/run/step.js'
|
|
|
1110
1113
|
// ─── evaluation harness ──────────────────────────────────────────────────
|
|
1111
1114
|
|
|
1112
1115
|
export {
|
|
1116
|
+
compareHarnessTrials,
|
|
1117
|
+
reviewHarnessCandidate,
|
|
1113
1118
|
completionScorer,
|
|
1114
1119
|
containsScorer,
|
|
1115
1120
|
customScorer,
|
package/src/public-tools.ts
CHANGED
|
@@ -97,7 +97,11 @@ export {
|
|
|
97
97
|
buildTaskUpdateTool,
|
|
98
98
|
} from './tools/task/index.js'
|
|
99
99
|
export { buildAdvisoryTools } from './tools/advisory/index.js'
|
|
100
|
-
export {
|
|
100
|
+
export {
|
|
101
|
+
buildMemoryTools,
|
|
102
|
+
buildUpdateMemoryTool,
|
|
103
|
+
buildDeleteMemoryTool,
|
|
104
|
+
} from './tools/memory/index.js'
|
|
101
105
|
export { buildCoordinatorTools } from './tools/coordinator/index.js'
|
|
102
106
|
export {
|
|
103
107
|
buildAskUserQuestionTool,
|
package/src/public-types.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type * from './types/common/index.js'
|
|
|
19
19
|
export type { CoalesceOptions } from './streaming/coalesce.js'
|
|
20
20
|
export type * from './types/bidi/index.js'
|
|
21
21
|
export type * from './types/tool/index.js'
|
|
22
|
+
export type { WorkerCodeRuntimeOptions } from './execution/code-runtime/worker.js'
|
|
22
23
|
export type {
|
|
23
24
|
CodeRunOutcome,
|
|
24
25
|
CodeRunResult,
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
ToolTierConfig,
|
|
19
19
|
} from '../../types/tool/index.js'
|
|
20
20
|
import { toErrorMessage } from '../../utils/error.js'
|
|
21
|
+
import { cloneJsonValue as clonePreparedInput } from '../../utils/json-snapshot.js'
|
|
21
22
|
import { ManagedRegistry } from '../ManagedRegistry.js'
|
|
22
23
|
import { renderToolSchema } from './schema.js'
|
|
23
24
|
import { ToolResultHalted, screenToolResult } from './screen.js'
|
|
@@ -90,82 +91,6 @@ export function assertToolName(name: string): void {
|
|
|
90
91
|
)
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
function clonePreparedInput(value: unknown, freeze: boolean, path = '$'): unknown {
|
|
94
|
-
const active = new WeakSet<object>()
|
|
95
|
-
const copies = new WeakMap<object, object>()
|
|
96
|
-
|
|
97
|
-
const clone = (candidate: unknown, at: string): unknown => {
|
|
98
|
-
if (candidate === null || typeof candidate === 'string' || typeof candidate === 'boolean') {
|
|
99
|
-
return candidate
|
|
100
|
-
}
|
|
101
|
-
if (typeof candidate === 'number') {
|
|
102
|
-
if (!Number.isFinite(candidate) || Object.is(candidate, -0)) {
|
|
103
|
-
throw new TypeError(`${at} must be a finite JSON number`)
|
|
104
|
-
}
|
|
105
|
-
return candidate
|
|
106
|
-
}
|
|
107
|
-
if (typeof candidate !== 'object') {
|
|
108
|
-
throw new TypeError(`${at} must be a JSON value, not ${typeof candidate}`)
|
|
109
|
-
}
|
|
110
|
-
if (active.has(candidate)) throw new TypeError(`${at} contains a cycle`)
|
|
111
|
-
const existing = copies.get(candidate)
|
|
112
|
-
if (existing) return existing
|
|
113
|
-
|
|
114
|
-
active.add(candidate)
|
|
115
|
-
try {
|
|
116
|
-
if (Array.isArray(candidate)) {
|
|
117
|
-
const extra = Reflect.ownKeys(candidate).filter(
|
|
118
|
-
(key) => key !== 'length' && (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key)),
|
|
119
|
-
)
|
|
120
|
-
if (extra.length > 0) throw new TypeError(`${at} has non-JSON array properties`)
|
|
121
|
-
const result: unknown[] = new Array(candidate.length)
|
|
122
|
-
copies.set(candidate, result)
|
|
123
|
-
for (let index = 0; index < candidate.length; index++) {
|
|
124
|
-
const descriptor = Object.getOwnPropertyDescriptor(candidate, String(index))
|
|
125
|
-
if (!descriptor) throw new TypeError(`${at}[${index}] is a sparse array hole`)
|
|
126
|
-
if (!descriptor.enumerable || !('value' in descriptor)) {
|
|
127
|
-
throw new TypeError(`${at}[${index}] must be an enumerable data property`)
|
|
128
|
-
}
|
|
129
|
-
result[index] = clone(descriptor.value, `${at}[${index}]`)
|
|
130
|
-
}
|
|
131
|
-
if (freeze) Object.freeze(result)
|
|
132
|
-
return result
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const prototype = Object.getPrototypeOf(candidate)
|
|
136
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
137
|
-
throw new TypeError(`${at} must be a plain JSON object`)
|
|
138
|
-
}
|
|
139
|
-
// JSON does not preserve prototypes. Canonicalize both admitted plain
|
|
140
|
-
// shapes to an ordinary object so a disk checkpoint round-trip compares
|
|
141
|
-
// equal to a fresh preparation of the same semantic value. Properties
|
|
142
|
-
// are still defined explicitly, so a literal "__proto__" key remains
|
|
143
|
-
// data rather than changing this object's prototype.
|
|
144
|
-
const result: Record<string, unknown> = {}
|
|
145
|
-
copies.set(candidate, result)
|
|
146
|
-
for (const key of Reflect.ownKeys(candidate)) {
|
|
147
|
-
if (typeof key !== 'string') throw new TypeError(`${at} has a symbol property`)
|
|
148
|
-
const descriptor = Object.getOwnPropertyDescriptor(candidate, key)
|
|
149
|
-
if (!descriptor?.enumerable || !('value' in descriptor)) {
|
|
150
|
-
throw new TypeError(`${at}.${key} must be an enumerable data property`)
|
|
151
|
-
}
|
|
152
|
-
Object.defineProperty(result, key, {
|
|
153
|
-
value: clone(descriptor.value, `${at}.${key}`),
|
|
154
|
-
enumerable: true,
|
|
155
|
-
writable: !freeze,
|
|
156
|
-
configurable: !freeze,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
if (freeze) Object.freeze(result)
|
|
160
|
-
return result
|
|
161
|
-
} finally {
|
|
162
|
-
active.delete(candidate)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return clone(value, path)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
94
|
/**
|
|
170
95
|
* Two sources contributed the same tool name and neither may take it.
|
|
171
96
|
*
|
|
@@ -364,17 +289,30 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
|
|
|
364
289
|
* would churn that prefix repeatedly and is rejected.
|
|
365
290
|
*/
|
|
366
291
|
searchDeferred(query: string): ToolDefinition[] {
|
|
292
|
+
return this.searchByAvailability(query, ['deferred'])
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Active matches use the same ranking, also recognizing exact short or generic names. */
|
|
296
|
+
searchActive(query: string): ToolDefinition[] {
|
|
297
|
+
return this.searchByAvailability(query, ['active'], true)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private searchByAvailability(
|
|
301
|
+
query: string,
|
|
302
|
+
states: ToolAvailability[],
|
|
303
|
+
allowExactName = false,
|
|
304
|
+
): ToolDefinition[] {
|
|
367
305
|
const q = query.toLowerCase().trim()
|
|
368
306
|
if (q.length === 0) return []
|
|
369
307
|
const terms = q.split(/\s+/).filter((tok) => tok.length >= 3 && !SEARCH_STOP_TOKENS.has(tok))
|
|
370
|
-
if (terms.length === 0) return []
|
|
308
|
+
if (terms.length === 0 && !allowExactName) return []
|
|
371
309
|
|
|
372
310
|
const scored: Array<{ tool: ToolDefinition; score: number }> = []
|
|
373
|
-
for (const tool of this.getByAvailability(
|
|
311
|
+
for (const tool of this.getByAvailability(states)) {
|
|
374
312
|
const name = tool.name.toLowerCase()
|
|
375
313
|
const description = tool.description.toLowerCase()
|
|
376
314
|
const argumentNames = listArgumentNames(tool)
|
|
377
|
-
let score = 0
|
|
315
|
+
let score = allowExactName && terms.length === 0 && name === q ? SEARCH_WEIGHT_NAME_EXACT : 0
|
|
378
316
|
for (const term of terms) {
|
|
379
317
|
if (name === term) {
|
|
380
318
|
score += SEARCH_WEIGHT_NAME_EXACT
|
package/src/run/command-gate.ts
CHANGED
|
@@ -110,11 +110,18 @@ export interface CommandGateOptions {
|
|
|
110
110
|
|
|
111
111
|
/** Head and tail of a command's output, with the middle marked as dropped. */
|
|
112
112
|
export function clipOutput(text: string, max: number): string {
|
|
113
|
+
if (!Number.isSafeInteger(max) || max < 0) {
|
|
114
|
+
throw new RangeError('maxOutputChars must be a nonnegative safe integer.')
|
|
115
|
+
}
|
|
113
116
|
const trimmed = text.trimEnd()
|
|
114
117
|
if (trimmed.length <= max) return trimmed
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
const markerBudget = `\n… ${trimmed.length} characters omitted …\n`.length
|
|
119
|
+
if (max < markerBudget) return max === 0 ? '' : '…'
|
|
120
|
+
const retained = max - markerBudget
|
|
121
|
+
const head = Math.ceil(retained / 2)
|
|
122
|
+
const tail = retained - head
|
|
123
|
+
const marker = `\n… ${trimmed.length - retained} characters omitted …\n`
|
|
124
|
+
return `${trimmed.slice(0, head)}${marker}${tail > 0 ? trimmed.slice(-tail) : ''}`
|
|
118
125
|
}
|
|
119
126
|
|
|
120
127
|
interface LastFailure {
|
|
@@ -142,7 +149,7 @@ function failureFeedback(
|
|
|
142
149
|
`Retained output is incomplete: ${truncatedStreams.join(' and ')} ${truncatedStreams.length === 1 ? 'was' : 'were'} truncated by the execution context. Re-run with a narrower command or filter to recover the missing diagnostics.`,
|
|
143
150
|
]
|
|
144
151
|
return [
|
|
145
|
-
`The answer was not accepted: \`${command}\` failed (attempt ${attempt}, exit ${result.exitCode}).`,
|
|
152
|
+
`The answer was not accepted: \`${command}\` failed (attempt ${attempt}, exit ${result.exitCode}${result.termination ? `, terminated: ${result.termination.origin}` : ''}).`,
|
|
146
153
|
'',
|
|
147
154
|
'Output:',
|
|
148
155
|
'```',
|
|
@@ -158,9 +165,9 @@ function unchangedFeedback(command: string, attempt: number): string {
|
|
|
158
165
|
return [
|
|
159
166
|
`The answer was not accepted, and \`${command}\` was NOT re-run (attempt ${attempt}).`,
|
|
160
167
|
'',
|
|
161
|
-
'The
|
|
168
|
+
'The configured change detector reports the same state as after the last failure. The default detector covers the Git commit and Git-visible working state; ignored files and external inputs may have changed.',
|
|
162
169
|
'',
|
|
163
|
-
'
|
|
170
|
+
'Check that the intended fix is present and addresses the reported failure. If verification depends on state outside the detector, the host should supply a matching fingerprint or return null to re-run checks.',
|
|
164
171
|
].join('\n')
|
|
165
172
|
}
|
|
166
173
|
|
|
@@ -183,20 +190,39 @@ export function createCommandGate(options: CommandGateOptions): ReviewAnswer {
|
|
|
183
190
|
const timeoutMs = options.timeoutMs ?? DEFAULT_GATE_TIMEOUT_MS
|
|
184
191
|
const maxRetries = options.maxRetries ?? DEFAULT_GATE_MAX_RETRIES
|
|
185
192
|
const maxOutputChars = options.maxOutputChars ?? DEFAULT_GATE_OUTPUT_CHARS
|
|
193
|
+
// Validate before a reviewer is installed: malformed limits cannot turn
|
|
194
|
+
// a formatting exception during verification into an unreviewed answer.
|
|
195
|
+
clipOutput('', maxOutputChars)
|
|
186
196
|
|
|
187
197
|
// Built once and reused: constructing a context per attempt would re-stat
|
|
188
198
|
// the directory for no gain, and the context holds nothing per-run.
|
|
189
199
|
const context = new LocalExecutionContext({ id: 'namzu-command-gate', cwd })
|
|
190
200
|
const exec: GateExec =
|
|
191
201
|
options.exec ?? ((command, args, opts) => context.executeCommand(command, args, opts))
|
|
192
|
-
const
|
|
193
|
-
|
|
202
|
+
const readFingerprint = async (signal?: AbortSignal): Promise<string | null> => {
|
|
203
|
+
if (signal?.aborted) return null
|
|
204
|
+
try {
|
|
205
|
+
return options.fingerprint
|
|
206
|
+
? await options.fingerprint()
|
|
207
|
+
: await fingerprintWorkspace({
|
|
208
|
+
cwd,
|
|
209
|
+
timeoutMs: 20_000,
|
|
210
|
+
exec: (command, args, commandOptions) =>
|
|
211
|
+
exec(command, args, { ...commandOptions, ...(signal ? { signal } : {}) }),
|
|
212
|
+
})
|
|
213
|
+
} catch {
|
|
214
|
+
return null
|
|
215
|
+
}
|
|
216
|
+
}
|
|
194
217
|
|
|
195
218
|
let attempt = 0
|
|
196
219
|
let last: LastFailure | undefined
|
|
197
220
|
let executions = 0
|
|
198
221
|
|
|
199
|
-
return async (): Promise<AnswerReview> => {
|
|
222
|
+
return async (_answer, reviewContext): Promise<AnswerReview> => {
|
|
223
|
+
const signal = reviewContext.signal
|
|
224
|
+
if (signal?.aborted)
|
|
225
|
+
return { accept: false, feedback: 'Verification was cancelled before admission.' }
|
|
200
226
|
attempt += 1
|
|
201
227
|
|
|
202
228
|
// A gate that already failed, over a tree nothing has touched since.
|
|
@@ -209,7 +235,7 @@ export function createCommandGate(options: CommandGateOptions): ReviewAnswer {
|
|
|
209
235
|
// that deleted it killed no test, which is what a dead condition looks
|
|
210
236
|
// like from the outside.
|
|
211
237
|
if (last && last.fingerprint !== null) {
|
|
212
|
-
const now = await
|
|
238
|
+
const now = await readFingerprint(signal)
|
|
213
239
|
if (now === last.fingerprint) {
|
|
214
240
|
return { accept: false, feedback: unchangedFeedback(last.command, attempt) }
|
|
215
241
|
}
|
|
@@ -221,20 +247,42 @@ export function createCommandGate(options: CommandGateOptions): ReviewAnswer {
|
|
|
221
247
|
|
|
222
248
|
executions += 1
|
|
223
249
|
for (const command of commands) {
|
|
250
|
+
if (signal?.aborted)
|
|
251
|
+
return { accept: false, feedback: 'Verification was cancelled before admission.' }
|
|
224
252
|
// `shell: true` because the operator handed over a command LINE —
|
|
225
253
|
// `pnpm test -- --run`, with its flags and its quoting — and taking
|
|
226
254
|
// that as an executable name plus literal arguments would fail on
|
|
227
255
|
// every gate anyone would actually write. Explicit, per the note on
|
|
228
256
|
// `LocalExecutionContext.executeCommand`: shell interpretation is
|
|
229
257
|
// opt-in, and this is the opt-in.
|
|
230
|
-
|
|
231
|
-
|
|
258
|
+
let result: CommandResult
|
|
259
|
+
try {
|
|
260
|
+
result = await exec(command, [], {
|
|
261
|
+
cwd,
|
|
262
|
+
timeoutMs,
|
|
263
|
+
shell: true,
|
|
264
|
+
...(signal ? { signal } : {}),
|
|
265
|
+
})
|
|
266
|
+
} catch (error) {
|
|
267
|
+
// A command that could not be observed completing is not a pass.
|
|
268
|
+
// Keep this inside the builtin reviewer: generic review callbacks
|
|
269
|
+
// historically fail open on throws. No fabricated exit status.
|
|
270
|
+
last = { command, fingerprint: null }
|
|
271
|
+
return {
|
|
272
|
+
accept: false,
|
|
273
|
+
feedback: `The answer was not accepted: verification with \`${command}\` could not complete (attempt ${attempt}).\n${clipOutput(error instanceof Error ? error.message : String(error), maxOutputChars)}\nCheck the execution problem and any partial effects before retrying. Do not claim verification passed.`,
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (signal?.aborted) return { accept: false, feedback: 'Verification was cancelled.' }
|
|
277
|
+
if (result.exitCode === 0 && result.termination === undefined) continue
|
|
232
278
|
|
|
233
279
|
// Taken AFTER the failure, not before the run: the comparison next
|
|
234
280
|
// time is against the tree this verdict was formed over. A snapshot
|
|
235
281
|
// from before the command would miss anything the command itself
|
|
236
282
|
// wrote — a formatter, a snapshot updater, a lockfile.
|
|
237
|
-
|
|
283
|
+
// Interrupted verification is not a stable failure of these source
|
|
284
|
+
// bytes. Allow another check even when no tracked file has changed.
|
|
285
|
+
last = { command, fingerprint: result.termination ? null : await readFingerprint(signal) }
|
|
238
286
|
return { accept: false, feedback: failureFeedback(command, attempt, result, maxOutputChars) }
|
|
239
287
|
}
|
|
240
288
|
|
package/src/run/index.ts
CHANGED
|
@@ -27,3 +27,5 @@ export type { LimitCheckerState, LimitCheckResult } from './LimitChecker.js'
|
|
|
27
27
|
|
|
28
28
|
export { RUN_MEMORY_TAG, createMemoryPromoter } from './memory-promoter.js'
|
|
29
29
|
export type { MemoryPromoterOptions } from './memory-promoter.js'
|
|
30
|
+
export { createMemoryRecallStep } from './memory-recall.js'
|
|
31
|
+
export type { MemoryRecallOptions } from './memory-recall.js'
|
|
@@ -1,41 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `promoteMemory` is called once at settle with the compaction extractor's
|
|
6
|
-
* already-structured output — decisions, discoveries, user requirements,
|
|
7
|
-
* failures, environment facts — and **nothing shipped supplied the hook**.
|
|
8
|
-
* So the structure the compaction pass had spent tokens producing was
|
|
9
|
-
* serialized into one system message and dropped on the floor when the run
|
|
10
|
-
* ended, exactly as its own module comment says. This is the supplier, and
|
|
11
|
-
* it is mostly a filter: the hard part — extracting facts from a transcript
|
|
12
|
-
* — already happened.
|
|
13
|
-
*
|
|
14
|
-
* ## The filter, which is the only decision here
|
|
15
|
-
*
|
|
16
|
-
* **A run that learned nothing must leave nothing.** Not an empty record,
|
|
17
|
-
* not a record whose body says "no decisions" — nothing. A promoter that
|
|
18
|
-
* wrote a row per run would fill the store with the runs least worth
|
|
19
|
-
* remembering, and `search_memory` would then return them: the model reads
|
|
20
|
-
* that store on later runs, so noise here is not merely wasted disk, it is
|
|
21
|
-
* context spent on a run that did nothing.
|
|
22
|
-
*
|
|
23
|
-
* What counts as having learned something is the five KNOWLEDGE categories —
|
|
24
|
-
* decisions, discoveries, user requirements, failures, environment. Not
|
|
25
|
-
* `task`, which every run has because it is the prompt restated. Not
|
|
26
|
-
* `files`, which every run that opened anything has, and which says what was
|
|
27
|
-
* touched rather than what was learned. A run whose only trace is "it read
|
|
28
|
-
* six files" is the exact record this filter exists to refuse.
|
|
29
|
-
*
|
|
30
|
-
* ## What it does NOT do
|
|
31
|
-
*
|
|
32
|
-
* Deduplicate against what is already stored, merge with a previous run's
|
|
33
|
-
* record, or expire anything. Each is a policy with real trade-offs and a
|
|
34
|
-
* host that wants one owns it — `promoteMemory` is a callback precisely so
|
|
35
|
-
* that the runtime does not decide this. This is the obvious default, not
|
|
36
|
-
* the only possible one.
|
|
2
|
+
* Select useful extracted claims for durable recall. Exact repeated claim sets
|
|
3
|
+
* are suppressed when already stored; archived claims are not reactivated.
|
|
4
|
+
* This deterministic filter does not verify truth or reconcile paraphrases.
|
|
37
5
|
*/
|
|
38
6
|
|
|
7
|
+
import { createHash } from 'node:crypto'
|
|
39
8
|
import type { MemoryStore } from '../types/memory/index.js'
|
|
40
9
|
import type { PromoteMemory, RunMemoryCandidate } from '../types/run/memory-promotion.js'
|
|
41
10
|
|
|
@@ -85,15 +54,18 @@ function knowledge(
|
|
|
85
54
|
): readonly (readonly [string, readonly string[]])[] {
|
|
86
55
|
const out: (readonly [string, readonly string[]])[] = []
|
|
87
56
|
for (const [key, heading] of KNOWLEDGE) {
|
|
88
|
-
const items =
|
|
57
|
+
const items = [
|
|
58
|
+
...new Set((candidate[key] as readonly string[]).map((item) => item.trim()).filter(Boolean)),
|
|
59
|
+
]
|
|
89
60
|
if (items.length > 0) out.push([heading, items.slice(0, cap)])
|
|
90
61
|
}
|
|
91
62
|
return out
|
|
92
63
|
}
|
|
93
64
|
|
|
94
|
-
/**
|
|
65
|
+
/** Carry actual claims into search results, with their category attribution. */
|
|
95
66
|
function summarize(sections: readonly (readonly [string, readonly string[]])[]): string {
|
|
96
|
-
|
|
67
|
+
const text = sections.map(([heading, items]) => `${heading}: ${items[0]}`).join('; ')
|
|
68
|
+
return text.length <= 600 ? text : `${text.slice(0, 599).replace(/[\uD800-\uDBFF]$/, '')}…`
|
|
97
69
|
}
|
|
98
70
|
|
|
99
71
|
function render(
|
|
@@ -131,6 +103,8 @@ function render(
|
|
|
131
103
|
*/
|
|
132
104
|
export function createMemoryPromoter(options: MemoryPromoterOptions): PromoteMemory {
|
|
133
105
|
const cap = options.maxPerCategory ?? 20
|
|
106
|
+
if (!Number.isSafeInteger(cap) || cap < 1)
|
|
107
|
+
throw new Error('maxPerCategory must be a positive integer')
|
|
134
108
|
const tags = [RUN_MEMORY_TAG, ...(options.tags ?? [])]
|
|
135
109
|
|
|
136
110
|
return async (candidate: RunMemoryCandidate): Promise<void> => {
|
|
@@ -139,17 +113,35 @@ export function createMemoryPromoter(options: MemoryPromoterOptions): PromoteMem
|
|
|
139
113
|
// of rows describing runs that discovered nothing is a store whose
|
|
140
114
|
// search results are mostly noise, and the model reads that store.
|
|
141
115
|
if (sections.length === 0) return
|
|
116
|
+
const digest = createHash('sha256').update(JSON.stringify(sections)).digest('hex')
|
|
117
|
+
const knowledgeTag = `knowledge:${digest}`
|
|
118
|
+
// A prior exact claim, including one deliberately archived, need not be
|
|
119
|
+
// saved again. This is not a cross-process uniqueness guarantee: the
|
|
120
|
+
// store's individual operations are atomic, not this read/create pair.
|
|
121
|
+
const existing = await options.store.list({
|
|
122
|
+
tags: [...tags, knowledgeTag],
|
|
123
|
+
})
|
|
124
|
+
for (const entry of existing.entries) {
|
|
125
|
+
const full = await options.store.get(entry.id)
|
|
126
|
+
if (full?.metadata?.source === RUN_MEMORY_TAG && full.metadata.knowledgeDigest === digest)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
142
129
|
|
|
143
130
|
await options.store.create({
|
|
144
131
|
title: candidate.task.trim() || `Run ${candidate.runId}`,
|
|
145
132
|
summary: summarize(sections),
|
|
146
133
|
content: render(candidate, sections),
|
|
147
|
-
tags,
|
|
134
|
+
tags: [...tags, knowledgeTag],
|
|
148
135
|
format: 'markdown',
|
|
149
136
|
// The run id, so a record can be traced back to the run that formed
|
|
150
137
|
// it. Evidence rather than decoration: without it a surprising
|
|
151
138
|
// memory cannot be checked against what actually happened.
|
|
152
|
-
metadata: {
|
|
139
|
+
metadata: {
|
|
140
|
+
runId: candidate.runId,
|
|
141
|
+
source: RUN_MEMORY_TAG,
|
|
142
|
+
knowledgeDigest: digest,
|
|
143
|
+
verification: 'unverified',
|
|
144
|
+
},
|
|
153
145
|
})
|
|
154
146
|
}
|
|
155
147
|
}
|