agentfootprint 7.24.0 → 7.26.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/AGENTS.md +1 -1
- package/CLAUDE.md +5 -3
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/hosting/agentcore.js +112 -1
- package/dist/adapters/hosting/agentcore.js.map +1 -1
- package/dist/adapters/llm/AnthropicProvider.js +10 -0
- package/dist/adapters/llm/AnthropicProvider.js.map +1 -1
- package/dist/adapters/llm/BedrockProvider.js +13 -1
- package/dist/adapters/llm/BedrockProvider.js.map +1 -1
- package/dist/adapters/llm/BrowserAnthropicProvider.js +6 -0
- package/dist/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
- package/dist/adapters/llm/BrowserOpenAIProvider.js +18 -0
- package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/MockProvider.js +9 -0
- package/dist/adapters/llm/MockProvider.js.map +1 -1
- package/dist/adapters/llm/OpenAIProvider.js +21 -0
- package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/conventions.js +12 -0
- package/dist/conventions.js.map +1 -1
- package/dist/core/Agent.js +56 -2
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +98 -1
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/buildAgentChart.js +12 -2
- package/dist/core/agent/buildAgentChart.js.map +1 -1
- package/dist/core/agent/buildDynamicAgentChart.js +12 -3
- package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/core/agent/outputEnforcement.js +192 -0
- package/dist/core/agent/outputEnforcement.js.map +1 -0
- package/dist/core/agent/stages/callLLM.js +31 -1
- package/dist/core/agent/stages/callLLM.js.map +1 -1
- package/dist/core/agent/stages/outputRetry.js +102 -0
- package/dist/core/agent/stages/outputRetry.js.map +1 -0
- package/dist/core/agent/stages/route.js +111 -6
- package/dist/core/agent/stages/route.js.map +1 -1
- package/dist/core/outputSchema.js.map +1 -1
- package/dist/esm/adapters/hosting/agentcore.d.ts +50 -1
- package/dist/esm/adapters/hosting/agentcore.js +110 -0
- package/dist/esm/adapters/hosting/agentcore.js.map +1 -1
- package/dist/esm/adapters/llm/AnthropicProvider.d.ts +10 -0
- package/dist/esm/adapters/llm/AnthropicProvider.js +10 -0
- package/dist/esm/adapters/llm/AnthropicProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BedrockProvider.d.ts +9 -0
- package/dist/esm/adapters/llm/BedrockProvider.js +13 -1
- package/dist/esm/adapters/llm/BedrockProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.d.ts +1 -0
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.js +6 -0
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.d.ts +4 -0
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js +18 -0
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/MockProvider.d.ts +9 -0
- package/dist/esm/adapters/llm/MockProvider.js +9 -0
- package/dist/esm/adapters/llm/MockProvider.js.map +1 -1
- package/dist/esm/adapters/llm/OpenAIProvider.d.ts +12 -0
- package/dist/esm/adapters/llm/OpenAIProvider.js +21 -0
- package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/types.d.ts +46 -0
- package/dist/esm/conventions.d.ts +4 -0
- package/dist/esm/conventions.js +12 -0
- package/dist/esm/conventions.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +26 -1
- package/dist/esm/core/Agent.js +56 -2
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.d.ts +15 -0
- package/dist/esm/core/agent/AgentBuilder.js +98 -1
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/buildAgentChart.d.ts +13 -1
- package/dist/esm/core/agent/buildAgentChart.js +12 -2
- package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js +12 -3
- package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/esm/core/agent/outputEnforcement.d.ts +173 -0
- package/dist/esm/core/agent/outputEnforcement.js +180 -0
- package/dist/esm/core/agent/outputEnforcement.js.map +1 -0
- package/dist/esm/core/agent/stages/callLLM.d.ts +15 -0
- package/dist/esm/core/agent/stages/callLLM.js +31 -1
- package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
- package/dist/esm/core/agent/stages/outputRetry.d.ts +34 -0
- package/dist/esm/core/agent/stages/outputRetry.js +98 -0
- package/dist/esm/core/agent/stages/outputRetry.js.map +1 -0
- package/dist/esm/core/agent/stages/route.d.ts +18 -2
- package/dist/esm/core/agent/stages/route.js +111 -6
- package/dist/esm/core/agent/stages/route.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +18 -0
- package/dist/esm/core/outputSchema.d.ts +51 -0
- package/dist/esm/core/outputSchema.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +47 -1
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/hosting/errors.d.ts +44 -2
- package/dist/esm/hosting/errors.js +63 -0
- package/dist/esm/hosting/errors.js.map +1 -1
- package/dist/esm/hosting/headers.d.ts +16 -0
- package/dist/esm/hosting/headers.js +24 -0
- package/dist/esm/hosting/headers.js.map +1 -0
- package/dist/esm/hosting/httpHost.d.ts +70 -4
- package/dist/esm/hosting/httpHost.js +211 -47
- package/dist/esm/hosting/httpHost.js.map +1 -1
- package/dist/esm/hosting/index.d.ts +23 -8
- package/dist/esm/hosting/index.js +21 -6
- package/dist/esm/hosting/index.js.map +1 -1
- package/dist/esm/hosting/nodeHost.d.ts +23 -0
- package/dist/esm/hosting/nodeHost.js +21 -1
- package/dist/esm/hosting/nodeHost.js.map +1 -1
- package/dist/esm/hosting/types.d.ts +212 -6
- package/dist/esm/hosting/types.js +7 -5
- package/dist/esm/hosting/types.js.map +1 -1
- package/dist/esm/hosting/webSocketConversation.d.ts +101 -0
- package/dist/esm/hosting/webSocketConversation.js +341 -0
- package/dist/esm/hosting/webSocketConversation.js.map +1 -0
- package/dist/esm/hosting/webSocketFrames.d.ts +164 -0
- package/dist/esm/hosting/webSocketFrames.js +284 -0
- package/dist/esm/hosting/webSocketFrames.js.map +1 -0
- package/dist/esm/hosting-providers.d.ts +7 -2
- package/dist/esm/hosting-providers.js +7 -2
- package/dist/esm/hosting-providers.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resilience/withCircuitBreaker.js +5 -0
- package/dist/esm/resilience/withCircuitBreaker.js.map +1 -1
- package/dist/esm/resilience/withFallback.js +5 -0
- package/dist/esm/resilience/withFallback.js.map +1 -1
- package/dist/esm/resilience/withRetry.js +6 -0
- package/dist/esm/resilience/withRetry.js.map +1 -1
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/hosting/errors.js +66 -1
- package/dist/hosting/errors.js.map +1 -1
- package/dist/hosting/headers.js +28 -0
- package/dist/hosting/headers.js.map +1 -0
- package/dist/hosting/httpHost.js +211 -47
- package/dist/hosting/httpHost.js.map +1 -1
- package/dist/hosting/index.js +23 -6
- package/dist/hosting/index.js.map +1 -1
- package/dist/hosting/nodeHost.js +20 -0
- package/dist/hosting/nodeHost.js.map +1 -1
- package/dist/hosting/types.js +7 -5
- package/dist/hosting/types.js.map +1 -1
- package/dist/hosting/webSocketConversation.js +345 -0
- package/dist/hosting/webSocketConversation.js.map +1 -0
- package/dist/hosting/webSocketFrames.js +297 -0
- package/dist/hosting/webSocketFrames.js.map +1 -0
- package/dist/hosting-providers.js +8 -2
- package/dist/hosting-providers.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/resilience/withCircuitBreaker.js +5 -0
- package/dist/resilience/withCircuitBreaker.js.map +1 -1
- package/dist/resilience/withFallback.js +5 -0
- package/dist/resilience/withFallback.js.map +1 -1
- package/dist/resilience/withRetry.js +6 -0
- package/dist/resilience/withRetry.js.map +1 -1
- package/dist/types/adapters/hosting/agentcore.d.ts +50 -1
- package/dist/types/adapters/hosting/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/llm/AnthropicProvider.d.ts +10 -0
- package/dist/types/adapters/llm/AnthropicProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BedrockProvider.d.ts +9 -0
- package/dist/types/adapters/llm/BedrockProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BrowserAnthropicProvider.d.ts +1 -0
- package/dist/types/adapters/llm/BrowserAnthropicProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts +4 -0
- package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/MockProvider.d.ts +9 -0
- package/dist/types/adapters/llm/MockProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/OpenAIProvider.d.ts +12 -0
- package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/types.d.ts +46 -0
- package/dist/types/adapters/types.d.ts.map +1 -1
- package/dist/types/conventions.d.ts +4 -0
- package/dist/types/conventions.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +26 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +15 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +13 -1
- package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/outputEnforcement.d.ts +174 -0
- package/dist/types/core/agent/outputEnforcement.d.ts.map +1 -0
- package/dist/types/core/agent/stages/callLLM.d.ts +15 -0
- package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
- package/dist/types/core/agent/stages/outputRetry.d.ts +35 -0
- package/dist/types/core/agent/stages/outputRetry.d.ts.map +1 -0
- package/dist/types/core/agent/stages/route.d.ts +18 -2
- package/dist/types/core/agent/stages/route.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +18 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/outputSchema.d.ts +51 -0
- package/dist/types/core/outputSchema.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +47 -1
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/hosting/errors.d.ts +44 -2
- package/dist/types/hosting/errors.d.ts.map +1 -1
- package/dist/types/hosting/headers.d.ts +17 -0
- package/dist/types/hosting/headers.d.ts.map +1 -0
- package/dist/types/hosting/httpHost.d.ts +70 -4
- package/dist/types/hosting/httpHost.d.ts.map +1 -1
- package/dist/types/hosting/index.d.ts +23 -8
- package/dist/types/hosting/index.d.ts.map +1 -1
- package/dist/types/hosting/nodeHost.d.ts +23 -0
- package/dist/types/hosting/nodeHost.d.ts.map +1 -1
- package/dist/types/hosting/types.d.ts +212 -6
- package/dist/types/hosting/types.d.ts.map +1 -1
- package/dist/types/hosting/webSocketConversation.d.ts +102 -0
- package/dist/types/hosting/webSocketConversation.d.ts.map +1 -0
- package/dist/types/hosting/webSocketFrames.d.ts +165 -0
- package/dist/types/hosting/webSocketFrames.d.ts.map +1 -0
- package/dist/types/hosting-providers.d.ts +7 -2
- package/dist/types/hosting-providers.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/resilience/withCircuitBreaker.d.ts.map +1 -1
- package/dist/types/resilience/withFallback.d.ts.map +1 -1
- package/dist/types/resilience/withRetry.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -25,6 +25,7 @@ const typedEmit_js_1 = require("../../../recorders/core/typedEmit.js");
|
|
|
25
25
|
const resilienceHooks_js_1 = require("../../../recorders/core/resilienceHooks.js");
|
|
26
26
|
const cost_js_1 = require("../../cost.js");
|
|
27
27
|
const outputSchema_js_1 = require("../../outputSchema.js");
|
|
28
|
+
const outputEnforcement_js_1 = require("../outputEnforcement.js");
|
|
28
29
|
const reliabilityExecution_js_1 = require("./reliabilityExecution.js");
|
|
29
30
|
/**
|
|
30
31
|
* Drop the fields that exist for the library and never for the model.
|
|
@@ -94,7 +95,14 @@ function buildCallLLMStage(deps) {
|
|
|
94
95
|
// schemas at startup before the tools slot has run. Computed BEFORE the
|
|
95
96
|
// llm_start emit so the event reports what the model ACTUALLY saw this call
|
|
96
97
|
// (count + the name/description catalog), not the static startup set.
|
|
97
|
-
const
|
|
98
|
+
const registeredToolSchemas = scope.dynamicToolSchemas ?? deps.toolSchemas;
|
|
99
|
+
// Under `'tool-forced'` the schema rides along as one more tool ON THE
|
|
100
|
+
// WIRE. It is reported in `llm_start` too, and deliberately: that event's
|
|
101
|
+
// whole claim is "what the model actually saw this call", and a tool the
|
|
102
|
+
// model was forced to use is the last thing to leave out of it.
|
|
103
|
+
const activeToolSchemas = deps.schemaTool
|
|
104
|
+
? [...registeredToolSchemas, deps.schemaTool]
|
|
105
|
+
: registeredToolSchemas;
|
|
98
106
|
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.llm_start', {
|
|
99
107
|
iteration,
|
|
100
108
|
provider: deps.provider.name,
|
|
@@ -121,6 +129,9 @@ function buildCallLLMStage(deps) {
|
|
|
121
129
|
...(deps.thinkingBudget !== undefined && {
|
|
122
130
|
thinking: { budget: deps.thinkingBudget },
|
|
123
131
|
}),
|
|
132
|
+
...(deps.schemaTool !== undefined && {
|
|
133
|
+
toolChoice: { type: 'tool', name: deps.schemaTool.name },
|
|
134
|
+
}),
|
|
124
135
|
};
|
|
125
136
|
// v2.6+ — call cache strategy to attach provider-specific cache
|
|
126
137
|
// hints. CacheGate has already routed (apply-markers / no-markers)
|
|
@@ -191,6 +202,25 @@ function buildCallLLMStage(deps) {
|
|
|
191
202
|
// after a stream is a pre-existing quirk; see MENTAL_MODEL §14.)
|
|
192
203
|
resp = await deps.provider.complete(req, providerHooks);
|
|
193
204
|
}
|
|
205
|
+
// `'tool-forced'`: the answer arrived as the synthetic tool's ARGUMENTS,
|
|
206
|
+
// so it is moved into `content` and the call is taken off the list here,
|
|
207
|
+
// at the single seam every later reader goes through. Everything
|
|
208
|
+
// downstream — the reliability validator, the scope writes, the Route
|
|
209
|
+
// decider, the retry loop — then sees the response it would have seen
|
|
210
|
+
// under `'instruct'`: a final answer that is a JSON string, and no tool
|
|
211
|
+
// calls. One normalization, no second code path, and nothing further
|
|
212
|
+
// down has to know which strategy is in force.
|
|
213
|
+
const forcedName = deps.schemaTool?.name;
|
|
214
|
+
if (forcedName !== undefined) {
|
|
215
|
+
const answer = (0, outputEnforcement_js_1.readSchemaToolAnswer)(resp);
|
|
216
|
+
if (answer !== undefined) {
|
|
217
|
+
resp = {
|
|
218
|
+
...resp,
|
|
219
|
+
content: answer,
|
|
220
|
+
toolCalls: resp.toolCalls.filter((tc) => tc.name !== forcedName),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
194
224
|
return resp;
|
|
195
225
|
};
|
|
196
226
|
// v2.13 — build the output-schema validator hook when both
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callLLM.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/callLLM.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAYH,uEAAiE;AACjE,mFAA6E;AAE7E,2CAA6C;AAE7C,2DAAmF;AACnF,uEAImC;AAGnC;;;;;;;GAOG;AACH,SAAS,oBAAoB,CAAC,QAA+B;IAC3D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxB,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC;QACzC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3C,KAAK,OAAO,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;
|
|
1
|
+
{"version":3,"file":"callLLM.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/callLLM.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* outputRetry — the branch that asks again when the answer failed the schema.
|
|
4
|
+
*
|
|
5
|
+
* Mounted as a THIRD branch of the Route decider, and only on an agent that
|
|
6
|
+
* opted into `.outputSchema(parser, { retries })`. It carries `{ loopTo }`
|
|
7
|
+
* to the same target the `tool-calls` branch loops to, which is the whole
|
|
8
|
+
* mechanism: a retry is not a special mode, it is one more ordinary turn of
|
|
9
|
+
* the ReAct loop. The injection engine re-evaluates, the slots recompose,
|
|
10
|
+
* the cache decides, the model is called — so the attempt gets its own
|
|
11
|
+
* `iteration_start` / `llm_start` / `llm_end` bracket and its own `cost.tick`
|
|
12
|
+
* against `costBudget`.
|
|
13
|
+
*
|
|
14
|
+
* That is the difference from the in-stage schema retry the reliability gate
|
|
15
|
+
* has done since v2.13. There, N attempts happen inside ONE `call-llm` stage:
|
|
16
|
+
* one bracket for all of them, and one cost tick carrying only the last
|
|
17
|
+
* attempt's usage — attempts that were genuinely billed and are invisible in
|
|
18
|
+
* the recording. Here every attempt is a turn, and the recording says so.
|
|
19
|
+
*
|
|
20
|
+
* The two layers compose rather than collide. With `.reliability()` also
|
|
21
|
+
* configured, its in-stage rules run FIRST and decide what to do with a
|
|
22
|
+
* response before it is committed; `retries` governs answers that WERE
|
|
23
|
+
* committed and turned out invalid.
|
|
24
|
+
*
|
|
25
|
+
* Pure function apart from its enforcement config — no closure over Agent
|
|
26
|
+
* class state.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.buildOutputRetryStage = void 0;
|
|
30
|
+
const typedEmit_js_1 = require("../../../recorders/core/typedEmit.js");
|
|
31
|
+
const outputEnforcement_js_1 = require("../outputEnforcement.js");
|
|
32
|
+
/**
|
|
33
|
+
* Build the retry stage. `enforcement.retries` is the cap the decider already
|
|
34
|
+
* checked before routing here — this stage does the work of asking again.
|
|
35
|
+
*/
|
|
36
|
+
function buildOutputRetryStage(enforcement) {
|
|
37
|
+
return (scope) => {
|
|
38
|
+
const iteration = scope.iteration;
|
|
39
|
+
const failure = scope.outputSchemaFailure;
|
|
40
|
+
if (failure === undefined) {
|
|
41
|
+
// Unreachable through the decider, which writes the carrier immediately
|
|
42
|
+
// before routing here. Returning quietly rather than throwing keeps a
|
|
43
|
+
// hand-built chart that mounts this branch without the decider from
|
|
44
|
+
// taking down a run over a missing diagnostic.
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const failedAnswer = scope.llmLatestContent;
|
|
48
|
+
const [answerTurn, correctionTurn] = (0, outputEnforcement_js_1.buildCorrectiveTurn)(failedAnswer, failure, {
|
|
49
|
+
attempt: failure.attempt,
|
|
50
|
+
// The total the run may spend: the first attempt plus its retries.
|
|
51
|
+
totalAttempts: enforcement.retries + 1,
|
|
52
|
+
});
|
|
53
|
+
const hash = (0, outputEnforcement_js_1.correctiveMessageHash)(correctionTurn.content);
|
|
54
|
+
// The conversation, as it really went: the answer that failed, then the
|
|
55
|
+
// correction. A plain local array — a TypedScope array read is a live
|
|
56
|
+
// proxy view, and both the commit and the event payload below must be
|
|
57
|
+
// detached plain data.
|
|
58
|
+
const newHistory = [
|
|
59
|
+
...scope.history,
|
|
60
|
+
answerTurn,
|
|
61
|
+
correctionTurn,
|
|
62
|
+
];
|
|
63
|
+
scope.history = newHistory;
|
|
64
|
+
(0, outputEnforcement_js_1.recordOutputAttempt)(scope, {
|
|
65
|
+
attempt: failure.attempt,
|
|
66
|
+
iteration,
|
|
67
|
+
outcome: 'retried',
|
|
68
|
+
stage: failure.stage,
|
|
69
|
+
error: failure.error,
|
|
70
|
+
...(failure.path !== undefined && { path: failure.path }),
|
|
71
|
+
correctiveMessageHash: hash,
|
|
72
|
+
});
|
|
73
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.output_schema_retry', {
|
|
74
|
+
attempt: failure.attempt,
|
|
75
|
+
// What is left AFTER this correction — `0` means this is the last ask.
|
|
76
|
+
retriesRemaining: enforcement.retries - failure.attempt,
|
|
77
|
+
iteration,
|
|
78
|
+
stage: failure.stage,
|
|
79
|
+
error: failure.error,
|
|
80
|
+
...(failure.path !== undefined && { path: failure.path }),
|
|
81
|
+
correctiveMessageHash: hash,
|
|
82
|
+
});
|
|
83
|
+
// Close this iteration's bracket before the loop turns. Every recorder
|
|
84
|
+
// that synthesizes steps counts on `iteration_start` and `iteration_end`
|
|
85
|
+
// pairing per `iterIndex`, and the crash-checkpoint tracker takes its
|
|
86
|
+
// history snapshot from this payload — so a retry that skipped it would
|
|
87
|
+
// leave a run with one more start than end and a checkpoint one turn
|
|
88
|
+
// behind the conversation.
|
|
89
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.iteration_end', {
|
|
90
|
+
turnIndex: 0,
|
|
91
|
+
iterIndex: iteration,
|
|
92
|
+
toolCallCount: 0,
|
|
93
|
+
history: newHistory,
|
|
94
|
+
});
|
|
95
|
+
// A retry consumes an iteration, exactly as a tool call does. It is one
|
|
96
|
+
// more real turn against the agent's declared budget, and the iteration
|
|
97
|
+
// counter is the vocabulary every bracket in the run is keyed on.
|
|
98
|
+
scope.iteration = iteration + 1;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
exports.buildOutputRetryStage = buildOutputRetryStage;
|
|
102
|
+
//# sourceMappingURL=outputRetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outputRetry.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/outputRetry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;;;AAIH,uEAAiE;AACjE,kEAKiC;AAGjC;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,WAAsC;IAEtC,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,SAAS,GAAG,KAAK,CAAC,SAAmB,CAAC;QAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,mBAAmB,CAAC;QAC1C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,wEAAwE;YACxE,sEAAsE;YACtE,oEAAoE;YACpE,+CAA+C;YAC/C,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,KAAK,CAAC,gBAA0B,CAAC;QACtD,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,GAAG,IAAA,0CAAmB,EAAC,YAAY,EAAE,OAAO,EAAE;YAC9E,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,mEAAmE;YACnE,aAAa,EAAE,WAAW,CAAC,OAAO,GAAG,CAAC;SACvC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAA,4CAAqB,EAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAE3D,wEAAwE;QACxE,sEAAsE;QACtE,sEAAsE;QACtE,uBAAuB;QACvB,MAAM,UAAU,GAAiB;YAC/B,GAAI,KAAK,CAAC,OAAiC;YAC3C,UAAU;YACV,cAAc;SACf,CAAC;QACF,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC;QAE3B,IAAA,0CAAmB,EAAC,KAAK,EAAE;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,SAAS;YACT,OAAO,EAAE,SAAS;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YACzD,qBAAqB,EAAE,IAAI;SAC5B,CAAC,CAAC;QAEH,IAAA,wBAAS,EAAC,KAAK,EAAE,0CAA0C,EAAE;YAC3D,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,uEAAuE;YACvE,gBAAgB,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO;YACvD,SAAS;YACT,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YACzD,qBAAqB,EAAE,IAAI;SAC5B,CAAC,CAAC;QAEH,uEAAuE;QACvE,yEAAyE;QACzE,sEAAsE;QACtE,wEAAwE;QACxE,qEAAqE;QACrE,2BAA2B;QAC3B,IAAA,wBAAS,EAAC,KAAK,EAAE,oCAAoC,EAAE;YACrD,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,SAAS;YACpB,aAAa,EAAE,CAAC;YAChB,OAAO,EAAE,UAAU;SACpB,CAAC,CAAC;QAEH,wEAAwE;QACxE,wEAAwE;QACxE,kEAAkE;QAClE,KAAK,CAAC,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC;AACJ,CAAC;AAxED,sDAwEC"}
|
|
@@ -18,20 +18,35 @@ exports.buildRouteDeciderStage = exports.routeDeciderStage = void 0;
|
|
|
18
18
|
const typedEmit_js_1 = require("../../../recorders/core/typedEmit.js");
|
|
19
19
|
const runChain_js_1 = require("../middleware/runChain.js");
|
|
20
20
|
const ledger_js_1 = require("../middleware/ledger.js");
|
|
21
|
-
const
|
|
21
|
+
const outputEnforcement_js_1 = require("../outputEnforcement.js");
|
|
22
|
+
/** The base decision, with the sentence that explains it. Split out so the
|
|
23
|
+
* enforcement-enabled path can decide, then judge, then announce ONCE — an
|
|
24
|
+
* agent whose answer is about to be re-asked should not have a route event
|
|
25
|
+
* saying it finished. */
|
|
26
|
+
function decideBranch(scope) {
|
|
22
27
|
const toolCalls = scope.llmLatestToolCalls;
|
|
23
28
|
const iteration = scope.iteration;
|
|
24
29
|
const chosen = toolCalls.length > 0 && iteration < scope.maxIterations ? 'tool-calls' : 'final';
|
|
25
|
-
|
|
26
|
-
turnIndex: 0,
|
|
27
|
-
iterIndex: iteration,
|
|
30
|
+
return {
|
|
28
31
|
chosen,
|
|
29
32
|
rationale: chosen === 'tool-calls'
|
|
30
33
|
? `LLM requested ${toolCalls.length} tool call(s)`
|
|
31
34
|
: iteration >= scope.maxIterations
|
|
32
35
|
? 'maxIterations reached — forcing final'
|
|
33
36
|
: 'LLM produced no tool calls — final answer',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function emitRouteDecided(scope, chosen, rationale) {
|
|
40
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.route_decided', {
|
|
41
|
+
turnIndex: 0,
|
|
42
|
+
iterIndex: scope.iteration,
|
|
43
|
+
chosen,
|
|
44
|
+
rationale,
|
|
34
45
|
});
|
|
46
|
+
}
|
|
47
|
+
const routeDeciderStage = (scope) => {
|
|
48
|
+
const { chosen, rationale } = decideBranch(scope);
|
|
49
|
+
emitRouteDecided(scope, chosen, rationale);
|
|
35
50
|
return chosen;
|
|
36
51
|
};
|
|
37
52
|
exports.routeDeciderStage = routeDeciderStage;
|
|
@@ -61,11 +76,28 @@ exports.routeDeciderStage = routeDeciderStage;
|
|
|
61
76
|
* would be running it over something that is not the output.
|
|
62
77
|
*
|
|
63
78
|
* Empty chain → the exact synchronous decider this file has always exported.
|
|
79
|
+
*
|
|
80
|
+
* ## Why the schema is judged HERE too
|
|
81
|
+
*
|
|
82
|
+
* The same property that made this the output seam makes it the enforcement
|
|
83
|
+
* seam. `outputSchema` used to be judged only at the caller's boundary, after
|
|
84
|
+
* the run — a fine place to reject an answer and a useless place to fix one,
|
|
85
|
+
* because the loop has already stopped. Judged here, one stage before the
|
|
86
|
+
* Final branch, the run still HAS a loop: a failed answer can route to
|
|
87
|
+
* `'output-retry'`, which loops back for one more real turn.
|
|
88
|
+
*
|
|
89
|
+
* The judging runs AFTER the message chain, over the content the chain
|
|
90
|
+
* produced, because that is the string the caller will receive — validating
|
|
91
|
+
* the pre-chain value would judge an answer nobody gets. A DENIED answer is
|
|
92
|
+
* never judged or retried: it was withheld on purpose, and re-asking for it
|
|
93
|
+
* would be the library working around a rule the app wrote.
|
|
64
94
|
*/
|
|
65
|
-
function buildRouteDeciderStage(messageMiddleware) {
|
|
95
|
+
function buildRouteDeciderStage(messageMiddleware, enforcement) {
|
|
66
96
|
const chain = messageMiddleware ?? [];
|
|
67
|
-
if (chain.length === 0)
|
|
97
|
+
if (chain.length === 0 && enforcement === undefined)
|
|
68
98
|
return exports.routeDeciderStage;
|
|
99
|
+
if (enforcement !== undefined)
|
|
100
|
+
return buildEnforcingDecider(chain, enforcement);
|
|
69
101
|
return async (scope) => {
|
|
70
102
|
const chosen = (0, exports.routeDeciderStage)(scope);
|
|
71
103
|
if (chosen !== 'final')
|
|
@@ -94,4 +126,77 @@ function buildRouteDeciderStage(messageMiddleware) {
|
|
|
94
126
|
};
|
|
95
127
|
}
|
|
96
128
|
exports.buildRouteDeciderStage = buildRouteDeciderStage;
|
|
129
|
+
/**
|
|
130
|
+
* The decider an agent with `.outputSchema(parser, { retries })` runs:
|
|
131
|
+
* decide, run the output chain if there is one, judge the answer, THEN
|
|
132
|
+
* announce the branch — so `route_decided` names the branch the run actually
|
|
133
|
+
* took rather than the one it was heading for.
|
|
134
|
+
*/
|
|
135
|
+
function buildEnforcingDecider(chain, enforcement) {
|
|
136
|
+
return async (scope) => {
|
|
137
|
+
const base = decideBranch(scope);
|
|
138
|
+
if (base.chosen !== 'final') {
|
|
139
|
+
emitRouteDecided(scope, base.chosen, base.rationale);
|
|
140
|
+
return base.chosen;
|
|
141
|
+
}
|
|
142
|
+
let denied = false;
|
|
143
|
+
if (chain.length > 0) {
|
|
144
|
+
const verdict = await (0, runChain_js_1.runMessageChain)(chain, {
|
|
145
|
+
phase: 'output',
|
|
146
|
+
content: scope.llmLatestContent,
|
|
147
|
+
history: [...scope.history],
|
|
148
|
+
iteration: scope.iteration,
|
|
149
|
+
...(scope.runIdentity && { identity: scope.runIdentity }),
|
|
150
|
+
});
|
|
151
|
+
(0, ledger_js_1.recordDecisions)(scope, verdict.decisions);
|
|
152
|
+
if (verdict.kind === 'deny') {
|
|
153
|
+
denied = true;
|
|
154
|
+
scope.messageDeniedReason = verdict.reason;
|
|
155
|
+
scope.messageDeniedPhase = 'output';
|
|
156
|
+
scope.messageDeniedBy = verdict.middleware;
|
|
157
|
+
}
|
|
158
|
+
scope.llmLatestContent = verdict.content;
|
|
159
|
+
}
|
|
160
|
+
// A withheld answer is not judged and never re-asked. The app decided
|
|
161
|
+
// nobody gets this string; asking the model for a better-shaped version
|
|
162
|
+
// of it would be the library routing around that decision.
|
|
163
|
+
if (denied) {
|
|
164
|
+
emitRouteDecided(scope, 'final', base.rationale);
|
|
165
|
+
return 'final';
|
|
166
|
+
}
|
|
167
|
+
const attempt = (scope.outputAttempts?.length ?? 0) + 1;
|
|
168
|
+
const failure = (0, outputEnforcement_js_1.judgeAnswer)(scope.llmLatestContent, enforcement.parser);
|
|
169
|
+
if (failure === undefined) {
|
|
170
|
+
(0, outputEnforcement_js_1.recordOutputAttempt)(scope, {
|
|
171
|
+
attempt,
|
|
172
|
+
iteration: scope.iteration,
|
|
173
|
+
outcome: 'passed',
|
|
174
|
+
});
|
|
175
|
+
emitRouteDecided(scope, 'final', base.rationale);
|
|
176
|
+
return 'final';
|
|
177
|
+
}
|
|
178
|
+
if (attempt <= enforcement.retries) {
|
|
179
|
+
// The retry stage writes the correction and files the row, because it
|
|
180
|
+
// is the one that knows what it wrote. This is the hand-off.
|
|
181
|
+
scope.outputSchemaFailure = { attempt, ...failure };
|
|
182
|
+
emitRouteDecided(scope, 'output-retry', `final answer failed the output schema (${failure.stage}) — ` +
|
|
183
|
+
`asking again, attempt ${attempt + 1} of ${enforcement.retries + 1}`);
|
|
184
|
+
return 'output-retry';
|
|
185
|
+
}
|
|
186
|
+
// Out of retries. The answer stands as the run's answer; `runTyped()`
|
|
187
|
+
// throws on it at the boundary exactly as it did before any of this
|
|
188
|
+
// existed, and `.outputFallback()` still gets its turn there.
|
|
189
|
+
(0, outputEnforcement_js_1.recordOutputAttempt)(scope, {
|
|
190
|
+
attempt,
|
|
191
|
+
iteration: scope.iteration,
|
|
192
|
+
outcome: 'exhausted',
|
|
193
|
+
stage: failure.stage,
|
|
194
|
+
error: failure.error,
|
|
195
|
+
...(failure.path !== undefined && { path: failure.path }),
|
|
196
|
+
});
|
|
197
|
+
emitRouteDecided(scope, 'final', `final answer failed the output schema (${failure.stage}) and ` +
|
|
198
|
+
`${enforcement.retries} retry/retries were spent`);
|
|
199
|
+
return 'final';
|
|
200
|
+
};
|
|
201
|
+
}
|
|
97
202
|
//# sourceMappingURL=route.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/route.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAGH,uEAAiE;AAIjE,2DAA4D;AAC5D,uDAA0D;
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/route.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outputSchema.js","sourceRoot":"","sources":["../../src/core/outputSchema.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;;;
|
|
1
|
+
{"version":3,"file":"outputSchema.js","sourceRoot":"","sources":["../../src/core/outputSchema.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;;;AAiGH;;;;;;;GAOG;AACH,MAAa,iBAAkB,SAAQ,KAAK;IACjC,SAAS,CAAS;IAClB,KAAK,CAAmC;IAC/B,KAAK,CAAW;IAElC,YACE,OAAe,EACf,IAAqF;QAErF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACxD,CAAC;CACF;AAfD,8CAeC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CAAC,MAAmC;IACzE,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,sBAAsB,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,OAAO,CACL,2DAA2D;QAC3D,6DAA6D;QAC7D,IAAI,CACL,CAAC;AACJ,CAAC;AAPD,0DAOC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,iBAAiB,CAAI,GAAW,EAAE,MAA6B;IAC7E,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CACzB,gFAAgF,EAChF,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAC/C,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,iEAAiE,EAAE;YAC7F,SAAS,EAAE,GAAG;YACd,KAAK,EAAE,iBAAiB;YACxB,KAAK;SACN,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAnBD,8CAmBC"}
|
|
@@ -23,12 +23,26 @@
|
|
|
23
23
|
*
|
|
24
24
|
* POST /invocations JSON `{ "prompt": "..." }` → JSON `{ "response", "status" }`
|
|
25
25
|
* GET /ping → `{ "status": "Healthy", "time_of_last_update": <unix seconds> }`
|
|
26
|
+
* GET /ws a bidirectional WebSocket, on the SAME port
|
|
26
27
|
*
|
|
27
28
|
* and the caller's conversation arrives in the
|
|
28
29
|
* `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header rather than in the body,
|
|
29
30
|
* which is the one thing paths-and-bodies configuration alone could not
|
|
30
31
|
* express before this release.
|
|
31
32
|
*
|
|
33
|
+
* ── The second door ──────────────────────────────────────────────────────────
|
|
34
|
+
* `/ws` is this runtime's answer for a caller that cannot host an inbound
|
|
35
|
+
* endpoint — a browser, most obviously — and so dials out and parks a channel
|
|
36
|
+
* instead. It is the same container and the same port, which is exactly why the
|
|
37
|
+
* two doors here share one socket.
|
|
38
|
+
*
|
|
39
|
+
* Its wire facts are ADAPTER facts and live nowhere but this file: 32KB frames,
|
|
40
|
+
* a 15-minute idle ceiling, the bearer credential carried as a
|
|
41
|
+
* `Sec-WebSocket-Protocol` offer because a browser's WebSocket API cannot set a
|
|
42
|
+
* header, and session affinity that has to be readable from the query string
|
|
43
|
+
* for the same reason. The port knows none of it — it is handed a session id
|
|
44
|
+
* and a header bag, the same two things every other transport hands it.
|
|
45
|
+
*
|
|
32
46
|
* ── Verification status, stated plainly ──────────────────────────────────────
|
|
33
47
|
* `agentCoreRuntimeHost` is **plain HTTP and is really verified**: it runs the
|
|
34
48
|
* same host conformance suite as `nodeHost`, over a real socket, in
|
|
@@ -54,7 +68,7 @@
|
|
|
54
68
|
* importing this module costs zero peer-dep load.
|
|
55
69
|
*/
|
|
56
70
|
/// <reference types="node" />
|
|
57
|
-
import type { HttpHost, HttpWire } from '../../hosting/httpHost.js';
|
|
71
|
+
import type { ConversationHandshake, HandshakeFacts, HttpHost, HttpWire } from '../../hosting/httpHost.js';
|
|
58
72
|
import type { CheckpointEnvelope, SessionLifecycle } from '../../hosting/types.js';
|
|
59
73
|
/** Options for {@link agentCoreRuntimeHost}. */
|
|
60
74
|
export interface AgentCoreRuntimeHostOptions {
|
|
@@ -104,6 +118,14 @@ export interface AgentCoreRuntimeHostOptions {
|
|
|
104
118
|
* });
|
|
105
119
|
*/
|
|
106
120
|
readonly server?: import('node:http').Server;
|
|
121
|
+
/**
|
|
122
|
+
* Path that takes a conversation upgrade. Default `'/ws'` — the runtime's
|
|
123
|
+
* own second door, beside `/invocations` on the same port.
|
|
124
|
+
*
|
|
125
|
+
* You do not need `server` for this: both doors share one socket by
|
|
126
|
+
* construction, which is what the single-port container required.
|
|
127
|
+
*/
|
|
128
|
+
readonly conversationPath?: string;
|
|
107
129
|
}
|
|
108
130
|
/**
|
|
109
131
|
* The AgentCore Runtime contract as an {@link HttpWire}.
|
|
@@ -113,6 +135,33 @@ export interface AgentCoreRuntimeHostOptions {
|
|
|
113
135
|
* else can reuse them by name.
|
|
114
136
|
*/
|
|
115
137
|
export declare function agentCoreRuntimeWire(busy?: () => boolean): HttpWire;
|
|
138
|
+
/**
|
|
139
|
+
* The `/ws` handshake, in this runtime's spelling: **header-or-query session
|
|
140
|
+
* affinity, and the bearer subprotocol mapped into headers.**
|
|
141
|
+
*
|
|
142
|
+
* ── Why the query string is read at all ──────────────────────────────────────
|
|
143
|
+
* The same header carries the session on `/invocations`, and it is preferred
|
|
144
|
+
* here too. But the caller this door exists for is a browser, and the browser
|
|
145
|
+
* WebSocket API cannot set a header — so a session id has nowhere to travel
|
|
146
|
+
* except the URL. Both the runtime's header name and the plain `sessionId` are
|
|
147
|
+
* accepted as query parameters, case-insensitively; **the header wins** when
|
|
148
|
+
* both arrive, so a caller that sets both is never surprised by which one the
|
|
149
|
+
* server preferred. That is the same precedence rule the request dialect uses.
|
|
150
|
+
*
|
|
151
|
+
* ── Why the credential becomes a header ──────────────────────────────────────
|
|
152
|
+
* A bearer token offered as a subprotocol is this runtime's spelling of
|
|
153
|
+
* `Authorization`, and a port field spelled the way one vendor spells it is how
|
|
154
|
+
* a port stops being one. So it lands in `headers.authorization` as
|
|
155
|
+
* `Bearer <token>` — the vocabulary every other transport already uses — and
|
|
156
|
+
* the raw `sec-websocket-protocol` header is left in place, so an application
|
|
157
|
+
* that reads the offer itself still can. **Nothing here authenticates
|
|
158
|
+
* anything**: the port never proves who is calling, and a token that arrived is
|
|
159
|
+
* a claim, exactly like the session id beside it.
|
|
160
|
+
*
|
|
161
|
+
* Exported by name so the mapping is inspectable and testable without binding a
|
|
162
|
+
* socket, the same way the body shapes are.
|
|
163
|
+
*/
|
|
164
|
+
export declare function readAgentCoreConversation(facts: HandshakeFacts): ConversationHandshake;
|
|
116
165
|
/**
|
|
117
166
|
* An `AgentHost` that speaks AgentCore Runtime's container contract.
|
|
118
167
|
*
|
|
@@ -23,12 +23,26 @@
|
|
|
23
23
|
*
|
|
24
24
|
* POST /invocations JSON `{ "prompt": "..." }` → JSON `{ "response", "status" }`
|
|
25
25
|
* GET /ping → `{ "status": "Healthy", "time_of_last_update": <unix seconds> }`
|
|
26
|
+
* GET /ws a bidirectional WebSocket, on the SAME port
|
|
26
27
|
*
|
|
27
28
|
* and the caller's conversation arrives in the
|
|
28
29
|
* `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header rather than in the body,
|
|
29
30
|
* which is the one thing paths-and-bodies configuration alone could not
|
|
30
31
|
* express before this release.
|
|
31
32
|
*
|
|
33
|
+
* ── The second door ──────────────────────────────────────────────────────────
|
|
34
|
+
* `/ws` is this runtime's answer for a caller that cannot host an inbound
|
|
35
|
+
* endpoint — a browser, most obviously — and so dials out and parks a channel
|
|
36
|
+
* instead. It is the same container and the same port, which is exactly why the
|
|
37
|
+
* two doors here share one socket.
|
|
38
|
+
*
|
|
39
|
+
* Its wire facts are ADAPTER facts and live nowhere but this file: 32KB frames,
|
|
40
|
+
* a 15-minute idle ceiling, the bearer credential carried as a
|
|
41
|
+
* `Sec-WebSocket-Protocol` offer because a browser's WebSocket API cannot set a
|
|
42
|
+
* header, and session affinity that has to be readable from the query string
|
|
43
|
+
* for the same reason. The port knows none of it — it is handed a session id
|
|
44
|
+
* and a header bag, the same two things every other transport hands it.
|
|
45
|
+
*
|
|
32
46
|
* ── Verification status, stated plainly ──────────────────────────────────────
|
|
33
47
|
* `agentCoreRuntimeHost` is **plain HTTP and is really verified**: it runs the
|
|
34
48
|
* same host conformance suite as `nodeHost`, over a real socket, in
|
|
@@ -61,6 +75,7 @@ const HOST_NAME = 'agentCoreRuntimeHost';
|
|
|
61
75
|
/** The runtime's container contract, as constants rather than as scattered literals. */
|
|
62
76
|
const INVOKE_PATH = '/invocations';
|
|
63
77
|
const HEALTH_PATH = '/ping';
|
|
78
|
+
const CONVERSATION_PATH = '/ws';
|
|
64
79
|
const RUNTIME_PORT = 8080;
|
|
65
80
|
/**
|
|
66
81
|
* The header the runtime puts the caller's conversation in. Matched
|
|
@@ -68,6 +83,34 @@ const RUNTIME_PORT = 8080;
|
|
|
68
83
|
* front of the container is free to re-case them.
|
|
69
84
|
*/
|
|
70
85
|
const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
|
|
86
|
+
/**
|
|
87
|
+
* What the `/ws` door caps, as the runtime imposes it — **32KB per frame and a
|
|
88
|
+
* 15-minute idle timeout.**
|
|
89
|
+
*
|
|
90
|
+
* Declared rather than worked around. A 32KB cap hidden inside auto-chunking
|
|
91
|
+
* would have this adapter deciding, for every consumer at once, how a message
|
|
92
|
+
* is split and how the far side knows the last piece landed; a 15-minute idle
|
|
93
|
+
* answered with an invented heartbeat would put bytes on the wire that the
|
|
94
|
+
* consumer's parser never agreed to. Both belong to the protocol above this
|
|
95
|
+
* door, and both are actionable only if the number is visible.
|
|
96
|
+
*
|
|
97
|
+
* `maxFrameBytes` is enforced here, in both directions, because a frame past it
|
|
98
|
+
* would be cut by the front door anyway and a refusal that names the ceiling
|
|
99
|
+
* beats a truncation that does not. `idleMs` is REPORTED: the timeout belongs
|
|
100
|
+
* to what sits in front of this container, and the honest thing is to say so
|
|
101
|
+
* rather than to close a channel the runtime might have kept.
|
|
102
|
+
*/
|
|
103
|
+
const CONVERSATION_LIMITS = { maxFrameBytes: 32_768, idleMs: 900_000 };
|
|
104
|
+
/**
|
|
105
|
+
* The subprotocol a browser offers to carry its bearer credential, because the
|
|
106
|
+
* WebSocket API gives it no way to send an `Authorization` header.
|
|
107
|
+
*
|
|
108
|
+
* Two spellings are recognised and both are ordinary browser-expressible ones:
|
|
109
|
+
* `['bearer', '<token>']` (two offers) and `['bearer.<token>']` (one). What is
|
|
110
|
+
* echoed back in the 101 is the word `bearer` and never the token — a
|
|
111
|
+
* credential belongs in a request, not in a response header a proxy may log.
|
|
112
|
+
*/
|
|
113
|
+
const BEARER_SUBPROTOCOL = 'bearer';
|
|
71
114
|
/**
|
|
72
115
|
* The AgentCore Runtime contract as an {@link HttpWire}.
|
|
73
116
|
*
|
|
@@ -118,8 +161,73 @@ export function agentCoreRuntimeWire(busy) {
|
|
|
118
161
|
// 'success' nor 'error' because it is neither: the run stopped to ask a
|
|
119
162
|
// person, it is stored, and a later call carrying `decision` finishes it.
|
|
120
163
|
awaiting: (pending) => ({ awaiting: pending, status: 'awaiting' }),
|
|
164
|
+
readConversation: readAgentCoreConversation,
|
|
121
165
|
};
|
|
122
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* The `/ws` handshake, in this runtime's spelling: **header-or-query session
|
|
169
|
+
* affinity, and the bearer subprotocol mapped into headers.**
|
|
170
|
+
*
|
|
171
|
+
* ── Why the query string is read at all ──────────────────────────────────────
|
|
172
|
+
* The same header carries the session on `/invocations`, and it is preferred
|
|
173
|
+
* here too. But the caller this door exists for is a browser, and the browser
|
|
174
|
+
* WebSocket API cannot set a header — so a session id has nowhere to travel
|
|
175
|
+
* except the URL. Both the runtime's header name and the plain `sessionId` are
|
|
176
|
+
* accepted as query parameters, case-insensitively; **the header wins** when
|
|
177
|
+
* both arrive, so a caller that sets both is never surprised by which one the
|
|
178
|
+
* server preferred. That is the same precedence rule the request dialect uses.
|
|
179
|
+
*
|
|
180
|
+
* ── Why the credential becomes a header ──────────────────────────────────────
|
|
181
|
+
* A bearer token offered as a subprotocol is this runtime's spelling of
|
|
182
|
+
* `Authorization`, and a port field spelled the way one vendor spells it is how
|
|
183
|
+
* a port stops being one. So it lands in `headers.authorization` as
|
|
184
|
+
* `Bearer <token>` — the vocabulary every other transport already uses — and
|
|
185
|
+
* the raw `sec-websocket-protocol` header is left in place, so an application
|
|
186
|
+
* that reads the offer itself still can. **Nothing here authenticates
|
|
187
|
+
* anything**: the port never proves who is calling, and a token that arrived is
|
|
188
|
+
* a claim, exactly like the session id beside it.
|
|
189
|
+
*
|
|
190
|
+
* Exported by name so the mapping is inspectable and testable without binding a
|
|
191
|
+
* socket, the same way the body shapes are.
|
|
192
|
+
*/
|
|
193
|
+
export function readAgentCoreConversation(facts) {
|
|
194
|
+
const sessionId = headerValue(facts, SESSION_HEADER) ?? queryValue(facts, SESSION_HEADER, 'sessionId');
|
|
195
|
+
const token = bearerFromSubprotocols(facts.headers['sec-websocket-protocol']);
|
|
196
|
+
return {
|
|
197
|
+
...(sessionId !== undefined && { sessionId }),
|
|
198
|
+
...(token !== undefined && {
|
|
199
|
+
headers: { authorization: `Bearer ${token}` },
|
|
200
|
+
// Echoed so a client that offered a subprotocol gets one back — the word
|
|
201
|
+
// only. Putting the token in a response header would hand the credential
|
|
202
|
+
// to every proxy on the way home.
|
|
203
|
+
protocol: BEARER_SUBPROTOCOL,
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/** A query parameter by any of several names, matched case-insensitively. */
|
|
208
|
+
function queryValue(facts, ...names) {
|
|
209
|
+
const wanted = names.map((name) => name.toLowerCase());
|
|
210
|
+
for (const [key, value] of facts.query.entries()) {
|
|
211
|
+
if (wanted.includes(key.toLowerCase()) && value.length > 0)
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
/** The token out of a `Sec-WebSocket-Protocol` offer, in either browser spelling. */
|
|
217
|
+
function bearerFromSubprotocols(offered) {
|
|
218
|
+
if (!offered)
|
|
219
|
+
return undefined;
|
|
220
|
+
const parts = offered
|
|
221
|
+
.split(',')
|
|
222
|
+
.map((part) => part.trim())
|
|
223
|
+
.filter((part) => part.length > 0);
|
|
224
|
+
const marker = parts.findIndex((part) => part.toLowerCase() === BEARER_SUBPROTOCOL);
|
|
225
|
+
if (marker >= 0 && parts[marker + 1] !== undefined)
|
|
226
|
+
return parts[marker + 1];
|
|
227
|
+
const prefix = `${BEARER_SUBPROTOCOL}.`;
|
|
228
|
+
const dotted = parts.find((part) => part.toLowerCase().startsWith(prefix));
|
|
229
|
+
return dotted?.slice(prefix.length) || undefined;
|
|
230
|
+
}
|
|
123
231
|
/**
|
|
124
232
|
* An `AgentHost` that speaks AgentCore Runtime's container contract.
|
|
125
233
|
*
|
|
@@ -140,6 +248,8 @@ export function agentCoreRuntimeHost(options = {}) {
|
|
|
140
248
|
wire: agentCoreRuntimeWire(options.busy),
|
|
141
249
|
invokePath: INVOKE_PATH,
|
|
142
250
|
healthPath: HEALTH_PATH,
|
|
251
|
+
conversationPath: options.conversationPath ?? CONVERSATION_PATH,
|
|
252
|
+
conversationLimits: CONVERSATION_LIMITS,
|
|
143
253
|
// With a caller-owned server this adapter binds nothing, so it must not
|
|
144
254
|
// invent the contract's port either — the port is whatever the caller
|
|
145
255
|
// listened on, and passing one anyway is refused by `httpHost` rather than
|