agentfootprint 9.26.0 → 9.28.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/dist/adapters/google/aiPlatform.js +438 -0
- package/dist/adapters/google/aiPlatform.js.map +1 -0
- package/dist/adapters/hosting/googleAgentEngine.js +372 -0
- package/dist/adapters/hosting/googleAgentEngine.js.map +1 -0
- package/dist/adapters/identity/google.js +275 -0
- package/dist/adapters/identity/google.js.map +1 -0
- package/dist/adapters/memory/agentcore.js +19 -0
- package/dist/adapters/memory/agentcore.js.map +1 -1
- package/dist/adapters/memory/memoryBank.js +823 -0
- package/dist/adapters/memory/memoryBank.js.map +1 -0
- package/dist/core/agent/stages/routeTurn.js +13 -1
- package/dist/core/agent/stages/routeTurn.js.map +1 -1
- package/dist/esm/adapters/google/aiPlatform.d.ts +453 -0
- package/dist/esm/adapters/google/aiPlatform.js +424 -0
- package/dist/esm/adapters/google/aiPlatform.js.map +1 -0
- package/dist/esm/adapters/hosting/googleAgentEngine.d.ts +156 -0
- package/dist/esm/adapters/hosting/googleAgentEngine.js +368 -0
- package/dist/esm/adapters/hosting/googleAgentEngine.js.map +1 -0
- package/dist/esm/adapters/identity/google.d.ts +179 -0
- package/dist/esm/adapters/identity/google.js +271 -0
- package/dist/esm/adapters/identity/google.js.map +1 -0
- package/dist/esm/adapters/memory/agentcore.d.ts +19 -0
- package/dist/esm/adapters/memory/agentcore.js +19 -0
- package/dist/esm/adapters/memory/agentcore.js.map +1 -1
- package/dist/esm/adapters/memory/memoryBank.d.ts +390 -0
- package/dist/esm/adapters/memory/memoryBank.js +817 -0
- package/dist/esm/adapters/memory/memoryBank.js.map +1 -0
- package/dist/esm/core/agent/stages/routeTurn.js +13 -1
- package/dist/esm/core/agent/stages/routeTurn.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +23 -0
- package/dist/esm/hosting-providers.d.ts +7 -0
- package/dist/esm/hosting-providers.js +6 -0
- package/dist/esm/hosting-providers.js.map +1 -1
- package/dist/esm/identity.d.ts +1 -0
- package/dist/esm/identity.js +5 -0
- package/dist/esm/identity.js.map +1 -1
- package/dist/esm/lib/injection-engine/buildInjectionEngineSubflow.js +9 -0
- package/dist/esm/lib/injection-engine/buildInjectionEngineSubflow.js.map +1 -1
- package/dist/esm/lib/injection-engine/routingPolicy.d.ts +8 -0
- package/dist/esm/lib/injection-engine/routingPolicy.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraph.d.ts +11 -2
- package/dist/esm/lib/injection-engine/skillGraph.js +25 -1
- package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillIntent.d.ts +13 -5
- package/dist/esm/lib/injection-engine/skillIntent.js +12 -2
- package/dist/esm/lib/injection-engine/skillIntent.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillMatch.d.ts +40 -0
- package/dist/esm/lib/injection-engine/skillMatch.js +60 -0
- package/dist/esm/lib/injection-engine/skillMatch.js.map +1 -1
- package/dist/esm/memory-providers.d.ts +1 -0
- package/dist/esm/memory-providers.js +7 -0
- package/dist/esm/memory-providers.js.map +1 -1
- package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.d.ts +4 -0
- package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.js +4 -1
- package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.js.map +1 -1
- package/dist/esm/recorders/observability/commentary/artifactPhrases.d.ts +50 -0
- package/dist/esm/recorders/observability/commentary/artifactPhrases.js +88 -0
- package/dist/esm/recorders/observability/commentary/artifactPhrases.js.map +1 -0
- package/dist/esm/recorders/observability/commentary/commentaryTemplates.js +233 -9
- package/dist/esm/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
- package/dist/hosting-providers.js +10 -1
- package/dist/hosting-providers.js.map +1 -1
- package/dist/identity.js +8 -1
- package/dist/identity.js.map +1 -1
- package/dist/lib/injection-engine/buildInjectionEngineSubflow.js +9 -0
- package/dist/lib/injection-engine/buildInjectionEngineSubflow.js.map +1 -1
- package/dist/lib/injection-engine/routingPolicy.js.map +1 -1
- package/dist/lib/injection-engine/skillGraph.js +25 -1
- package/dist/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/lib/injection-engine/skillIntent.js +12 -2
- package/dist/lib/injection-engine/skillIntent.js.map +1 -1
- package/dist/lib/injection-engine/skillMatch.js +61 -1
- package/dist/lib/injection-engine/skillMatch.js.map +1 -1
- package/dist/memory-providers.js +12 -1
- package/dist/memory-providers.js.map +1 -1
- package/dist/recorders/observability/AgentThinkingTraceRecorder.js +4 -1
- package/dist/recorders/observability/AgentThinkingTraceRecorder.js.map +1 -1
- package/dist/recorders/observability/commentary/artifactPhrases.js +94 -0
- package/dist/recorders/observability/commentary/artifactPhrases.js.map +1 -0
- package/dist/recorders/observability/commentary/commentaryTemplates.js +233 -9
- package/dist/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
- package/dist/types/adapters/google/aiPlatform.d.ts +454 -0
- package/dist/types/adapters/google/aiPlatform.d.ts.map +1 -0
- package/dist/types/adapters/hosting/googleAgentEngine.d.ts +157 -0
- package/dist/types/adapters/hosting/googleAgentEngine.d.ts.map +1 -0
- package/dist/types/adapters/identity/google.d.ts +180 -0
- package/dist/types/adapters/identity/google.d.ts.map +1 -0
- package/dist/types/adapters/memory/agentcore.d.ts +19 -0
- package/dist/types/adapters/memory/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/memory/memoryBank.d.ts +391 -0
- package/dist/types/adapters/memory/memoryBank.d.ts.map +1 -0
- package/dist/types/core/agent/stages/routeTurn.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +23 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/hosting-providers.d.ts +7 -0
- package/dist/types/hosting-providers.d.ts.map +1 -1
- package/dist/types/identity.d.ts +1 -0
- package/dist/types/identity.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/buildInjectionEngineSubflow.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/routingPolicy.d.ts +8 -0
- package/dist/types/lib/injection-engine/routingPolicy.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraph.d.ts +11 -2
- package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillIntent.d.ts +13 -5
- package/dist/types/lib/injection-engine/skillIntent.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillMatch.d.ts +40 -0
- package/dist/types/lib/injection-engine/skillMatch.d.ts.map +1 -1
- package/dist/types/memory-providers.d.ts +1 -0
- package/dist/types/memory-providers.d.ts.map +1 -1
- package/dist/types/recorders/observability/AgentThinkingTraceRecorder.d.ts +4 -0
- package/dist/types/recorders/observability/AgentThinkingTraceRecorder.d.ts.map +1 -1
- package/dist/types/recorders/observability/commentary/artifactPhrases.d.ts +51 -0
- package/dist/types/recorders/observability/commentary/artifactPhrases.d.ts.map +1 -0
- package/dist/types/recorders/observability/commentary/commentaryTemplates.d.ts.map +1 -1
- package/package.json +24 -15
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memoryBankStore — the `MemoryStore` port over Vertex AI **Memory Bank**.
|
|
3
|
+
*
|
|
4
|
+
* import { memoryBankStore } from 'agentfootprint/memory';
|
|
5
|
+
*
|
|
6
|
+
* const store = memoryBankStore({
|
|
7
|
+
* project: 'my-project',
|
|
8
|
+
* location: 'us-central1',
|
|
9
|
+
* reasoningEngine: '1234567890',
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* ── Read this before you write anything into it ─────────────────────────────
|
|
13
|
+
* Memory Bank is a **natural-language** memory service, not a key-value store
|
|
14
|
+
* and not a vector database. A `Memory` is a `fact` string plus an immutable
|
|
15
|
+
* `scope`; retrieval takes a QUESTION IN WORDS, embeds it on Google's side and
|
|
16
|
+
* ranks there. Three consequences, each of which has a silent-failure mode
|
|
17
|
+
* that this adapter turns into something you can see:
|
|
18
|
+
*
|
|
19
|
+
* 1. **It never ranks the vectors you wrote.** `supportsVectorSearch` is
|
|
20
|
+
* `false` and `ranksBy` is `'server-text'`, so the corpus builders
|
|
21
|
+
* (`indexCorpus`, `indexFolder`, `indexDocuments`) refuse this store by
|
|
22
|
+
* name instead of embedding a whole corpus, reporting success, and leaving
|
|
23
|
+
* it unreachable forever. An `embedding` on an entry handed to `put()` is
|
|
24
|
+
* **not stored** — there is nowhere to put it and nothing that would read
|
|
25
|
+
* it — and the two declarations above are how this adapter says so before
|
|
26
|
+
* you spend anything.
|
|
27
|
+
*
|
|
28
|
+
* 2. **The retrieval score is a DISTANCE, and smaller is closer.** The port's
|
|
29
|
+
* `ScoredEntry.score` is a cosine similarity, where HIGHER is closer.
|
|
30
|
+
* Passed through unconverted, `search()` would return the LEAST relevant
|
|
31
|
+
* memories first with a confident-looking number in the right range —
|
|
32
|
+
* which no threshold and no eyeball can separate from a working search.
|
|
33
|
+
* See {@link MemoryBankStore.search} for exactly what this adapter does
|
|
34
|
+
* instead, and why it refuses `minScore` rather than reinterpreting it.
|
|
35
|
+
*
|
|
36
|
+
* 3. **`scope` is an exact match and immutable once written.** A retrieval
|
|
37
|
+
* whose scope is a subset of a memory's scope returns NOTHING — not a
|
|
38
|
+
* superset, not a partial match, nothing. So the scope convention has to
|
|
39
|
+
* be right before the first write, because it cannot be changed after it
|
|
40
|
+
* and a bank written under the wrong one is poisoned permanently. See
|
|
41
|
+
* {@link MemoryBankStoreOptions.scopeFor}.
|
|
42
|
+
*
|
|
43
|
+
* ── How a memory is ADDRESSED, and why it is not just the entry id ──────────
|
|
44
|
+
* A memory's resource name is `<engine>/memories/<resource id>`, and that
|
|
45
|
+
* resource id is composed from **the resolved scope and the entry id
|
|
46
|
+
* together** — never the entry id alone.
|
|
47
|
+
*
|
|
48
|
+
* The reason is that entry ids in this library are deliberately deterministic
|
|
49
|
+
* and identity-free: `msg-<turn>-<index>`, `fact:<key>`, `snap-<turn>`. Two
|
|
50
|
+
* people talking to the same agent produce the SAME entry ids, so an address
|
|
51
|
+
* built from the id alone is one row for both of them — and since a resource
|
|
52
|
+
* name addresses a row directly, the second writer's `fact` lands on the first
|
|
53
|
+
* writer's row while the immutable `scope` stays the first writer's. What comes
|
|
54
|
+
* back is one tenant reading another tenant's private fact, one tenant's own
|
|
55
|
+
* write invisible to them, and `forget()` finding nothing to erase. Every
|
|
56
|
+
* sibling store in this library namespaces by identity (`s3Vectors` keys on
|
|
57
|
+
* `<namespace>#<id>`, `pgVector` on `(namespace, id)`, `InMemoryStore` on a map
|
|
58
|
+
* per namespace); this one does the same thing, keyed on the SCOPE rather than
|
|
59
|
+
* the raw identity so that a widened `scopeFor` widens sharing exactly as much
|
|
60
|
+
* as it widens retrieval, and not one row more.
|
|
61
|
+
*
|
|
62
|
+
* The composed address is a partition, not the boundary itself. The boundary is
|
|
63
|
+
* the stored `scope`, which is re-checked on the way back from every read AND
|
|
64
|
+
* before every overwrite — so even an address collision is refused rather than
|
|
65
|
+
* written through.
|
|
66
|
+
*
|
|
67
|
+
* ── Writes are long-running operations ──────────────────────────────────────
|
|
68
|
+
* `create`, `patch` and `delete` all answer with an Operation rather than the
|
|
69
|
+
* resource — verified against the installed SDK's own return types. Every
|
|
70
|
+
* write here waits for `done` before returning, because a `put` that came back
|
|
71
|
+
* early followed by a `get` is a race whose failure mode is "no data", and
|
|
72
|
+
* nobody can tell that from a memory that was never written.
|
|
73
|
+
*
|
|
74
|
+
* ── What has no primitive here, and is therefore refused ────────────────────
|
|
75
|
+
* `putIfVersion`, `seen`, `recordSignature`, `feedback` and `getFeedback` have
|
|
76
|
+
* no counterpart in this service: a `Memory` carries no etag and there is no
|
|
77
|
+
* dedup or feedback surface. The sibling AgentCore adapter emulates them
|
|
78
|
+
* in-process; this one refuses them by name, and the difference is deliberate.
|
|
79
|
+
* A store you reach for BECAUSE it is shared across a fleet is the worst place
|
|
80
|
+
* for a per-process shadow: `seen()` would answer `false` in the second
|
|
81
|
+
* container for a signature the first one recorded, and an emulated
|
|
82
|
+
* `putIfVersion` across two writers is a lost-update generator that reports
|
|
83
|
+
* `{ applied: true }` to both. A refusal you read once beats a correctness bug
|
|
84
|
+
* you never find.
|
|
85
|
+
*
|
|
86
|
+
* Pattern: Adapter (GoF) — `MemoryStore` onto `reasoningEngines.memories`,
|
|
87
|
+
* through the shared REST client in `adapters/google/aiPlatform.ts`.
|
|
88
|
+
*/
|
|
89
|
+
import type { MemoryEntry } from '../../memory/entry/index.js';
|
|
90
|
+
import type { MemoryIdentity } from '../../memory/identity/index.js';
|
|
91
|
+
import type { ListOptions, ListResult, MemoryStore, PutIfVersionResult, ScoredEntry, SearchOptions } from '../../memory/store/types.js';
|
|
92
|
+
import { type AiPlatformConnection } from '../google/aiPlatform.js';
|
|
93
|
+
/** The scope map an identity resolves to. Keys and values are both strings. */
|
|
94
|
+
export type MemoryScope = Readonly<Record<string, string>>;
|
|
95
|
+
/** Options for {@link memoryBankStore}. */
|
|
96
|
+
export interface MemoryBankStoreOptions extends AiPlatformConnection {
|
|
97
|
+
/**
|
|
98
|
+
* Map this library's identity tuple onto Memory Bank's `scope` — **the one
|
|
99
|
+
* decision that cannot be taken back.**
|
|
100
|
+
*
|
|
101
|
+
* The default is the full tuple:
|
|
102
|
+
*
|
|
103
|
+
* ```
|
|
104
|
+
* { tenant: '<tenant|_>', principal: '<principal|_>', conversation: '<conversationId>' }
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* which is the same isolation every other store in this library enforces
|
|
108
|
+
* (`identityNamespace` composes exactly these three), so agent code behaves
|
|
109
|
+
* identically whichever column it runs on. That consistency is why it is the
|
|
110
|
+
* default even though it is the NARROWEST useful choice.
|
|
111
|
+
*
|
|
112
|
+
* **What it costs, stated plainly.** Because scope matching is exact, a
|
|
113
|
+
* memory written under a conversation is retrievable only within that
|
|
114
|
+
* conversation. If what you want from a memory bank is "remember this person
|
|
115
|
+
* across their conversations" — which is usually the point — widen it here:
|
|
116
|
+
*
|
|
117
|
+
* ```ts
|
|
118
|
+
* scopeFor: (identity) => ({
|
|
119
|
+
* tenant: identity.tenant ?? '_',
|
|
120
|
+
* principal: identity.principal ?? '_',
|
|
121
|
+
* })
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* **And why it is worth getting right the first time.** `Memory.scope` is
|
|
125
|
+
* immutable. Memories already written keep the scope they were written with,
|
|
126
|
+
* and a later retrieval under a different convention will not find them —
|
|
127
|
+
* not with a warning, not with a partial match, but with an empty result
|
|
128
|
+
* that looks exactly like "this person has told us nothing". Changing the
|
|
129
|
+
* convention on a live bank means re-writing every memory in it.
|
|
130
|
+
*
|
|
131
|
+
* Values may not contain `*`; this adapter replaces any it is handed and
|
|
132
|
+
* refuses an empty scope outright, because a scope of `{}` is the one value
|
|
133
|
+
* that matches every other empty-scoped memory in the bank regardless of who
|
|
134
|
+
* wrote it.
|
|
135
|
+
*/
|
|
136
|
+
readonly scopeFor?: (identity: MemoryIdentity) => MemoryScope;
|
|
137
|
+
/**
|
|
138
|
+
* How long a memory lives, as a duration string the API accepts (`'86400s'`).
|
|
139
|
+
* Omit and memories do not expire.
|
|
140
|
+
*
|
|
141
|
+
* A `MemoryEntry.ttl` is a unix TIMESTAMP and this is a DURATION; the two
|
|
142
|
+
* are different quantities and the entry's own is honoured per write, so
|
|
143
|
+
* this is only the default for entries that name none.
|
|
144
|
+
*/
|
|
145
|
+
readonly ttl?: string;
|
|
146
|
+
/**
|
|
147
|
+
* How long a write waits for its long-running operation before refusing.
|
|
148
|
+
* Default {@link DEFAULT_OPERATION_TIMEOUT_MS} (30s).
|
|
149
|
+
*/
|
|
150
|
+
readonly operationTimeoutMs?: number;
|
|
151
|
+
/**
|
|
152
|
+
* How many rows a `list()` page carries when the caller names no limit.
|
|
153
|
+
* Default 20. The service's own ceiling is 100 and it silently coerces
|
|
154
|
+
* anything larger, so this adapter clamps rather than letting a request for
|
|
155
|
+
* 500 come back as 100 with no explanation.
|
|
156
|
+
*/
|
|
157
|
+
readonly pageSize?: number;
|
|
158
|
+
}
|
|
159
|
+
/** The service's own ceiling on a page or a top-k. Larger values are coerced. */
|
|
160
|
+
export declare const MAX_PAGE_SIZE = 100;
|
|
161
|
+
/**
|
|
162
|
+
* A `MemoryStore` over Vertex AI Memory Bank.
|
|
163
|
+
*
|
|
164
|
+
* **Status: contract-shaped and tested; awaiting field use.** Every call is
|
|
165
|
+
* exercised through an injected client and pinned against the really-installed
|
|
166
|
+
* SDK. None of it has yet answered a request from Google in a real project.
|
|
167
|
+
*/
|
|
168
|
+
export declare class MemoryBankStore implements MemoryStore {
|
|
169
|
+
/**
|
|
170
|
+
* **No.** `search()` exists here, but it is Memory Bank's own retrieval:
|
|
171
|
+
* Google embeds and ranks on its side, over the `fact` strings this store
|
|
172
|
+
* wrote, and never over an `embedding` handed to `put()`. Embeddings are not
|
|
173
|
+
* stored at all.
|
|
174
|
+
*
|
|
175
|
+
* Declared because a method's presence could not say that — and because the
|
|
176
|
+
* sibling column already paid for the lesson once, with a corpus that
|
|
177
|
+
* indexed, billed, reported success, and was unreachable forever.
|
|
178
|
+
*/
|
|
179
|
+
readonly supportsVectorSearch = false;
|
|
180
|
+
/**
|
|
181
|
+
* The query form this store takes: **words, not a vector.** `search()` reads
|
|
182
|
+
* {@link SearchOptions.text} and refuses by name without it. A retriever
|
|
183
|
+
* built over this store therefore needs no `Embedder`, and wiring one would
|
|
184
|
+
* be spend on a vector discarded on arrival.
|
|
185
|
+
*/
|
|
186
|
+
readonly ranksBy: "server-text";
|
|
187
|
+
private readonly memories;
|
|
188
|
+
private readonly scope;
|
|
189
|
+
private readonly scopeFor;
|
|
190
|
+
private readonly operationTimeoutMs;
|
|
191
|
+
private readonly pageSize;
|
|
192
|
+
private readonly defaultTtl;
|
|
193
|
+
private closed;
|
|
194
|
+
constructor(options: MemoryBankStoreOptions);
|
|
195
|
+
/**
|
|
196
|
+
* One memory by id.
|
|
197
|
+
*
|
|
198
|
+
* Two independent things keep this from reading somebody else's memory, and
|
|
199
|
+
* both are deliberate. The **address** carries the scope, so another
|
|
200
|
+
* identity's row for the same entry id is a different resource name that
|
|
201
|
+
* simply is not there. And the **stored scope is re-checked on the way
|
|
202
|
+
* back**, because a resource name addresses a memory directly and a `get`
|
|
203
|
+
* alone would happily read another tenant's row for anyone who could guess a
|
|
204
|
+
* name. A memory whose scope is not this identity's answers `null` — the same
|
|
205
|
+
* `null` a missing one answers, because "exists but not yours" is an oracle
|
|
206
|
+
* for which ids are real.
|
|
207
|
+
*/
|
|
208
|
+
get<T = unknown>(identity: MemoryIdentity, id: string): Promise<MemoryEntry<T> | null>;
|
|
209
|
+
/**
|
|
210
|
+
* A page of this identity's memories, in no particular order.
|
|
211
|
+
*
|
|
212
|
+
* It rides `retrieve` with `simpleRetrievalParams` rather than `memories.list`
|
|
213
|
+
* — deliberately. `list` filters with AIP-160 over the resource's own fields,
|
|
214
|
+
* and whether that filter language can express an exact scope match is not
|
|
215
|
+
* something this adapter is willing to guess at for the call that decides
|
|
216
|
+
* which memories a caller can see. `retrieve` takes the scope as a structured
|
|
217
|
+
* field with semantics the SDK states outright, so the isolation is the
|
|
218
|
+
* service's rather than a filter string's.
|
|
219
|
+
*
|
|
220
|
+
* `tiers` filtering is applied to what comes back, since a tier is this
|
|
221
|
+
* library's own metadata and not something the service ranks on.
|
|
222
|
+
*/
|
|
223
|
+
list<T = unknown>(identity: MemoryIdentity, options?: ListOptions): Promise<ListResult<T>>;
|
|
224
|
+
/**
|
|
225
|
+
* Memory Bank's own semantic retrieval — **text in, and the ranking trap
|
|
226
|
+
* handled rather than passed on.**
|
|
227
|
+
*
|
|
228
|
+
* ── It takes WORDS, not the vector ───────────────────────────────────────
|
|
229
|
+
* Google embeds and ranks server-side, so the `query` vector this method is
|
|
230
|
+
* handed cannot be sent anywhere. The query it needs travels in
|
|
231
|
+
* {@link SearchOptions.text}, and omitting it is refused by name — returning
|
|
232
|
+
* `[]` would read as "no matches" when it means "wrong query form".
|
|
233
|
+
*
|
|
234
|
+
* ── The score, and what this adapter refuses to pretend ──────────────────
|
|
235
|
+
* The service reports a **distance**, in its own words "smaller values
|
|
236
|
+
* indicate more similar memories". The port's score is a cosine similarity,
|
|
237
|
+
* where higher is closer. Two things follow, and both are decisions:
|
|
238
|
+
*
|
|
239
|
+
* • The distance is **converted**, never forwarded: `score = 1 / (1 + d)`,
|
|
240
|
+
* which is strictly decreasing in `d`, so **the ordering is right** —
|
|
241
|
+
* the closest memory has the highest score, which is the whole point.
|
|
242
|
+
* The raw distance is carried on `entry.metadata.distance` so nothing is
|
|
243
|
+
* hidden and a caller who knows the metric can do better.
|
|
244
|
+
*
|
|
245
|
+
* • **`minScore` is REFUSED by name**, because that number is calibrated
|
|
246
|
+
* for a cosine similarity and this scale is not one. Silently applying a
|
|
247
|
+
* cosine threshold to a converted distance is precisely the failure this
|
|
248
|
+
* library refuses elsewhere: a number that READS like a similarity, in
|
|
249
|
+
* the right range, that no threshold and no eyeball can separate from a
|
|
250
|
+
* real one. The sibling S3 Vectors adapter refuses a non-cosine index
|
|
251
|
+
* for the same reason; here the metric is Google's and cannot be
|
|
252
|
+
* changed, so the threshold is what goes rather than the store.
|
|
253
|
+
*
|
|
254
|
+
* ── One more thing the service requires ──────────────────────────────────
|
|
255
|
+
* Similarity search only works if the reasoning engine was configured with a
|
|
256
|
+
* similarity-search config. Without it the service refuses the call, and
|
|
257
|
+
* that refusal is passed through with its status — it is a setup fact, not a
|
|
258
|
+
* bug in the query.
|
|
259
|
+
*
|
|
260
|
+
* @throws when `options.text` is absent, or `options.minScore` is present.
|
|
261
|
+
*/
|
|
262
|
+
search<T = unknown>(identity: MemoryIdentity, query: readonly number[], options?: SearchOptions): Promise<readonly ScoredEntry<T>[]>;
|
|
263
|
+
/**
|
|
264
|
+
* Write one memory, waiting for the service to say it landed.
|
|
265
|
+
*
|
|
266
|
+
* ── Read-then-write, and what the read is FOR ────────────────────────────
|
|
267
|
+
* This costs one `get` before the write, and that read is not an
|
|
268
|
+
* optimisation — it is the tenant check. A `patch` names a resource
|
|
269
|
+
* directly and the service does not ask whose it is, so a patch sent
|
|
270
|
+
* without looking is a write this adapter cannot promise landed on its own
|
|
271
|
+
* row. The address already carries the scope (see the module header), so
|
|
272
|
+
* the row under this name is ours in every ordinary run; the read is what
|
|
273
|
+
* turns "ordinary" into "checked", and what makes the one case where it is
|
|
274
|
+
* NOT ours a refusal you can read instead of a fact one tenant wrote into
|
|
275
|
+
* another tenant's memory.
|
|
276
|
+
*
|
|
277
|
+
* What the read finds decides the rest: an existing row of ours is patched,
|
|
278
|
+
* an absent one is created, and a row that is somebody else's is refused by
|
|
279
|
+
* name. The `create` race — two writers, neither of whom saw a row — is
|
|
280
|
+
* caught as `ALREADY EXISTS` and folded back into the same checked patch.
|
|
281
|
+
*/
|
|
282
|
+
put<T = unknown>(identity: MemoryIdentity, entry: MemoryEntry<T>): Promise<void>;
|
|
283
|
+
/**
|
|
284
|
+
* Sequential, not batched: the service has no batch-write operation, and
|
|
285
|
+
* each write is a long-running operation that has to be waited on
|
|
286
|
+
* individually. An empty batch is a no-op and costs no round trip, which
|
|
287
|
+
* callers rely on.
|
|
288
|
+
*/
|
|
289
|
+
putMany<T = unknown>(identity: MemoryIdentity, entries: readonly MemoryEntry<T>[]): Promise<void>;
|
|
290
|
+
/**
|
|
291
|
+
* Remove one memory.
|
|
292
|
+
*
|
|
293
|
+
* Scope-checked first, for the reason {@link get} spells out: a resource
|
|
294
|
+
* name addresses a row directly, and a delete that skipped the check would
|
|
295
|
+
* let anyone who could guess an id remove another tenant's memory. A memory
|
|
296
|
+
* that is not this identity's is left alone and reported as nothing to do —
|
|
297
|
+
* the same answer a missing one gets.
|
|
298
|
+
*/
|
|
299
|
+
delete(identity: MemoryIdentity, id: string): Promise<void>;
|
|
300
|
+
/**
|
|
301
|
+
* GDPR — every memory for this identity, gone.
|
|
302
|
+
*
|
|
303
|
+
* Paginated retrieve-then-delete, and **deliberately not `memories.purge`**,
|
|
304
|
+
* for two reasons that are both about not being silently wrong on the one
|
|
305
|
+
* operation where that matters most:
|
|
306
|
+
*
|
|
307
|
+
* 1. `PurgeMemoriesRequest.force` defaults to **false**, which the service
|
|
308
|
+
* documents as "the purge request will be validated but not executed".
|
|
309
|
+
* A forget built on it and written without that flag would report
|
|
310
|
+
* success and delete nothing — a compliance failure that looks exactly
|
|
311
|
+
* like a working erasure.
|
|
312
|
+
* 2. Purge selects rows with an AIP-160 filter STRING, and whether that
|
|
313
|
+
* language can express an exact scope match is not verified. A filter
|
|
314
|
+
* that under-matches leaves data behind; one that over-matches deletes
|
|
315
|
+
* somebody else's. Neither is a guess worth making here.
|
|
316
|
+
*
|
|
317
|
+
* The scoped retrieve has semantics the SDK states outright, so that is what
|
|
318
|
+
* this uses. It costs one delete per memory, which is the right price.
|
|
319
|
+
*/
|
|
320
|
+
forget(identity: MemoryIdentity): Promise<void>;
|
|
321
|
+
/**
|
|
322
|
+
* @throws always — this service has no compare-and-set.
|
|
323
|
+
* @see the module header for why this refuses where the sibling adapter
|
|
324
|
+
* emulates.
|
|
325
|
+
*/
|
|
326
|
+
putIfVersion<T = unknown>(_identity: MemoryIdentity, entry: MemoryEntry<T>, expectedVersion: number): Promise<PutIfVersionResult>;
|
|
327
|
+
/** @throws always — this service has no recognition set. */
|
|
328
|
+
seen(_identity: MemoryIdentity, signature: string): Promise<boolean>;
|
|
329
|
+
/** @throws always — the write side of a recognition set this service does not have. */
|
|
330
|
+
recordSignature(_identity: MemoryIdentity, signature: string): Promise<void>;
|
|
331
|
+
/** @throws always — this service has no feedback primitive. */
|
|
332
|
+
feedback(_identity: MemoryIdentity, id: string, _usefulness: number): Promise<void>;
|
|
333
|
+
/** @throws always — the read side of feedback this service does not record. */
|
|
334
|
+
getFeedback(_identity: MemoryIdentity, id: string): Promise<{
|
|
335
|
+
average: number;
|
|
336
|
+
count: number;
|
|
337
|
+
} | null>;
|
|
338
|
+
/**
|
|
339
|
+
* Stop using this store. Idempotent and final. Nothing is torn down on
|
|
340
|
+
* Google's side — the memories outlive this process, which is the point.
|
|
341
|
+
*/
|
|
342
|
+
close(): Promise<void>;
|
|
343
|
+
/** Where this identity's copy of `id` lives. See the module header. */
|
|
344
|
+
private nameOf;
|
|
345
|
+
/** One memory by resource name, or `undefined` when there is none. */
|
|
346
|
+
private fetch;
|
|
347
|
+
/**
|
|
348
|
+
* Patch the row at `name` if it exists AND is this scope's; answer `false`
|
|
349
|
+
* when there is nothing there to patch.
|
|
350
|
+
*
|
|
351
|
+
* A row that exists under somebody else's scope is REFUSED rather than
|
|
352
|
+
* written. It should be unreachable — the address carries the scope — so
|
|
353
|
+
* reaching it means the fingerprint collided or the bank was written by
|
|
354
|
+
* another tool under a name of ours, and both of those are facts an operator
|
|
355
|
+
* has to be told rather than have resolved in favour of the last writer.
|
|
356
|
+
*/
|
|
357
|
+
private overwrite;
|
|
358
|
+
private ensureOpen;
|
|
359
|
+
private wait;
|
|
360
|
+
/** Keep an already-sanitized refusal; sanitize anything else. */
|
|
361
|
+
private asFailure;
|
|
362
|
+
/** The identity's scope, checked for the two values that would break isolation. */
|
|
363
|
+
private resolveScope;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* A `MemoryStore` over Vertex AI Memory Bank.
|
|
367
|
+
*
|
|
368
|
+
* @example Per-person memory that survives a conversation ending
|
|
369
|
+
* const store = memoryBankStore({
|
|
370
|
+
* project: 'my-project',
|
|
371
|
+
* location: 'us-central1',
|
|
372
|
+
* reasoningEngine: '1234567890',
|
|
373
|
+
* scopeFor: (id) => ({ tenant: id.tenant ?? '_', principal: id.principal ?? '_' }),
|
|
374
|
+
* });
|
|
375
|
+
*
|
|
376
|
+
* const hits = await store.search(identity, [], { text: 'what does she prefer?', k: 5 });
|
|
377
|
+
*/
|
|
378
|
+
export declare function memoryBankStore(options: MemoryBankStoreOptions): MemoryBankStore;
|
|
379
|
+
/**
|
|
380
|
+
* Distance → a score whose ORDER is right.
|
|
381
|
+
*
|
|
382
|
+
* `1 / (1 + d)` is strictly decreasing on `d >= 0`, lands in `(0, 1]`, and is
|
|
383
|
+
* exactly 1 at distance 0. It is **not** a cosine similarity and this adapter
|
|
384
|
+
* never says it is — see {@link MemoryBankStore.search} for why `minScore` is
|
|
385
|
+
* refused rather than measured against it.
|
|
386
|
+
*
|
|
387
|
+
* A row with no distance is a simple retrieval, which does no ranking at all;
|
|
388
|
+
* `0` is the honest score for "this was not ranked", and it sorts last.
|
|
389
|
+
*/
|
|
390
|
+
export declare function scoreFromDistance(distance: number | null | undefined): number;
|