@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
|
@@ -62,7 +62,7 @@ export interface CapacityValidator {
|
|
|
62
62
|
): Promise<void>
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Asserts `
|
|
65
|
+
* Asserts `liveDirectChildren + pendingNewChildren ≤ projectMaxWidth`
|
|
66
66
|
* under `parentSessionId`. The width cap applies to a single spawn call —
|
|
67
67
|
* a broadcast of N recipients passes `pendingNewChildren = N`.
|
|
68
68
|
*/
|
|
@@ -77,7 +77,7 @@ export interface CapacityValidator {
|
|
|
77
77
|
/**
|
|
78
78
|
* Default validator backed by {@link SessionStore}. Uses `getAncestry` for
|
|
79
79
|
* depth (root-to-self chain length) and `getChildren` for width (count of
|
|
80
|
-
*
|
|
80
|
+
* pending or active direct sub-sessions). Historical edges stay queryable.
|
|
81
81
|
*/
|
|
82
82
|
export class DefaultCapacityValidator implements CapacityValidator {
|
|
83
83
|
constructor(private readonly store: SessionStore) {}
|
|
@@ -108,7 +108,11 @@ export class DefaultCapacityValidator implements CapacityValidator {
|
|
|
108
108
|
tenantId: TenantId,
|
|
109
109
|
): Promise<void> {
|
|
110
110
|
const existing = await this.store.getChildren(parentSessionId, tenantId)
|
|
111
|
-
const
|
|
111
|
+
const live = existing.filter(
|
|
112
|
+
(child) =>
|
|
113
|
+
child.status !== 'idle' && child.status !== 'failed' && child.status !== 'archived',
|
|
114
|
+
)
|
|
115
|
+
const total = live.length + pendingNewChildren
|
|
112
116
|
if (total > projectMaxWidth) {
|
|
113
117
|
throw new DelegationCapacityExceeded({
|
|
114
118
|
dimension: 'width',
|
package/src/store/memory/disk.ts
CHANGED
|
@@ -6,16 +6,24 @@ import type {
|
|
|
6
6
|
CreateMemoryParams,
|
|
7
7
|
MemoryContent,
|
|
8
8
|
MemoryIndexEntry,
|
|
9
|
+
MemoryRecord,
|
|
9
10
|
MemorySearchParams,
|
|
10
11
|
MemorySearchResult,
|
|
11
12
|
MemoryStore,
|
|
13
|
+
UpdateMemoryParams,
|
|
12
14
|
} from '../../types/memory/index.js'
|
|
15
|
+
import { assertMemoryStatus } from '../../types/memory/index.js'
|
|
13
16
|
import { generateMemoryId, isEntityId } from '../../utils/id.js'
|
|
14
17
|
import { SCOPE_ATTRIBUTE } from '../../utils/log/types.js'
|
|
15
18
|
import { type Logger, resolveLogger } from '../../utils/logger.js'
|
|
16
19
|
import { DiskRecordStore } from '../kv/record-store.js'
|
|
17
20
|
import { defineSchema } from '../schema.js'
|
|
18
|
-
import { InMemoryMemoryIndex } from './index.js'
|
|
21
|
+
import { InMemoryMemoryIndex, searchMemoryEntries } from './index.js'
|
|
22
|
+
import {
|
|
23
|
+
DEFAULT_MEMORY_LOCK_TIMEOUT_MS,
|
|
24
|
+
acquireMemoryOperationLock,
|
|
25
|
+
validateMemoryLockTimeout,
|
|
26
|
+
} from './operation-lock.js'
|
|
19
27
|
|
|
20
28
|
/**
|
|
21
29
|
* This store's on-disk format, versioned as a unit — which is how a
|
|
@@ -32,27 +40,6 @@ interface StorageLocation {
|
|
|
32
40
|
readonly contentDir: string
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
const operationTails = new Map<string, Promise<void>>()
|
|
36
|
-
|
|
37
|
-
/** Serialize every operation over one canonical disk projection in this process. */
|
|
38
|
-
async function withMemoryOperationLock<T>(key: string, operation: () => Promise<T>): Promise<T> {
|
|
39
|
-
const previous = operationTails.get(key) ?? Promise.resolve()
|
|
40
|
-
let release = () => {}
|
|
41
|
-
const current = new Promise<void>((resolveCurrent) => {
|
|
42
|
-
release = resolveCurrent
|
|
43
|
-
})
|
|
44
|
-
const tail = previous.then(() => current)
|
|
45
|
-
operationTails.set(key, tail)
|
|
46
|
-
|
|
47
|
-
await previous
|
|
48
|
-
try {
|
|
49
|
-
return await operation()
|
|
50
|
-
} finally {
|
|
51
|
-
release()
|
|
52
|
-
if (operationTails.get(key) === tail) operationTails.delete(key)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
43
|
function invalidIndex(
|
|
57
44
|
reason: string,
|
|
58
45
|
details: { entryIndex?: number; field?: string } = {},
|
|
@@ -163,11 +150,14 @@ function assertMemoryContent(value: unknown, expectedId: MemoryId): asserts valu
|
|
|
163
150
|
export interface DiskMemoryStoreConfig {
|
|
164
151
|
baseDir: string
|
|
165
152
|
logger?: Logger
|
|
153
|
+
/** Maximum wait for another process's operation; default 10 seconds. Never breaks stale locks. */
|
|
154
|
+
lockTimeoutMs?: number
|
|
166
155
|
}
|
|
167
156
|
|
|
168
157
|
export class DiskMemoryStore implements MemoryStore {
|
|
169
158
|
private readonly baseDir: string
|
|
170
159
|
private readonly log: Logger
|
|
160
|
+
private readonly lockTimeoutMs: number
|
|
171
161
|
private readonly index = new InMemoryMemoryIndex()
|
|
172
162
|
private location?: StorageLocation
|
|
173
163
|
// Two instances of one primitive rather than two copies of its body.
|
|
@@ -180,6 +170,8 @@ export class DiskMemoryStore implements MemoryStore {
|
|
|
180
170
|
constructor(config: DiskMemoryStoreConfig) {
|
|
181
171
|
this.baseDir = join(config.baseDir, 'memory')
|
|
182
172
|
this.log = resolveLogger(config.logger).child({ [SCOPE_ATTRIBUTE]: 'store/memory/disk' })
|
|
173
|
+
this.lockTimeoutMs = config.lockTimeoutMs ?? DEFAULT_MEMORY_LOCK_TIMEOUT_MS
|
|
174
|
+
validateMemoryLockTimeout(this.lockTimeoutMs)
|
|
183
175
|
}
|
|
184
176
|
|
|
185
177
|
private get contentDir(): string {
|
|
@@ -235,10 +227,16 @@ export class DiskMemoryStore implements MemoryStore {
|
|
|
235
227
|
operation: (location: StorageLocation) => Promise<T>,
|
|
236
228
|
): Promise<T> {
|
|
237
229
|
const location = await this.storageLocation()
|
|
238
|
-
|
|
230
|
+
const release = await acquireMemoryOperationLock(
|
|
231
|
+
join(dirname(location.indexPath), 'operation.lock'),
|
|
232
|
+
this.lockTimeoutMs,
|
|
233
|
+
)
|
|
234
|
+
try {
|
|
239
235
|
await this.reloadIndex(location)
|
|
240
|
-
return operation(location)
|
|
241
|
-
}
|
|
236
|
+
return await operation(location)
|
|
237
|
+
} finally {
|
|
238
|
+
await release()
|
|
239
|
+
}
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
private async readContent(location: StorageLocation, id: MemoryId): Promise<MemoryContent> {
|
|
@@ -307,10 +305,17 @@ export class DiskMemoryStore implements MemoryStore {
|
|
|
307
305
|
})
|
|
308
306
|
}
|
|
309
307
|
|
|
310
|
-
async
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
308
|
+
async getRecord(id: MemoryId): Promise<MemoryRecord | undefined> {
|
|
309
|
+
return this.withAuthoritativeIndex(async (location) => {
|
|
310
|
+
assertStorageMemoryId(id, (reason) => invalidContent(id, reason, { field: 'id' }))
|
|
311
|
+
const entry = this.index.getEntry(id)
|
|
312
|
+
if (!entry) return undefined
|
|
313
|
+
return structuredClone({ entry, content: await this.readContent(location, id) })
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async update(id: MemoryId, updates: UpdateMemoryParams): Promise<MemoryIndexEntry | undefined> {
|
|
318
|
+
if (updates.status !== undefined) assertMemoryStatus(updates.status)
|
|
314
319
|
return this.withAuthoritativeIndex(async (location) => {
|
|
315
320
|
assertStorageMemoryId(id, (reason) => invalidContent(id, reason, { field: 'id' }))
|
|
316
321
|
const existing = this.index.getEntry(id)
|
|
@@ -321,6 +326,7 @@ export class DiskMemoryStore implements MemoryStore {
|
|
|
321
326
|
title: updates.title ?? existing.title,
|
|
322
327
|
summary: updates.summary ?? existing.summary,
|
|
323
328
|
tags: updates.tags ? [...updates.tags] : existing.tags,
|
|
329
|
+
status: updates.status ?? existing.status,
|
|
324
330
|
updatedAt: Date.now(),
|
|
325
331
|
}
|
|
326
332
|
const updatesContent =
|
|
@@ -367,7 +373,23 @@ export class DiskMemoryStore implements MemoryStore {
|
|
|
367
373
|
}
|
|
368
374
|
|
|
369
375
|
async list(params?: MemorySearchParams): Promise<MemorySearchResult> {
|
|
370
|
-
return this.withAuthoritativeIndex(async () =>
|
|
376
|
+
return this.withAuthoritativeIndex(async (location) => {
|
|
377
|
+
if (!params?.query?.trim() && !params?.requiredIdentifiers?.length)
|
|
378
|
+
return this.index.search(params ?? {})
|
|
379
|
+
// Search the current bodies inside the same operation as the index
|
|
380
|
+
// snapshot. No retained cache can hide another process's update.
|
|
381
|
+
const candidates = this.index.search({
|
|
382
|
+
...params,
|
|
383
|
+
query: undefined,
|
|
384
|
+
limit: undefined,
|
|
385
|
+
requiredIdentifiers: undefined,
|
|
386
|
+
})
|
|
387
|
+
const contents = new Map<MemoryId, string>()
|
|
388
|
+
for (const entry of candidates.entries) {
|
|
389
|
+
contents.set(entry.id, (await this.readContent(location, entry.id)).content)
|
|
390
|
+
}
|
|
391
|
+
return searchMemoryEntries(candidates.entries, params, (id) => contents.get(id) ?? '')
|
|
392
|
+
})
|
|
371
393
|
}
|
|
372
394
|
|
|
373
395
|
getIndex(): InMemoryMemoryIndex {
|
|
@@ -6,37 +6,85 @@ import type {
|
|
|
6
6
|
MemorySearchResult,
|
|
7
7
|
} from '../../types/memory/index.js'
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
results = results.filter(
|
|
18
|
-
(e) => e.title.toLowerCase().includes(q) || e.summary.toLowerCase().includes(q),
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (params.tags && params.tags.length > 0) {
|
|
23
|
-
const requiredTags = params.tags
|
|
24
|
-
results = results.filter((e) => requiredTags.every((tag) => e.tags.includes(tag)))
|
|
25
|
-
}
|
|
9
|
+
function terms(text: string): Set<string> {
|
|
10
|
+
return new Set(
|
|
11
|
+
text
|
|
12
|
+
.normalize('NFKC')
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.match(/[\p{L}\p{N}]+/gu) ?? [],
|
|
15
|
+
)
|
|
16
|
+
}
|
|
26
17
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
/** Exact normalized word membership; no substring, stemming or alias inference. */
|
|
19
|
+
export function matchesMemoryIdentifier(text: string, identifiers: ReadonlySet<string>): boolean {
|
|
20
|
+
for (const match of text
|
|
21
|
+
.normalize('NFKC')
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.matchAll(/[\p{L}\p{N}_]+/gu)) {
|
|
24
|
+
if (identifiers.has(match[0])) return true
|
|
25
|
+
}
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
/** Shared lexical ranking; a caller-owned index can omit body content. */
|
|
30
|
+
export function searchMemoryEntries(
|
|
31
|
+
entries: readonly MemoryIndexEntry[],
|
|
32
|
+
params: MemorySearchParams,
|
|
33
|
+
contentOf: (id: MemoryId) => string = () => '',
|
|
34
|
+
): MemorySearchResult {
|
|
35
|
+
const query = terms(params.query ?? '')
|
|
36
|
+
const identifiers = new Set(
|
|
37
|
+
params.requiredIdentifiers?.map((id) => id.normalize('NFKC').toLowerCase()),
|
|
38
|
+
)
|
|
39
|
+
if (params.query?.trim() && query.size === 0) return { entries: [], totalCount: 0 }
|
|
40
|
+
const ranked = entries
|
|
41
|
+
.filter(
|
|
42
|
+
(entry) =>
|
|
43
|
+
(!params.status || entry.status === params.status) &&
|
|
44
|
+
(!params.tags?.length || params.tags.every((tag) => entry.tags.includes(tag))),
|
|
45
|
+
)
|
|
46
|
+
.filter(
|
|
47
|
+
(entry) =>
|
|
48
|
+
!identifiers.size ||
|
|
49
|
+
[entry.id, entry.title, entry.summary, contentOf(entry.id)].some((text) =>
|
|
50
|
+
matchesMemoryIdentifier(text, identifiers),
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
.map((entry) => {
|
|
54
|
+
let coverage = 0
|
|
55
|
+
let score = 0
|
|
56
|
+
if (query.size > 0) {
|
|
57
|
+
const title = terms(entry.title)
|
|
58
|
+
const summary = terms(entry.summary)
|
|
59
|
+
const body = terms(contentOf(entry.id))
|
|
60
|
+
for (const term of query) {
|
|
61
|
+
const weight =
|
|
62
|
+
(title.has(term) ? 8 : 0) + (summary.has(term) ? 4 : 0) + (body.has(term) ? 1 : 0)
|
|
63
|
+
if (weight > 0) coverage++
|
|
64
|
+
score += weight
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { entry, coverage, score }
|
|
68
|
+
})
|
|
69
|
+
.filter(({ coverage }) => query.size === 0 || coverage > 0)
|
|
70
|
+
.sort(
|
|
71
|
+
(a, b) =>
|
|
72
|
+
b.coverage - a.coverage ||
|
|
73
|
+
b.score - a.score ||
|
|
74
|
+
b.entry.updatedAt - a.entry.updatedAt ||
|
|
75
|
+
(a.entry.id < b.entry.id ? -1 : a.entry.id > b.entry.id ? 1 : 0),
|
|
76
|
+
)
|
|
77
|
+
return {
|
|
78
|
+
entries: ranked.slice(0, params.limit ?? ranked.length).map(({ entry }) => entry),
|
|
79
|
+
totalCount: ranked.length,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
32
82
|
|
|
33
|
-
|
|
34
|
-
|
|
83
|
+
export class InMemoryMemoryIndex implements MemoryIndex {
|
|
84
|
+
private entries = new Map<string, MemoryIndexEntry>()
|
|
35
85
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
totalCount,
|
|
39
|
-
}
|
|
86
|
+
search(params: MemorySearchParams): MemorySearchResult {
|
|
87
|
+
return searchMemoryEntries([...this.entries.values()], params)
|
|
40
88
|
}
|
|
41
89
|
|
|
42
90
|
getEntry(id: MemoryId): MemoryIndexEntry | undefined {
|
|
@@ -3,12 +3,15 @@ import type {
|
|
|
3
3
|
CreateMemoryParams,
|
|
4
4
|
MemoryContent,
|
|
5
5
|
MemoryIndexEntry,
|
|
6
|
+
MemoryRecord,
|
|
6
7
|
MemorySearchParams,
|
|
7
8
|
MemorySearchResult,
|
|
8
9
|
MemoryStore,
|
|
10
|
+
UpdateMemoryParams,
|
|
9
11
|
} from '../../types/memory/index.js'
|
|
12
|
+
import { assertMemoryStatus } from '../../types/memory/index.js'
|
|
10
13
|
import { generateMemoryId } from '../../utils/id.js'
|
|
11
|
-
import { InMemoryMemoryIndex } from './index.js'
|
|
14
|
+
import { InMemoryMemoryIndex, searchMemoryEntries } from './index.js'
|
|
12
15
|
|
|
13
16
|
export class InMemoryMemoryStore implements MemoryStore {
|
|
14
17
|
private content = new Map<string, MemoryContent>()
|
|
@@ -47,10 +50,14 @@ export class InMemoryMemoryStore implements MemoryStore {
|
|
|
47
50
|
return this.content.get(id)
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
async
|
|
51
|
-
id
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
async getRecord(id: MemoryId): Promise<MemoryRecord | undefined> {
|
|
54
|
+
const entry = this.index.getEntry(id)
|
|
55
|
+
const content = this.content.get(id)
|
|
56
|
+
return entry && content ? structuredClone({ entry, content }) : undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async update(id: MemoryId, updates: UpdateMemoryParams): Promise<MemoryIndexEntry | undefined> {
|
|
60
|
+
if (updates.status !== undefined) assertMemoryStatus(updates.status)
|
|
54
61
|
const existing = this.index.getEntry(id)
|
|
55
62
|
if (!existing) return undefined
|
|
56
63
|
|
|
@@ -61,6 +68,7 @@ export class InMemoryMemoryStore implements MemoryStore {
|
|
|
61
68
|
title: updates.title ?? existing.title,
|
|
62
69
|
summary: updates.summary ?? existing.summary,
|
|
63
70
|
tags: updates.tags ? [...updates.tags] : existing.tags,
|
|
71
|
+
status: updates.status ?? existing.status,
|
|
64
72
|
updatedAt: now,
|
|
65
73
|
}
|
|
66
74
|
|
|
@@ -94,7 +102,11 @@ export class InMemoryMemoryStore implements MemoryStore {
|
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
async list(params?: MemorySearchParams): Promise<MemorySearchResult> {
|
|
97
|
-
return
|
|
105
|
+
return searchMemoryEntries(
|
|
106
|
+
this.index.allEntries(),
|
|
107
|
+
params ?? {},
|
|
108
|
+
(id) => this.content.get(id)?.content ?? '',
|
|
109
|
+
)
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
getIndex(): InMemoryMemoryIndex {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import { type FileHandle, lstat, open, readFile, unlink } from 'node:fs/promises'
|
|
3
|
+
import { setTimeout as delay } from 'node:timers/promises'
|
|
4
|
+
|
|
5
|
+
import { NamzuError } from '../../types/errors/index.js'
|
|
6
|
+
|
|
7
|
+
/** Wait bound, not a lease: a slow or crashed owner is never silently replaced. */
|
|
8
|
+
export const DEFAULT_MEMORY_LOCK_TIMEOUT_MS = 10_000
|
|
9
|
+
|
|
10
|
+
export function validateMemoryLockTimeout(timeoutMs: number): void {
|
|
11
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {
|
|
12
|
+
throw new NamzuError({
|
|
13
|
+
code: 'invalid_config',
|
|
14
|
+
message: 'DiskMemoryStore lockTimeoutMs must be a positive safe integer.',
|
|
15
|
+
retryable: false,
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function lockError(path: string, reason: string, timeoutMs: number): NamzuError {
|
|
21
|
+
return new NamzuError({
|
|
22
|
+
code: 'storage_error',
|
|
23
|
+
message: `Memory operation lock ${path}: ${reason}. Stop all processes using this memory store and inspect the lock owner before removing a stale lock; it is never broken automatically.`,
|
|
24
|
+
details: { lockPath: path, timeoutMs },
|
|
25
|
+
retryable: false,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Local-filesystem exclusion for cooperating processes. Atomic rename of the
|
|
31
|
+
* index alone cannot serialize the index/content read-modify-write transaction.
|
|
32
|
+
* An abandoned lock fails closed; guessing a lease expired would permit two
|
|
33
|
+
* live writers to overwrite each other again.
|
|
34
|
+
*/
|
|
35
|
+
export async function acquireMemoryOperationLock(
|
|
36
|
+
path: string,
|
|
37
|
+
timeoutMs: number,
|
|
38
|
+
): Promise<() => Promise<void>> {
|
|
39
|
+
const deadline = performance.now() + timeoutMs
|
|
40
|
+
let attempted = false
|
|
41
|
+
for (;;) {
|
|
42
|
+
if (attempted && performance.now() >= deadline) {
|
|
43
|
+
throw lockError(path, `acquisition timed out after ${timeoutMs} ms`, timeoutMs)
|
|
44
|
+
}
|
|
45
|
+
attempted = true
|
|
46
|
+
let handle: FileHandle
|
|
47
|
+
try {
|
|
48
|
+
handle = await open(path, 'wx', 0o600)
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error
|
|
51
|
+
const existing = await lstat(path).catch((statError: NodeJS.ErrnoException) => {
|
|
52
|
+
if (statError.code === 'ENOENT') return undefined
|
|
53
|
+
throw statError
|
|
54
|
+
})
|
|
55
|
+
if (!existing) continue
|
|
56
|
+
if (!existing.isFile() || existing.isSymbolicLink()) {
|
|
57
|
+
throw lockError(path, 'the occupied lock is not a regular file', timeoutMs)
|
|
58
|
+
}
|
|
59
|
+
if (performance.now() >= deadline) {
|
|
60
|
+
throw lockError(path, `acquisition timed out after ${timeoutMs} ms`, timeoutMs)
|
|
61
|
+
}
|
|
62
|
+
await delay(Math.min(25, Math.max(1, deadline - performance.now())))
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const owner = `${JSON.stringify({ pid: process.pid, token: randomUUID(), acquiredAt: Date.now() })}\n`
|
|
67
|
+
const identity = await handle.stat().catch(async (error: unknown) => {
|
|
68
|
+
await handle.close()
|
|
69
|
+
// Exclusive create happened, but ownership could not be established.
|
|
70
|
+
// Leave the path for explicit recovery rather than unlink an unknown inode.
|
|
71
|
+
throw error
|
|
72
|
+
})
|
|
73
|
+
try {
|
|
74
|
+
await handle.writeFile(owner, 'utf8')
|
|
75
|
+
await handle.sync()
|
|
76
|
+
} catch (error) {
|
|
77
|
+
await handle.close()
|
|
78
|
+
const current = await lstat(path).catch(() => undefined)
|
|
79
|
+
if (current?.dev === identity.dev && current.ino === identity.ino) {
|
|
80
|
+
await unlink(path).catch(() => undefined)
|
|
81
|
+
}
|
|
82
|
+
throw error
|
|
83
|
+
}
|
|
84
|
+
await handle.close()
|
|
85
|
+
return async () => {
|
|
86
|
+
const current = await lstat(path)
|
|
87
|
+
if (
|
|
88
|
+
!current.isFile() ||
|
|
89
|
+
current.isSymbolicLink() ||
|
|
90
|
+
current.dev !== identity.dev ||
|
|
91
|
+
current.ino !== identity.ino ||
|
|
92
|
+
(await readFile(path, 'utf8')) !== owner
|
|
93
|
+
) {
|
|
94
|
+
throw lockError(path, 'the lock owner changed before release', timeoutMs)
|
|
95
|
+
}
|
|
96
|
+
await unlink(path)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|