@aid-framework/runtime 0.0.0-stage → 0.1.39

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.
Files changed (188) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +52 -2
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/agents/deep_agents.d.ts +78 -0
  5. package/dist/agents/deep_agents.d.ts.map +1 -0
  6. package/dist/agents/deep_agents.js +477 -0
  7. package/dist/agents/deep_agents.js.map +1 -0
  8. package/dist/agents/engine.d.ts +85 -0
  9. package/dist/agents/engine.d.ts.map +1 -0
  10. package/dist/agents/engine.js +129 -0
  11. package/dist/agents/engine.js.map +1 -0
  12. package/dist/agents/gateway_chat_model.d.ts +151 -0
  13. package/dist/agents/gateway_chat_model.d.ts.map +1 -0
  14. package/dist/agents/gateway_chat_model.js +350 -0
  15. package/dist/agents/gateway_chat_model.js.map +1 -0
  16. package/dist/agents/guardrail_middleware.d.ts +57 -0
  17. package/dist/agents/guardrail_middleware.d.ts.map +1 -0
  18. package/dist/agents/guardrail_middleware.js +85 -0
  19. package/dist/agents/guardrail_middleware.js.map +1 -0
  20. package/dist/agents/guardrails.d.ts +124 -0
  21. package/dist/agents/guardrails.d.ts.map +1 -0
  22. package/dist/agents/guardrails.js +336 -0
  23. package/dist/agents/guardrails.js.map +1 -0
  24. package/dist/agents/index.d.ts +15 -0
  25. package/dist/agents/index.d.ts.map +1 -0
  26. package/dist/agents/index.js +15 -0
  27. package/dist/agents/index.js.map +1 -0
  28. package/dist/agents/ir.d.ts +144 -0
  29. package/dist/agents/ir.d.ts.map +1 -0
  30. package/dist/agents/ir.js +513 -0
  31. package/dist/agents/ir.js.map +1 -0
  32. package/dist/agents/loop.d.ts +145 -0
  33. package/dist/agents/loop.d.ts.map +1 -0
  34. package/dist/agents/loop.js +1025 -0
  35. package/dist/agents/loop.js.map +1 -0
  36. package/dist/agents/memory.d.ts +115 -0
  37. package/dist/agents/memory.d.ts.map +1 -0
  38. package/dist/agents/memory.js +258 -0
  39. package/dist/agents/memory.js.map +1 -0
  40. package/dist/agents/state.d.ts +137 -0
  41. package/dist/agents/state.d.ts.map +1 -0
  42. package/dist/agents/state.js +255 -0
  43. package/dist/agents/state.js.map +1 -0
  44. package/dist/concurrency.d.ts +36 -0
  45. package/dist/concurrency.d.ts.map +1 -0
  46. package/dist/concurrency.js +86 -0
  47. package/dist/concurrency.js.map +1 -0
  48. package/dist/control.d.ts +116 -0
  49. package/dist/control.d.ts.map +1 -0
  50. package/dist/control.js +281 -0
  51. package/dist/control.js.map +1 -0
  52. package/dist/cost.d.ts +95 -0
  53. package/dist/cost.d.ts.map +1 -0
  54. package/dist/cost.js +161 -0
  55. package/dist/cost.js.map +1 -0
  56. package/dist/errors.d.ts +213 -0
  57. package/dist/errors.d.ts.map +1 -0
  58. package/dist/errors.js +316 -0
  59. package/dist/errors.js.map +1 -0
  60. package/dist/evals/dataset.d.ts +45 -0
  61. package/dist/evals/dataset.d.ts.map +1 -0
  62. package/dist/evals/dataset.js +147 -0
  63. package/dist/evals/dataset.js.map +1 -0
  64. package/dist/evals/gate.d.ts +236 -0
  65. package/dist/evals/gate.d.ts.map +1 -0
  66. package/dist/evals/gate.js +572 -0
  67. package/dist/evals/gate.js.map +1 -0
  68. package/dist/evals/metrics.d.ts +141 -0
  69. package/dist/evals/metrics.d.ts.map +1 -0
  70. package/dist/evals/metrics.js +364 -0
  71. package/dist/evals/metrics.js.map +1 -0
  72. package/dist/evals/predicate.d.ts +79 -0
  73. package/dist/evals/predicate.d.ts.map +1 -0
  74. package/dist/evals/predicate.js +178 -0
  75. package/dist/evals/predicate.js.map +1 -0
  76. package/dist/evals/runner.d.ts +94 -0
  77. package/dist/evals/runner.d.ts.map +1 -0
  78. package/dist/evals/runner.js +202 -0
  79. package/dist/evals/runner.js.map +1 -0
  80. package/dist/gateway.d.ts +118 -0
  81. package/dist/gateway.d.ts.map +1 -0
  82. package/dist/gateway.js +250 -0
  83. package/dist/gateway.js.map +1 -0
  84. package/dist/index.d.ts +83 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +59 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/internal/json.d.ts +44 -0
  89. package/dist/internal/json.d.ts.map +1 -0
  90. package/dist/internal/json.js +90 -0
  91. package/dist/internal/json.js.map +1 -0
  92. package/dist/internal/text.d.ts +17 -0
  93. package/dist/internal/text.d.ts.map +1 -0
  94. package/dist/internal/text.js +22 -0
  95. package/dist/internal/text.js.map +1 -0
  96. package/dist/pipeline.d.ts +80 -0
  97. package/dist/pipeline.d.ts.map +1 -0
  98. package/dist/pipeline.js +159 -0
  99. package/dist/pipeline.js.map +1 -0
  100. package/dist/policy.d.ts +52 -0
  101. package/dist/policy.d.ts.map +1 -0
  102. package/dist/policy.js +199 -0
  103. package/dist/policy.js.map +1 -0
  104. package/dist/prompts.d.ts +86 -0
  105. package/dist/prompts.d.ts.map +1 -0
  106. package/dist/prompts.js +337 -0
  107. package/dist/prompts.js.map +1 -0
  108. package/dist/providers/base.d.ts +19 -0
  109. package/dist/providers/base.d.ts.map +1 -0
  110. package/dist/providers/base.js +13 -0
  111. package/dist/providers/base.js.map +1 -0
  112. package/dist/providers/fake.d.ts +98 -0
  113. package/dist/providers/fake.d.ts.map +1 -0
  114. package/dist/providers/fake.js +181 -0
  115. package/dist/providers/fake.js.map +1 -0
  116. package/dist/providers/http.d.ts +62 -0
  117. package/dist/providers/http.d.ts.map +1 -0
  118. package/dist/providers/http.js +245 -0
  119. package/dist/providers/http.js.map +1 -0
  120. package/dist/retrieval/chunking.d.ts +88 -0
  121. package/dist/retrieval/chunking.d.ts.map +1 -0
  122. package/dist/retrieval/chunking.js +188 -0
  123. package/dist/retrieval/chunking.js.map +1 -0
  124. package/dist/retrieval/citations.d.ts +98 -0
  125. package/dist/retrieval/citations.d.ts.map +1 -0
  126. package/dist/retrieval/citations.js +134 -0
  127. package/dist/retrieval/citations.js.map +1 -0
  128. package/dist/retrieval/connectors.d.ts +74 -0
  129. package/dist/retrieval/connectors.d.ts.map +1 -0
  130. package/dist/retrieval/connectors.js +218 -0
  131. package/dist/retrieval/connectors.js.map +1 -0
  132. package/dist/retrieval/embedding.d.ts +116 -0
  133. package/dist/retrieval/embedding.d.ts.map +1 -0
  134. package/dist/retrieval/embedding.js +282 -0
  135. package/dist/retrieval/embedding.js.map +1 -0
  136. package/dist/retrieval/gate.d.ts +52 -0
  137. package/dist/retrieval/gate.d.ts.map +1 -0
  138. package/dist/retrieval/gate.js +91 -0
  139. package/dist/retrieval/gate.js.map +1 -0
  140. package/dist/retrieval/hybrid.d.ts +76 -0
  141. package/dist/retrieval/hybrid.d.ts.map +1 -0
  142. package/dist/retrieval/hybrid.js +150 -0
  143. package/dist/retrieval/hybrid.js.map +1 -0
  144. package/dist/retrieval/metrics.d.ts +126 -0
  145. package/dist/retrieval/metrics.d.ts.map +1 -0
  146. package/dist/retrieval/metrics.js +200 -0
  147. package/dist/retrieval/metrics.js.map +1 -0
  148. package/dist/retrieval/pgvector.d.ts +62 -0
  149. package/dist/retrieval/pgvector.d.ts.map +1 -0
  150. package/dist/retrieval/pgvector.js +262 -0
  151. package/dist/retrieval/pgvector.js.map +1 -0
  152. package/dist/retrieval/rerank.d.ts +61 -0
  153. package/dist/retrieval/rerank.d.ts.map +1 -0
  154. package/dist/retrieval/rerank.js +105 -0
  155. package/dist/retrieval/rerank.js.map +1 -0
  156. package/dist/retrieval/retriever.d.ts +125 -0
  157. package/dist/retrieval/retriever.d.ts.map +1 -0
  158. package/dist/retrieval/retriever.js +281 -0
  159. package/dist/retrieval/retriever.js.map +1 -0
  160. package/dist/retrieval/stores.d.ts +106 -0
  161. package/dist/retrieval/stores.d.ts.map +1 -0
  162. package/dist/retrieval/stores.js +142 -0
  163. package/dist/retrieval/stores.js.map +1 -0
  164. package/dist/retrieval/types.d.ts +314 -0
  165. package/dist/retrieval/types.d.ts.map +1 -0
  166. package/dist/retrieval/types.js +388 -0
  167. package/dist/retrieval/types.js.map +1 -0
  168. package/dist/steps.d.ts +156 -0
  169. package/dist/steps.d.ts.map +1 -0
  170. package/dist/steps.js +199 -0
  171. package/dist/steps.js.map +1 -0
  172. package/dist/structured.d.ts +91 -0
  173. package/dist/structured.d.ts.map +1 -0
  174. package/dist/structured.js +155 -0
  175. package/dist/structured.js.map +1 -0
  176. package/dist/tools.d.ts +100 -0
  177. package/dist/tools.d.ts.map +1 -0
  178. package/dist/tools.js +201 -0
  179. package/dist/tools.js.map +1 -0
  180. package/dist/tracing.d.ts +104 -0
  181. package/dist/tracing.d.ts.map +1 -0
  182. package/dist/tracing.js +155 -0
  183. package/dist/tracing.js.map +1 -0
  184. package/dist/types.d.ts +240 -0
  185. package/dist/types.d.ts.map +1 -0
  186. package/dist/types.js +357 -0
  187. package/dist/types.js.map +1 -0
  188. package/package.json +77 -3
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Expose {@link ModelGateway} as a LangChain chat model.
3
+ *
4
+ * This module is the load-bearing part of the Deep Agents backend. A harness handed a
5
+ * provider would keep working while silently dropping every guarantee the gateway exists
6
+ * to provide: the fallback chain, the budget preflight, the cost ledger and the
7
+ * per-attempt LLM span. The agent would look fine and the budget would stop applying. So
8
+ * the harness is never handed a provider -- it is handed *this adapter*, and every model
9
+ * call inside the graph goes back out through our gateway.
10
+ *
11
+ * What the adapter is responsible for:
12
+ *
13
+ * - **Translation, both directions.** LangChain messages to our {@link Message}, and our
14
+ * {@link CompletionResponse} back to an `AIMessage` carrying tool calls, `usage_metadata`
15
+ * and the alias/cost the gateway actually charged. The alias matters: a fallback means
16
+ * the answer did not come from the pinned model, and the response says so rather than
17
+ * letting the harness believe otherwise.
18
+ * - **Tool filtering.** `bindTools` is the single funnel every tool reaches the model
19
+ * through, which makes it the one place to enforce what the agent may call. Deep Agents
20
+ * bundles `ls`/`read_file`/`write_file`/`edit_file`/`delete`/`glob`/`grep`/`execute` and
21
+ * binds all of them; the allow-list drops everything the agent did not declare, so the
22
+ * filesystem and shell tools are unreachable rather than merely undocumented.
23
+ * - **Budget continuity.** The agent's ceiling travels with every call, so a breach
24
+ * surfaces as the gateway's own {@link BudgetExceededError} from inside the harness.
25
+ * There is no second accounting path here to disagree with it.
26
+ *
27
+ * Everything in here statically imports `@langchain/*`. That is deliberate and safe: the
28
+ * harness is optional for consumers, `agents/deep_agents.ts` is the only module that
29
+ * reaches this one, and it does so with a dynamic `import()` after {@link checkEngine} has
30
+ * proved the packages are installed.
31
+ */
32
+ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
33
+ import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from '@langchain/core/messages';
34
+ import { tool } from '@langchain/core/tools';
35
+ import { z } from 'zod';
36
+ import { DeepAgentsEngineError, DeepAgentsMaxStepsError } from '../errors.js';
37
+ import { CompletionRequest, Message, ToolCall, ToolDefinition } from '../types.js';
38
+ /**
39
+ * A LangChain chat model whose every generation is a gateway call.
40
+ *
41
+ * Construct it with the alias the IR pinned, the gateway that owns fallback and
42
+ * accounting, and the ceiling this agent may spend. `allowedTools` is the tool allow-list:
43
+ * `undefined` admits everything the harness binds, which is only appropriate for an agent
44
+ * that declares no tools.
45
+ */
46
+ export class GatewayChatModel extends BaseChatModel {
47
+ gateway;
48
+ alias;
49
+ fallbacks;
50
+ budget;
51
+ allowedTools;
52
+ /**
53
+ * The agent's `maxSteps`, counted in model calls. Enforced here because this adapter is
54
+ * the only place that sees every model call -- and because the harness's own limiter
55
+ * *completes* the run with a synthetic answer instead of failing.
56
+ */
57
+ maxCalls;
58
+ /** What `bindTools` last admitted. Read by tests, never by the harness. */
59
+ boundTools;
60
+ /** Every generation this model produced, in order: proof the harness went through us. */
61
+ calls;
62
+ constructor(init) {
63
+ super({});
64
+ this.gateway = init.gateway;
65
+ this.alias = init.alias;
66
+ this.fallbacks = [...(init.fallbacks ?? [])];
67
+ this.budget = init.budget;
68
+ this.allowedTools = init.allowedTools;
69
+ this.maxCalls = init.maxCalls;
70
+ this.boundTools = [...(init.boundTools ?? [])];
71
+ this.calls = init.calls ?? [];
72
+ }
73
+ /**
74
+ * Admit only the tools this agent declared.
75
+ *
76
+ * Every tool the harness offers -- bundled ones included -- arrives here, so an
77
+ * allow-list applied at this point is the difference between "we do not document a
78
+ * shell" and "there is no shell the model can reach". The filtered set is kept on a copy
79
+ * rather than on `this` so two agents sharing one adapter cannot widen each other's
80
+ * grant; the copy shares `calls`, because the accumulator is the run's spend record and a
81
+ * per-copy one would silently lose the generations of every bound model.
82
+ */
83
+ bindTools(tools) {
84
+ const admitted = toToolDefinitions(tools, { allowed: this.allowedTools });
85
+ return new GatewayChatModel({
86
+ gateway: this.gateway,
87
+ alias: this.alias,
88
+ fallbacks: this.fallbacks,
89
+ ...(this.budget === undefined ? {} : { budget: this.budget }),
90
+ ...(this.allowedTools === undefined ? {} : { allowedTools: this.allowedTools }),
91
+ ...(this.maxCalls === undefined ? {} : { maxCalls: this.maxCalls }),
92
+ boundTools: admitted,
93
+ calls: this.calls,
94
+ });
95
+ }
96
+ _llmType() {
97
+ return 'aid-gateway';
98
+ }
99
+ _identifyingParams() {
100
+ return { alias: this.alias, fallbacks: [...this.fallbacks] };
101
+ }
102
+ /**
103
+ * One harness model call, routed through the gateway.
104
+ *
105
+ * LangChain 1.x exposes a single async generation hook: `generate` and `invoke` both
106
+ * return promises and there is no synchronous entry point at all, so unlike the Python
107
+ * adapter there is no second path to refuse here.
108
+ *
109
+ * `fallbacks` and `budget` travel with the call, so the harness gets the same fallback
110
+ * behaviour and the same hard ceiling as the native loop. A breach is raised, not
111
+ * returned: the harness must not be able to continue past a budget the ledger refused.
112
+ */
113
+ async _generate(messages, _options, _runManager) {
114
+ const request = new CompletionRequest({
115
+ messages: toAidMessages(messages),
116
+ tools: this.boundTools,
117
+ });
118
+ if (this.maxCalls !== undefined && this.calls.length >= this.maxCalls) {
119
+ // Refused before the call, not after: an agent that has spent its step budget must
120
+ // not spend one more to discover that it has.
121
+ throw new DeepAgentsMaxStepsError(this.alias, this.maxCalls);
122
+ }
123
+ const generation = await this.gateway.generate(this.alias, request, {
124
+ fallbacks: this.fallbacks,
125
+ ...(this.budget === undefined ? {} : { budget: this.budget }),
126
+ });
127
+ this.calls.push(generation);
128
+ return {
129
+ generations: [{ text: generation.response.text, message: toAiMessage(generation) }],
130
+ };
131
+ }
132
+ // biome-ignore lint/correctness/useYield: a stream that works is the bug; this refuses.
133
+ async *_streamResponseChunks(_messages, _options, _runManager) {
134
+ throw new DeepAgentsEngineError('streaming is not exposed through the deepagents engine: ModelGateway.stream serves ' +
135
+ 'Server-Sent Event bytes for the HTTP layer, but the engine consumes ' +
136
+ 'request/response generation and never an SSE byte stream. A structured LangChain ' +
137
+ 'chunk stream would be a second streaming contract and a second accounting path, ' +
138
+ 'so it is refused here rather than buffered into a non-stream.');
139
+ }
140
+ }
141
+ /** Carry the gateway's answer across, including what it cost and where from. */
142
+ function toAiMessage(generation) {
143
+ const response = generation.response;
144
+ const usage = generation.usage;
145
+ return new AIMessage({
146
+ content: response.text,
147
+ tool_calls: response.toolCalls.map((call) => ({
148
+ name: call.name,
149
+ args: { ...call.args },
150
+ id: call.id,
151
+ type: 'tool_call',
152
+ })),
153
+ usage_metadata: {
154
+ input_tokens: usage.inputTokens,
155
+ output_tokens: usage.outputTokens,
156
+ total_tokens: usage.totalTokens,
157
+ },
158
+ response_metadata: {
159
+ model: response.model,
160
+ provider: response.provider,
161
+ finish_reason: response.finishReason,
162
+ // Not decoration: after a fallback these differ from the alias the IR pinned, and
163
+ // that has to stay visible to the caller.
164
+ alias: generation.alias,
165
+ cost_usd: generation.costUsd,
166
+ fell_back: generation.fellBack,
167
+ },
168
+ });
169
+ }
170
+ /**
171
+ * Translate the harness transcript into ours.
172
+ *
173
+ * Tool calls and their ids are preserved verbatim: the harness pairs a result with its
174
+ * call by id, and renaming or renumbering them here would break the pairing in a way that
175
+ * only shows up as a tool result attached to the wrong call.
176
+ */
177
+ export function toAidMessages(messages) {
178
+ const converted = [];
179
+ for (const message of messages) {
180
+ const type = message.getType();
181
+ if (type === 'system') {
182
+ converted.push(Message.system(text(message)));
183
+ }
184
+ else if (type === 'human') {
185
+ converted.push(Message.user(text(message)));
186
+ }
187
+ else if (type === 'ai') {
188
+ const calls = message.tool_calls ?? [];
189
+ if (calls.length > 0) {
190
+ converted.push(Message.assistantToolCalls(text(message), calls.map((call, index) => new ToolCall({
191
+ id: call.id ?? `call_${index}`,
192
+ name: call.name,
193
+ arguments: call.args ?? {},
194
+ }))));
195
+ }
196
+ else {
197
+ converted.push(Message.assistant(text(message)));
198
+ }
199
+ }
200
+ else if (type === 'tool') {
201
+ const observed = message;
202
+ converted.push(Message.tool(observed.tool_call_id, text(message), {
203
+ ...(observed.name === undefined ? {} : { name: observed.name }),
204
+ }));
205
+ }
206
+ else {
207
+ // Deep Agents may hand us one of its own message subclasses. Dropping it would lose
208
+ // a turn from the transcript, so it is carried as plain text.
209
+ converted.push(Message.user(text(message)));
210
+ }
211
+ }
212
+ return converted;
213
+ }
214
+ /**
215
+ * Normalise the harness's tool specs and drop everything outside the grant.
216
+ *
217
+ * The harness offers OpenAI-shaped objects, bare `{name, parameters}` records, and
218
+ * `BaseTool` instances carrying a Zod schema. All are accepted so the allow-list cannot be
219
+ * bypassed by a shape the filter did not recognise: anything unparseable has no name, and
220
+ * a tool with no name is refused rather than passed through.
221
+ */
222
+ export function toToolDefinitions(tools, options = {}) {
223
+ const allowed = options.allowed;
224
+ const definitions = [];
225
+ for (const entry of tools) {
226
+ const definition = toolDefinition(entry);
227
+ if (definition === undefined)
228
+ continue;
229
+ if (allowed !== undefined && !allowed.has(definition.name))
230
+ continue;
231
+ definitions.push(definition);
232
+ }
233
+ return definitions;
234
+ }
235
+ function toolDefinition(entry) {
236
+ const record = entry;
237
+ const body = record.type === 'function' && isRecord(record.function)
238
+ ? record.function
239
+ : record;
240
+ const name = body.name;
241
+ if (typeof name !== 'string' || name.length === 0)
242
+ return undefined;
243
+ return new ToolDefinition({
244
+ name,
245
+ description: typeof body.description === 'string' ? body.description : '',
246
+ parameters: jsonSchemaOf(body),
247
+ });
248
+ }
249
+ /**
250
+ * The parameter schema of one harness tool, as JSON Schema.
251
+ *
252
+ * A LangChain tool normally carries a Zod schema here. Reading it through
253
+ * `z.toJSONSchema` keeps the model's parameter schema intact instead of handing it an
254
+ * empty one, which would only fail later as a tool call with no arguments.
255
+ */
256
+ function jsonSchemaOf(body) {
257
+ const declared = body.parameters;
258
+ if (isRecord(declared))
259
+ return { ...declared };
260
+ const schema = body.schema;
261
+ if (schema === undefined || schema === null)
262
+ return {};
263
+ try {
264
+ const json = z.toJSONSchema(schema);
265
+ // `$schema` is metadata about the dialect, not a constraint the model can act on.
266
+ const { $schema: _dialect, ...rest } = json;
267
+ return rest;
268
+ }
269
+ catch {
270
+ return {};
271
+ }
272
+ }
273
+ function isRecord(value) {
274
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
275
+ }
276
+ /** Flatten message content to text, keeping block content that carries prose. */
277
+ function text(message) {
278
+ const content = message.content;
279
+ if (typeof content === 'string')
280
+ return content;
281
+ const parts = [];
282
+ for (const block of content) {
283
+ if (typeof block === 'string')
284
+ parts.push(block);
285
+ else if (isRecord(block) && typeof block.text === 'string')
286
+ parts.push(block.text);
287
+ }
288
+ return parts.join('');
289
+ }
290
+ /**
291
+ * Translate our transcript back out, for seeding the harness with prior turns.
292
+ *
293
+ * This exists so a resumed run hands the harness the same transcript the native loop would
294
+ * have, rather than a summary of it. Tool calls are re-emitted as `AIMessage.tool_calls` so
295
+ * the harness sees them as calls it can pair, which is what keeps a resumed run's
296
+ * transcript comparable to an uninterrupted one.
297
+ */
298
+ export function toLangchainMessages(messages) {
299
+ const converted = [];
300
+ for (const message of messages) {
301
+ if (message.role === 'system') {
302
+ converted.push(new SystemMessage(message.content));
303
+ }
304
+ else if (message.role === 'user') {
305
+ converted.push(new HumanMessage(message.content));
306
+ }
307
+ else if (message.role === 'tool') {
308
+ converted.push(new ToolMessage({
309
+ content: message.content,
310
+ tool_call_id: message.toolCallId ?? '',
311
+ name: message.name ?? '',
312
+ }));
313
+ }
314
+ else if (message.toolCalls.length > 0) {
315
+ converted.push(new AIMessage({
316
+ content: message.content,
317
+ tool_calls: message.toolCalls.map((call) => ({
318
+ name: call.name,
319
+ args: { ...call.args },
320
+ id: call.id,
321
+ type: 'tool_call',
322
+ })),
323
+ }));
324
+ }
325
+ else {
326
+ converted.push(new AIMessage(message.content));
327
+ }
328
+ }
329
+ return converted;
330
+ }
331
+ /**
332
+ * Wrap one declared tool as a harness tool whose body is our executor.
333
+ *
334
+ * The body is deliberately thin: authorization and the tool-call guardrail run in the
335
+ * guardrail middleware of whichever agent is calling, and execution goes through the same
336
+ * `ToolExecutor` the native loop uses. That is what makes a tool call under this engine the
337
+ * same event as one under the native engine.
338
+ *
339
+ * The call id is derived, not random: the harness pairs a result with its call by id, and a
340
+ * random one would make two identical runs differ.
341
+ */
342
+ export function harnessTool(spec) {
343
+ const schema = z.fromJSONSchema(spec.parameters);
344
+ return tool(async (args) => spec.call(args), {
345
+ name: spec.name,
346
+ description: spec.description,
347
+ schema,
348
+ });
349
+ }
350
+ //# sourceMappingURL=gateway_chat_model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway_chat_model.js","sourceRoot":"","sources":["../../src/agents/gateway_chat_model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAE5E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE/F,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAG9E,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAWnF;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAiB,SAAQ,aAAa;IACxC,OAAO,CAAe;IACtB,KAAK,CAAS;IACd,SAAS,CAAoB;IAC7B,MAAM,CAAqB;IAC3B,YAAY,CAAkC;IACvD;;;;OAIG;IACM,QAAQ,CAAqB;IACtC,2EAA2E;IAClE,UAAU,CAA4B;IAC/C,yFAAyF;IAChF,KAAK,CAAqB;IAEnC,YAAY,IASX;QACC,KAAK,CAAC,EAAE,CAAC,CAAC;QACV,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAChC,CAAC;IAED;;;;;;;;;OASG;IACM,SAAS,CAAC,KAAuB;QACxC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC1E,OAAO,IAAI,gBAAgB,CAAC;YAC1B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7D,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/E,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnE,UAAU,EAAE,QAAQ;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;IAEQ,QAAQ;QACf,OAAO,aAAa,CAAC;IACvB,CAAC;IAEQ,kBAAkB;QACzB,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;IAC/D,CAAC;IAED;;;;;;;;;;OAUG;IACM,KAAK,CAAC,SAAS,CACtB,QAAuB,EACvB,QAAkC,EAClC,WAAsC;QAEtC,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC;YACpC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC;YACjC,KAAK,EAAE,IAAI,CAAC,UAAU;SACvB,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACtE,mFAAmF;YACnF,8CAA8C;YAC9C,MAAM,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE;YAClE,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5B,OAAO;YACL,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;SACpF,CAAC;IACJ,CAAC;IAED,wFAAwF;IAC/E,KAAK,CAAC,CAAC,qBAAqB,CACnC,SAAwB,EACxB,QAAkC,EAClC,WAAsC;QAEtC,MAAM,IAAI,qBAAqB,CAC7B,qFAAqF;YACnF,sEAAsE;YACtE,mFAAmF;YACnF,kFAAkF;YAClF,+DAA+D,CAClE,CAAC;IACJ,CAAC;CACF;AAED,gFAAgF;AAChF,SAAS,WAAW,CAAC,UAA4B;IAC/C,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;IAC/B,OAAO,IAAI,SAAS,CAAC;QACnB,OAAO,EAAE,QAAQ,CAAC,IAAI;QACtB,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC5C,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;YACtB,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,WAAoB;SAC3B,CAAC,CAAC;QACH,cAAc,EAAE;YACd,YAAY,EAAE,KAAK,CAAC,WAAW;YAC/B,aAAa,EAAE,KAAK,CAAC,YAAY;YACjC,YAAY,EAAE,KAAK,CAAC,WAAW;SAChC;QACD,iBAAiB,EAAE;YACjB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,aAAa,EAAE,QAAQ,CAAC,YAAY;YACpC,kFAAkF;YAClF,0CAA0C;YAC1C,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,QAAQ,EAAE,UAAU,CAAC,OAAO;YAC5B,SAAS,EAAE,UAAU,CAAC,QAAQ;SAC/B;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgC;IAC5D,MAAM,SAAS,GAAc,EAAE,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YAC5B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,KAAK,GAAI,OAAqB,CAAC,UAAU,IAAI,EAAE,CAAC;YACtD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,SAAS,CAAC,IAAI,CACZ,OAAO,CAAC,kBAAkB,CACxB,IAAI,CAAC,OAAO,CAAC,EACb,KAAK,CAAC,GAAG,CACP,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACd,IAAI,QAAQ,CAAC;oBACX,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,QAAQ,KAAK,EAAE;oBAC9B,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,SAAS,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;iBAC3B,CAAC,CACL,CACF,CACF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,OAAsB,CAAC;YACxC,SAAS,CAAC,IAAI,CACZ,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE;gBACjD,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;aAChE,CAAC,CACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,oFAAoF;YACpF,8DAA8D;YAC9D,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAgC,EAChC,OAAO,GAA2D,EAAE;IAEpE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,UAAU,KAAK,SAAS;YAAE,SAAS;QACvC,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACrE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,cAAc,CAAC,KAAqB;IAC3C,MAAM,MAAM,GAAG,KAA2C,CAAC;IAC3D,MAAM,IAAI,GACR,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;QACrD,CAAC,CAAE,MAAM,CAAC,QAAoC;QAC9C,CAAC,CAAC,MAAM,CAAC;IACb,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACpE,OAAO,IAAI,cAAc,CAAC;QACxB,IAAI;QACJ,WAAW,EAAE,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;QACzE,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC;KAC/B,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,IAA6B;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,IAAI,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,MAAmB,CAA4B,CAAC;QAC5E,kFAAkF;QAClF,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,iFAAiF;AACjF,SAAS,IAAI,CAAC,OAAoB;IAChC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aAC5C,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAA4B;IAC9D,MAAM,SAAS,GAAkB,EAAE,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACnC,SAAS,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACnC,SAAS,CAAC,IAAI,CACZ,IAAI,WAAW,CAAC;gBACd,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,YAAY,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;gBACtC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;aACzB,CAAC,CACH,CAAC;QACJ,CAAC;aAAM,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxC,SAAS,CAAC,IAAI,CACZ,IAAI,SAAS,CAAC;gBACZ,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBAC3C,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;oBACtB,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,IAAI,EAAE,WAAoB;iBAC3B,CAAC,CAAC;aACJ,CAAC,CACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,IAAqB;IAC/C,MAAM,MAAM,GAAG,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,UAAoD,CAAC,CAAC;IAC3F,OAAO,IAAI,CAAC,KAAK,EAAE,IAA6B,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACpE,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Our authorization and tool-call guardrail engine, at the harness's tool boundary.
3
+ *
4
+ * The harness has no guardrail concept, so this is where ours wraps it. It runs before the
5
+ * tool body -- the only point where a decision can still stop the call -- and it throws
6
+ * rather than returning an observation, so the harness cannot hand the decision back to the
7
+ * model as something to work around.
8
+ *
9
+ * One middleware instance is bound to one frame. The caller's is attached to the graph; a
10
+ * delegate's is attached to its subagent spec and bound to the *delegate's* frame, which is
11
+ * the same split the native loop makes by driving each frame with its own agent's
12
+ * guardrails.
13
+ */
14
+ import type { AgentMiddleware } from 'langchain';
15
+ import type { Principal } from '../policy.js';
16
+ import type { DeepAgentsHost } from './deep_agents.js';
17
+ import type { Frame, Outcome } from './loop.js';
18
+ /**
19
+ * The harness's delegation tool.
20
+ *
21
+ * Delegation is the one harness tool this engine exposes on purpose, and only an agent that
22
+ * declares a delegate is granted it. It carries no side effect of its own: the delegate's
23
+ * own grant governs what it may do once it is running.
24
+ */
25
+ export declare const DELEGATE_TOOL = "task";
26
+ /**
27
+ * A guardrail decision the harness must not be able to continue past.
28
+ *
29
+ * An error rather than a returned observation: a `ToolMessage` saying "blocked" would be
30
+ * fed back to the model as a tool result, and the model would be free to try again. The
31
+ * harness propagates an exception, so the decision ends the run -- which is what `blocked`
32
+ * means.
33
+ */
34
+ export declare class HaltError extends Error {
35
+ readonly outcome: Outcome;
36
+ constructor(outcome: Outcome);
37
+ }
38
+ /** The parts of the runtime this middleware is allowed to reach. */
39
+ export interface GuardrailMiddlewareOptions {
40
+ readonly host: DeepAgentsHost;
41
+ readonly frame: Frame;
42
+ readonly principal: Principal;
43
+ readonly memoryKey: string;
44
+ }
45
+ /**
46
+ * Build the middleware for one frame.
47
+ *
48
+ * The `task` branch is the delegation boundary, and it is deliberately the first thing the
49
+ * hook does: a delegate's call is authorized and guarded by the middleware bound to the
50
+ * *delegate's* frame, so running the caller's authorize/guardrail over it would refuse a
51
+ * call the delegate is entitled to make and would apply the caller's redactions inside
52
+ * another agent's grant. That is the native loop's semantic too -- `#delegate` opens a frame
53
+ * for the target and drives it, so the target's `tool-call` stage is what runs and the
54
+ * caller's does not cross the boundary.
55
+ */
56
+ export declare function guardrailMiddleware(options: GuardrailMiddlewareOptions): AgentMiddleware;
57
+ //# sourceMappingURL=guardrail_middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrail_middleware.d.ts","sourceRoot":"","sources":["../../src/agents/guardrail_middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAoC,MAAM,WAAW,CAAC;AAGnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEhD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC;;;;;;;GAOG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,YAAY,OAAO,EAAE,OAAO,EAI3B;CACF;AAWD,oEAAoE;AACpE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,eAAe,CA6BxF"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Our authorization and tool-call guardrail engine, at the harness's tool boundary.
3
+ *
4
+ * The harness has no guardrail concept, so this is where ours wraps it. It runs before the
5
+ * tool body -- the only point where a decision can still stop the call -- and it throws
6
+ * rather than returning an observation, so the harness cannot hand the decision back to the
7
+ * model as something to work around.
8
+ *
9
+ * One middleware instance is bound to one frame. The caller's is attached to the graph; a
10
+ * delegate's is attached to its subagent spec and bound to the *delegate's* frame, which is
11
+ * the same split the native loop makes by driving each frame with its own agent's
12
+ * guardrails.
13
+ */
14
+ import { canonicalJson } from '../internal/json.js';
15
+ import { ToolCall } from '../types.js';
16
+ /**
17
+ * The harness's delegation tool.
18
+ *
19
+ * Delegation is the one harness tool this engine exposes on purpose, and only an agent that
20
+ * declares a delegate is granted it. It carries no side effect of its own: the delegate's
21
+ * own grant governs what it may do once it is running.
22
+ */
23
+ export const DELEGATE_TOOL = 'task';
24
+ /**
25
+ * A guardrail decision the harness must not be able to continue past.
26
+ *
27
+ * An error rather than a returned observation: a `ToolMessage` saying "blocked" would be
28
+ * fed back to the model as a tool result, and the model would be free to try again. The
29
+ * harness propagates an exception, so the decision ends the run -- which is what `blocked`
30
+ * means.
31
+ */
32
+ export class HaltError extends Error {
33
+ outcome;
34
+ constructor(outcome) {
35
+ super(`the harness was halted at the tool boundary with status ${outcome.status}`);
36
+ this.name = 'HaltError';
37
+ this.outcome = outcome;
38
+ }
39
+ }
40
+ /** The harness's call shape, converted to ours. */
41
+ function asCall(raw) {
42
+ return new ToolCall({
43
+ id: raw.id ?? raw.name ?? 'tool-call',
44
+ name: raw.name ?? '',
45
+ arguments: raw.args ?? {},
46
+ });
47
+ }
48
+ /**
49
+ * Build the middleware for one frame.
50
+ *
51
+ * The `task` branch is the delegation boundary, and it is deliberately the first thing the
52
+ * hook does: a delegate's call is authorized and guarded by the middleware bound to the
53
+ * *delegate's* frame, so running the caller's authorize/guardrail over it would refuse a
54
+ * call the delegate is entitled to make and would apply the caller's redactions inside
55
+ * another agent's grant. That is the native loop's semantic too -- `#delegate` opens a frame
56
+ * for the target and drives it, so the target's `tool-call` stage is what runs and the
57
+ * caller's does not cross the boundary.
58
+ */
59
+ export function guardrailMiddleware(options) {
60
+ const { host, frame, principal, memoryKey } = options;
61
+ return {
62
+ name: 'aid-guardrails',
63
+ async wrapToolCall(request, handler) {
64
+ const call = asCall(request.toolCall);
65
+ if (call.name === DELEGATE_TOOL)
66
+ return await handler(request);
67
+ host.authorize(frame.agent, call, principal);
68
+ const guarded = host.guardrailToolCalls(frame, [call], memoryKey);
69
+ if (guarded.paused !== undefined)
70
+ throw new HaltError(guarded.paused);
71
+ const rewritten = guarded.calls[0];
72
+ if (rewritten !== undefined &&
73
+ canonicalJson(rewritten.arguments) !== canonicalJson(call.arguments)) {
74
+ // A redaction rewrote the arguments; the tool must see the rewritten ones, not the
75
+ // model's originals.
76
+ return await handler({
77
+ ...request,
78
+ toolCall: { ...request.toolCall, args: rewritten.arguments },
79
+ });
80
+ }
81
+ return await handler(request);
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=guardrail_middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrail_middleware.js","sourceRoot":"","sources":["../../src/agents/guardrail_middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC;;;;;;;GAOG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IACzB,OAAO,CAAU;IAE1B,YAAY,OAAgB;QAC1B,KAAK,CAAC,2DAA2D,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,mDAAmD;AACnD,SAAS,MAAM,CAAC,GAAmE;IACjF,OAAO,IAAI,QAAQ,CAAC;QAClB,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,WAAW;QACrC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;QACpB,SAAS,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;KAC1B,CAAC,CAAC;AACL,CAAC;AAUD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAmC;IACrE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IACtD,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,KAAK,CAAC,YAAY,CAChB,OAAwB,EACxB,OAAwB;YAExB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa;gBAAE,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;YAE/D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;YAClE,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACtE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnC,IACE,SAAS,KAAK,SAAS;gBACvB,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,EACpE,CAAC;gBACD,mFAAmF;gBACnF,qBAAqB;gBACrB,OAAO,MAAM,OAAO,CAAC;oBACnB,GAAG,OAAO;oBACV,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,EAAE;iBAC7D,CAAC,CAAC;YACL,CAAC;YACD,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The guardrails engine: the IR's `guardrails` collection, actually evaluated.
3
+ *
4
+ * The IR already carries the *declaration* -- stages, policy kinds, an action, the fields
5
+ * a redaction may touch. This module is the missing other half: something that looks at
6
+ * text and decides. It is deliberately small and offline. Every detector is a regular
7
+ * expression, so the answer for a given input does not depend on a model, a network call,
8
+ * or a random seed, and a spec that passes here will pass here again tomorrow.
9
+ *
10
+ * Four stages, in the order a run meets them:
11
+ *
12
+ * - `input` -- before the model sees the user's turn.
13
+ * - `retrieval` -- around the chunks a retriever would splice into the prompt.
14
+ * - `tool-call` -- before a tool's handler body runs, over the call's arguments.
15
+ * - `output` -- after the model answers.
16
+ *
17
+ * Three decisions this module owns:
18
+ *
19
+ * **Undecidable is a block.** A guardrail naming a policy with no evaluator, or whose
20
+ * `redact` fields do not cover the text it matched, raises {@link GuardrailBlockedError}.
21
+ * There is no path from "the check could not run" to "no violation found".
22
+ *
23
+ * **Evaluation order is declaration order, except that `block` outranks it.** At one stage
24
+ * the engine walks the agent's guardrails in the order the IR declared them and collects
25
+ * every guardrail that fired. If *any* of them is a `block`, the first such guardrail
26
+ * decides -- a later `flag` cannot talk an earlier `block` down. Otherwise the first
27
+ * guardrail that fired decides.
28
+ *
29
+ * **`flag` cannot be ignored, but it does not stop anything.** A flag is recorded on the
30
+ * run (`RunResult.guardrails`) and the guarded text passes through unchanged. The consumer
31
+ * is whoever reads the run result -- an eval, a log shipper, a reviewer. It is *not* an
32
+ * allow: a flag means a detector matched, and the run carried on because the spec said the
33
+ * run may.
34
+ */
35
+ import type { GuardrailDefinition } from './ir.js';
36
+ export type GuardrailStage = 'input' | 'output' | 'retrieval' | 'tool-call';
37
+ export type GuardrailAction = 'block' | 'redact' | 'flag' | 'escalate';
38
+ export declare const ACTION_BLOCK: GuardrailAction;
39
+ export declare const ACTION_REDACT: GuardrailAction;
40
+ export declare const ACTION_FLAG: GuardrailAction;
41
+ export declare const ACTION_ESCALATE: GuardrailAction;
42
+ export declare const GUARDRAIL_STAGES: readonly GuardrailStage[];
43
+ export declare const GUARDRAIL_ACTIONS: readonly GuardrailAction[];
44
+ /** One match: which policy fired, and the half-open span it fired on. */
45
+ export interface Detection {
46
+ readonly policy: string;
47
+ readonly start: number;
48
+ readonly end: number;
49
+ }
50
+ /** One guardrail that fired at one stage. The audit trail's unit. */
51
+ export interface GuardrailRecord {
52
+ readonly guardrail: string;
53
+ readonly stage: GuardrailStage;
54
+ readonly action: GuardrailAction;
55
+ readonly policies: readonly string[];
56
+ readonly message: string;
57
+ }
58
+ /**
59
+ * A guardrail that entered human-in-the-loop instead of deciding by itself.
60
+ *
61
+ * `text` is the guarded payload, kept so that approving an `output` escalation can release
62
+ * the model's answer without re-running the model -- and so that a rejection can show the
63
+ * human what they rejected.
64
+ */
65
+ export interface GuardrailEscalation {
66
+ readonly guardrail: string;
67
+ readonly stage: GuardrailStage;
68
+ readonly message: string;
69
+ readonly channel: string;
70
+ readonly text: string;
71
+ }
72
+ /**
73
+ * The engine's answer for one stage of one turn.
74
+ *
75
+ * `records` is every guardrail that fired, not only the deciding one: a `flag` next to a
76
+ * `block` still has to reach the audit trail. `action` and `deciding` are the outcome;
77
+ * `text` and `arguments` are the payload after any `redact` was applied.
78
+ */
79
+ export interface GuardrailVerdict {
80
+ readonly stage: GuardrailStage;
81
+ readonly records: readonly GuardrailRecord[];
82
+ readonly action: string | undefined;
83
+ readonly deciding: GuardrailRecord | undefined;
84
+ readonly text: string;
85
+ readonly arguments: Readonly<Record<string, unknown>>;
86
+ }
87
+ /** Whether any guardrail matched, whatever it decided to do about it. */
88
+ export declare function fired(verdict: GuardrailVerdict): boolean;
89
+ /**
90
+ * One entry per `GuardrailPolicyKind` in `packages/ir/src/shapes.ts`.
91
+ *
92
+ * These are *heuristics*, and saying so is the honest description. They catch the shapes a
93
+ * red-team corpus is built from -- an instruction-override phrase, a well-formed email or
94
+ * card-like digit run, a jailbreak persona -- and they will not catch a paraphrase.
95
+ */
96
+ export declare const DETECTORS: Readonly<Record<string, readonly RegExp[]>>;
97
+ /**
98
+ * Every match of `policy` in `text`, in document order.
99
+ *
100
+ * Raises {@link ConfigurationError} for an unknown policy: that is a caller bug, not
101
+ * untrusted input, and the engine reports it as a block before it ever gets here.
102
+ */
103
+ export declare function detect(policy: string, text: string): readonly Detection[];
104
+ /** Evaluates an agent's guardrails at one stage. */
105
+ export declare class GuardrailEngine {
106
+ #private;
107
+ constructor(guardrails?: ReadonlyMap<string, GuardrailDefinition>);
108
+ declared(guardrailId: string): GuardrailDefinition | undefined;
109
+ checkInput(guardrails: readonly GuardrailDefinition[], text: string): GuardrailVerdict;
110
+ checkOutput(guardrails: readonly GuardrailDefinition[], text: string): GuardrailVerdict;
111
+ /**
112
+ * Guard what a retriever would splice into the prompt.
113
+ *
114
+ * Only the *results* are in the payload, not the query. The stage is about the text a
115
+ * model is handed, and putting the user's question in the same payload would let a
116
+ * `redact` guardrail over the `text` field fire on a violation it cannot remove -- which
117
+ * fails closed as a block and hides the real cause. The query's own checks belong to the
118
+ * `input` stage.
119
+ */
120
+ checkRetrieval(guardrails: readonly GuardrailDefinition[], results: readonly string[]): GuardrailVerdict;
121
+ checkToolCall(guardrails: readonly GuardrailDefinition[], toolId: string, arguments_: Readonly<Record<string, unknown>>): GuardrailVerdict;
122
+ check(stage: GuardrailStage, guardrails: readonly GuardrailDefinition[], payload: Readonly<Record<string, unknown>>, toolId: string | undefined): GuardrailVerdict;
123
+ }
124
+ //# sourceMappingURL=guardrails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../src/agents/guardrails.ts"],"names":[],"mappings":"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"}