@neuraltrust/trustguard-sdk 0.1.5 → 0.1.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/README.md CHANGED
@@ -33,7 +33,8 @@ if (response.isBlocked) {
33
33
 
34
34
  ```typescript
35
35
  const response = await client.guard({
36
- payload: { input: "user text" },
36
+ // A model response goes in an assistant message; `{ input }` is read as the user's text.
37
+ payload: { messages: [{ role: "assistant", content: "model response" }] },
37
38
  direction: "output", // "input" (default) or "output"
38
39
  protocol: "llm", // "all" (default), "llm", "mcp", or "a2a"
39
40
  sessionId: "conversation-42", // groups multi-turn traffic
@@ -88,7 +89,7 @@ import { openai } from "@ai-sdk/openai";
88
89
  import { TrustGuard } from "@neuraltrust/trustguard-sdk";
89
90
  import { trustguard } from "@neuraltrust/trustguard-sdk/ai-sdk";
90
91
 
91
- const client = new TrustGuard({ baseUrl: process.env.TRUSTGUARD_URL!, apiKey: process.env.TRUSTGUARD_API_KEY! });
92
+ const client = new TrustGuard({ baseUrl: process.env.TRUSTGUARD_BASE_URL!, apiKey: process.env.TRUSTGUARD_API_KEY! });
92
93
 
93
94
  // One instance per request, so every evaluation carries the user and the conversation.
94
95
  const tg = trustguard(client, { consumerId: user.id, sessionId: chatId });
@@ -97,6 +98,7 @@ const result = streamText({
97
98
  model: wrapLanguageModel({ model: openai("gpt-5.2"), middleware: tg.middleware }),
98
99
  tools: tg.tools(tools),
99
100
  toolApproval: tg.toolApproval,
101
+ experimental_toolApprovalSecret: process.env.TOOL_APPROVAL_SECRET, // signs approval requests
100
102
  messages,
101
103
  });
102
104
  ```
@@ -110,12 +112,16 @@ const result = streamText({
110
112
 
111
113
  Steps that continue a tool loop are not evaluated as prompts again: the tool results in them are covered by `tools()`. Wrap MCP tools the same way: `tg.tools(await mcpClient.tools())`.
112
114
 
115
+ A complete Next.js app, with approvals and a live verdict panel, is in [`examples/ai-sdk`](../examples/ai-sdk).
116
+
113
117
  **Streaming.** By default a streamed response is monitored: text streams untouched and is evaluated when the response finishes, so findings reach **Activity** but nothing is enforced. `stream: "buffer"` holds each text block until it ends, evaluates it, then releases it, masked or replaced. That enforces the policy and gives up streaming.
114
118
 
115
119
  **Failures.** With the default `failMode: "closed"`, an evaluation error throws on the prompt and the response, and denies the tool call. `failMode: "open"` lets the traffic through. `onError` sees every error either way, and `onVerdict` every verdict.
116
120
 
117
121
  **Not evaluated.** The system prompt, which your code writes. Files in the user turn, such as images and PDFs: only their text parts are sent. Reasoning parts of the response, which pass through unchanged.
118
122
 
123
+ **Approvals.** The answer to an approval request comes back in the message history the browser sends. Set the AI SDK's `experimental_toolApprovalSecret` so it signs each request and a client cannot forge an approval. When the answer arrives, the AI SDK calls `toolApproval` again: a call the policy now blocks stays denied even after the user allowed it.
124
+
119
125
  **Composing approvals.** `toolApproval` returns `undefined` when TrustGuard lets a call through, so your own rules can follow it:
120
126
 
121
127
  ```typescript
@@ -136,7 +136,7 @@ var Guard = class {
136
136
  throw new TrustGuardBlockedError("input", response, reasonFor(response, "Prompt blocked by TrustGuard"));
137
137
  }
138
138
  if (status !== "transform") return params;
139
- const masked = transformedText(response);
139
+ const masked = transformedText(response, sentInput);
140
140
  if (masked === void 0) {
141
141
  throw new TrustGuardBlockedError(
142
142
  "input",
@@ -159,7 +159,7 @@ var Guard = class {
159
159
  let response;
160
160
  try {
161
161
  response = await this.#evaluate("output", {
162
- payload: { input: text },
162
+ payload: assistantTurn(text),
163
163
  direction: "output",
164
164
  protocol: "llm",
165
165
  attributes: modelAttributes(model)
@@ -169,7 +169,7 @@ var Guard = class {
169
169
  throw error;
170
170
  }
171
171
  if (response.status === "block") return this.#blockedMessage();
172
- if (response.status === "transform") return transformedText(response) ?? this.#blockedMessage();
172
+ if (response.status === "transform") return transformedText(response, sentAssistant) ?? this.#blockedMessage();
173
173
  return void 0;
174
174
  }
175
175
  #monitorStream(model) {
@@ -178,7 +178,7 @@ var Guard = class {
178
178
  if (!text.trim()) return;
179
179
  try {
180
180
  await this.#evaluate("output", {
181
- payload: { input: text },
181
+ payload: assistantTurn(text),
182
182
  direction: "output",
183
183
  protocol: "llm",
184
184
  attributes: modelAttributes(model)
@@ -244,7 +244,7 @@ var Guard = class {
244
244
  let response;
245
245
  try {
246
246
  response = await this.#evaluate("tool-result", {
247
- payload: { input: text },
247
+ payload: toolsResult(text),
248
248
  direction: "output",
249
249
  protocol: "mcp",
250
250
  attributes: { tool: { name: toolName } }
@@ -261,7 +261,7 @@ var Guard = class {
261
261
  );
262
262
  }
263
263
  if (response.status !== "transform") return output;
264
- const masked = transformedText(response);
264
+ const masked = transformedText(response, sentToolResult);
265
265
  if (masked === void 0) {
266
266
  throw new TrustGuardBlockedError(
267
267
  "tool-result",
@@ -330,9 +330,25 @@ function replaceText(parts, text) {
330
330
  }
331
331
  return out;
332
332
  }
333
- function transformedText(response) {
334
- const input = response.transformedPayload?.input;
335
- return typeof input === "string" ? input : void 0;
333
+ function transformedText(response, at) {
334
+ const payload = response.transformedPayload;
335
+ const text = payload ? at(payload) : void 0;
336
+ return typeof text === "string" ? text : void 0;
337
+ }
338
+ var sentInput = (payload) => payload.input;
339
+ var sentAssistant = (payload) => firstItem(payload.messages)?.content;
340
+ var sentToolResult = (payload) => firstItem(asRecord(payload.result)?.content)?.text;
341
+ function firstItem(value) {
342
+ return Array.isArray(value) ? asRecord(value[0]) : void 0;
343
+ }
344
+ function asRecord(value) {
345
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
346
+ }
347
+ function assistantTurn(text) {
348
+ return { messages: [{ role: "assistant", content: text }] };
349
+ }
350
+ function toolsResult(text) {
351
+ return { jsonrpc: "2.0", id: 1, result: { content: [{ type: "text", text }] } };
336
352
  }
337
353
  function toolsCall(name, input) {
338
354
  const args = input !== null && typeof input === "object" && !Array.isArray(input) ? input : { input };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ai-sdk/index.ts","../../src/ai-sdk/trustguard.ts"],"sourcesContent":["export { trustguard, TrustGuardBlockedError } from \"./trustguard.js\";\nexport type { ApprovalToolCall, GuardPhase, TrustGuardAISDK, TrustGuardAISDKOptions } from \"./trustguard.js\";\n","import type {\n LanguageModelV4,\n LanguageModelV4CallOptions,\n LanguageModelV4Content,\n LanguageModelV4Middleware,\n LanguageModelV4Prompt,\n LanguageModelV4StreamPart,\n} from \"@ai-sdk/provider\";\nimport type { ToolApprovalStatus, ToolSet } from \"ai\";\n\nimport type { TrustGuard } from \"../client.js\";\nimport type { GuardRequest, GuardResponse } from \"../types.js\";\n\n/** Where in the agent loop an evaluation ran. */\nexport type GuardPhase = \"input\" | \"output\" | \"tool-call\" | \"tool-result\";\n\n/** Options for {@link trustguard}. Create one instance per request so every evaluation carries the right user. */\nexport interface TrustGuardAISDKOptions {\n /** The end user the request runs for. Findings are grouped under it and gates match it as `consumer.id`. */\n consumerId?: string;\n /** The conversation key. Without it TrustGuard synthesises one per evaluation and turns lose their grouping. */\n sessionId?: string;\n /** Extra attributes merged into every evaluation, for gates and rule conditions. */\n attributes?: Record<string, unknown>;\n /**\n * How streamed responses are guarded.\n * - `\"monitor\"` (default): text streams untouched and is evaluated when the response finishes. Findings are recorded, nothing is enforced.\n * - `\"buffer\"`: each text block is held until it ends, evaluated, then released, redacted or replaced. Enforces the policy at the cost of streaming.\n */\n stream?: \"monitor\" | \"buffer\";\n /** What an `ask` verdict on the prompt does. The model call has no one to ask, so the default is `\"block\"`. */\n promptAsk?: \"block\" | \"allow\";\n /** What an `ask` verdict on a tool call does. The default, `\"user-approval\"`, asks the user through the AI SDK approval flow. */\n toolAsk?: \"user-approval\" | \"deny\";\n /** Text that replaces a response the policy blocked. */\n blockedMessage?: string;\n /**\n * What happens when TrustGuard cannot be reached or returns an error.\n * `\"closed\"` (default) throws on the prompt and the response and denies the tool call. `\"open\"` lets the traffic through.\n * Monitor-mode stream evaluations never fail the stream.\n */\n failMode?: \"closed\" | \"open\";\n /** Called with every verdict, for logging. */\n onVerdict?: (event: { phase: GuardPhase; response: GuardResponse }) => void;\n /** Called with every evaluation error, including the ones `failMode: \"open\"` swallows. */\n onError?: (event: { phase: GuardPhase; error: unknown }) => void;\n}\n\n/** Thrown when the policy blocks the prompt or the response, and by guarded tools whose result was withheld. */\nexport class TrustGuardBlockedError extends Error {\n readonly phase: GuardPhase;\n readonly response: GuardResponse;\n\n constructor(phase: GuardPhase, response: GuardResponse, message: string) {\n super(message);\n this.name = \"TrustGuardBlockedError\";\n this.phase = phase;\n this.response = response;\n }\n}\n\n/** The tool call the approval function receives. Structural, so it matches static and dynamic tool calls alike. */\nexport interface ApprovalToolCall {\n toolName: string;\n toolCallId: string;\n input: unknown;\n}\n\nexport interface TrustGuardAISDK {\n /** Language model middleware for `wrapLanguageModel`: guards the prompt and the response. */\n middleware: LanguageModelV4Middleware;\n /** A `toolApproval` function for `generateText` / `streamText`: guards each tool call before it runs. */\n toolApproval: (options: { toolCall: ApprovalToolCall }) => Promise<ToolApprovalStatus>;\n /** Wraps a tool set so every result is evaluated before the model reads it. */\n tools: <TOOLS extends ToolSet>(tools: TOOLS) => TOOLS;\n}\n\nconst SOURCE_APPLICATION = \"vercel-ai-sdk\";\nconst DEFAULT_BLOCKED_MESSAGE = \"This response was blocked by policy.\";\n\n/**\n * Connects a TrustGuard client to the Vercel AI SDK.\n *\n * ```ts\n * const tg = trustguard(client, { consumerId: user.id, sessionId: chatId });\n * streamText({\n * model: wrapLanguageModel({ model, middleware: tg.middleware }),\n * tools: tg.tools(tools),\n * toolApproval: tg.toolApproval,\n * messages,\n * });\n * ```\n */\nexport function trustguard(client: TrustGuard, options: TrustGuardAISDKOptions = {}): TrustGuardAISDK {\n const guard = new Guard(client, options);\n return {\n middleware: guard.middleware(),\n toolApproval: (approval) => guard.approveToolCall(approval.toolCall),\n tools: (tools) => guard.wrapTools(tools),\n };\n}\n\nclass Guard {\n readonly #client: TrustGuard;\n readonly #options: TrustGuardAISDKOptions;\n\n constructor(client: TrustGuard, options: TrustGuardAISDKOptions) {\n this.#client = client;\n this.#options = options;\n }\n\n middleware(): LanguageModelV4Middleware {\n return {\n specificationVersion: \"v4\",\n transformParams: async ({ params, model }) => this.#guardPrompt(params, model),\n wrapGenerate: async ({ doGenerate, model }) => {\n const result = await doGenerate();\n return { ...result, content: await this.#guardContent(result.content, model) };\n },\n wrapStream: async ({ doStream, model }) => {\n const result = await doStream();\n const transform =\n this.#options.stream === \"buffer\" ? this.#bufferStream(model) : this.#monitorStream(model);\n return { ...result, stream: result.stream.pipeThrough(transform) };\n },\n };\n }\n\n async approveToolCall(call: ApprovalToolCall): Promise<ToolApprovalStatus> {\n let response: GuardResponse | undefined;\n try {\n response = await this.#evaluate(\"tool-call\", {\n payload: toolsCall(call.toolName, call.input),\n direction: \"input\",\n protocol: \"mcp\",\n attributes: { tool: { name: call.toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-call\", error)) return undefined;\n return { type: \"denied\", reason: \"TrustGuard could not evaluate this tool call.\" };\n }\n\n switch (response.status) {\n case \"block\":\n return { type: \"denied\", reason: reasonFor(response, \"Blocked by TrustGuard\") };\n case \"ask\":\n return this.#options.toolAsk === \"deny\"\n ? { type: \"denied\", reason: reasonFor(response, \"TrustGuard requires approval\") }\n : { type: \"user-approval\", reason: reasonFor(response, \"TrustGuard requires approval\") };\n case \"transform\":\n // Approval cannot rewrite the arguments, and running the call unredacted would leak what the policy masks.\n return {\n type: \"denied\",\n reason: reasonFor(response, \"Blocked by TrustGuard because the arguments contain data the policy masks\"),\n };\n default:\n return undefined;\n }\n }\n\n wrapTools<TOOLS extends ToolSet>(tools: TOOLS): TOOLS {\n const wrapped: Record<string, unknown> = {};\n for (const [name, tool] of Object.entries(tools)) {\n const execute = tool.execute as ((input: unknown, options: unknown) => unknown) | undefined;\n if (typeof execute !== \"function\") {\n wrapped[name] = tool;\n continue;\n }\n wrapped[name] = {\n ...tool,\n execute: (input: unknown, executeOptions: unknown) => {\n const output = execute.call(tool, input, executeOptions);\n return isAsyncIterable(output)\n ? this.#guardIterableResult(name, output)\n : Promise.resolve(output).then((value) => this.#guardResult(name, value));\n },\n };\n }\n return wrapped as TOOLS;\n }\n\n async #guardPrompt(params: LanguageModelV4CallOptions, model: LanguageModelV4): Promise<LanguageModelV4CallOptions> {\n const index = lastUserTurn(params.prompt);\n if (index < 0) return params;\n const message = params.prompt[index] as Extract<LanguageModelV4Prompt[number], { role: \"user\" }>;\n const text = joinText(message.content);\n if (!text.trim()) return params;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"input\", {\n payload: { input: text },\n direction: \"input\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"input\", error)) return params;\n throw error;\n }\n\n const status = response.status === \"ask\" && this.#options.promptAsk !== \"allow\" ? \"block\" : response.status;\n if (status === \"block\") {\n throw new TrustGuardBlockedError(\"input\", response, reasonFor(response, \"Prompt blocked by TrustGuard\"));\n }\n if (status !== \"transform\") return params;\n\n const masked = transformedText(response);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"input\",\n response,\n \"Prompt blocked by TrustGuard: the policy masked it but returned no masked text\",\n );\n }\n const prompt = [...params.prompt];\n prompt[index] = { ...message, content: replaceText(message.content, masked) };\n return { ...params, prompt };\n }\n\n async #guardContent(content: LanguageModelV4Content[], model: LanguageModelV4): Promise<LanguageModelV4Content[]> {\n const text = joinText(content);\n if (!text.trim()) return content;\n\n const replacement = await this.#outputReplacement(text, model);\n return replacement === undefined ? content : replaceText(content, replacement);\n }\n\n /** The text that must replace a response, or undefined when it can go out as is. Throws when failing closed. */\n async #outputReplacement(text: string, model: LanguageModelV4): Promise<string | undefined> {\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"output\", {\n payload: { input: text },\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"output\", error)) return undefined;\n throw error;\n }\n if (response.status === \"block\") return this.#blockedMessage();\n if (response.status === \"transform\") return transformedText(response) ?? this.#blockedMessage();\n return undefined;\n }\n\n #monitorStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n let text = \"\";\n const evaluate = async () => {\n if (!text.trim()) return;\n try {\n await this.#evaluate(\"output\", {\n payload: { input: text },\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n this.#options.onError?.({ phase: \"output\", error });\n }\n };\n return new TransformStream({\n transform(part, controller) {\n if (part.type === \"text-delta\") text += part.delta;\n controller.enqueue(part);\n },\n // The stream does not close until this resolves, so a serverless function stays alive until the evaluation is sent.\n async flush() {\n await evaluate();\n },\n });\n }\n\n #bufferStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n const open = new Map<string, LanguageModelV4StreamPart[]>();\n const release = async (\n id: string,\n end: LanguageModelV4StreamPart | undefined,\n controller: TransformStreamDefaultController<LanguageModelV4StreamPart>,\n ) => {\n const parts = open.get(id) ?? [];\n open.delete(id);\n const text = parts.map((p) => (p.type === \"text-delta\" ? p.delta : \"\")).join(\"\");\n const replacement = text.trim() ? await this.#outputReplacement(text, model) : undefined;\n if (replacement === undefined) {\n for (const p of parts) controller.enqueue(p);\n } else {\n for (const p of parts) if (p.type !== \"text-delta\") controller.enqueue(p);\n controller.enqueue({ type: \"text-delta\", id, delta: replacement });\n }\n if (end) controller.enqueue(end);\n };\n return new TransformStream({\n async transform(part, controller) {\n switch (part.type) {\n case \"text-start\":\n open.set(part.id, [part]);\n return;\n case \"text-delta\": {\n const parts = open.get(part.id);\n if (parts) parts.push(part);\n else controller.enqueue(part);\n return;\n }\n case \"text-end\":\n if (open.has(part.id)) await release(part.id, part, controller);\n else controller.enqueue(part);\n return;\n default:\n controller.enqueue(part);\n }\n },\n async flush(controller) {\n // A stream that ends without text-end still goes through the policy before anything is released.\n for (const id of [...open.keys()]) await release(id, undefined, controller);\n },\n });\n }\n\n async #guardResult(toolName: string, output: unknown): Promise<unknown> {\n const text = typeof output === \"string\" ? output : JSON.stringify(output);\n if (text === undefined || !text.trim()) return output;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"tool-result\", {\n payload: { input: text },\n direction: \"output\",\n protocol: \"mcp\",\n attributes: { tool: { name: toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-result\", error)) return output;\n throw error;\n }\n\n if (response.status === \"block\") {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n reasonFor(response, `TrustGuard withheld the result of ${toolName}`),\n );\n }\n if (response.status !== \"transform\") return output;\n\n const masked = transformedText(response);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n `TrustGuard withheld the result of ${toolName}: the policy masked it but returned no masked text`,\n );\n }\n if (typeof output === \"string\") return masked;\n try {\n return JSON.parse(masked) as unknown;\n } catch {\n return masked;\n }\n }\n\n async *#guardIterableResult(toolName: string, output: AsyncIterable<unknown>): AsyncGenerator<unknown> {\n // Preliminary outputs reach the UI only. The last one is what the model reads, so that is the one guarded:\n // when the policy changes it, the guarded value is yielded after it and becomes the final output.\n let last: unknown;\n let seen = false;\n for await (const value of output) {\n last = value;\n seen = true;\n yield value;\n }\n if (!seen) return;\n const guarded = await this.#guardResult(toolName, last);\n if (guarded !== last) yield guarded;\n }\n\n async #evaluate(phase: GuardPhase, request: GuardRequest): Promise<GuardResponse> {\n const response = await this.#client.guard({\n ...request,\n sessionId: this.#options.sessionId,\n consumerId: this.#options.consumerId,\n attributes: {\n ...this.#options.attributes,\n ...request.attributes,\n source: { application: SOURCE_APPLICATION },\n },\n });\n this.#options.onVerdict?.({ phase, response });\n return response;\n }\n\n #failOpen(phase: GuardPhase, error: unknown): boolean {\n this.#options.onError?.({ phase, error });\n return this.#options.failMode === \"open\";\n }\n\n #blockedMessage(): string {\n return this.#options.blockedMessage ?? DEFAULT_BLOCKED_MESSAGE;\n }\n}\n\n/** Index of the user message that starts this model call, or -1 when the call continues a tool loop. */\nfunction lastUserTurn(prompt: LanguageModelV4Prompt): number {\n const last = prompt.length - 1;\n return last >= 0 && prompt[last]?.role === \"user\" ? last : -1;\n}\n\ntype TextLike = { type: string; text?: string };\n\nfunction joinText(parts: readonly TextLike[]): string {\n return parts\n .filter((p) => p.type === \"text\" && typeof p.text === \"string\")\n .map((p) => p.text)\n .join(\"\\n\");\n}\n\n/** Puts `text` in place of the first text part and drops the others, keeping every non-text part where it was. */\nfunction replaceText<T extends TextLike>(parts: readonly T[], text: string): T[] {\n let placed = false;\n const out: T[] = [];\n for (const part of parts) {\n if (part.type !== \"text\") {\n out.push(part);\n } else if (!placed) {\n out.push({ ...part, text });\n placed = true;\n }\n }\n return out;\n}\n\nfunction transformedText(response: GuardResponse): string | undefined {\n const input = response.transformedPayload?.input;\n return typeof input === \"string\" ? input : undefined;\n}\n\nfunction toolsCall(name: string, input: unknown): Record<string, unknown> {\n const args = input !== null && typeof input === \"object\" && !Array.isArray(input) ? input : { input };\n return { jsonrpc: \"2.0\", id: 1, method: \"tools/call\", params: { name, arguments: args } };\n}\n\nfunction modelAttributes(model: LanguageModelV4): Record<string, unknown> {\n return { model: { name: model.modelId, provider: model.provider } };\n}\n\n/** `reason`, followed by the gate or detector that produced the verdict when the response names one. */\nfunction reasonFor(response: GuardResponse, reason: string): string {\n const finding =\n response.findings.find((f) => f.outcome?.action === response.status) ?? response.findings.find((f) => f.outcome);\n const name = finding?.source.gateName || finding?.source.detectorName || finding?.signal?.type;\n return name ? `${reason}: ${name}` : reason;\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return value !== null && typeof value === \"object\" && Symbol.asyncIterator in value;\n}\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/ai-sdk/index.ts","../../src/ai-sdk/trustguard.ts"],"sourcesContent":["export { trustguard, TrustGuardBlockedError } from \"./trustguard.js\";\nexport type { ApprovalToolCall, GuardPhase, TrustGuardAISDK, TrustGuardAISDKOptions } from \"./trustguard.js\";\n","import type {\n LanguageModelV4,\n LanguageModelV4CallOptions,\n LanguageModelV4Content,\n LanguageModelV4Middleware,\n LanguageModelV4Prompt,\n LanguageModelV4StreamPart,\n} from \"@ai-sdk/provider\";\nimport type { ToolApprovalStatus, ToolSet } from \"ai\";\n\nimport type { TrustGuard } from \"../client.js\";\nimport type { GuardRequest, GuardResponse } from \"../types.js\";\n\n/** Where in the agent loop an evaluation ran. */\nexport type GuardPhase = \"input\" | \"output\" | \"tool-call\" | \"tool-result\";\n\n/** Options for {@link trustguard}. Create one instance per request so every evaluation carries the right user. */\nexport interface TrustGuardAISDKOptions {\n /** The end user the request runs for. Findings are grouped under it and gates match it as `consumer.id`. */\n consumerId?: string;\n /** The conversation key. Without it TrustGuard synthesises one per evaluation and turns lose their grouping. */\n sessionId?: string;\n /** Extra attributes merged into every evaluation, for gates and rule conditions. */\n attributes?: Record<string, unknown>;\n /**\n * How streamed responses are guarded.\n * - `\"monitor\"` (default): text streams untouched and is evaluated when the response finishes. Findings are recorded, nothing is enforced.\n * - `\"buffer\"`: each text block is held until it ends, evaluated, then released, redacted or replaced. Enforces the policy at the cost of streaming.\n */\n stream?: \"monitor\" | \"buffer\";\n /** What an `ask` verdict on the prompt does. The model call has no one to ask, so the default is `\"block\"`. */\n promptAsk?: \"block\" | \"allow\";\n /** What an `ask` verdict on a tool call does. The default, `\"user-approval\"`, asks the user through the AI SDK approval flow. */\n toolAsk?: \"user-approval\" | \"deny\";\n /** Text that replaces a response the policy blocked. */\n blockedMessage?: string;\n /**\n * What happens when TrustGuard cannot be reached or returns an error.\n * `\"closed\"` (default) throws on the prompt and the response and denies the tool call. `\"open\"` lets the traffic through.\n * Monitor-mode stream evaluations never fail the stream.\n */\n failMode?: \"closed\" | \"open\";\n /** Called with every verdict, for logging. */\n onVerdict?: (event: { phase: GuardPhase; response: GuardResponse }) => void;\n /** Called with every evaluation error, including the ones `failMode: \"open\"` swallows. */\n onError?: (event: { phase: GuardPhase; error: unknown }) => void;\n}\n\n/** Thrown when the policy blocks the prompt or the response, and by guarded tools whose result was withheld. */\nexport class TrustGuardBlockedError extends Error {\n readonly phase: GuardPhase;\n readonly response: GuardResponse;\n\n constructor(phase: GuardPhase, response: GuardResponse, message: string) {\n super(message);\n this.name = \"TrustGuardBlockedError\";\n this.phase = phase;\n this.response = response;\n }\n}\n\n/** The tool call the approval function receives. Structural, so it matches static and dynamic tool calls alike. */\nexport interface ApprovalToolCall {\n toolName: string;\n toolCallId: string;\n input: unknown;\n}\n\nexport interface TrustGuardAISDK {\n /** Language model middleware for `wrapLanguageModel`: guards the prompt and the response. */\n middleware: LanguageModelV4Middleware;\n /** A `toolApproval` function for `generateText` / `streamText`: guards each tool call before it runs. */\n toolApproval: (options: { toolCall: ApprovalToolCall }) => Promise<ToolApprovalStatus>;\n /** Wraps a tool set so every result is evaluated before the model reads it. */\n tools: <TOOLS extends ToolSet>(tools: TOOLS) => TOOLS;\n}\n\nconst SOURCE_APPLICATION = \"vercel-ai-sdk\";\nconst DEFAULT_BLOCKED_MESSAGE = \"This response was blocked by policy.\";\n\n/**\n * Connects a TrustGuard client to the Vercel AI SDK.\n *\n * ```ts\n * const tg = trustguard(client, { consumerId: user.id, sessionId: chatId });\n * streamText({\n * model: wrapLanguageModel({ model, middleware: tg.middleware }),\n * tools: tg.tools(tools),\n * toolApproval: tg.toolApproval,\n * messages,\n * });\n * ```\n */\nexport function trustguard(client: TrustGuard, options: TrustGuardAISDKOptions = {}): TrustGuardAISDK {\n const guard = new Guard(client, options);\n return {\n middleware: guard.middleware(),\n toolApproval: (approval) => guard.approveToolCall(approval.toolCall),\n tools: (tools) => guard.wrapTools(tools),\n };\n}\n\nclass Guard {\n readonly #client: TrustGuard;\n readonly #options: TrustGuardAISDKOptions;\n\n constructor(client: TrustGuard, options: TrustGuardAISDKOptions) {\n this.#client = client;\n this.#options = options;\n }\n\n middleware(): LanguageModelV4Middleware {\n return {\n specificationVersion: \"v4\",\n transformParams: async ({ params, model }) => this.#guardPrompt(params, model),\n wrapGenerate: async ({ doGenerate, model }) => {\n const result = await doGenerate();\n return { ...result, content: await this.#guardContent(result.content, model) };\n },\n wrapStream: async ({ doStream, model }) => {\n const result = await doStream();\n const transform =\n this.#options.stream === \"buffer\" ? this.#bufferStream(model) : this.#monitorStream(model);\n return { ...result, stream: result.stream.pipeThrough(transform) };\n },\n };\n }\n\n async approveToolCall(call: ApprovalToolCall): Promise<ToolApprovalStatus> {\n let response: GuardResponse | undefined;\n try {\n response = await this.#evaluate(\"tool-call\", {\n payload: toolsCall(call.toolName, call.input),\n direction: \"input\",\n protocol: \"mcp\",\n attributes: { tool: { name: call.toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-call\", error)) return undefined;\n return { type: \"denied\", reason: \"TrustGuard could not evaluate this tool call.\" };\n }\n\n switch (response.status) {\n case \"block\":\n return { type: \"denied\", reason: reasonFor(response, \"Blocked by TrustGuard\") };\n case \"ask\":\n return this.#options.toolAsk === \"deny\"\n ? { type: \"denied\", reason: reasonFor(response, \"TrustGuard requires approval\") }\n : { type: \"user-approval\", reason: reasonFor(response, \"TrustGuard requires approval\") };\n case \"transform\":\n // Approval cannot rewrite the arguments, and running the call unredacted would leak what the policy masks.\n return {\n type: \"denied\",\n reason: reasonFor(response, \"Blocked by TrustGuard because the arguments contain data the policy masks\"),\n };\n default:\n return undefined;\n }\n }\n\n wrapTools<TOOLS extends ToolSet>(tools: TOOLS): TOOLS {\n const wrapped: Record<string, unknown> = {};\n for (const [name, tool] of Object.entries(tools)) {\n const execute = tool.execute as ((input: unknown, options: unknown) => unknown) | undefined;\n if (typeof execute !== \"function\") {\n wrapped[name] = tool;\n continue;\n }\n wrapped[name] = {\n ...tool,\n execute: (input: unknown, executeOptions: unknown) => {\n const output = execute.call(tool, input, executeOptions);\n return isAsyncIterable(output)\n ? this.#guardIterableResult(name, output)\n : Promise.resolve(output).then((value) => this.#guardResult(name, value));\n },\n };\n }\n return wrapped as TOOLS;\n }\n\n async #guardPrompt(params: LanguageModelV4CallOptions, model: LanguageModelV4): Promise<LanguageModelV4CallOptions> {\n const index = lastUserTurn(params.prompt);\n if (index < 0) return params;\n const message = params.prompt[index] as Extract<LanguageModelV4Prompt[number], { role: \"user\" }>;\n const text = joinText(message.content);\n if (!text.trim()) return params;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"input\", {\n payload: { input: text },\n direction: \"input\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"input\", error)) return params;\n throw error;\n }\n\n const status = response.status === \"ask\" && this.#options.promptAsk !== \"allow\" ? \"block\" : response.status;\n if (status === \"block\") {\n throw new TrustGuardBlockedError(\"input\", response, reasonFor(response, \"Prompt blocked by TrustGuard\"));\n }\n if (status !== \"transform\") return params;\n\n const masked = transformedText(response, sentInput);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"input\",\n response,\n \"Prompt blocked by TrustGuard: the policy masked it but returned no masked text\",\n );\n }\n const prompt = [...params.prompt];\n prompt[index] = { ...message, content: replaceText(message.content, masked) };\n return { ...params, prompt };\n }\n\n async #guardContent(content: LanguageModelV4Content[], model: LanguageModelV4): Promise<LanguageModelV4Content[]> {\n const text = joinText(content);\n if (!text.trim()) return content;\n\n const replacement = await this.#outputReplacement(text, model);\n return replacement === undefined ? content : replaceText(content, replacement);\n }\n\n /** The text that must replace a response, or undefined when it can go out as is. Throws when failing closed. */\n async #outputReplacement(text: string, model: LanguageModelV4): Promise<string | undefined> {\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"output\", {\n payload: assistantTurn(text),\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"output\", error)) return undefined;\n throw error;\n }\n if (response.status === \"block\") return this.#blockedMessage();\n if (response.status === \"transform\") return transformedText(response, sentAssistant) ?? this.#blockedMessage();\n return undefined;\n }\n\n #monitorStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n let text = \"\";\n const evaluate = async () => {\n if (!text.trim()) return;\n try {\n await this.#evaluate(\"output\", {\n payload: assistantTurn(text),\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n this.#options.onError?.({ phase: \"output\", error });\n }\n };\n return new TransformStream({\n transform(part, controller) {\n if (part.type === \"text-delta\") text += part.delta;\n controller.enqueue(part);\n },\n // The stream does not close until this resolves, so a serverless function stays alive until the evaluation is sent.\n async flush() {\n await evaluate();\n },\n });\n }\n\n #bufferStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n const open = new Map<string, LanguageModelV4StreamPart[]>();\n const release = async (\n id: string,\n end: LanguageModelV4StreamPart | undefined,\n controller: TransformStreamDefaultController<LanguageModelV4StreamPart>,\n ) => {\n const parts = open.get(id) ?? [];\n open.delete(id);\n const text = parts.map((p) => (p.type === \"text-delta\" ? p.delta : \"\")).join(\"\");\n const replacement = text.trim() ? await this.#outputReplacement(text, model) : undefined;\n if (replacement === undefined) {\n for (const p of parts) controller.enqueue(p);\n } else {\n for (const p of parts) if (p.type !== \"text-delta\") controller.enqueue(p);\n controller.enqueue({ type: \"text-delta\", id, delta: replacement });\n }\n if (end) controller.enqueue(end);\n };\n return new TransformStream({\n async transform(part, controller) {\n switch (part.type) {\n case \"text-start\":\n open.set(part.id, [part]);\n return;\n case \"text-delta\": {\n const parts = open.get(part.id);\n if (parts) parts.push(part);\n else controller.enqueue(part);\n return;\n }\n case \"text-end\":\n if (open.has(part.id)) await release(part.id, part, controller);\n else controller.enqueue(part);\n return;\n default:\n controller.enqueue(part);\n }\n },\n async flush(controller) {\n // A stream that ends without text-end still goes through the policy before anything is released.\n for (const id of [...open.keys()]) await release(id, undefined, controller);\n },\n });\n }\n\n async #guardResult(toolName: string, output: unknown): Promise<unknown> {\n const text = typeof output === \"string\" ? output : JSON.stringify(output);\n if (text === undefined || !text.trim()) return output;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"tool-result\", {\n payload: toolsResult(text),\n direction: \"output\",\n protocol: \"mcp\",\n attributes: { tool: { name: toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-result\", error)) return output;\n throw error;\n }\n\n if (response.status === \"block\") {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n reasonFor(response, `TrustGuard withheld the result of ${toolName}`),\n );\n }\n if (response.status !== \"transform\") return output;\n\n const masked = transformedText(response, sentToolResult);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n `TrustGuard withheld the result of ${toolName}: the policy masked it but returned no masked text`,\n );\n }\n if (typeof output === \"string\") return masked;\n try {\n return JSON.parse(masked) as unknown;\n } catch {\n return masked;\n }\n }\n\n async *#guardIterableResult(toolName: string, output: AsyncIterable<unknown>): AsyncGenerator<unknown> {\n // Preliminary outputs reach the UI only. The last one is what the model reads, so that is the one guarded:\n // when the policy changes it, the guarded value is yielded after it and becomes the final output.\n let last: unknown;\n let seen = false;\n for await (const value of output) {\n last = value;\n seen = true;\n yield value;\n }\n if (!seen) return;\n const guarded = await this.#guardResult(toolName, last);\n if (guarded !== last) yield guarded;\n }\n\n async #evaluate(phase: GuardPhase, request: GuardRequest): Promise<GuardResponse> {\n const response = await this.#client.guard({\n ...request,\n sessionId: this.#options.sessionId,\n consumerId: this.#options.consumerId,\n attributes: {\n ...this.#options.attributes,\n ...request.attributes,\n source: { application: SOURCE_APPLICATION },\n },\n });\n this.#options.onVerdict?.({ phase, response });\n return response;\n }\n\n #failOpen(phase: GuardPhase, error: unknown): boolean {\n this.#options.onError?.({ phase, error });\n return this.#options.failMode === \"open\";\n }\n\n #blockedMessage(): string {\n return this.#options.blockedMessage ?? DEFAULT_BLOCKED_MESSAGE;\n }\n}\n\n/** Index of the user message that starts this model call, or -1 when the call continues a tool loop. */\nfunction lastUserTurn(prompt: LanguageModelV4Prompt): number {\n const last = prompt.length - 1;\n return last >= 0 && prompt[last]?.role === \"user\" ? last : -1;\n}\n\ntype TextLike = { type: string; text?: string };\n\nfunction joinText(parts: readonly TextLike[]): string {\n return parts\n .filter((p) => p.type === \"text\" && typeof p.text === \"string\")\n .map((p) => p.text)\n .join(\"\\n\");\n}\n\n/** Puts `text` in place of the first text part and drops the others, keeping every non-text part where it was. */\nfunction replaceText<T extends TextLike>(parts: readonly T[], text: string): T[] {\n let placed = false;\n const out: T[] = [];\n for (const part of parts) {\n if (part.type !== \"text\") {\n out.push(part);\n } else if (!placed) {\n out.push({ ...part, text });\n placed = true;\n }\n }\n return out;\n}\n\ntype Payload = Record<string, unknown>;\n\n/** The masked text of a transform verdict. TrustGuard returns the payload it was sent, rewritten, so `at` reads it from where it was sent. */\nfunction transformedText(response: GuardResponse, at: (payload: Payload) => unknown): string | undefined {\n const payload = response.transformedPayload;\n const text = payload ? at(payload) : undefined;\n return typeof text === \"string\" ? text : undefined;\n}\n\nconst sentInput = (payload: Payload): unknown => payload.input;\nconst sentAssistant = (payload: Payload): unknown => firstItem(payload.messages)?.content;\nconst sentToolResult = (payload: Payload): unknown => firstItem(asRecord(payload.result)?.content)?.text;\n\nfunction firstItem(value: unknown): Payload | undefined {\n return Array.isArray(value) ? asRecord(value[0]) : undefined;\n}\n\nfunction asRecord(value: unknown): Payload | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) ? (value as Payload) : undefined;\n}\n\n// TrustGuard reads `{ input }` as the user's message, so on output Toxicity Detection and Custom Moderation would skip the\n// response. It is sent as the assistant turn it is.\nfunction assistantTurn(text: string): Payload {\n return { messages: [{ role: \"assistant\", content: text }] };\n}\n\n// An MCP payload must be a JSON-RPC envelope, so a tool result is sent as the result of the call that produced it.\nfunction toolsResult(text: string): Payload {\n return { jsonrpc: \"2.0\", id: 1, result: { content: [{ type: \"text\", text }] } };\n}\n\nfunction toolsCall(name: string, input: unknown): Record<string, unknown> {\n const args = input !== null && typeof input === \"object\" && !Array.isArray(input) ? input : { input };\n return { jsonrpc: \"2.0\", id: 1, method: \"tools/call\", params: { name, arguments: args } };\n}\n\nfunction modelAttributes(model: LanguageModelV4): Record<string, unknown> {\n return { model: { name: model.modelId, provider: model.provider } };\n}\n\n/** `reason`, followed by the gate or detector that produced the verdict when the response names one. */\nfunction reasonFor(response: GuardResponse, reason: string): string {\n const finding =\n response.findings.find((f) => f.outcome?.action === response.status) ?? response.findings.find((f) => f.outcome);\n const name = finding?.source.gateName || finding?.source.detectorName || finding?.signal?.type;\n return name ? `${reason}: ${name}` : reason;\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return value !== null && typeof value === \"object\" && Symbol.asyncIterator in value;\n}\n\n"],"mappings":"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","names":[]}
@@ -109,7 +109,7 @@ var Guard = class {
109
109
  throw new TrustGuardBlockedError("input", response, reasonFor(response, "Prompt blocked by TrustGuard"));
110
110
  }
111
111
  if (status !== "transform") return params;
112
- const masked = transformedText(response);
112
+ const masked = transformedText(response, sentInput);
113
113
  if (masked === void 0) {
114
114
  throw new TrustGuardBlockedError(
115
115
  "input",
@@ -132,7 +132,7 @@ var Guard = class {
132
132
  let response;
133
133
  try {
134
134
  response = await this.#evaluate("output", {
135
- payload: { input: text },
135
+ payload: assistantTurn(text),
136
136
  direction: "output",
137
137
  protocol: "llm",
138
138
  attributes: modelAttributes(model)
@@ -142,7 +142,7 @@ var Guard = class {
142
142
  throw error;
143
143
  }
144
144
  if (response.status === "block") return this.#blockedMessage();
145
- if (response.status === "transform") return transformedText(response) ?? this.#blockedMessage();
145
+ if (response.status === "transform") return transformedText(response, sentAssistant) ?? this.#blockedMessage();
146
146
  return void 0;
147
147
  }
148
148
  #monitorStream(model) {
@@ -151,7 +151,7 @@ var Guard = class {
151
151
  if (!text.trim()) return;
152
152
  try {
153
153
  await this.#evaluate("output", {
154
- payload: { input: text },
154
+ payload: assistantTurn(text),
155
155
  direction: "output",
156
156
  protocol: "llm",
157
157
  attributes: modelAttributes(model)
@@ -217,7 +217,7 @@ var Guard = class {
217
217
  let response;
218
218
  try {
219
219
  response = await this.#evaluate("tool-result", {
220
- payload: { input: text },
220
+ payload: toolsResult(text),
221
221
  direction: "output",
222
222
  protocol: "mcp",
223
223
  attributes: { tool: { name: toolName } }
@@ -234,7 +234,7 @@ var Guard = class {
234
234
  );
235
235
  }
236
236
  if (response.status !== "transform") return output;
237
- const masked = transformedText(response);
237
+ const masked = transformedText(response, sentToolResult);
238
238
  if (masked === void 0) {
239
239
  throw new TrustGuardBlockedError(
240
240
  "tool-result",
@@ -303,9 +303,25 @@ function replaceText(parts, text) {
303
303
  }
304
304
  return out;
305
305
  }
306
- function transformedText(response) {
307
- const input = response.transformedPayload?.input;
308
- return typeof input === "string" ? input : void 0;
306
+ function transformedText(response, at) {
307
+ const payload = response.transformedPayload;
308
+ const text = payload ? at(payload) : void 0;
309
+ return typeof text === "string" ? text : void 0;
310
+ }
311
+ var sentInput = (payload) => payload.input;
312
+ var sentAssistant = (payload) => firstItem(payload.messages)?.content;
313
+ var sentToolResult = (payload) => firstItem(asRecord(payload.result)?.content)?.text;
314
+ function firstItem(value) {
315
+ return Array.isArray(value) ? asRecord(value[0]) : void 0;
316
+ }
317
+ function asRecord(value) {
318
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
319
+ }
320
+ function assistantTurn(text) {
321
+ return { messages: [{ role: "assistant", content: text }] };
322
+ }
323
+ function toolsResult(text) {
324
+ return { jsonrpc: "2.0", id: 1, result: { content: [{ type: "text", text }] } };
309
325
  }
310
326
  function toolsCall(name, input) {
311
327
  const args = input !== null && typeof input === "object" && !Array.isArray(input) ? input : { input };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ai-sdk/trustguard.ts"],"sourcesContent":["import type {\n LanguageModelV4,\n LanguageModelV4CallOptions,\n LanguageModelV4Content,\n LanguageModelV4Middleware,\n LanguageModelV4Prompt,\n LanguageModelV4StreamPart,\n} from \"@ai-sdk/provider\";\nimport type { ToolApprovalStatus, ToolSet } from \"ai\";\n\nimport type { TrustGuard } from \"../client.js\";\nimport type { GuardRequest, GuardResponse } from \"../types.js\";\n\n/** Where in the agent loop an evaluation ran. */\nexport type GuardPhase = \"input\" | \"output\" | \"tool-call\" | \"tool-result\";\n\n/** Options for {@link trustguard}. Create one instance per request so every evaluation carries the right user. */\nexport interface TrustGuardAISDKOptions {\n /** The end user the request runs for. Findings are grouped under it and gates match it as `consumer.id`. */\n consumerId?: string;\n /** The conversation key. Without it TrustGuard synthesises one per evaluation and turns lose their grouping. */\n sessionId?: string;\n /** Extra attributes merged into every evaluation, for gates and rule conditions. */\n attributes?: Record<string, unknown>;\n /**\n * How streamed responses are guarded.\n * - `\"monitor\"` (default): text streams untouched and is evaluated when the response finishes. Findings are recorded, nothing is enforced.\n * - `\"buffer\"`: each text block is held until it ends, evaluated, then released, redacted or replaced. Enforces the policy at the cost of streaming.\n */\n stream?: \"monitor\" | \"buffer\";\n /** What an `ask` verdict on the prompt does. The model call has no one to ask, so the default is `\"block\"`. */\n promptAsk?: \"block\" | \"allow\";\n /** What an `ask` verdict on a tool call does. The default, `\"user-approval\"`, asks the user through the AI SDK approval flow. */\n toolAsk?: \"user-approval\" | \"deny\";\n /** Text that replaces a response the policy blocked. */\n blockedMessage?: string;\n /**\n * What happens when TrustGuard cannot be reached or returns an error.\n * `\"closed\"` (default) throws on the prompt and the response and denies the tool call. `\"open\"` lets the traffic through.\n * Monitor-mode stream evaluations never fail the stream.\n */\n failMode?: \"closed\" | \"open\";\n /** Called with every verdict, for logging. */\n onVerdict?: (event: { phase: GuardPhase; response: GuardResponse }) => void;\n /** Called with every evaluation error, including the ones `failMode: \"open\"` swallows. */\n onError?: (event: { phase: GuardPhase; error: unknown }) => void;\n}\n\n/** Thrown when the policy blocks the prompt or the response, and by guarded tools whose result was withheld. */\nexport class TrustGuardBlockedError extends Error {\n readonly phase: GuardPhase;\n readonly response: GuardResponse;\n\n constructor(phase: GuardPhase, response: GuardResponse, message: string) {\n super(message);\n this.name = \"TrustGuardBlockedError\";\n this.phase = phase;\n this.response = response;\n }\n}\n\n/** The tool call the approval function receives. Structural, so it matches static and dynamic tool calls alike. */\nexport interface ApprovalToolCall {\n toolName: string;\n toolCallId: string;\n input: unknown;\n}\n\nexport interface TrustGuardAISDK {\n /** Language model middleware for `wrapLanguageModel`: guards the prompt and the response. */\n middleware: LanguageModelV4Middleware;\n /** A `toolApproval` function for `generateText` / `streamText`: guards each tool call before it runs. */\n toolApproval: (options: { toolCall: ApprovalToolCall }) => Promise<ToolApprovalStatus>;\n /** Wraps a tool set so every result is evaluated before the model reads it. */\n tools: <TOOLS extends ToolSet>(tools: TOOLS) => TOOLS;\n}\n\nconst SOURCE_APPLICATION = \"vercel-ai-sdk\";\nconst DEFAULT_BLOCKED_MESSAGE = \"This response was blocked by policy.\";\n\n/**\n * Connects a TrustGuard client to the Vercel AI SDK.\n *\n * ```ts\n * const tg = trustguard(client, { consumerId: user.id, sessionId: chatId });\n * streamText({\n * model: wrapLanguageModel({ model, middleware: tg.middleware }),\n * tools: tg.tools(tools),\n * toolApproval: tg.toolApproval,\n * messages,\n * });\n * ```\n */\nexport function trustguard(client: TrustGuard, options: TrustGuardAISDKOptions = {}): TrustGuardAISDK {\n const guard = new Guard(client, options);\n return {\n middleware: guard.middleware(),\n toolApproval: (approval) => guard.approveToolCall(approval.toolCall),\n tools: (tools) => guard.wrapTools(tools),\n };\n}\n\nclass Guard {\n readonly #client: TrustGuard;\n readonly #options: TrustGuardAISDKOptions;\n\n constructor(client: TrustGuard, options: TrustGuardAISDKOptions) {\n this.#client = client;\n this.#options = options;\n }\n\n middleware(): LanguageModelV4Middleware {\n return {\n specificationVersion: \"v4\",\n transformParams: async ({ params, model }) => this.#guardPrompt(params, model),\n wrapGenerate: async ({ doGenerate, model }) => {\n const result = await doGenerate();\n return { ...result, content: await this.#guardContent(result.content, model) };\n },\n wrapStream: async ({ doStream, model }) => {\n const result = await doStream();\n const transform =\n this.#options.stream === \"buffer\" ? this.#bufferStream(model) : this.#monitorStream(model);\n return { ...result, stream: result.stream.pipeThrough(transform) };\n },\n };\n }\n\n async approveToolCall(call: ApprovalToolCall): Promise<ToolApprovalStatus> {\n let response: GuardResponse | undefined;\n try {\n response = await this.#evaluate(\"tool-call\", {\n payload: toolsCall(call.toolName, call.input),\n direction: \"input\",\n protocol: \"mcp\",\n attributes: { tool: { name: call.toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-call\", error)) return undefined;\n return { type: \"denied\", reason: \"TrustGuard could not evaluate this tool call.\" };\n }\n\n switch (response.status) {\n case \"block\":\n return { type: \"denied\", reason: reasonFor(response, \"Blocked by TrustGuard\") };\n case \"ask\":\n return this.#options.toolAsk === \"deny\"\n ? { type: \"denied\", reason: reasonFor(response, \"TrustGuard requires approval\") }\n : { type: \"user-approval\", reason: reasonFor(response, \"TrustGuard requires approval\") };\n case \"transform\":\n // Approval cannot rewrite the arguments, and running the call unredacted would leak what the policy masks.\n return {\n type: \"denied\",\n reason: reasonFor(response, \"Blocked by TrustGuard because the arguments contain data the policy masks\"),\n };\n default:\n return undefined;\n }\n }\n\n wrapTools<TOOLS extends ToolSet>(tools: TOOLS): TOOLS {\n const wrapped: Record<string, unknown> = {};\n for (const [name, tool] of Object.entries(tools)) {\n const execute = tool.execute as ((input: unknown, options: unknown) => unknown) | undefined;\n if (typeof execute !== \"function\") {\n wrapped[name] = tool;\n continue;\n }\n wrapped[name] = {\n ...tool,\n execute: (input: unknown, executeOptions: unknown) => {\n const output = execute.call(tool, input, executeOptions);\n return isAsyncIterable(output)\n ? this.#guardIterableResult(name, output)\n : Promise.resolve(output).then((value) => this.#guardResult(name, value));\n },\n };\n }\n return wrapped as TOOLS;\n }\n\n async #guardPrompt(params: LanguageModelV4CallOptions, model: LanguageModelV4): Promise<LanguageModelV4CallOptions> {\n const index = lastUserTurn(params.prompt);\n if (index < 0) return params;\n const message = params.prompt[index] as Extract<LanguageModelV4Prompt[number], { role: \"user\" }>;\n const text = joinText(message.content);\n if (!text.trim()) return params;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"input\", {\n payload: { input: text },\n direction: \"input\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"input\", error)) return params;\n throw error;\n }\n\n const status = response.status === \"ask\" && this.#options.promptAsk !== \"allow\" ? \"block\" : response.status;\n if (status === \"block\") {\n throw new TrustGuardBlockedError(\"input\", response, reasonFor(response, \"Prompt blocked by TrustGuard\"));\n }\n if (status !== \"transform\") return params;\n\n const masked = transformedText(response);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"input\",\n response,\n \"Prompt blocked by TrustGuard: the policy masked it but returned no masked text\",\n );\n }\n const prompt = [...params.prompt];\n prompt[index] = { ...message, content: replaceText(message.content, masked) };\n return { ...params, prompt };\n }\n\n async #guardContent(content: LanguageModelV4Content[], model: LanguageModelV4): Promise<LanguageModelV4Content[]> {\n const text = joinText(content);\n if (!text.trim()) return content;\n\n const replacement = await this.#outputReplacement(text, model);\n return replacement === undefined ? content : replaceText(content, replacement);\n }\n\n /** The text that must replace a response, or undefined when it can go out as is. Throws when failing closed. */\n async #outputReplacement(text: string, model: LanguageModelV4): Promise<string | undefined> {\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"output\", {\n payload: { input: text },\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"output\", error)) return undefined;\n throw error;\n }\n if (response.status === \"block\") return this.#blockedMessage();\n if (response.status === \"transform\") return transformedText(response) ?? this.#blockedMessage();\n return undefined;\n }\n\n #monitorStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n let text = \"\";\n const evaluate = async () => {\n if (!text.trim()) return;\n try {\n await this.#evaluate(\"output\", {\n payload: { input: text },\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n this.#options.onError?.({ phase: \"output\", error });\n }\n };\n return new TransformStream({\n transform(part, controller) {\n if (part.type === \"text-delta\") text += part.delta;\n controller.enqueue(part);\n },\n // The stream does not close until this resolves, so a serverless function stays alive until the evaluation is sent.\n async flush() {\n await evaluate();\n },\n });\n }\n\n #bufferStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n const open = new Map<string, LanguageModelV4StreamPart[]>();\n const release = async (\n id: string,\n end: LanguageModelV4StreamPart | undefined,\n controller: TransformStreamDefaultController<LanguageModelV4StreamPart>,\n ) => {\n const parts = open.get(id) ?? [];\n open.delete(id);\n const text = parts.map((p) => (p.type === \"text-delta\" ? p.delta : \"\")).join(\"\");\n const replacement = text.trim() ? await this.#outputReplacement(text, model) : undefined;\n if (replacement === undefined) {\n for (const p of parts) controller.enqueue(p);\n } else {\n for (const p of parts) if (p.type !== \"text-delta\") controller.enqueue(p);\n controller.enqueue({ type: \"text-delta\", id, delta: replacement });\n }\n if (end) controller.enqueue(end);\n };\n return new TransformStream({\n async transform(part, controller) {\n switch (part.type) {\n case \"text-start\":\n open.set(part.id, [part]);\n return;\n case \"text-delta\": {\n const parts = open.get(part.id);\n if (parts) parts.push(part);\n else controller.enqueue(part);\n return;\n }\n case \"text-end\":\n if (open.has(part.id)) await release(part.id, part, controller);\n else controller.enqueue(part);\n return;\n default:\n controller.enqueue(part);\n }\n },\n async flush(controller) {\n // A stream that ends without text-end still goes through the policy before anything is released.\n for (const id of [...open.keys()]) await release(id, undefined, controller);\n },\n });\n }\n\n async #guardResult(toolName: string, output: unknown): Promise<unknown> {\n const text = typeof output === \"string\" ? output : JSON.stringify(output);\n if (text === undefined || !text.trim()) return output;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"tool-result\", {\n payload: { input: text },\n direction: \"output\",\n protocol: \"mcp\",\n attributes: { tool: { name: toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-result\", error)) return output;\n throw error;\n }\n\n if (response.status === \"block\") {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n reasonFor(response, `TrustGuard withheld the result of ${toolName}`),\n );\n }\n if (response.status !== \"transform\") return output;\n\n const masked = transformedText(response);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n `TrustGuard withheld the result of ${toolName}: the policy masked it but returned no masked text`,\n );\n }\n if (typeof output === \"string\") return masked;\n try {\n return JSON.parse(masked) as unknown;\n } catch {\n return masked;\n }\n }\n\n async *#guardIterableResult(toolName: string, output: AsyncIterable<unknown>): AsyncGenerator<unknown> {\n // Preliminary outputs reach the UI only. The last one is what the model reads, so that is the one guarded:\n // when the policy changes it, the guarded value is yielded after it and becomes the final output.\n let last: unknown;\n let seen = false;\n for await (const value of output) {\n last = value;\n seen = true;\n yield value;\n }\n if (!seen) return;\n const guarded = await this.#guardResult(toolName, last);\n if (guarded !== last) yield guarded;\n }\n\n async #evaluate(phase: GuardPhase, request: GuardRequest): Promise<GuardResponse> {\n const response = await this.#client.guard({\n ...request,\n sessionId: this.#options.sessionId,\n consumerId: this.#options.consumerId,\n attributes: {\n ...this.#options.attributes,\n ...request.attributes,\n source: { application: SOURCE_APPLICATION },\n },\n });\n this.#options.onVerdict?.({ phase, response });\n return response;\n }\n\n #failOpen(phase: GuardPhase, error: unknown): boolean {\n this.#options.onError?.({ phase, error });\n return this.#options.failMode === \"open\";\n }\n\n #blockedMessage(): string {\n return this.#options.blockedMessage ?? DEFAULT_BLOCKED_MESSAGE;\n }\n}\n\n/** Index of the user message that starts this model call, or -1 when the call continues a tool loop. */\nfunction lastUserTurn(prompt: LanguageModelV4Prompt): number {\n const last = prompt.length - 1;\n return last >= 0 && prompt[last]?.role === \"user\" ? last : -1;\n}\n\ntype TextLike = { type: string; text?: string };\n\nfunction joinText(parts: readonly TextLike[]): string {\n return parts\n .filter((p) => p.type === \"text\" && typeof p.text === \"string\")\n .map((p) => p.text)\n .join(\"\\n\");\n}\n\n/** Puts `text` in place of the first text part and drops the others, keeping every non-text part where it was. */\nfunction replaceText<T extends TextLike>(parts: readonly T[], text: string): T[] {\n let placed = false;\n const out: T[] = [];\n for (const part of parts) {\n if (part.type !== \"text\") {\n out.push(part);\n } else if (!placed) {\n out.push({ ...part, text });\n placed = true;\n }\n }\n return out;\n}\n\nfunction transformedText(response: GuardResponse): string | undefined {\n const input = response.transformedPayload?.input;\n return typeof input === \"string\" ? input : undefined;\n}\n\nfunction toolsCall(name: string, input: unknown): Record<string, unknown> {\n const args = input !== null && typeof input === \"object\" && !Array.isArray(input) ? input : { input };\n return { jsonrpc: \"2.0\", id: 1, method: \"tools/call\", params: { name, arguments: args } };\n}\n\nfunction modelAttributes(model: LanguageModelV4): Record<string, unknown> {\n return { model: { name: model.modelId, provider: model.provider } };\n}\n\n/** `reason`, followed by the gate or detector that produced the verdict when the response names one. */\nfunction reasonFor(response: GuardResponse, reason: string): string {\n const finding =\n response.findings.find((f) => f.outcome?.action === response.status) ?? response.findings.find((f) => f.outcome);\n const name = finding?.source.gateName || finding?.source.detectorName || finding?.signal?.type;\n return name ? `${reason}: ${name}` : reason;\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return value !== null && typeof value === \"object\" && Symbol.asyncIterator in value;\n}\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/ai-sdk/trustguard.ts"],"sourcesContent":["import type {\n LanguageModelV4,\n LanguageModelV4CallOptions,\n LanguageModelV4Content,\n LanguageModelV4Middleware,\n LanguageModelV4Prompt,\n LanguageModelV4StreamPart,\n} from \"@ai-sdk/provider\";\nimport type { ToolApprovalStatus, ToolSet } from \"ai\";\n\nimport type { TrustGuard } from \"../client.js\";\nimport type { GuardRequest, GuardResponse } from \"../types.js\";\n\n/** Where in the agent loop an evaluation ran. */\nexport type GuardPhase = \"input\" | \"output\" | \"tool-call\" | \"tool-result\";\n\n/** Options for {@link trustguard}. Create one instance per request so every evaluation carries the right user. */\nexport interface TrustGuardAISDKOptions {\n /** The end user the request runs for. Findings are grouped under it and gates match it as `consumer.id`. */\n consumerId?: string;\n /** The conversation key. Without it TrustGuard synthesises one per evaluation and turns lose their grouping. */\n sessionId?: string;\n /** Extra attributes merged into every evaluation, for gates and rule conditions. */\n attributes?: Record<string, unknown>;\n /**\n * How streamed responses are guarded.\n * - `\"monitor\"` (default): text streams untouched and is evaluated when the response finishes. Findings are recorded, nothing is enforced.\n * - `\"buffer\"`: each text block is held until it ends, evaluated, then released, redacted or replaced. Enforces the policy at the cost of streaming.\n */\n stream?: \"monitor\" | \"buffer\";\n /** What an `ask` verdict on the prompt does. The model call has no one to ask, so the default is `\"block\"`. */\n promptAsk?: \"block\" | \"allow\";\n /** What an `ask` verdict on a tool call does. The default, `\"user-approval\"`, asks the user through the AI SDK approval flow. */\n toolAsk?: \"user-approval\" | \"deny\";\n /** Text that replaces a response the policy blocked. */\n blockedMessage?: string;\n /**\n * What happens when TrustGuard cannot be reached or returns an error.\n * `\"closed\"` (default) throws on the prompt and the response and denies the tool call. `\"open\"` lets the traffic through.\n * Monitor-mode stream evaluations never fail the stream.\n */\n failMode?: \"closed\" | \"open\";\n /** Called with every verdict, for logging. */\n onVerdict?: (event: { phase: GuardPhase; response: GuardResponse }) => void;\n /** Called with every evaluation error, including the ones `failMode: \"open\"` swallows. */\n onError?: (event: { phase: GuardPhase; error: unknown }) => void;\n}\n\n/** Thrown when the policy blocks the prompt or the response, and by guarded tools whose result was withheld. */\nexport class TrustGuardBlockedError extends Error {\n readonly phase: GuardPhase;\n readonly response: GuardResponse;\n\n constructor(phase: GuardPhase, response: GuardResponse, message: string) {\n super(message);\n this.name = \"TrustGuardBlockedError\";\n this.phase = phase;\n this.response = response;\n }\n}\n\n/** The tool call the approval function receives. Structural, so it matches static and dynamic tool calls alike. */\nexport interface ApprovalToolCall {\n toolName: string;\n toolCallId: string;\n input: unknown;\n}\n\nexport interface TrustGuardAISDK {\n /** Language model middleware for `wrapLanguageModel`: guards the prompt and the response. */\n middleware: LanguageModelV4Middleware;\n /** A `toolApproval` function for `generateText` / `streamText`: guards each tool call before it runs. */\n toolApproval: (options: { toolCall: ApprovalToolCall }) => Promise<ToolApprovalStatus>;\n /** Wraps a tool set so every result is evaluated before the model reads it. */\n tools: <TOOLS extends ToolSet>(tools: TOOLS) => TOOLS;\n}\n\nconst SOURCE_APPLICATION = \"vercel-ai-sdk\";\nconst DEFAULT_BLOCKED_MESSAGE = \"This response was blocked by policy.\";\n\n/**\n * Connects a TrustGuard client to the Vercel AI SDK.\n *\n * ```ts\n * const tg = trustguard(client, { consumerId: user.id, sessionId: chatId });\n * streamText({\n * model: wrapLanguageModel({ model, middleware: tg.middleware }),\n * tools: tg.tools(tools),\n * toolApproval: tg.toolApproval,\n * messages,\n * });\n * ```\n */\nexport function trustguard(client: TrustGuard, options: TrustGuardAISDKOptions = {}): TrustGuardAISDK {\n const guard = new Guard(client, options);\n return {\n middleware: guard.middleware(),\n toolApproval: (approval) => guard.approveToolCall(approval.toolCall),\n tools: (tools) => guard.wrapTools(tools),\n };\n}\n\nclass Guard {\n readonly #client: TrustGuard;\n readonly #options: TrustGuardAISDKOptions;\n\n constructor(client: TrustGuard, options: TrustGuardAISDKOptions) {\n this.#client = client;\n this.#options = options;\n }\n\n middleware(): LanguageModelV4Middleware {\n return {\n specificationVersion: \"v4\",\n transformParams: async ({ params, model }) => this.#guardPrompt(params, model),\n wrapGenerate: async ({ doGenerate, model }) => {\n const result = await doGenerate();\n return { ...result, content: await this.#guardContent(result.content, model) };\n },\n wrapStream: async ({ doStream, model }) => {\n const result = await doStream();\n const transform =\n this.#options.stream === \"buffer\" ? this.#bufferStream(model) : this.#monitorStream(model);\n return { ...result, stream: result.stream.pipeThrough(transform) };\n },\n };\n }\n\n async approveToolCall(call: ApprovalToolCall): Promise<ToolApprovalStatus> {\n let response: GuardResponse | undefined;\n try {\n response = await this.#evaluate(\"tool-call\", {\n payload: toolsCall(call.toolName, call.input),\n direction: \"input\",\n protocol: \"mcp\",\n attributes: { tool: { name: call.toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-call\", error)) return undefined;\n return { type: \"denied\", reason: \"TrustGuard could not evaluate this tool call.\" };\n }\n\n switch (response.status) {\n case \"block\":\n return { type: \"denied\", reason: reasonFor(response, \"Blocked by TrustGuard\") };\n case \"ask\":\n return this.#options.toolAsk === \"deny\"\n ? { type: \"denied\", reason: reasonFor(response, \"TrustGuard requires approval\") }\n : { type: \"user-approval\", reason: reasonFor(response, \"TrustGuard requires approval\") };\n case \"transform\":\n // Approval cannot rewrite the arguments, and running the call unredacted would leak what the policy masks.\n return {\n type: \"denied\",\n reason: reasonFor(response, \"Blocked by TrustGuard because the arguments contain data the policy masks\"),\n };\n default:\n return undefined;\n }\n }\n\n wrapTools<TOOLS extends ToolSet>(tools: TOOLS): TOOLS {\n const wrapped: Record<string, unknown> = {};\n for (const [name, tool] of Object.entries(tools)) {\n const execute = tool.execute as ((input: unknown, options: unknown) => unknown) | undefined;\n if (typeof execute !== \"function\") {\n wrapped[name] = tool;\n continue;\n }\n wrapped[name] = {\n ...tool,\n execute: (input: unknown, executeOptions: unknown) => {\n const output = execute.call(tool, input, executeOptions);\n return isAsyncIterable(output)\n ? this.#guardIterableResult(name, output)\n : Promise.resolve(output).then((value) => this.#guardResult(name, value));\n },\n };\n }\n return wrapped as TOOLS;\n }\n\n async #guardPrompt(params: LanguageModelV4CallOptions, model: LanguageModelV4): Promise<LanguageModelV4CallOptions> {\n const index = lastUserTurn(params.prompt);\n if (index < 0) return params;\n const message = params.prompt[index] as Extract<LanguageModelV4Prompt[number], { role: \"user\" }>;\n const text = joinText(message.content);\n if (!text.trim()) return params;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"input\", {\n payload: { input: text },\n direction: \"input\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"input\", error)) return params;\n throw error;\n }\n\n const status = response.status === \"ask\" && this.#options.promptAsk !== \"allow\" ? \"block\" : response.status;\n if (status === \"block\") {\n throw new TrustGuardBlockedError(\"input\", response, reasonFor(response, \"Prompt blocked by TrustGuard\"));\n }\n if (status !== \"transform\") return params;\n\n const masked = transformedText(response, sentInput);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"input\",\n response,\n \"Prompt blocked by TrustGuard: the policy masked it but returned no masked text\",\n );\n }\n const prompt = [...params.prompt];\n prompt[index] = { ...message, content: replaceText(message.content, masked) };\n return { ...params, prompt };\n }\n\n async #guardContent(content: LanguageModelV4Content[], model: LanguageModelV4): Promise<LanguageModelV4Content[]> {\n const text = joinText(content);\n if (!text.trim()) return content;\n\n const replacement = await this.#outputReplacement(text, model);\n return replacement === undefined ? content : replaceText(content, replacement);\n }\n\n /** The text that must replace a response, or undefined when it can go out as is. Throws when failing closed. */\n async #outputReplacement(text: string, model: LanguageModelV4): Promise<string | undefined> {\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"output\", {\n payload: assistantTurn(text),\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n if (this.#failOpen(\"output\", error)) return undefined;\n throw error;\n }\n if (response.status === \"block\") return this.#blockedMessage();\n if (response.status === \"transform\") return transformedText(response, sentAssistant) ?? this.#blockedMessage();\n return undefined;\n }\n\n #monitorStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n let text = \"\";\n const evaluate = async () => {\n if (!text.trim()) return;\n try {\n await this.#evaluate(\"output\", {\n payload: assistantTurn(text),\n direction: \"output\",\n protocol: \"llm\",\n attributes: modelAttributes(model),\n });\n } catch (error) {\n this.#options.onError?.({ phase: \"output\", error });\n }\n };\n return new TransformStream({\n transform(part, controller) {\n if (part.type === \"text-delta\") text += part.delta;\n controller.enqueue(part);\n },\n // The stream does not close until this resolves, so a serverless function stays alive until the evaluation is sent.\n async flush() {\n await evaluate();\n },\n });\n }\n\n #bufferStream(model: LanguageModelV4): TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart> {\n const open = new Map<string, LanguageModelV4StreamPart[]>();\n const release = async (\n id: string,\n end: LanguageModelV4StreamPart | undefined,\n controller: TransformStreamDefaultController<LanguageModelV4StreamPart>,\n ) => {\n const parts = open.get(id) ?? [];\n open.delete(id);\n const text = parts.map((p) => (p.type === \"text-delta\" ? p.delta : \"\")).join(\"\");\n const replacement = text.trim() ? await this.#outputReplacement(text, model) : undefined;\n if (replacement === undefined) {\n for (const p of parts) controller.enqueue(p);\n } else {\n for (const p of parts) if (p.type !== \"text-delta\") controller.enqueue(p);\n controller.enqueue({ type: \"text-delta\", id, delta: replacement });\n }\n if (end) controller.enqueue(end);\n };\n return new TransformStream({\n async transform(part, controller) {\n switch (part.type) {\n case \"text-start\":\n open.set(part.id, [part]);\n return;\n case \"text-delta\": {\n const parts = open.get(part.id);\n if (parts) parts.push(part);\n else controller.enqueue(part);\n return;\n }\n case \"text-end\":\n if (open.has(part.id)) await release(part.id, part, controller);\n else controller.enqueue(part);\n return;\n default:\n controller.enqueue(part);\n }\n },\n async flush(controller) {\n // A stream that ends without text-end still goes through the policy before anything is released.\n for (const id of [...open.keys()]) await release(id, undefined, controller);\n },\n });\n }\n\n async #guardResult(toolName: string, output: unknown): Promise<unknown> {\n const text = typeof output === \"string\" ? output : JSON.stringify(output);\n if (text === undefined || !text.trim()) return output;\n\n let response: GuardResponse;\n try {\n response = await this.#evaluate(\"tool-result\", {\n payload: toolsResult(text),\n direction: \"output\",\n protocol: \"mcp\",\n attributes: { tool: { name: toolName } },\n });\n } catch (error) {\n if (this.#failOpen(\"tool-result\", error)) return output;\n throw error;\n }\n\n if (response.status === \"block\") {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n reasonFor(response, `TrustGuard withheld the result of ${toolName}`),\n );\n }\n if (response.status !== \"transform\") return output;\n\n const masked = transformedText(response, sentToolResult);\n if (masked === undefined) {\n throw new TrustGuardBlockedError(\n \"tool-result\",\n response,\n `TrustGuard withheld the result of ${toolName}: the policy masked it but returned no masked text`,\n );\n }\n if (typeof output === \"string\") return masked;\n try {\n return JSON.parse(masked) as unknown;\n } catch {\n return masked;\n }\n }\n\n async *#guardIterableResult(toolName: string, output: AsyncIterable<unknown>): AsyncGenerator<unknown> {\n // Preliminary outputs reach the UI only. The last one is what the model reads, so that is the one guarded:\n // when the policy changes it, the guarded value is yielded after it and becomes the final output.\n let last: unknown;\n let seen = false;\n for await (const value of output) {\n last = value;\n seen = true;\n yield value;\n }\n if (!seen) return;\n const guarded = await this.#guardResult(toolName, last);\n if (guarded !== last) yield guarded;\n }\n\n async #evaluate(phase: GuardPhase, request: GuardRequest): Promise<GuardResponse> {\n const response = await this.#client.guard({\n ...request,\n sessionId: this.#options.sessionId,\n consumerId: this.#options.consumerId,\n attributes: {\n ...this.#options.attributes,\n ...request.attributes,\n source: { application: SOURCE_APPLICATION },\n },\n });\n this.#options.onVerdict?.({ phase, response });\n return response;\n }\n\n #failOpen(phase: GuardPhase, error: unknown): boolean {\n this.#options.onError?.({ phase, error });\n return this.#options.failMode === \"open\";\n }\n\n #blockedMessage(): string {\n return this.#options.blockedMessage ?? DEFAULT_BLOCKED_MESSAGE;\n }\n}\n\n/** Index of the user message that starts this model call, or -1 when the call continues a tool loop. */\nfunction lastUserTurn(prompt: LanguageModelV4Prompt): number {\n const last = prompt.length - 1;\n return last >= 0 && prompt[last]?.role === \"user\" ? last : -1;\n}\n\ntype TextLike = { type: string; text?: string };\n\nfunction joinText(parts: readonly TextLike[]): string {\n return parts\n .filter((p) => p.type === \"text\" && typeof p.text === \"string\")\n .map((p) => p.text)\n .join(\"\\n\");\n}\n\n/** Puts `text` in place of the first text part and drops the others, keeping every non-text part where it was. */\nfunction replaceText<T extends TextLike>(parts: readonly T[], text: string): T[] {\n let placed = false;\n const out: T[] = [];\n for (const part of parts) {\n if (part.type !== \"text\") {\n out.push(part);\n } else if (!placed) {\n out.push({ ...part, text });\n placed = true;\n }\n }\n return out;\n}\n\ntype Payload = Record<string, unknown>;\n\n/** The masked text of a transform verdict. TrustGuard returns the payload it was sent, rewritten, so `at` reads it from where it was sent. */\nfunction transformedText(response: GuardResponse, at: (payload: Payload) => unknown): string | undefined {\n const payload = response.transformedPayload;\n const text = payload ? at(payload) : undefined;\n return typeof text === \"string\" ? text : undefined;\n}\n\nconst sentInput = (payload: Payload): unknown => payload.input;\nconst sentAssistant = (payload: Payload): unknown => firstItem(payload.messages)?.content;\nconst sentToolResult = (payload: Payload): unknown => firstItem(asRecord(payload.result)?.content)?.text;\n\nfunction firstItem(value: unknown): Payload | undefined {\n return Array.isArray(value) ? asRecord(value[0]) : undefined;\n}\n\nfunction asRecord(value: unknown): Payload | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) ? (value as Payload) : undefined;\n}\n\n// TrustGuard reads `{ input }` as the user's message, so on output Toxicity Detection and Custom Moderation would skip the\n// response. It is sent as the assistant turn it is.\nfunction assistantTurn(text: string): Payload {\n return { messages: [{ role: \"assistant\", content: text }] };\n}\n\n// An MCP payload must be a JSON-RPC envelope, so a tool result is sent as the result of the call that produced it.\nfunction toolsResult(text: string): Payload {\n return { jsonrpc: \"2.0\", id: 1, result: { content: [{ type: \"text\", text }] } };\n}\n\nfunction toolsCall(name: string, input: unknown): Record<string, unknown> {\n const args = input !== null && typeof input === \"object\" && !Array.isArray(input) ? input : { input };\n return { jsonrpc: \"2.0\", id: 1, method: \"tools/call\", params: { name, arguments: args } };\n}\n\nfunction modelAttributes(model: LanguageModelV4): Record<string, unknown> {\n return { model: { name: model.modelId, provider: model.provider } };\n}\n\n/** `reason`, followed by the gate or detector that produced the verdict when the response names one. */\nfunction reasonFor(response: GuardResponse, reason: string): string {\n const finding =\n response.findings.find((f) => f.outcome?.action === response.status) ?? response.findings.find((f) => f.outcome);\n const name = finding?.source.gateName || finding?.source.detectorName || finding?.signal?.type;\n return name ? `${reason}: ${name}` : reason;\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return value !== null && typeof value === \"object\" && Symbol.asyncIterator in value;\n}\n\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuraltrust/trustguard-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Official Node.js SDK for the TrustGuard runtime evaluate API (POST /v1/evaluate)",
5
5
  "license": "MIT",
6
6
  "author": "NeuralTrust",