agentfootprint 7.23.0 → 7.25.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/README.md +34 -0
- package/dist/adapters/hosting/agentcore.js +112 -1
- package/dist/adapters/hosting/agentcore.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/act.js +143 -0
- package/dist/core/agent/act.js.map +1 -0
- package/dist/core/agent/middleware/index.js +5 -0
- package/dist/core/agent/middleware/index.js.map +1 -1
- package/dist/core/agent/middleware/ledger.js +7 -0
- package/dist/core/agent/middleware/ledger.js.map +1 -1
- package/dist/core/agent/middleware/outcomes.js +9 -2
- package/dist/core/agent/middleware/outcomes.js.map +1 -1
- package/dist/core/agent/middleware/runChain.js +97 -3
- package/dist/core/agent/middleware/runChain.js.map +1 -1
- package/dist/core/agent/middleware/types.js +30 -0
- package/dist/core/agent/middleware/types.js.map +1 -1
- package/dist/core/agent/moments.js +53 -0
- package/dist/core/agent/moments.js.map +1 -0
- package/dist/core/agent/stages/toolCalls.js +130 -7
- package/dist/core/agent/stages/toolCalls.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/core/agent/AgentBuilder.d.ts +71 -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/act.d.ts +69 -0
- package/dist/esm/core/agent/act.js +139 -0
- package/dist/esm/core/agent/act.js.map +1 -0
- package/dist/esm/core/agent/middleware/index.d.ts +6 -1
- package/dist/esm/core/agent/middleware/index.js +5 -0
- package/dist/esm/core/agent/middleware/index.js.map +1 -1
- package/dist/esm/core/agent/middleware/ledger.d.ts +6 -0
- package/dist/esm/core/agent/middleware/ledger.js +7 -0
- package/dist/esm/core/agent/middleware/ledger.js.map +1 -1
- package/dist/esm/core/agent/middleware/outcomes.d.ts +15 -0
- package/dist/esm/core/agent/middleware/outcomes.js +9 -2
- package/dist/esm/core/agent/middleware/outcomes.js.map +1 -1
- package/dist/esm/core/agent/middleware/runChain.d.ts +47 -0
- package/dist/esm/core/agent/middleware/runChain.js +95 -2
- package/dist/esm/core/agent/middleware/runChain.js.map +1 -1
- package/dist/esm/core/agent/middleware/types.d.ts +132 -10
- package/dist/esm/core/agent/middleware/types.js +30 -0
- package/dist/esm/core/agent/middleware/types.js.map +1 -1
- package/dist/esm/core/agent/moments.d.ts +55 -0
- package/dist/esm/core/agent/moments.js +49 -0
- package/dist/esm/core/agent/moments.js.map +1 -0
- package/dist/esm/core/agent/stages/toolCalls.d.ts +6 -1
- package/dist/esm/core/agent/stages/toolCalls.js +131 -8
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +4 -0
- 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 +3 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpServe.js +25 -1
- package/dist/esm/lib/mcp/mcpServe.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 +12 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/mcpServe.js +24 -0
- package/dist/lib/mcp/mcpServe.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/core/agent/AgentBuilder.d.ts +71 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/act.d.ts +70 -0
- package/dist/types/core/agent/act.d.ts.map +1 -0
- package/dist/types/core/agent/middleware/index.d.ts +6 -1
- package/dist/types/core/agent/middleware/index.d.ts.map +1 -1
- package/dist/types/core/agent/middleware/ledger.d.ts +6 -0
- package/dist/types/core/agent/middleware/ledger.d.ts.map +1 -1
- package/dist/types/core/agent/middleware/outcomes.d.ts +15 -0
- package/dist/types/core/agent/middleware/outcomes.d.ts.map +1 -1
- package/dist/types/core/agent/middleware/runChain.d.ts +47 -0
- package/dist/types/core/agent/middleware/runChain.d.ts.map +1 -1
- package/dist/types/core/agent/middleware/types.d.ts +132 -10
- package/dist/types/core/agent/middleware/types.d.ts.map +1 -1
- package/dist/types/core/agent/moments.d.ts +56 -0
- package/dist/types/core/agent/moments.d.ts.map +1 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts +6 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +4 -0
- package/dist/types/events/payloads.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 +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/index.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAEH,6CAAiD;AAAxC,oGAAA,KAAK,OAAA;AAAE,kGAAA,GAAG,OAAA;AAAE,mGAAA,IAAI,OAAA;AACzB,yCAA4E;AAAnE,+GAAA,kBAAkB,OAAA"}
|
|
@@ -17,6 +17,12 @@
|
|
|
17
17
|
* disagreement from a lie into a record. Every slice taken afterwards can
|
|
18
18
|
* then find the moment the value changed and who changed it.
|
|
19
19
|
*
|
|
20
|
+
* The same reasoning covers the `'after-tool'` moment from the other side. A
|
|
21
|
+
* result the model was not allowed to read still HAPPENED — the tool ran, the
|
|
22
|
+
* side effect landed — so the refusal row carries the real result. A run that
|
|
23
|
+
* dropped it would record an agent that called a tool and got nothing back,
|
|
24
|
+
* which is not what occurred.
|
|
25
|
+
*
|
|
20
26
|
* This is not a redaction layer, and it is not trying to be one. For the
|
|
21
27
|
* `'input'` phase in particular, the ledger row is the ONLY copy of the
|
|
22
28
|
* pre-scrub text anywhere in the run — the seed stage commits the
|
|
@@ -46,6 +52,7 @@ function recordDecisions(scope, rows) {
|
|
|
46
52
|
for (const row of rows) {
|
|
47
53
|
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.middleware.decision', {
|
|
48
54
|
middleware: row.middleware,
|
|
55
|
+
moment: row.moment,
|
|
49
56
|
at: row.at,
|
|
50
57
|
...(row.phase !== undefined && { phase: row.phase }),
|
|
51
58
|
...(row.toolName !== undefined && { toolName: row.toolName }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/ledger.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/ledger.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;AAEH,uEAAiE;AASjE;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,KAAkB,EAAE,IAAmC;IACrF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAI,KAAK,CAAC,mBAAiE,IAAI,EAAE,CAAC;IAC5F,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,KAAK,CAAC,mBAAmB,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAA,wBAAS,EAAC,KAAK,EAAE,oCAAoC,EAAE;YACrD,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7D,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;YACnE,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AArBD,0CAqBC"}
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.ask = exports.deny = exports.allow = void 0;
|
|
20
20
|
function allow(value, why) {
|
|
21
|
-
if (value === undefined)
|
|
22
|
-
return { kind: 'allow' };
|
|
21
|
+
if (value === undefined) {
|
|
22
|
+
return typeof why === 'string' && why.length > 0 ? { kind: 'allow', why } : { kind: 'allow' };
|
|
23
|
+
}
|
|
23
24
|
if (typeof why !== 'string' || why.length === 0) {
|
|
24
25
|
throw new Error('allow(value, why): a transform must say why. Pass a short reason — it is what the ' +
|
|
25
26
|
'ledger shows next to the before/after pair. To pass the value through unchanged, ' +
|
|
@@ -34,6 +35,12 @@ exports.allow = allow;
|
|
|
34
35
|
* For a tool the reason reaches the model verbatim, as the tool's result,
|
|
35
36
|
* and the loop continues — the agent gets to adapt. For a message it
|
|
36
37
|
* surfaces as a `MessageDeniedError`.
|
|
38
|
+
*
|
|
39
|
+
* At the after-tool moment it means "the model does not get to read this" — the
|
|
40
|
+
* tool has already run, so the refusal replaces what the model reads while
|
|
41
|
+
* the run keeps the real result in the ledger. Refusing there hides an answer
|
|
42
|
+
* from the model; it cannot un-happen a side effect, and it does not pretend
|
|
43
|
+
* to.
|
|
37
44
|
*/
|
|
38
45
|
function deny(reason) {
|
|
39
46
|
if (typeof reason !== 'string' || reason.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outcomes.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/outcomes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;
|
|
1
|
+
{"version":3,"file":"outcomes.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/outcomes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAuBH,SAAgB,KAAK,CAAI,KAAS,EAAE,GAAY;IAC9C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAChG,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,oFAAoF;YAClF,mFAAmF;YACnF,iCAAiC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACvC,CAAC;AAZD,sBAYC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,IAAI,CAAC,MAAc;IACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,qEAAqE,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC;AARD,oBAQC;AAED;;;;;;;;GAQG;AACH,SAAgB,GAAG,CAAC,OAAmB;IACrC,IACE,OAAO,KAAK,IAAI;QAChB,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CACb,uFAAuF;YACrF,gDAAgD,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAbD,kBAaC"}
|
|
@@ -26,9 +26,19 @@
|
|
|
26
26
|
* permission gate has always applied to a checker that throws: a
|
|
27
27
|
* governance layer whose failure mode is "allow" is not a governance
|
|
28
28
|
* layer.
|
|
29
|
+
*
|
|
30
|
+
* **The result comes back through the onion.** `runToolAfterChain` walks the
|
|
31
|
+
* SAME list in reverse, so the first-declared link gets the first word about
|
|
32
|
+
* the call and the last word about the result. An outer rule is the one that
|
|
33
|
+
* sees what every inner rule already did — which is the only order in which
|
|
34
|
+
* "wrap" means anything.
|
|
35
|
+
*
|
|
36
|
+
* **A link that has no hook for a moment files no row.** It did not decide;
|
|
37
|
+
* saying it allowed would be inventing a decision, and the ledger's whole
|
|
38
|
+
* value is that a row means somebody looked.
|
|
29
39
|
*/
|
|
30
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.runMessageChain = exports.runToolChain = void 0;
|
|
41
|
+
exports.runMessageChain = exports.runToolAfterChain = exports.runToolChain = void 0;
|
|
32
42
|
/** Walk the tool chain. Never throws — a throwing link becomes a denial. */
|
|
33
43
|
async function runToolChain(chain, input) {
|
|
34
44
|
const decisions = [];
|
|
@@ -36,8 +46,13 @@ async function runToolChain(chain, input) {
|
|
|
36
46
|
let args = input.args;
|
|
37
47
|
for (let i = input.startIndex ?? 0; i < chain.length; i++) {
|
|
38
48
|
const mw = chain[i];
|
|
49
|
+
// A result-only link takes no part in dispatch — and files no row here,
|
|
50
|
+
// because it did not decide anything about this call.
|
|
51
|
+
if (typeof mw.onToolCall !== 'function')
|
|
52
|
+
continue;
|
|
39
53
|
const row = (extra) => ({
|
|
40
54
|
middleware: mw.name,
|
|
55
|
+
moment: 'before-tool',
|
|
41
56
|
at: 'tool',
|
|
42
57
|
toolName: input.toolName,
|
|
43
58
|
toolCallId: input.toolCallId,
|
|
@@ -94,12 +109,90 @@ async function runToolChain(chain, input) {
|
|
|
94
109
|
decisions.push(row({ changed: true, ...(outcome.why && { why: outcome.why }), before, after: args }));
|
|
95
110
|
}
|
|
96
111
|
else {
|
|
97
|
-
|
|
112
|
+
// `allow(undefined, why)` — nothing moved, and the link said why it was
|
|
113
|
+
// comfortable. The reason belongs on the row of the call it permitted.
|
|
114
|
+
decisions.push(row(outcome.why ? { why: outcome.why } : {}));
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
return { kind: 'allow', args, decisions };
|
|
101
118
|
}
|
|
102
119
|
exports.runToolChain = runToolChain;
|
|
120
|
+
/**
|
|
121
|
+
* Walk the chain BACKWARDS over a finished call. Never throws — a throwing
|
|
122
|
+
* link becomes a denial, which at this moment means the model reads the
|
|
123
|
+
* reason instead of the result.
|
|
124
|
+
*
|
|
125
|
+
* Only called for a call that actually executed. A call the chain denied, or
|
|
126
|
+
* one still waiting on a person, has no result to decide about, and asking a
|
|
127
|
+
* rule about a result that does not exist would be the same fabrication the
|
|
128
|
+
* outcome union exists to prevent.
|
|
129
|
+
*/
|
|
130
|
+
async function runToolAfterChain(chain, input) {
|
|
131
|
+
const decisions = [];
|
|
132
|
+
const real = input.result;
|
|
133
|
+
let result = real;
|
|
134
|
+
// Reverse: first-declared saw the call first, so it sees the result last.
|
|
135
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
136
|
+
const mw = chain[i];
|
|
137
|
+
const hook = mw.onToolResult;
|
|
138
|
+
if (typeof hook !== 'function')
|
|
139
|
+
continue;
|
|
140
|
+
const row = (extra) => ({
|
|
141
|
+
middleware: mw.name,
|
|
142
|
+
moment: 'after-tool',
|
|
143
|
+
at: 'tool',
|
|
144
|
+
toolName: input.toolName,
|
|
145
|
+
toolCallId: input.toolCallId,
|
|
146
|
+
iteration: input.iteration,
|
|
147
|
+
outcome: 'allow',
|
|
148
|
+
changed: false,
|
|
149
|
+
...extra,
|
|
150
|
+
});
|
|
151
|
+
let outcome;
|
|
152
|
+
try {
|
|
153
|
+
outcome = await hook.call(mw, {
|
|
154
|
+
toolName: input.toolName,
|
|
155
|
+
...(input.toolSource !== undefined && { toolSource: input.toolSource }),
|
|
156
|
+
toolCallId: input.toolCallId,
|
|
157
|
+
iteration: input.iteration,
|
|
158
|
+
args: input.args,
|
|
159
|
+
result,
|
|
160
|
+
...(input.error === true && { error: true }),
|
|
161
|
+
history: input.history,
|
|
162
|
+
...(input.identity && { identity: input.identity }),
|
|
163
|
+
...(input.signal && { signal: input.signal }),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const reason = `middleware '${mw.name}' threw: ${err instanceof Error ? err.message : String(err)}`;
|
|
168
|
+
decisions.push(row({ outcome: 'deny', changed: true, why: reason, before: result, after: reason }));
|
|
169
|
+
return { kind: 'deny', reason, middleware: mw.name, result: real, decisions };
|
|
170
|
+
}
|
|
171
|
+
if (outcome.kind === 'deny') {
|
|
172
|
+
// `changed: true` on purpose: unlike a refusal before dispatch, this one
|
|
173
|
+
// DOES replace something. The real result rides `before` — often the
|
|
174
|
+
// only copy of it in the run.
|
|
175
|
+
decisions.push(row({
|
|
176
|
+
outcome: 'deny',
|
|
177
|
+
changed: true,
|
|
178
|
+
why: outcome.reason,
|
|
179
|
+
before: result,
|
|
180
|
+
after: outcome.reason,
|
|
181
|
+
}));
|
|
182
|
+
return { kind: 'deny', reason: outcome.reason, middleware: mw.name, result: real, decisions };
|
|
183
|
+
}
|
|
184
|
+
if (outcome.value !== undefined) {
|
|
185
|
+
const before = result;
|
|
186
|
+
result = outcome.value;
|
|
187
|
+
decisions.push(row({ changed: true, ...(outcome.why && { why: outcome.why }), before, after: result }));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
decisions.push(row(outcome.why ? { why: outcome.why } : {}));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return { kind: 'allow', result, decisions };
|
|
194
|
+
}
|
|
195
|
+
exports.runToolAfterChain = runToolAfterChain;
|
|
103
196
|
/** Walk the message chain. Never throws — a throwing link becomes a denial. */
|
|
104
197
|
async function runMessageChain(chain, input) {
|
|
105
198
|
const decisions = [];
|
|
@@ -107,6 +200,7 @@ async function runMessageChain(chain, input) {
|
|
|
107
200
|
for (const mw of chain) {
|
|
108
201
|
const row = (extra) => ({
|
|
109
202
|
middleware: mw.name,
|
|
203
|
+
moment: input.phase,
|
|
110
204
|
at: 'message',
|
|
111
205
|
phase: input.phase,
|
|
112
206
|
iteration: input.iteration,
|
|
@@ -139,7 +233,7 @@ async function runMessageChain(chain, input) {
|
|
|
139
233
|
decisions.push(row({ changed: true, ...(outcome.why && { why: outcome.why }), before, after: content }));
|
|
140
234
|
}
|
|
141
235
|
else {
|
|
142
|
-
decisions.push(row({}));
|
|
236
|
+
decisions.push(row(outcome.why ? { why: outcome.why } : {}));
|
|
143
237
|
}
|
|
144
238
|
}
|
|
145
239
|
return { kind: 'allow', content, decisions };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runChain.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/runChain.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"runChain.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/runChain.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,6 +36,36 @@
|
|
|
36
36
|
* `checkIn` and `askHuman` already go through. `MessageOutcome` does not,
|
|
37
37
|
* because the message boundary is a plain stage, and inventing a second
|
|
38
38
|
* pause to give it one would be a worse answer than not offering it.
|
|
39
|
+
* `ToolResultOutcome` does not either — see below.
|
|
40
|
+
*
|
|
41
|
+
* ## The two moments of a tool call
|
|
42
|
+
*
|
|
43
|
+
* A tool middleware may speak twice about one call:
|
|
44
|
+
*
|
|
45
|
+
* `onToolCall` BEFORE dispatch — about the call. Three verbs.
|
|
46
|
+
* `onToolResult` AFTER the tool ran, before its result enters the history
|
|
47
|
+
* or reaches the model — about the result. Two verbs.
|
|
48
|
+
*
|
|
49
|
+
* Each hook is named for what it RECEIVES; the moments they sit at are named
|
|
50
|
+
* `'before-tool'` and `'after-tool'` (and `.act()`'s keys after those).
|
|
51
|
+
*
|
|
52
|
+
* Either hook alone is a whole middleware; a link with only `onToolResult`
|
|
53
|
+
* does not take part in dispatch at all. The chain walks the two moments in **onion
|
|
54
|
+
* order**: the first-declared link sees the CALL first and the RESULT last —
|
|
55
|
+
* first word going in, last word coming out — which is the order that lets an
|
|
56
|
+
* outer rule inspect what every inner rule already did.
|
|
57
|
+
*
|
|
58
|
+
* **There is no `ask` at the after-tool moment.** Not because the machinery is missing —
|
|
59
|
+
* the dispatch loop pauses perfectly well — but because the tool has ALREADY
|
|
60
|
+
* RUN. A person woken to answer a question about a side effect that already
|
|
61
|
+
* happened cannot prevent it; the honest verbs there are "let the result
|
|
62
|
+
* through" and "do not let the model see it", and both are available now. The
|
|
63
|
+
* business cases this was measured against — authorize before, hide from the
|
|
64
|
+
* model, annotate the result, attach a fact through a context trigger — none
|
|
65
|
+
* of them needed a person at that moment. This is a refusal, not an oversight,
|
|
66
|
+
* and it is written here so evidence can promote it later: bring a case that
|
|
67
|
+
* genuinely needs a human at the after-tool moment and the arm can be added, on the
|
|
68
|
+
* pause machinery that already exists.
|
|
39
69
|
*/
|
|
40
70
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
71
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/types.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* moments — PUBLIC. The five places in the loop where a rule may speak.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: Closed enumeration + a mechanical name mapping, with the mapping
|
|
6
|
+
* pinned by the compiler rather than by memory.
|
|
7
|
+
* Role: core/ layer. `LoopMoment` is the vocabulary `.act()` is keyed on
|
|
8
|
+
* and the vocabulary every ledger row now stamps itself with, so a
|
|
9
|
+
* person asking "where in the loop did this happen?" and a person
|
|
10
|
+
* asking "where in the loop can I intervene?" are reading the same
|
|
11
|
+
* five words.
|
|
12
|
+
* Emits: N/A (types + one pure function).
|
|
13
|
+
*
|
|
14
|
+
* ## Why the list is here and not inside `.act()`
|
|
15
|
+
*
|
|
16
|
+
* A bundle whose keys ARE the moments is only honest while the two sets
|
|
17
|
+
* agree. Keep the list of moments in the options type and the sixth moment
|
|
18
|
+
* ships with no key and nothing notices; keep it here, derive the key names
|
|
19
|
+
* from it, and the day a moment is added the build fails inside `act.ts`
|
|
20
|
+
* naming the key nobody wrote. That is the same trick `conformSource` plays
|
|
21
|
+
* on the outside world, turned inward on ourselves.
|
|
22
|
+
*
|
|
23
|
+
* The mapping between the two spellings is mechanical — kebab in the record
|
|
24
|
+
* (`'before-tool'`, which reads as a phase), camel in the bundle
|
|
25
|
+
* (`beforeTool`, which reads as a property) — and `actKeyFor` is its runtime
|
|
26
|
+
* twin, so the validator that decides which keys `.act()` accepts is
|
|
27
|
+
* DERIVED from this list rather than typed out beside it.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.actKeyFor = exports.LOOP_MOMENTS = void 0;
|
|
31
|
+
/**
|
|
32
|
+
* Every moment of one agent turn where a rule may act, in the order the loop
|
|
33
|
+
* reaches them.
|
|
34
|
+
*
|
|
35
|
+
* ```
|
|
36
|
+
* input → [ window → … LLM … → before-tool → tool → after-tool ]* → output
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* `watch` attends all five and more; `act` attends exactly these. The
|
|
40
|
+
* difference is what a rule may DO there — an observer reports, a rule
|
|
41
|
+
* changes what happens next.
|
|
42
|
+
*/
|
|
43
|
+
exports.LOOP_MOMENTS = ['input', 'before-tool', 'after-tool', 'window', 'output'];
|
|
44
|
+
/**
|
|
45
|
+
* The runtime twin of {@link ActKey}. `.act()`'s accepted key set is built
|
|
46
|
+
* from this over `LOOP_MOMENTS`, so an unknown key is refused by a rule that
|
|
47
|
+
* cannot fall behind the list it is derived from.
|
|
48
|
+
*/
|
|
49
|
+
function actKeyFor(moment) {
|
|
50
|
+
return moment.replace(/-(.)/g, (_match, c) => c.toUpperCase());
|
|
51
|
+
}
|
|
52
|
+
exports.actKeyFor = actKeyFor;
|
|
53
|
+
//# sourceMappingURL=moments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moments.js","sourceRoot":"","sources":["../../../src/core/agent/moments.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;AAEH;;;;;;;;;;;GAWG;AACU,QAAA,YAAY,GAAG,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAehG;;;;GAIG;AACH,SAAgB,SAAS,CAAC,MAAkB;IAC1C,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAW,CAAC;AACnF,CAAC;AAFD,8BAEC"}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* Gate order for one call, and why it is this order:
|
|
25
25
|
*
|
|
26
26
|
* permission → MIDDLEWARE CHAIN → arg validation → check-in →
|
|
27
|
-
* credentials → execute
|
|
27
|
+
* credentials → execute → THE CHAIN AGAIN, BACKWARDS (`onToolResult`)
|
|
28
28
|
*
|
|
29
29
|
* The chain sits after the permission gate so an existing checker still
|
|
30
30
|
* decides first (a denial there means no middleware runs), and before arg
|
|
@@ -34,6 +34,11 @@
|
|
|
34
34
|
* pauses on the SAME wire `checkIn` uses; the human's answer is a
|
|
35
35
|
* decision, not a result, so the chain resumes and the REAL tool runs.
|
|
36
36
|
*
|
|
37
|
+
* The last step is the same chain walked BACKWARDS over the result, before it
|
|
38
|
+
* becomes history — so the first-declared rule has the first word about the
|
|
39
|
+
* call and the last word about the answer. It runs only for a call that
|
|
40
|
+
* executed: everything the gates above refuse has no result to decide about.
|
|
41
|
+
*
|
|
37
42
|
* `read_skill` is the auto-attached activation tool — when the LLM
|
|
38
43
|
* calls it with a valid Skill id, the next InjectionEngine pass
|
|
39
44
|
* activates that Skill (lifetime: turn).
|
|
@@ -73,6 +78,45 @@ function buildToolCallsHandler(deps) {
|
|
|
73
78
|
const cached = providerToolCache?.current ?? [];
|
|
74
79
|
return cached.find((t) => t.schema.name === toolName);
|
|
75
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* The after-tool moment: the chain's last word, on a call that RAN.
|
|
83
|
+
*
|
|
84
|
+
* Called from all three dispatch sites (the loop, an approved ask, an
|
|
85
|
+
* approved check-in) and from nowhere else — every one of them has just
|
|
86
|
+
* executed a tool, which is the entire precondition. A call the chain
|
|
87
|
+
* denied, a call whose args were rejected, a call whose credential never
|
|
88
|
+
* issued and a call still waiting on a person have no result, and asking a
|
|
89
|
+
* rule about a result that does not exist would be the same fabrication the
|
|
90
|
+
* outcome union removes.
|
|
91
|
+
*
|
|
92
|
+
* Returns what the MODEL reads. The real result stays with the caller for
|
|
93
|
+
* `stream.tool_end`, so an event stream keeps reporting what the tool
|
|
94
|
+
* returned while the history carries what the rules allowed through — and
|
|
95
|
+
* the ledger row beside them says which is which.
|
|
96
|
+
*/
|
|
97
|
+
const afterMoment = async (scope, call) => {
|
|
98
|
+
const chain = deps.toolMiddleware ?? [];
|
|
99
|
+
// No `onToolResult` hook anywhere in the chain → no walk, no rows, no await
|
|
100
|
+
// beyond the ones this dispatch already made. An agent whose middleware
|
|
101
|
+
// only governs calls is byte-identical to one built before this moment
|
|
102
|
+
// existed.
|
|
103
|
+
if (!chain.some((mw) => typeof mw.onToolResult === 'function'))
|
|
104
|
+
return call.result;
|
|
105
|
+
const verdict = await (0, runChain_js_1.runToolAfterChain)(chain, {
|
|
106
|
+
toolName: call.toolName,
|
|
107
|
+
...(call.tool?.source !== undefined && { toolSource: call.tool.source }),
|
|
108
|
+
toolCallId: call.toolCallId,
|
|
109
|
+
iteration: call.iteration,
|
|
110
|
+
args: call.args,
|
|
111
|
+
result: call.result,
|
|
112
|
+
...(call.error === true && { error: true }),
|
|
113
|
+
history: call.history,
|
|
114
|
+
...(call.identity && { identity: call.identity }),
|
|
115
|
+
...(call.signal && { signal: call.signal }),
|
|
116
|
+
});
|
|
117
|
+
(0, ledger_js_1.recordDecisions)(scope, verdict.decisions);
|
|
118
|
+
return verdict.kind === 'deny' ? verdict.reason : verdict.result;
|
|
119
|
+
};
|
|
76
120
|
// Resolve a tool's declared credential (declare-and-push) and execute it,
|
|
77
121
|
// emitting the same credential.* events as the main loop. Used by the
|
|
78
122
|
// check-in RESUME path when a human APPROVES — the tool never ran at pause
|
|
@@ -137,16 +181,24 @@ function buildToolCallsHandler(deps) {
|
|
|
137
181
|
hasCredentials,
|
|
138
182
|
...(resolvedCredential && { credential: resolvedCredential }),
|
|
139
183
|
});
|
|
140
|
-
return { result };
|
|
184
|
+
return { result, executed: true };
|
|
141
185
|
}
|
|
142
186
|
catch (err) {
|
|
143
187
|
if ((0, pause_js_1.isPauseRequest)(err)) {
|
|
144
188
|
return {
|
|
145
189
|
result: `tool '${toolName}' requested a pause while resuming an approved check-in, which is not supported`,
|
|
146
190
|
error: true,
|
|
191
|
+
// It ran — a tool that asked to pause had already started work.
|
|
192
|
+
executed: true,
|
|
147
193
|
};
|
|
148
194
|
}
|
|
149
|
-
|
|
195
|
+
// A tool that threw still RAN, and may have done half its work; the
|
|
196
|
+
// after-tool moment exists precisely for the rules that care about that.
|
|
197
|
+
return {
|
|
198
|
+
result: err instanceof Error ? err.message : String(err),
|
|
199
|
+
error: true,
|
|
200
|
+
executed: true,
|
|
201
|
+
};
|
|
150
202
|
}
|
|
151
203
|
};
|
|
152
204
|
return {
|
|
@@ -234,6 +286,8 @@ function buildToolCallsHandler(deps) {
|
|
|
234
286
|
// answer to "what did this call really run with".
|
|
235
287
|
let callArgs = tc.args;
|
|
236
288
|
let denied = false;
|
|
289
|
+
/** True once `tool.execute` has been entered — see `afterMoment`. */
|
|
290
|
+
let executed = false;
|
|
237
291
|
let haltContext;
|
|
238
292
|
if (permissionChecker) {
|
|
239
293
|
try {
|
|
@@ -500,6 +554,10 @@ function buildToolCallsHandler(deps) {
|
|
|
500
554
|
try {
|
|
501
555
|
if (!tool)
|
|
502
556
|
throw new Error(`Unknown tool: ${tc.name}`);
|
|
557
|
+
// Set BEFORE the await: a tool that throws has still run, and a
|
|
558
|
+
// tool that does not exist has not. This flag is the entire
|
|
559
|
+
// precondition of the after-tool moment below.
|
|
560
|
+
executed = true;
|
|
503
561
|
result = await tool.execute(callArgs, {
|
|
504
562
|
toolCallId: tc.id,
|
|
505
563
|
iteration,
|
|
@@ -559,6 +617,24 @@ function buildToolCallsHandler(deps) {
|
|
|
559
617
|
}
|
|
560
618
|
}
|
|
561
619
|
}
|
|
620
|
+
// ── The after-tool moment ────────────────────────────────────────
|
|
621
|
+
// Last thing before the result becomes history, and only for a call
|
|
622
|
+
// that ran. `modelResult` is what the model reads; `result` stays the
|
|
623
|
+
// truth about the tool and is what `stream.tool_end` reports.
|
|
624
|
+
const modelResult = executed
|
|
625
|
+
? await afterMoment(scope, {
|
|
626
|
+
...(tool && { tool }),
|
|
627
|
+
toolName: tc.name,
|
|
628
|
+
toolCallId: tc.id,
|
|
629
|
+
iteration,
|
|
630
|
+
args: callArgs,
|
|
631
|
+
result,
|
|
632
|
+
...(error === true && { error: true }),
|
|
633
|
+
history: newHistory,
|
|
634
|
+
...(runIdentity && { identity: runIdentity }),
|
|
635
|
+
...(env.signal && { signal: env.signal }),
|
|
636
|
+
})
|
|
637
|
+
: result;
|
|
562
638
|
const durationMs = Date.now() - startMs;
|
|
563
639
|
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.tool_end', {
|
|
564
640
|
toolCallId: tc.id,
|
|
@@ -566,7 +642,7 @@ function buildToolCallsHandler(deps) {
|
|
|
566
642
|
durationMs,
|
|
567
643
|
...(error === true && { error: true }),
|
|
568
644
|
});
|
|
569
|
-
const resultStr = typeof
|
|
645
|
+
const resultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
|
|
570
646
|
newHistory.push({
|
|
571
647
|
role: 'tool',
|
|
572
648
|
content: resultStr,
|
|
@@ -673,12 +749,16 @@ function buildToolCallsHandler(deps) {
|
|
|
673
749
|
? input
|
|
674
750
|
: (0, checkin_js_1.checkInDeclined)({ by: 'unknown', note: 'resume input was not a CheckInDecision' });
|
|
675
751
|
let result;
|
|
752
|
+
/** What the model reads. Differs from `result` only when a rule at the
|
|
753
|
+
* after-tool moment transformed or withheld it. */
|
|
754
|
+
let modelResult;
|
|
676
755
|
let error;
|
|
677
756
|
if (!decision.approved) {
|
|
678
757
|
result = decision.note ? `declined by human: ${decision.note}` : 'declined by human';
|
|
679
758
|
(0, ledger_js_1.recordDecisions)(scope, [
|
|
680
759
|
{
|
|
681
760
|
middleware: askedBy,
|
|
761
|
+
moment: 'before-tool',
|
|
682
762
|
at: 'tool',
|
|
683
763
|
toolName,
|
|
684
764
|
toolCallId,
|
|
@@ -693,6 +773,7 @@ function buildToolCallsHandler(deps) {
|
|
|
693
773
|
(0, ledger_js_1.recordDecisions)(scope, [
|
|
694
774
|
{
|
|
695
775
|
middleware: askedBy,
|
|
776
|
+
moment: 'before-tool',
|
|
696
777
|
at: 'tool',
|
|
697
778
|
toolName,
|
|
698
779
|
toolCallId,
|
|
@@ -747,9 +828,30 @@ function buildToolCallsHandler(deps) {
|
|
|
747
828
|
const dispatched = await resolveCredentialAndExecute(scope, tool, toolName, rest.args, toolCallId, iteration, env);
|
|
748
829
|
result = dispatched.result;
|
|
749
830
|
error = dispatched.error;
|
|
831
|
+
// The tool ran on this side of the pause, so the chain gets its
|
|
832
|
+
// last word here too — a rule about results cannot be skipped by
|
|
833
|
+
// routing a call through a human.
|
|
834
|
+
if (dispatched.executed === true) {
|
|
835
|
+
modelResult = await afterMoment(scope, {
|
|
836
|
+
...(tool && { tool }),
|
|
837
|
+
toolName,
|
|
838
|
+
toolCallId,
|
|
839
|
+
iteration,
|
|
840
|
+
args: rest.args,
|
|
841
|
+
result,
|
|
842
|
+
...(error === true && { error: true }),
|
|
843
|
+
history: [...scope.history],
|
|
844
|
+
...(scope.runIdentity && { identity: scope.runIdentity }),
|
|
845
|
+
...(env.signal && { signal: env.signal }),
|
|
846
|
+
});
|
|
847
|
+
}
|
|
750
848
|
}
|
|
751
849
|
}
|
|
752
|
-
|
|
850
|
+
// `modelResult` is only set where the after-tool moment ran; everywhere
|
|
851
|
+
// else the two are the same value.
|
|
852
|
+
if (modelResult === undefined)
|
|
853
|
+
modelResult = result;
|
|
854
|
+
const askResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
|
|
753
855
|
const askHistory = [
|
|
754
856
|
...scope.history,
|
|
755
857
|
{ role: 'tool', content: askResultStr, toolCallId, toolName },
|
|
@@ -803,17 +905,38 @@ function buildToolCallsHandler(deps) {
|
|
|
803
905
|
...(decision.note !== undefined && { note: decision.note }),
|
|
804
906
|
});
|
|
805
907
|
let result;
|
|
908
|
+
/** What the model reads — see the ask path above. */
|
|
909
|
+
let modelResult;
|
|
806
910
|
let error;
|
|
807
911
|
if (decision.approved) {
|
|
808
912
|
const env = scope.$getEnv();
|
|
809
|
-
const
|
|
913
|
+
const tool = lookupTool(toolName);
|
|
914
|
+
const dispatched = await resolveCredentialAndExecute(scope, tool, toolName, args, toolCallId, iteration, env);
|
|
810
915
|
result = dispatched.result;
|
|
811
916
|
error = dispatched.error;
|
|
917
|
+
// Consent moved the execution to this side of the pause; the rules
|
|
918
|
+
// about results move with it.
|
|
919
|
+
if (dispatched.executed === true) {
|
|
920
|
+
modelResult = await afterMoment(scope, {
|
|
921
|
+
...(tool && { tool }),
|
|
922
|
+
toolName,
|
|
923
|
+
toolCallId,
|
|
924
|
+
iteration,
|
|
925
|
+
args,
|
|
926
|
+
result,
|
|
927
|
+
...(error === true && { error: true }),
|
|
928
|
+
history: [...scope.history],
|
|
929
|
+
...(scope.runIdentity && { identity: scope.runIdentity }),
|
|
930
|
+
...(env.signal && { signal: env.signal }),
|
|
931
|
+
});
|
|
932
|
+
}
|
|
812
933
|
}
|
|
813
934
|
else {
|
|
814
935
|
result = decision.note ? `declined by human: ${decision.note}` : 'declined by human';
|
|
815
936
|
}
|
|
816
|
-
|
|
937
|
+
if (modelResult === undefined)
|
|
938
|
+
modelResult = result;
|
|
939
|
+
const decisionResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
|
|
817
940
|
const decisionHistory = [
|
|
818
941
|
...scope.history,
|
|
819
942
|
{ role: 'tool', content: decisionResultStr, toolCallId, toolName },
|