@namzu/sdk 36.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 +180 -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/public-runtime.d.ts +3 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +2 -1
- 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 +5 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +70 -14
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +5 -8
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +54 -7
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +10 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +325 -36
- 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 +9 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/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 +2 -0
- package/dist/runtime/query/iteration/stream-turn.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/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/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/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/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 +4 -2
- 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/public-runtime.ts +4 -0
- 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 +77 -14
- package/src/runtime/query/index.ts +73 -16
- package/src/runtime/query/iteration/index.ts +377 -44
- 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 +9 -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 +2 -0
- 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/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/computer-use.ts +61 -7
- 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/structured-output/index.ts +15 -2
- package/src/types/tool/index.ts +16 -0
- package/src/utils/json-snapshot.ts +76 -0
|
@@ -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
|
+
}
|
|
@@ -63,7 +63,7 @@ const pointModelInputSchema = {
|
|
|
63
63
|
additionalProperties: false,
|
|
64
64
|
} as const
|
|
65
65
|
|
|
66
|
-
const modelInputSchema
|
|
66
|
+
const modelInputSchema = {
|
|
67
67
|
type: 'object',
|
|
68
68
|
properties: {
|
|
69
69
|
type: {
|
|
@@ -136,16 +136,17 @@ function requiredCapability(type: ComputerUseAction['type']): keyof ComputerUseC
|
|
|
136
136
|
|
|
137
137
|
function buildDescription(host: ComputerUseHost): string {
|
|
138
138
|
const caps = host.capabilities
|
|
139
|
-
const available
|
|
140
|
-
if (caps.screenshot) available.push('screenshot')
|
|
141
|
-
if (caps.cursorPosition) available.push('cursor_position')
|
|
142
|
-
if (caps.mouse) available.push('mouse_move, mouse_click, mouse_drag, scroll')
|
|
143
|
-
if (caps.keyboard) available.push('type_text, key')
|
|
139
|
+
const available = availableActions(caps)
|
|
144
140
|
const unavailable: string[] = []
|
|
145
141
|
if (!caps.screenshot) unavailable.push('screenshot')
|
|
146
142
|
if (!caps.cursorPosition) unavailable.push('cursor_position')
|
|
147
143
|
if (!caps.mouse) unavailable.push('mouse')
|
|
148
144
|
if (!caps.keyboard) unavailable.push('keyboard')
|
|
145
|
+
if (caps.supportedActions) {
|
|
146
|
+
for (const action of actionSchema.options.map((option) => option.shape.type.value)) {
|
|
147
|
+
if (!available.includes(action)) unavailable.push(action)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
149
150
|
|
|
150
151
|
const lines = [
|
|
151
152
|
`Controls the user's desktop on a ${caps.displayServer} host. Use to take screenshots and drive mouse/keyboard input for GUI tasks.`,
|
|
@@ -161,9 +162,42 @@ function buildDescription(host: ComputerUseHost): string {
|
|
|
161
162
|
lines.push(
|
|
162
163
|
'Coordinates are in logical pixels from the top-left of the primary display. Call getDisplayGeometry through screenshot output before clicking to confirm bounds.',
|
|
163
164
|
)
|
|
165
|
+
if (caps.mouseClickButtons && available.includes('mouse_click'))
|
|
166
|
+
lines.push(`Click buttons: ${caps.mouseClickButtons.join(', ') || 'none'}.`)
|
|
167
|
+
if (caps.mouseDragButtons && available.includes('mouse_drag'))
|
|
168
|
+
lines.push(`Drag buttons: ${caps.mouseDragButtons.join(', ') || 'none'}.`)
|
|
164
169
|
return lines.join(' ')
|
|
165
170
|
}
|
|
166
171
|
|
|
172
|
+
function availableActions(caps: ComputerUseCapabilities): ComputerUseAction['type'][] {
|
|
173
|
+
return actionSchema.options
|
|
174
|
+
.map((option) => option.shape.type.value)
|
|
175
|
+
.filter((action) => {
|
|
176
|
+
const required = requiredCapability(action)
|
|
177
|
+
return (
|
|
178
|
+
(required === null || caps[required] === true) &&
|
|
179
|
+
(caps.supportedActions === undefined || caps.supportedActions.includes(action)) &&
|
|
180
|
+
(action !== 'mouse_click' || caps.mouseClickButtons?.length !== 0) &&
|
|
181
|
+
(action !== 'mouse_drag' || caps.mouseDragButtons?.length !== 0)
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function hostModelSchema(caps: ComputerUseCapabilities): Record<string, unknown> {
|
|
187
|
+
const schema = structuredClone(modelInputSchema)
|
|
188
|
+
const actions = availableActions(caps)
|
|
189
|
+
// An unavailable host remains a diagnostic tool. Avoid invalid empty enums
|
|
190
|
+
// on provider wires; every execution is still refused before host access.
|
|
191
|
+
if (actions.length > 0) schema.properties.type.enum = actions
|
|
192
|
+
const buttons = new Set<string>()
|
|
193
|
+
if (actions.includes('mouse_click'))
|
|
194
|
+
for (const button of caps.mouseClickButtons ?? ['left', 'right', 'middle']) buttons.add(button)
|
|
195
|
+
if (actions.includes('mouse_drag'))
|
|
196
|
+
for (const button of caps.mouseDragButtons ?? ['left', 'right', 'middle']) buttons.add(button)
|
|
197
|
+
if (buttons.size > 0) schema.properties.button.enum = [...buttons]
|
|
198
|
+
return schema
|
|
199
|
+
}
|
|
200
|
+
|
|
167
201
|
function pointLabel(point: { readonly x: number; readonly y: number }): string {
|
|
168
202
|
return `(${point.x}, ${point.y})`
|
|
169
203
|
}
|
|
@@ -283,7 +317,7 @@ export function createComputerUseTool(host: ComputerUseHost): ToolDefinition<Act
|
|
|
283
317
|
name: COMPUTER_USE_TOOL_NAME,
|
|
284
318
|
description: buildDescription(host),
|
|
285
319
|
inputSchema: actionSchema,
|
|
286
|
-
modelInputSchema:
|
|
320
|
+
modelInputSchema: hostModelSchema(host.capabilities),
|
|
287
321
|
validationErrorHint:
|
|
288
322
|
'Action requirements: mouse_move needs "to"; mouse_click needs "at" and "button"; mouse_drag needs "from", "to", and "button"; scroll needs "at", "direction", and positive "amount"; type_text needs "text"; key needs "keys".',
|
|
289
323
|
category: 'custom',
|
|
@@ -310,6 +344,26 @@ export function createComputerUseTool(host: ComputerUseHost): ToolDefinition<Act
|
|
|
310
344
|
error: `computer_use: action "${input.type}" requires capability "${required}" which is not available on this host (displayServer=${host.capabilities.displayServer}).${host.capabilities.unavailableReason ? ` ${host.capabilities.unavailableReason} Do not retry; tell the user.` : ''}`,
|
|
311
345
|
}
|
|
312
346
|
}
|
|
347
|
+
if (!availableActions(host.capabilities).includes(input.type)) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
output: '',
|
|
351
|
+
error: `computer_use: action "${input.type}" is not supported on this host.`,
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const buttons =
|
|
355
|
+
input.type === 'mouse_click'
|
|
356
|
+
? host.capabilities.mouseClickButtons
|
|
357
|
+
: input.type === 'mouse_drag'
|
|
358
|
+
? host.capabilities.mouseDragButtons
|
|
359
|
+
: undefined
|
|
360
|
+
if (buttons && 'button' in input && !buttons.includes(input.button)) {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
output: '',
|
|
364
|
+
error: `computer_use: action "${input.type}" does not support button "${input.button}" on this host.`,
|
|
365
|
+
}
|
|
366
|
+
}
|
|
313
367
|
try {
|
|
314
368
|
const result = await host.execute(input as ComputerUseAction)
|
|
315
369
|
return resultToToolResult(result)
|
|
@@ -49,6 +49,12 @@ export interface RunCodeToolOptions {
|
|
|
49
49
|
readonly runtime?: CodeRuntime
|
|
50
50
|
readonly timeoutMs?: number
|
|
51
51
|
readonly maxOutputBytes?: number
|
|
52
|
+
/**
|
|
53
|
+
* What a successful `call()` resolves to. Default: `text` (ToolResult.output).
|
|
54
|
+
* `structured` returns `{ output, data? }`, preserving JSON tool data for
|
|
55
|
+
* local filtering. Failures still reject; authority and dispatch are unchanged.
|
|
56
|
+
*/
|
|
57
|
+
readonly toolResultMode?: 'text' | 'structured'
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
const DEFAULT_TIMEOUT_MS = 30_000
|
|
@@ -59,8 +65,11 @@ export function buildRunCodeTool(options: RunCodeToolOptions = {}) {
|
|
|
59
65
|
|
|
60
66
|
return defineTool({
|
|
61
67
|
name: RUN_CODE_TOOL_NAME,
|
|
62
|
-
description:
|
|
63
|
-
|
|
68
|
+
description: `Runs a short JavaScript program that can call this run's own tools in a loop. Use it when the same tool would otherwise be called many times in a row — filtering, retrying, fanning out — and not for a single call. ${
|
|
69
|
+
options.toolResultMode === 'structured'
|
|
70
|
+
? 'Each successful call() returns { output: string, data?: JSON value }. Filter data locally and return only the needed result. Failed calls reject.'
|
|
71
|
+
: 'Each successful call() returns the tool output string. Failed calls reject.'
|
|
72
|
+
}`,
|
|
64
73
|
inputSchema,
|
|
65
74
|
category: 'custom',
|
|
66
75
|
permissions: [],
|
|
@@ -108,9 +117,19 @@ export function buildRunCodeTool(options: RunCodeToolOptions = {}) {
|
|
|
108
117
|
signal: operation.signal,
|
|
109
118
|
runtimeToolCallId: operation.runtimeToolCallId,
|
|
110
119
|
})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
if (!toolResult.success) {
|
|
121
|
+
return { ok: false, error: toolResult.error ?? 'the tool failed' }
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
value:
|
|
126
|
+
options.toolResultMode === 'structured'
|
|
127
|
+
? {
|
|
128
|
+
output: toolResult.output,
|
|
129
|
+
...(toolResult.data !== undefined ? { data: toolResult.data } : {}),
|
|
130
|
+
}
|
|
131
|
+
: toolResult.output,
|
|
132
|
+
}
|
|
114
133
|
} catch (err) {
|
|
115
134
|
return {
|
|
116
135
|
ok: false,
|
|
@@ -38,8 +38,7 @@ export const SearchToolsTool = defineTool({
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const allowed =
|
|
42
|
-
context.allowedTools && context.allowedTools.length > 0 ? new Set(context.allowedTools) : null
|
|
41
|
+
const allowed = context.allowedTools !== undefined ? new Set(context.allowedTools) : null
|
|
43
42
|
// `searchDeferred` returns a ranked list (score-descending), so slicing
|
|
44
43
|
// the head is a true top-k activation, not an arbitrary subset.
|
|
45
44
|
const ranked = context.toolRegistry
|
|
@@ -47,9 +46,25 @@ export const SearchToolsTool = defineTool({
|
|
|
47
46
|
.filter((tool) => !allowed || allowed.has(tool.name))
|
|
48
47
|
|
|
49
48
|
if (ranked.length === 0) {
|
|
49
|
+
const active = context.toolRegistry
|
|
50
|
+
.searchActive?.(input.query)
|
|
51
|
+
.filter(
|
|
52
|
+
(tool) =>
|
|
53
|
+
(!allowed || allowed.has(tool.name)) &&
|
|
54
|
+
context.toolRegistry?.getAvailability(tool.name) === 'active',
|
|
55
|
+
)
|
|
56
|
+
const activeReceipt =
|
|
57
|
+
active === undefined
|
|
58
|
+
? 'This registry cannot search active tools.'
|
|
59
|
+
: active.length === 0
|
|
60
|
+
? 'No matching active tools were found.'
|
|
61
|
+
: `Already active matching tools (up to ${ACTIVATION_TOP_K}):\n${active
|
|
62
|
+
.slice(0, ACTIVATION_TOP_K)
|
|
63
|
+
.map((tool) => `- ${tool.name}`)
|
|
64
|
+
.join('\n')}`
|
|
50
65
|
return {
|
|
51
66
|
success: true,
|
|
52
|
-
output: `No deferred tools matching "${input.query}".
|
|
67
|
+
output: `No deferred tools matching "${input.query}". ${activeReceipt}`,
|
|
53
68
|
}
|
|
54
69
|
}
|
|
55
70
|
|
package/src/tools/defineTool.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface DefineToolOptions<S extends z.ZodType> {
|
|
|
20
20
|
readOnly: boolean
|
|
21
21
|
destructive: boolean | ((input: z.infer<S>) => boolean)
|
|
22
22
|
concurrencySafe: boolean
|
|
23
|
+
/** Batch ordering boundary; see {@link ToolDefinition.executionBarrier}. */
|
|
24
|
+
executionBarrier?: boolean
|
|
23
25
|
tier?: string
|
|
24
26
|
/**
|
|
25
27
|
* How this tool's call and result should be shown; see
|
|
@@ -81,6 +83,9 @@ export function defineTool<S extends z.ZodType>(
|
|
|
81
83
|
...(options.presentResult ? { presentResult: options.presentResult } : {}),
|
|
82
84
|
...(options.outputSchema !== undefined ? { outputSchema: options.outputSchema } : {}),
|
|
83
85
|
...(options.terminal !== undefined ? { terminal: options.terminal } : {}),
|
|
86
|
+
...(options.executionBarrier !== undefined
|
|
87
|
+
? { executionBarrier: options.executionBarrier }
|
|
88
|
+
: {}),
|
|
84
89
|
category: options.category,
|
|
85
90
|
permissions: options.permissions,
|
|
86
91
|
isReadOnly: () => options.readOnly,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import type { MemoryStore } from '../../types/memory/index.js'
|
|
3
|
+
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
4
|
+
import { asMemoryId } from '../../utils/id.js'
|
|
5
|
+
import { defineTool } from '../defineTool.js'
|
|
6
|
+
|
|
7
|
+
export function buildDeleteMemoryTool(store: MemoryStore): ToolDefinition {
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'delete_memory',
|
|
10
|
+
description:
|
|
11
|
+
'Permanently delete a stored memory by ID. Use update_memory with status archived when the record should remain available for inspection. Deletion does not erase past conversation transcripts.',
|
|
12
|
+
inputSchema: z.object({
|
|
13
|
+
id: z.string().describe('Memory ID to permanently delete'),
|
|
14
|
+
}),
|
|
15
|
+
category: 'custom',
|
|
16
|
+
permissions: [],
|
|
17
|
+
readOnly: false,
|
|
18
|
+
destructive: true,
|
|
19
|
+
concurrencySafe: true,
|
|
20
|
+
async execute({ id }) {
|
|
21
|
+
const removed = await store.delete(asMemoryId(id))
|
|
22
|
+
return {
|
|
23
|
+
success: removed,
|
|
24
|
+
output: removed ? `Memory deleted: ${id}.` : `Memory ${id} not found.`,
|
|
25
|
+
...(removed ? {} : { error: 'Memory not found' }),
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { MemoryIndex, MemoryStore } from '../../types/memory/index.js'
|
|
2
2
|
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
3
|
+
import { buildDeleteMemoryTool } from './delete.js'
|
|
3
4
|
import { buildReadMemoryTool } from './read.js'
|
|
4
5
|
import { buildSaveMemoryTool } from './save.js'
|
|
5
6
|
import { buildSearchMemoryTool, buildStoreSearchMemoryTool } from './search.js'
|
|
7
|
+
import { buildUpdateMemoryTool } from './update.js'
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Build memory tools over one authoritative store.
|
|
@@ -28,9 +30,13 @@ export function buildMemoryTools(store: MemoryStore, index?: MemoryIndex): ToolD
|
|
|
28
30
|
index ? buildSearchMemoryTool(index) : buildStoreSearchMemoryTool(store),
|
|
29
31
|
buildReadMemoryTool(store),
|
|
30
32
|
buildSaveMemoryTool(store),
|
|
33
|
+
buildUpdateMemoryTool(store),
|
|
34
|
+
buildDeleteMemoryTool(store),
|
|
31
35
|
]
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
export { buildSearchMemoryTool } from './search.js'
|
|
35
39
|
export { buildReadMemoryTool } from './read.js'
|
|
36
40
|
export { buildSaveMemoryTool } from './save.js'
|
|
41
|
+
export { buildUpdateMemoryTool } from './update.js'
|
|
42
|
+
export { buildDeleteMemoryTool } from './delete.js'
|
package/src/tools/memory/save.ts
CHANGED
|
@@ -6,7 +6,8 @@ import { defineTool } from '../defineTool.js'
|
|
|
6
6
|
export function buildSaveMemoryTool(store: MemoryStore): ToolDefinition {
|
|
7
7
|
return defineTool({
|
|
8
8
|
name: 'save_memory',
|
|
9
|
-
description:
|
|
9
|
+
description:
|
|
10
|
+
'Save a new historical claim for future reference. Include the actual useful fact and its evidence in the summary and content. For corrections to an existing record use update_memory instead of creating contradictory duplicates.',
|
|
10
11
|
inputSchema: z.object({
|
|
11
12
|
title: z.string().min(1).describe('Short descriptive title'),
|
|
12
13
|
summary: z.string().min(1).describe('Brief summary (1-2 sentences)'),
|
|
@@ -18,12 +19,13 @@ export function buildSaveMemoryTool(store: MemoryStore): ToolDefinition {
|
|
|
18
19
|
readOnly: false,
|
|
19
20
|
destructive: false,
|
|
20
21
|
concurrencySafe: true,
|
|
21
|
-
async execute({ title, summary, content, tags }) {
|
|
22
|
+
async execute({ title, summary, content, tags }, context) {
|
|
22
23
|
const { entry } = await store.create({
|
|
23
24
|
title,
|
|
24
25
|
summary,
|
|
25
26
|
content,
|
|
26
27
|
tags,
|
|
28
|
+
metadata: { source: 'agent-memory', runId: context.runId },
|
|
27
29
|
})
|
|
28
30
|
|
|
29
31
|
return {
|
|
@@ -14,19 +14,26 @@ function defineSearchMemoryTool(search: SearchMemory): ToolDefinition {
|
|
|
14
14
|
return defineTool({
|
|
15
15
|
name: 'search_memory',
|
|
16
16
|
description:
|
|
17
|
-
'Search stored memories by
|
|
17
|
+
'Search active stored memories by relevant words or tags. The built-in store ranks matches in titles, summaries and full content. Returns titles and summaries; use read_memory for evidence. Set status to archived to inspect obsolete records.',
|
|
18
18
|
inputSchema: z.object({
|
|
19
|
-
query: z.string().optional().describe('
|
|
19
|
+
query: z.string().optional().describe('Relevant words or identifiers to search'),
|
|
20
20
|
tags: z.array(z.string()).optional().describe('Filter by tags (all must match)'),
|
|
21
|
-
|
|
21
|
+
status: z.enum(['active', 'archived']).default('active'),
|
|
22
|
+
limit: z
|
|
23
|
+
.number()
|
|
24
|
+
.int()
|
|
25
|
+
.min(1)
|
|
26
|
+
.max(50)
|
|
27
|
+
.default(10)
|
|
28
|
+
.describe('Maximum results to return (1–50)'),
|
|
22
29
|
}),
|
|
23
30
|
category: 'analysis',
|
|
24
31
|
permissions: [],
|
|
25
32
|
readOnly: true,
|
|
26
33
|
destructive: false,
|
|
27
34
|
concurrencySafe: true,
|
|
28
|
-
async execute({ query, tags, limit }) {
|
|
29
|
-
const result = await search({ query, tags, limit })
|
|
35
|
+
async execute({ query, tags, status, limit }) {
|
|
36
|
+
const result = await search({ query, tags, status, limit })
|
|
30
37
|
|
|
31
38
|
if (result.entries.length === 0) {
|
|
32
39
|
return {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import type { MemoryStore } from '../../types/memory/index.js'
|
|
3
|
+
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
4
|
+
import { asMemoryId } from '../../utils/id.js'
|
|
5
|
+
import { defineTool } from '../defineTool.js'
|
|
6
|
+
|
|
7
|
+
export function buildUpdateMemoryTool(store: MemoryStore): ToolDefinition {
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'update_memory',
|
|
10
|
+
description:
|
|
11
|
+
'Correct an existing memory in place, or archive an obsolete claim so it is no longer recalled. Use the ID from search_memory; current evidence should determine corrections.',
|
|
12
|
+
inputSchema: z.object({
|
|
13
|
+
id: z.string().describe('Memory ID to correct or archive'),
|
|
14
|
+
title: z.string().min(1).optional(),
|
|
15
|
+
summary: z.string().min(1).optional(),
|
|
16
|
+
content: z.string().min(1).optional(),
|
|
17
|
+
tags: z.array(z.string()).optional(),
|
|
18
|
+
status: z.enum(['active', 'archived']).optional(),
|
|
19
|
+
}),
|
|
20
|
+
category: 'custom',
|
|
21
|
+
permissions: [],
|
|
22
|
+
readOnly: false,
|
|
23
|
+
destructive: false,
|
|
24
|
+
concurrencySafe: true,
|
|
25
|
+
async execute({ id, ...updates }) {
|
|
26
|
+
if (Object.values(updates).every((value) => value === undefined)) {
|
|
27
|
+
return {
|
|
28
|
+
success: false,
|
|
29
|
+
output: 'Provide a correction or status to update.',
|
|
30
|
+
error: 'No memory update supplied',
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const memoryId = asMemoryId(id)
|
|
34
|
+
// Patch only requested fields in one store operation. A read/merge of
|
|
35
|
+
// provenance here would overwrite metadata from a concurrent writer.
|
|
36
|
+
const entry = await store.update(memoryId, updates)
|
|
37
|
+
if (!entry)
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
output: `Memory ${id} no longer exists.`,
|
|
41
|
+
error: 'Memory not found',
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
output: `Memory updated: ${id} — ${entry.title} (${entry.status}).`,
|
|
46
|
+
data: { id, status: entry.status },
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
}
|
|
@@ -29,6 +29,12 @@ export interface TaskHandle {
|
|
|
29
29
|
export type SiblingFailurePolicy = 'continue' | 'cancel-siblings'
|
|
30
30
|
|
|
31
31
|
export interface CreateTaskOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Revalidate host authority at actual admission, including after a capacity wait.
|
|
34
|
+
* Queue retries may invoke this more than once; checks must tolerate repeated calls.
|
|
35
|
+
*/
|
|
36
|
+
readonly beforeStart?: () => Promise<void>
|
|
37
|
+
|
|
32
38
|
/**
|
|
33
39
|
* Observe events from this one delegated run when the scheduler can expose
|
|
34
40
|
* them.
|