@zenera/neo 1.1.10 → 1.1.12

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.
Files changed (90) hide show
  1. package/README.md +3 -3
  2. package/dist/agent.d.ts +8 -7
  3. package/dist/agent.js +15 -8
  4. package/dist/architecture.d.ts +7 -5
  5. package/dist/architecture.js +20 -12
  6. package/dist/embedding.d.ts +20 -1
  7. package/dist/embedding.js +3 -2
  8. package/dist/embeddings/fanout.d.ts +51 -0
  9. package/dist/embeddings/fanout.js +76 -0
  10. package/dist/embeddings/gemini.d.ts +3 -10
  11. package/dist/embeddings/gemini.js +46 -30
  12. package/dist/embeddings/index.d.ts +3 -0
  13. package/dist/embeddings/index.js +3 -0
  14. package/dist/embeddings/limiter.d.ts +36 -0
  15. package/dist/embeddings/limiter.js +182 -0
  16. package/dist/embeddings/openai.d.ts +3 -2
  17. package/dist/embeddings/openai.js +54 -13
  18. package/dist/embeddings/openrouter.d.ts +2 -1
  19. package/dist/embeddings/openrouter.js +52 -23
  20. package/dist/embeddings/rate-limit.d.ts +16 -0
  21. package/dist/embeddings/rate-limit.js +131 -0
  22. package/dist/failure.d.ts +82 -0
  23. package/dist/failure.js +323 -0
  24. package/dist/index.d.ts +13 -2
  25. package/dist/index.js +13 -2
  26. package/dist/inspect/client.d.ts +1 -1
  27. package/dist/inspect/client.js +42 -26
  28. package/dist/kernel.d.ts +1 -1
  29. package/dist/kernel.js +40 -23
  30. package/dist/memory/files.d.ts +24 -0
  31. package/dist/memory/files.js +85 -0
  32. package/dist/memory/graph.d.ts +56 -0
  33. package/dist/memory/graph.js +159 -0
  34. package/dist/memory/index.d.ts +93 -0
  35. package/dist/memory/index.js +357 -0
  36. package/dist/memory/instructions.d.ts +15 -0
  37. package/dist/memory/instructions.js +103 -0
  38. package/dist/memory/page.d.ts +8 -0
  39. package/dist/memory/page.js +797 -0
  40. package/dist/memory/recall.d.ts +35 -0
  41. package/dist/memory/recall.js +161 -0
  42. package/dist/memory/render.d.ts +10 -0
  43. package/dist/memory/render.js +228 -0
  44. package/dist/memory/report.d.ts +57 -0
  45. package/dist/memory/report.js +113 -0
  46. package/dist/memory/store.d.ts +49 -0
  47. package/dist/memory/store.js +226 -0
  48. package/dist/memory/tools.d.ts +11 -0
  49. package/dist/memory/tools.js +310 -0
  50. package/dist/memory/types.d.ts +192 -0
  51. package/dist/memory/types.js +105 -0
  52. package/dist/memory/vectors.d.ts +29 -0
  53. package/dist/memory/vectors.js +152 -0
  54. package/dist/models/anthropic.d.ts +2 -1
  55. package/dist/models/anthropic.js +11 -4
  56. package/dist/models/factory.d.ts +15 -0
  57. package/dist/models/factory.js +49 -10
  58. package/dist/models/gemini.d.ts +2 -1
  59. package/dist/models/gemini.js +8 -3
  60. package/dist/models/openai-chat.d.ts +2 -1
  61. package/dist/models/openai-chat.js +10 -5
  62. package/dist/models/openai-responses.d.ts +2 -1
  63. package/dist/models/openai-responses.js +22 -7
  64. package/dist/models/openrouter.d.ts +2 -1
  65. package/dist/models/openrouter.js +14 -6
  66. package/dist/project/config.d.ts +55 -3
  67. package/dist/project/config.js +76 -1
  68. package/dist/project/index.d.ts +2 -2
  69. package/dist/project/index.js +1 -1
  70. package/dist/project/load.d.ts +16 -2
  71. package/dist/project/load.js +67 -1
  72. package/dist/runner.d.ts +4 -2
  73. package/dist/runner.js +29 -30
  74. package/dist/services.d.ts +23 -6
  75. package/dist/services.js +25 -15
  76. package/dist/tools/workspace.js +195 -17
  77. package/dist/trajectory.d.ts +14 -12
  78. package/dist/types.d.ts +5 -5
  79. package/dist/types.js +3 -3
  80. package/package.json +2 -5
  81. package/dist/memory-stores/factory.d.ts +0 -15
  82. package/dist/memory-stores/factory.js +0 -29
  83. package/dist/memory-stores/file.d.ts +0 -37
  84. package/dist/memory-stores/file.js +0 -174
  85. package/dist/memory-stores/in-memory.d.ts +0 -17
  86. package/dist/memory-stores/in-memory.js +0 -80
  87. package/dist/memory-stores/index.d.ts +0 -4
  88. package/dist/memory-stores/index.js +0 -5
  89. package/dist/memory.d.ts +0 -115
  90. package/dist/memory.js +0 -213
