@silmaril-security/sdk 0.6.3 → 0.7.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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  All notable changes to the Silmaril Firewall TypeScript SDK are documented here.
4
4
 
5
+ ## 0.7.0 - 2026-09-30
6
+
7
+ - Add optional Deep Agents middleware and protected constructors for root, general-purpose,
8
+ declarative, and explicitly protected compiled subagents. The compiled graph factory
9
+ records middleware installation and constructors reject unverified graphs.
10
+ - Enforce input, tool-call, tool-result, and non-streamed model-output decisions in
11
+ Block mode with safe continuation and a repeated-denial cap. Shadow and Warn report
12
+ decisions without changing content.
13
+ - Enable LangChain tool start/end callbacks by default and send the LangChain run ID
14
+ as correlation metadata alongside a distinct classification request ID per event.
15
+
5
16
  ## 0.6.3 - 2026-09-24
6
17
 
7
18
  - Add an optional `signal` option to `classify()` and `classifyBatch()`.
package/README.md CHANGED
@@ -37,7 +37,7 @@ npm install @silmaril-security/sdk
37
37
  For reproducible installs, pin a tagged release:
38
38
 
39
39
  ```sh
40
- npm install @silmaril-security/sdk@0.6.2
40
+ npm install @silmaril-security/sdk@0.7.0
41
41
  ```
42
42
 
43
43
  Requires Node 20 or later.
@@ -63,6 +63,12 @@ Optional LangChain.js support:
63
63
  npm install @langchain/core @langchain/openai
64
64
  ```
65
65
 
66
+ Optional Deep Agents support:
67
+
68
+ ```sh
69
+ npm install deepagents langchain @langchain/core @langchain/langgraph
70
+ ```
71
+
66
72
  ## Configuration
67
73
 
68
74
  Every `Firewall` client needs two required options:
@@ -353,6 +359,12 @@ preserved as the backend sequence identity. No aliases are inspected. If
353
359
  callers provide `metadata.silmaril`, it must be an object and SDK-reserved keys
354
360
  are overwritten by the SDK.
355
361
 
362
+ The `governance` option on `classify()` and per-item `governance` array on
363
+ `classifyBatch()` send typed agent/resource context. `BlockResult.governance`
364
+ returns the server action, policy version, and optional rule ID. A malicious
365
+ prediction or explicit governance block is blocked in Block mode; legacy
366
+ responses without governance remain valid.
367
+
356
368
  ## Errors
357
369
 
358
370
  - `SilmarilApiError`: thrown when the firewall API responds with a non-2xx or redirect status. Carries `status`, `statusText`, a 64 KiB-capped `body`, and any parsed malformed-input diagnostics. The default error message omits the body to keep logs clean.
@@ -464,6 +476,12 @@ and the LLM call proceeds. Set `failOpen: false` to make API errors bubble up.
464
476
  Blocking decisions still throw `FirewallBlockedException` unless shadow mode is
465
477
  enabled. `PromptBlockedException` continues to work as a deprecated alias for
466
478
  one release.
479
+ Model-start, tool-start, and tool-end hooks are enabled by default; retriever
480
+ hooks remain opt-in. The LangChain run ID is sent as
481
+ `metadata.langgraph.run_id`; every classification gets a distinct
482
+ `metadata.silmaril.request_id`. Supply `conversationId` to the handler for
483
+ sequence identity; it sends `metadata.conversationId`. Callback blocks throw
484
+ and end that graph execution.
467
485
 
468
486
  `asLangChainHandler()` is async because it lazy-loads `@langchain/core` so core
469
487
  users do not pay for it. The root package intentionally exposes a structural
@@ -478,6 +496,37 @@ import { createLangChainHandler } from "@silmaril-security/sdk/adapters/langchai
478
496
  const handler = await createLangChainHandler(fw);
479
497
  ```
480
498
 
499
+ ## Deep Agents
500
+
501
+ ```ts
502
+ import { createProtectedDeepAgent } from "@silmaril-security/sdk/adapters/deepagents";
503
+
504
+ const agent = createProtectedDeepAgent(fw, {
505
+ model, tools,
506
+ subagents: [{ name: "research", description: "Research safely" }],
507
+ silmaril: { conversationId },
508
+ });
509
+ ```
510
+
511
+ The constructor installs checks on the root, general-purpose, and declarative
512
+ subagents. For a compiled subagent, call
513
+ `createProtectedCompiledSubagent(fw, { name: "review", description: "Review",
514
+ model, tools })` and pass its returned spec through
515
+ `protectedCompiledSubagents`. That factory installs middleware before
516
+ compilation. The parent constructor verifies the exact graph and Firewall
517
+ client; it rejects arbitrary compiled runnables. Root custom middleware does
518
+ not automatically reach every subagent.
519
+
520
+ The middleware checks input before model use, tool calls before execution,
521
+ tool results before the next model call, and non-streamed model output before
522
+ the graph consumes it. In Block mode, denied tool interactions become a fixed
523
+ safe `ToolMessage` with the original call ID. The agent can choose an allowed
524
+ alternative; repeated denials end with a fixed safe response. Denied model
525
+ output is replaced. Shadow and Warn report decisions through `onClassify`
526
+ without replacing content. Classification errors allow model and tool execution
527
+ by default; set `silmaril: { failOpen: false }` to require a successful
528
+ classification. Already emitted streaming text cannot be recalled.
529
+
481
530
  ## Retries
482
531
 
