agentfootprint 9.28.0 → 9.30.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.
Files changed (101) hide show
  1. package/README.md +3 -2
  2. package/dist/adapters/google/aiPlatform.js +23 -1
  3. package/dist/adapters/google/aiPlatform.js.map +1 -1
  4. package/dist/adapters/hosting/googleAgentEngine.js +180 -61
  5. package/dist/adapters/hosting/googleAgentEngine.js.map +1 -1
  6. package/dist/adapters/identity/google.js +18 -4
  7. package/dist/adapters/identity/google.js.map +1 -1
  8. package/dist/adapters/llm/GeminiProvider.js +198 -36
  9. package/dist/adapters/llm/GeminiProvider.js.map +1 -1
  10. package/dist/adapters/llm/OpenAIProvider.js +66 -2
  11. package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
  12. package/dist/adapters/llm/googleGenAI.js +155 -8
  13. package/dist/adapters/llm/googleGenAI.js.map +1 -1
  14. package/dist/adapters/memory/memoryBank.js +250 -6
  15. package/dist/adapters/memory/memoryBank.js.map +1 -1
  16. package/dist/adapters/types.js.map +1 -1
  17. package/dist/artifacts/gcsArtifacts.js +21 -5
  18. package/dist/artifacts/gcsArtifacts.js.map +1 -1
  19. package/dist/embedders/index.js +8 -6
  20. package/dist/embedders/index.js.map +1 -1
  21. package/dist/esm/adapters/google/aiPlatform.d.ts +44 -0
  22. package/dist/esm/adapters/google/aiPlatform.js +23 -1
  23. package/dist/esm/adapters/google/aiPlatform.js.map +1 -1
  24. package/dist/esm/adapters/hosting/googleAgentEngine.d.ts +104 -18
  25. package/dist/esm/adapters/hosting/googleAgentEngine.js +179 -60
  26. package/dist/esm/adapters/hosting/googleAgentEngine.js.map +1 -1
  27. package/dist/esm/adapters/identity/google.d.ts +18 -4
  28. package/dist/esm/adapters/identity/google.js +18 -4
  29. package/dist/esm/adapters/identity/google.js.map +1 -1
  30. package/dist/esm/adapters/llm/GeminiProvider.d.ts +96 -15
  31. package/dist/esm/adapters/llm/GeminiProvider.js +199 -37
  32. package/dist/esm/adapters/llm/GeminiProvider.js.map +1 -1
  33. package/dist/esm/adapters/llm/OpenAIProvider.d.ts +34 -2
  34. package/dist/esm/adapters/llm/OpenAIProvider.js +66 -2
  35. package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
  36. package/dist/esm/adapters/llm/googleGenAI.d.ts +105 -4
  37. package/dist/esm/adapters/llm/googleGenAI.js +152 -7
  38. package/dist/esm/adapters/llm/googleGenAI.js.map +1 -1
  39. package/dist/esm/adapters/memory/memoryBank.d.ts +42 -3
  40. package/dist/esm/adapters/memory/memoryBank.js +249 -5
  41. package/dist/esm/adapters/memory/memoryBank.js.map +1 -1
  42. package/dist/esm/adapters/types.d.ts +27 -0
  43. package/dist/esm/adapters/types.js.map +1 -1
  44. package/dist/esm/artifacts/gcsArtifacts.d.ts +21 -5
  45. package/dist/esm/artifacts/gcsArtifacts.js +21 -5
  46. package/dist/esm/artifacts/gcsArtifacts.js.map +1 -1
  47. package/dist/esm/core/agent/types.d.ts +1 -0
  48. package/dist/esm/embedders/index.js +9 -7
  49. package/dist/esm/embedders/index.js.map +1 -1
  50. package/dist/esm/events/payloads.d.ts +22 -0
  51. package/dist/esm/hosting-providers.d.ts +4 -2
  52. package/dist/esm/hosting-providers.js +4 -2
  53. package/dist/esm/hosting-providers.js.map +1 -1
  54. package/dist/esm/memory-providers.d.ts +1 -1
  55. package/dist/esm/memory-providers.js +4 -2
  56. package/dist/esm/memory-providers.js.map +1 -1
  57. package/dist/esm/providers.js.map +1 -1
  58. package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.js +5 -1
  59. package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.js.map +1 -1
  60. package/dist/esm/recorders/observability/commentary/commentaryTemplates.js +44 -3
  61. package/dist/esm/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
  62. package/dist/hosting-providers.js +5 -2
  63. package/dist/hosting-providers.js.map +1 -1
  64. package/dist/memory-providers.js +5 -2
  65. package/dist/memory-providers.js.map +1 -1
  66. package/dist/providers.js.map +1 -1
  67. package/dist/recorders/observability/AgentThinkingTraceRecorder.js +5 -1
  68. package/dist/recorders/observability/AgentThinkingTraceRecorder.js.map +1 -1
  69. package/dist/recorders/observability/commentary/commentaryTemplates.js +44 -3
  70. package/dist/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
  71. package/dist/types/adapters/google/aiPlatform.d.ts +44 -0
  72. package/dist/types/adapters/google/aiPlatform.d.ts.map +1 -1
  73. package/dist/types/adapters/hosting/googleAgentEngine.d.ts +104 -18
  74. package/dist/types/adapters/hosting/googleAgentEngine.d.ts.map +1 -1
  75. package/dist/types/adapters/identity/google.d.ts +18 -4
  76. package/dist/types/adapters/identity/google.d.ts.map +1 -1
  77. package/dist/types/adapters/llm/GeminiProvider.d.ts +96 -15
  78. package/dist/types/adapters/llm/GeminiProvider.d.ts.map +1 -1
  79. package/dist/types/adapters/llm/OpenAIProvider.d.ts +34 -2
  80. package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
  81. package/dist/types/adapters/llm/googleGenAI.d.ts +105 -4
  82. package/dist/types/adapters/llm/googleGenAI.d.ts.map +1 -1
  83. package/dist/types/adapters/memory/memoryBank.d.ts +42 -3
  84. package/dist/types/adapters/memory/memoryBank.d.ts.map +1 -1
  85. package/dist/types/adapters/types.d.ts +27 -0
  86. package/dist/types/adapters/types.d.ts.map +1 -1
  87. package/dist/types/artifacts/gcsArtifacts.d.ts +21 -5
  88. package/dist/types/artifacts/gcsArtifacts.d.ts.map +1 -1
  89. package/dist/types/core/agent/types.d.ts +1 -0
  90. package/dist/types/core/agent/types.d.ts.map +1 -1
  91. package/dist/types/embedders/index.d.ts.map +1 -1
  92. package/dist/types/events/payloads.d.ts +22 -0
  93. package/dist/types/events/payloads.d.ts.map +1 -1
  94. package/dist/types/hosting-providers.d.ts +4 -2
  95. package/dist/types/hosting-providers.d.ts.map +1 -1
  96. package/dist/types/memory-providers.d.ts +1 -1
  97. package/dist/types/memory-providers.d.ts.map +1 -1
  98. package/dist/types/providers.d.ts.map +1 -1
  99. package/dist/types/recorders/observability/AgentThinkingTraceRecorder.d.ts.map +1 -1
  100. package/dist/types/recorders/observability/commentary/commentaryTemplates.d.ts.map +1 -1
  101. package/package.json +1 -1