@@ -1,174 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { mkdir, readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
3
- import { join, resolve } from 'node:path';
4
- import { rankMemories, } from "../memory.js";
5
- // ---------------------------------------------------------------------------
6
- // Filesystem-backed memory store
7
- // ---------------------------------------------------------------------------
8
- /**
9
- * Record ids and op ids reach this store from model-authored tool arguments
10
- * (`memory_update`, `memory_delete`), so they are validated before becoming
11
- * path segments. Dots are excluded outright, which makes `.` and `..`
12
- * unrepresentable.
13
- */
14
- const SAFE_ID = /^[A-Za-z0-9_-]+$/;
15
- /**
16
- * One JSON file per record, under one directory per scope:
17
- *
18
- * ```
19
- * <dir>/<scope>/scope.json the unescaped scope name, for humans
20
- * <dir>/<scope>/records/<id>.json
21
- * <dir>/<scope>/ops/<opId>.json idempotency ledger
22
- * ```
23
- *
24
- * A file per record (rather than one appended log) keeps writes atomic and
25
- * deletes cheap without a compaction step. Search reads the whole scope and
26
- * ranks in process, which is exactly the trade this backend makes: no server,
27
- * no index, fine up to a few thousand records per scope.
28
- *
29
- * There is no cross-process lock. Concurrent writers to the *same* record can
30
- * lose an update; `expectedRevision` narrows that window, and a deployment
31
- * that needs real isolation should use a database-backed store.
32
- */
33
- export class FileMemoryStore {
34
- id;
35
- #dir;
36
- constructor(opts) {
37
- const o = typeof opts === 'string' ? { dir: opts } : opts;
38
- this.#dir = resolve(o.dir);
39
- this.id = o.id ?? 'file';
40
- }
41
- get dir() {
42
- return this.#dir;
43
- }
44
- async search(scope, q) {
45
- return rankMemories(await this.#all(scope), q);
46
- }
47
- async get(scope, id) {
48
- return this.#readJson(this.#recordPath(scope, id));
49
- }
50
- async write(scope, rec, opId) {
51
- const known = await this.#readOp(scope, opId);
52
- if (known) {
53
- const existing = await this.get(scope, known);
54
- if (existing) {
55
- return existing;
56
- }
57
- }
58
- const now = new Date().toISOString();
59
- const record = {
60
- id: randomUUID(),
61
- scope,
62
- kind: rec.kind ?? 'fact',
63
- text: rec.text,
64
- metadata: rec.metadata,
65
- createdAt: now,
66
- updatedAt: now,
67
- revision: 1,
68
- };
69
- await this.#writeRecord(record);
70
- await this.#writeOp(scope, opId, record.id);
71
- return record;
72
- }
73
- async update(scope, id, patch, opId) {
74
- const cur = await this.get(scope, id);
75
- if (!cur) {
76
- throw new Error(`memory record not found: ${scope}/${id}`);
77
- }
78
- if ((await this.#readOp(scope, opId)) === id) {
79
- return cur;
80
- }
81
- if (patch.expectedRevision !== undefined && patch.expectedRevision !== cur.revision) {
82
- throw new Error(`memory conflict on ${scope}/${id}: expected revision ` +
83
- `${patch.expectedRevision}, found ${cur.revision}`);
84
- }
85
- const next = {
86
- ...cur,
87
- kind: patch.kind ?? cur.kind,
88
- text: patch.text ?? cur.text,
89
- metadata: patch.metadata ?? cur.metadata,
90
- updatedAt: new Date().toISOString(),
91
- revision: cur.revision + 1,
92
- };
93
- await this.#writeRecord(next);
94
- await this.#writeOp(scope, opId, id);
95
- return next;
96
- }
97
- async delete(scope, id, opId) {
98
- await rm(this.#recordPath(scope, id), { force: true });
99
- await this.#writeOp(scope, opId, id);
100
- }
101
- // --- layout -----------------------------------------------------------
102
- /**
103
- * Percent-encoding is reversible and, with dots escaped too, cannot
104
- * produce a traversal segment out of a scope like `../etc`.
105
- */
106
- #scopeDir(scope) {
107
- return join(this.#dir, encodeURIComponent(scope).replace(/\./g, '%2E'));
108
- }
109
- #recordPath(scope, id) {
110
- return join(this.#scopeDir(scope), 'records', `${safeId(id, 'record id')}.json`);
111
- }
112
- #opPath(scope, opId) {
113
- return join(this.#scopeDir(scope), 'ops', `${safeId(opId, 'op id')}.json`);
114
- }
115
- // --- io ---------------------------------------------------------------
116
- async #all(scope) {
117
- const dir = join(this.#scopeDir(scope), 'records');
118
- let names;
119
- try {
120
- names = await readdir(dir);
121
- }
122
- catch (err) {
123
- if (err.code === 'ENOENT') {
124
- return [];
125
- }
126
- throw err;
127
- }
128
- const records = await Promise.all(names
129
- .filter((n) => n.endsWith('.json'))
130
- .map((n) => this.#readJson(join(dir, n))));
131
- return records.filter((r) => r !== undefined);
132
- }
133
- async #readOp(scope, opId) {
134
- const op = await this.#readJson(this.#opPath(scope, opId));
135
- return op?.recordId;
136
- }
137
- async #writeOp(scope, opId, recordId) {
138
- await writeJson(this.#opPath(scope, opId), { recordId });
139
- }
140
- async #writeRecord(record) {
141
- await writeJson(join(this.#scopeDir(record.scope), 'scope.json'), { scope: record.scope });
142
- await writeJson(this.#recordPath(record.scope, record.id), record);
143
- }
144
- async #readJson(path) {
145
- try {
146
- return JSON.parse(await readFile(path, 'utf8'));
147
- }
148
- catch (err) {
149
- if (err.code === 'ENOENT') {
150
- return undefined;
151
- }
152
- throw err;
153
- }
154
- }
155
- }
156
- function safeId(value, what) {
157
- if (!SAFE_ID.test(value)) {
158
- throw new Error(`invalid ${what}: ${JSON.stringify(value)}`);
159
- }
160
- return value;
161
- }
162
- async function writeJson(path, value) {
163
- await mkdir(join(path, '..'), { recursive: true });
164
- const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
165
- await writeFile(tmp, JSON.stringify(value), 'utf8');
166
- try {
167
- await rename(tmp, path);
168
- }
169
- catch (err) {
170
- await rm(tmp, { force: true });
171
- throw err;
172
- }
173
- }
174
- //# sourceMappingURL=file.js.map
@@ -1,17 +0,0 @@
1
- import { type MemoryDraft, type MemoryHit, type MemoryPatch, type MemoryQuery, type MemoryRecord, type MemoryStore } from '../memory.ts';
2
- /**
3
- * Reference implementation: scoped maps plus token-overlap scoring. Good enough
4
- * for tests and local runs; production deployments swap in a vector store
5
- * without touching the kernel.
6
- */
7
- export declare class InMemoryMemoryStore implements MemoryStore {
8
- #private;
9
- readonly id: string;
10
- constructor(id?: string);
11
- search(scope: string, q: MemoryQuery): Promise<MemoryHit[]>;
12
- get(scope: string, id: string): Promise<MemoryRecord | undefined>;
13
- write(scope: string, rec: MemoryDraft, opId: string): Promise<MemoryRecord>;
14
- update(scope: string, id: string, patch: MemoryPatch, opId: string): Promise<MemoryRecord>;
15
- delete(scope: string, id: string, opId: string): Promise<void>;
16
- }
17
- //# sourceMappingURL=in-memory.d.ts.map
@@ -1,80 +0,0 @@
1
- import { rankMemories, } from "../memory.js";
2
- /**
3
- * Reference implementation: scoped maps plus token-overlap scoring. Good enough
4
- * for tests and local runs; production deployments swap in a vector store
5
- * without touching the kernel.
6
- */
7
- export class InMemoryMemoryStore {
8
- id;
9
- #scopes = new Map();
10
- /** opId → record id, so a replayed op returns the original result */
11
- #ops = new Map();
12
- #seq = 0;
13
- constructor(id = 'mem') {
14
- this.id = id;
15
- }
16
- async search(scope, q) {
17
- return rankMemories(this.#space(scope).values(), q);
18
- }
19
- async get(scope, id) {
20
- return this.#space(scope).get(id);
21
- }
22
- async write(scope, rec, opId) {
23
- const known = this.#ops.get(opId);
24
- if (known) {
25
- const existing = this.#space(scope).get(known);
26
- if (existing) {
27
- return existing;
28
- }
29
- }
30
- const now = new Date().toISOString();
31
- const record = {
32
- id: `m${++this.#seq}`,
33
- scope,
34
- kind: rec.kind ?? 'fact',
35
- text: rec.text,
36
- metadata: rec.metadata,
37
- createdAt: now,
38
- updatedAt: now,
39
- revision: 1,
40
- };
41
- this.#space(scope).set(record.id, record);
42
- this.#ops.set(opId, record.id);
43
- return record;
44
- }
45
- async update(scope, id, patch, opId) {
46
- const space = this.#space(scope);
47
- const cur = space.get(id);
48
- if (!cur) {
49
- throw new Error(`memory record not found: ${scope}/${id}`);
50
- }
51
- if (this.#ops.get(opId) === id) {
52
- return cur;
53
- }
54
- if (patch.expectedRevision !== undefined && patch.expectedRevision !== cur.revision) {
55
- throw new Error(`memory conflict on ${scope}/${id}: expected revision ` +
56
- `${patch.expectedRevision}, found ${cur.revision}`);
57
- }
58
- const next = {
59
- ...cur,
60
- kind: patch.kind ?? cur.kind,
61
- text: patch.text ?? cur.text,
62
- metadata: patch.metadata ?? cur.metadata,
63
- updatedAt: new Date().toISOString(),
64
- revision: cur.revision + 1,
65
- };
66
- space.set(id, next);
67
- this.#ops.set(opId, id);
68
- return next;
69
- }
70
- async delete(scope, id, opId) {
71
- this.#space(scope).delete(id);
72
- this.#ops.set(opId, id);
73
- }
74
- #space(scope) {
75
- const s = this.#scopes.get(scope) ?? new Map();
76
- this.#scopes.set(scope, s);
77
- return s;
78
- }
79
- }
80
- //# sourceMappingURL=in-memory.js.map
@@ -1,4 +0,0 @@
1
- export * from './factory.ts';
2
- export * from './file.ts';
3
- export * from './in-memory.ts';
4
- //# sourceMappingURL=index.d.ts.map
@@ -1,5 +0,0 @@
1
- // Backends for the `MemoryStore` contract in `../memory.ts`.
2
- export * from "./factory.js";
3
- export * from "./file.js";
4
- export * from "./in-memory.js";
5
- //# sourceMappingURL=index.js.map
package/dist/memory.d.ts DELETED
@@ -1,115 +0,0 @@
1
- import { type AnyTool } from './types.ts';
2
- export interface MemoryRecord {
3
- id: string;
4
- /** memory space this record belongs to */
5
- scope: string;
6
- /** app-defined: 'fact' | 'preference' | 'episode' | … */
7
- kind: string;
8
- text: string;
9
- metadata?: Record<string, unknown>;
10
- createdAt: string;
11
- updatedAt: string;
12
- /** optimistic-concurrency token */
13
- revision: number;
14
- }
15
- export interface MemoryDraft {
16
- kind?: string;
17
- text: string;
18
- metadata?: Record<string, unknown>;
19
- }
20
- export interface MemoryPatch {
21
- kind?: string;
22
- text?: string;
23
- metadata?: Record<string, unknown>;
24
- /** when given, the update fails unless the stored revision matches */
25
- expectedRevision?: number;
26
- }
27
- export interface MemoryQuery {
28
- /** semantic query; omitted ⇒ pure filter listing */
29
- text?: string;
30
- filter?: Record<string, unknown>;
31
- kind?: string;
32
- limit?: number;
33
- minScore?: number;
34
- }
35
- export interface MemoryHit {
36
- record: MemoryRecord;
37
- /** 0..1, backend-normalized */
38
- score: number;
39
- }
40
- /**
41
- * Embedding generation is the store's business, not the kernel's: a pgvector
42
- * implementation embeds inside `write`/`search`, the in-memory one below falls
43
- * back to token overlap. The kernel never sees vectors.
44
- */
45
- export interface MemoryStore {
46
- readonly id: string;
47
- search(scope: string, q: MemoryQuery): Promise<MemoryHit[]>;
48
- get(scope: string, id: string): Promise<MemoryRecord | undefined>;
49
- /** `opId` makes writes idempotent under retry/replay */
50
- write(scope: string, rec: MemoryDraft, opId: string): Promise<MemoryRecord>;
51
- update(scope: string, id: string, patch: MemoryPatch, opId: string): Promise<MemoryRecord>;
52
- delete(scope: string, id: string, opId: string): Promise<void>;
53
- }
54
- export interface MemoryBinding<TCtx = unknown> {
55
- /** MemoryStore id */
56
- store: string;
57
- /** namespace; default `agent:${agent.name}`. A function is resolved per run. */
58
- scope?: string | ((ctx: TCtx) => string);
59
- access: 'read' | 'read-write';
60
- /** inject top-k matches before an LLM call */
61
- autoRecall?: {
62
- query: 'last_user_input' | 'none';
63
- limit: number;
64
- };
65
- }
66
- /** A binding with its scope already resolved against the run context. */
67
- export interface ResolvedBinding {
68
- store: string;
69
- scope: string;
70
- access: 'read' | 'read-write';
71
- autoRecall?: {
72
- query: 'last_user_input' | 'none';
73
- limit: number;
74
- };
75
- }
76
- export interface MemoryRecallSpec {
77
- kind: 'recall';
78
- store: string;
79
- scope: string;
80
- query: MemoryQuery;
81
- hits: {
82
- id: string;
83
- score: number;
84
- revision: number;
85
- }[];
86
- /** the rendered block the model actually saw */
87
- content: string;
88
- }
89
- export interface MemoryOpSpec {
90
- kind: 'op';
91
- op: 'write' | 'update' | 'delete';
92
- store: string;
93
- scope: string;
94
- /** sha256(runId, callId) — deterministic, so replay re-issues the same write */
95
- opId: string;
96
- recordId: string;
97
- revision: number;
98
- before?: string;
99
- after?: string;
100
- }
101
- export declare function memoryOpId(runId: string, callId: string): string;
102
- export declare function renderMemories(hits: MemoryHit[]): string;
103
- /**
104
- * Filtering plus token-overlap scoring, shared by the backends that have no
105
- * embeddings of their own. A vector store ignores this and ranks in the
106
- * database instead — the kernel only ever sees `MemoryHit[]`.
107
- */
108
- export declare function rankMemories(records: Iterable<MemoryRecord>, q: MemoryQuery): MemoryHit[];
109
- /**
110
- * Memory is reachable both explicitly (these tools) and implicitly (auto-recall
111
- * in the runner). Both land in the trajectory; only the explicit path is
112
- * visible to the model as a tool.
113
- */
114
- export declare function memoryTools<TCtx>(bindings: ResolvedBinding[]): AnyTool<TCtx>[];
115
- //# sourceMappingURL=memory.d.ts.map
package/dist/memory.js DELETED
@@ -1,213 +0,0 @@
1
- import { hash } from "./payload.js";
2
- import { MEMORY_DELETE_TOOL, MEMORY_SEARCH_TOOL, MEMORY_UPDATE_TOOL, MEMORY_WRITE_TOOL, tool, withEffects, } from "./types.js";
3
- export function memoryOpId(runId, callId) {
4
- return hash(`${runId}\u0000${callId}`);
5
- }
6
- export function renderMemories(hits) {
7
- if (!hits.length) {
8
- return '';
9
- }
10
- const lines = hits.map((h) => `- [${h.record.id}] (${h.record.kind}, score ${h.score.toFixed(2)}) ${h.record.text}`);
11
- return `Relevant memories:\n${lines.join('\n')}`;
12
- }
13
- // ---------------------------------------------------------------------------
14
- // Shared ranking
15
- // ---------------------------------------------------------------------------
16
- /**
17
- * Filtering plus token-overlap scoring, shared by the backends that have no
18
- * embeddings of their own. A vector store ignores this and ranks in the
19
- * database instead — the kernel only ever sees `MemoryHit[]`.
20
- */
21
- export function rankMemories(records, q) {
22
- const limit = q.limit ?? 8;
23
- const terms = tokenize(q.text ?? '');
24
- const hits = [];
25
- for (const rec of records) {
26
- if (q.kind && rec.kind !== q.kind) {
27
- continue;
28
- }
29
- if (q.filter && !matches(rec.metadata, q.filter)) {
30
- continue;
31
- }
32
- const score = terms.length ? overlap(terms, tokenize(rec.text)) : 1;
33
- if (score <= 0 || (q.minScore !== undefined && score < q.minScore)) {
34
- continue;
35
- }
36
- hits.push({ record: rec, score });
37
- }
38
- return hits.sort((a, b) => b.score - a.score).slice(0, limit);
39
- }
40
- function tokenize(v) {
41
- return v
42
- .toLowerCase()
43
- .split(/[^a-z0-9]+/)
44
- .filter((t) => t.length > 2);
45
- }
46
- function overlap(a, b) {
47
- const set = new Set(b);
48
- const shared = a.filter((t) => set.has(t)).length;
49
- return a.length ? shared / a.length : 0;
50
- }
51
- function matches(meta, filter) {
52
- return Object.entries(filter).every(([k, v]) => meta?.[k] === v);
53
- }
54
- // ---------------------------------------------------------------------------
55
- // Built-in memory tools
56
- // ---------------------------------------------------------------------------
57
- function spaceParam(bindings) {
58
- return bindings.length > 1
59
- ? { type: 'string', enum: bindings.map((b) => b.scope), description: 'memory space' }
60
- : undefined;
61
- }
62
- function pick(bindings, space) {
63
- const b = space ? bindings.find((x) => x.scope === space) : bindings[0];
64
- if (!b) {
65
- throw new Error(`unknown memory space: ${space ?? '(default)'}`);
66
- }
67
- return b;
68
- }
69
- /**
70
- * Memory is reachable both explicitly (these tools) and implicitly (auto-recall
71
- * in the runner). Both land in the trajectory; only the explicit path is
72
- * visible to the model as a tool.
73
- */
74
- export function memoryTools(bindings) {
75
- if (!bindings.length) {
76
- return [];
77
- }
78
- const writable = bindings.filter((b) => b.access === 'read-write');
79
- const space = spaceParam(bindings);
80
- const withSpace = (props) => (space ? { ...props, space } : props);
81
- const tools = [
82
- tool({
83
- name: MEMORY_SEARCH_TOOL,
84
- description: 'Search long-lived memories.',
85
- parameters: {
86
- type: 'object',
87
- properties: withSpace({
88
- query: { type: 'string' },
89
- kind: { type: 'string' },
90
- limit: { type: 'integer' },
91
- }),
92
- required: ['query'],
93
- additionalProperties: false,
94
- },
95
- execute: async (args, tc) => {
96
- const b = pick(bindings, args.space);
97
- const store = tc.services.memoryStore(b.store);
98
- const hits = await store.search(b.scope, {
99
- text: args.query,
100
- kind: args.kind,
101
- limit: args.limit,
102
- });
103
- return hits.map((h) => ({
104
- id: h.record.id,
105
- kind: h.record.kind,
106
- text: h.record.text,
107
- revision: h.record.revision,
108
- score: Number(h.score.toFixed(3)),
109
- }));
110
- },
111
- }),
112
- ];
113
- if (!writable.length) {
114
- return tools;
115
- }
116
- const wSpace = spaceParam(writable);
117
- const withWSpace = (props) => wSpace ? { ...props, space: wSpace } : props;
118
- tools.push(tool({
119
- name: MEMORY_WRITE_TOOL,
120
- description: 'Store a new long-lived memory.',
121
- parameters: {
122
- type: 'object',
123
- properties: withWSpace({ text: { type: 'string' }, kind: { type: 'string' } }),
124
- required: ['text'],
125
- additionalProperties: false,
126
- },
127
- execute: async (args, tc) => {
128
- const b = pick(writable, args.space);
129
- const opId = memoryOpId(tc.state.runId, tc.callId);
130
- const rec = await tc.services
131
- .memoryStore(b.store)
132
- .write(b.scope, { text: args.text, kind: args.kind }, opId);
133
- return withEffects(`stored memory ${rec.id}`, {
134
- kind: 'memory_op',
135
- spec: {
136
- kind: 'op',
137
- op: 'write',
138
- store: b.store,
139
- scope: b.scope,
140
- opId,
141
- recordId: rec.id,
142
- revision: rec.revision,
143
- after: rec.text,
144
- },
145
- });
146
- },
147
- }), tool({
148
- name: MEMORY_UPDATE_TOOL,
149
- description: 'Update an existing memory by id.',
150
- parameters: {
151
- type: 'object',
152
- properties: withWSpace({
153
- id: { type: 'string' },
154
- text: { type: 'string' },
155
- kind: { type: 'string' },
156
- }),
157
- required: ['id'],
158
- additionalProperties: false,
159
- },
160
- execute: async (args, tc) => {
161
- const b = pick(writable, args.space);
162
- const store = tc.services.memoryStore(b.store);
163
- const before = await store.get(b.scope, args.id);
164
- const opId = memoryOpId(tc.state.runId, tc.callId);
165
- const rec = await store.update(b.scope, args.id, { text: args.text, kind: args.kind }, opId);
166
- return withEffects(`updated memory ${rec.id}`, {
167
- kind: 'memory_op',
168
- spec: {
169
- kind: 'op',
170
- op: 'update',
171
- store: b.store,
172
- scope: b.scope,
173
- opId,
174
- recordId: rec.id,
175
- revision: rec.revision,
176
- before: before?.text,
177
- after: rec.text,
178
- },
179
- });
180
- },
181
- }), tool({
182
- name: MEMORY_DELETE_TOOL,
183
- description: 'Delete a memory by id.',
184
- parameters: {
185
- type: 'object',
186
- properties: withWSpace({ id: { type: 'string' } }),
187
- required: ['id'],
188
- additionalProperties: false,
189
- },
190
- execute: async (args, tc) => {
191
- const b = pick(writable, args.space);
192
- const store = tc.services.memoryStore(b.store);
193
- const before = await store.get(b.scope, args.id);
194
- const opId = memoryOpId(tc.state.runId, tc.callId);
195
- await store.delete(b.scope, args.id, opId);
196
- return withEffects(`deleted memory ${args.id}`, {
197
- kind: 'memory_op',
198
- spec: {
199
- kind: 'op',
200
- op: 'delete',
201
- store: b.store,
202
- scope: b.scope,
203
- opId,
204
- recordId: args.id,
205
- revision: before?.revision ?? 0,
206
- before: before?.text,
207
- },
208
- });
209
- },
210
- }));
211
- return tools;
212
- }
213
- //# sourceMappingURL=memory.js.map