483
532
  HTTP 429 responses are retried with exponential backoff capped at 30s, up to 5
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/deepagents.ts
21
+ var deepagents_exports = {};
22
+ __export(deepagents_exports, {
23
+ SAFE_FINAL_MESSAGE: () => SAFE_FINAL_MESSAGE,
24
+ SAFE_OUTPUT_MESSAGE: () => SAFE_OUTPUT_MESSAGE,
25
+ SAFE_TOOL_MESSAGE: () => SAFE_TOOL_MESSAGE,
26
+ createDeepAgentsMiddleware: () => createDeepAgentsMiddleware,
27
+ createProtectedCompiledSubagent: () => createProtectedCompiledSubagent,
28
+ createProtectedDeepAgent: () => createProtectedDeepAgent
29
+ });
30
+ module.exports = __toCommonJS(deepagents_exports);
31
+ var import_messages = require("@langchain/core/messages");
32
+ var import_langgraph = require("@langchain/langgraph");
33
+ var import_deepagents = require("deepagents");
34
+ var import_langchain = require("langchain");
35
+
36
+ // src/hooks.ts
37
+ var HookLabel = {
38
+ USER_INPUT: "user_input",
39
+ SYSTEM_PROMPT: "system_prompt",
40
+ TOOL_CALL: "tool_call",
41
+ TOOL_RESPONSE: "tool_response",
42
+ LLM_OUTPUT: "llm_output",
43
+ UNKNOWN: "unknown"
44
+ };
45
+ var FirewallHook = {
46
+ LLM_START: "on_llm_start",
47
+ CHAT_MODEL_START: "on_chat_model_start",
48
+ TOOL_START: "on_tool_start",
49
+ RETRIEVER_START: "on_retriever_start",
50
+ LLM_END: "on_llm_end",
51
+ TOOL_END: "on_tool_end",
52
+ RETRIEVER_END: "on_retriever_end"
53
+ };
54
+ var DEFAULT_HOOKS = /* @__PURE__ */ new Set([
55
+ FirewallHook.LLM_START,
56
+ FirewallHook.CHAT_MODEL_START,
57
+ FirewallHook.TOOL_START,
58
+ FirewallHook.TOOL_END
59
+ ]);
60
+ var INPUT_HOOKS = /* @__PURE__ */ new Set([
61
+ FirewallHook.LLM_START,
62
+ FirewallHook.CHAT_MODEL_START,
63
+ FirewallHook.TOOL_START,
64
+ FirewallHook.RETRIEVER_START
65
+ ]);
66
+ var OUTPUT_HOOKS = /* @__PURE__ */ new Set([
67
+ FirewallHook.LLM_END,
68
+ FirewallHook.TOOL_END,
69
+ FirewallHook.RETRIEVER_END
70
+ ]);
71
+ var ALL_HOOKS = /* @__PURE__ */ new Set([
72
+ ...INPUT_HOOKS,
73
+ ...OUTPUT_HOOKS
74
+ ]);
75
+ var FIREWALL_HOOK_TO_LABEL = {
76
+ [FirewallHook.CHAT_MODEL_START]: HookLabel.USER_INPUT,
77
+ [FirewallHook.LLM_START]: HookLabel.USER_INPUT,
78
+ [FirewallHook.TOOL_START]: HookLabel.TOOL_CALL,
79
+ [FirewallHook.TOOL_END]: HookLabel.TOOL_RESPONSE,
80
+ [FirewallHook.RETRIEVER_START]: HookLabel.TOOL_CALL,
81
+ [FirewallHook.RETRIEVER_END]: HookLabel.TOOL_RESPONSE,
82
+ [FirewallHook.LLM_END]: HookLabel.LLM_OUTPUT
83
+ };
84
+ var FIREWALL_HOOK_VALUES = new Set(Object.values(FirewallHook));
85
+
86
+ // src/adapters/deepagents.ts
87
+ var SAFE_TOOL_MESSAGE = "Silmaril Firewall blocked this tool interaction. Choose a different safe action.";
88
+ var SAFE_FINAL_MESSAGE = "Silmaril Firewall stopped this request after repeated unsafe actions.";
89
+ var SAFE_OUTPUT_MESSAGE = "Silmaril Firewall blocked this response.";
90
+ var BLOCKED_TOOL_MARKER = "silmaril-firewall:v1:blocked-tool";
91
+ var issuedBlockedMessages = /* @__PURE__ */ new WeakSet();
92
+ var protectedCompiledGraphs = /* @__PURE__ */ new WeakMap();
93
+ function textOf(message) {
94
+ return typeof message.content === "string" ? message.content : JSON.stringify(message.content);
95
+ }
96
+ function textOfStructuredValue(value, seen = /* @__PURE__ */ new WeakSet()) {
97
+ if (value == null) return "";
98
+ if (typeof value !== "object") return String(value);
99
+ if (seen.has(value)) return "[circular]";
100
+ seen.add(value);
101
+ if (Array.isArray(value)) return value.map((item) => textOfStructuredValue(item, seen)).join("\n");
102
+ return Object.entries(value).map(([key, item]) => `${key}: ${textOfStructuredValue(item, seen)}`).join("\n");
103
+ }
104
+ function stripAllowedMarker(result) {
105
+ const strip = (message) => {
106
+ if (message.additional_kwargs?.silmarilBlocked !== BLOCKED_TOOL_MARKER) return message;
107
+ if (issuedBlockedMessages.has(message)) return message;
108
+ const { silmarilBlocked: _marker, ...additional_kwargs } = message.additional_kwargs;
109
+ return new import_messages.ToolMessage({ ...message, additional_kwargs });
110
+ };
111
+ if (import_messages.ToolMessage.isInstance(result)) return strip(result);
112
+ if (result instanceof import_langgraph.Command) {
113
+ const update = result.update;
114
+ if (update && !Array.isArray(update) && "messages" in update && Array.isArray(update.messages)) {
115
+ const originalMessages = update.messages;
116
+ const messages = originalMessages.map((message) => import_messages.ToolMessage.isInstance(message) ? strip(message) : message);
117
+ if (messages.some((message, index) => message !== originalMessages[index])) {
118
+ return new import_langgraph.Command({ ...result, update: { ...update, messages } });
119
+ }
120
+ }
121
+ }
122
+ return result;
123
+ }
124
+ function createDeepAgentsMiddleware(firewall, options = {}) {
125
+ const maxBlockedAttempts = options.maxBlockedAttempts ?? 3;
126
+ if (!Number.isInteger(maxBlockedAttempts) || maxBlockedAttempts < 1) {
127
+ throw new Error("maxBlockedAttempts must be a positive integer");
128
+ }
129
+ const effectiveMode = options.mode ?? firewall.mode;
130
+ const classify = async (text, hook, toolName) => {
131
+ if (!text.trim()) return { enforce: false, mode: effectiveMode };
132
+ try {
133
+ const result = await firewall.classify(text, {
134
+ hook,
135
+ ...toolName === void 0 ? {} : { toolName },
136
+ ...effectiveMode === void 0 ? {} : { mode: effectiveMode },
137
+ ...options.conversationId === void 0 ? {} : { metadata: { conversationId: options.conversationId } }
138
+ });
139
+ const mode = effectiveMode ?? result.mode ?? "block";
140
+ const blocked = result.prediction === "MALICIOUS" || result.governance?.action === "block";
141
+ if (options.onClassify) {
142
+ try {
143
+ options.onClassify({ hook, ...toolName === void 0 ? {} : { toolName }, text, result, blocked, mode, shadowMode: mode === "shadow" });
144
+ } catch {
145
+ }
146
+ }
147
+ return { enforce: blocked && mode === "block", mode };
148
+ } catch (error) {
149
+ if (options.failOpen === false) throw error;
150
+ return { enforce: false, mode: effectiveMode };
151
+ }
152
+ };
153
+ return (0, import_langchain.createMiddleware)({
154
+ name: "SilmarilDeepAgentsMiddleware",
155
+ wrapModelCall: async (request, handler) => {
156
+ const history = request.state.messages;
157
+ let lastUserIndex = -1;
158
+ for (let i = history.length - 1; i >= 0; i--) {
159
+ if (import_messages.HumanMessage.isInstance(history[i])) {
160
+ lastUserIndex = i;
161
+ break;
162
+ }
163
+ }
164
+ const blockedCount = history.slice(lastUserIndex + 1).filter(
165
+ (message) => import_messages.ToolMessage.isInstance(message) && message.content === SAFE_TOOL_MESSAGE && message.additional_kwargs?.silmarilBlocked === BLOCKED_TOOL_MARKER
166
+ ).length;
167
+ const latestUser = [...request.messages].reverse().find(import_messages.HumanMessage.isInstance);
168
+ const inputDecision = latestUser ? await classify(textOf(latestUser), HookLabel.USER_INPUT) : void 0;
169
+ if (inputDecision?.enforce) return new import_messages.AIMessage(SAFE_OUTPUT_MESSAGE);
170
+ if (blockedCount >= maxBlockedAttempts) {
171
+ return new import_messages.AIMessage(SAFE_FINAL_MESSAGE);
172
+ }
173
+ const response = await handler(request);
174
+ if (response instanceof import_langgraph.Command && (await classify(textOfStructuredValue(response.update), HookLabel.LLM_OUTPUT)).enforce) {
175
+ return new import_messages.AIMessage(SAFE_OUTPUT_MESSAGE);
176
+ }
177
+ if (import_messages.AIMessage.isInstance(response) && (await classify(textOf(response), HookLabel.LLM_OUTPUT)).enforce) {
178
+ return new import_messages.AIMessage(SAFE_OUTPUT_MESSAGE);
179
+ }
180
+ return response;
181
+ },
182
+ wrapToolCall: async (request, handler) => {
183
+ const safe = () => {
184
+ const message = new import_messages.ToolMessage({
185
+ content: SAFE_TOOL_MESSAGE,
186
+ tool_call_id: request.toolCall.id ?? "",
187
+ name: request.toolCall.name,
188
+ additional_kwargs: { silmarilBlocked: BLOCKED_TOOL_MARKER }
189
+ });
190
+ issuedBlockedMessages.add(message);
191
+ return message;
192
+ };
193
+ if ((await classify(JSON.stringify(request.toolCall.args ?? {}), HookLabel.TOOL_CALL, request.toolCall.name)).enforce) {
194
+ return safe();
195
+ }
196
+ const result = await handler(request);
197
+ let resultText;
198
+ try {
199
+ resultText = import_messages.ToolMessage.isInstance(result) ? textOf(result) : result instanceof import_langgraph.Command ? textOfStructuredValue(result.update) : String(result);
200
+ } catch {
201
+ const decision = await classify("[uninspectable tool result]", HookLabel.TOOL_RESPONSE, request.toolCall.name);
202
+ return decision.mode === "block" ? safe() : stripAllowedMarker(result);
203
+ }
204
+ if ((await classify(resultText, HookLabel.TOOL_RESPONSE, request.toolCall.name)).enforce) {
205
+ return safe();
206
+ }
207
+ return stripAllowedMarker(result);
208
+ }
209
+ });
210
+ }
211
+ function createProtectedCompiledSubagent(firewall, options) {
212
+ const { name, description, silmaril, middleware = [], ...agentOptions } = options;
213
+ const runnable = (0, import_langchain.createAgent)({
214
+ ...agentOptions,
215
+ middleware: [...middleware, createDeepAgentsMiddleware(firewall, silmaril)]
216
+ });
217
+ protectedCompiledGraphs.set(runnable, firewall);
218
+ return { name, description, runnable };
219
+ }
220
+ function createProtectedDeepAgent(firewall, options = {}) {
221
+ const { silmaril, subagents = [], protectedCompiledSubagents = [], middleware = [], ...agentOptions } = options;
222
+ const protectedSubagents = subagents.map((subagent) => {
223
+ if ("runnable" in subagent || "graphId" in subagent) {
224
+ throw new Error("Compiled or remote subagents must install Silmaril middleware inside their own graph");
225
+ }
226
+ return { ...subagent, middleware: [...subagent.middleware ?? [], createDeepAgentsMiddleware(firewall, silmaril)] };
227
+ });
228
+ if (!protectedSubagents.some((subagent) => subagent.name === import_deepagents.GENERAL_PURPOSE_SUBAGENT.name)) {
229
+ protectedSubagents.unshift({ ...import_deepagents.GENERAL_PURPOSE_SUBAGENT, middleware: [createDeepAgentsMiddleware(firewall, silmaril)] });
230
+ }
231
+ for (const spec of protectedCompiledSubagents) {
232
+ if (!spec.runnable || protectedCompiledGraphs.get(spec.runnable) !== firewall) {
233
+ throw new Error("Compiled subagents must be built with createProtectedCompiledSubagent for this Firewall client");
234
+ }
235
+ }
236
+ return (0, import_deepagents.createDeepAgent)({
237
+ ...agentOptions,
238
+ middleware: [...middleware, createDeepAgentsMiddleware(firewall, silmaril)],
239
+ subagents: [...protectedSubagents, ...protectedCompiledSubagents]
240
+ });
241
+ }
242
+ // Annotate the CommonJS export names for ESM import in node:
243
+ 0 && (module.exports = {
244
+ SAFE_FINAL_MESSAGE,
245
+ SAFE_OUTPUT_MESSAGE,
246
+ SAFE_TOOL_MESSAGE,
247
+ createDeepAgentsMiddleware,
248
+ createProtectedCompiledSubagent,
249
+ createProtectedDeepAgent
250
+ });
251
+ //# sourceMappingURL=deepagents.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/deepagents.ts","../../src/hooks.ts"],"sourcesContent":["// Copyright (c) 2024-2026 Silmaril Security Inc. All rights reserved.\n\n/** Optional Deep Agents integration. Import from @silmaril-security/sdk/adapters/deepagents. */\nimport { AIMessage, HumanMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { Command } from \"@langchain/langgraph\";\nimport { createDeepAgent, GENERAL_PURPOSE_SUBAGENT, type AnySubAgent, type CompiledSubAgent } from \"deepagents\";\nimport { createAgent, createMiddleware, type CreateAgentParams } from \"langchain\";\n\nimport type { Firewall } from \"../firewall.js\";\nimport { HookLabel } from \"../hooks.js\";\nimport type { ClassifyEvent, FirewallMode } from \"../types.js\";\n\nexport const SAFE_TOOL_MESSAGE = \"Silmaril Firewall blocked this tool interaction. Choose a different safe action.\";\nexport const SAFE_FINAL_MESSAGE = \"Silmaril Firewall stopped this request after repeated unsafe actions.\";\nexport const SAFE_OUTPUT_MESSAGE = \"Silmaril Firewall blocked this response.\";\nconst BLOCKED_TOOL_MARKER = \"silmaril-firewall:v1:blocked-tool\";\nconst issuedBlockedMessages = new WeakSet<ToolMessage>();\n\n// A protected graph is identified by the exact runnable returned by our factory.\nconst protectedCompiledGraphs = new WeakMap<object, Firewall>();\n\nexport interface DeepAgentsMiddlewareOptions {\n mode?: FirewallMode;\n failOpen?: boolean;\n maxBlockedAttempts?: number;\n /** A caller-supplied sequence identity; never derived from a LangChain run ID. */\n conversationId?: string;\n onClassify?: (event: ClassifyEvent) => void;\n}\n\nfunction textOf(message: { content: unknown }): string {\n return typeof message.content === \"string\" ? message.content : JSON.stringify(message.content);\n}\n\nfunction textOfStructuredValue(value: unknown, seen = new WeakSet<object>()): string {\n if (value == null) return \"\";\n if (typeof value !== \"object\") return String(value);\n if (seen.has(value)) return \"[circular]\";\n seen.add(value);\n if (Array.isArray(value)) return value.map((item) => textOfStructuredValue(item, seen)).join(\"\\n\");\n return Object.entries(value).map(([key, item]) => `${key}: ${textOfStructuredValue(item, seen)}`).join(\"\\n\");\n}\n\nfunction stripAllowedMarker(result: ToolMessage | Command): ToolMessage | Command {\n const strip = (message: ToolMessage): ToolMessage => {\n if (message.additional_kwargs?.silmarilBlocked !== BLOCKED_TOOL_MARKER) return message;\n if (issuedBlockedMessages.has(message)) return message;\n const { silmarilBlocked: _marker, ...additional_kwargs } = message.additional_kwargs;\n // Tool providers may return frozen messages or metadata. Copy rather\n // than mutating a result owned by the caller.\n return new ToolMessage({ ...message, additional_kwargs });\n };\n if (ToolMessage.isInstance(result)) return strip(result);\n if (result instanceof Command) {\n const update = result.update;\n if (update && !Array.isArray(update) && \"messages\" in update && Array.isArray(update.messages)) {\n const originalMessages = update.messages;\n const messages = originalMessages.map((message) => ToolMessage.isInstance(message) ? strip(message) : message);\n if (messages.some((message, index) => message !== originalMessages[index])) {\n return new Command({ ...result, update: { ...update, messages } });\n }\n }\n }\n return result;\n}\n\nexport function createDeepAgentsMiddleware(firewall: Firewall, options: DeepAgentsMiddlewareOptions = {}) {\n const maxBlockedAttempts = options.maxBlockedAttempts ?? 3;\n if (!Number.isInteger(maxBlockedAttempts) || maxBlockedAttempts < 1) {\n throw new Error(\"maxBlockedAttempts must be a positive integer\");\n }\n const effectiveMode = options.mode ?? firewall.mode;\n const classify = async (text: string, hook: HookLabel, toolName?: string): Promise<{ enforce: boolean; mode: FirewallMode | undefined }> => {\n if (!text.trim()) return { enforce: false, mode: effectiveMode };\n try {\n const result = await firewall.classify(text, {\n hook,\n ...(toolName === undefined ? {} : { toolName }),\n ...(effectiveMode === undefined ? {} : { mode: effectiveMode }),\n ...(options.conversationId === undefined ? {} : { metadata: { conversationId: options.conversationId } }),\n });\n const mode = effectiveMode ?? result.mode ?? \"block\";\n const blocked = result.prediction === \"MALICIOUS\" || result.governance?.action === \"block\";\n if (options.onClassify) {\n try {\n options.onClassify({ hook, ...(toolName === undefined ? {} : { toolName }), text, result, blocked, mode, shadowMode: mode === \"shadow\" });\n } catch {\n // Observation callbacks do not change enforcement.\n }\n }\n return { enforce: blocked && mode === \"block\", mode };\n } catch (error) {\n if (options.failOpen === false) throw error;\n return { enforce: false, mode: effectiveMode };\n }\n };\n\n return createMiddleware({\n name: \"SilmarilDeepAgentsMiddleware\",\n wrapModelCall: async (request, handler) => {\n const history = request.state.messages;\n let lastUserIndex = -1;\n for (let i = history.length - 1; i >= 0; i--) {\n if (HumanMessage.isInstance(history[i])) {\n lastUserIndex = i;\n break;\n }\n }\n const blockedCount = history.slice(lastUserIndex + 1).filter(\n (message) => ToolMessage.isInstance(message) && message.content === SAFE_TOOL_MESSAGE\n && message.additional_kwargs?.silmarilBlocked === BLOCKED_TOOL_MARKER,\n ).length;\n const latestUser = [...request.messages].reverse().find(HumanMessage.isInstance);\n const inputDecision = latestUser\n ? await classify(textOf(latestUser), HookLabel.USER_INPUT)\n : undefined;\n if (inputDecision?.enforce) return new AIMessage(SAFE_OUTPUT_MESSAGE);\n // The marker is added only after a Block decision, so neither an\n // unrelated input mode nor tool output that quotes the safe text affects the cap.\n if (blockedCount >= maxBlockedAttempts) {\n return new AIMessage(SAFE_FINAL_MESSAGE);\n }\n const response = await handler(request);\n if (response instanceof Command && (await classify(textOfStructuredValue(response.update), HookLabel.LLM_OUTPUT)).enforce) {\n return new AIMessage(SAFE_OUTPUT_MESSAGE);\n }\n if (AIMessage.isInstance(response) && (await classify(textOf(response), HookLabel.LLM_OUTPUT)).enforce) {\n return new AIMessage(SAFE_OUTPUT_MESSAGE);\n }\n return response;\n },\n wrapToolCall: async (request, handler) => {\n const safe = () => {\n const message = new ToolMessage({\n content: SAFE_TOOL_MESSAGE,\n tool_call_id: request.toolCall.id ?? \"\",\n name: request.toolCall.name,\n additional_kwargs: { silmarilBlocked: BLOCKED_TOOL_MARKER },\n });\n issuedBlockedMessages.add(message);\n return message;\n };\n if ((await classify(JSON.stringify(request.toolCall.args ?? {}), HookLabel.TOOL_CALL, request.toolCall.name)).enforce) {\n return safe();\n }\n const result = await handler(request);\n let resultText: string;\n try {\n resultText = ToolMessage.isInstance(result) ? textOf(result)\n : result instanceof Command ? textOfStructuredValue(result.update) : String(result);\n } catch {\n // Content cannot be inspected, but the backend still resolves the\n // enforcement mode. Observation modes retain the original result.\n const decision = await classify(\"[uninspectable tool result]\", HookLabel.TOOL_RESPONSE, request.toolCall.name);\n return decision.mode === \"block\" ? safe() : stripAllowedMarker(result);\n }\n if ((await classify(resultText, HookLabel.TOOL_RESPONSE, request.toolCall.name)).enforce) {\n return safe();\n }\n return stripAllowedMarker(result);\n },\n });\n}\n\nexport interface ProtectedCompiledSubagentOptions extends Omit<CreateAgentParams, \"middleware\"> {\n name: string;\n description: string;\n middleware?: CreateAgentParams[\"middleware\"];\n silmaril?: DeepAgentsMiddlewareOptions;\n}\n\n/** Compile a subagent with Silmaril middleware and register that exact graph. */\nexport function createProtectedCompiledSubagent(firewall: Firewall, options: ProtectedCompiledSubagentOptions): CompiledSubAgent {\n const { name, description, silmaril, middleware = [], ...agentOptions } = options;\n const runnable = createAgent({\n ...agentOptions,\n middleware: [...middleware, createDeepAgentsMiddleware(firewall, silmaril)] as const,\n });\n protectedCompiledGraphs.set(runnable, firewall);\n return { name, description, runnable };\n}\n\nexport interface ProtectedDeepAgentOptions extends Omit<NonNullable<Parameters<typeof createDeepAgent>[0]>, \"subagents\" | \"middleware\"> {\n subagents?: readonly AnySubAgent[];\n /** Only pass specs returned by createProtectedCompiledSubagent for this client. */\n protectedCompiledSubagents?: readonly CompiledSubAgent[];\n middleware?: NonNullable<Parameters<typeof createDeepAgent>[0]>[\"middleware\"];\n silmaril?: DeepAgentsMiddlewareOptions;\n}\n\n/** Protect root, default general-purpose, and declarative subagents. */\nexport function createProtectedDeepAgent(firewall: Firewall, options: ProtectedDeepAgentOptions = {}) {\n const { silmaril, subagents = [], protectedCompiledSubagents = [], middleware = [], ...agentOptions } = options;\n const protectedSubagents = subagents.map((subagent) => {\n if (\"runnable\" in subagent || \"graphId\" in subagent) {\n throw new Error(\"Compiled or remote subagents must install Silmaril middleware inside their own graph\");\n }\n return { ...subagent, middleware: [...(subagent.middleware ?? []), createDeepAgentsMiddleware(firewall, silmaril)] };\n });\n if (!protectedSubagents.some((subagent) => subagent.name === GENERAL_PURPOSE_SUBAGENT.name)) {\n protectedSubagents.unshift({ ...GENERAL_PURPOSE_SUBAGENT, middleware: [createDeepAgentsMiddleware(firewall, silmaril)] });\n }\n for (const spec of protectedCompiledSubagents) {\n if (!spec.runnable || protectedCompiledGraphs.get(spec.runnable) !== firewall) {\n throw new Error(\"Compiled subagents must be built with createProtectedCompiledSubagent for this Firewall client\");\n }\n }\n return createDeepAgent({\n ...agentOptions,\n middleware: [...middleware, createDeepAgentsMiddleware(firewall, silmaril)],\n subagents: [...protectedSubagents, ...protectedCompiledSubagents],\n });\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport const HookLabel = {\n USER_INPUT: \"user_input\",\n SYSTEM_PROMPT: \"system_prompt\",\n TOOL_CALL: \"tool_call\",\n TOOL_RESPONSE: \"tool_response\",\n LLM_OUTPUT: \"llm_output\",\n UNKNOWN: \"unknown\",\n} as const;\n\nexport type HookLabel = (typeof HookLabel)[keyof typeof HookLabel];\n\nexport const FirewallHook = {\n LLM_START: \"on_llm_start\",\n CHAT_MODEL_START: \"on_chat_model_start\",\n TOOL_START: \"on_tool_start\",\n RETRIEVER_START: \"on_retriever_start\",\n LLM_END: \"on_llm_end\",\n TOOL_END: \"on_tool_end\",\n RETRIEVER_END: \"on_retriever_end\",\n} as const;\n\nexport type FirewallHook = (typeof FirewallHook)[keyof typeof FirewallHook];\n\nexport const DEFAULT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_START,\n FirewallHook.CHAT_MODEL_START,\n FirewallHook.TOOL_START,\n FirewallHook.TOOL_END,\n]);\n\nexport const INPUT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_START,\n FirewallHook.CHAT_MODEL_START,\n FirewallHook.TOOL_START,\n FirewallHook.RETRIEVER_START,\n]);\n\nexport const OUTPUT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_END,\n FirewallHook.TOOL_END,\n FirewallHook.RETRIEVER_END,\n]);\n\nexport const ALL_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n ...INPUT_HOOKS,\n ...OUTPUT_HOOKS,\n]);\n\nexport const FIREWALL_HOOK_TO_LABEL: Readonly<Record<FirewallHook, HookLabel>> = {\n [FirewallHook.CHAT_MODEL_START]: HookLabel.USER_INPUT,\n [FirewallHook.LLM_START]: HookLabel.USER_INPUT,\n [FirewallHook.TOOL_START]: HookLabel.TOOL_CALL,\n [FirewallHook.TOOL_END]: HookLabel.TOOL_RESPONSE,\n [FirewallHook.RETRIEVER_START]: HookLabel.TOOL_CALL,\n [FirewallHook.RETRIEVER_END]: HookLabel.TOOL_RESPONSE,\n [FirewallHook.LLM_END]: HookLabel.LLM_OUTPUT,\n};\n\nconst FIREWALL_HOOK_VALUES: ReadonlySet<string> = new Set(Object.values(FirewallHook));\n\nexport function resolveHooks(\n hooks: Iterable<FirewallHook | string> | undefined,\n): ReadonlySet<FirewallHook> {\n if (hooks === undefined) {\n return DEFAULT_HOOKS;\n }\n const resolved = new Set<FirewallHook>();\n for (const h of hooks) {\n if (!FIREWALL_HOOK_VALUES.has(h)) {\n throw new Error(`Invalid FirewallHook value: ${String(h)}`);\n }\n resolved.add(h as FirewallHook);\n }\n return resolved;\n}\n\nexport function prependHook(text: string, hook: HookLabel | string | undefined | null): string {\n if (hook === undefined || hook === null) {\n return text;\n }\n if (hook === HookLabel.UNKNOWN) {\n return text;\n }\n return `[HOOK:${hook}] ${text}`;\n}\n\nexport function prependToolName(text: string, toolName: string | undefined | null): string {\n if (toolName === undefined || toolName === null) {\n return text;\n }\n return `[TOOL:${toolName}] ${text}`;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,184 @@
1
+ import * as _langchain_core_language_models_base from '@langchain/core/language_models/base';
2
+ import * as _langchain_core_runnables from '@langchain/core/runnables';
3
+ import * as _langchain_core_messages from '@langchain/core/messages';
4
+ import { ToolMessage, HumanMessage } from '@langchain/core/messages';
5
+ import * as deepagents from 'deepagents';
6
+ import { createDeepAgent, AnySubAgent, CompiledSubAgent } from 'deepagents';
7
+ import * as zod_v4_core from 'zod/v4/core';
8
+ import * as zod from 'zod';
9
+ import * as _langchain_langgraph from '@langchain/langgraph';
10
+ import { Command } from '@langchain/langgraph';
11
+ import * as _langchain_core_utils_types from '@langchain/core/utils/types';
12
+ import * as langchain from 'langchain';
13
+ import { CreateAgentParams } from 'langchain';
14
+ import * as _langchain_core_tools from '@langchain/core/tools';
15
+ import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-CRNFqgMa.cjs';
16
+
17
+ declare const SAFE_TOOL_MESSAGE = "Silmaril Firewall blocked this tool interaction. Choose a different safe action.";
18
+ declare const SAFE_FINAL_MESSAGE = "Silmaril Firewall stopped this request after repeated unsafe actions.";
19
+ declare const SAFE_OUTPUT_MESSAGE = "Silmaril Firewall blocked this response.";
20
+ interface DeepAgentsMiddlewareOptions {
21
+ mode?: FirewallMode;
22
+ failOpen?: boolean;
23
+ maxBlockedAttempts?: number;
24
+ /** A caller-supplied sequence identity; never derived from a LangChain run ID. */
25
+ conversationId?: string;
26
+ onClassify?: (event: ClassifyEvent) => void;
27
+ }
28
+ declare function createDeepAgentsMiddleware(firewall: Firewall, options?: DeepAgentsMiddlewareOptions): langchain.AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly []>;
29
+ interface ProtectedCompiledSubagentOptions extends Omit<CreateAgentParams, "middleware"> {
30
+ name: string;
31
+ description: string;
32
+ middleware?: CreateAgentParams["middleware"];
33
+ silmaril?: DeepAgentsMiddlewareOptions;
34
+ }
35
+ /** Compile a subagent with Silmaril middleware and register that exact graph. */
36
+ declare function createProtectedCompiledSubagent(firewall: Firewall, options: ProtectedCompiledSubagentOptions): CompiledSubAgent;
37
+ interface ProtectedDeepAgentOptions extends Omit<NonNullable<Parameters<typeof createDeepAgent>[0]>, "subagents" | "middleware"> {
38
+ subagents?: readonly AnySubAgent[];
39
+ /** Only pass specs returned by createProtectedCompiledSubagent for this client. */
40
+ protectedCompiledSubagents?: readonly CompiledSubAgent[];
41
+ middleware?: NonNullable<Parameters<typeof createDeepAgent>[0]>["middleware"];
42
+ silmaril?: DeepAgentsMiddlewareOptions;
43
+ }
44
+ /** Protect root, default general-purpose, and declarative subagents. */
45
+ declare function createProtectedDeepAgent(firewall: Firewall, options?: ProtectedDeepAgentOptions): deepagents.DeepAgent<deepagents.DeepAgentTypeConfig<langchain.ResponseFormatUndefined, _langchain_core_utils_types.InteropZodObject | _langchain_langgraph.AnyStateSchema | undefined, _langchain_core_utils_types.InteropZodObject, readonly [langchain.AgentMiddleware<_langchain_langgraph.StateSchema<{
46
+ skillsMetadata: zod.ZodOptional<zod.ZodNullable<zod.ZodArray<zod.ZodObject<{
47
+ name: zod.ZodString;
48
+ description: zod.ZodString;
49
+ path: zod.ZodString;
50
+ license: zod.ZodOptional<zod.ZodNullable<zod.ZodString>>;
51
+ compatibility: zod.ZodOptional<zod.ZodNullable<zod.ZodString>>;
52
+ metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodString>>;
53
+ allowedTools: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
54
+ module: zod.ZodOptional<zod.ZodString>;
55
+ }, zod_v4_core.$strip>>>>;
56
+ files: _langchain_langgraph.ReducedValue<{
57
+ [x: string]: deepagents.FileData;
58
+ } | undefined, {
59
+ [x: string]: deepagents.FileData | null;
60
+ } | undefined>;
61
+ }>, undefined, unknown, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly []>, langchain.AgentMiddleware<_langchain_langgraph.StateSchema<{
62
+ files: _langchain_langgraph.ReducedValue<{
63
+ [x: string]: deepagents.FileData;
64
+ } | undefined, {
65
+ [x: string]: deepagents.FileData | null;
66
+ } | undefined>;
67
+ }>, undefined, unknown, (langchain.DynamicStructuredTool<zod.ZodObject<{
68
+ path: zod.ZodDefault<zod.ZodOptional<zod.ZodString>>;
69
+ }, zod_v4_core.$strip>, {
70
+ path: string;
71
+ }, {
72
+ path?: string | undefined;
73
+ }, string | ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>, unknown, "ls"> | langchain.DynamicStructuredTool<zod.ZodObject<{
74
+ pattern: zod.ZodString;
75
+ path: zod.ZodOptional<zod.ZodString>;
76
+ }, zod_v4_core.$strip>, {
77
+ pattern: string;
78
+ path?: string | undefined;
79
+ }, {
80
+ pattern: string;
81
+ path?: string | undefined;
82
+ }, string | ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>, unknown, "glob"> | langchain.DynamicStructuredTool<zod.ZodObject<{
83
+ pattern: zod.ZodString;
84
+ path: zod.ZodDefault<zod.ZodOptional<zod.ZodString>>;
85
+ glob: zod.ZodDefault<zod.ZodNullable<zod.ZodOptional<zod.ZodString>>>;
86
+ max_count: zod.ZodDefault<zod.ZodNullable<zod.ZodOptional<zod.ZodCoercedNumber<unknown>>>>;
87
+ output_mode: zod.ZodDefault<zod.ZodOptional<zod.ZodEnum<{
88
+ content: "content";
89
+ count: "count";
90
+ files_with_matches: "files_with_matches";
91
+ }>>>;
92
+ }, zod_v4_core.$strip>, {
93
+ pattern: string;
94
+ path: string;
95
+ glob: string | null;
96
+ max_count: number | null;
97
+ output_mode: "content" | "count" | "files_with_matches";
98
+ }, {
99
+ pattern: string;
100
+ path?: string | undefined;
101
+ glob?: string | null | undefined;
102
+ max_count?: unknown;
103
+ output_mode?: "content" | "count" | "files_with_matches" | undefined;
104
+ }, string | ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>, unknown, "grep"> | langchain.DynamicStructuredTool<zod.ZodObject<{
105
+ command: zod.ZodString;
106
+ }, zod_v4_core.$strip>, {
107
+ command: string;
108
+ }, {
109
+ command: string;
110
+ }, string, unknown, "execute"> | langchain.DynamicStructuredTool<zod.ZodPreprocess<zod.ZodObject<{
111
+ file_path: zod.ZodString;
112
+ offset: zod.ZodDefault<zod.ZodOptional<zod.ZodCoercedNumber<unknown>>>;
113
+ limit: zod.ZodDefault<zod.ZodOptional<zod.ZodCoercedNumber<unknown>>>;
114
+ }, zod_v4_core.$strip>, unknown>, {
115
+ file_path: string;
116
+ offset: number;
117
+ limit: number;
118
+ }, unknown, ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>> | {
119
+ type: string;
120
+ text: string;
121
+ }[] | {
122
+ type: string;
123
+ mimeType: string;
124
+ data: string;
125
+ }[], unknown, "read_file"> | langchain.DynamicStructuredTool<zod.ZodPreprocess<zod.ZodObject<{
126
+ file_path: zod.ZodString;
127
+ content: zod.ZodString;
128
+ }, zod_v4_core.$strip>, unknown>, {
129
+ file_path: string;
130
+ content: string;
131
+ }, unknown, string | ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>> | Command<unknown, {
132
+ files: Record<string, deepagents.FileData>;
133
+ messages: ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>[];
134
+ }, string>, unknown, "write_file"> | langchain.DynamicStructuredTool<zod.ZodPreprocess<zod.ZodObject<{
135
+ file_path: zod.ZodString;
136
+ old_string: zod.ZodString;
137
+ new_string: zod.ZodString;
138
+ replace_all: zod.ZodDefault<zod.ZodOptional<zod.ZodBoolean>>;
139
+ }, zod_v4_core.$strip>, unknown>, {
140
+ file_path: string;
141
+ old_string: string;
142
+ new_string: string;
143
+ replace_all: boolean;
144
+ }, unknown, string | ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>> | Command<unknown, {
145
+ files: Record<string, deepagents.FileData>;
146
+ messages: ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>[];
147
+ }, string>, unknown, "edit_file"> | langchain.DynamicStructuredTool<zod.ZodPreprocess<zod.ZodObject<{
148
+ file_path: zod.ZodString;
149
+ }, zod_v4_core.$strip>, unknown>, {
150
+ file_path: string;
151
+ }, unknown, ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>> | Command<unknown, {
152
+ files: Record<string, null>;
153
+ messages: ToolMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>[];
154
+ }, string>, unknown, "delete">)[], readonly []>, langchain.AgentMiddleware<undefined, undefined, unknown, readonly [langchain.DynamicStructuredTool<zod.ZodObject<{
155
+ description: zod.ZodString;
156
+ subagent_type: zod.ZodString;
157
+ }, zod_v4_core.$strip>, {
158
+ description: string;
159
+ subagent_type: string;
160
+ }, {
161
+ description: string;
162
+ subagent_type: string;
163
+ }, string | Command<unknown, Record<string, unknown>, string>, unknown, "task">], readonly []>, langchain.AgentMiddleware<zod.ZodObject<{
164
+ _summarizationSessionId: zod.ZodOptional<zod.ZodString>;
165
+ _summarizationEvent: zod.ZodOptional<zod.ZodObject<{
166
+ cutoffIndex: zod.ZodNumber;
167
+ summaryMessage: zod.ZodCustom<HumanMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>, HumanMessage<_langchain_core_messages.MessageStructure<_langchain_core_messages.MessageToolSet>>>;
168
+ filePath: zod.ZodNullable<zod.ZodString>;
169
+ }, zod_v4_core.$strip>>;
170
+ }, zod_v4_core.$strip>, undefined, unknown, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly []>, langchain.AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly []>, ...langchain.AgentMiddleware<any, any, any, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly (() => _langchain_langgraph.StreamTransformer<any>)[]>[], langchain.AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly []>], readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly (CompiledSubAgent<langchain.ReactAgent<any> | _langchain_core_runnables.Runnable<any, any, _langchain_core_runnables.RunnableConfig<Record<string, any>>>> | {
171
+ middleware: (langchain.AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly []> | langchain.AgentMiddleware<any, any, any, readonly (_langchain_core_tools.ClientTool | _langchain_core_tools.ServerTool)[], readonly (() => _langchain_langgraph.StreamTransformer<any>)[]>)[];
172
+ name: string;
173
+ description: string;
174
+ systemPrompt?: string | langchain.SystemMessage;
175
+ mode?: "isolated" | "fork";
176
+ tools?: langchain.StructuredTool[];
177
+ model?: _langchain_core_language_models_base.LanguageModelLike | string;
178
+ interruptOn?: Record<string, boolean | langchain.InterruptOnConfig>;
179
+ skills?: readonly string[];
180
+ responseFormat?: CreateAgentParams["responseFormat"];
181
+ permissions?: deepagents.FilesystemPermission[];
182
+ })[], readonly (() => _langchain_langgraph.StreamTransformer<any>)[]>>;
183
+
184
+ export { type DeepAgentsMiddlewareOptions, type ProtectedCompiledSubagentOptions, type ProtectedDeepAgentOptions, SAFE_FINAL_MESSAGE, SAFE_OUTPUT_MESSAGE, SAFE_TOOL_MESSAGE, createDeepAgentsMiddleware, createProtectedCompiledSubagent, createProtectedDeepAgent };