@@ -28,10 +28,63 @@
28
28
  * `test/adapters/google/google-surface-pin.test.ts`. It is not `v1`. Callers
29
29
  * who need a specific version pass `apiVersion`; callers who do not at least
30
30
  * find the truth stated instead of assuming a GA path.
31
+ *
32
+ * ─── The key can be a CALLBACK, and why (9.29.0) ────────────────────
33
+ *
34
+ * `GoogleGenAIOptions.apiKey` is `string` on the installed SDK (@google/genai
35
+ * 2.16.0 `genai.d.ts`) — one value, fixed at construction. That is fine for an
36
+ * AI Studio key, which does not expire, and wrong for every credential that
37
+ * does: a Vertex OAuth access token lives about an hour, and a key pulled from
38
+ * a secret manager is rotated on somebody else's schedule.
39
+ *
40
+ * An independent field trial on live GCP measured exactly that boundary: an
41
+ * OAuth token that worked returned HTTP 401 once expired, with no place in the
42
+ * options to put a fresh one ("Part 2B — ADC refresh versus OpenAI-compatible
43
+ * OAuth"). So `apiKey` widens to `string | (() => string | Promise<string>)`,
44
+ * and the refresh boundary is stated rather than implied:
45
+ *
46
+ * • The callback runs ONCE PER REQUEST, before the request is built.
47
+ * • The SDK client is REBUILT only when the returned string differs from the
48
+ * one already in hand — a callback that returns a cached token costs one
49
+ * function call and nothing else.
50
+ * • A stream keeps the key it STARTED with. The boundary is the call, not
51
+ * the chunk; nothing here can re-authenticate a socket that is already
52
+ * open.
53
+ * • Vertex needs none of this. ADC refreshes itself, which the same trial
54
+ * verified by forcing an in-memory expiry and completing the next call.
31
55
  */
32
56
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.resolveGoogleGenAIClient = void 0;
57
+ exports.createGoogleGenAIClientResolver = exports.resolveGoogleGenAIClient = exports.resolveGoogleDoor = void 0;
34
58
  const lazyRequire_js_1 = require("../../lib/lazyRequire.js");
59
+ /** An empty environment variable is not a setting — see `resolveGoogleGenAIClient`. */
60
+ const set = (value) => value !== undefined && value.trim().length > 0 ? value : undefined;
61
+ /** The env this module reads, or `{}` off-Node. */
62
+ const environment = () => (typeof process !== 'undefined' ? process.env : {});
63
+ /**
64
+ * Which door these options open.
65
+ *
66
+ * The order mirrors `resolveGoogleGenAIClient` exactly, because a door that
67
+ * disagreed with the client that gets built is worse than no door at all.
68
+ *
69
+ * @param readEnv `false` when the caller injected a `_client`. A double talks
70
+ * to no service, so the ambient `GEMINI_API_KEY` of whoever is running
71
+ * the tests describes a door that will never be dialled — reading it
72
+ * would make an offline suite depend on a developer's shell.
73
+ */
74
+ function resolveGoogleDoor(options, readEnv = true) {
75
+ if (options.vertexai === true)
76
+ return 'vertex';
77
+ if (options.vertexai === false)
78
+ return 'gemini-api';
79
+ const env = readEnv ? environment() : {};
80
+ if ((set(options.project) ?? set(env.GOOGLE_CLOUD_PROJECT)) !== undefined)
81
+ return 'vertex';
82
+ const key = (typeof options.apiKey === 'function' ? 'callback' : set(options.apiKey)) ??
83
+ set(env.GEMINI_API_KEY) ??
84
+ set(env.GOOGLE_API_KEY);
85
+ return key !== undefined ? 'gemini-api' : 'vertex';
86
+ }
87
+ exports.resolveGoogleDoor = resolveGoogleDoor;
35
88
  /**
36
89
  * Build (or accept) a `GoogleGenAI` client.
37
90
  *
@@ -43,14 +96,18 @@ const lazyRequire_js_1 = require("../../lib/lazyRequire.js");
43
96
  * @param factory the public name to put in refusals — `'gemini'`,
44
97
  * `'geminiEmbedder'`. A message that names the wrong factory
45
98
  * sends the reader to the wrong line of their own code.
99
+ * @param apiKey the key STRING for this build. Callers holding a callback
100
+ * resolve it first (see {@link createGoogleGenAIClientResolver});
101
+ * a function reaching the SDK's `apiKey` field would be sent
102
+ * as `[object Function]` and fail as an auth error.
46
103
  * @throws when neither a project nor an API key is resolvable; when
47
104
  * `vertexai: true` is asked for without a project; and when
48
105
  * `@google/genai` is not installed.
49
106
  */
50
- function resolveGoogleGenAIClient(options, factory, injected) {
107
+ function resolveGoogleGenAIClient(options, factory, injected, apiKey) {
51
108
  if (injected)
52
109
  return injected;
53
- const env = (typeof process !== 'undefined' ? process.env : {});
110
+ const env = environment();
54
111
  // Read HERE only to decide whether there is enough configuration to build
55
112
  // anything at all. The values are never copied into the constructor, so the
56
113
  // SDK stays the single resolver of its own environment variables — one place
@@ -58,11 +115,13 @@ function resolveGoogleGenAIClient(options, factory, injected) {
58
115
  // An EMPTY variable is not a setting. `GOOGLE_CLOUD_PROJECT=` in a shell or a
59
116
  // CI matrix is how a project comes to be "present" and unusable — the guards
60
117
  // below would pass and the SDK would fail on the first call instead.
61
- const set = (value) => value !== undefined && value.trim().length > 0 ? value : undefined;
62
118
  const project = set(options.project) ?? set(env.GOOGLE_CLOUD_PROJECT);
63
- const apiKey = set(options.apiKey) ?? set(env.GEMINI_API_KEY) ?? set(env.GOOGLE_API_KEY);
119
+ const resolvedKey = set(apiKey) ??
120
+ (typeof options.apiKey === 'string' ? set(options.apiKey) : undefined) ??
121
+ set(env.GEMINI_API_KEY) ??
122
+ set(env.GOOGLE_API_KEY);
64
123
  const vertexai = options.vertexai ?? (project !== undefined ? true : undefined);
65
- if (vertexai !== false && project === undefined && apiKey === undefined) {
124
+ if (vertexai !== false && project === undefined && resolvedKey === undefined) {
66
125
  throw new Error(`${factory}: no Google project and no API key — this factory cannot tell which service ` +
67
126
  'you meant, and the SDK would warn on stderr, construct anyway, and fail on the first ' +
68
127
  'call with something that reads like a network problem.\n' +
@@ -93,12 +152,15 @@ function resolveGoogleGenAIClient(options, factory, injected) {
93
152
  'are built against @google/genai 2.x — update the package.');
94
153
  }
95
154
  // Only what was ASKED for goes on the wire; everything omitted is left to the
96
- // SDK's own environment resolution.
155
+ // SDK's own environment resolution. The key is the one exception: the
156
+ // CALLBACK form has already been called by the time we get here, so what
157
+ // travels is the string it answered with — never the function.
158
+ const key = apiKey ?? (typeof options.apiKey === 'string' ? options.apiKey : undefined);
97
159
  return new GoogleGenAI({
98
160
  ...(vertexai !== undefined && { vertexai }),
99
161
  ...(options.project !== undefined && { project: options.project }),
100
162
  ...(options.location !== undefined && { location: options.location }),
101
- ...(options.apiKey !== undefined && { apiKey: options.apiKey }),
163
+ ...(key !== undefined && { apiKey: key }),
102
164
  ...(options.apiVersion !== undefined && { apiVersion: options.apiVersion }),
103
165
  ...(options.googleAuthOptions !== undefined && {
104
166
  googleAuthOptions: options.googleAuthOptions,
@@ -106,4 +168,89 @@ function resolveGoogleGenAIClient(options, factory, injected) {
106
168
  });
107
169
  }
108
170
  exports.resolveGoogleGenAIClient = resolveGoogleGenAIClient;
171
+ /**
172
+ * The client seam every Google adapter calls through — one per request.
173
+ *
174
+ * Three paths, and only the third one is new:
175
+ *
176
+ * 1. **`_client` injected** — the double, always, no SDK, no environment.
177
+ * Any `apiKey` still rides along on the lease so redaction tests can
178
+ * prove a secret never reaches an error message.
179
+ * 2. **`apiKey` a string (or absent)** — the client is built ONCE. With
180
+ * `eager`, it is built at factory time, so a missing peer dependency and
181
+ * an unanswerable door are still refused where the consumer typed the
182
+ * call rather than on their first request.
183
+ * 3. **`apiKey` a callback** — called before every request. The client is
184
+ * rebuilt only when the answer CHANGED, so a cached token costs one
185
+ * function call. Construction cannot be eager here: calling a consumer's
186
+ * credential provider from a factory would fetch a token nobody asked
187
+ * for yet, and possibly before their own setup ran.
188
+ *
189
+ * @param eager build now (path 2 only), preserving construction-time refusals.
190
+ */
191
+ function createGoogleGenAIClientResolver(options, factory, injected, eager = false) {
192
+ const source = options.apiKey;
193
+ if (injected) {
194
+ // A double stands in for the SDK CLIENT, not for the credential. So a
195
+ // callback is still called per request here: it is the only way a test can
196
+ // watch a key rotate, and the only way redaction can be proved against the
197
+ // key that is actually in force rather than the one at construction.
198
+ if (typeof source !== 'function') {
199
+ const lease = {
200
+ client: injected,
201
+ ...(source !== undefined && { apiKey: source }),
202
+ };
203
+ return async () => lease;
204
+ }
205
+ return async () => ({ client: injected, apiKey: await resolveKey(source, factory) });
206
+ }
207
+ if (typeof source !== 'function') {
208
+ let built = eager
209
+ ? resolveGoogleGenAIClient(options, factory, undefined)
210
+ : undefined;
211
+ return async () => {
212
+ built ??= resolveGoogleGenAIClient(options, factory, undefined);
213
+ return { client: built, ...(source !== undefined && { apiKey: source }) };
214
+ };
215
+ }
216
+ // The callback path. `lastKey` is held so the SDK client survives a callback
217
+ // that keeps answering the same thing — which is what a well-behaved token
218
+ // cache does on all but one call in a thousand.
219
+ let lastKey;
220
+ let built;
221
+ return async () => {
222
+ const answer = await resolveKey(source, factory);
223
+ if (built === undefined || answer !== lastKey) {
224
+ built = resolveGoogleGenAIClient(options, factory, undefined, answer);
225
+ lastKey = answer;
226
+ }
227
+ return { client: built, apiKey: answer };
228
+ };
229
+ }
230
+ exports.createGoogleGenAIClientResolver = createGoogleGenAIClientResolver;
231
+ /** Call the credential callback and insist on something usable. */
232
+ async function resolveKey(source, factory) {
233
+ const answer = await source();
234
+ if (typeof answer === 'string' && answer.trim().length > 0)
235
+ return answer;
236
+ // The value is NOT quoted back. It is a credential when it is right, and it
237
+ // is whatever the consumer's provider returned when it is wrong; a message
238
+ // that printed it would be the one place this library leaks one.
239
+ throw new Error(`${factory}: the \`apiKey\` callback returned ${describeKey(answer)}, and a key has to be a ` +
240
+ 'non-empty string.\n' +
241
+ ' The callback is called before every request, so this is a live credential failure, ' +
242
+ 'not a configuration one — a token fetch that failed usually throws rather than returning ' +
243
+ 'nothing.\n' +
244
+ ` Fix: return the token, or throw from the callback so ${factory} can report why.`);
245
+ }
246
+ /** What came back, said without saying it. */
247
+ function describeKey(value) {
248
+ if (typeof value === 'string')
249
+ return 'an empty string';
250
+ if (value === null)
251
+ return 'null';
252
+ if (value === undefined)
253
+ return 'undefined';
254
+ return `a ${typeof value}`;
255
+ }
109
256
  //# sourceMappingURL=googleGenAI.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"googleGenAI.js","sourceRoot":"","sources":["../../../src/adapters/llm/googleGenAI.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"googleGenAI.js","sourceRoot":"","sources":["../../../src/adapters/llm/googleGenAI.ts"],"names":[],"mappings":"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"}
@@ -65,6 +65,22 @@
65
65
  * before every overwrite — so even an address collision is refused rather than
66
66
  * written through.
67
67
  *
68
+ * ── The retrieved NAME is not the name you wrote ────────────────────────────
69
+ * A live field trial on the raw service found this and it is worth stating,
70
+ * because it is exactly the assumption an adapter is tempted to make: `create`
71
+ * and `list` came back with the caller-chosen memory ids, while SIMILARITY
72
+ * RETRIEVAL answered with generated numeric resource names for the very same
73
+ * facts (FINDINGS "Agent Runtime Memory Bank"). Anything reading an entry id
74
+ * out of `memory.name` would therefore work perfectly on `list()` and hand back
75
+ * unusable ids from `search()` — ids that no `get()` or `delete()` could find.
76
+ *
77
+ * This adapter never does that: `toEntry` reads the id from the metadata this
78
+ * library wrote, and the resource name is carried only as
79
+ * `entry.metadata.resourceName`, for looking at. The same trial also confirmed
80
+ * exact-match scope semantics (a partial `{tenant}` scope retrieved nothing)
81
+ * and the distance-not-similarity ranking that {@link MemoryBankStore.search}
82
+ * converts.
83
+ *
68
84
  * ── Writes are long-running operations ──────────────────────────────────────
69
85
  * `create`, `patch` and `delete` all answer with an Operation rather than the
70
86
  * resource — verified against the installed SDK's own return types. Every
@@ -88,7 +104,7 @@
88
104
  * through the shared REST client in `adapters/google/aiPlatform.ts`.
89
105
  */
90
106
  Object.defineProperty(exports, "__esModule", { value: true });
91
- exports.scoreFromDistance = exports.memoryBankStore = exports.MemoryBankStore = exports.MAX_PAGE_SIZE = void 0;
107
+ exports.scoreFromDistance = exports.memoryBankStore = exports.MemoryBankStore = exports.MAX_PAGE_SIZE = exports.MAX_CARRIED_JSON = void 0;
92
108
  const aiPlatform_js_1 = require("../google/aiPlatform.js");
93
109
  const ADAPTER = 'memoryBankStore';
94
110
  /**
@@ -107,7 +123,44 @@ const META = {
107
123
  updatedAt: 'agentfootprint_updated_at',
108
124
  tier: 'agentfootprint_tier',
109
125
  json: 'agentfootprint_json',
126
+ /** {@link MemoryEntry.source}, verbatim, as JSON. See {@link MAX_CARRIED_JSON}. */
127
+ source: 'agentfootprint_source',
128
+ /** {@link MemoryEntry.metadata} the CALLER wrote, verbatim, as JSON. */
129
+ meta: 'agentfootprint_metadata',
130
+ /** {@link MemoryEntry.decayPolicy}, as JSON — retrieval ranking depends on it. */
131
+ decay: 'agentfootprint_decay',
110
132
  };
133
+ /**
134
+ * The metadata keys this adapter GENERATES on the way out, which therefore
135
+ * cannot also be caller metadata.
136
+ *
137
+ * They are read-side facts about the row, not stored data: `source` names the
138
+ * backend, `resourceName` is the Vertex name, `distance` is the raw retrieval
139
+ * distance. Round-tripping an entry this store handed back must not fail, and
140
+ * a caller's own value under one of these names must not be silently replaced
141
+ * — see {@link splitMetadata} for how those two are told apart.
142
+ */
143
+ const GENERATED_METADATA = ['source', 'resourceName', 'distance'];
144
+ /**
145
+ * What a Vertex resource name for a memory looks like:
146
+ * `projects/<p>/locations/<l>/reasoningEngines/<e>/memories/<resource id>`.
147
+ *
148
+ * Used as the SHAPE half of recognising this adapter's own `resourceName` on the
149
+ * way back in — never as a parser. Nothing reads an id out of a resource name
150
+ * here (the module header says why); this only answers "could this string be one
151
+ * of ours?".
152
+ */
153
+ const RESOURCE_NAME = /^projects\/.+\/memories\/[^/]+$/;
154
+ /**
155
+ * The most JSON one carried field may be, in characters.
156
+ *
157
+ * Memory Bank metadata values are typed scalars and this column has NOT
158
+ * measured the service's own ceiling on a string one, so the bound is this
159
+ * adapter's own and says so where it refuses. It is a refusal rather than a
160
+ * truncation on purpose: provenance that came back shortened would be
161
+ * provenance nobody could tell was shortened.
162
+ */
163
+ exports.MAX_CARRIED_JSON = 8_192;
111
164
  /** The service's own ceiling on a page or a top-k. Larger values are coerced. */
112
165
  exports.MAX_PAGE_SIZE = 100;
113
166
  /** What a `list()` page carries when nothing was asked for. */
@@ -115,9 +168,22 @@ const DEFAULT_PAGE_SIZE = 20;
115
168
  /**
116
169
  * A `MemoryStore` over Vertex AI Memory Bank.
117
170
  *
118
- * **Status: contract-shaped and tested; awaiting field use.** Every call is
119
- * exercised through an injected client and pinned against the really-installed
120
- * SDK. None of it has yet answered a request from Google in a real project.
171
+ * **Status: field-validated on the data plane (2026-08-14).** An independent
172
+ * trial ran THIS class against a real Memory Bank and every one of these
173
+ * answered a live request: the honest `supportsVectorSearch: false` /
174
+ * `ranksBy: 'server-text'` declarations; cross-conversation recall under a
175
+ * widened `scopeFor`; two identities using the SAME entry id without collision
176
+ * or disclosure; string and structured values; opaque pagination cursors; tier
177
+ * filtering; text similarity that found the right marker, excluded the other
178
+ * identity, returned finite distances and converted them to correctly ORDERED
179
+ * scores; overwrite advancing value and version; a scoped delete leaving the
180
+ * other identity intact; `forget()` erasing across the widened scope; and the
181
+ * five unsupported operations refusing by name rather than pretending.
182
+ *
183
+ * The same trial found the one thing that was NOT faithful — `source` and
184
+ * caller `metadata` were accepted and silently dropped — which 9.30.0 fixes by
185
+ * carrying them (see `toMemory`). That fix is tested here and has not itself
186
+ * been re-run in a live project.
121
187
  */
122
188
  class MemoryBankStore {
123
189
  /**
@@ -732,10 +798,29 @@ const num = (value) => ({ doubleValue: value });
732
798
  * retrieval over structured values is close to meaningless. Store a sentence
733
799
  * when you want it found.
734
800
  *
735
- * `embedding` is deliberately dropped — see `supportsVectorSearch`.
801
+ * ── What is CARRIED, and why it took a field trial ──────────────────────────
802
+ * `source`, the caller's own `metadata` and `decayPolicy` are stored as JSON
803
+ * under prefixed keys of ours and restored verbatim on the way back.
804
+ *
805
+ * They were dropped until 9.30.0, and an independent trial (2026-08-14) is what
806
+ * made that visible: an entry written with `source.turn`, `source.messageId`
807
+ * and `metadata.classification` came back carrying only this adapter's own
808
+ * metadata. That is a contract failure and not merely a gap —
809
+ * `MemorySource.identity` is documented as a field "storage adapters MUST
810
+ * preserve verbatim on every read/write", and the fields feed audit, causal
811
+ * chains, decay and retrieval policy. A store that accepts them, reports
812
+ * success and silently forgets them is the exact shape of wrongness this
813
+ * library refuses everywhere else.
814
+ *
815
+ * `embedding` and `embeddingModel` are the ONE pair still dropped, and that is
816
+ * a refusal rather than an oversight: there is nowhere to put a vector here and
817
+ * nothing that would rank it (see `supportsVectorSearch`), and a stored
818
+ * `embeddingModel` with no vector beside it would claim a compatibility that
819
+ * does not exist.
736
820
  */
737
821
  function toMemory(entry, scope, defaultTtl) {
738
822
  const isString = typeof entry.value === 'string';
823
+ const carried = splitMetadata(entry);
739
824
  const metadata = {
740
825
  [META.id]: str(entry.id),
741
826
  [META.version]: num(entry.version),
@@ -743,6 +828,15 @@ function toMemory(entry, scope, defaultTtl) {
743
828
  [META.updatedAt]: num(entry.updatedAt),
744
829
  [META.json]: { boolValue: !isString },
745
830
  ...(entry.tier !== undefined && { [META.tier]: str(entry.tier) }),
831
+ ...(entry.source !== undefined && {
832
+ [META.source]: str(carriedJson(entry.source, 'source', entry.id)),
833
+ }),
834
+ ...(carried !== undefined && {
835
+ [META.meta]: str(carriedJson(carried, 'metadata', entry.id)),
836
+ }),
837
+ ...(entry.decayPolicy !== undefined && {
838
+ [META.decay]: str(carriedJson(entry.decayPolicy, 'decayPolicy', entry.id)),
839
+ }),
746
840
  };
747
841
  return {
748
842
  fact: isString ? entry.value : JSON.stringify(entry.value ?? null),
@@ -756,6 +850,128 @@ function toMemory(entry, scope, defaultTtl) {
756
850
  : defaultTtl !== undefined && { ttl: defaultTtl }),
757
851
  };
758
852
  }
853
+ /**
854
+ * The caller's own metadata, with this adapter's generated keys separated out
855
+ * — or `undefined` when there is none to carry.
856
+ *
857
+ * The three keys in {@link GENERATED_METADATA} are produced on every read, so
858
+ * an entry that came out of this store carries them and a `get`-then-`put`
859
+ * round trip hands them straight back. Two cases, told apart rather than
860
+ * conflated:
861
+ *
862
+ * • **It is one of ours coming home** — recognised by IDENTITY, not by shape.
863
+ * See {@link isGeneratedValue}.
864
+ * • **It is the caller's own value** under one of those names — refused by
865
+ * name. Storing it would mean the next read silently answered with our
866
+ * value instead of theirs, which is the failure mode this whole function
867
+ * exists to end.
868
+ */
869
+ function splitMetadata(entry) {
870
+ const metadata = entry.metadata;
871
+ if (metadata === undefined || metadata === null)
872
+ return undefined;
873
+ // `toEntry` stamps `source` on EVERY read, so its presence — with exactly the
874
+ // backend name this store writes — is what distinguishes an entry coming home
875
+ // from a caller who happened to pick one of our key names. Computed once for
876
+ // the whole bag, because it is a fact about the ENTRY, not about a key.
877
+ const ours = metadata['source'] === BACKEND_NAME;
878
+ const kept = {};
879
+ for (const [key, value] of Object.entries(metadata)) {
880
+ if (!GENERATED_METADATA.includes(key)) {
881
+ kept[key] = value;
882
+ continue;
883
+ }
884
+ if (isGeneratedValue(key, value, ours))
885
+ continue;
886
+ throw metadataKeyConflict(entry.id, key, value, ours);
887
+ }
888
+ return Object.keys(kept).length === 0 ? undefined : kept;
889
+ }
890
+ /**
891
+ * Is this the value THIS adapter put under that key on a read — or the caller's
892
+ * own, wearing one of our names?
893
+ *
894
+ * **Recognition is by identity, not by shape**, and the difference is a bug this
895
+ * adapter shipped once. A shape test asks "is `resourceName` a string, is
896
+ * `distance` a number?" — which every string and every number passes, so a
897
+ * caller's `metadata.resourceName = 'sku-42'` or `metadata.distance = 12` was
898
+ * accepted as ours, dropped, and answered on the next read with THIS adapter's
899
+ * resourceName sitting where their value had been. That is precisely the
900
+ * accepted-and-silently-wrong failure {@link metadataKeyConflict} exists to
901
+ * refuse, and a shape test could not tell the two apart even in principle
902
+ * (finding 29, 2026-08-14 field trial).
903
+ *
904
+ * So the test is: `source` must be exactly {@link BACKEND_NAME} — the stamp
905
+ * `toEntry` writes on every read and nothing else does — and `resourceName` /
906
+ * `distance` count as ours only when that stamp RIDES WITH THEM on the same
907
+ * entry, and the value itself still has the right shape (a Vertex resource name;
908
+ * a number). Both halves are needed: the stamp says "this entry came from here",
909
+ * the shape says "and this field was not overwritten since".
910
+ *
911
+ * The one ambiguity left is honest and narrow: a caller who takes an entry out
912
+ * of this store and writes their OWN number into `metadata.distance` before
913
+ * putting it back is indistinguishable from the retrieval distance that came
914
+ * with it, and is dropped. Keep such a value under a name of your own.
915
+ */
916
+ function isGeneratedValue(key, value, ours) {
917
+ if (key === 'source')
918
+ return value === BACKEND_NAME;
919
+ if (!ours)
920
+ return false;
921
+ if (key === 'resourceName')
922
+ return typeof value === 'string' && RESOURCE_NAME.test(value);
923
+ return typeof value === 'number';
924
+ }
925
+ /**
926
+ * A caller's metadata key collides with one this adapter generates on every read.
927
+ *
928
+ * `ours` says whether the entry carried this store's own `source` stamp, which
929
+ * decides WHICH of the two things went wrong — a name collision, or a value
930
+ * edited into a round-tripped entry — and therefore what the reader should do.
931
+ */
932
+ function metadataKeyConflict(id, key, value, ours) {
933
+ const err = new Error(
934
+ // The caller's own value, echoed back short: enough to recognise which
935
+ // field this is, never enough to paste a whole payload into a log line
936
+ // that an error reaches more sinks than the writer expects.
937
+ `${ADAPTER}: entry '${id}' carries metadata.${key} = ${shortly(value)}, and this ` +
938
+ `adapter GENERATES metadata.${key} on every read.\n` +
939
+ ` Storing it would mean your value went in and this adapter's came back — a read that ` +
940
+ `looks right and is not. The three generated keys are: ` +
941
+ `${GENERATED_METADATA.join(', ')} (the backend name, the Vertex resource name, and the ` +
942
+ `raw retrieval distance).\n` +
943
+ (ours
944
+ ? ` This entry does carry this store's own metadata.source = '${BACKEND_NAME}', so it ` +
945
+ `came from here — but this particular value is not the one this adapter wrote ` +
946
+ `(a resourceName must look like 'projects/…/memories/<id>'; a distance must be a ` +
947
+ `number). It is refused rather than dropped, because dropping a value somebody ` +
948
+ `deliberately set is the same silent wrongness in the other direction.\n`
949
+ : '') +
950
+ ` Fix: rename the key on your entry. Values this store itself produced are recognised ` +
951
+ `and dropped instead, so reading an entry and writing it back is always safe.`);
952
+ err.name = 'MemoryMetadataConflictError';
953
+ return err;
954
+ }
955
+ /** A value as at most 80 characters of JSON, for a refusal to point with. */
956
+ function shortly(value) {
957
+ const json = JSON.stringify(value) ?? String(value);
958
+ return json.length <= 80 ? json : `${json.slice(0, 77)}…`;
959
+ }
960
+ /** One carried field as JSON, or a refusal that says which field and how big. */
961
+ function carriedJson(value, field, id) {
962
+ const json = JSON.stringify(value ?? null);
963
+ if (json.length <= exports.MAX_CARRIED_JSON)
964
+ return json;
965
+ throw new RangeError(`${ADAPTER}: entry '${id}' has a '${field}' of ${json.length} JSON characters, over this ` +
966
+ `adapter's ${exports.MAX_CARRIED_JSON}-character bound for a carried field.\n` +
967
+ ` Memory Bank stores these as metadata STRINGS, and the service's own ceiling on one is ` +
968
+ `not measured by this library — so the bound is ours and deliberately conservative.\n` +
969
+ ` It refuses rather than truncating: provenance that came back shortened would be ` +
970
+ `provenance nothing could tell was shortened. Keep large payloads in the entry VALUE, ` +
971
+ `which becomes the memory's fact.`);
972
+ }
973
+ /** What this adapter names itself as the backend, in a returned entry's metadata. */
974
+ const BACKEND_NAME = 'vertex-memory-bank';
759
975
  /**
760
976
  * `Memory` → `MemoryEntry`, or `null` for a row this store did not write.
761
977
  *
@@ -788,6 +1004,9 @@ function toEntry(memory, retrieved) {
788
1004
  const updatedAt = metadata[META.updatedAt]?.doubleValue ?? toMillis(memory.updateTime);
789
1005
  const tier = metadata[META.tier]?.stringValue;
790
1006
  const expireTime = toMillis(memory.expireTime);
1007
+ const source = carriedBack(metadata[META.source]?.stringValue);
1008
+ const callerMetadata = carriedBack(metadata[META.meta]?.stringValue);
1009
+ const decayPolicy = carriedBack(metadata[META.decay]?.stringValue);
791
1010
  return {
792
1011
  id,
793
1012
  value: value,
@@ -798,8 +1017,14 @@ function toEntry(memory, retrieved) {
798
1017
  accessCount: 0,
799
1018
  ...(expireTime > 0 && { ttl: expireTime }),
800
1019
  ...(tier === 'hot' || tier === 'warm' || tier === 'cold' ? { tier } : {}),
1020
+ ...(source !== undefined && { source }),
1021
+ ...(decayPolicy !== undefined && { decayPolicy }),
801
1022
  metadata: {
802
- source: 'vertex-memory-bank',
1023
+ // The caller's own metadata first, then this adapter's generated facts.
1024
+ // They cannot collide: a caller value under a generated key is refused at
1025
+ // write time rather than overwritten here (see splitMetadata).
1026
+ ...callerMetadata,
1027
+ source: BACKEND_NAME,
803
1028
  ...(memory.name !== null && memory.name !== undefined && { resourceName: memory.name }),
804
1029
  // The raw distance, carried through unmodified — the honest number
805
1030
  // beside the converted one, for a caller who knows the metric.
@@ -807,6 +1032,25 @@ function toEntry(memory, retrieved) {
807
1032
  },
808
1033
  };
809
1034
  }
1035
+ /**
1036
+ * One carried JSON field on the way back, or `undefined`.
1037
+ *
1038
+ * Unparseable JSON answers `undefined` rather than raising: the bytes were
1039
+ * written by an older release of this adapter or edited in the console, and a
1040
+ * memory that EXISTS must not read as one that was never written over a
1041
+ * damaged provenance field. The entry's own value is unaffected.
1042
+ */
1043
+ function carriedBack(json) {
1044
+ if (typeof json !== 'string' || json === '')
1045
+ return undefined;
1046
+ try {
1047
+ const parsed = JSON.parse(json);
1048
+ return parsed === null ? undefined : parsed;
1049
+ }
1050
+ catch {
1051
+ return undefined;
1052
+ }
1053
+ }
810
1054
  /** An RFC 3339 timestamp as unix milliseconds, or 0 when it is not one. */
811
1055
  function toMillis(value) {
812
1056
  if (typeof value !== 'string')