agentfootprint 9.24.0 → 9.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +7 -1
- package/README.md +3 -1
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/code/local.js +102 -2
- package/dist/adapters/code/local.js.map +1 -1
- package/dist/adapters/hosting/agentcore.js +11 -0
- package/dist/adapters/hosting/agentcore.js.map +1 -1
- package/dist/adapters/identity/jwks.js +277 -0
- package/dist/adapters/identity/jwks.js.map +1 -0
- package/dist/adapters/types.js +18 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/artifacts/fileArtifacts.js +144 -17
- package/dist/artifacts/fileArtifacts.js.map +1 -1
- package/dist/artifacts/gcsArtifacts.js +398 -0
- package/dist/artifacts/gcsArtifacts.js.map +1 -0
- package/dist/artifacts/index.js +17 -1
- package/dist/artifacts/index.js.map +1 -1
- package/dist/artifacts/objectStore.js +264 -0
- package/dist/artifacts/objectStore.js.map +1 -0
- package/dist/artifacts/payload.js +41 -2
- package/dist/artifacts/payload.js.map +1 -1
- package/dist/artifacts/recordingArtifact.js +88 -0
- package/dist/artifacts/recordingArtifact.js.map +1 -0
- package/dist/artifacts/s3Artifacts.js +542 -0
- package/dist/artifacts/s3Artifacts.js.map +1 -0
- package/dist/artifacts/scopePath.js +87 -0
- package/dist/artifacts/scopePath.js.map +1 -0
- package/dist/artifacts/streaming.js +132 -0
- package/dist/artifacts/streaming.js.map +1 -0
- package/dist/artifacts/types.js +10 -2
- package/dist/artifacts/types.js.map +1 -1
- package/dist/core/Agent.js +176 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +20 -0
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/repeatedCall.js +190 -0
- package/dist/core/agent/repeatedCall.js.map +1 -0
- package/dist/core/agent/stages/toolCalls.js +50 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/codeRunnerTool.js +149 -12
- package/dist/core/codeRunnerTool.js.map +1 -1
- package/dist/esm/adapters/code/local.d.ts +16 -0
- package/dist/esm/adapters/code/local.js +102 -2
- package/dist/esm/adapters/code/local.js.map +1 -1
- package/dist/esm/adapters/hosting/agentcore.js +11 -0
- package/dist/esm/adapters/hosting/agentcore.js.map +1 -1
- package/dist/esm/adapters/identity/jwks.d.ts +124 -0
- package/dist/esm/adapters/identity/jwks.js +249 -0
- package/dist/esm/adapters/identity/jwks.js.map +1 -0
- package/dist/esm/adapters/types.d.ts +86 -0
- package/dist/esm/adapters/types.js +16 -0
- package/dist/esm/adapters/types.js.map +1 -1
- package/dist/esm/artifacts/fileArtifacts.d.ts +13 -1
- package/dist/esm/artifacts/fileArtifacts.js +145 -18
- package/dist/esm/artifacts/fileArtifacts.js.map +1 -1
- package/dist/esm/artifacts/gcsArtifacts.d.ts +142 -0
- package/dist/esm/artifacts/gcsArtifacts.js +394 -0
- package/dist/esm/artifacts/gcsArtifacts.js.map +1 -0
- package/dist/esm/artifacts/index.d.ts +5 -1
- package/dist/esm/artifacts/index.js +4 -0
- package/dist/esm/artifacts/index.js.map +1 -1
- package/dist/esm/artifacts/objectStore.d.ts +166 -0
- package/dist/esm/artifacts/objectStore.js +252 -0
- package/dist/esm/artifacts/objectStore.js.map +1 -0
- package/dist/esm/artifacts/payload.d.ts +36 -4
- package/dist/esm/artifacts/payload.js +38 -1
- package/dist/esm/artifacts/payload.js.map +1 -1
- package/dist/esm/artifacts/recordingArtifact.d.ts +76 -0
- package/dist/esm/artifacts/recordingArtifact.js +83 -0
- package/dist/esm/artifacts/recordingArtifact.js.map +1 -0
- package/dist/esm/artifacts/s3Artifacts.d.ts +149 -0
- package/dist/esm/artifacts/s3Artifacts.js +538 -0
- package/dist/esm/artifacts/s3Artifacts.js.map +1 -0
- package/dist/esm/artifacts/scopePath.d.ts +50 -0
- package/dist/esm/artifacts/scopePath.js +80 -0
- package/dist/esm/artifacts/scopePath.js.map +1 -0
- package/dist/esm/artifacts/streaming.d.ts +82 -0
- package/dist/esm/artifacts/streaming.js +123 -0
- package/dist/esm/artifacts/streaming.js.map +1 -0
- package/dist/esm/artifacts/types.d.ts +71 -5
- package/dist/esm/artifacts/types.js +10 -2
- package/dist/esm/artifacts/types.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +66 -2
- package/dist/esm/core/Agent.js +176 -0
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.js +20 -0
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/repeatedCall.d.ts +150 -0
- package/dist/esm/core/agent/repeatedCall.js +184 -0
- package/dist/esm/core/agent/repeatedCall.js.map +1 -0
- package/dist/esm/core/agent/stages/toolCalls.d.ts +12 -0
- package/dist/esm/core/agent/stages/toolCalls.js +50 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +82 -0
- package/dist/esm/core/codeRunnerTool.d.ts +31 -0
- package/dist/esm/core/codeRunnerTool.js +149 -12
- package/dist/esm/core/codeRunnerTool.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +22 -0
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/hosting/admission.d.ts +180 -0
- package/dist/esm/hosting/admission.js +188 -0
- package/dist/esm/hosting/admission.js.map +1 -0
- package/dist/esm/hosting/artifactWire.d.ts +8 -5
- package/dist/esm/hosting/artifactWire.js +14 -9
- package/dist/esm/hosting/artifactWire.js.map +1 -1
- package/dist/esm/hosting/envelope.d.ts +34 -0
- package/dist/esm/hosting/envelope.js +81 -0
- package/dist/esm/hosting/envelope.js.map +1 -1
- package/dist/esm/hosting/errors.d.ts +131 -0
- package/dist/esm/hosting/errors.js +195 -0
- package/dist/esm/hosting/errors.js.map +1 -1
- package/dist/esm/hosting/httpHost.d.ts +21 -0
- package/dist/esm/hosting/httpHost.js +44 -2
- package/dist/esm/hosting/httpHost.js.map +1 -1
- package/dist/esm/hosting/identityVerification.d.ts +154 -0
- package/dist/esm/hosting/identityVerification.js +135 -0
- package/dist/esm/hosting/identityVerification.js.map +1 -0
- package/dist/esm/hosting/index.d.ts +12 -3
- package/dist/esm/hosting/index.js +16 -2
- package/dist/esm/hosting/index.js.map +1 -1
- package/dist/esm/hosting/memorySessions.d.ts +9 -0
- package/dist/esm/hosting/memorySessions.js +86 -0
- package/dist/esm/hosting/memorySessions.js.map +1 -1
- package/dist/esm/hosting/nodeHost.js +8 -0
- package/dist/esm/hosting/nodeHost.js.map +1 -1
- package/dist/esm/hosting/sessionWire.d.ts +126 -0
- package/dist/esm/hosting/sessionWire.js +95 -0
- package/dist/esm/hosting/sessionWire.js.map +1 -0
- package/dist/esm/hosting/sqliteSessions.js +122 -5
- package/dist/esm/hosting/sqliteSessions.js.map +1 -1
- package/dist/esm/hosting/standingAgent.js +299 -8
- package/dist/esm/hosting/standingAgent.js.map +1 -1
- package/dist/esm/hosting/types.d.ts +166 -6
- package/dist/esm/hosting/types.js.map +1 -1
- package/dist/esm/hosting/wireOps.d.ts +52 -0
- package/dist/esm/hosting/wireOps.js +60 -0
- package/dist/esm/hosting/wireOps.js.map +1 -0
- package/dist/esm/identity.d.ts +1 -0
- package/dist/esm/identity.js +6 -0
- package/dist/esm/identity.js.map +1 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +10 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/factories/defineSkill.d.ts +27 -0
- package/dist/esm/lib/injection-engine/factories/defineSkill.js +13 -0
- package/dist/esm/lib/injection-engine/factories/defineSkill.js.map +1 -1
- package/dist/esm/lib/injection-engine/index.d.ts +1 -0
- package/dist/esm/lib/injection-engine/index.js +7 -0
- package/dist/esm/lib/injection-engine/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraph.js +9 -1
- package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraphCheckup.d.ts +1 -1
- package/dist/esm/lib/injection-engine/skillGraphCheckup.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillSteps.d.ts +16 -0
- package/dist/esm/lib/injection-engine/skillSteps.js +5 -0
- package/dist/esm/lib/injection-engine/skillSteps.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillVocabulary.d.ts +83 -0
- package/dist/esm/lib/injection-engine/skillVocabulary.js +218 -0
- package/dist/esm/lib/injection-engine/skillVocabulary.js.map +1 -0
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/hosting/admission.js +194 -0
- package/dist/hosting/admission.js.map +1 -0
- package/dist/hosting/artifactWire.js +14 -9
- package/dist/hosting/artifactWire.js.map +1 -1
- package/dist/hosting/envelope.js +84 -1
- package/dist/hosting/envelope.js.map +1 -1
- package/dist/hosting/errors.js +203 -1
- package/dist/hosting/errors.js.map +1 -1
- package/dist/hosting/httpHost.js +43 -1
- package/dist/hosting/httpHost.js.map +1 -1
- package/dist/hosting/identityVerification.js +140 -0
- package/dist/hosting/identityVerification.js.map +1 -0
- package/dist/hosting/index.js +38 -1
- package/dist/hosting/index.js.map +1 -1
- package/dist/hosting/memorySessions.js +86 -0
- package/dist/hosting/memorySessions.js.map +1 -1
- package/dist/hosting/nodeHost.js +8 -0
- package/dist/hosting/nodeHost.js.map +1 -1
- package/dist/hosting/sessionWire.js +100 -0
- package/dist/hosting/sessionWire.js.map +1 -0
- package/dist/hosting/sqliteSessions.js +121 -4
- package/dist/hosting/sqliteSessions.js.map +1 -1
- package/dist/hosting/standingAgent.js +297 -6
- package/dist/hosting/standingAgent.js.map +1 -1
- package/dist/hosting/types.js.map +1 -1
- package/dist/hosting/wireOps.js +65 -0
- package/dist/hosting/wireOps.js.map +1 -0
- package/dist/identity.js +9 -1
- package/dist/identity.js.map +1 -1
- package/dist/index.js +30 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/injection-engine/factories/defineSkill.js +13 -0
- package/dist/lib/injection-engine/factories/defineSkill.js.map +1 -1
- package/dist/lib/injection-engine/index.js +10 -1
- package/dist/lib/injection-engine/index.js.map +1 -1
- package/dist/lib/injection-engine/skillGraph.js +9 -1
- package/dist/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/lib/injection-engine/skillGraphCheckup.js.map +1 -1
- package/dist/lib/injection-engine/skillSteps.js +5 -0
- package/dist/lib/injection-engine/skillSteps.js.map +1 -1
- package/dist/lib/injection-engine/skillVocabulary.js +224 -0
- package/dist/lib/injection-engine/skillVocabulary.js.map +1 -0
- package/dist/types/adapters/code/local.d.ts +16 -0
- package/dist/types/adapters/code/local.d.ts.map +1 -1
- package/dist/types/adapters/hosting/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/identity/jwks.d.ts +125 -0
- package/dist/types/adapters/identity/jwks.d.ts.map +1 -0
- package/dist/types/adapters/types.d.ts +86 -0
- package/dist/types/adapters/types.d.ts.map +1 -1
- package/dist/types/artifacts/fileArtifacts.d.ts +13 -1
- package/dist/types/artifacts/fileArtifacts.d.ts.map +1 -1
- package/dist/types/artifacts/gcsArtifacts.d.ts +143 -0
- package/dist/types/artifacts/gcsArtifacts.d.ts.map +1 -0
- package/dist/types/artifacts/index.d.ts +5 -1
- package/dist/types/artifacts/index.d.ts.map +1 -1
- package/dist/types/artifacts/objectStore.d.ts +167 -0
- package/dist/types/artifacts/objectStore.d.ts.map +1 -0
- package/dist/types/artifacts/payload.d.ts +36 -4
- package/dist/types/artifacts/payload.d.ts.map +1 -1
- package/dist/types/artifacts/recordingArtifact.d.ts +77 -0
- package/dist/types/artifacts/recordingArtifact.d.ts.map +1 -0
- package/dist/types/artifacts/s3Artifacts.d.ts +150 -0
- package/dist/types/artifacts/s3Artifacts.d.ts.map +1 -0
- package/dist/types/artifacts/scopePath.d.ts +51 -0
- package/dist/types/artifacts/scopePath.d.ts.map +1 -0
- package/dist/types/artifacts/streaming.d.ts +83 -0
- package/dist/types/artifacts/streaming.d.ts.map +1 -0
- package/dist/types/artifacts/types.d.ts +71 -5
- package/dist/types/artifacts/types.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +66 -2
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/repeatedCall.d.ts +151 -0
- package/dist/types/core/agent/repeatedCall.d.ts.map +1 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts +12 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +82 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/codeRunnerTool.d.ts +31 -0
- package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +22 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/hosting/admission.d.ts +181 -0
- package/dist/types/hosting/admission.d.ts.map +1 -0
- package/dist/types/hosting/artifactWire.d.ts +8 -5
- package/dist/types/hosting/artifactWire.d.ts.map +1 -1
- package/dist/types/hosting/envelope.d.ts +34 -0
- package/dist/types/hosting/envelope.d.ts.map +1 -1
- package/dist/types/hosting/errors.d.ts +131 -0
- package/dist/types/hosting/errors.d.ts.map +1 -1
- package/dist/types/hosting/httpHost.d.ts +21 -0
- package/dist/types/hosting/httpHost.d.ts.map +1 -1
- package/dist/types/hosting/identityVerification.d.ts +155 -0
- package/dist/types/hosting/identityVerification.d.ts.map +1 -0
- package/dist/types/hosting/index.d.ts +12 -3
- package/dist/types/hosting/index.d.ts.map +1 -1
- package/dist/types/hosting/memorySessions.d.ts +9 -0
- package/dist/types/hosting/memorySessions.d.ts.map +1 -1
- package/dist/types/hosting/nodeHost.d.ts.map +1 -1
- package/dist/types/hosting/sessionWire.d.ts +127 -0
- package/dist/types/hosting/sessionWire.d.ts.map +1 -0
- package/dist/types/hosting/sqliteSessions.d.ts.map +1 -1
- package/dist/types/hosting/standingAgent.d.ts.map +1 -1
- package/dist/types/hosting/types.d.ts +166 -6
- package/dist/types/hosting/types.d.ts.map +1 -1
- package/dist/types/hosting/wireOps.d.ts +53 -0
- package/dist/types/hosting/wireOps.d.ts.map +1 -0
- package/dist/types/identity.d.ts +1 -0
- package/dist/types/identity.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/factories/defineSkill.d.ts +27 -0
- package/dist/types/lib/injection-engine/factories/defineSkill.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/index.d.ts +1 -0
- package/dist/types/lib/injection-engine/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraphCheckup.d.ts +1 -1
- package/dist/types/lib/injection-engine/skillGraphCheckup.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillSteps.d.ts +16 -0
- package/dist/types/lib/injection-engine/skillSteps.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillVocabulary.d.ts +84 -0
- package/dist/types/lib/injection-engine/skillVocabulary.d.ts.map +1 -0
- package/package.json +15 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* core/agent/repeatedCall — tell a model when it has already asked this.
|
|
4
|
+
*
|
|
5
|
+
* ── The measured failure ────────────────────────────────────────────────────
|
|
6
|
+
* A traced production run: the model called one tool three times in a row with
|
|
7
|
+
* byte-identical arguments and got a byte-identical result each time. The tool
|
|
8
|
+
* was doing its job — the arguments named a filter the backend did not honour,
|
|
9
|
+
* so the same rows came back — and the model read the same rows as a fresh
|
|
10
|
+
* answer each iteration, concluded nothing had changed, and tried again. Three
|
|
11
|
+
* calls, three identical results, one wasted turn, and nothing anywhere in the
|
|
12
|
+
* loop that could say "you have done this".
|
|
13
|
+
*
|
|
14
|
+
* That class of loop is invisible from inside the conversation, because the
|
|
15
|
+
* history genuinely does show three separate calls that each returned data. The
|
|
16
|
+
* only party with the whole picture is the framework, which watched all three
|
|
17
|
+
* land.
|
|
18
|
+
*
|
|
19
|
+
* ── The intervention: a NOTE, never a refusal ───────────────────────────────
|
|
20
|
+
* On the Nth identical (tool, args) → identical result, the framework appends
|
|
21
|
+
* one sentence to that result. It does not block the call, does not change the
|
|
22
|
+
* result, does not error, and does not stop a later identical call from
|
|
23
|
+
* running. That restraint is the design:
|
|
24
|
+
*
|
|
25
|
+
* • **A repeat is sometimes correct.** Polling a job until its status
|
|
26
|
+
* changes is a loop of identical calls returning identical results, on
|
|
27
|
+
* purpose. Refusing it would break a legitimate pattern to fix an
|
|
28
|
+
* illegitimate one, and the model is the only party that knows which it is
|
|
29
|
+
* doing.
|
|
30
|
+
* • **A note is evidence; a refusal is a wall.** The model reads what
|
|
31
|
+
* happened and decides. That is the same posture every teaching refusal in
|
|
32
|
+
* this library takes, minus the refusal.
|
|
33
|
+
*
|
|
34
|
+
* ── Why the result must match too ───────────────────────────────────────────
|
|
35
|
+
* Identical ARGUMENTS alone are not evidence of anything: a "check status" call
|
|
36
|
+
* with the same arguments returning a DIFFERENT status is progress. It is the
|
|
37
|
+
* identical RESULT that makes the repeat pointless, so both halves are
|
|
38
|
+
* required. Which also means the note can say something true and specific —
|
|
39
|
+
* *calling again will not change it* — rather than a vague "you seem to be
|
|
40
|
+
* repeating yourself".
|
|
41
|
+
*
|
|
42
|
+
* ── What is stored, and what is deliberately not ────────────────────────────
|
|
43
|
+
* A short non-cryptographic FINGERPRINT of the arguments and the result, never
|
|
44
|
+
* the values. Tool arguments routinely carry the things redaction exists for,
|
|
45
|
+
* and a fingerprint answers the only question this feature asks ("is this the
|
|
46
|
+
* same?") and answers nothing else.
|
|
47
|
+
*
|
|
48
|
+
* ── And WHERE it is stored: beside the run, never inside its state ──────────
|
|
49
|
+
* The counters live in {@link repeatedCallLedgers}, a run-keyed map the
|
|
50
|
+
* dispatch loop holds — NOT on tracked scope. That is not a tidiness
|
|
51
|
+
* preference, it is the zero-cost law:
|
|
52
|
+
*
|
|
53
|
+
* • Tracked scope IS the commit log, the snapshot, the narrative, every
|
|
54
|
+
* recording and every causal slice. A key written there on every tool
|
|
55
|
+
* landing would appear in all of them for every existing agent the moment
|
|
56
|
+
* it upgraded — a turn that never repeated anything would no longer be
|
|
57
|
+
* byte-identical to the release before, and a consumer asserting a state-key
|
|
58
|
+
* set would break for a feature it never asked for.
|
|
59
|
+
* • A within-turn counter is not conversation state. Nothing resumes from it,
|
|
60
|
+
* nothing branches on it later, and no reader of a trace needs it: the
|
|
61
|
+
* repeat itself lands on the record as `agentfootprint.tools.repeated_call`,
|
|
62
|
+
* which is the telemetry channel this library puts per-attempt facts on
|
|
63
|
+
* (the same reasoning as retries and streaming tokens, and the same
|
|
64
|
+
* reasoning that keeps a consent record off tracked state).
|
|
65
|
+
*
|
|
66
|
+
* So an agent that never repeats a call is byte-identical to 9.25 in behaviour,
|
|
67
|
+
* in state AND in events — the ledger exists only in memory, only for the
|
|
68
|
+
* duration of a run, and only where a tool actually landed.
|
|
69
|
+
*/
|
|
70
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
71
|
+
exports.noteRepeatedCall = exports.repeatedCallKey = exports.repeatedCallLedgers = exports.REPEATED_CALL_THRESHOLD = void 0;
|
|
72
|
+
/** How many identical (tool, args, result) landings trigger the note. The
|
|
73
|
+
* SECOND one: the first repeat is the first moment the fact exists. */
|
|
74
|
+
exports.REPEATED_CALL_THRESHOLD = 2;
|
|
75
|
+
/** How many runs' counters one dispatch loop keeps at once. Small on purpose:
|
|
76
|
+
* concurrent runs on ONE agent instance are the only reason for more than
|
|
77
|
+
* one, and a deployment serving many callers at once gives each its own
|
|
78
|
+
* agent (that is what `agentFactory` is for). */
|
|
79
|
+
const LEDGER_RUNS = 8;
|
|
80
|
+
/** Build the run-keyed holder. One per agent — the chart is built once, so the
|
|
81
|
+
* loop that owns this is built once too. */
|
|
82
|
+
function repeatedCallLedgers(maxRuns = LEDGER_RUNS) {
|
|
83
|
+
const byRun = new Map();
|
|
84
|
+
return {
|
|
85
|
+
read: (runId) => byRun.get(runId),
|
|
86
|
+
write: (runId, ledger) => {
|
|
87
|
+
// Delete-then-set makes insertion order recency order, which is what the
|
|
88
|
+
// eviction below reads.
|
|
89
|
+
byRun.delete(runId);
|
|
90
|
+
byRun.set(runId, ledger);
|
|
91
|
+
while (byRun.size > maxRuns) {
|
|
92
|
+
const oldest = byRun.keys().next();
|
|
93
|
+
if (oldest.done === true)
|
|
94
|
+
break;
|
|
95
|
+
byRun.delete(oldest.value);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
exports.repeatedCallLedgers = repeatedCallLedgers;
|
|
101
|
+
/**
|
|
102
|
+
* A stable, order-insensitive fingerprint of one call.
|
|
103
|
+
*
|
|
104
|
+
* Object keys are SORTED before hashing, at every depth: `{ a: 1, b: 2 }` and
|
|
105
|
+
* `{ b: 2, a: 1 }` are the same call, and a model that happens to emit its JSON
|
|
106
|
+
* in a different key order twice is repeating itself just as surely. Arrays
|
|
107
|
+
* keep their order, because `[1, 2]` and `[2, 1]` are not the same argument.
|
|
108
|
+
*/
|
|
109
|
+
function stableString(value) {
|
|
110
|
+
if (value === null || typeof value !== 'object')
|
|
111
|
+
return JSON.stringify(value) ?? 'undefined';
|
|
112
|
+
if (Array.isArray(value))
|
|
113
|
+
return `[${value.map(stableString).join(',')}]`;
|
|
114
|
+
const entries = Object.entries(value)
|
|
115
|
+
.filter(([, v]) => v !== undefined)
|
|
116
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
117
|
+
return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableString(v)}`).join(',')}}`;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* FNV-1a, 32-bit, as 8 hex characters.
|
|
121
|
+
*
|
|
122
|
+
* Non-cryptographic ON PURPOSE and stated as such: this compares a string to
|
|
123
|
+
* ITSELF a few iterations later inside one run, where an adversary has nothing
|
|
124
|
+
* to gain from a collision and the cost of `crypto.subtle` (async, and one
|
|
125
|
+
* digest per tool result) buys nothing. A collision produces one unnecessary
|
|
126
|
+
* teaching note, which is the cheapest possible failure this could have.
|
|
127
|
+
*/
|
|
128
|
+
function fingerprint(text) {
|
|
129
|
+
let hash = 0x811c9dc5;
|
|
130
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
131
|
+
hash ^= text.charCodeAt(i);
|
|
132
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
133
|
+
}
|
|
134
|
+
return hash.toString(16).padStart(8, '0');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The two fingerprints for one landing, and the ledger key that joins them.
|
|
138
|
+
*
|
|
139
|
+
* Kept apart on the way out so a debugger reading the event can tell "same
|
|
140
|
+
* call, different answer" from "same call, same answer" — without either value
|
|
141
|
+
* being present anywhere.
|
|
142
|
+
*/
|
|
143
|
+
function repeatedCallKey(toolName, args, result) {
|
|
144
|
+
const argsFingerprint = fingerprint(stableString(args));
|
|
145
|
+
const resultFingerprint = fingerprint(result);
|
|
146
|
+
return {
|
|
147
|
+
key: `${toolName}:${argsFingerprint}:${resultFingerprint}`,
|
|
148
|
+
argsFingerprint,
|
|
149
|
+
resultFingerprint,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
exports.repeatedCallKey = repeatedCallKey;
|
|
153
|
+
/**
|
|
154
|
+
* The teaching sentence.
|
|
155
|
+
*
|
|
156
|
+
* It says three things, in the order the model needs them: what happened (the
|
|
157
|
+
* fact it cannot see), what follows from it (calling again is not going to
|
|
158
|
+
* help), and what to do instead (two named options, neither of which is "stop"
|
|
159
|
+
* — a model told only to stop tends to stop answering).
|
|
160
|
+
*/
|
|
161
|
+
function noteFor(toolName, occurrences) {
|
|
162
|
+
return (`\n\n[identical call: '${toolName}' has now returned exactly this result ${occurrences} ` +
|
|
163
|
+
`times this turn, for exactly these arguments. Calling it again will not change it — ` +
|
|
164
|
+
`act on what you have, or change the arguments (a different filter, a wider range, a ` +
|
|
165
|
+
`different tool). If you are waiting for something to change, say so in your answer ` +
|
|
166
|
+
`rather than calling again.]`);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Record one landing and decide whether it earns the note.
|
|
170
|
+
*
|
|
171
|
+
* PURE — takes the ledger, returns the next one. The dispatch loop owns reading
|
|
172
|
+
* and writing scope, so this file never imports the agent and can be tested as
|
|
173
|
+
* a table.
|
|
174
|
+
*
|
|
175
|
+
* The note fires ONCE per distinct call, on the Nth landing exactly. A third
|
|
176
|
+
* and fourth identical call add nothing further: the model has been told, and
|
|
177
|
+
* repeating the lesson every iteration would be the framework doing the very
|
|
178
|
+
* thing it is complaining about.
|
|
179
|
+
*/
|
|
180
|
+
function noteRepeatedCall(ledger, toolName, args, result) {
|
|
181
|
+
const { key, argsFingerprint, resultFingerprint } = repeatedCallKey(toolName, args, result);
|
|
182
|
+
const occurrences = (ledger?.[key] ?? 0) + 1;
|
|
183
|
+
const next = { ...(ledger ?? {}), [key]: occurrences };
|
|
184
|
+
const outcome = { ledger: next, occurrences, argsFingerprint, resultFingerprint };
|
|
185
|
+
if (occurrences !== exports.REPEATED_CALL_THRESHOLD)
|
|
186
|
+
return outcome;
|
|
187
|
+
return { ...outcome, note: noteFor(toolName, occurrences) };
|
|
188
|
+
}
|
|
189
|
+
exports.noteRepeatedCall = noteRepeatedCall;
|
|
190
|
+
//# sourceMappingURL=repeatedCall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repeatedCall.js","sourceRoot":"","sources":["../../../src/core/agent/repeatedCall.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;;;AAEH;wEACwE;AAC3D,QAAA,uBAAuB,GAAG,CAAC,CAAC;AAyCzC;;;kDAGkD;AAClD,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB;6CAC6C;AAC7C,SAAgB,mBAAmB,CAAC,UAAkB,WAAW;IAC/D,MAAM,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAC;IACpD,OAAO;QACL,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;QACjC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACvB,yEAAyE;YACzE,wBAAwB;YACxB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACzB,OAAO,KAAK,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC;gBAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;oBAAE,MAAM;gBAChC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAhBD,kDAgBC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC;IAC7F,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1E,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;SAC7D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;SAClC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC7F,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,eAAe,CAC7B,QAAgB,EAChB,IAAa,EACb,MAAc;IAEd,MAAM,eAAe,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,iBAAiB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO;QACL,GAAG,EAAE,GAAG,QAAQ,IAAI,eAAe,IAAI,iBAAiB,EAAE;QAC1D,eAAe;QACf,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAZD,0CAYC;AAiBD;;;;;;;GAOG;AACH,SAAS,OAAO,CAAC,QAAgB,EAAE,WAAmB;IACpD,OAAO,CACL,yBAAyB,QAAQ,0CAA0C,WAAW,GAAG;QACzF,sFAAsF;QACtF,sFAAsF;QACtF,qFAAqF;QACrF,6BAA6B,CAC9B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,gBAAgB,CAC9B,MAAsC,EACtC,QAAgB,EAChB,IAAa,EACb,MAAc;IAEd,MAAM,EAAE,GAAG,EAAE,eAAe,EAAE,iBAAiB,EAAE,GAAG,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5F,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAuB,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3E,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;IAClF,IAAI,WAAW,KAAK,+BAAuB;QAAE,OAAO,OAAO,CAAC;IAC5D,OAAO,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC;AAC9D,CAAC;AAZD,4CAYC"}
|
|
@@ -62,6 +62,7 @@ const askComponent_js_1 = require("../../askComponent.js");
|
|
|
62
62
|
const checkin_js_1 = require("../../checkin.js");
|
|
63
63
|
const runChain_js_1 = require("../middleware/runChain.js");
|
|
64
64
|
const ledger_js_1 = require("../middleware/ledger.js");
|
|
65
|
+
const repeatedCall_js_1 = require("../repeatedCall.js");
|
|
65
66
|
const toolArgsValidation_js_1 = require("../toolArgsValidation.js");
|
|
66
67
|
const validators_js_1 = require("../validators.js");
|
|
67
68
|
const toolResultCap_js_1 = require("../toolResultCap.js");
|
|
@@ -222,6 +223,17 @@ function argsForPausedCall(scope, toolCallId) {
|
|
|
222
223
|
function appendBatchResult(scope, entry) {
|
|
223
224
|
scope.toolResults = [...(scope.toolResults ?? []), entry];
|
|
224
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* The ledger key for a handler built with no `currentRun` accessor — a
|
|
228
|
+
* hand-composed dispatch loop in a test, never an Agent (which always wires
|
|
229
|
+
* it).
|
|
230
|
+
*
|
|
231
|
+
* One shared bucket, stated rather than hidden: without a run id there is
|
|
232
|
+
* nothing to tell two runs apart by, and the honest consequence is that such a
|
|
233
|
+
* loop counts across them. It cannot leak anything — the ledger holds
|
|
234
|
+
* fingerprints — and the only visible effect is a note arriving one call early.
|
|
235
|
+
*/
|
|
236
|
+
const UNSCOPED_RUN = '#no-run-id';
|
|
225
237
|
function buildToolCallsHandler(deps) {
|
|
226
238
|
const { registryByName, externalToolProvider, providerToolCache, permissionChecker } = deps;
|
|
227
239
|
const toolArgValidation = deps.toolArgValidation ?? 'enforce';
|
|
@@ -232,6 +244,10 @@ function buildToolCallsHandler(deps) {
|
|
|
232
244
|
// that THROWS on use (never undefined) — so a tool can't silently no-op.
|
|
233
245
|
const credentials = deps.credentialProvider ?? (0, types_js_2.unconfiguredCredentialProvider)();
|
|
234
246
|
const hasCredentials = deps.credentialProvider !== undefined;
|
|
247
|
+
// The repeated-call counters (9.26.0), run-keyed and OFF tracked scope — an
|
|
248
|
+
// empty Map here, and not one byte written anywhere a reader can see until a
|
|
249
|
+
// tool actually lands. See `../repeatedCall.ts` for why they are not state.
|
|
250
|
+
const repeatLedgers = (0, repeatedCall_js_1.repeatedCallLedgers)();
|
|
235
251
|
/**
|
|
236
252
|
* The tool-result ceiling, applied at the ONE place a result leaves dispatch.
|
|
237
253
|
*
|
|
@@ -2035,6 +2051,11 @@ function buildToolCallsHandler(deps) {
|
|
|
2035
2051
|
...(toolStatus !== undefined && { status: toolStatus }),
|
|
2036
2052
|
});
|
|
2037
2053
|
let resultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
|
|
2054
|
+
// The tool's OWN answer, before any framework suffix joins it — what
|
|
2055
|
+
// the repeated-call ledger fingerprints. Fingerprinting the decorated
|
|
2056
|
+
// string instead would compare our own additions (a step that advanced
|
|
2057
|
+
// once, an effect note) and miss the repeat they decorate.
|
|
2058
|
+
const deliveredResult = resultStr;
|
|
2038
2059
|
// ── Step boundary (9.18.0): advance decided, then decorate, THEN
|
|
2039
2060
|
// push — the suffix must be part of the one past every reader sees
|
|
2040
2061
|
// (history, `lastToolResult`, the batch), never spliced in later.
|
|
@@ -2071,6 +2092,35 @@ function buildToolCallsHandler(deps) {
|
|
|
2071
2092
|
if (toolEnvelope !== undefined && executed && !error && !denied) {
|
|
2072
2093
|
resultStr += applyToolEffects(scope, { toolName: tc.name, toolCallId: tc.id, iteration }, toolEnvelope, transitionState);
|
|
2073
2094
|
}
|
|
2095
|
+
// ── Repeated-call nudge (9.26.0) ───────────────────────────────
|
|
2096
|
+
// The framework is the only party that watched all three landings, so
|
|
2097
|
+
// it is the only one that can say so. A NOTE on the result — the call
|
|
2098
|
+
// ran, nothing was refused, and a later identical call is not blocked.
|
|
2099
|
+
// Only for a call that RAN: a permission denial, a gate rejection and
|
|
2100
|
+
// a ceiling refusal each already teach their own lesson, and stacking
|
|
2101
|
+
// a second one would bury it.
|
|
2102
|
+
if (deps.repeatedCallNudge !== false && executed && !denied && !skillRejected) {
|
|
2103
|
+
// Counted beside the run, never inside its state: a tracked write is
|
|
2104
|
+
// a commit-log entry, a snapshot key, a narrative line and a row in
|
|
2105
|
+
// every recording, and a turn that repeats NOTHING must stay
|
|
2106
|
+
// byte-identical to the release before this one. `currentRun()` is
|
|
2107
|
+
// the same accessor `ctx.runId` is composed from — one answer to
|
|
2108
|
+
// "which run is this", not a second spelling of it.
|
|
2109
|
+
const runKey = deps.currentRun?.().runId ?? UNSCOPED_RUN;
|
|
2110
|
+
const repeat = (0, repeatedCall_js_1.noteRepeatedCall)(repeatLedgers.read(runKey), tc.name, callArgs, deliveredResult);
|
|
2111
|
+
repeatLedgers.write(runKey, repeat.ledger);
|
|
2112
|
+
if (repeat.note !== undefined) {
|
|
2113
|
+
resultStr += repeat.note;
|
|
2114
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.tools.repeated_call', {
|
|
2115
|
+
toolName: tc.name,
|
|
2116
|
+
toolCallId: tc.id,
|
|
2117
|
+
iteration,
|
|
2118
|
+
occurrences: repeat.occurrences,
|
|
2119
|
+
argsFingerprint: repeat.argsFingerprint,
|
|
2120
|
+
resultFingerprint: repeat.resultFingerprint,
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2074
2124
|
newHistory.push({
|
|
2075
2125
|
role: 'tool',
|
|
2076
2126
|
content: resultStr,
|