agentfootprint 2.4.0 → 2.5.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 +21 -3
- package/dist/adapters/llm/AnthropicProvider.js +2 -2
- package/dist/adapters/llm/AnthropicProvider.js.map +1 -1
- package/dist/adapters/llm/BedrockProvider.js +2 -2
- package/dist/adapters/llm/BedrockProvider.js.map +1 -1
- package/dist/adapters/llm/BrowserAnthropicProvider.js +96 -28
- package/dist/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
- package/dist/adapters/llm/OpenAIProvider.js +2 -2
- package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/adapters/memory/agentcore.js +9 -3
- package/dist/adapters/memory/agentcore.js.map +1 -1
- package/dist/adapters/memory/redis.js +9 -3
- package/dist/adapters/memory/redis.js.map +1 -1
- package/dist/core/Agent.js +477 -79
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/flowchartAsTool.js +188 -0
- package/dist/core/flowchartAsTool.js.map +1 -0
- package/dist/core/outputSchema.js +119 -0
- package/dist/core/outputSchema.js.map +1 -0
- package/dist/core/slots/buildSystemPromptSlot.js +8 -0
- package/dist/core/slots/buildSystemPromptSlot.js.map +1 -1
- package/dist/core/slots/buildToolsSlot.js +56 -5
- package/dist/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/adapters/llm/AnthropicProvider.js +2 -2
- package/dist/esm/adapters/llm/AnthropicProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BedrockProvider.js +2 -2
- package/dist/esm/adapters/llm/BedrockProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.js +96 -28
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
- package/dist/esm/adapters/llm/OpenAIProvider.js +2 -2
- package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/memory/agentcore.js +9 -3
- package/dist/esm/adapters/memory/agentcore.js.map +1 -1
- package/dist/esm/adapters/memory/redis.js +9 -3
- package/dist/esm/adapters/memory/redis.js.map +1 -1
- package/dist/esm/core/Agent.js +476 -78
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/flowchartAsTool.js +184 -0
- package/dist/esm/core/flowchartAsTool.js.map +1 -0
- package/dist/esm/core/outputSchema.js +113 -0
- package/dist/esm/core/outputSchema.js.map +1 -0
- package/dist/esm/core/slots/buildSystemPromptSlot.js +8 -0
- package/dist/esm/core/slots/buildSystemPromptSlot.js.map +1 -1
- package/dist/esm/core/slots/buildToolsSlot.js +56 -5
- package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/index.js +34 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/SkillRegistry.js +98 -0
- package/dist/esm/lib/injection-engine/SkillRegistry.js.map +1 -1
- package/dist/esm/lib/injection-engine/factories/defineSkill.js +1 -0
- package/dist/esm/lib/injection-engine/factories/defineSkill.js.map +1 -1
- 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/skillTools.js +125 -0
- package/dist/esm/lib/injection-engine/skillTools.js.map +1 -0
- package/dist/esm/lib/injection-engine/types.js +8 -0
- package/dist/esm/lib/injection-engine/types.js.map +1 -1
- package/dist/esm/lib/lazyRequire.js +33 -0
- package/dist/esm/lib/lazyRequire.js.map +1 -0
- package/dist/esm/lib/mcp/mcpClient.js +4 -6
- package/dist/esm/lib/mcp/mcpClient.js.map +1 -1
- package/dist/esm/llm-providers.js +31 -0
- package/dist/esm/llm-providers.js.map +1 -0
- package/dist/esm/locales/index.js +144 -0
- package/dist/esm/locales/index.js.map +1 -0
- package/dist/esm/memory-providers.js +44 -0
- package/dist/esm/memory-providers.js.map +1 -0
- package/dist/esm/providers.js +11 -0
- package/dist/esm/providers.js.map +1 -1
- package/dist/esm/recorders/core/contextEngineering.js +155 -0
- package/dist/esm/recorders/core/contextEngineering.js.map +1 -0
- package/dist/esm/recorders/observability/commentary/commentaryTemplates.js +6 -1
- package/dist/esm/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
- package/dist/esm/security/PermissionPolicy.js +135 -0
- package/dist/esm/security/PermissionPolicy.js.map +1 -0
- package/dist/esm/security/index.js +38 -0
- package/dist/esm/security/index.js.map +1 -0
- package/dist/esm/tool-providers/gatedTools.js +52 -0
- package/dist/esm/tool-providers/gatedTools.js.map +1 -0
- package/dist/esm/tool-providers/index.js +43 -0
- package/dist/esm/tool-providers/index.js.map +1 -0
- package/dist/esm/tool-providers/skillScopedTools.js +63 -0
- package/dist/esm/tool-providers/skillScopedTools.js.map +1 -0
- package/dist/esm/tool-providers/staticTools.js +33 -0
- package/dist/esm/tool-providers/staticTools.js.map +1 -0
- package/dist/esm/tool-providers/types.js +53 -0
- package/dist/esm/tool-providers/types.js.map +1 -0
- package/dist/index.js +55 -12
- package/dist/index.js.map +1 -1
- package/dist/lib/injection-engine/SkillRegistry.js +98 -0
- package/dist/lib/injection-engine/SkillRegistry.js.map +1 -1
- package/dist/lib/injection-engine/factories/defineSkill.js +1 -0
- package/dist/lib/injection-engine/factories/defineSkill.js.map +1 -1
- package/dist/lib/injection-engine/index.js +11 -1
- package/dist/lib/injection-engine/index.js.map +1 -1
- package/dist/lib/injection-engine/skillTools.js +130 -0
- package/dist/lib/injection-engine/skillTools.js.map +1 -0
- package/dist/lib/injection-engine/types.js +8 -0
- package/dist/lib/injection-engine/types.js.map +1 -1
- package/dist/lib/lazyRequire.js +37 -0
- package/dist/lib/lazyRequire.js.map +1 -0
- package/dist/lib/mcp/mcpClient.js +4 -6
- package/dist/lib/mcp/mcpClient.js.map +1 -1
- package/dist/llm-providers.js +47 -0
- package/dist/llm-providers.js.map +1 -0
- package/dist/locales/index.js +149 -0
- package/dist/locales/index.js.map +1 -0
- package/dist/memory-providers.js +49 -0
- package/dist/memory-providers.js.map +1 -0
- package/dist/providers.js +11 -0
- package/dist/providers.js.map +1 -1
- package/dist/recorders/core/contextEngineering.js +161 -0
- package/dist/recorders/core/contextEngineering.js.map +1 -0
- package/dist/recorders/observability/commentary/commentaryTemplates.js +6 -1
- package/dist/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
- package/dist/security/PermissionPolicy.js +139 -0
- package/dist/security/PermissionPolicy.js.map +1 -0
- package/dist/security/index.js +42 -0
- package/dist/security/index.js.map +1 -0
- package/dist/tool-providers/gatedTools.js +56 -0
- package/dist/tool-providers/gatedTools.js.map +1 -0
- package/dist/tool-providers/index.js +51 -0
- package/dist/tool-providers/index.js.map +1 -0
- package/dist/tool-providers/skillScopedTools.js +67 -0
- package/dist/tool-providers/skillScopedTools.js.map +1 -0
- package/dist/tool-providers/staticTools.js +37 -0
- package/dist/tool-providers/staticTools.js.map +1 -0
- package/dist/tool-providers/types.js +54 -0
- package/dist/tool-providers/types.js.map +1 -0
- package/dist/types/adapters/llm/AnthropicProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BedrockProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BrowserAnthropicProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/memory/agentcore.d.ts +7 -1
- package/dist/types/adapters/memory/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/memory/redis.d.ts +7 -1
- package/dist/types/adapters/memory/redis.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +202 -2
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/flowchartAsTool.d.ts +161 -0
- package/dist/types/core/flowchartAsTool.d.ts.map +1 -0
- package/dist/types/core/outputSchema.d.ts +128 -0
- package/dist/types/core/outputSchema.d.ts.map +1 -0
- package/dist/types/core/slots/buildSystemPromptSlot.d.ts.map +1 -1
- package/dist/types/core/slots/buildToolsSlot.d.ts +10 -0
- package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
- package/dist/types/index.d.ts +8 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/SkillRegistry.d.ts +98 -0
- package/dist/types/lib/injection-engine/SkillRegistry.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/factories/defineSkill.d.ts +33 -6
- package/dist/types/lib/injection-engine/factories/defineSkill.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/index.d.ts +5 -3
- package/dist/types/lib/injection-engine/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillTools.d.ts +73 -0
- package/dist/types/lib/injection-engine/skillTools.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/types.d.ts +18 -0
- package/dist/types/lib/injection-engine/types.d.ts.map +1 -1
- package/dist/types/lib/lazyRequire.d.ts +30 -0
- package/dist/types/lib/lazyRequire.d.ts.map +1 -0
- package/dist/types/lib/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/llm-providers.d.ts +31 -0
- package/dist/types/llm-providers.d.ts.map +1 -0
- package/dist/types/locales/index.d.ts +133 -0
- package/dist/types/locales/index.d.ts.map +1 -0
- package/dist/types/memory-providers.d.ts +41 -0
- package/dist/types/memory-providers.d.ts.map +1 -0
- package/dist/types/providers.d.ts +11 -0
- package/dist/types/providers.d.ts.map +1 -1
- package/dist/types/recorders/core/contextEngineering.d.ts +137 -0
- package/dist/types/recorders/core/contextEngineering.d.ts.map +1 -0
- package/dist/types/recorders/observability/commentary/commentaryTemplates.d.ts.map +1 -1
- package/dist/types/security/PermissionPolicy.d.ts +125 -0
- package/dist/types/security/PermissionPolicy.d.ts.map +1 -0
- package/dist/types/security/index.d.ts +40 -0
- package/dist/types/security/index.d.ts.map +1 -0
- package/dist/types/tool-providers/gatedTools.d.ts +37 -0
- package/dist/types/tool-providers/gatedTools.d.ts.map +1 -0
- package/dist/types/tool-providers/index.d.ts +42 -0
- package/dist/types/tool-providers/index.d.ts.map +1 -0
- package/dist/types/tool-providers/skillScopedTools.d.ts +46 -0
- package/dist/types/tool-providers/skillScopedTools.d.ts.map +1 -0
- package/dist/types/tool-providers/staticTools.d.ts +22 -0
- package/dist/types/tool-providers/staticTools.d.ts.map +1 -0
- package/dist/types/tool-providers/types.d.ts +103 -0
- package/dist/types/tool-providers/types.d.ts.map +1 -0
- package/package.json +36 -2
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* contextEngineering(agent) — first-class handle on the engineered
|
|
4
|
+
* subset of `context.injected` events.
|
|
5
|
+
*
|
|
6
|
+
* The Block A8 piece. agentfootprint already emits `context.injected`
|
|
7
|
+
* for EVERY piece of content that lands in a slot — including the
|
|
8
|
+
* baseline flow (the user message, every tool result, the static
|
|
9
|
+
* system prompt). For a developer who wants to inspect what their
|
|
10
|
+
* RAG / Skills / Memory / Instructions / Steering / Facts ARE
|
|
11
|
+
* INJECTING (the actual context-engineering work), the baseline flow
|
|
12
|
+
* is noise.
|
|
13
|
+
*
|
|
14
|
+
* `contextEngineering(agent)` filters the stream to ONLY the
|
|
15
|
+
* engineered injections and gives consumers two cleaner subscriptions:
|
|
16
|
+
*
|
|
17
|
+
* - `onEngineered(cb)` — fires for `source` ∈ {rag, skill, memory,
|
|
18
|
+
* instructions, steering, fact, custom}. The actual
|
|
19
|
+
* context-engineering work.
|
|
20
|
+
* - `onBaseline(cb)` — fires for `source` ∈ {user, tool-result,
|
|
21
|
+
* assistant, base, registry}. The baseline message-history flow.
|
|
22
|
+
*
|
|
23
|
+
* Use cases:
|
|
24
|
+
* - **Lens UI**: render only engineered injections in the "context
|
|
25
|
+
* bin"; show the baseline flow as edges between iterations.
|
|
26
|
+
* - **Eval pipelines**: count how many RAG chunks vs Memory entries
|
|
27
|
+
* vs Skill bodies entered the prompt for an eval-set query.
|
|
28
|
+
* - **Cost attribution**: sum tokens by `source` to know what
|
|
29
|
+
* fraction of spend is RAG vs Skills vs baseline.
|
|
30
|
+
* - **Debug logging**: tail just the engineered signals to spot
|
|
31
|
+
* surprising activations during dev.
|
|
32
|
+
*
|
|
33
|
+
* Pattern: Strategy + Filter (GoF) — pure classifier function over
|
|
34
|
+
* the existing `context.injected` event payload, paired with
|
|
35
|
+
* a thin subscription helper.
|
|
36
|
+
*
|
|
37
|
+
* Role: Layer-2 (event taxonomy) consumer-side helper. Doesn't
|
|
38
|
+
* emit new events; doesn't change the agent's flowchart.
|
|
39
|
+
* Pure observation.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* import { contextEngineering } from 'agentfootprint';
|
|
43
|
+
*
|
|
44
|
+
* const ce = contextEngineering(agent);
|
|
45
|
+
* ce.onEngineered((e) => {
|
|
46
|
+
* console.log(`[${e.payload.source}] ${e.payload.contentSummary}`);
|
|
47
|
+
* });
|
|
48
|
+
* ce.onBaseline((e) => {
|
|
49
|
+
* console.log(`[baseline:${e.payload.source}]`);
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* await agent.run({ message: 'help me' });
|
|
53
|
+
* // ... runs; engineered + baseline streams fire separately
|
|
54
|
+
*
|
|
55
|
+
* ce.detach(); // stops both subscriptions; the agent itself is fine
|
|
56
|
+
*/
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.contextEngineering = exports.isBaselineSource = exports.isEngineeredSource = exports.BASELINE_SOURCES = exports.ENGINEERED_SOURCES = void 0;
|
|
59
|
+
/**
|
|
60
|
+
* Public set of "engineered" sources — the context-engineering
|
|
61
|
+
* primitives that consumers configure (RAG, Skills, Memory,
|
|
62
|
+
* Instructions, Steering, Facts) plus user-defined `custom`.
|
|
63
|
+
*
|
|
64
|
+
* Frozen so consumers can `.has(value)` directly without copy.
|
|
65
|
+
*/
|
|
66
|
+
exports.ENGINEERED_SOURCES = new Set([
|
|
67
|
+
'rag',
|
|
68
|
+
'skill',
|
|
69
|
+
'memory',
|
|
70
|
+
'instructions',
|
|
71
|
+
'steering',
|
|
72
|
+
'fact',
|
|
73
|
+
'custom',
|
|
74
|
+
]);
|
|
75
|
+
/**
|
|
76
|
+
* Public set of "baseline" sources — the message-history flow that
|
|
77
|
+
* exists regardless of context engineering: user input, tool results,
|
|
78
|
+
* assistant outputs, the always-on system prompt anchor (`base`), and
|
|
79
|
+
* the agent's static tool registry advertisement (`registry`).
|
|
80
|
+
*/
|
|
81
|
+
exports.BASELINE_SOURCES = new Set([
|
|
82
|
+
'user',
|
|
83
|
+
'tool-result',
|
|
84
|
+
'assistant',
|
|
85
|
+
'base',
|
|
86
|
+
'registry',
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* Pure classifier: given a `ContextSource`, is it engineered?
|
|
90
|
+
*
|
|
91
|
+
* Useful for ad-hoc filtering on a raw `agent.on('agentfootprint.context.injected', ...)`
|
|
92
|
+
* subscription when you don't need the wrapper helper.
|
|
93
|
+
*/
|
|
94
|
+
function isEngineeredSource(source) {
|
|
95
|
+
return exports.ENGINEERED_SOURCES.has(source);
|
|
96
|
+
}
|
|
97
|
+
exports.isEngineeredSource = isEngineeredSource;
|
|
98
|
+
/**
|
|
99
|
+
* Pure classifier: given a `ContextSource`, is it baseline?
|
|
100
|
+
*/
|
|
101
|
+
function isBaselineSource(source) {
|
|
102
|
+
return exports.BASELINE_SOURCES.has(source);
|
|
103
|
+
}
|
|
104
|
+
exports.isBaselineSource = isBaselineSource;
|
|
105
|
+
/**
|
|
106
|
+
* Wrap a runner's `agentfootprint.context.injected` stream into two
|
|
107
|
+
* filtered subscriptions: engineered + baseline. Multiple listeners
|
|
108
|
+
* per stream are allowed; `detach()` removes all of them.
|
|
109
|
+
*
|
|
110
|
+
* The classifier inspects `event.payload.source`. Unknown sources
|
|
111
|
+
* (forward-compat: `ContextSource` is open-extensible) are routed
|
|
112
|
+
* to NEITHER stream — preferring under-firing over miscategorizing.
|
|
113
|
+
* Use `agent.on('agentfootprint.context.injected', ...)` directly
|
|
114
|
+
* if you need to observe sources that aren't (yet) classified.
|
|
115
|
+
*/
|
|
116
|
+
function contextEngineering(agent) {
|
|
117
|
+
const unsubscribers = [];
|
|
118
|
+
function onEngineered(listener) {
|
|
119
|
+
const wrapped = (e) => {
|
|
120
|
+
if (isEngineeredSource(e.payload.source))
|
|
121
|
+
listener(e);
|
|
122
|
+
};
|
|
123
|
+
const unsub = agent.on('agentfootprint.context.injected', wrapped);
|
|
124
|
+
unsubscribers.push(unsub);
|
|
125
|
+
return () => {
|
|
126
|
+
unsub();
|
|
127
|
+
const idx = unsubscribers.indexOf(unsub);
|
|
128
|
+
if (idx >= 0)
|
|
129
|
+
unsubscribers.splice(idx, 1);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function onBaseline(listener) {
|
|
133
|
+
const wrapped = (e) => {
|
|
134
|
+
if (isBaselineSource(e.payload.source))
|
|
135
|
+
listener(e);
|
|
136
|
+
};
|
|
137
|
+
const unsub = agent.on('agentfootprint.context.injected', wrapped);
|
|
138
|
+
unsubscribers.push(unsub);
|
|
139
|
+
return () => {
|
|
140
|
+
unsub();
|
|
141
|
+
const idx = unsubscribers.indexOf(unsub);
|
|
142
|
+
if (idx >= 0)
|
|
143
|
+
unsubscribers.splice(idx, 1);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function detach() {
|
|
147
|
+
for (const unsub of unsubscribers) {
|
|
148
|
+
try {
|
|
149
|
+
unsub();
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Defensive: a misbehaving subscription's throw should not
|
|
153
|
+
// prevent detaching the rest.
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
unsubscribers.length = 0;
|
|
157
|
+
}
|
|
158
|
+
return { onEngineered, onBaseline, detach };
|
|
159
|
+
}
|
|
160
|
+
exports.contextEngineering = contextEngineering;
|
|
161
|
+
//# sourceMappingURL=contextEngineering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextEngineering.js","sourceRoot":"","sources":["../../../src/recorders/core/contextEngineering.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;;;AAKH;;;;;;GAMG;AACU,QAAA,kBAAkB,GAA+B,IAAI,GAAG,CAAgB;IACnF,KAAK;IACL,OAAO;IACP,QAAQ;IACR,cAAc;IACd,UAAU;IACV,MAAM;IACN,QAAQ;CACT,CAAC,CAAC;AAEH;;;;;GAKG;AACU,QAAA,gBAAgB,GAA+B,IAAI,GAAG,CAAgB;IACjF,MAAM;IACN,aAAa;IACb,WAAW;IACX,MAAM;IACN,UAAU;CACX,CAAC,CAAC;AAEH;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,MAAqB;IACtD,OAAO,0BAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAFD,gDAEC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,MAAqB;IACpD,OAAO,wBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAFD,4CAEC;AAkDD;;;;;;;;;;GAUG;AACH,SAAgB,kBAAkB,CAAC,KAAuB;IACxD,MAAM,aAAa,GAAoC,EAAE,CAAC;IAE1D,SAAS,YAAY,CAAC,QAAiC;QACrD,MAAM,OAAO,GAA4B,CAAC,CAAC,EAAE,EAAE;YAC7C,IAAI,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,iCAAiC,EAAE,OAAO,CAAC,CAAC;QACnE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,KAAK,EAAE,CAAC;YACR,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,GAAG,IAAI,CAAC;gBAAE,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC;IACJ,CAAC;IAED,SAAS,UAAU,CAAC,QAAiC;QACnD,MAAM,OAAO,GAA4B,CAAC,CAAC,EAAE,EAAE;YAC7C,IAAI,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,iCAAiC,EAAE,OAAO,CAAC,CAAC;QACnE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,KAAK,EAAE,CAAC;YACR,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,GAAG,IAAI,CAAC;gBAAE,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC;IACJ,CAAC;IAED,SAAS,MAAM;QACb,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,KAAK,EAAE,CAAC;YACV,CAAC;YAAC,MAAM,CAAC;gBACP,2DAA2D;gBAC3D,8BAA8B;YAChC,CAAC;QACH,CAAC;QACD,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAC9C,CAAC;AA1CD,gDA0CC"}
|
|
@@ -73,7 +73,12 @@ exports.defaultCommentaryTemplates = {
|
|
|
73
73
|
'context.injected.rag': '{{appName}} retrieved relevant content and added it to the conversation.',
|
|
74
74
|
'context.injected.skill': '{{appName}} activated a skill — its body went into the system prompt, and its tools became available to the LLM.',
|
|
75
75
|
'context.injected.memory': '{{appName}} pulled prior content from memory and added it to the conversation.',
|
|
76
|
-
|
|
76
|
+
// Generic — fits always-on rules + on-tool-return predicates uniformly.
|
|
77
|
+
// Specialized variants below disambiguate when the trigger metadata
|
|
78
|
+
// is available on the event.
|
|
79
|
+
'context.injected.instructions': '{{appName}} added a rule to the system prompt: {{descClause}}.',
|
|
80
|
+
'context.injected.instructions.onToolReturn': '{{appName}} added a tool-specific reminder after `{{lastToolName}}` returned: {{descClause}}.',
|
|
81
|
+
'context.injected.instructions.alwaysOn': '{{appName}} added an always-on rule to the system prompt: {{descClause}}.',
|
|
77
82
|
'context.injected.custom': '{{appName}} injected a custom piece of context.',
|
|
78
83
|
'skill.activated': '{{appName}} turned on a skill — its tools and instructions are now available.',
|
|
79
84
|
'skill.deactivated': '{{appName}} turned off a skill.',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commentaryTemplates.js","sourceRoot":"","sources":["../../../../src/recorders/observability/commentary/commentaryTemplates.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;;;AAUH;;;;GAIG;AACU,QAAA,0BAA0B,GAAwB;IAC7D,kBAAkB,EAAE,2CAA2C;IAE/D,wBAAwB,EAAE,2CAA2C;IACrE,wBAAwB,EAAE,8DAA8D;IAExF,sBAAsB,EAAE,qEAAqE;IAC7F,yBAAyB,EAAE,qEAAqE;IAEhG,mEAAmE;IACnE,iEAAiE;IACjE,iEAAiE;IACjE,8DAA8D;IAC9D,gDAAgD;IAChD,mEAAmE;IACnE,iDAAiD;IACjD,6DAA6D;IAC7D,6CAA6C;IAC7C,iEAAiE;IACjE,iEAAiE;IACjE,iBAAiB,EAAE,0BAA0B;IAC7C,sBAAsB,EAAE,wCAAwC;IAEhE,mBAAmB,EACjB,+IAA+I;IACjJ,wBAAwB,EAAE,6BAA6B;IACvD,0BAA0B,EAAE,EAAE;IAE9B,iBAAiB,EAAE,4EAA4E;IAE/F,sBAAsB,EACpB,0EAA0E;IAC5E,wBAAwB,EACtB,kHAAkH;IACpH,yBAAyB,EACvB,gFAAgF;IAClF,+BAA+B,
|
|
1
|
+
{"version":3,"file":"commentaryTemplates.js","sourceRoot":"","sources":["../../../../src/recorders/observability/commentary/commentaryTemplates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PermissionPolicy — data-driven role-based authorization for tool dispatch.
|
|
4
|
+
*
|
|
5
|
+
* Closes Neo gap #2 (of 8). Permissions are CROSS-CUTTING — they're not
|
|
6
|
+
* context engineering, they're a guard ON context-engineering operations
|
|
7
|
+
* (tool dispatch, skill activation, memory writes, output emission).
|
|
8
|
+
* That's why this lives in `agentfootprint/security`, parallel to the
|
|
9
|
+
* provider subpaths.
|
|
10
|
+
*
|
|
11
|
+
* Two surfaces, one primitive:
|
|
12
|
+
* 1. `PermissionPolicy.fromRoles({...}, activeRole)` — declarative,
|
|
13
|
+
* data-driven, auditable. Production governance.
|
|
14
|
+
* 2. The PermissionPolicy instance satisfies BOTH:
|
|
15
|
+
* - `PermissionChecker` interface (async check; consumed by Agent
|
|
16
|
+
* constructor's `permissionChecker` field)
|
|
17
|
+
* - sync `isAllowed(toolId)` method (consumed by `gatedTools(...)`
|
|
18
|
+
* from `agentfootprint/tool-providers`)
|
|
19
|
+
*
|
|
20
|
+
* Pattern: Strategy (GoF) for the role-allowlist policy + Adapter
|
|
21
|
+
* (matches `PermissionChecker` interface so it composes with
|
|
22
|
+
* existing v2.4 Agent constructor).
|
|
23
|
+
*
|
|
24
|
+
* Role: Layer-3 cross-cutting guard. Not Injection. Not provider.
|
|
25
|
+
* Lives in its own subpath (`agentfootprint/security`).
|
|
26
|
+
*
|
|
27
|
+
* @example Read-only role for a support agent
|
|
28
|
+
* const policy = PermissionPolicy.fromRoles(
|
|
29
|
+
* {
|
|
30
|
+
* readonly: ['lookup_order', 'get_status', 'list_skills', 'read_skill'],
|
|
31
|
+
* support: ['lookup_order', 'get_status', 'process_refund', 'list_skills', 'read_skill'],
|
|
32
|
+
* },
|
|
33
|
+
* 'readonly',
|
|
34
|
+
* );
|
|
35
|
+
*
|
|
36
|
+
* policy.isAllowed('lookup_order'); // → true
|
|
37
|
+
* policy.isAllowed('process_refund'); // → false (not in readonly role)
|
|
38
|
+
*
|
|
39
|
+
* // As a tool-dispatch gate (composes with gatedTools)
|
|
40
|
+
* const provider = gatedTools(staticTools(allTools), (name) => policy.isAllowed(name));
|
|
41
|
+
*
|
|
42
|
+
* // As an Agent permissionChecker (the v2.4 surface)
|
|
43
|
+
* const agent = Agent.create({ provider, model, permissionChecker: policy }).build();
|
|
44
|
+
*
|
|
45
|
+
* @example Per-identity role switching at runtime
|
|
46
|
+
* const policy = PermissionPolicy.fromRoles({
|
|
47
|
+
* readonly: [...],
|
|
48
|
+
* admin: [...],
|
|
49
|
+
* }, 'readonly');
|
|
50
|
+
*
|
|
51
|
+
* const adminPolicy = policy.withActiveRole('admin');
|
|
52
|
+
* // Same allowlist data; different active role.
|
|
53
|
+
*/
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.PermissionPolicy = void 0;
|
|
56
|
+
/**
|
|
57
|
+
* Data-driven role-based permission policy. Satisfies the v2.4
|
|
58
|
+
* `PermissionChecker` interface AND exposes a sync `isAllowed` method
|
|
59
|
+
* for use with `gatedTools` from `agentfootprint/tool-providers`.
|
|
60
|
+
*/
|
|
61
|
+
class PermissionPolicy {
|
|
62
|
+
opts;
|
|
63
|
+
name = 'PermissionPolicy';
|
|
64
|
+
constructor(opts) {
|
|
65
|
+
this.opts = opts;
|
|
66
|
+
if (!opts.roles[opts.activeRole]) {
|
|
67
|
+
throw new Error(`PermissionPolicy: activeRole '${opts.activeRole}' is not defined in roles. Available: ${Object.keys(opts.roles).join(', ') || '(none)'}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Factory: build a role-based policy from a role → tool-ids map and
|
|
72
|
+
* the role active for this instance.
|
|
73
|
+
*
|
|
74
|
+
* Throws if `activeRole` isn't a key in `roles` — fail loud at
|
|
75
|
+
* config time, not at first denied call.
|
|
76
|
+
*/
|
|
77
|
+
static fromRoles(roles, activeRole) {
|
|
78
|
+
return new PermissionPolicy({ roles, activeRole });
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Sync allowlist check. Use as a predicate with `gatedTools`:
|
|
82
|
+
*
|
|
83
|
+
* gatedTools(staticTools(allTools), (toolId) => policy.isAllowed(toolId))
|
|
84
|
+
*
|
|
85
|
+
* Returns true iff `toolId` is in the active role's allowlist.
|
|
86
|
+
* Closes-fail by design: missing role membership = denied.
|
|
87
|
+
*/
|
|
88
|
+
isAllowed(toolId) {
|
|
89
|
+
return (this.opts.roles[this.opts.activeRole] ?? []).includes(toolId);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Async check matching the `PermissionChecker` interface — consumed
|
|
93
|
+
* by `Agent.create({ permissionChecker })`. Wraps `isAllowed` with
|
|
94
|
+
* the structured `PermissionDecision` envelope (allow / deny + a
|
|
95
|
+
* `policyRuleId` so observability can trace which role decided).
|
|
96
|
+
*
|
|
97
|
+
* Today the policy only checks the tool name (request.target).
|
|
98
|
+
* Future work: also gate by capability ('memory_write', etc.) when
|
|
99
|
+
* the role allowlist is widened to capability-by-id.
|
|
100
|
+
*/
|
|
101
|
+
async check(request) {
|
|
102
|
+
const toolId = request.target ?? request.capability;
|
|
103
|
+
if (this.isAllowed(toolId)) {
|
|
104
|
+
return {
|
|
105
|
+
result: 'allow',
|
|
106
|
+
policyRuleId: `${this.opts.activeRole}.allowlist`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
result: 'deny',
|
|
111
|
+
policyRuleId: `${this.opts.activeRole}.allowlist.miss`,
|
|
112
|
+
rationale: `Tool '${toolId}' is not in the '${this.opts.activeRole}' role allowlist.`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Derive a sibling policy with a different active role. Same role
|
|
117
|
+
* map; different active role. Useful for per-identity routing
|
|
118
|
+
* (one policy instance per request, varying active role per caller).
|
|
119
|
+
*
|
|
120
|
+
* Returns a NEW PermissionPolicy — original is unchanged.
|
|
121
|
+
*/
|
|
122
|
+
withActiveRole(activeRole) {
|
|
123
|
+
return new PermissionPolicy({ roles: this.opts.roles, activeRole });
|
|
124
|
+
}
|
|
125
|
+
/** The role name currently active. Useful for observability. */
|
|
126
|
+
get activeRole() {
|
|
127
|
+
return this.opts.activeRole;
|
|
128
|
+
}
|
|
129
|
+
/** All defined role names. Stable order = registration order. */
|
|
130
|
+
get roles() {
|
|
131
|
+
return Object.keys(this.opts.roles);
|
|
132
|
+
}
|
|
133
|
+
/** All tool ids allowed under the current active role. */
|
|
134
|
+
allowedToolIds() {
|
|
135
|
+
return [...(this.opts.roles[this.opts.activeRole] ?? [])];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.PermissionPolicy = PermissionPolicy;
|
|
139
|
+
//# sourceMappingURL=PermissionPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PermissionPolicy.js","sourceRoot":"","sources":["../../src/security/PermissionPolicy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;;;AA6BH;;;;GAIG;AACH,MAAa,gBAAgB;IAGU;IAF5B,IAAI,GAAG,kBAAkB,CAAC;IAEnC,YAAqC,IAA6B;QAA7B,SAAI,GAAJ,IAAI,CAAyB;QAChE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CACb,iCAAiC,IAAI,CAAC,UAAU,yCAC9C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QACxC,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CAAC,KAAoB,EAAE,UAAkB;QACvD,OAAO,IAAI,gBAAgB,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;;OAOG;IACH,SAAS,CAAC,MAAc;QACtB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxE,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,CAAC,OAA0B;QACpC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC;QACpD,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO;gBACL,MAAM,EAAE,OAAO;gBACf,YAAY,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,YAAY;aAClD,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,iBAAiB;YACtD,SAAS,EAAE,SAAS,MAAM,oBAAoB,IAAI,CAAC,IAAI,CAAC,UAAU,mBAAmB;SACtF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,cAAc,CAAC,UAAkB;QAC/B,OAAO,IAAI,gBAAgB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,gEAAgE;IAChE,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;IAC9B,CAAC;IAED,iEAAiE;IACjE,IAAI,KAAK;QACP,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,0DAA0D;IAC1D,cAAc;QACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC;CACF;AAtFD,4CAsFC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* agentfootprint/security — cross-cutting authorization + governance.
|
|
4
|
+
*
|
|
5
|
+
* Permissions are NOT context engineering — they're a guard ON
|
|
6
|
+
* context-engineering operations (tool dispatch, skill activation,
|
|
7
|
+
* memory writes, output emission). That's why this lives in its own
|
|
8
|
+
* subpath, parallel to `agentfootprint/tool-providers` and the
|
|
9
|
+
* `agentfootprint/memory-*` and `agentfootprint/providers` subpaths.
|
|
10
|
+
*
|
|
11
|
+
* Today's surface is small and data-driven on purpose: one role
|
|
12
|
+
* allowlist primitive that satisfies BOTH the v2.4 `PermissionChecker`
|
|
13
|
+
* interface AND a sync `isAllowed(toolId)` predicate for use with
|
|
14
|
+
* `gatedTools` from `agentfootprint/tool-providers`.
|
|
15
|
+
*
|
|
16
|
+
* Future additions (capability gating, gate_open flows, audit logs)
|
|
17
|
+
* land here without expanding the public root barrel.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { PermissionPolicy } from 'agentfootprint/security';
|
|
21
|
+
* import { gatedTools, staticTools } from 'agentfootprint/tool-providers';
|
|
22
|
+
*
|
|
23
|
+
* const policy = PermissionPolicy.fromRoles(
|
|
24
|
+
* {
|
|
25
|
+
* readonly: ['lookup', 'list_skills', 'read_skill'],
|
|
26
|
+
* admin: ['lookup', 'list_skills', 'read_skill', 'write', 'delete'],
|
|
27
|
+
* },
|
|
28
|
+
* 'readonly',
|
|
29
|
+
* );
|
|
30
|
+
*
|
|
31
|
+
* const provider = gatedTools(
|
|
32
|
+
* staticTools(allTools),
|
|
33
|
+
* (name) => policy.isAllowed(name),
|
|
34
|
+
* );
|
|
35
|
+
*
|
|
36
|
+
* const agent = Agent.create({ provider, model, permissionChecker: policy }).build();
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.PermissionPolicy = void 0;
|
|
40
|
+
var PermissionPolicy_js_1 = require("./PermissionPolicy.js");
|
|
41
|
+
Object.defineProperty(exports, "PermissionPolicy", { enumerable: true, get: function () { return PermissionPolicy_js_1.PermissionPolicy; } });
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;;;AAEH,6DAAyD;AAAhD,uHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* gatedTools — wrap any ToolProvider with a per-tool gating predicate.
|
|
4
|
+
*
|
|
5
|
+
* The DECORATOR for tool providers. Filters the inner provider's
|
|
6
|
+
* output by running the predicate against each tool name. Composes
|
|
7
|
+
* freely:
|
|
8
|
+
*
|
|
9
|
+
* gatedTools(
|
|
10
|
+
* gatedTools(staticTools(allTools), readOnlyPredicate),
|
|
11
|
+
* skillGatePredicate,
|
|
12
|
+
* )
|
|
13
|
+
*
|
|
14
|
+
* Reads as: "static list of all tools, filtered by readonly policy,
|
|
15
|
+
* then further filtered by the active skill's tool set." Each gate
|
|
16
|
+
* is one concern; composition handles the rest.
|
|
17
|
+
*
|
|
18
|
+
* Pattern: Decorator (GoF) — wraps any ToolProvider with an additional
|
|
19
|
+
* filter. Mirrors `withRetry` / `withFallback` over LLMProvider.
|
|
20
|
+
*
|
|
21
|
+
* @example Read-only enforcement
|
|
22
|
+
* const readOnly = gatedTools(
|
|
23
|
+
* staticTools([read, write]),
|
|
24
|
+
* (toolName) => toolName.startsWith('read_'),
|
|
25
|
+
* );
|
|
26
|
+
* readOnly.list(ctx); // → [read]
|
|
27
|
+
*
|
|
28
|
+
* @example Skill-gated dispatch (autoActivate use case)
|
|
29
|
+
* const skillGated = gatedTools(
|
|
30
|
+
* staticTools(allTools),
|
|
31
|
+
* (toolName, ctx) => ctx.activeSkillId
|
|
32
|
+
* ? skillToolMap[ctx.activeSkillId].includes(toolName)
|
|
33
|
+
* : alwaysVisible.includes(toolName),
|
|
34
|
+
* );
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.gatedTools = void 0;
|
|
38
|
+
// #region gatedTools
|
|
39
|
+
function gatedTools(inner, predicate) {
|
|
40
|
+
return {
|
|
41
|
+
id: 'gated',
|
|
42
|
+
list(ctx) {
|
|
43
|
+
// Pull from the inner provider first; each recomputation sees
|
|
44
|
+
// the freshest state from any nested gates.
|
|
45
|
+
const innerTools = inner.list(ctx);
|
|
46
|
+
// Filter by predicate — tool name from `tool.schema.name`.
|
|
47
|
+
// Predicates throwing escape: a buggy predicate should crash
|
|
48
|
+
// loudly, not silently allow tools through. Per the
|
|
49
|
+
// permission-as-defense-in-depth principle.
|
|
50
|
+
return innerTools.filter((t) => predicate(t.schema.name, ctx));
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
exports.gatedTools = gatedTools;
|
|
55
|
+
// #endregion gatedTools
|
|
56
|
+
//# sourceMappingURL=gatedTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatedTools.js","sourceRoot":"","sources":["../../src/tool-providers/gatedTools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;;;AAIH,qBAAqB;AACrB,SAAgB,UAAU,CAAC,KAAmB,EAAE,SAA4B;IAC1E,OAAO;QACL,EAAE,EAAE,OAAO;QACX,IAAI,CAAC,GAAwB;YAC3B,8DAA8D;YAC9D,4CAA4C;YAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnC,2DAA2D;YAC3D,6DAA6D;YAC7D,oDAAoD;YACpD,4CAA4C;YAC5C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACjE,CAAC;KACF,CAAC;AACJ,CAAC;AAdD,gCAcC;AACD,wBAAwB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* agentfootprint/tool-providers — chainable tool dispatch + tool sources.
|
|
4
|
+
*
|
|
5
|
+
* Two layers under one subpath:
|
|
6
|
+
*
|
|
7
|
+
* 1. Tool dispatch (this folder)
|
|
8
|
+
* - `staticTools(arr)` — wrap a flat tool list
|
|
9
|
+
* - `gatedTools(inner, predicate)` — decorator that filters
|
|
10
|
+
* - `ToolProvider` interface — the contract
|
|
11
|
+
* - `ToolDispatchContext` — read-only context per iteration
|
|
12
|
+
*
|
|
13
|
+
* 2. Tool sources (re-exported from existing modules)
|
|
14
|
+
* - `mcpClient(opts)` — connect to an MCP server (real)
|
|
15
|
+
* - `mockMcpClient({ tools })` — in-memory MCP source for dev / tests
|
|
16
|
+
*
|
|
17
|
+
* Compose freely. The dispatch layer is decorator-shaped (mirroring
|
|
18
|
+
* `withRetry` / `withFallback` over LLMProvider). Tool sources produce
|
|
19
|
+
* `Tool[]` that flow into a `staticTools(arr)` provider, which can
|
|
20
|
+
* then be wrapped by `gatedTools(...)` for permission gating or
|
|
21
|
+
* per-skill filtering.
|
|
22
|
+
*
|
|
23
|
+
* @example Static (90% case — what `agent.tools(arr)` does today)
|
|
24
|
+
* const provider = staticTools([weatherTool, lookupTool]);
|
|
25
|
+
*
|
|
26
|
+
* @example Read-only enforcement
|
|
27
|
+
* const readOnly = gatedTools(
|
|
28
|
+
* staticTools(allTools),
|
|
29
|
+
* (name) => policy.isAllowed(name),
|
|
30
|
+
* );
|
|
31
|
+
*
|
|
32
|
+
* @example MCP source + permission gate
|
|
33
|
+
* const slack = await mcpClient({ transport: ... });
|
|
34
|
+
* const slackTools = await slack.tools();
|
|
35
|
+
* const provider = gatedTools(staticTools(slackTools), (name) => allowed(name));
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.mockMcpClient = exports.mcpClient = exports.skillScopedTools = exports.gatedTools = exports.staticTools = void 0;
|
|
39
|
+
var staticTools_js_1 = require("./staticTools.js");
|
|
40
|
+
Object.defineProperty(exports, "staticTools", { enumerable: true, get: function () { return staticTools_js_1.staticTools; } });
|
|
41
|
+
var gatedTools_js_1 = require("./gatedTools.js");
|
|
42
|
+
Object.defineProperty(exports, "gatedTools", { enumerable: true, get: function () { return gatedTools_js_1.gatedTools; } });
|
|
43
|
+
var skillScopedTools_js_1 = require("./skillScopedTools.js");
|
|
44
|
+
Object.defineProperty(exports, "skillScopedTools", { enumerable: true, get: function () { return skillScopedTools_js_1.skillScopedTools; } });
|
|
45
|
+
// Re-export tool sources from the MCP module so consumers find them in
|
|
46
|
+
// one place. The top-level barrel still exports `mcpClient` for v2.2
|
|
47
|
+
// back-compat.
|
|
48
|
+
var index_js_1 = require("../lib/mcp/index.js");
|
|
49
|
+
Object.defineProperty(exports, "mcpClient", { enumerable: true, get: function () { return index_js_1.mcpClient; } });
|
|
50
|
+
Object.defineProperty(exports, "mockMcpClient", { enumerable: true, get: function () { return index_js_1.mockMcpClient; } });
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tool-providers/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;;;AAEH,mDAA+C;AAAtC,6GAAA,WAAW,OAAA;AACpB,iDAA6C;AAApC,2GAAA,UAAU,OAAA;AACnB,6DAAyD;AAAhD,uHAAA,gBAAgB,OAAA;AAGzB,uEAAuE;AACvE,qEAAqE;AACrE,eAAe;AACf,gDAA+D;AAAtD,qGAAA,SAAS,OAAA;AAAE,yGAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* skillScopedTools — ToolProvider that exposes a tool subset only when
|
|
4
|
+
* a specific Skill is active in the current iteration's context.
|
|
5
|
+
*
|
|
6
|
+
* The Block A5 piece. Pairs with `defineSkill({ autoActivate: 'currentSkill' })`
|
|
7
|
+
* to give the LLM a sharper choice space: when `billing` activates, the
|
|
8
|
+
* tool list flips from "all 25 agent tools" to "the 7 billing tools" +
|
|
9
|
+
* any baseline (always-on) tools the consumer composes alongside.
|
|
10
|
+
*
|
|
11
|
+
* Pattern: gated ToolProvider keyed by `ctx.activeSkillId`. Pure compute;
|
|
12
|
+
* no Agent-runtime dependency. Composes freely with `staticTools`
|
|
13
|
+
* for the always-on baseline.
|
|
14
|
+
*
|
|
15
|
+
* @example One skill's tools, scoped by activation
|
|
16
|
+
* const billingTools = skillScopedTools('billing', [refundTool, chargeTool]);
|
|
17
|
+
* billingTools.list({ iteration: 1, activeSkillId: 'billing', identity: ... });
|
|
18
|
+
* // → [refundTool, chargeTool]
|
|
19
|
+
* billingTools.list({ iteration: 1, activeSkillId: 'refund', identity: ... });
|
|
20
|
+
* // → [] (different skill active)
|
|
21
|
+
* billingTools.list({ iteration: 1, identity: ... });
|
|
22
|
+
* // → [] (no skill active)
|
|
23
|
+
*
|
|
24
|
+
* @example Compose with baseline + multiple skills
|
|
25
|
+
* const baseline = staticTools([lookupOrderTool, listSkills, readSkill]);
|
|
26
|
+
* const billingTbx = skillScopedTools('billing', [refundTool, chargeTool]);
|
|
27
|
+
* const refundTbx = skillScopedTools('refund', [reverseTool]);
|
|
28
|
+
*
|
|
29
|
+
* // Wrap each scope-provider in a gatedTools for downstream composition,
|
|
30
|
+
* // OR build a small wrapper that concatenates list(ctx) outputs:
|
|
31
|
+
* const provider: ToolProvider = {
|
|
32
|
+
* id: 'composite',
|
|
33
|
+
* list: (ctx) => [
|
|
34
|
+
* ...baseline.list(ctx),
|
|
35
|
+
* ...billingTbx.list(ctx),
|
|
36
|
+
* ...refundTbx.list(ctx),
|
|
37
|
+
* ],
|
|
38
|
+
* };
|
|
39
|
+
*
|
|
40
|
+
* Note: the runtime that POPULATES `ctx.activeSkillId` from
|
|
41
|
+
* `scope.activatedInjectionIds` lands in Block C / v2.5+. Today,
|
|
42
|
+
* consumers can drive it manually for tests + design-time inspection.
|
|
43
|
+
*/
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.skillScopedTools = void 0;
|
|
46
|
+
// #region skillScopedTools
|
|
47
|
+
function skillScopedTools(skillId, tools) {
|
|
48
|
+
if (!skillId || skillId.trim().length === 0) {
|
|
49
|
+
throw new Error('skillScopedTools: `skillId` is required and must be non-empty.');
|
|
50
|
+
}
|
|
51
|
+
// Capture the tool list once. `list()` returns a fresh array each
|
|
52
|
+
// call (matches the staticTools / gatedTools convention so the
|
|
53
|
+
// agent's reference-equality check always sees an update).
|
|
54
|
+
const captured = [...tools];
|
|
55
|
+
return {
|
|
56
|
+
id: `skill-scoped:${skillId}`,
|
|
57
|
+
list(ctx) {
|
|
58
|
+
// Empty list when the skill is not active.
|
|
59
|
+
if (ctx.activeSkillId !== skillId)
|
|
60
|
+
return [];
|
|
61
|
+
return [...captured];
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
exports.skillScopedTools = skillScopedTools;
|
|
66
|
+
// #endregion skillScopedTools
|
|
67
|
+
//# sourceMappingURL=skillScopedTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillScopedTools.js","sourceRoot":"","sources":["../../src/tool-providers/skillScopedTools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;;;AAKH,2BAA2B;AAC3B,SAAgB,gBAAgB,CAAC,OAAe,EAAE,KAAsB;IACtE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;IACD,kEAAkE;IAClE,+DAA+D;IAC/D,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC5B,OAAO;QACL,EAAE,EAAE,gBAAgB,OAAO,EAAE;QAC7B,IAAI,CAAC,GAAwB;YAC3B,2CAA2C;YAC3C,IAAI,GAAG,CAAC,aAAa,KAAK,OAAO;gBAAE,OAAO,EAAE,CAAC;YAC7C,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC;AAhBD,4CAgBC;AACD,8BAA8B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* staticTools — the simplest ToolProvider. Wraps a fixed Tool[] list.
|
|
4
|
+
*
|
|
5
|
+
* 90% case. What `agent.tools(arr)` does today, made composable.
|
|
6
|
+
* Equivalent to passing `arr` directly EXCEPT that `staticTools(arr)`
|
|
7
|
+
* is now a `ToolProvider` you can wrap with `gatedTools(...)` for
|
|
8
|
+
* permission filtering or per-skill gating.
|
|
9
|
+
*
|
|
10
|
+
* Pattern: identity ToolProvider — no filtering, just exposes the
|
|
11
|
+
* underlying list verbatim.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const provider = staticTools([weatherTool, lookupTool]);
|
|
15
|
+
* // Materialize the visible list and register via .tools(...).
|
|
16
|
+
* // Direct .toolProvider(...) wiring on the builder lands in Block A5 / v2.5+.
|
|
17
|
+
* const visible = provider.list({ iteration: 0, identity: { conversationId: '_' } });
|
|
18
|
+
* const agent = Agent.create({ provider: llm, model }).tools(visible).build();
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.staticTools = void 0;
|
|
22
|
+
// #region staticTools
|
|
23
|
+
function staticTools(tools) {
|
|
24
|
+
// Capture the input list once. `list()` returns a fresh array each
|
|
25
|
+
// call so the agent's reference-equality check always sees an update
|
|
26
|
+
// (matches the `gatedTools` decorator's per-call recomputation).
|
|
27
|
+
const captured = [...tools];
|
|
28
|
+
return {
|
|
29
|
+
id: 'static',
|
|
30
|
+
list(_ctx) {
|
|
31
|
+
return [...captured];
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
exports.staticTools = staticTools;
|
|
36
|
+
// #endregion staticTools
|
|
37
|
+
//# sourceMappingURL=staticTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staticTools.js","sourceRoot":"","sources":["../../src/tool-providers/staticTools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAKH,sBAAsB;AACtB,SAAgB,WAAW,CAAC,KAAsB;IAChD,mEAAmE;IACnE,qEAAqE;IACrE,iEAAiE;IACjE,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC5B,OAAO;QACL,EAAE,EAAE,QAAQ;QACZ,IAAI,CAAC,IAAyB;YAC5B,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC;AAXD,kCAWC;AACD,yBAAyB"}
|