agentfootprint 7.14.0 → 7.15.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/hosting/agentcore.js +350 -0
- package/dist/adapters/hosting/agentcore.js.map +1 -0
- package/dist/adapters/memory/agentcore.js +125 -1
- package/dist/adapters/memory/agentcore.js.map +1 -1
- package/dist/adapters/security/agentcore.js +0 -0
- package/dist/adapters/security/agentcore.js.map +1 -0
- package/dist/esm/adapters/hosting/agentcore.d.ts +199 -0
- package/dist/esm/adapters/hosting/agentcore.js +321 -0
- package/dist/esm/adapters/hosting/agentcore.js.map +1 -0
- package/dist/esm/adapters/memory/agentcore.d.ts +88 -2
- package/dist/esm/adapters/memory/agentcore.js +125 -1
- package/dist/esm/adapters/memory/agentcore.js.map +1 -1
- package/dist/esm/adapters/security/agentcore.d.ts +157 -0
- package/dist/esm/adapters/security/agentcore.js +0 -0
- package/dist/esm/adapters/security/agentcore.js.map +1 -0
- package/dist/esm/hosting/httpHost.d.ts +121 -0
- package/dist/esm/hosting/httpHost.js +248 -0
- package/dist/esm/hosting/httpHost.js.map +1 -0
- package/dist/esm/hosting/index.d.ts +8 -1
- package/dist/esm/hosting/index.js +7 -1
- package/dist/esm/hosting/index.js.map +1 -1
- package/dist/esm/hosting/nodeHost.d.ts +23 -16
- package/dist/esm/hosting/nodeHost.js +32 -199
- package/dist/esm/hosting/nodeHost.js.map +1 -1
- package/dist/esm/hosting-providers.d.ts +50 -0
- package/dist/esm/hosting-providers.js +50 -0
- package/dist/esm/hosting-providers.js.map +1 -0
- package/dist/esm/lib/mcp/gatewayTransport.d.ts +103 -0
- package/dist/esm/lib/mcp/gatewayTransport.js +123 -0
- package/dist/esm/lib/mcp/gatewayTransport.js.map +1 -0
- package/dist/esm/lib/mcp/index.d.ts +2 -1
- package/dist/esm/lib/mcp/index.js +1 -0
- package/dist/esm/lib/mcp/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpClient.js +10 -2
- package/dist/esm/lib/mcp/mcpClient.js.map +1 -1
- package/dist/esm/lib/mcp/types.d.ts +45 -1
- package/dist/esm/memory/store/types.d.ts +22 -0
- package/dist/esm/memory-providers.d.ts +1 -1
- package/dist/esm/memory-providers.js.map +1 -1
- package/dist/esm/security/index.d.ts +10 -1
- package/dist/esm/security/index.js +14 -1
- package/dist/esm/security/index.js.map +1 -1
- package/dist/esm/tool-providers/index.d.ts +6 -2
- package/dist/esm/tool-providers/index.js +5 -1
- package/dist/esm/tool-providers/index.js.map +1 -1
- package/dist/hosting/httpHost.js +276 -0
- package/dist/hosting/httpHost.js.map +1 -0
- package/dist/hosting/index.js +10 -1
- package/dist/hosting/index.js.map +1 -1
- package/dist/hosting/nodeHost.js +34 -224
- package/dist/hosting/nodeHost.js.map +1 -1
- package/dist/hosting-providers.js +57 -0
- package/dist/hosting-providers.js.map +1 -0
- package/dist/lib/mcp/gatewayTransport.js +129 -0
- package/dist/lib/mcp/gatewayTransport.js.map +1 -0
- package/dist/lib/mcp/index.js +4 -1
- package/dist/lib/mcp/index.js.map +1 -1
- package/dist/lib/mcp/mcpClient.js +10 -2
- package/dist/lib/mcp/mcpClient.js.map +1 -1
- package/dist/memory-providers.js.map +1 -1
- package/dist/security/index.js +16 -2
- package/dist/security/index.js.map +1 -1
- package/dist/tool-providers/index.js +7 -1
- package/dist/tool-providers/index.js.map +1 -1
- package/dist/types/adapters/hosting/agentcore.d.ts +200 -0
- package/dist/types/adapters/hosting/agentcore.d.ts.map +1 -0
- package/dist/types/adapters/memory/agentcore.d.ts +88 -2
- package/dist/types/adapters/memory/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/security/agentcore.d.ts +158 -0
- package/dist/types/adapters/security/agentcore.d.ts.map +1 -0
- package/dist/types/hosting/httpHost.d.ts +122 -0
- package/dist/types/hosting/httpHost.d.ts.map +1 -0
- package/dist/types/hosting/index.d.ts +8 -1
- package/dist/types/hosting/index.d.ts.map +1 -1
- package/dist/types/hosting/nodeHost.d.ts +23 -16
- package/dist/types/hosting/nodeHost.d.ts.map +1 -1
- package/dist/types/hosting-providers.d.ts +51 -0
- package/dist/types/hosting-providers.d.ts.map +1 -0
- package/dist/types/lib/mcp/gatewayTransport.d.ts +104 -0
- package/dist/types/lib/mcp/gatewayTransport.d.ts.map +1 -0
- package/dist/types/lib/mcp/index.d.ts +2 -1
- package/dist/types/lib/mcp/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/lib/mcp/types.d.ts +45 -1
- package/dist/types/lib/mcp/types.d.ts.map +1 -1
- package/dist/types/memory/store/types.d.ts +22 -0
- package/dist/types/memory/store/types.d.ts.map +1 -1
- package/dist/types/memory-providers.d.ts +1 -1
- package/dist/types/memory-providers.d.ts.map +1 -1
- package/dist/types/security/index.d.ts +10 -1
- package/dist/types/security/index.d.ts.map +1 -1
- package/dist/types/tool-providers/index.d.ts +6 -2
- package/dist/types/tool-providers/index.d.ts.map +1 -1
- package/package.json +14 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/hosting/agentcore — AWS Bedrock **AgentCore Runtime** adapters for
|
|
3
|
+
* the two hosting ports.
|
|
4
|
+
*
|
|
5
|
+
* import { agentCoreRuntimeHost, agentCoreSessions } from 'agentfootprint/hosting-providers';
|
|
6
|
+
* import { standingAgent } from 'agentfootprint/hosting';
|
|
7
|
+
*
|
|
8
|
+
* const handle = await standingAgent({
|
|
9
|
+
* agent,
|
|
10
|
+
* host: agentCoreRuntimeHost(),
|
|
11
|
+
* sessions: agentCoreSessions({ store: 'session-storage' }),
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* ── What this file actually is ───────────────────────────────────────────────
|
|
15
|
+
* Vendor paths, a header name, and two JSON body shapes. That is the whole
|
|
16
|
+
* adapter, and it is the claim the hosting ports were designed to make: a
|
|
17
|
+
* container runtime's contract is a CONFIGURATION of HTTP work that already
|
|
18
|
+
* exists, not a second implementation of it. Nothing here reaches into the
|
|
19
|
+
* ports, and nothing here needed the ports to change.
|
|
20
|
+
*
|
|
21
|
+
* AgentCore Runtime is a **container contract**: an ARM64 image serving HTTP on
|
|
22
|
+
* `0.0.0.0:8080` —
|
|
23
|
+
*
|
|
24
|
+
* POST /invocations JSON `{ "prompt": "..." }` → JSON `{ "response", "status" }`
|
|
25
|
+
* GET /ping → `{ "status": "Healthy", "time_of_last_update": <unix seconds> }`
|
|
26
|
+
*
|
|
27
|
+
* and the caller's conversation arrives in the
|
|
28
|
+
* `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header rather than in the body,
|
|
29
|
+
* which is the one thing paths-and-bodies configuration alone could not
|
|
30
|
+
* express before this release.
|
|
31
|
+
*
|
|
32
|
+
* ── Verification status, stated plainly ──────────────────────────────────────
|
|
33
|
+
* `agentCoreRuntimeHost` is **plain HTTP and is really verified**: it runs the
|
|
34
|
+
* same host conformance suite as `nodeHost`, over a real socket, in
|
|
35
|
+
* `test/hosting/host-contract.test.ts`. There is no AWS SDK on its path.
|
|
36
|
+
*
|
|
37
|
+
* `agentCoreSessions({ store: 'memory' })` is **contract-mapped and
|
|
38
|
+
* injection-tested**: its AgentCore Memory calls are exercised through the
|
|
39
|
+
* `_client` seam, never against AWS. Confirm the command and field names
|
|
40
|
+
* against your installed `@aws-sdk/client-bedrock-agentcore` before you rely
|
|
41
|
+
* on it; real-cloud verification lands with a field deployment.
|
|
42
|
+
*
|
|
43
|
+
* Pattern: Adapter (GoF). Role: outer ring. The file-backed session store uses
|
|
44
|
+
* `node:fs` and nothing else; the event-backed one lazy-loads the AWS SDK, so
|
|
45
|
+
* importing this module costs zero peer-dep load.
|
|
46
|
+
*/
|
|
47
|
+
import type { HttpHost, HttpWire } from '../../hosting/httpHost.js';
|
|
48
|
+
import type { CheckpointEnvelope, SessionLifecycle } from '../../hosting/types.js';
|
|
49
|
+
/** Options for {@link agentCoreRuntimeHost}. */
|
|
50
|
+
export interface AgentCoreRuntimeHostOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Port to bind. Default `8080` — the port the container contract specifies.
|
|
53
|
+
* Pass `0` in tests to take an ephemeral one.
|
|
54
|
+
*/
|
|
55
|
+
readonly port?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Interface to bind. Default `'0.0.0.0'`, which the contract requires: bind
|
|
58
|
+
* to loopback inside the container and the runtime's health probe cannot
|
|
59
|
+
* reach you.
|
|
60
|
+
*/
|
|
61
|
+
readonly hostname?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Report `'HealthyBusy'` instead of `'Healthy'` on the health path.
|
|
64
|
+
*
|
|
65
|
+
* A function, not a flag, because busy is a live fact about the process, not
|
|
66
|
+
* a setting: the runtime reads it on every probe to decide whether to send
|
|
67
|
+
* you more work. Omit it and the host reports `'Healthy'`, which is the
|
|
68
|
+
* honest answer for an agent that answers synchronously.
|
|
69
|
+
*/
|
|
70
|
+
readonly busy?: () => boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The AgentCore Runtime contract as an {@link HttpWire}.
|
|
74
|
+
*
|
|
75
|
+
* Exported so the body shapes are inspectable and testable without binding a
|
|
76
|
+
* socket, and so a deployment that must serve the same bodies from somewhere
|
|
77
|
+
* else can reuse them by name.
|
|
78
|
+
*/
|
|
79
|
+
export declare function agentCoreRuntimeWire(busy?: () => boolean): HttpWire;
|
|
80
|
+
/**
|
|
81
|
+
* An `AgentHost` that speaks AgentCore Runtime's container contract.
|
|
82
|
+
*
|
|
83
|
+
* Passes the same conformance suite as `nodeHost` — it is the same HTTP host
|
|
84
|
+
* with this runtime's two paths, its header, and its two body shapes.
|
|
85
|
+
*
|
|
86
|
+
* @example The container's entry point
|
|
87
|
+
* const handle = await standingAgent({
|
|
88
|
+
* agent,
|
|
89
|
+
* host: agentCoreRuntimeHost(),
|
|
90
|
+
* sessions: agentCoreSessions({ store: 'session-storage' }),
|
|
91
|
+
* });
|
|
92
|
+
* process.on('SIGTERM', () => void handle.close());
|
|
93
|
+
*/
|
|
94
|
+
export declare function agentCoreRuntimeHost(options?: AgentCoreRuntimeHostOptions): HttpHost;
|
|
95
|
+
/**
|
|
96
|
+
* Where {@link agentCoreSessions} keeps a conversation between requests.
|
|
97
|
+
*
|
|
98
|
+
* - `'session-storage'` — a JSON file under the container's own storage. The
|
|
99
|
+
* runtime keeps that storage for the life of a session, INCLUDING across a
|
|
100
|
+
* stop/resume of the container, so a conversation survives the thing most
|
|
101
|
+
* likely to interrupt it. It does not survive the session ending.
|
|
102
|
+
* - `'memory'` — one AgentCore Memory event per persist. Outlives the session,
|
|
103
|
+
* the container and the deployment; costs an API call per turn and the
|
|
104
|
+
* `@aws-sdk/client-bedrock-agentcore` peer dependency.
|
|
105
|
+
*
|
|
106
|
+
* Chosen at construction, never per call: a store that silently changed where
|
|
107
|
+
* it wrote would be a store you cannot reason about after an incident.
|
|
108
|
+
*/
|
|
109
|
+
export type AgentCoreSessionStore = 'session-storage' | 'memory';
|
|
110
|
+
/** The default file the `'session-storage'` mode writes to. */
|
|
111
|
+
export declare const DEFAULT_SESSION_STORAGE_PATH = "/tmp/agentcore-session";
|
|
112
|
+
/** Options for the file-backed mode. */
|
|
113
|
+
export interface AgentCoreFileSessionsOptions {
|
|
114
|
+
readonly store: 'session-storage';
|
|
115
|
+
/**
|
|
116
|
+
* Where to write. Default {@link DEFAULT_SESSION_STORAGE_PATH}. One file
|
|
117
|
+
* holds every session this container has seen, keyed by session id — the
|
|
118
|
+
* runtime already gives each session its own storage, so the keying is
|
|
119
|
+
* belt-and-braces for the case where it does not.
|
|
120
|
+
*/
|
|
121
|
+
readonly path?: string;
|
|
122
|
+
}
|
|
123
|
+
/** One AgentCore Memory event, as this adapter cares about it. */
|
|
124
|
+
export interface AgentCoreSessionEvent {
|
|
125
|
+
/** Server-assigned event id. */
|
|
126
|
+
readonly eventId: string;
|
|
127
|
+
/** The envelope decoded from the event's blob payload, or `null` when unreadable. */
|
|
128
|
+
readonly envelope: unknown;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The minimal AgentCore Memory surface the session store calls. The real SDK is
|
|
132
|
+
* adapted to this shape in one function below; tests inject a fake via
|
|
133
|
+
* `_client` and never touch AWS.
|
|
134
|
+
*/
|
|
135
|
+
export interface AgentCoreSessionClientLike {
|
|
136
|
+
/** Append one envelope as an event (the server assigns the event id). */
|
|
137
|
+
createEvent(input: {
|
|
138
|
+
memoryId: string;
|
|
139
|
+
actorId: string;
|
|
140
|
+
sessionId: string;
|
|
141
|
+
envelope: CheckpointEnvelope;
|
|
142
|
+
}): Promise<void>;
|
|
143
|
+
/** The session's events, newest first — the adapter reads only the newest. */
|
|
144
|
+
listEvents(input: {
|
|
145
|
+
memoryId: string;
|
|
146
|
+
actorId: string;
|
|
147
|
+
sessionId: string;
|
|
148
|
+
maxResults?: number;
|
|
149
|
+
}): Promise<{
|
|
150
|
+
events: readonly AgentCoreSessionEvent[];
|
|
151
|
+
}>;
|
|
152
|
+
}
|
|
153
|
+
/** Options for the event-backed mode. */
|
|
154
|
+
export interface AgentCoreMemorySessionsOptions {
|
|
155
|
+
readonly store: 'memory';
|
|
156
|
+
/** AgentCore Memory ARN or id. Required. */
|
|
157
|
+
readonly memoryId: string;
|
|
158
|
+
/** AWS region, when the adapter constructs the SDK client itself. */
|
|
159
|
+
readonly region?: string;
|
|
160
|
+
/**
|
|
161
|
+
* The AgentCore `actorId` these conversations belong to. Default
|
|
162
|
+
* `'afp-standing-agent'`. One actor per deployed agent is the usual shape.
|
|
163
|
+
*/
|
|
164
|
+
readonly actorId?: string;
|
|
165
|
+
/** Pre-built client, to share one SDK config across the host app. */
|
|
166
|
+
readonly client?: AgentCoreSessionClientLike;
|
|
167
|
+
/** @internal Test injection — skips the SDK require entirely. */
|
|
168
|
+
readonly _client?: AgentCoreSessionClientLike;
|
|
169
|
+
/** @internal Test injection — the AWS SDK module, to exercise the real shim with a fake SDK. */
|
|
170
|
+
readonly _sdk?: BedrockAgentCoreSessionSdkModule;
|
|
171
|
+
}
|
|
172
|
+
/** Options for {@link agentCoreSessions}. */
|
|
173
|
+
export type AgentCoreSessionsOptions = AgentCoreFileSessionsOptions | AgentCoreMemorySessionsOptions;
|
|
174
|
+
/**
|
|
175
|
+
* A `SessionLifecycle` backed by AgentCore, with the checkpoint's home chosen
|
|
176
|
+
* at construction.
|
|
177
|
+
*
|
|
178
|
+
* Both modes store the SAME `CheckpointEnvelope` the port defines, and both
|
|
179
|
+
* refuse an unknown `format` by name through the shared `readEnvelope` — a
|
|
180
|
+
* conversation written by a newer runtime is refused, never half-restored.
|
|
181
|
+
* That law is inherited, not re-implemented.
|
|
182
|
+
*
|
|
183
|
+
* @example Survive a stop/resume, no AWS SDK required
|
|
184
|
+
* agentCoreSessions({ store: 'session-storage' });
|
|
185
|
+
*
|
|
186
|
+
* @example Outlive the session entirely
|
|
187
|
+
* agentCoreSessions({ store: 'memory', memoryId: process.env.MEMORY_ID!, region: 'us-west-2' });
|
|
188
|
+
*/
|
|
189
|
+
export declare function agentCoreSessions(options: AgentCoreSessionsOptions): SessionLifecycle;
|
|
190
|
+
/** The slice of `@aws-sdk/client-bedrock-agentcore` this shim touches. */
|
|
191
|
+
export interface BedrockAgentCoreSessionSdkModule {
|
|
192
|
+
readonly BedrockAgentCoreClient?: new (config: {
|
|
193
|
+
region?: string;
|
|
194
|
+
}) => {
|
|
195
|
+
send(cmd: unknown): Promise<unknown>;
|
|
196
|
+
};
|
|
197
|
+
readonly CreateEventCommand?: new (input: unknown) => unknown;
|
|
198
|
+
readonly ListEventsCommand?: new (input: unknown) => unknown;
|
|
199
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/hosting/agentcore — AWS Bedrock **AgentCore Runtime** adapters for
|
|
3
|
+
* the two hosting ports.
|
|
4
|
+
*
|
|
5
|
+
* import { agentCoreRuntimeHost, agentCoreSessions } from 'agentfootprint/hosting-providers';
|
|
6
|
+
* import { standingAgent } from 'agentfootprint/hosting';
|
|
7
|
+
*
|
|
8
|
+
* const handle = await standingAgent({
|
|
9
|
+
* agent,
|
|
10
|
+
* host: agentCoreRuntimeHost(),
|
|
11
|
+
* sessions: agentCoreSessions({ store: 'session-storage' }),
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* ── What this file actually is ───────────────────────────────────────────────
|
|
15
|
+
* Vendor paths, a header name, and two JSON body shapes. That is the whole
|
|
16
|
+
* adapter, and it is the claim the hosting ports were designed to make: a
|
|
17
|
+
* container runtime's contract is a CONFIGURATION of HTTP work that already
|
|
18
|
+
* exists, not a second implementation of it. Nothing here reaches into the
|
|
19
|
+
* ports, and nothing here needed the ports to change.
|
|
20
|
+
*
|
|
21
|
+
* AgentCore Runtime is a **container contract**: an ARM64 image serving HTTP on
|
|
22
|
+
* `0.0.0.0:8080` —
|
|
23
|
+
*
|
|
24
|
+
* POST /invocations JSON `{ "prompt": "..." }` → JSON `{ "response", "status" }`
|
|
25
|
+
* GET /ping → `{ "status": "Healthy", "time_of_last_update": <unix seconds> }`
|
|
26
|
+
*
|
|
27
|
+
* and the caller's conversation arrives in the
|
|
28
|
+
* `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header rather than in the body,
|
|
29
|
+
* which is the one thing paths-and-bodies configuration alone could not
|
|
30
|
+
* express before this release.
|
|
31
|
+
*
|
|
32
|
+
* ── Verification status, stated plainly ──────────────────────────────────────
|
|
33
|
+
* `agentCoreRuntimeHost` is **plain HTTP and is really verified**: it runs the
|
|
34
|
+
* same host conformance suite as `nodeHost`, over a real socket, in
|
|
35
|
+
* `test/hosting/host-contract.test.ts`. There is no AWS SDK on its path.
|
|
36
|
+
*
|
|
37
|
+
* `agentCoreSessions({ store: 'memory' })` is **contract-mapped and
|
|
38
|
+
* injection-tested**: its AgentCore Memory calls are exercised through the
|
|
39
|
+
* `_client` seam, never against AWS. Confirm the command and field names
|
|
40
|
+
* against your installed `@aws-sdk/client-bedrock-agentcore` before you rely
|
|
41
|
+
* on it; real-cloud verification lands with a field deployment.
|
|
42
|
+
*
|
|
43
|
+
* Pattern: Adapter (GoF). Role: outer ring. The file-backed session store uses
|
|
44
|
+
* `node:fs` and nothing else; the event-backed one lazy-loads the AWS SDK, so
|
|
45
|
+
* importing this module costs zero peer-dep load.
|
|
46
|
+
*/
|
|
47
|
+
import { readEnvelope } from '../../hosting/envelope.js';
|
|
48
|
+
import { headerValue, httpHost } from '../../hosting/httpHost.js';
|
|
49
|
+
import { lazyRequire } from '../../lib/lazyRequire.js';
|
|
50
|
+
// ─── The runtime host ────────────────────────────────────────────────
|
|
51
|
+
const HOST_NAME = 'agentCoreRuntimeHost';
|
|
52
|
+
/** The runtime's container contract, as constants rather than as scattered literals. */
|
|
53
|
+
const INVOKE_PATH = '/invocations';
|
|
54
|
+
const HEALTH_PATH = '/ping';
|
|
55
|
+
const RUNTIME_PORT = 8080;
|
|
56
|
+
/**
|
|
57
|
+
* The header the runtime puts the caller's conversation in. Matched
|
|
58
|
+
* case-insensitively — HTTP header names are case-insensitive and a proxy in
|
|
59
|
+
* front of the container is free to re-case them.
|
|
60
|
+
*/
|
|
61
|
+
const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
|
|
62
|
+
/**
|
|
63
|
+
* The AgentCore Runtime contract as an {@link HttpWire}.
|
|
64
|
+
*
|
|
65
|
+
* Exported so the body shapes are inspectable and testable without binding a
|
|
66
|
+
* socket, and so a deployment that must serve the same bodies from somewhere
|
|
67
|
+
* else can reuse them by name.
|
|
68
|
+
*/
|
|
69
|
+
export function agentCoreRuntimeWire(busy) {
|
|
70
|
+
return {
|
|
71
|
+
readRequest(facts) {
|
|
72
|
+
// `prompt` is the field the runtime's own quickstart and this repo's
|
|
73
|
+
// deploy template use. `input` is accepted too because the runtime passes
|
|
74
|
+
// the payload through verbatim — it is the CALLER who picks the field —
|
|
75
|
+
// and refusing a caller who used the port's own word would be a rule this
|
|
76
|
+
// adapter invented rather than one the contract imposes.
|
|
77
|
+
const prompt = facts.body.prompt ?? facts.body.input;
|
|
78
|
+
const input = typeof prompt === 'string' ? prompt : '';
|
|
79
|
+
// The conversation id arrives in a header, never in the body. It is
|
|
80
|
+
// caller-adjacent data, not identity — the port says so and it is just as
|
|
81
|
+
// true here.
|
|
82
|
+
const sessionId = headerValue(facts, SESSION_HEADER);
|
|
83
|
+
return sessionId !== undefined ? { input, sessionId } : { input };
|
|
84
|
+
},
|
|
85
|
+
// The runtime polls this to decide whether the container is ready and
|
|
86
|
+
// whether to send it more work. `time_of_last_update` is unix SECONDS.
|
|
87
|
+
health: () => ({
|
|
88
|
+
status: busy?.() === true ? 'HealthyBusy' : 'Healthy',
|
|
89
|
+
time_of_last_update: Math.floor(Date.now() / 1000),
|
|
90
|
+
}),
|
|
91
|
+
output: (response) => ({ response, status: 'success' }),
|
|
92
|
+
// The message only — never a stack. The runtime surfaces the status code;
|
|
93
|
+
// the body is read by whoever called the agent.
|
|
94
|
+
failure: (error, code) => ({ error, status: 'error', ...(code !== undefined && { code }) }),
|
|
95
|
+
// A distinct field from `response` on purpose: a caller concatenating
|
|
96
|
+
// stream frames must not be able to double-count the final answer by
|
|
97
|
+
// reading the same key twice.
|
|
98
|
+
chunk: (chunk) => ({ chunk }),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* An `AgentHost` that speaks AgentCore Runtime's container contract.
|
|
103
|
+
*
|
|
104
|
+
* Passes the same conformance suite as `nodeHost` — it is the same HTTP host
|
|
105
|
+
* with this runtime's two paths, its header, and its two body shapes.
|
|
106
|
+
*
|
|
107
|
+
* @example The container's entry point
|
|
108
|
+
* const handle = await standingAgent({
|
|
109
|
+
* agent,
|
|
110
|
+
* host: agentCoreRuntimeHost(),
|
|
111
|
+
* sessions: agentCoreSessions({ store: 'session-storage' }),
|
|
112
|
+
* });
|
|
113
|
+
* process.on('SIGTERM', () => void handle.close());
|
|
114
|
+
*/
|
|
115
|
+
export function agentCoreRuntimeHost(options = {}) {
|
|
116
|
+
return httpHost({
|
|
117
|
+
name: HOST_NAME,
|
|
118
|
+
wire: agentCoreRuntimeWire(options.busy),
|
|
119
|
+
invokePath: INVOKE_PATH,
|
|
120
|
+
healthPath: HEALTH_PATH,
|
|
121
|
+
port: options.port ?? RUNTIME_PORT,
|
|
122
|
+
hostname: options.hostname ?? '0.0.0.0',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/** The default file the `'session-storage'` mode writes to. */
|
|
126
|
+
export const DEFAULT_SESSION_STORAGE_PATH = '/tmp/agentcore-session';
|
|
127
|
+
/**
|
|
128
|
+
* A `SessionLifecycle` backed by AgentCore, with the checkpoint's home chosen
|
|
129
|
+
* at construction.
|
|
130
|
+
*
|
|
131
|
+
* Both modes store the SAME `CheckpointEnvelope` the port defines, and both
|
|
132
|
+
* refuse an unknown `format` by name through the shared `readEnvelope` — a
|
|
133
|
+
* conversation written by a newer runtime is refused, never half-restored.
|
|
134
|
+
* That law is inherited, not re-implemented.
|
|
135
|
+
*
|
|
136
|
+
* @example Survive a stop/resume, no AWS SDK required
|
|
137
|
+
* agentCoreSessions({ store: 'session-storage' });
|
|
138
|
+
*
|
|
139
|
+
* @example Outlive the session entirely
|
|
140
|
+
* agentCoreSessions({ store: 'memory', memoryId: process.env.MEMORY_ID!, region: 'us-west-2' });
|
|
141
|
+
*/
|
|
142
|
+
export function agentCoreSessions(options) {
|
|
143
|
+
return options.store === 'memory' ? memoryEventSessions(options) : fileSessions(options);
|
|
144
|
+
}
|
|
145
|
+
function fileSessions(options) {
|
|
146
|
+
const path = options.path ?? DEFAULT_SESSION_STORAGE_PATH;
|
|
147
|
+
async function readFile() {
|
|
148
|
+
const { readFile: read } = await import('node:fs/promises');
|
|
149
|
+
let raw;
|
|
150
|
+
try {
|
|
151
|
+
raw = await read(path, 'utf8');
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// No file yet is the ordinary first-request state, not an error.
|
|
155
|
+
return { version: 1, sessions: {} };
|
|
156
|
+
}
|
|
157
|
+
let parsed;
|
|
158
|
+
try {
|
|
159
|
+
parsed = JSON.parse(raw);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
throw new TypeError(`[hosting] the session file at '${path}' is not JSON (${err.message}). ` +
|
|
163
|
+
`Refusing rather than starting every conversation over silently — delete the file ` +
|
|
164
|
+
`to start fresh, or point 'path' somewhere else.`);
|
|
165
|
+
}
|
|
166
|
+
const sessions = parsed?.sessions;
|
|
167
|
+
return sessions && typeof sessions === 'object'
|
|
168
|
+
? { version: 1, sessions: sessions }
|
|
169
|
+
: { version: 1, sessions: {} };
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
async hydrate(sessionId) {
|
|
173
|
+
const file = await readFile();
|
|
174
|
+
const stored = file.sessions[sessionId];
|
|
175
|
+
if (stored === undefined)
|
|
176
|
+
return undefined;
|
|
177
|
+
// Validate HERE as well as in the composer, so a refusal points at the
|
|
178
|
+
// store that produced the bytes rather than at whoever read them next.
|
|
179
|
+
readEnvelope(stored);
|
|
180
|
+
return stored;
|
|
181
|
+
},
|
|
182
|
+
async persist(sessionId, envelope) {
|
|
183
|
+
const { writeFile, rename, mkdir } = await import('node:fs/promises');
|
|
184
|
+
const { dirname } = await import('node:path');
|
|
185
|
+
const file = await readFile();
|
|
186
|
+
const next = {
|
|
187
|
+
version: 1,
|
|
188
|
+
sessions: { ...file.sessions, [sessionId]: envelope },
|
|
189
|
+
};
|
|
190
|
+
await mkdir(dirname(path), { recursive: true }).catch(() => undefined);
|
|
191
|
+
// Write-then-rename: a container killed mid-write leaves the previous
|
|
192
|
+
// conversation intact rather than a truncated file that refuses to parse.
|
|
193
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
194
|
+
await writeFile(temporary, JSON.stringify(next), 'utf8');
|
|
195
|
+
await rename(temporary, path);
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// ─── 'memory': one AgentCore Memory event per persist ────────────────
|
|
200
|
+
const DEFAULT_ACTOR_ID = 'afp-standing-agent';
|
|
201
|
+
function memoryEventSessions(options) {
|
|
202
|
+
if (!options.memoryId) {
|
|
203
|
+
throw new Error(`agentCoreSessions({ store: 'memory' }) requires 'memoryId'.`);
|
|
204
|
+
}
|
|
205
|
+
const memoryId = options.memoryId;
|
|
206
|
+
const actorId = options.actorId ?? DEFAULT_ACTOR_ID;
|
|
207
|
+
const client = options._client ?? options.client ?? createSessionClient(options.region, options._sdk);
|
|
208
|
+
return {
|
|
209
|
+
async hydrate(sessionId) {
|
|
210
|
+
// AgentCore Memory is an append-only log and lists newest-first, so the
|
|
211
|
+
// newest readable event IS the conversation. Older ones are the earlier
|
|
212
|
+
// turns and deliberately left where they are — they are the audit trail.
|
|
213
|
+
const page = await client.listEvents({
|
|
214
|
+
memoryId,
|
|
215
|
+
actorId,
|
|
216
|
+
sessionId: safeSessionId(sessionId),
|
|
217
|
+
maxResults: 1,
|
|
218
|
+
});
|
|
219
|
+
const newest = page.events[0];
|
|
220
|
+
if (!newest || newest.envelope === null || newest.envelope === undefined)
|
|
221
|
+
return undefined;
|
|
222
|
+
readEnvelope(newest.envelope);
|
|
223
|
+
return newest.envelope;
|
|
224
|
+
},
|
|
225
|
+
async persist(sessionId, envelope) {
|
|
226
|
+
await client.createEvent({
|
|
227
|
+
memoryId,
|
|
228
|
+
actorId,
|
|
229
|
+
sessionId: safeSessionId(sessionId),
|
|
230
|
+
envelope,
|
|
231
|
+
});
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const SESSION_ID_MAX = 99;
|
|
236
|
+
/** AgentCore ids accept `[A-Za-z0-9_-]`; a session id is caller data and need not. */
|
|
237
|
+
function safeSessionId(raw) {
|
|
238
|
+
const slug = raw.replace(/[^A-Za-z0-9_-]/g, '-');
|
|
239
|
+
if (slug.length <= SESSION_ID_MAX)
|
|
240
|
+
return slug;
|
|
241
|
+
// Keep a readable head plus a stable tail so two long ids stay distinct.
|
|
242
|
+
return `${slug.slice(0, SESSION_ID_MAX - 9)}-${fnv1a(raw)}`;
|
|
243
|
+
}
|
|
244
|
+
function fnv1a(s) {
|
|
245
|
+
let h = 0x811c9dc5;
|
|
246
|
+
for (let i = 0; i < s.length; i++) {
|
|
247
|
+
h ^= s.charCodeAt(i);
|
|
248
|
+
h = Math.imul(h, 0x01000193);
|
|
249
|
+
}
|
|
250
|
+
return (h >>> 0).toString(36);
|
|
251
|
+
}
|
|
252
|
+
/** Pull the envelope out of an event's `payload` (a single `blob` document). */
|
|
253
|
+
function envelopeFromPayload(payload) {
|
|
254
|
+
if (!Array.isArray(payload))
|
|
255
|
+
return null;
|
|
256
|
+
for (const part of payload) {
|
|
257
|
+
const blob = part?.blob;
|
|
258
|
+
if (blob && typeof blob === 'object')
|
|
259
|
+
return blob;
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Map {@link AgentCoreSessionClientLike} onto the real SDK commands. If AWS
|
|
265
|
+
* renames a command, only this function changes — which is also why every test
|
|
266
|
+
* injects past it.
|
|
267
|
+
*/
|
|
268
|
+
function createSessionClient(region, injected) {
|
|
269
|
+
let mod;
|
|
270
|
+
if (injected) {
|
|
271
|
+
mod = injected;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
try {
|
|
275
|
+
mod = lazyRequire('@aws-sdk/client-bedrock-agentcore');
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
throw new Error(`agentCoreSessions({ store: 'memory' }) requires the ` +
|
|
279
|
+
'`@aws-sdk/client-bedrock-agentcore` peer dependency.\n' +
|
|
280
|
+
' Install: npm install @aws-sdk/client-bedrock-agentcore\n' +
|
|
281
|
+
" Or use { store: 'session-storage' }, which needs no SDK at all.");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (!mod.BedrockAgentCoreClient) {
|
|
285
|
+
throw new Error('agentCoreSessions: `@aws-sdk/client-bedrock-agentcore` is installed but ' +
|
|
286
|
+
'`BedrockAgentCoreClient` was not found. Update the SDK.');
|
|
287
|
+
}
|
|
288
|
+
const sdk = new mod.BedrockAgentCoreClient({ ...(region && { region }) });
|
|
289
|
+
const send = async (Ctor, name, input) => {
|
|
290
|
+
if (!Ctor) {
|
|
291
|
+
throw new Error(`agentCoreSessions: \`@aws-sdk/client-bedrock-agentcore\` is missing ${name}. Upgrade the SDK.`);
|
|
292
|
+
}
|
|
293
|
+
return sdk.send(new Ctor(input));
|
|
294
|
+
};
|
|
295
|
+
return {
|
|
296
|
+
async createEvent({ memoryId, actorId, sessionId, envelope }) {
|
|
297
|
+
await send(mod.CreateEventCommand, 'CreateEventCommand', {
|
|
298
|
+
memoryId,
|
|
299
|
+
actorId,
|
|
300
|
+
sessionId,
|
|
301
|
+
eventTimestamp: new Date(),
|
|
302
|
+
payload: [{ blob: envelope }],
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
async listEvents({ memoryId, actorId, sessionId, maxResults }) {
|
|
306
|
+
const result = (await send(mod.ListEventsCommand, 'ListEventsCommand', {
|
|
307
|
+
memoryId,
|
|
308
|
+
actorId,
|
|
309
|
+
sessionId,
|
|
310
|
+
includePayloads: true,
|
|
311
|
+
...(maxResults !== undefined && { maxResults }),
|
|
312
|
+
}));
|
|
313
|
+
const events = (result?.events ?? []).map((event) => ({
|
|
314
|
+
eventId: event.eventId ?? '',
|
|
315
|
+
envelope: envelopeFromPayload(event.payload),
|
|
316
|
+
}));
|
|
317
|
+
return { events };
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=agentcore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../../src/adapters/hosting/agentcore.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,14 +27,20 @@
|
|
|
27
27
|
* AgentCore's ids are server-assigned. **O(events in session)** — fine for typical
|
|
28
28
|
* window sizes; if you need O(1) keyed access at scale, use RedisStore.
|
|
29
29
|
* • `forget` → `ListEvents` + `DeleteEvent` per event (no `DeleteSession` on AgentCore).
|
|
30
|
-
* • `search` →
|
|
30
|
+
* • `search` → `RetrieveMemoryRecords`, **text-in**. AgentCore embeds and ranks on its
|
|
31
|
+
* own side, so it takes a natural-language query; the port's `search()` takes a
|
|
32
|
+
* vector. Pass `options.text` and this store serves the query; omit it and it refuses
|
|
33
|
+
* by name rather than ranking an empty set. See `search()` below for the whole story.
|
|
31
34
|
* • `putIfVersion` / `seen` / `feedback` → in-process emulation (AgentCore has no native
|
|
32
35
|
* CAS / dedup / feedback primitive; these don't survive process restart).
|
|
36
|
+
* • no `stream()` — AgentCore Memory has no streaming data-plane operation, and the
|
|
37
|
+
* `MemoryStore` port has no streaming method to implement. Inventing one for a single
|
|
38
|
+
* backend is how a port stops being a port.
|
|
33
39
|
*
|
|
34
40
|
* Role: Outer ring. Lazy-requires the AWS SDK; zero runtime cost when another adapter is
|
|
35
41
|
* in use. Emits: N/A (storage adapters don't emit).
|
|
36
42
|
*/
|
|
37
|
-
import type { ListOptions, ListResult, MemoryStore, PutIfVersionResult } from '../../memory/store/types.js';
|
|
43
|
+
import type { ListOptions, ListResult, MemoryStore, PutIfVersionResult, ScoredEntry, SearchOptions } from '../../memory/store/types.js';
|
|
38
44
|
import type { MemoryEntry } from '../../memory/entry/index.js';
|
|
39
45
|
import type { MemoryIdentity } from '../../memory/identity/index.js';
|
|
40
46
|
/** One event as the adapter cares about it: AgentCore's id + the decoded entry. */
|
|
@@ -75,6 +81,35 @@ export interface AgentCoreLikeClient {
|
|
|
75
81
|
sessionId: string;
|
|
76
82
|
eventId: string;
|
|
77
83
|
}): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Server-side semantic retrieval (`RetrieveMemoryRecords`). Optional: a client
|
|
86
|
+
* built before this existed still satisfies the interface, and `search()`
|
|
87
|
+
* feature-detects it rather than assuming.
|
|
88
|
+
*/
|
|
89
|
+
retrieveRecords?(input: {
|
|
90
|
+
memoryId: string;
|
|
91
|
+
namespace: string;
|
|
92
|
+
searchQuery: string;
|
|
93
|
+
maxResults?: number;
|
|
94
|
+
memoryStrategyId?: string;
|
|
95
|
+
}): Promise<{
|
|
96
|
+
records: readonly AgentCoreMemoryRecord[];
|
|
97
|
+
}>;
|
|
98
|
+
}
|
|
99
|
+
/** One record as `RetrieveMemoryRecords` returns it. */
|
|
100
|
+
export interface AgentCoreMemoryRecord {
|
|
101
|
+
/** AgentCore's own record id. */
|
|
102
|
+
readonly memoryRecordId: string;
|
|
103
|
+
/** The record's text content. */
|
|
104
|
+
readonly content: string;
|
|
105
|
+
/** Relevance as AgentCore scored it, when it reports one. */
|
|
106
|
+
readonly score?: number;
|
|
107
|
+
/** Which strategy produced the record (semantic, summary, user-preference, …). */
|
|
108
|
+
readonly memoryStrategyId?: string;
|
|
109
|
+
/** The namespace it was found in. */
|
|
110
|
+
readonly namespace?: string;
|
|
111
|
+
/** When AgentCore created it (unix ms), when reported. */
|
|
112
|
+
readonly createdAt?: number;
|
|
78
113
|
}
|
|
79
114
|
export interface AgentCoreStoreOptions {
|
|
80
115
|
/** AgentCore Memory ARN or id. Required. */
|
|
@@ -85,6 +120,27 @@ export interface AgentCoreStoreOptions {
|
|
|
85
120
|
readonly client?: AgentCoreLikeClient;
|
|
86
121
|
/** Page size for `listEvents`. Default 100. */
|
|
87
122
|
readonly pageSize?: number;
|
|
123
|
+
/**
|
|
124
|
+
* Where `search()` looks. AgentCore organises extracted memory records into
|
|
125
|
+
* namespaces configured on the Memory resource's strategies (commonly
|
|
126
|
+
* something like `/strategies/{strategyId}/actors/{actorId}`).
|
|
127
|
+
*
|
|
128
|
+
* A function, because the namespace usually contains the actor: it is handed
|
|
129
|
+
* the resolved AgentCore ids for the identity being searched. Default:
|
|
130
|
+
* `/actors/{actorId}/sessions/{sessionId}` — the session's own records.
|
|
131
|
+
*/
|
|
132
|
+
readonly searchNamespace?: (scope: {
|
|
133
|
+
readonly actorId: string;
|
|
134
|
+
readonly sessionId: string;
|
|
135
|
+
}) => string;
|
|
136
|
+
/**
|
|
137
|
+
* Restrict `search()` to one extraction strategy (semantic, summary,
|
|
138
|
+
* user-preference…). Omit to search across all of them.
|
|
139
|
+
*
|
|
140
|
+
* This is the metadata filter that reaches AgentCore's own side; `tiers` /
|
|
141
|
+
* `minScore` / `k` from {@link SearchOptions} are applied to what comes back.
|
|
142
|
+
*/
|
|
143
|
+
readonly searchStrategyId?: string;
|
|
88
144
|
/** @internal Test injection — skips the SDK require entirely. */
|
|
89
145
|
readonly _client?: AgentCoreLikeClient;
|
|
90
146
|
/** @internal Test injection — the AWS SDK module (to exercise the real shim with a mock SDK). */
|
|
@@ -100,6 +156,8 @@ export declare class AgentCoreStore implements MemoryStore {
|
|
|
100
156
|
private readonly client;
|
|
101
157
|
private readonly memoryId;
|
|
102
158
|
private readonly pageSize;
|
|
159
|
+
private readonly searchNamespace;
|
|
160
|
+
private readonly searchStrategyId;
|
|
103
161
|
private closed;
|
|
104
162
|
private readonly signatures;
|
|
105
163
|
private readonly feedbackBag;
|
|
@@ -130,6 +188,33 @@ export declare class AgentCoreStore implements MemoryStore {
|
|
|
130
188
|
} | null>;
|
|
131
189
|
/** GDPR "everything for this identity, gone." No DeleteSession on AgentCore → delete every event. */
|
|
132
190
|
forget(identity: MemoryIdentity): Promise<void>;
|
|
191
|
+
/**
|
|
192
|
+
* Server-side semantic retrieval over AgentCore's extracted memory records
|
|
193
|
+
* (`RetrieveMemoryRecords`).
|
|
194
|
+
*
|
|
195
|
+
* ── Read this before you call it ─────────────────────────────────────────
|
|
196
|
+
* **It takes TEXT, not the vector.** AgentCore embeds and ranks on its own
|
|
197
|
+
* side, so `query` — the port's vector — is unusable here, and the query it
|
|
198
|
+
* actually needs travels in `options.text`. Omit that and this method throws
|
|
199
|
+
* a corrective error naming what is missing, because the alternative is
|
|
200
|
+
* ranking nothing and handing back `[]`, which reads as "no matches" when it
|
|
201
|
+
* really means "wrong query form". Pass both and every store can serve you:
|
|
202
|
+
* local-ranking backends use the vector and ignore the text.
|
|
203
|
+
*
|
|
204
|
+
* **It searches a DIFFERENT population than `list()`.** `list` returns the
|
|
205
|
+
* events this store wrote. This returns the records AgentCore's extraction
|
|
206
|
+
* strategies derived FROM those events — summaries, semantic facts, user
|
|
207
|
+
* preferences. The ids therefore belong to AgentCore, not to entries you
|
|
208
|
+
* `put()`, and `store.get(entry.id)` will not find them. They arrive as
|
|
209
|
+
* entries so ranking code needs no special case, with `metadata.source`
|
|
210
|
+
* saying plainly where they came from.
|
|
211
|
+
*
|
|
212
|
+
* Filters: `searchStrategyId` and the namespace reach AgentCore's own side;
|
|
213
|
+
* `k`, `minScore` and `tiers` are applied to what comes back.
|
|
214
|
+
*
|
|
215
|
+
* @throws when `options.text` is absent, or when the client cannot retrieve.
|
|
216
|
+
*/
|
|
217
|
+
search<T = unknown>(identity: MemoryIdentity, query: readonly number[], options?: SearchOptions): Promise<readonly ScoredEntry<T>[]>;
|
|
133
218
|
close(): Promise<void>;
|
|
134
219
|
private ensureOpen;
|
|
135
220
|
}
|
|
@@ -143,4 +228,5 @@ export interface BedrockAgentCoreSdkModule {
|
|
|
143
228
|
readonly CreateEventCommand?: new (input: unknown) => unknown;
|
|
144
229
|
readonly ListEventsCommand?: new (input: unknown) => unknown;
|
|
145
230
|
readonly DeleteEventCommand?: new (input: unknown) => unknown;
|
|
231
|
+
readonly RetrieveMemoryRecordsCommand?: new (input: unknown) => unknown;
|
|
146
232
|
}
|