agentfootprint 7.17.0 → 7.18.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 +2 -2
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/core/Agent.js +51 -2
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/RunnerBase.js +16 -1
- package/dist/core/RunnerBase.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +117 -1
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/middleware/errors.js +54 -0
- package/dist/core/agent/middleware/errors.js.map +1 -0
- package/dist/core/agent/middleware/index.js +23 -0
- package/dist/core/agent/middleware/index.js.map +1 -0
- package/dist/core/agent/middleware/ledger.js +61 -0
- package/dist/core/agent/middleware/ledger.js.map +1 -0
- package/dist/core/agent/middleware/outcomes.js +66 -0
- package/dist/core/agent/middleware/outcomes.js.map +1 -0
- package/dist/core/agent/middleware/runChain.js +144 -0
- package/dist/core/agent/middleware/runChain.js.map +1 -0
- package/dist/core/agent/middleware/types.js +41 -0
- package/dist/core/agent/middleware/types.js.map +1 -0
- package/dist/core/agent/stages/prepareFinal.js +10 -0
- package/dist/core/agent/stages/prepareFinal.js.map +1 -1
- package/dist/core/agent/stages/route.js +62 -1
- package/dist/core/agent/stages/route.js.map +1 -1
- package/dist/core/agent/stages/seed.js +130 -85
- package/dist/core/agent/stages/seed.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +195 -8
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/pause.js +19 -1
- package/dist/core/pause.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +9 -1
- package/dist/esm/core/Agent.js +52 -3
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/RunnerBase.js +16 -1
- package/dist/esm/core/RunnerBase.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.d.ts +97 -0
- package/dist/esm/core/agent/AgentBuilder.js +117 -1
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/buildAgentChart.d.ts +2 -2
- package/dist/esm/core/agent/middleware/errors.d.ts +51 -0
- package/dist/esm/core/agent/middleware/errors.js +50 -0
- package/dist/esm/core/agent/middleware/errors.js.map +1 -0
- package/dist/esm/core/agent/middleware/index.d.ts +16 -0
- package/dist/esm/core/agent/middleware/index.js +16 -0
- package/dist/esm/core/agent/middleware/index.js.map +1 -0
- package/dist/esm/core/agent/middleware/ledger.d.ts +40 -0
- package/dist/esm/core/agent/middleware/ledger.js +57 -0
- package/dist/esm/core/agent/middleware/ledger.js.map +1 -0
- package/dist/esm/core/agent/middleware/outcomes.d.ts +45 -0
- package/dist/esm/core/agent/middleware/outcomes.js +60 -0
- package/dist/esm/core/agent/middleware/outcomes.js.map +1 -0
- package/dist/esm/core/agent/middleware/runChain.d.ts +104 -0
- package/dist/esm/core/agent/middleware/runChain.js +139 -0
- package/dist/esm/core/agent/middleware/runChain.js.map +1 -0
- package/dist/esm/core/agent/middleware/types.d.ts +191 -0
- package/dist/esm/core/agent/middleware/types.js +40 -0
- package/dist/esm/core/agent/middleware/types.js.map +1 -0
- package/dist/esm/core/agent/stages/prepareFinal.d.ts +10 -0
- package/dist/esm/core/agent/stages/prepareFinal.js +10 -0
- package/dist/esm/core/agent/stages/prepareFinal.js.map +1 -1
- package/dist/esm/core/agent/stages/route.d.ts +29 -0
- package/dist/esm/core/agent/stages/route.js +60 -0
- package/dist/esm/core/agent/stages/route.js.map +1 -1
- package/dist/esm/core/agent/stages/seed.d.ts +16 -1
- package/dist/esm/core/agent/stages/seed.js +130 -85
- package/dist/esm/core/agent/stages/seed.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.d.ts +23 -0
- package/dist/esm/core/agent/stages/toolCalls.js +195 -8
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +18 -0
- package/dist/esm/core/pause.d.ts +42 -0
- package/dist/esm/core/pause.js +17 -0
- package/dist/esm/core/pause.js.map +1 -1
- package/dist/esm/events/dispatcher.d.ts +1 -1
- package/dist/esm/events/dispatcher.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +26 -0
- package/dist/esm/events/registry.d.ts +5 -1
- package/dist/esm/events/registry.js +4 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +13 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpServe.js +39 -6
- package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
- package/dist/esm/lib/mcp/types.d.ts +16 -0
- package/dist/events/dispatcher.js.map +1 -1
- package/dist/events/registry.js +4 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +31 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/mcpServe.js +39 -6
- package/dist/lib/mcp/mcpServe.js.map +1 -1
- package/dist/types/core/Agent.d.ts +9 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/RunnerBase.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +97 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +2 -2
- package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/middleware/errors.d.ts +52 -0
- package/dist/types/core/agent/middleware/errors.d.ts.map +1 -0
- package/dist/types/core/agent/middleware/index.d.ts +17 -0
- package/dist/types/core/agent/middleware/index.d.ts.map +1 -0
- package/dist/types/core/agent/middleware/ledger.d.ts +41 -0
- package/dist/types/core/agent/middleware/ledger.d.ts.map +1 -0
- package/dist/types/core/agent/middleware/outcomes.d.ts +46 -0
- package/dist/types/core/agent/middleware/outcomes.d.ts.map +1 -0
- package/dist/types/core/agent/middleware/runChain.d.ts +105 -0
- package/dist/types/core/agent/middleware/runChain.d.ts.map +1 -0
- package/dist/types/core/agent/middleware/types.d.ts +192 -0
- package/dist/types/core/agent/middleware/types.d.ts.map +1 -0
- package/dist/types/core/agent/stages/prepareFinal.d.ts +10 -0
- package/dist/types/core/agent/stages/prepareFinal.d.ts.map +1 -1
- package/dist/types/core/agent/stages/route.d.ts +29 -0
- package/dist/types/core/agent/stages/route.d.ts.map +1 -1
- package/dist/types/core/agent/stages/seed.d.ts +16 -1
- package/dist/types/core/agent/stages/seed.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts +23 -0
- package/dist/types/core/agent/stages/toolCalls.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/pause.d.ts +42 -0
- package/dist/types/core/pause.d.ts.map +1 -1
- package/dist/types/events/dispatcher.d.ts +1 -1
- package/dist/types/events/dispatcher.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +26 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +5 -1
- package/dist/types/events/registry.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/lib/mcp/mcpServe.d.ts.map +1 -1
- package/dist/types/lib/mcp/types.d.ts +16 -0
- package/dist/types/lib/mcp/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -20,100 +20,145 @@
|
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.buildSeedStage = void 0;
|
|
22
22
|
const typedEmit_js_1 = require("../../../recorders/core/typedEmit.js");
|
|
23
|
+
const runChain_js_1 = require("../middleware/runChain.js");
|
|
24
|
+
const ledger_js_1 = require("../middleware/ledger.js");
|
|
23
25
|
/**
|
|
24
26
|
* Build the seed stage function for an Agent instance. Captures both
|
|
25
27
|
* the chart-build-time constants and the per-run mutable accessors
|
|
26
28
|
* via the deps object.
|
|
27
29
|
*/
|
|
28
30
|
function buildSeedStage(deps) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// (without resumeOnError) start fresh.
|
|
37
|
-
const resumeHistory = deps.consumePendingResumeHistory();
|
|
38
|
-
if (resumeHistory && resumeHistory.length > 0) {
|
|
39
|
-
scope.history = [...resumeHistory];
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
scope.history = [{ role: 'user', content: args.message }];
|
|
43
|
-
}
|
|
44
|
-
// Default identity uses the runId so multi-run isolation works
|
|
45
|
-
// without consumer changes; explicit identity (multi-tenant)
|
|
46
|
-
// overrides via `agent.run({ identity })`.
|
|
47
|
-
scope.runIdentity = args.identity ?? {
|
|
48
|
-
conversationId: deps.getCurrentRunId() ?? 'default',
|
|
31
|
+
const chain = deps.messageMiddleware ?? [];
|
|
32
|
+
// No chain → the same synchronous function this stage has always been.
|
|
33
|
+
// Not an optimisation: an agent without middleware must produce the same
|
|
34
|
+
// stage shape, the same committed keys and the same request bytes as before.
|
|
35
|
+
if (chain.length === 0) {
|
|
36
|
+
return (scope) => {
|
|
37
|
+
seedFrom(scope, scope.$getArgs().message, deps);
|
|
49
38
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
scope.totalOutputTokens = 0;
|
|
61
|
-
scope.turnStartMs = Date.now();
|
|
62
|
-
scope.systemPromptInjections = [];
|
|
63
|
-
scope.messagesInjections = [];
|
|
64
|
-
scope.toolsInjections = [];
|
|
65
|
-
scope.llmLatestContent = '';
|
|
66
|
-
scope.llmLatestToolCalls = [];
|
|
67
|
-
// v2.14 — initialize thinking blocks. Empty array means "no thinking
|
|
68
|
-
// this iteration"; the NormalizeThinking sub-subflow overwrites
|
|
69
|
-
// this AFTER each CallLLM when a ThinkingHandler is configured.
|
|
70
|
-
scope.thinkingBlocks = [];
|
|
71
|
-
scope.pausedToolCallId = '';
|
|
72
|
-
scope.pausedToolName = '';
|
|
73
|
-
scope.pausedToolStartMs = 0;
|
|
74
|
-
scope.cumTokensInput = 0;
|
|
75
|
-
scope.cumTokensOutput = 0;
|
|
76
|
-
scope.cumEstimatedUsd = 0;
|
|
77
|
-
scope.costBudgetHit = false;
|
|
78
|
-
scope.activeInjections = [];
|
|
79
|
-
scope.activatedInjectionIds = [];
|
|
80
|
-
scope.dynamicToolSchemas = deps.toolSchemas;
|
|
81
|
-
// Cache layer state (v2.6) — initialized to inert defaults.
|
|
82
|
-
// CacheDecision subflow populates `cacheMarkers` per iteration;
|
|
83
|
-
// UpdateSkillHistory + CacheGate consume `cachingDisabled`,
|
|
84
|
-
// `recentHitRate`, `skillHistory`. Empty defaults mean the
|
|
85
|
-
// CacheGate falls through to 'apply-markers' on iter 1 (no
|
|
86
|
-
// history yet → no churn detected; recentHitRate undefined →
|
|
87
|
-
// hit-rate floor doesn't fire).
|
|
88
|
-
scope.cacheMarkers = [];
|
|
89
|
-
scope.cachingDisabled = deps.cachingDisabled;
|
|
90
|
-
scope.recentHitRate = undefined;
|
|
91
|
-
scope.skillHistory = [];
|
|
92
|
-
// Skill-graph cursor — reset per turn so each new user message re-enters the
|
|
93
|
-
// graph through the entry router (cold start). The Injection Engine advances
|
|
94
|
-
// it each iteration; undefined for agents without a skillGraph().
|
|
95
|
-
scope.currentSkillId = undefined;
|
|
96
|
-
// `.configure()` — resolved ONCE here (seed runs exactly once per run)
|
|
97
|
-
// and written to scope, which means the run's commit log records the
|
|
98
|
-
// model and instructions the run actually used. A run that changed its
|
|
99
|
-
// own model without committing that fact would produce a trace that
|
|
100
|
-
// reads as if the built-in default answered.
|
|
101
|
-
//
|
|
102
|
-
// Only what the resolver actually returned is written: an agent with no
|
|
103
|
-
// `.configure()`, or one whose resolver returned `{}`, commits nothing
|
|
104
|
-
// extra and behaves exactly as before.
|
|
105
|
-
if (deps.resolveRunConfig) {
|
|
106
|
-
const resolved = deps.resolveRunConfig(args);
|
|
107
|
-
if (resolved?.model !== undefined)
|
|
108
|
-
scope.resolvedModel = resolved.model;
|
|
109
|
-
if (resolved?.instructions !== undefined)
|
|
110
|
-
scope.resolvedInstructions = resolved.instructions;
|
|
111
|
-
}
|
|
112
|
-
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.turn_start', {
|
|
113
|
-
turnIndex: 0,
|
|
114
|
-
userPrompt: args.message,
|
|
39
|
+
}
|
|
40
|
+
return async (scope) => {
|
|
41
|
+
const args = scope.$getArgs();
|
|
42
|
+
const verdict = await (0, runChain_js_1.runMessageChain)(chain, {
|
|
43
|
+
phase: 'input',
|
|
44
|
+
content: args.message,
|
|
45
|
+
history: [],
|
|
46
|
+
// The input boundary runs before iteration 1 exists.
|
|
47
|
+
iteration: 0,
|
|
48
|
+
...(args.identity && { identity: args.identity }),
|
|
115
49
|
});
|
|
50
|
+
(0, ledger_js_1.recordDecisions)(scope, verdict.decisions);
|
|
51
|
+
if (verdict.kind === 'deny') {
|
|
52
|
+
// Seed the run anyway, with the content as it stood when it was
|
|
53
|
+
// refused, then stop. Committing it costs nothing (a refusal is a fact
|
|
54
|
+
// about a run, and hiding what was refused would make the record
|
|
55
|
+
// useless), and a fully-seeded state means `resumeOnError` and every
|
|
56
|
+
// recorder see the shape they expect rather than a half-built one.
|
|
57
|
+
seedFrom(scope, verdict.content, deps);
|
|
58
|
+
scope.messageDeniedReason = verdict.reason;
|
|
59
|
+
scope.messageDeniedPhase = 'input';
|
|
60
|
+
scope.messageDeniedBy = verdict.middleware;
|
|
61
|
+
// Stops the chart here: no injections, no slots, no LLM call. The
|
|
62
|
+
// boundary turns these flags into a MessageDeniedError.
|
|
63
|
+
scope.$break(`message denied at input: ${verdict.reason}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
seedFrom(scope, verdict.content, deps);
|
|
116
67
|
};
|
|
117
68
|
}
|
|
118
69
|
exports.buildSeedStage = buildSeedStage;
|
|
70
|
+
/**
|
|
71
|
+
* Initialise every mutable field of `AgentState` from `message` + the run
|
|
72
|
+
* args. Split out so the message the run proceeds with can come either
|
|
73
|
+
* straight from the caller or from the `'input'` middleware chain — one
|
|
74
|
+
* initialiser, so the two paths cannot drift.
|
|
75
|
+
*/
|
|
76
|
+
function seedFrom(scope, message, deps) {
|
|
77
|
+
const args = scope.$getArgs();
|
|
78
|
+
scope.userMessage = message;
|
|
79
|
+
// If `resumeOnError(...)` set the side channel, restore the
|
|
80
|
+
// checkpointed conversation history. The next iteration sees
|
|
81
|
+
// the prior messages and continues from the failure point.
|
|
82
|
+
// Always clear the field after reading so subsequent runs
|
|
83
|
+
// (without resumeOnError) start fresh.
|
|
84
|
+
const resumeHistory = deps.consumePendingResumeHistory();
|
|
85
|
+
if (resumeHistory && resumeHistory.length > 0) {
|
|
86
|
+
scope.history = [...resumeHistory];
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
scope.history = [{ role: 'user', content: message }];
|
|
90
|
+
}
|
|
91
|
+
// Default identity uses the runId so multi-run isolation works
|
|
92
|
+
// without consumer changes; explicit identity (multi-tenant)
|
|
93
|
+
// overrides via `agent.run({ identity })`.
|
|
94
|
+
scope.runIdentity = args.identity ?? {
|
|
95
|
+
conversationId: deps.getCurrentRunId() ?? 'default',
|
|
96
|
+
};
|
|
97
|
+
scope.newMessages = [];
|
|
98
|
+
scope.turnNumber = 1;
|
|
99
|
+
// Permissive default — explicit cap will land when PricingTable
|
|
100
|
+
// gets a context-window field. Memory pickByBudget treats anything
|
|
101
|
+
// ≥ minimumTokens as "fits", so this just enables the budget path.
|
|
102
|
+
scope.contextTokensRemaining = 32_000;
|
|
103
|
+
scope.iteration = 1;
|
|
104
|
+
scope.maxIterations = deps.maxIterations;
|
|
105
|
+
scope.finalContent = '';
|
|
106
|
+
scope.totalInputTokens = 0;
|
|
107
|
+
scope.totalOutputTokens = 0;
|
|
108
|
+
scope.turnStartMs = Date.now();
|
|
109
|
+
scope.systemPromptInjections = [];
|
|
110
|
+
scope.messagesInjections = [];
|
|
111
|
+
scope.toolsInjections = [];
|
|
112
|
+
scope.llmLatestContent = '';
|
|
113
|
+
scope.llmLatestToolCalls = [];
|
|
114
|
+
// v2.14 — initialize thinking blocks. Empty array means "no thinking
|
|
115
|
+
// this iteration"; the NormalizeThinking sub-subflow overwrites
|
|
116
|
+
// this AFTER each CallLLM when a ThinkingHandler is configured.
|
|
117
|
+
scope.thinkingBlocks = [];
|
|
118
|
+
scope.pausedToolCallId = '';
|
|
119
|
+
scope.pausedToolName = '';
|
|
120
|
+
scope.pausedToolStartMs = 0;
|
|
121
|
+
scope.cumTokensInput = 0;
|
|
122
|
+
scope.cumTokensOutput = 0;
|
|
123
|
+
scope.cumEstimatedUsd = 0;
|
|
124
|
+
scope.costBudgetHit = false;
|
|
125
|
+
scope.activeInjections = [];
|
|
126
|
+
scope.activatedInjectionIds = [];
|
|
127
|
+
scope.dynamicToolSchemas = deps.toolSchemas;
|
|
128
|
+
// Cache layer state (v2.6) — initialized to inert defaults.
|
|
129
|
+
// CacheDecision subflow populates `cacheMarkers` per iteration;
|
|
130
|
+
// UpdateSkillHistory + CacheGate consume `cachingDisabled`,
|
|
131
|
+
// `recentHitRate`, `skillHistory`. Empty defaults mean the
|
|
132
|
+
// CacheGate falls through to 'apply-markers' on iter 1 (no
|
|
133
|
+
// history yet → no churn detected; recentHitRate undefined →
|
|
134
|
+
// hit-rate floor doesn't fire).
|
|
135
|
+
scope.cacheMarkers = [];
|
|
136
|
+
scope.cachingDisabled = deps.cachingDisabled;
|
|
137
|
+
scope.recentHitRate = undefined;
|
|
138
|
+
scope.skillHistory = [];
|
|
139
|
+
// Skill-graph cursor — reset per turn so each new user message re-enters the
|
|
140
|
+
// graph through the entry router (cold start). The Injection Engine advances
|
|
141
|
+
// it each iteration; undefined for agents without a skillGraph().
|
|
142
|
+
scope.currentSkillId = undefined;
|
|
143
|
+
// `.configure()` — resolved ONCE here (seed runs exactly once per run)
|
|
144
|
+
// and written to scope, which means the run's commit log records the
|
|
145
|
+
// model and instructions the run actually used. A run that changed its
|
|
146
|
+
// own model without committing that fact would produce a trace that
|
|
147
|
+
// reads as if the built-in default answered.
|
|
148
|
+
//
|
|
149
|
+
// Only what the resolver actually returned is written: an agent with no
|
|
150
|
+
// `.configure()`, or one whose resolver returned `{}`, commits nothing
|
|
151
|
+
// extra and behaves exactly as before.
|
|
152
|
+
if (deps.resolveRunConfig) {
|
|
153
|
+
const resolved = deps.resolveRunConfig(args);
|
|
154
|
+
if (resolved?.model !== undefined)
|
|
155
|
+
scope.resolvedModel = resolved.model;
|
|
156
|
+
if (resolved?.instructions !== undefined)
|
|
157
|
+
scope.resolvedInstructions = resolved.instructions;
|
|
158
|
+
}
|
|
159
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.turn_start', {
|
|
160
|
+
turnIndex: 0,
|
|
161
|
+
userPrompt: message,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
119
164
|
//# sourceMappingURL=seed.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/seed.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAIH,uEAAiE;
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../../../src/core/agent/stages/seed.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,19 @@
|
|
|
21
21
|
* `tool.execute`. Deny → tool not executed; result is a synthetic
|
|
22
22
|
* denial string. Allow / gate_open → execution proceeds.
|
|
23
23
|
*
|
|
24
|
+
* Gate order for one call, and why it is this order:
|
|
25
|
+
*
|
|
26
|
+
* permission → MIDDLEWARE CHAIN → arg validation → check-in →
|
|
27
|
+
* credentials → execute
|
|
28
|
+
*
|
|
29
|
+
* The chain sits after the permission gate so an existing checker still
|
|
30
|
+
* decides first (a denial there means no middleware runs), and before arg
|
|
31
|
+
* validation so validation judges the args that will actually be sent —
|
|
32
|
+
* a middleware that transformed args into something the tool's schema
|
|
33
|
+
* rejects must be caught, not forwarded. A middleware answering `ask`
|
|
34
|
+
* pauses on the SAME wire `checkIn` uses; the human's answer is a
|
|
35
|
+
* decision, not a result, so the chain resumes and the REAL tool runs.
|
|
36
|
+
*
|
|
24
37
|
* `read_skill` is the auto-attached activation tool — when the LLM
|
|
25
38
|
* calls it with a valid Skill id, the next InjectionEngine pass
|
|
26
39
|
* activates that Skill (lifetime: turn).
|
|
@@ -32,6 +45,8 @@ const extractSequence_js_1 = require("../../../security/extractSequence.js");
|
|
|
32
45
|
const types_js_1 = require("../../../identity/types.js");
|
|
33
46
|
const pause_js_1 = require("../../pause.js");
|
|
34
47
|
const checkin_js_1 = require("../../checkin.js");
|
|
48
|
+
const runChain_js_1 = require("../middleware/runChain.js");
|
|
49
|
+
const ledger_js_1 = require("../middleware/ledger.js");
|
|
35
50
|
const toolArgsValidation_js_1 = require("../toolArgsValidation.js");
|
|
36
51
|
const validators_js_1 = require("../validators.js");
|
|
37
52
|
/**
|
|
@@ -205,6 +220,12 @@ function buildToolCallsHandler(deps) {
|
|
|
205
220
|
// identity, and abort signal — enough surface to build sequence-
|
|
206
221
|
// aware policies (forbidden chains, idempotency limits, cost
|
|
207
222
|
// guards) without maintaining parallel state.
|
|
223
|
+
// Args as they will actually be used. The middleware chain below may
|
|
224
|
+
// replace this; everything downstream (validation, the check-in
|
|
225
|
+
// evidence a human approves, credentials, execute, the read_skill
|
|
226
|
+
// gate) reads `callArgs`, never `tc.args`, so there is exactly one
|
|
227
|
+
// answer to "what did this call really run with".
|
|
228
|
+
let callArgs = tc.args;
|
|
208
229
|
let denied = false;
|
|
209
230
|
let haltContext;
|
|
210
231
|
if (permissionChecker) {
|
|
@@ -271,6 +292,52 @@ function buildToolCallsHandler(deps) {
|
|
|
271
292
|
result = `[permission denied: checker error: ${msg}]`;
|
|
272
293
|
}
|
|
273
294
|
}
|
|
295
|
+
// ── The middleware chain ─────────────────────────────────────────
|
|
296
|
+
// Walked only for a call the permission gate let through, so an
|
|
297
|
+
// existing checker keeps deciding first and a denial there costs
|
|
298
|
+
// nothing. A denial from the chain lands as the tool result, exactly
|
|
299
|
+
// like every other refusal in this loop — the model reads it and
|
|
300
|
+
// adapts. An `ask` commits partial state and pauses, on the same wire
|
|
301
|
+
// the check-in gate uses.
|
|
302
|
+
if (!denied && deps.toolMiddleware && deps.toolMiddleware.length > 0) {
|
|
303
|
+
const chain = await (0, runChain_js_1.runToolChain)(deps.toolMiddleware, {
|
|
304
|
+
toolName: tc.name,
|
|
305
|
+
toolCallId: tc.id,
|
|
306
|
+
iteration,
|
|
307
|
+
args: callArgs,
|
|
308
|
+
history: newHistory,
|
|
309
|
+
...(runIdentity && { identity: runIdentity }),
|
|
310
|
+
...(env.signal && { signal: env.signal }),
|
|
311
|
+
});
|
|
312
|
+
(0, ledger_js_1.recordDecisions)(scope, chain.decisions);
|
|
313
|
+
callArgs = chain.args;
|
|
314
|
+
if (chain.kind === 'deny') {
|
|
315
|
+
denied = true;
|
|
316
|
+
result = chain.reason;
|
|
317
|
+
}
|
|
318
|
+
else if (chain.kind === 'ask') {
|
|
319
|
+
// Commit partial state so resume() finds history intact (the
|
|
320
|
+
// pauseHere / check-in path does the same). The TRANSFORMED args
|
|
321
|
+
// ride the checkpoint: a person approves what the chain produced,
|
|
322
|
+
// not what the model originally proposed.
|
|
323
|
+
scope.history = newHistory;
|
|
324
|
+
scope.pausedToolCallId = tc.id;
|
|
325
|
+
scope.pausedToolName = tc.name;
|
|
326
|
+
scope.pausedToolStartMs = startMs;
|
|
327
|
+
scope.pausedAsk = true;
|
|
328
|
+
scope.pausedAskArgs = chain.args;
|
|
329
|
+
scope.pausedAskIndex = chain.index;
|
|
330
|
+
scope.pausedAskMiddleware = chain.middleware;
|
|
331
|
+
// A defined return value triggers the footprintjs pause; this
|
|
332
|
+
// object becomes the checkpoint's pauseData, and detectPause
|
|
333
|
+
// surfaces `pauseData.ask` as `outcome.ask`.
|
|
334
|
+
return {
|
|
335
|
+
toolCallId: tc.id,
|
|
336
|
+
toolName: tc.name,
|
|
337
|
+
ask: { ...chain.payload, middleware: chain.middleware },
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
}
|
|
274
341
|
// Tool-args validation (#9) — AFTER the permission gate (policy must
|
|
275
342
|
// see every attempted call, valid or not) and BEFORE credential
|
|
276
343
|
// resolution (never acquire credentials for a call that won't run).
|
|
@@ -281,7 +348,7 @@ function buildToolCallsHandler(deps) {
|
|
|
281
348
|
// tools (their inputSchema is the contract the LLM was shown).
|
|
282
349
|
let argsRejected = false;
|
|
283
350
|
if (!denied && tool && toolArgValidation !== 'off') {
|
|
284
|
-
const verdict = (0, toolArgsValidation_js_1.validateToolArgs)(
|
|
351
|
+
const verdict = (0, toolArgsValidation_js_1.validateToolArgs)(callArgs, tool.schema.inputSchema);
|
|
285
352
|
if (!verdict.ok) {
|
|
286
353
|
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.validation.args_invalid', {
|
|
287
354
|
toolName: tc.name,
|
|
@@ -319,7 +386,7 @@ function buildToolCallsHandler(deps) {
|
|
|
319
386
|
const historyForEvidence = systemPrompt
|
|
320
387
|
? [{ role: 'system', content: systemPrompt }, ...newHistory]
|
|
321
388
|
: newHistory;
|
|
322
|
-
if (!(0, checkin_js_1.shouldCheckIn)(tool.checkIn,
|
|
389
|
+
if (!(0, checkin_js_1.shouldCheckIn)(tool.checkIn, callArgs, {
|
|
323
390
|
iteration,
|
|
324
391
|
toolCallId: tc.id,
|
|
325
392
|
history: historyForEvidence,
|
|
@@ -331,7 +398,7 @@ function buildToolCallsHandler(deps) {
|
|
|
331
398
|
const intent = scope.llmLatestContent ? String(scope.llmLatestContent) : undefined;
|
|
332
399
|
const evidence = await deps.checkIn.assembler({
|
|
333
400
|
tool: { name: tc.name, description: tool.schema.description },
|
|
334
|
-
args:
|
|
401
|
+
args: callArgs,
|
|
335
402
|
...(intent !== undefined && { intent }),
|
|
336
403
|
iteration,
|
|
337
404
|
history: historyForEvidence,
|
|
@@ -340,7 +407,7 @@ function buildToolCallsHandler(deps) {
|
|
|
340
407
|
});
|
|
341
408
|
const request = {
|
|
342
409
|
tool: tc.name,
|
|
343
|
-
args:
|
|
410
|
+
args: callArgs,
|
|
344
411
|
...(intent !== undefined && { intent }),
|
|
345
412
|
evidence,
|
|
346
413
|
};
|
|
@@ -358,7 +425,7 @@ function buildToolCallsHandler(deps) {
|
|
|
358
425
|
scope.pausedToolName = tc.name;
|
|
359
426
|
scope.pausedToolStartMs = startMs;
|
|
360
427
|
scope.pausedCheckIn = true;
|
|
361
|
-
scope.pausedCheckInArgs =
|
|
428
|
+
scope.pausedCheckInArgs = callArgs;
|
|
362
429
|
// Returning a defined value triggers the footprintjs pause; the
|
|
363
430
|
// returned object becomes the checkpoint's pauseData. detectPause
|
|
364
431
|
// surfaces `pauseData.checkIn` as `outcome.checkIn`.
|
|
@@ -423,7 +490,7 @@ function buildToolCallsHandler(deps) {
|
|
|
423
490
|
try {
|
|
424
491
|
if (!tool)
|
|
425
492
|
throw new Error(`Unknown tool: ${tc.name}`);
|
|
426
|
-
result = await tool.execute(
|
|
493
|
+
result = await tool.execute(callArgs, {
|
|
427
494
|
toolCallId: tc.id,
|
|
428
495
|
iteration,
|
|
429
496
|
...(env.signal && { signal: env.signal }),
|
|
@@ -462,7 +529,7 @@ function buildToolCallsHandler(deps) {
|
|
|
462
529
|
// so plain read_skill agents are byte-for-byte unaffected.
|
|
463
530
|
let skillRejected = false;
|
|
464
531
|
if (deps.allowedSkillIds && tc.name === 'read_skill' && !error && !denied) {
|
|
465
|
-
const reqId =
|
|
532
|
+
const reqId = callArgs.id;
|
|
466
533
|
if (typeof reqId === 'string' && reqId.length > 0) {
|
|
467
534
|
const currentSkillId = scope.currentSkillId;
|
|
468
535
|
const allowed = deps.allowedSkillIds(currentSkillId);
|
|
@@ -508,7 +575,7 @@ function buildToolCallsHandler(deps) {
|
|
|
508
575
|
// NEXT pass activates that Skill (lifetime: turn — stays
|
|
509
576
|
// active until the turn ends).
|
|
510
577
|
if (tc.name === 'read_skill' && !error && !denied && !skillRejected) {
|
|
511
|
-
const requestedId =
|
|
578
|
+
const requestedId = callArgs.id;
|
|
512
579
|
if (typeof requestedId === 'string' && requestedId.length > 0) {
|
|
513
580
|
const current = scope.activatedInjectionIds;
|
|
514
581
|
if (!current.includes(requestedId)) {
|
|
@@ -570,6 +637,126 @@ function buildToolCallsHandler(deps) {
|
|
|
570
637
|
const toolCallId = scope.pausedToolCallId;
|
|
571
638
|
const toolName = scope.pausedToolName;
|
|
572
639
|
const startMs = scope.pausedToolStartMs;
|
|
640
|
+
// ── Middleware-ask decision path ─────────────────────────────────
|
|
641
|
+
// Discriminated by `scope.pausedAsk`, restored from the checkpoint.
|
|
642
|
+
//
|
|
643
|
+
// The answer is a DECISION, not a result. That is the whole reason the
|
|
644
|
+
// outcome union has no `result` arm: a middleware asks a person whether
|
|
645
|
+
// this call may proceed, and on approval the REAL tool runs — the person
|
|
646
|
+
// never writes the tool's answer, and neither does the middleware.
|
|
647
|
+
//
|
|
648
|
+
// A malformed resume DECLINES, for the same reason the check-in path
|
|
649
|
+
// does: a governed call must never execute because a message was
|
|
650
|
+
// mis-shaped.
|
|
651
|
+
if (scope.pausedAsk === true) {
|
|
652
|
+
const iteration = scope.iteration;
|
|
653
|
+
const args = (scope.pausedAskArgs ?? {});
|
|
654
|
+
const askIndex = (scope.pausedAskIndex ?? 0);
|
|
655
|
+
const askedBy = (scope.pausedAskMiddleware ?? 'middleware');
|
|
656
|
+
const decision = (0, checkin_js_1.isCheckInDecision)(input)
|
|
657
|
+
? input
|
|
658
|
+
: (0, checkin_js_1.checkInDeclined)({ by: 'unknown', note: 'resume input was not a CheckInDecision' });
|
|
659
|
+
let result;
|
|
660
|
+
let error;
|
|
661
|
+
if (!decision.approved) {
|
|
662
|
+
result = decision.note ? `declined by human: ${decision.note}` : 'declined by human';
|
|
663
|
+
(0, ledger_js_1.recordDecisions)(scope, [
|
|
664
|
+
{
|
|
665
|
+
middleware: askedBy,
|
|
666
|
+
at: 'tool',
|
|
667
|
+
toolName,
|
|
668
|
+
toolCallId,
|
|
669
|
+
iteration,
|
|
670
|
+
outcome: 'deny',
|
|
671
|
+
changed: false,
|
|
672
|
+
why: `declined by ${decision.by}${decision.note ? `: ${decision.note}` : ''}`,
|
|
673
|
+
},
|
|
674
|
+
]);
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
(0, ledger_js_1.recordDecisions)(scope, [
|
|
678
|
+
{
|
|
679
|
+
middleware: askedBy,
|
|
680
|
+
at: 'tool',
|
|
681
|
+
toolName,
|
|
682
|
+
toolCallId,
|
|
683
|
+
iteration,
|
|
684
|
+
outcome: 'allow',
|
|
685
|
+
changed: false,
|
|
686
|
+
why: `approved by ${decision.by}${decision.note ? `: ${decision.note}` : ''}`,
|
|
687
|
+
},
|
|
688
|
+
]);
|
|
689
|
+
// Continue the chain from the link AFTER the one that asked. Its
|
|
690
|
+
// decision is already on the checkpoint; re-running it would ask the
|
|
691
|
+
// same question twice and file a duplicate row.
|
|
692
|
+
//
|
|
693
|
+
// `askPolicy: 'refuse'` because footprintjs's `PausableHandler.resume`
|
|
694
|
+
// returns void — a resumed dispatch has no second checkpoint to give.
|
|
695
|
+
// A link further down the chain that also wants a person gets a named,
|
|
696
|
+
// model-visible refusal and the tool does NOT run. That is the same
|
|
697
|
+
// rule already applied to a tool that tries to pause during an
|
|
698
|
+
// approved check-in resume: at most one human question per resume.
|
|
699
|
+
const rest = await (0, runChain_js_1.runToolChain)(deps.toolMiddleware ?? [], {
|
|
700
|
+
toolName,
|
|
701
|
+
toolCallId,
|
|
702
|
+
iteration,
|
|
703
|
+
args,
|
|
704
|
+
history: [...scope.history],
|
|
705
|
+
startIndex: askIndex + 1,
|
|
706
|
+
askPolicy: 'refuse',
|
|
707
|
+
});
|
|
708
|
+
(0, ledger_js_1.recordDecisions)(scope, rest.decisions);
|
|
709
|
+
const tool = lookupTool(toolName);
|
|
710
|
+
if (rest.kind === 'deny') {
|
|
711
|
+
result = rest.reason;
|
|
712
|
+
}
|
|
713
|
+
else if (tool?.checkIn !== undefined) {
|
|
714
|
+
// Same one-question rule, from the other direction: this tool also
|
|
715
|
+
// demands consent, and there is no checkpoint left to ask with.
|
|
716
|
+
// Refusing loudly beats executing a tool whose consent gate we
|
|
717
|
+
// silently skipped.
|
|
718
|
+
error = true;
|
|
719
|
+
result =
|
|
720
|
+
`tool '${toolName}' also declares checkIn, and a resumed dispatch cannot pause ` +
|
|
721
|
+
`again to ask a second time. The call was not executed — approve it through one ` +
|
|
722
|
+
`gate, not both.`;
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
const env = scope.$getEnv();
|
|
726
|
+
const dispatched = await resolveCredentialAndExecute(scope, tool, toolName, rest.args, toolCallId, iteration, env);
|
|
727
|
+
result = dispatched.result;
|
|
728
|
+
error = dispatched.error;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
const askResultStr = typeof result === 'string' ? result : (0, validators_js_1.safeStringify)(result);
|
|
732
|
+
const askHistory = [
|
|
733
|
+
...scope.history,
|
|
734
|
+
{ role: 'tool', content: askResultStr, toolCallId, toolName },
|
|
735
|
+
];
|
|
736
|
+
scope.history = askHistory;
|
|
737
|
+
scope.lastToolResult = { toolName, result: askResultStr };
|
|
738
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.tool_end', {
|
|
739
|
+
toolCallId,
|
|
740
|
+
result,
|
|
741
|
+
durationMs: Date.now() - startMs,
|
|
742
|
+
...(error === true && { error: true }),
|
|
743
|
+
});
|
|
744
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.iteration_end', {
|
|
745
|
+
turnIndex: 0,
|
|
746
|
+
iterIndex: iteration,
|
|
747
|
+
toolCallCount: 1,
|
|
748
|
+
history: askHistory,
|
|
749
|
+
});
|
|
750
|
+
scope.iteration = iteration + 1;
|
|
751
|
+
scope.pausedToolCallId = '';
|
|
752
|
+
scope.pausedToolName = '';
|
|
753
|
+
scope.pausedToolStartMs = 0;
|
|
754
|
+
scope.pausedAsk = false;
|
|
755
|
+
scope.pausedAskArgs = undefined;
|
|
756
|
+
scope.pausedAskIndex = undefined;
|
|
757
|
+
scope.pausedAskMiddleware = undefined;
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
573
760
|
// ── Check-in decision path ───────────────────────────────────────
|
|
574
761
|
// A check-in pause is discriminated by `scope.pausedCheckIn` (restored
|
|
575
762
|
// from the checkpoint). The resume input is a `CheckInDecision`. On
|