agentfootprint 7.14.0 → 7.16.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/llm/BrowserOpenAIProvider.js +7 -3
- package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/OpenAIProvider.js +11 -3
- package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
- 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/conventions.js +7 -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 +86 -1
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/buildAgentChart.js +12 -1
- package/dist/core/agent/buildAgentChart.js.map +1 -1
- package/dist/core/agent/buildDynamicAgentChart.js +10 -1
- package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/core/agent/compaction/errors.js +40 -0
- package/dist/core/agent/compaction/errors.js.map +1 -0
- package/dist/core/agent/compaction/index.js +24 -0
- package/dist/core/agent/compaction/index.js.map +1 -0
- package/dist/core/agent/compaction/strategy.js +152 -0
- package/dist/core/agent/compaction/strategy.js.map +1 -0
- package/dist/core/agent/compaction/summarize.js +103 -0
- package/dist/core/agent/compaction/summarize.js.map +1 -0
- package/dist/core/agent/compaction/turns.js +153 -0
- package/dist/core/agent/compaction/turns.js.map +1 -0
- package/dist/core/agent/compaction/types.js +21 -0
- package/dist/core/agent/compaction/types.js.map +1 -0
- package/dist/core/agent/stages/compact.js +130 -0
- package/dist/core/agent/stages/compact.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/llm/BrowserOpenAIProvider.js +7 -3
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/OpenAIProvider.js +11 -3
- package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
- 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/conventions.d.ts +7 -0
- package/dist/esm/conventions.js +7 -0
- package/dist/esm/conventions.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +8 -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 +43 -0
- package/dist/esm/core/agent/AgentBuilder.js +86 -1
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/buildAgentChart.d.ts +13 -0
- package/dist/esm/core/agent/buildAgentChart.js +12 -1
- package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js +10 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/esm/core/agent/compaction/errors.d.ts +26 -0
- package/dist/esm/core/agent/compaction/errors.js +36 -0
- package/dist/esm/core/agent/compaction/errors.js.map +1 -0
- package/dist/esm/core/agent/compaction/index.d.ts +18 -0
- package/dist/esm/core/agent/compaction/index.js +18 -0
- package/dist/esm/core/agent/compaction/index.js.map +1 -0
- package/dist/esm/core/agent/compaction/strategy.d.ts +103 -0
- package/dist/esm/core/agent/compaction/strategy.js +148 -0
- package/dist/esm/core/agent/compaction/strategy.js.map +1 -0
- package/dist/esm/core/agent/compaction/summarize.d.ts +61 -0
- package/dist/esm/core/agent/compaction/summarize.js +96 -0
- package/dist/esm/core/agent/compaction/summarize.js.map +1 -0
- package/dist/esm/core/agent/compaction/turns.d.ts +85 -0
- package/dist/esm/core/agent/compaction/turns.js +145 -0
- package/dist/esm/core/agent/compaction/turns.js.map +1 -0
- package/dist/esm/core/agent/compaction/types.d.ts +148 -0
- package/dist/esm/core/agent/compaction/types.js +20 -0
- package/dist/esm/core/agent/compaction/types.js.map +1 -0
- package/dist/esm/core/agent/stages/compact.d.ts +59 -0
- package/dist/esm/core/agent/stages/compact.js +126 -0
- package/dist/esm/core/agent/stages/compact.js.map +1 -0
- package/dist/esm/core/agent/types.d.ts +11 -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/index.d.ts +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- 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/recorders/core/CompactionMeter.d.ts +78 -0
- package/dist/esm/recorders/core/CompactionMeter.js +101 -0
- package/dist/esm/recorders/core/CompactionMeter.js.map +1 -0
- 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/index.js +13 -5
- package/dist/index.js.map +1 -1
- 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/recorders/core/CompactionMeter.js +105 -0
- package/dist/recorders/core/CompactionMeter.js.map +1 -0
- 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/llm/BrowserOpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
- 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/conventions.d.ts +7 -0
- package/dist/types/conventions.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +8 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +43 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +13 -0
- 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/compaction/errors.d.ts +27 -0
- package/dist/types/core/agent/compaction/errors.d.ts.map +1 -0
- package/dist/types/core/agent/compaction/index.d.ts +19 -0
- package/dist/types/core/agent/compaction/index.d.ts.map +1 -0
- package/dist/types/core/agent/compaction/strategy.d.ts +104 -0
- package/dist/types/core/agent/compaction/strategy.d.ts.map +1 -0
- package/dist/types/core/agent/compaction/summarize.d.ts +62 -0
- package/dist/types/core/agent/compaction/summarize.d.ts.map +1 -0
- package/dist/types/core/agent/compaction/turns.d.ts +86 -0
- package/dist/types/core/agent/compaction/turns.d.ts.map +1 -0
- package/dist/types/core/agent/compaction/types.d.ts +149 -0
- package/dist/types/core/agent/compaction/types.d.ts.map +1 -0
- package/dist/types/core/agent/stages/compact.d.ts +60 -0
- package/dist/types/core/agent/stages/compact.d.ts.map +1 -0
- package/dist/types/core/agent/types.d.ts +11 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- 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/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- 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/recorders/core/CompactionMeter.d.ts +79 -0
- package/dist/types/recorders/core/CompactionMeter.d.ts.map +1 -0
- 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,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* compaction/turns — where a turn boundary is, and which turns may fold.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: Pure functions over the window (no scope, no I/O, no clock).
|
|
6
|
+
* Role: core/ layer. The whole safety argument of compaction lives here:
|
|
7
|
+
* a fold that splits an assistant's `tool_use` from its
|
|
8
|
+
* `tool_result` produces a request the vendor rejects, and a fold
|
|
9
|
+
* that swallows an unanswered question destroys the referent of the
|
|
10
|
+
* answer that has not arrived yet.
|
|
11
|
+
* Emits: N/A.
|
|
12
|
+
*
|
|
13
|
+
* Testable on its own — see `test/core/agent/compaction-turns.test.ts`.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.windowChars = exports.planFold = exports.refusalFor = exports.answeredCallIds = exports.segmentTurns = void 0;
|
|
17
|
+
/**
|
|
18
|
+
* Segment a window into turns.
|
|
19
|
+
*
|
|
20
|
+
* A new turn starts at any non-`tool` message; `tool` messages join the turn
|
|
21
|
+
* in progress. A leading `tool` message (only reachable from a hand-built
|
|
22
|
+
* history) starts its own turn rather than being silently dropped.
|
|
23
|
+
*/
|
|
24
|
+
function segmentTurns(history) {
|
|
25
|
+
const turns = [];
|
|
26
|
+
let current = [];
|
|
27
|
+
let start = 0;
|
|
28
|
+
const flush = () => {
|
|
29
|
+
if (current.length === 0)
|
|
30
|
+
return;
|
|
31
|
+
turns.push({ index: turns.length, start, length: current.length, messages: current });
|
|
32
|
+
current = [];
|
|
33
|
+
};
|
|
34
|
+
for (let i = 0; i < history.length; i++) {
|
|
35
|
+
const msg = history[i];
|
|
36
|
+
if (msg.role !== 'tool' || current.length === 0) {
|
|
37
|
+
flush();
|
|
38
|
+
start = i;
|
|
39
|
+
}
|
|
40
|
+
current.push(msg);
|
|
41
|
+
}
|
|
42
|
+
flush();
|
|
43
|
+
return turns;
|
|
44
|
+
}
|
|
45
|
+
exports.segmentTurns = segmentTurns;
|
|
46
|
+
/** Every tool_call id that has a matching `role: 'tool'` message. */
|
|
47
|
+
function answeredCallIds(history) {
|
|
48
|
+
const answered = new Set();
|
|
49
|
+
for (const msg of history) {
|
|
50
|
+
if (msg.role === 'tool' && msg.toolCallId)
|
|
51
|
+
answered.add(msg.toolCallId);
|
|
52
|
+
}
|
|
53
|
+
return answered;
|
|
54
|
+
}
|
|
55
|
+
exports.answeredCallIds = answeredCallIds;
|
|
56
|
+
/**
|
|
57
|
+
* Why this turn may NOT fold, or `undefined` when it may.
|
|
58
|
+
*
|
|
59
|
+
* Order matters only for which reason gets reported first; every check is
|
|
60
|
+
* independent. `paused-tool` / `pending-check-in` are separated from
|
|
61
|
+
* `unresolved-tool-call` on purpose: they are the same shape but a different
|
|
62
|
+
* fact about the world, and "we are waiting on a human" is what the person
|
|
63
|
+
* reading the trace needs to see.
|
|
64
|
+
*/
|
|
65
|
+
function refusalFor(turn, ctx) {
|
|
66
|
+
for (const msg of turn.messages) {
|
|
67
|
+
if (msg.role === 'system')
|
|
68
|
+
return 'system-envelope';
|
|
69
|
+
}
|
|
70
|
+
const paused = ctx.pausedToolCallId;
|
|
71
|
+
if (paused !== undefined && paused.length > 0) {
|
|
72
|
+
for (const msg of turn.messages) {
|
|
73
|
+
const holdsPaused = msg.toolCallId === paused || (msg.toolCalls ?? []).some((tc) => tc.id === paused);
|
|
74
|
+
if (holdsPaused)
|
|
75
|
+
return ctx.pausedCheckIn === true ? 'pending-check-in' : 'paused-tool';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const msg of turn.messages) {
|
|
79
|
+
for (const call of msg.toolCalls ?? []) {
|
|
80
|
+
if (!ctx.answeredCallIds.has(call.id))
|
|
81
|
+
return 'unresolved-tool-call';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
exports.refusalFor = refusalFor;
|
|
87
|
+
/**
|
|
88
|
+
* Choose the fold span: the LONGEST CONTIGUOUS run of foldable candidate
|
|
89
|
+
* turns, starting at the oldest foldable one.
|
|
90
|
+
*
|
|
91
|
+
* Contiguity is not fussiness — it is what keeps the conversation in order.
|
|
92
|
+
* A fold replaces its span with ONE summary message; if the span skipped over
|
|
93
|
+
* an unfoldable turn, that turn would end up after a summary of things that
|
|
94
|
+
* happened before it. So an unfoldable turn at the front is stepped over (the
|
|
95
|
+
* fold "takes the next oldest instead") and an unfoldable turn in the middle
|
|
96
|
+
* ends the span. Everything not folded keeps its position.
|
|
97
|
+
*
|
|
98
|
+
* @param turns the window's turn segmentation
|
|
99
|
+
* @param keepRecent how many trailing turns are off-limits
|
|
100
|
+
* @param ctx foldability inputs
|
|
101
|
+
* @param isSummaryTurn true for a turn that is a summary a prior fold wrote
|
|
102
|
+
*/
|
|
103
|
+
function planFold(turns, keepRecent, ctx, isSummaryTurn) {
|
|
104
|
+
const refusals = [];
|
|
105
|
+
const candidateCount = Math.max(0, turns.length - keepRecent);
|
|
106
|
+
for (let i = candidateCount; i < turns.length; i++) {
|
|
107
|
+
const turn = turns[i];
|
|
108
|
+
refusals.push({ reason: 'inside-keep-window', turnIndex: i, messageIndex: turn.start });
|
|
109
|
+
}
|
|
110
|
+
if (candidateCount === 0)
|
|
111
|
+
return { from: -1, to: -1, refusals };
|
|
112
|
+
const before = [];
|
|
113
|
+
let from = -1;
|
|
114
|
+
let to = -1;
|
|
115
|
+
for (let i = 0; i < candidateCount; i++) {
|
|
116
|
+
const turn = turns[i];
|
|
117
|
+
const reason = refusalFor(turn, ctx);
|
|
118
|
+
if (reason === undefined) {
|
|
119
|
+
if (from === -1)
|
|
120
|
+
from = i;
|
|
121
|
+
to = i;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
before.push({ reason, turnIndex: i, messageIndex: turn.start });
|
|
125
|
+
if (from !== -1)
|
|
126
|
+
break; // an unfoldable turn ENDS the span
|
|
127
|
+
}
|
|
128
|
+
// A span that is nothing but one existing summary is not worth a call:
|
|
129
|
+
// re-summarizing a summary spends tokens to lose detail and names nothing
|
|
130
|
+
// new. It becomes foldable again as soon as a real turn joins it.
|
|
131
|
+
if (from !== -1 && from === to && isSummaryTurn(turns[from])) {
|
|
132
|
+
return {
|
|
133
|
+
from: -1,
|
|
134
|
+
to: -1,
|
|
135
|
+
refusals: [
|
|
136
|
+
...before,
|
|
137
|
+
{ reason: 'only-existing-summary', turnIndex: from, messageIndex: turns[from].start },
|
|
138
|
+
...refusals,
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return { from, to, refusals: [...before, ...refusals] };
|
|
143
|
+
}
|
|
144
|
+
exports.planFold = planFold;
|
|
145
|
+
/** Total characters of message content in a window. Exact; not tokens. */
|
|
146
|
+
function windowChars(history) {
|
|
147
|
+
let total = 0;
|
|
148
|
+
for (const msg of history)
|
|
149
|
+
total += msg.content.length;
|
|
150
|
+
return total;
|
|
151
|
+
}
|
|
152
|
+
exports.windowChars = windowChars;
|
|
153
|
+
//# sourceMappingURL=turns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turns.js","sourceRoot":"","sources":["../../../../src/core/agent/compaction/turns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* compaction/types — the public shape of `.compaction()` and the record it
|
|
4
|
+
* writes into the ledger.
|
|
5
|
+
*
|
|
6
|
+
* Pattern: Value objects (no behavior) + one resolved-config type.
|
|
7
|
+
* Role: core/ layer. The law this feature exists to keep is stated once,
|
|
8
|
+
* here, because every other file in this folder implements a piece
|
|
9
|
+
* of it: **compaction edits the WINDOW, never the LEDGER.**
|
|
10
|
+
* Emits: N/A (types only).
|
|
11
|
+
*
|
|
12
|
+
* The window is `scope.history` — the array `call-llm` hands the provider.
|
|
13
|
+
* The ledger is footprintjs's commit log, which is append-only: the turns a
|
|
14
|
+
* fold removes from the window were committed by `seed#0` / `tool-calls#N`
|
|
15
|
+
* BEFORE the fold and stay in those bundles byte-identical forever. A fold
|
|
16
|
+
* therefore cannot destroy history even in principle; it can only stop
|
|
17
|
+
* re-sending it. The summary is a CLAIM about the past, so it is filed as a
|
|
18
|
+
* claim — its own recorded step, naming every `runtimeStageId` it folded.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/agent/compaction/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* compact — the loop-head stage that keeps the window inside budget.
|
|
4
|
+
*
|
|
5
|
+
* Reads the last call's ADAPTER-REPORTED input tokens from the compaction
|
|
6
|
+
* meter and, when they exceed `thresholdTokens`, hands the window to a window
|
|
7
|
+
* strategy. Runs once per ReAct iteration boundary, as the loop target, so
|
|
8
|
+
* everything downstream in the turn — the injection engine's triggers, all
|
|
9
|
+
* three context slots, and the wire itself — sees ONE window. No component
|
|
10
|
+
* gets a different past than the model does.
|
|
11
|
+
*
|
|
12
|
+
* The law: **it edits the window, never the ledger.** The turns a fold removes
|
|
13
|
+
* were committed by `seed#0` / `tool-calls#N` before this stage ran and stay
|
|
14
|
+
* in those bundles byte-identical; footprintjs's commit log is append-only, so
|
|
15
|
+
* a fold cannot erase history even in principle. What it can do is stop
|
|
16
|
+
* re-sending it — and say so, in its own commit, naming every runtimeStageId
|
|
17
|
+
* it folded. A compacted run is still a provable run.
|
|
18
|
+
*
|
|
19
|
+
* This file is deliberately all WIRING. The decision — what the window should
|
|
20
|
+
* become — lives behind `WindowStrategy` (compaction/strategy.ts, internal),
|
|
21
|
+
* so the duty to record, emit and cost what happened stays in exactly one
|
|
22
|
+
* place instead of being re-implemented per strategy. `.compaction()` is the
|
|
23
|
+
* only strategy that ships.
|
|
24
|
+
*
|
|
25
|
+
* Emits (existing vocabulary only — no new event types):
|
|
26
|
+
* agentfootprint.context.evicted — one per message leaving the window
|
|
27
|
+
* agentfootprint.context.budget_pressure — one per over-budget visit
|
|
28
|
+
* agentfootprint.cost.tick — when a pricingTable is set: the
|
|
29
|
+
* summarizer's call is a real
|
|
30
|
+
* billed call and counts
|
|
31
|
+
*
|
|
32
|
+
* The summarizer call is deliberately NOT bracketed with
|
|
33
|
+
* `stream.llm_start` / `llm_end`: those carry an `iteration` and every
|
|
34
|
+
* consumer pairs them by it, so a second bracket inside one iteration would
|
|
35
|
+
* corrupt the pairing. Its cost rides the cost channel and its tokens are
|
|
36
|
+
* recorded in the commit instead.
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.buildCompactStage = void 0;
|
|
40
|
+
const typedEmit_js_1 = require("../../../recorders/core/typedEmit.js");
|
|
41
|
+
const helpers_js_1 = require("../../slots/helpers.js");
|
|
42
|
+
const cost_js_1 = require("../../cost.js");
|
|
43
|
+
const errors_js_1 = require("../compaction/errors.js");
|
|
44
|
+
const strategy_js_1 = require("../compaction/strategy.js");
|
|
45
|
+
const turns_js_1 = require("../compaction/turns.js");
|
|
46
|
+
/** Build the compaction stage function. */
|
|
47
|
+
function buildCompactStage(deps) {
|
|
48
|
+
const { config, meter } = deps;
|
|
49
|
+
const now = deps.now ?? (() => Date.now());
|
|
50
|
+
const strategy = (0, strategy_js_1.summarizeOldestStrategy)(config, deps.defaultModel);
|
|
51
|
+
// Dedup latch for the strategy's warning: a summarizer that is down is down
|
|
52
|
+
// for the whole run, and one warning is a warning while ten is noise.
|
|
53
|
+
let warned = false;
|
|
54
|
+
return async (scope) => {
|
|
55
|
+
const metered = meter.lastCall();
|
|
56
|
+
// Iteration 1: nothing has been sent, so nothing has been counted. A
|
|
57
|
+
// compactor that acted here would be guessing, which is the one thing
|
|
58
|
+
// this feature refuses to do.
|
|
59
|
+
if (metered === undefined)
|
|
60
|
+
return;
|
|
61
|
+
if (metered.input === 0 && metered.output === 0) {
|
|
62
|
+
throw new errors_js_1.CompactionUnmeasurableError(deps.providerName);
|
|
63
|
+
}
|
|
64
|
+
if (metered.input <= config.thresholdTokens)
|
|
65
|
+
return;
|
|
66
|
+
// ── Over budget. Ask the strategy what the window should become. ──
|
|
67
|
+
const history = (scope.history ?? []).slice();
|
|
68
|
+
const pausedToolCallId = scope.pausedToolCallId;
|
|
69
|
+
const foldability = {
|
|
70
|
+
answeredCallIds: (0, turns_js_1.answeredCallIds)(history),
|
|
71
|
+
...(pausedToolCallId !== undefined && { pausedToolCallId }),
|
|
72
|
+
...(scope.pausedCheckIn === true && { pausedCheckIn: true }),
|
|
73
|
+
};
|
|
74
|
+
const result = await strategy.plan({
|
|
75
|
+
history,
|
|
76
|
+
turns: (0, turns_js_1.segmentTurns)(history),
|
|
77
|
+
origins: meter.origins(),
|
|
78
|
+
measuredTokens: metered.input,
|
|
79
|
+
foldability,
|
|
80
|
+
iteration: scope.iteration ?? 1,
|
|
81
|
+
signal: scope.$getEnv?.()?.signal,
|
|
82
|
+
now,
|
|
83
|
+
});
|
|
84
|
+
// ── Apply. The stage owns every side effect. ─────────────────────
|
|
85
|
+
if (result.window !== undefined && result.rebase !== undefined) {
|
|
86
|
+
// Tell the meter before writing: the fold is the one window shape it
|
|
87
|
+
// cannot infer (the set trap JSON-round-trips every write).
|
|
88
|
+
meter.rebaseForFold(result.rebase.headCount, result.rebase.keptTailCount, now());
|
|
89
|
+
scope.history = result.window;
|
|
90
|
+
}
|
|
91
|
+
const prior = scope.compactions ?? [];
|
|
92
|
+
scope.compactions = [...prior, result.record];
|
|
93
|
+
// One eviction per message that left, in the slot vocabulary consumers
|
|
94
|
+
// already subscribe to. The hash uses the SAME formula the messages slot
|
|
95
|
+
// used to report the piece as injected, so evicted and injected refer to
|
|
96
|
+
// the same piece by the same name.
|
|
97
|
+
for (const eviction of result.evictions) {
|
|
98
|
+
const msg = history[eviction.index];
|
|
99
|
+
if (msg === undefined)
|
|
100
|
+
continue;
|
|
101
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.context.evicted', {
|
|
102
|
+
slot: 'messages',
|
|
103
|
+
contentHash: (0, helpers_js_1.fnv1a)(`${msg.role}:${eviction.index}:${msg.content}`),
|
|
104
|
+
reason: 'budget',
|
|
105
|
+
survivalMs: eviction.survivalMs,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// `capTokens` / `projectedTokens` are the historical names on
|
|
109
|
+
// `BudgetPressureRecord`; the slots measure them in chars, and this
|
|
110
|
+
// measures them in the tokens the decision was actually made on.
|
|
111
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.context.budget_pressure', {
|
|
112
|
+
slot: 'messages',
|
|
113
|
+
capTokens: config.thresholdTokens,
|
|
114
|
+
projectedTokens: metered.input,
|
|
115
|
+
overflowBy: Math.max(0, metered.input - config.thresholdTokens),
|
|
116
|
+
planAction: result.planAction,
|
|
117
|
+
});
|
|
118
|
+
// A summarizer call is real money. It counts against the same budget.
|
|
119
|
+
if (result.spend !== undefined) {
|
|
120
|
+
(0, cost_js_1.emitCostTick)(scope, deps.pricingTable, deps.costBudget, result.spend.model, result.spend.usage);
|
|
121
|
+
}
|
|
122
|
+
if (result.warning !== undefined && !warned) {
|
|
123
|
+
warned = true;
|
|
124
|
+
// eslint-disable-next-line no-console
|
|
125
|
+
console.warn(`[agentfootprint compaction] ${result.warning}`);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
exports.buildCompactStage = buildCompactStage;
|
|
130
|
+
//# sourceMappingURL=compact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/compact.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
+
}
|