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,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/google/aiPlatform — the one place this package builds a Vertex AI
|
|
3
|
+
* REST client, names a Vertex resource, waits on a Vertex operation, or
|
|
4
|
+
* describes a Vertex failure.
|
|
5
|
+
*
|
|
6
|
+
* Three adapters sit on top of it — `agentEngineSessions`, `memoryBankStore`
|
|
7
|
+
* and (for its auth half only) `googleIdentity` — and none of them repeats any
|
|
8
|
+
* of the four things above. That is the whole reason this file exists: the AWS
|
|
9
|
+
* column learned, expensively, that a shim duplicated across three adapters is
|
|
10
|
+
* three places for the same wire fact to go stale, and only one of them gets
|
|
11
|
+
* fixed.
|
|
12
|
+
*
|
|
13
|
+
* ── Which client, and why THIS one ──────────────────────────────────────────
|
|
14
|
+
* `@googleapis/aiplatform` — the **split, per-API** discovery package (31.0.0,
|
|
15
|
+
* 27 MB) rather than the `googleapis` mega-package (174.0.1, 209 MB) that
|
|
16
|
+
* carries every Google API at once for the same generated code. Both were
|
|
17
|
+
* installed and measured before this was written.
|
|
18
|
+
*
|
|
19
|
+
* The gax/proto client (`@google-cloud/aiplatform`, 78 MB) was rejected on a
|
|
20
|
+
* fact rather than on size: its Memory Bank surface is **v1beta1 only**, while
|
|
21
|
+
* the REST **v1** surface is complete — `memories.purge` and `memories.rollback`
|
|
22
|
+
* exist at v1 and do not exist at v1beta1. One client, at the version that has
|
|
23
|
+
* everything, beats two clients at two versions.
|
|
24
|
+
*
|
|
25
|
+
* `@google-cloud/vertexai` is past its own announced removal date and is not
|
|
26
|
+
* loaded anywhere in this package, ever.
|
|
27
|
+
*
|
|
28
|
+
* ── The endpoint fact that is not in anybody's design doc ───────────────────
|
|
29
|
+
* The generated client defaults to `https://aiplatform.googleapis.com/` — the
|
|
30
|
+
* GLOBAL host. Reasoning engines, their sessions and their memories are
|
|
31
|
+
* **regional** resources. An adapter that accepts the default calls the wrong
|
|
32
|
+
* host and gets a 404 that reads exactly like "your resource does not exist".
|
|
33
|
+
* So {@link buildAiPlatformClient} always sets a regional `rootUrl`, derived
|
|
34
|
+
* from the same `location` that composes the resource name, and the surface pin
|
|
35
|
+
* asserts the default really is the global one so this comment cannot go stale
|
|
36
|
+
* quietly.
|
|
37
|
+
*
|
|
38
|
+
* ── Secrets ─────────────────────────────────────────────────────────────────
|
|
39
|
+
* {@link googleSdkFailure} is the `sdkFailure` law from the AWS identity
|
|
40
|
+
* adapter, re-aimed at a Gaxios error: the SDK's own message never comes
|
|
41
|
+
* through. It is not that a Vertex error always contains a secret — it is that
|
|
42
|
+
* a REST client echoes the request into failure text, our requests carry
|
|
43
|
+
* conversation state and access tokens, and an error message here reaches the
|
|
44
|
+
* model as a tool result AND rides the event stream to every sink attached.
|
|
45
|
+
* One echo publishes it to both at once.
|
|
46
|
+
*/
|
|
47
|
+
import { lazyRequire } from '../../lib/lazyRequire.js';
|
|
48
|
+
// ─── Connection ──────────────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* The API version every adapter in this column dials, **stated rather than
|
|
51
|
+
* defaulted**.
|
|
52
|
+
*
|
|
53
|
+
* v1, not v1beta1, and that is a decision with evidence behind it: at v1 the
|
|
54
|
+
* memories collection carries `purge` and `rollback`; at v1beta1 it does not.
|
|
55
|
+
* The Google column's pin asserts this against the installed package on every
|
|
56
|
+
* test run, because "which version does this really call" is the question that
|
|
57
|
+
* made the pin exist.
|
|
58
|
+
*/
|
|
59
|
+
export const AI_PLATFORM_API_VERSION = 'v1';
|
|
60
|
+
/** The OAuth scope every Vertex data-plane call needs. */
|
|
61
|
+
export const CLOUD_PLATFORM_SCOPE = 'https://www.googleapis.com/auth/cloud-platform';
|
|
62
|
+
const ENGINE_NAME = /^projects\/([^/]+)\/locations\/([^/]+)\/reasoningEngines\/([^/]+)$/;
|
|
63
|
+
/**
|
|
64
|
+
* Work out which reasoning engine this adapter talks to, from either spelling
|
|
65
|
+
* of `reasoningEngine`.
|
|
66
|
+
*
|
|
67
|
+
* A full resource name wins over `project` / `location` and is CHECKED against
|
|
68
|
+
* them rather than silently overriding: two spellings of one fact that could
|
|
69
|
+
* disagree is the same law the builder refuses `agent` beside `agentFactory`
|
|
70
|
+
* under, and a name that says `us-central1` under a config that says
|
|
71
|
+
* `europe-west4` is a bug somebody should be told about, not arbitrated.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveEngine(adapter, connection) {
|
|
74
|
+
const { reasoningEngine, location } = connection;
|
|
75
|
+
if (typeof reasoningEngine !== 'string' || reasoningEngine.trim() === '') {
|
|
76
|
+
throw new TypeError(`${adapter} requires 'reasoningEngine' — the id of the Agent Runtime resource these ` +
|
|
77
|
+
`live under, or its full resource name.\n` +
|
|
78
|
+
` Sessions and memories are CHILDREN of a reasoning engine; there is nowhere else ` +
|
|
79
|
+
`to put them, so one has to exist even if you deploy no code to it.\n` +
|
|
80
|
+
` Creating it is a control-plane job (gcloud / Terraform / the console) that this ` +
|
|
81
|
+
`library deliberately does not do.`);
|
|
82
|
+
}
|
|
83
|
+
const match = ENGINE_NAME.exec(reasoningEngine.trim());
|
|
84
|
+
if (match) {
|
|
85
|
+
const [, project, engineLocation, engineId] = match;
|
|
86
|
+
if (connection.project !== undefined && connection.project !== project) {
|
|
87
|
+
throw new TypeError(`${adapter}: 'reasoningEngine' names project '${project}' but 'project' says ` +
|
|
88
|
+
`'${connection.project}'. Two spellings of one fact that disagree are refused rather ` +
|
|
89
|
+
`than arbitrated — drop one of them.`);
|
|
90
|
+
}
|
|
91
|
+
if (location !== undefined && location !== engineLocation) {
|
|
92
|
+
throw new TypeError(`${adapter}: 'reasoningEngine' names location '${engineLocation}' but 'location' says ` +
|
|
93
|
+
`'${location}'. The location picks the regional host as well as the resource name, ` +
|
|
94
|
+
`so a mismatch would call one region for a resource that lives in another. Drop one.`);
|
|
95
|
+
}
|
|
96
|
+
return { project, location: engineLocation, engineId, parent: reasoningEngine.trim() };
|
|
97
|
+
}
|
|
98
|
+
const project = connection.project ?? readEnv('GOOGLE_CLOUD_PROJECT');
|
|
99
|
+
if (project === undefined || project === '') {
|
|
100
|
+
throw new TypeError(`${adapter} requires 'project' — no project was configured and GOOGLE_CLOUD_PROJECT is ` +
|
|
101
|
+
`not set.\n` +
|
|
102
|
+
` Pass it, set the environment variable, or give 'reasoningEngine' as a full resource ` +
|
|
103
|
+
`name ('projects/…/locations/…/reasoningEngines/…'), which carries the project with it.`);
|
|
104
|
+
}
|
|
105
|
+
if (typeof location !== 'string' || location.trim() === '') {
|
|
106
|
+
throw new TypeError(`${adapter} requires 'location' (e.g. 'us-central1'). There is no default, on purpose: ` +
|
|
107
|
+
`it selects the REGIONAL API host as well as composing the resource name, so a guess ` +
|
|
108
|
+
`does not fail — it calls a different region and answers "not found".`);
|
|
109
|
+
}
|
|
110
|
+
const engineId = reasoningEngine.trim();
|
|
111
|
+
return {
|
|
112
|
+
project,
|
|
113
|
+
location: location.trim(),
|
|
114
|
+
engineId,
|
|
115
|
+
parent: `projects/${project}/locations/${location.trim()}/reasoningEngines/${engineId}`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** `process.env` without assuming `process` exists (browser bundles do not have one). */
|
|
119
|
+
function readEnv(name) {
|
|
120
|
+
return typeof process !== 'undefined' && process.env ? process.env[name] : undefined;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The regional host for a location.
|
|
124
|
+
*
|
|
125
|
+
* See the module header: the client's own default is the global host, and
|
|
126
|
+
* these resources are regional. This is the fix, in one line, applied at every
|
|
127
|
+
* construction.
|
|
128
|
+
*/
|
|
129
|
+
export function regionalRootUrl(location) {
|
|
130
|
+
return `https://${location}-aiplatform.googleapis.com/`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Build the REST client, or refuse by name.
|
|
134
|
+
*
|
|
135
|
+
* An injected `_client` short-circuits everything below it, which is how every
|
|
136
|
+
* test in this column runs with no package installed and no credential.
|
|
137
|
+
*/
|
|
138
|
+
export function buildAiPlatformClient(adapter, connection, scope) {
|
|
139
|
+
if (connection._client)
|
|
140
|
+
return connection._client;
|
|
141
|
+
let mod;
|
|
142
|
+
if (connection._sdk) {
|
|
143
|
+
mod = connection._sdk;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
try {
|
|
147
|
+
mod = lazyRequire('@googleapis/aiplatform');
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
throw new Error(`${adapter} requires the \`@googleapis/aiplatform\` peer dependency.\n` +
|
|
151
|
+
` Install: npm install @googleapis/aiplatform\n` +
|
|
152
|
+
` It is the SPLIT per-API package (~27 MB), not the \`googleapis\` mega-package ` +
|
|
153
|
+
`(~209 MB) that carries every Google API for the same generated code.\n` +
|
|
154
|
+
` It is optional and loaded only when you construct this adapter, so nothing else ` +
|
|
155
|
+
`in this library pays for it.`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (typeof mod.aiplatform !== 'function') {
|
|
159
|
+
throw new Error(`${adapter}: \`@googleapis/aiplatform\` is installed but exports no \`aiplatform\` ` +
|
|
160
|
+
`factory. This adapter is built against the 31.x package — update it, or pass a ` +
|
|
161
|
+
`pre-built client.`);
|
|
162
|
+
}
|
|
163
|
+
const auth = connection.auth ?? defaultAuth(adapter, mod);
|
|
164
|
+
return mod.aiplatform({
|
|
165
|
+
version: AI_PLATFORM_API_VERSION,
|
|
166
|
+
// Never the client's global default — see the module header.
|
|
167
|
+
rootUrl: regionalRootUrl(scope.location),
|
|
168
|
+
auth,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Application Default Credentials, from the SDK's own re-exported auth surface.
|
|
173
|
+
*
|
|
174
|
+
* Taken from `@googleapis/aiplatform` rather than by loading
|
|
175
|
+
* `google-auth-library` separately: the package already carries it, and one
|
|
176
|
+
* load is one version to reason about instead of two that can drift apart.
|
|
177
|
+
*/
|
|
178
|
+
function defaultAuth(adapter, mod) {
|
|
179
|
+
const GoogleAuth = mod.auth?.GoogleAuth;
|
|
180
|
+
if (typeof GoogleAuth !== 'function') {
|
|
181
|
+
throw new Error(`${adapter}: \`@googleapis/aiplatform\` exposes no \`auth.GoogleAuth\`, so Application ` +
|
|
182
|
+
`Default Credentials cannot be resolved.\n` +
|
|
183
|
+
` Pass 'auth' with your own GoogleAuth / OAuth2Client, or update the package.`);
|
|
184
|
+
}
|
|
185
|
+
return new GoogleAuth({ scopes: [CLOUD_PLATFORM_SCOPE] });
|
|
186
|
+
}
|
|
187
|
+
// ─── Long-running operations ─────────────────────────────────────────
|
|
188
|
+
/** How long {@link awaitOperation} keeps waiting before it refuses, by default. */
|
|
189
|
+
export const DEFAULT_OPERATION_TIMEOUT_MS = 30_000;
|
|
190
|
+
/** One server-side wait, in the duration spelling the API takes. */
|
|
191
|
+
const WAIT_SLICE = '10s';
|
|
192
|
+
/**
|
|
193
|
+
* Wait for a long-running operation to finish, or refuse by name.
|
|
194
|
+
*
|
|
195
|
+
* ── Why any of this exists ──────────────────────────────────────────────────
|
|
196
|
+
* `sessions.create`, `sessions.delete`, `memories.create`, `memories.patch`
|
|
197
|
+
* and `memories.delete` **all answer with an Operation, not with the resource**
|
|
198
|
+
* — verified against the installed package's own return types before a line of
|
|
199
|
+
* either adapter was written. `get`, `list`, `patch`-on-a-session and
|
|
200
|
+
* `retrieve` are the synchronous ones.
|
|
201
|
+
*
|
|
202
|
+
* That asymmetry is the trap: a `put` that returns as soon as the service
|
|
203
|
+
* accepts the request, followed by a `get`, is a race that passes on a warm
|
|
204
|
+
* day and fails under load — and fails by answering "no data", which is
|
|
205
|
+
* indistinguishable from the truth. So every write in this column goes through
|
|
206
|
+
* here and does not return until the service says `done`.
|
|
207
|
+
*
|
|
208
|
+
* An operation that finished with an error is raised as one. The operation's
|
|
209
|
+
* own message is a Google-side description of OUR request, so it is subject to
|
|
210
|
+
* the same secrecy law as everything else here: the code comes through, the
|
|
211
|
+
* text does not.
|
|
212
|
+
*/
|
|
213
|
+
export async function awaitOperation(adapter, operations, operation, what, timeoutMs = DEFAULT_OPERATION_TIMEOUT_MS) {
|
|
214
|
+
if (operation === undefined)
|
|
215
|
+
return;
|
|
216
|
+
// Some services answer an already-finished operation on the first call. That
|
|
217
|
+
// is the common case for a small write, and it costs no round trip.
|
|
218
|
+
if (operation.done === true) {
|
|
219
|
+
throwIfOperationFailed(adapter, operation, what);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const name = operation.name;
|
|
223
|
+
if (typeof name !== 'string' || name === '') {
|
|
224
|
+
// Nothing to wait ON. Answering as though the write had landed would be
|
|
225
|
+
// exactly the silent success this whole function exists to prevent.
|
|
226
|
+
throw operationError(`${adapter}: ${what} was accepted but the service returned an operation with no name, ` +
|
|
227
|
+
`so there is nothing to wait on and no way to confirm the write landed.\n` +
|
|
228
|
+
` Refusing rather than reporting a success this adapter cannot verify.`);
|
|
229
|
+
}
|
|
230
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
231
|
+
let current = operation;
|
|
232
|
+
while (current.done !== true) {
|
|
233
|
+
if (Date.now() >= deadline) {
|
|
234
|
+
throw operationError(`${adapter}: ${what} did not finish within ${timeoutMs}ms.\n` +
|
|
235
|
+
` The operation is still running on Google's side — it may yet succeed — but this ` +
|
|
236
|
+
`call will not report a write it has not seen land.\n` +
|
|
237
|
+
` Raise the adapter's 'operationTimeoutMs' if your engine is routinely slower.`);
|
|
238
|
+
}
|
|
239
|
+
const answer = await operations.wait({ name, timeout: WAIT_SLICE });
|
|
240
|
+
current = answer?.data ?? {};
|
|
241
|
+
}
|
|
242
|
+
throwIfOperationFailed(adapter, current, what);
|
|
243
|
+
}
|
|
244
|
+
function throwIfOperationFailed(adapter, operation, what) {
|
|
245
|
+
const error = operation.error;
|
|
246
|
+
if (error === null || error === undefined)
|
|
247
|
+
return;
|
|
248
|
+
const code = typeof error.code === 'number' ? ` (code ${error.code})` : '';
|
|
249
|
+
throw operationError(`${adapter}: ${what} failed${code}.\n` +
|
|
250
|
+
` The operation's own message is withheld: it is Google's description of OUR request, ` +
|
|
251
|
+
`and this request carried conversation state. Check Cloud Logging for the full text.`);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The name every refusal from this function carries.
|
|
255
|
+
*
|
|
256
|
+
* It exists so a caller's `catch` can tell "the operation went wrong" — which
|
|
257
|
+
* is already sanitized and already says what to do — apart from "the transport
|
|
258
|
+
* went wrong", which still needs {@link googleSdkFailure} run over it. Without
|
|
259
|
+
* the distinction an adapter re-wraps its own refusal and replaces a precise
|
|
260
|
+
* diagnosis ("did not finish within 30000ms") with a generic one.
|
|
261
|
+
*/
|
|
262
|
+
export const OPERATION_ERROR_NAME = 'GoogleOperationError';
|
|
263
|
+
function operationError(message) {
|
|
264
|
+
const err = new Error(message);
|
|
265
|
+
err.name = OPERATION_ERROR_NAME;
|
|
266
|
+
return err;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Has this error already been sanitized by this module? Used by every adapter's
|
|
270
|
+
* `catch` so a refusal is reported once rather than wrapped twice.
|
|
271
|
+
*/
|
|
272
|
+
export function isSanitizedGoogleError(err) {
|
|
273
|
+
return (err instanceof Error && (err.name === OPERATION_ERROR_NAME || err.name === 'GoogleApiError'));
|
|
274
|
+
}
|
|
275
|
+
// ─── Failures ────────────────────────────────────────────────────────
|
|
276
|
+
/**
|
|
277
|
+
* Re-raise a failed REST call **without its text** — the `sdkFailure` law from
|
|
278
|
+
* the AWS identity adapter, re-aimed at a Gaxios error.
|
|
279
|
+
*
|
|
280
|
+
* What comes through is the part that is both safe and actionable: which
|
|
281
|
+
* operation failed and the HTTP status. What does not is the message, because
|
|
282
|
+
* a REST client echoes the request into its failure text and these requests
|
|
283
|
+
* carry a whole conversation's state, a user id, and an access token in the
|
|
284
|
+
* headers. A thrown message here reaches the LLM as a tool result AND rides the
|
|
285
|
+
* event stream to every sink attached to the agent.
|
|
286
|
+
*
|
|
287
|
+
* **The original is deliberately not attached as `cause`** — a cause travels
|
|
288
|
+
* with the error into every serializer that walks own properties, which would
|
|
289
|
+
* undo all of this in one `JSON.stringify`.
|
|
290
|
+
*/
|
|
291
|
+
export function googleSdkFailure(adapter, operation, err) {
|
|
292
|
+
const status = httpStatusOf(err);
|
|
293
|
+
const failure = new Error(`${adapter}: ${operation} failed` +
|
|
294
|
+
(status === undefined ? '' : ` (HTTP ${status})`) +
|
|
295
|
+
`.\n The SDK's own message is withheld: this request carried session state and an ` +
|
|
296
|
+
`access token, and REST clients echo request detail into failure text. Check Cloud ` +
|
|
297
|
+
`Logging for the full error.`);
|
|
298
|
+
failure.name = 'GoogleApiError';
|
|
299
|
+
return failure;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The HTTP status of a failed call, wherever this client happened to put it.
|
|
303
|
+
*
|
|
304
|
+
* Three places rather than one because the client reports a transport failure,
|
|
305
|
+
* an API error and a thrown `GaxiosError` slightly differently, and a
|
|
306
|
+
* classification that only reads one of them silently stops classifying the
|
|
307
|
+
* day the client is upgraded.
|
|
308
|
+
*/
|
|
309
|
+
export function httpStatusOf(err) {
|
|
310
|
+
const e = err;
|
|
311
|
+
if (e === null || typeof e !== 'object')
|
|
312
|
+
return undefined;
|
|
313
|
+
for (const candidate of [e.status, e.code, e.response?.status]) {
|
|
314
|
+
if (typeof candidate === 'number' && Number.isFinite(candidate))
|
|
315
|
+
return candidate;
|
|
316
|
+
// Gaxios sometimes reports the status as a numeric STRING.
|
|
317
|
+
if (typeof candidate === 'string' && /^\d{3}$/.test(candidate))
|
|
318
|
+
return Number(candidate);
|
|
319
|
+
}
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
/** Is this the service's "no such resource"? */
|
|
323
|
+
export function isNotFound(err) {
|
|
324
|
+
return httpStatusOf(err) === 404;
|
|
325
|
+
}
|
|
326
|
+
/** Is this "a resource by that name already exists"? */
|
|
327
|
+
export function isAlreadyExists(err) {
|
|
328
|
+
return httpStatusOf(err) === 409;
|
|
329
|
+
}
|
|
330
|
+
// ─── Ids ─────────────────────────────────────────────────────────────
|
|
331
|
+
/** The longest a resource id may be in both collections this column writes to. */
|
|
332
|
+
export const MAX_RESOURCE_ID_LENGTH = 63;
|
|
333
|
+
/**
|
|
334
|
+
* The id grammar this column really has to satisfy — the INTERSECTION of the
|
|
335
|
+
* two documented rules, so one function is right for both callers and neither
|
|
336
|
+
* has to remember which is stricter: `[a-z0-9-]`, first character a letter,
|
|
337
|
+
* last character a letter or a digit.
|
|
338
|
+
*
|
|
339
|
+
* Exported so the surface pin can hold it against the installed package's own
|
|
340
|
+
* words rather than against this file's memory of them.
|
|
341
|
+
*/
|
|
342
|
+
export const LEGAL_RESOURCE_ID = /^[a-z]$|^[a-z][a-z0-9-]*[a-z0-9]$/;
|
|
343
|
+
/**
|
|
344
|
+
* Turn caller data into a resource id the service will accept — and never into
|
|
345
|
+
* a DIFFERENT caller's id.
|
|
346
|
+
*
|
|
347
|
+
* ── The grammar, quoted rather than guessed ─────────────────────────────────
|
|
348
|
+
* This function used to state that "Vertex resource ids accept `[A-Za-z0-9_-]`".
|
|
349
|
+
* That is a Google-wide habit and it is not what either collection this column
|
|
350
|
+
* writes to documents. From the installed package (`@googleapis/aiplatform`
|
|
351
|
+
* 31.0.0, `build/v1.d.ts`), verbatim:
|
|
352
|
+
*
|
|
353
|
+
* `memoryId` — "This value may be up to 63 characters, and valid characters
|
|
354
|
+
* are `[a-z0-9-]`. The first character must be a letter, and
|
|
355
|
+
* the last character must be a letter or number."
|
|
356
|
+
* `sessionId` — "This value may be up to 63 characters, and valid characters
|
|
357
|
+
* are `[a-z0-9-]`. The first and last characters must be a
|
|
358
|
+
* letter or number."
|
|
359
|
+
*
|
|
360
|
+
* So UPPERCASE and `_` are illegal in both, and a leading digit is illegal for
|
|
361
|
+
* a memory. Under the old grammar a UUID entry id (leading digit) and a ULID
|
|
362
|
+
* session id (uppercase Crockford base32) — two of the most ordinary id shapes
|
|
363
|
+
* there are — went to the wire unchanged, to be refused by Google with a 400
|
|
364
|
+
* whose text {@link googleSdkFailure} then withholds. A grammar error the
|
|
365
|
+
* adapter could have caught locally, delivered as a censored 400, is the one
|
|
366
|
+
* place the secrecy law and the teaching-refusal law collide; the fix is to not
|
|
367
|
+
* send it. The surface pin reads those two sentences out of the installed
|
|
368
|
+
* `.d.ts` and checks them against {@link LEGAL_RESOURCE_ID}, so this cannot
|
|
369
|
+
* drift back to a guess.
|
|
370
|
+
*
|
|
371
|
+
* ── Why a hash and not just a fold ──────────────────────────────────────────
|
|
372
|
+
* Lowercasing and substituting are LOSSY: `Alice` folds onto `alice`, `a_b`
|
|
373
|
+
* onto `a-b`. Two ids that folded together would be ONE row, which is the same
|
|
374
|
+
* silent overwrite this column's addressing law exists to prevent. So the
|
|
375
|
+
* readable fast path is taken only when the caller's id already is a legal id
|
|
376
|
+
* byte for byte; anything the fold touched — or that overruns 63 characters —
|
|
377
|
+
* is carried by a {@link fingerprint} of the ORIGINAL, which keeps distinct
|
|
378
|
+
* inputs distinct.
|
|
379
|
+
*/
|
|
380
|
+
export function safeResourceId(raw, max = MAX_RESOURCE_ID_LENGTH) {
|
|
381
|
+
const slug = raw.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
382
|
+
if (slug === raw && slug.length <= max && LEGAL_RESOURCE_ID.test(slug))
|
|
383
|
+
return slug;
|
|
384
|
+
const suffix = fingerprint(raw);
|
|
385
|
+
const room = max - suffix.length - 1;
|
|
386
|
+
if (room < 2) {
|
|
387
|
+
// Returning something longer than `max` would be a silently invalid id —
|
|
388
|
+
// refused rather than sent, since only a caller of this function can fix it.
|
|
389
|
+
throw new RangeError(`safeResourceId: max of ${max} leaves no room for the fingerprint that keeps two ` +
|
|
390
|
+
`folded ids apart. The smallest workable bound is ${suffix.length + 3}.`);
|
|
391
|
+
}
|
|
392
|
+
// `id-` rather than the bare slug: the first character must be a LETTER, and
|
|
393
|
+
// the fold cannot promise one. The fingerprint is base36, so the last
|
|
394
|
+
// character is a letter or a digit by construction — which also makes this
|
|
395
|
+
// function IDEMPOTENT: its own output is a legal id and comes back unchanged.
|
|
396
|
+
// `agentEngineSessions.listByUser` relies on that, since it hands composed
|
|
397
|
+
// resource ids back to callers who feed them to `hydrate`.
|
|
398
|
+
const head = `id-${slug}`.slice(0, room).replace(/-+$/, '');
|
|
399
|
+
return `${head}-${suffix}`;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* A stable fingerprint of a string, in `[0-9a-z-]`.
|
|
403
|
+
*
|
|
404
|
+
* TWO FNV-1a lanes rather than one, because of what this hash is now asked to
|
|
405
|
+
* carry: it is the only thing keeping two ids apart once the fold has run them
|
|
406
|
+
* together, and it is half of how `memoryBankStore` addresses one identity's
|
|
407
|
+
* memories apart from another's. A single 32-bit lane collides at around one
|
|
408
|
+
* chance in a hundred across ten thousand ids, which is too often for either
|
|
409
|
+
* job; two lanes cost one more multiply per character and make it negligible.
|
|
410
|
+
*
|
|
411
|
+
* It is a fingerprint, not a security boundary — a colliding address is still
|
|
412
|
+
* refused by the scope check that runs before every read and every overwrite.
|
|
413
|
+
*/
|
|
414
|
+
export function fingerprint(value) {
|
|
415
|
+
let a = 0x811c9dc5;
|
|
416
|
+
let b = 0x01000193;
|
|
417
|
+
for (let i = 0; i < value.length; i++) {
|
|
418
|
+
const code = value.charCodeAt(i);
|
|
419
|
+
a = Math.imul(a ^ code, 0x01000193);
|
|
420
|
+
b = Math.imul(b ^ code, 0x85ebca6b);
|
|
421
|
+
}
|
|
422
|
+
return `${(a >>> 0).toString(36)}-${(b >>> 0).toString(36)}`;
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=aiPlatform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiPlatform.js","sourceRoot":"","sources":["../../../../src/adapters/google/aiPlatform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agentEngineSessions — conversations in Vertex AI's own session service, so a
|
|
3
|
+
* fleet shares them.
|
|
4
|
+
*
|
|
5
|
+
* `memorySessions()` loses everything on restart and says so. `sqliteSessions()`
|
|
6
|
+
* survives a restart on ONE machine and says so. The row above both — *many
|
|
7
|
+
* containers, one conversation* — is where a managed session service belongs,
|
|
8
|
+
* and on this column that service is the `sessions` collection under a
|
|
9
|
+
* reasoning engine.
|
|
10
|
+
*
|
|
11
|
+
* ── The name, said once ─────────────────────────────────────────────────────
|
|
12
|
+
* The product was **Agent Engine**, is now **Agent Runtime**, and the API
|
|
13
|
+
* resource is still spelled `reasoningEngines`. This factory keeps the name it
|
|
14
|
+
* was designed under; where the product name and the API disagree, the API is
|
|
15
|
+
* the one that has not moved.
|
|
16
|
+
*
|
|
17
|
+
* ── The fit, and it is a good one ───────────────────────────────────────────
|
|
18
|
+
* `Session.sessionState` is an arbitrary JSON `Struct`. A `CheckpointEnvelope`
|
|
19
|
+
* is arbitrary JSON. So the envelope goes in whole, under one key, and comes
|
|
20
|
+
* back whole — no event log to fold, no blob encoding to get wrong, no
|
|
21
|
+
* per-turn append. That is a materially better fit than the other column's
|
|
22
|
+
* session store, which had to learn the hard way that an object handed to an
|
|
23
|
+
* event blob comes back as somebody else's `toString()`.
|
|
24
|
+
*
|
|
25
|
+
* ── The four facts that shaped the code, all read off the installed SDK ─────
|
|
26
|
+
* 1. **`sessions.create` takes a caller-supplied `sessionId`.** So our session
|
|
27
|
+
* id IS the resource id and `hydrate` is one `get` by name. No mapping
|
|
28
|
+
* table, no listing to find a conversation.
|
|
29
|
+
* 2. **`create` and `delete` answer a long-running Operation; `get` and
|
|
30
|
+
* `patch` answer the Session.** Every write here therefore waits for the
|
|
31
|
+
* operation to report `done` before it returns — a `persist` that returned
|
|
32
|
+
* early would make the very next `hydrate` a race whose failure mode is
|
|
33
|
+
* "no conversation", which nobody can tell from a new user.
|
|
34
|
+
* 3. **`Session.userId` is required and immutable.** Our port's
|
|
35
|
+
* `persist(sessionId, envelope)` carries no user, so one has to be
|
|
36
|
+
* resolved — see {@link AgentEngineSessionsOptions.userId}. Immutable
|
|
37
|
+
* means the first write decides forever, which is exactly the ownership
|
|
38
|
+
* rule this library already enforces in its own stores; here the service
|
|
39
|
+
* enforces it for us.
|
|
40
|
+
* 4. **`ttl` is input-only with a 24-hour floor**, and `expireTime` always
|
|
41
|
+
* comes back. Sliding expiry is free; an hour-long TTL is not available at
|
|
42
|
+
* any price.
|
|
43
|
+
*
|
|
44
|
+
* ── The laws it inherits rather than re-implements ──────────────────────────
|
|
45
|
+
* `checkEnvelope` runs on the way OUT and on the way IN, so an envelope whose
|
|
46
|
+
* `format` this runtime does not know is refused by name, and a session that
|
|
47
|
+
* is PRESENT but unreadable is refused by name too. Only a session that was
|
|
48
|
+
* never written hydrates as `undefined`. A conversation that exists and cannot
|
|
49
|
+
* be read must never be answered with a fresh start — that failure is
|
|
50
|
+
* indistinguishable, from the outside, from a brand-new user.
|
|
51
|
+
*/
|
|
52
|
+
import type { CheckpointEnvelope, SessionLifecycle } from '../../hosting/types.js';
|
|
53
|
+
import { type AiPlatformConnection } from '../google/aiPlatform.js';
|
|
54
|
+
/**
|
|
55
|
+
* The `sessionState` key the envelope lives under.
|
|
56
|
+
*
|
|
57
|
+
* One key, namespaced, rather than spreading the envelope's own fields across
|
|
58
|
+
* `sessionState`: the struct belongs to whoever owns the reasoning engine, an
|
|
59
|
+
* agent framework is a guest in it, and a guest that scatters `format` and
|
|
60
|
+
* `data` at the top level collides with the next guest. Namespacing also makes
|
|
61
|
+
* the console readable — one entry that says whose it is.
|
|
62
|
+
*/
|
|
63
|
+
export declare const SESSION_STATE_KEY = "agentfootprint.envelope";
|
|
64
|
+
/** Options for {@link agentEngineSessions}. */
|
|
65
|
+
export interface AgentEngineSessionsOptions extends AiPlatformConnection {
|
|
66
|
+
/**
|
|
67
|
+
* WHO a session belongs to — required by the service on create, and
|
|
68
|
+
* **immutable** once written.
|
|
69
|
+
*
|
|
70
|
+
* The port hands `persist` a session id and an envelope, never a user, so
|
|
71
|
+
* this is where the missing half comes from. Two spellings:
|
|
72
|
+
*
|
|
73
|
+
* - a **function**, called with the session id and the envelope about to be
|
|
74
|
+
* stored. The recommended shape: return `envelopeOwner(envelope)` — the
|
|
75
|
+
* principal the conversation itself was signed with — so the service's
|
|
76
|
+
* idea of the owner and this library's own ownership index agree by
|
|
77
|
+
* construction rather than by coincidence. That is what the default does.
|
|
78
|
+
* - a **string**, when every conversation in this engine belongs to one
|
|
79
|
+
* service identity. Honest for a single-tenant deployment and wrong the
|
|
80
|
+
* moment it is not, which is why it is not the default.
|
|
81
|
+
*
|
|
82
|
+
* The default resolver reads the envelope's own principal and falls back to
|
|
83
|
+
* {@link DEFAULT_USER_ID} for a conversation that ran anonymously. It never
|
|
84
|
+
* invents a per-session user id: the service treats `userId` as the thing
|
|
85
|
+
* you filter a listing by, and minting a unique one per session would make
|
|
86
|
+
* every listing return exactly one row and look like it worked.
|
|
87
|
+
*/
|
|
88
|
+
readonly userId?: string | ((sessionId: string, envelope: CheckpointEnvelope) => string);
|
|
89
|
+
/**
|
|
90
|
+
* How long a session lives after its last write, as a duration string the
|
|
91
|
+
* API accepts (`'86400s'`). **The service's own floor is 24 hours** and it
|
|
92
|
+
* rejects anything shorter, so this is a knob for keeping conversations
|
|
93
|
+
* LONGER, never for expiring them sooner.
|
|
94
|
+
*
|
|
95
|
+
* Omit and no `ttl` is sent, which leaves the service's own default
|
|
96
|
+
* expiry in charge.
|
|
97
|
+
*/
|
|
98
|
+
readonly ttl?: string;
|
|
99
|
+
/**
|
|
100
|
+
* How long a write waits for its long-running operation before refusing.
|
|
101
|
+
* Default {@link DEFAULT_OPERATION_TIMEOUT_MS} (30s).
|
|
102
|
+
*
|
|
103
|
+
* It refuses rather than returning: a `persist` that reported success on an
|
|
104
|
+
* operation it never saw finish is a conversation that may or may not be
|
|
105
|
+
* there next turn.
|
|
106
|
+
*/
|
|
107
|
+
readonly operationTimeoutMs?: number;
|
|
108
|
+
}
|
|
109
|
+
/** What a conversation that named nobody is stored under. */
|
|
110
|
+
export declare const DEFAULT_USER_ID = "agentfootprint-anonymous";
|
|
111
|
+
/**
|
|
112
|
+
* A session store in Vertex AI's session service.
|
|
113
|
+
*
|
|
114
|
+
* It is a {@link SessionLifecycle} plus the two things a real store owns beyond
|
|
115
|
+
* the port — forgetting, and closing — because the port deliberately asks for
|
|
116
|
+
* two methods and leaves the rest to whoever implements it.
|
|
117
|
+
*/
|
|
118
|
+
export interface AgentEngineSessions extends SessionLifecycle {
|
|
119
|
+
/** The resource these sessions live under. Useful in an incident. */
|
|
120
|
+
readonly parent: string;
|
|
121
|
+
/** Forget one session. A session that was never there is not an error. */
|
|
122
|
+
forget(sessionId: string): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Stop using this store. Idempotent, and **final** — reading or writing
|
|
125
|
+
* afterwards refuses by name rather than quietly reconnecting, because a
|
|
126
|
+
* store that reopened behind you would hide a shutdown-ordering bug instead
|
|
127
|
+
* of surfacing it.
|
|
128
|
+
*
|
|
129
|
+
* Nothing is torn down on Google's side: the sessions outlive this process,
|
|
130
|
+
* which is the entire reason to use a managed store.
|
|
131
|
+
*/
|
|
132
|
+
close(): void;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Conversations in Vertex AI's session service — the store that survives a
|
|
136
|
+
* fleet, not just a restart.
|
|
137
|
+
*
|
|
138
|
+
* **Status: contract-shaped and tested; awaiting field use.** Every call is
|
|
139
|
+
* exercised through an injected client and pinned against the really-installed
|
|
140
|
+
* SDK. None of it has yet answered a request from Google in a real project.
|
|
141
|
+
*
|
|
142
|
+
* @example A standing agent whose conversations are shared across instances
|
|
143
|
+
* import { standingAgent, nodeHost } from 'agentfootprint/hosting';
|
|
144
|
+
* import { agentEngineSessions } from 'agentfootprint/hosting';
|
|
145
|
+
*
|
|
146
|
+
* const handle = await standingAgent({
|
|
147
|
+
* agentFactory: () => buildAgent(),
|
|
148
|
+
* host: nodeHost({ port: 8080 }),
|
|
149
|
+
* sessions: agentEngineSessions({
|
|
150
|
+
* project: 'my-project',
|
|
151
|
+
* location: 'us-central1',
|
|
152
|
+
* reasoningEngine: '1234567890',
|
|
153
|
+
* }),
|
|
154
|
+
* });
|
|
155
|
+
*/
|
|
156
|
+
export declare function agentEngineSessions(options: AgentEngineSessionsOptions): AgentEngineSessions;
|