@silmaril-security/sdk 0.7.4 → 0.7.6
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 +15 -0
- package/README.md +42 -14
- package/dist/adapters/deepagents.d.cts +1 -1
- package/dist/adapters/deepagents.d.ts +1 -1
- package/dist/adapters/langchain.d.cts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/vercel.d.cts +1 -1
- package/dist/adapters/vercel.d.ts +1 -1
- package/dist/{firewall-CRNFqgMa.d.cts → firewall-CRADRBLY.d.cts} +15 -6
- package/dist/{firewall-CRNFqgMa.d.ts → firewall-CRADRBLY.d.ts} +15 -6
- package/dist/index.cjs +30 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +30 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.6
|
|
4
|
+
|
|
5
|
+
- Send typed governance resources in the runtime's top-level `resource` and
|
|
6
|
+
aligned `resources` fields, preserving compatibility attribution metadata.
|
|
7
|
+
- Reject invalid canonical resource references before submitting a request.
|
|
8
|
+
Caller-supplied agent metadata remains attribution, not authenticated identity.
|
|
9
|
+
|
|
3
10
|
All notable changes to the Silmaril Firewall TypeScript SDK are documented here.
|
|
4
11
|
|
|
12
|
+
## 0.7.5 - 2026-10-12
|
|
13
|
+
|
|
14
|
+
- Correct the mode documentation for current mode-less Gateway responses and
|
|
15
|
+
Python/Rust wire contracts: explicit local client, call, and adapter overrides
|
|
16
|
+
remain authoritative. With no request or response mode, direct TypeScript
|
|
17
|
+
calls return decisions without local enforcement while the Vercel, LangChain,
|
|
18
|
+
and Deep Agents adapters retain their existing Block fallback behavior.
|
|
19
|
+
|
|
5
20
|
## 0.7.4 - 2026-10-09
|
|
6
21
|
|
|
7
22
|
- Ship the corrected README with its reproducible install command pinned to
|
package/README.md
CHANGED
|
@@ -18,8 +18,8 @@ This SDK provides the low-level TypeScript interface for that workflow:
|
|
|
18
18
|
- Classify user input, tool calls, tool responses, model output, or system
|
|
19
19
|
prompt content.
|
|
20
20
|
- Preserve hook and tool-name context for more accurate decisions.
|
|
21
|
-
- Honor backend threat and governance decisions
|
|
22
|
-
Block behavior
|
|
21
|
+
- Honor backend threat and governance decisions while adapters apply their
|
|
22
|
+
effective Shadow, Warn, or Block behavior.
|
|
23
23
|
- Send each complete sanitized event in one request.
|
|
24
24
|
- On individual `classify()` calls, preserve exact `metadata.conversationId` as sequence identity and add one event ID.
|
|
25
25
|
- Retry API rate-limit responses.
|
|
@@ -34,10 +34,10 @@ This SDK is distributed as an npm package.
|
|
|
34
34
|
npm install @silmaril-security/sdk
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
After publication, pin version 0.7.6 for reproducible installs:
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
|
-
npm install @silmaril-security/sdk@0.7.
|
|
40
|
+
npm install @silmaril-security/sdk@0.7.6
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Requires Node 20 or later.
|
|
@@ -241,7 +241,7 @@ interface FirewallOptions {
|
|
|
241
241
|
apiKey: string; // required
|
|
242
242
|
apiUrl: string; // required
|
|
243
243
|
timeoutMs?: number; // default: 10000 ms, max 2147483647
|
|
244
|
-
mode?: "shadow" | "warn" | "block"; //
|
|
244
|
+
mode?: "shadow" | "warn" | "block"; // explicit local client default
|
|
245
245
|
shadowMode?: boolean; // deprecated legacy mapping
|
|
246
246
|
}
|
|
247
247
|
```
|
|
@@ -265,15 +265,31 @@ threshold.
|
|
|
265
265
|
|
|
266
266
|
## Modes
|
|
267
267
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
268
|
+
Mode controls local SDK and adapter handling; the backend remains authoritative
|
|
269
|
+
for threat decisions and thresholds. Explicitly set `mode: "shadow"` or
|
|
270
|
+
`mode: "warn"` when you want observation without adapter enforcement. Set
|
|
271
|
+
`mode: "block"` when you want Block handling.
|
|
272
|
+
|
|
273
|
+
A per-call or per-adapter mode takes precedence over the client mode. Any
|
|
274
|
+
explicit mode is locally authoritative even when the response omits `mode` or
|
|
275
|
+
reports a conflicting value. If no explicit mode is requested, a future
|
|
276
|
+
compatible service can supply the result mode. This is forward compatibility,
|
|
277
|
+
not a statement that current Firewall services return mode.
|
|
278
|
+
|
|
279
|
+
Current Gateway responses omit `mode`, as do the current Python and Rust
|
|
280
|
+
classify wire contracts; callers cannot currently rely on backend mode
|
|
281
|
+
configuration. When a TypeScript request and response both omit mode, direct
|
|
282
|
+
`classify()` and `classifyBatch()` calls return the backend decision without
|
|
283
|
+
enforcing it, and `BlockResult.mode` remains unset. The Vercel middleware and
|
|
284
|
+
LangChain handler retain their existing Block fallback for successful mode-less
|
|
285
|
+
malicious or governance-block decisions. LangChain, Vercel input scanning, and
|
|
286
|
+
Vercel non-streamed output scanning throw `FirewallBlockedException`; Vercel
|
|
287
|
+
streamed-output scanning instead emits an error part carrying that exception in
|
|
288
|
+
the stream. Deep Agents applies its existing Block fallback to a successful
|
|
289
|
+
mode-less decision through its safe replacement and blocked-attempt behavior;
|
|
290
|
+
classification errors remain fail-open by default. In the Python and Go SDKs,
|
|
291
|
+
direct calls retain their existing Block enforcement when both the request and
|
|
292
|
+
response omit mode.
|
|
277
293
|
|
|
278
294
|
```ts
|
|
279
295
|
import { wrapLanguageModel, generateText } from "ai";
|
|
@@ -621,3 +637,15 @@ npm publish --access public
|
|
|
621
637
|
|
|
622
638
|
This SDK is distributed under the license terms in [LICENSE](LICENSE). It is not
|
|
623
639
|
permissive open source.
|
|
640
|
+
|
|
641
|
+
## Governance resource requests
|
|
642
|
+
|
|
643
|
+
Typed governance resources are sent in the classify request's top-level
|
|
644
|
+
`resource` field or aligned nullable `resources` array for batch calls. Resource
|
|
645
|
+
IDs must be non-empty; MCP tools also require their canonical server parent ID.
|
|
646
|
+
The compatibility metadata copy remains attribution only. Caller agent metadata
|
|
647
|
+
does not supply an authenticated principal.
|
|
648
|
+
|
|
649
|
+
This source prepares version 0.7.6. Its registry install command becomes
|
|
650
|
+
available after the authorized main-branch release workflow publishes the package.
|
|
651
|
+
Confirm registry publication before installing this version.
|
|
@@ -12,7 +12,7 @@ import * as _langchain_core_utils_types from '@langchain/core/utils/types';
|
|
|
12
12
|
import * as langchain from 'langchain';
|
|
13
13
|
import { CreateAgentParams } from 'langchain';
|
|
14
14
|
import * as _langchain_core_tools from '@langchain/core/tools';
|
|
15
|
-
import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-
|
|
15
|
+
import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-CRADRBLY.cjs';
|
|
16
16
|
|
|
17
17
|
declare const SAFE_TOOL_MESSAGE = "Silmaril Firewall blocked this tool interaction. Choose a different safe action.";
|
|
18
18
|
declare const SAFE_FINAL_MESSAGE = "Silmaril Firewall stopped this request after repeated unsafe actions.";
|
|
@@ -12,7 +12,7 @@ import * as _langchain_core_utils_types from '@langchain/core/utils/types';
|
|
|
12
12
|
import * as langchain from 'langchain';
|
|
13
13
|
import { CreateAgentParams } from 'langchain';
|
|
14
14
|
import * as _langchain_core_tools from '@langchain/core/tools';
|
|
15
|
-
import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-
|
|
15
|
+
import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-CRADRBLY.js';
|
|
16
16
|
|
|
17
17
|
declare const SAFE_TOOL_MESSAGE = "Silmaril Firewall blocked this tool interaction. Choose a different safe action.";
|
|
18
18
|
declare const SAFE_FINAL_MESSAGE = "Silmaril Firewall stopped this request after repeated unsafe actions.";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
2
|
-
import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-
|
|
2
|
+
import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-CRADRBLY.cjs';
|
|
3
3
|
|
|
4
4
|
declare function createLangChainHandler(firewall: Firewall, options?: LangChainAdapterOptions): Promise<BaseCallbackHandler>;
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
2
|
-
import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-
|
|
2
|
+
import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-CRADRBLY.js';
|
|
3
3
|
|
|
4
4
|
declare function createLangChainHandler(firewall: Firewall, options?: LangChainAdapterOptions): Promise<BaseCallbackHandler>;
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-
|
|
1
|
+
export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-CRADRBLY.cjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-
|
|
1
|
+
export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-CRADRBLY.js';
|
|
@@ -74,11 +74,15 @@ type Prediction = "BENIGN" | "MALICIOUS";
|
|
|
74
74
|
type FirewallMode = "shadow" | "warn" | "block";
|
|
75
75
|
type GovernanceAction = "allow" | "block";
|
|
76
76
|
type GovernanceResourceKind = "agent" | "tool" | "mcp_server" | "mcp_tool" | "plugin" | "skill" | "extension";
|
|
77
|
-
|
|
78
|
-
readonly kind:
|
|
79
|
-
readonly id
|
|
80
|
-
readonly parentId
|
|
81
|
-
}
|
|
77
|
+
type GovernanceResource = {
|
|
78
|
+
readonly kind: "mcp_tool";
|
|
79
|
+
readonly id: string;
|
|
80
|
+
readonly parentId: string;
|
|
81
|
+
} | {
|
|
82
|
+
readonly kind: Exclude<GovernanceResourceKind, "mcp_tool">;
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly parentId?: never;
|
|
85
|
+
};
|
|
82
86
|
interface GovernanceContext {
|
|
83
87
|
readonly agent?: string;
|
|
84
88
|
readonly resource?: GovernanceResource;
|
|
@@ -92,7 +96,7 @@ interface BlockResult {
|
|
|
92
96
|
readonly prediction: Prediction;
|
|
93
97
|
readonly score: number;
|
|
94
98
|
readonly threshold: number;
|
|
95
|
-
/** Omitted
|
|
99
|
+
/** Omitted when neither an explicit local override nor the response supplies a mode. */
|
|
96
100
|
readonly mode?: FirewallMode;
|
|
97
101
|
readonly primaryOutcome?: PrimaryOutcome;
|
|
98
102
|
readonly outcomeScores?: Readonly<Partial<Record<HarmfulOutcome, number>>>;
|
|
@@ -104,12 +108,14 @@ interface FirewallOptions {
|
|
|
104
108
|
apiKey: string;
|
|
105
109
|
apiUrl: string;
|
|
106
110
|
timeoutMs?: number;
|
|
111
|
+
/** Explicit local client default; a per-call or per-adapter mode takes precedence. */
|
|
107
112
|
mode?: FirewallMode;
|
|
108
113
|
/** @deprecated Use mode: "shadow" or mode: "block". */
|
|
109
114
|
shadowMode?: boolean;
|
|
110
115
|
}
|
|
111
116
|
type ClassificationMetadata = Readonly<Record<string, unknown>>;
|
|
112
117
|
interface ClassifyOptions {
|
|
118
|
+
/** Explicit local per-call override; authoritative over any response mode. */
|
|
113
119
|
mode?: FirewallMode;
|
|
114
120
|
hook?: HookLabel;
|
|
115
121
|
toolName?: string;
|
|
@@ -123,6 +129,7 @@ interface ClassifyOptions {
|
|
|
123
129
|
signal?: AbortSignal;
|
|
124
130
|
}
|
|
125
131
|
interface ClassifyBatchOptions {
|
|
132
|
+
/** Explicit local per-call override; authoritative over every response mode. */
|
|
126
133
|
mode?: FirewallMode;
|
|
127
134
|
hooks?: readonly HookLabel[];
|
|
128
135
|
toolNames?: readonly (string | undefined)[];
|
|
@@ -143,6 +150,7 @@ interface LangChainAdapterOptions {
|
|
|
143
150
|
includeTool?: boolean;
|
|
144
151
|
failOpen?: boolean;
|
|
145
152
|
logger?: (message: string, error: unknown) => void;
|
|
153
|
+
/** Explicit local adapter override; takes precedence over the client and response modes. */
|
|
146
154
|
mode?: FirewallMode;
|
|
147
155
|
/** @deprecated Use mode: "shadow" or mode: "block". */
|
|
148
156
|
shadowMode?: boolean;
|
|
@@ -175,6 +183,7 @@ interface MiddlewareOptions {
|
|
|
175
183
|
scanInput?: boolean;
|
|
176
184
|
scanOutput?: boolean;
|
|
177
185
|
scanToolCalls?: boolean;
|
|
186
|
+
/** Explicit local adapter override; takes precedence over the client and response modes. */
|
|
178
187
|
mode?: FirewallMode;
|
|
179
188
|
/** @deprecated Use mode: "shadow" or mode: "block". */
|
|
180
189
|
shadowMode?: boolean;
|
|
@@ -74,11 +74,15 @@ type Prediction = "BENIGN" | "MALICIOUS";
|
|
|
74
74
|
type FirewallMode = "shadow" | "warn" | "block";
|
|
75
75
|
type GovernanceAction = "allow" | "block";
|
|
76
76
|
type GovernanceResourceKind = "agent" | "tool" | "mcp_server" | "mcp_tool" | "plugin" | "skill" | "extension";
|
|
77
|
-
|
|
78
|
-
readonly kind:
|
|
79
|
-
readonly id
|
|
80
|
-
readonly parentId
|
|
81
|
-
}
|
|
77
|
+
type GovernanceResource = {
|
|
78
|
+
readonly kind: "mcp_tool";
|
|
79
|
+
readonly id: string;
|
|
80
|
+
readonly parentId: string;
|
|
81
|
+
} | {
|
|
82
|
+
readonly kind: Exclude<GovernanceResourceKind, "mcp_tool">;
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly parentId?: never;
|
|
85
|
+
};
|
|
82
86
|
interface GovernanceContext {
|
|
83
87
|
readonly agent?: string;
|
|
84
88
|
readonly resource?: GovernanceResource;
|
|
@@ -92,7 +96,7 @@ interface BlockResult {
|
|
|
92
96
|
readonly prediction: Prediction;
|
|
93
97
|
readonly score: number;
|
|
94
98
|
readonly threshold: number;
|
|
95
|
-
/** Omitted
|
|
99
|
+
/** Omitted when neither an explicit local override nor the response supplies a mode. */
|
|
96
100
|
readonly mode?: FirewallMode;
|
|
97
101
|
readonly primaryOutcome?: PrimaryOutcome;
|
|
98
102
|
readonly outcomeScores?: Readonly<Partial<Record<HarmfulOutcome, number>>>;
|
|
@@ -104,12 +108,14 @@ interface FirewallOptions {
|
|
|
104
108
|
apiKey: string;
|
|
105
109
|
apiUrl: string;
|
|
106
110
|
timeoutMs?: number;
|
|
111
|
+
/** Explicit local client default; a per-call or per-adapter mode takes precedence. */
|
|
107
112
|
mode?: FirewallMode;
|
|
108
113
|
/** @deprecated Use mode: "shadow" or mode: "block". */
|
|
109
114
|
shadowMode?: boolean;
|
|
110
115
|
}
|
|
111
116
|
type ClassificationMetadata = Readonly<Record<string, unknown>>;
|
|
112
117
|
interface ClassifyOptions {
|
|
118
|
+
/** Explicit local per-call override; authoritative over any response mode. */
|
|
113
119
|
mode?: FirewallMode;
|
|
114
120
|
hook?: HookLabel;
|
|
115
121
|
toolName?: string;
|
|
@@ -123,6 +129,7 @@ interface ClassifyOptions {
|
|
|
123
129
|
signal?: AbortSignal;
|
|
124
130
|
}
|
|
125
131
|
interface ClassifyBatchOptions {
|
|
132
|
+
/** Explicit local per-call override; authoritative over every response mode. */
|
|
126
133
|
mode?: FirewallMode;
|
|
127
134
|
hooks?: readonly HookLabel[];
|
|
128
135
|
toolNames?: readonly (string | undefined)[];
|
|
@@ -143,6 +150,7 @@ interface LangChainAdapterOptions {
|
|
|
143
150
|
includeTool?: boolean;
|
|
144
151
|
failOpen?: boolean;
|
|
145
152
|
logger?: (message: string, error: unknown) => void;
|
|
153
|
+
/** Explicit local adapter override; takes precedence over the client and response modes. */
|
|
146
154
|
mode?: FirewallMode;
|
|
147
155
|
/** @deprecated Use mode: "shadow" or mode: "block". */
|
|
148
156
|
shadowMode?: boolean;
|
|
@@ -175,6 +183,7 @@ interface MiddlewareOptions {
|
|
|
175
183
|
scanInput?: boolean;
|
|
176
184
|
scanOutput?: boolean;
|
|
177
185
|
scanToolCalls?: boolean;
|
|
186
|
+
/** Explicit local adapter override; takes precedence over the client and response modes. */
|
|
178
187
|
mode?: FirewallMode;
|
|
179
188
|
/** @deprecated Use mode: "shadow" or mode: "block". */
|
|
180
189
|
shadowMode?: boolean;
|
package/dist/index.cjs
CHANGED
|
@@ -818,7 +818,7 @@ function sanitizeText(text) {
|
|
|
818
818
|
}
|
|
819
819
|
|
|
820
820
|
// src/firewall.ts
|
|
821
|
-
var SDK_VERSION = "0.7.
|
|
821
|
+
var SDK_VERSION = "0.7.6";
|
|
822
822
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
823
823
|
var DEFAULT_MAX_RETRIES = 5;
|
|
824
824
|
var MAX_BACKOFF_SECONDS = 30;
|
|
@@ -894,15 +894,31 @@ function withSdkMetadata(metadata, info) {
|
|
|
894
894
|
};
|
|
895
895
|
return payload;
|
|
896
896
|
}
|
|
897
|
+
function governanceResourceToWire(resource) {
|
|
898
|
+
if (!["agent", "tool", "mcp_server", "mcp_tool", "plugin", "skill", "extension"].includes(resource.kind)) {
|
|
899
|
+
throw new Error("Firewall: invalid governance resource kind");
|
|
900
|
+
}
|
|
901
|
+
if (typeof resource.id !== "string" || !resource.id.trim()) {
|
|
902
|
+
throw new Error("Firewall: governance resource id must be a non-empty string");
|
|
903
|
+
}
|
|
904
|
+
if (resource.kind === "mcp_tool") {
|
|
905
|
+
if (typeof resource.parentId !== "string" || !resource.parentId.trim()) {
|
|
906
|
+
throw new Error("Firewall: mcp_tool resource requires a non-empty parentId");
|
|
907
|
+
}
|
|
908
|
+
} else if (resource.parentId !== void 0) {
|
|
909
|
+
throw new Error("Firewall: parentId is valid only for mcp_tool resources");
|
|
910
|
+
}
|
|
911
|
+
return {
|
|
912
|
+
kind: resource.kind,
|
|
913
|
+
id: resource.id,
|
|
914
|
+
...resource.parentId === void 0 ? {} : { parent_id: resource.parentId }
|
|
915
|
+
};
|
|
916
|
+
}
|
|
897
917
|
function governanceContextToWire(context) {
|
|
898
918
|
return {
|
|
899
919
|
...context.agent === void 0 ? {} : { agent: context.agent },
|
|
900
920
|
...context.resource === void 0 ? {} : {
|
|
901
|
-
resource:
|
|
902
|
-
kind: context.resource.kind,
|
|
903
|
-
...context.resource.id === void 0 ? {} : { id: context.resource.id },
|
|
904
|
-
...context.resource.parentId === void 0 ? {} : { parent_id: context.resource.parentId }
|
|
905
|
-
}
|
|
921
|
+
resource: governanceResourceToWire(context.resource)
|
|
906
922
|
}
|
|
907
923
|
};
|
|
908
924
|
}
|
|
@@ -1122,6 +1138,11 @@ var Firewall = class {
|
|
|
1122
1138
|
...options.governance?.[index] === void 0 ? {} : { governance: options.governance[index] }
|
|
1123
1139
|
})
|
|
1124
1140
|
);
|
|
1141
|
+
if (options.governance !== void 0) {
|
|
1142
|
+
payload.resources = options.governance.map(
|
|
1143
|
+
(context) => context?.resource === void 0 ? null : governanceResourceToWire(context.resource)
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1125
1146
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1126
1147
|
if (!Array.isArray(data.predictions)) {
|
|
1127
1148
|
throw new Error("Firewall: response predictions must be an array");
|
|
@@ -1190,6 +1211,9 @@ var Firewall = class {
|
|
|
1190
1211
|
if (options.toolName !== void 0) {
|
|
1191
1212
|
payload.tool_name = options.toolName;
|
|
1192
1213
|
}
|
|
1214
|
+
if (options.governance?.resource !== void 0) {
|
|
1215
|
+
payload.resource = governanceResourceToWire(options.governance.resource);
|
|
1216
|
+
}
|
|
1193
1217
|
payload.metadata = withSdkMetadata(options.metadata, {
|
|
1194
1218
|
...metadataInfo,
|
|
1195
1219
|
...options.governance === void 0 ? {} : { governance: options.governance }
|