agentid-sdk 0.1.40 → 0.1.42

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
@@ -22,7 +22,7 @@ User Input -> guard() -> [AgentID Policy] -> verdict
22
22
  log() -> [Immutable Ledger]
23
23
  ```
24
24
 
25
- - `guard()`: evaluates prompt and context before model execution.
25
+ - `guard()`: evaluates prompt and context once per model invocation before model execution. For chat flows, that single invocation can include the full protected history.
26
26
  - Model call: executes only if guard verdict is allowed.
27
27
  - `log()`: persists immutable telemetry (prompt, output, latency) for audit and compliance.
28
28
 
@@ -129,6 +129,22 @@ forwarded to the model provider. The wrapper also protects returned completion
129
129
  text before it is logged or returned from the wrapped call when SDK-side masking
130
130
  is enabled.
131
131
 
132
+ By default, caller-facing output stays masked. If the model responds with a
133
+ placeholder produced from this request, such as `<PERSON_1>` or `<EMAIL_1>`,
134
+ the wrapper returns the placeholder to your app and stores masked telemetry.
135
+ If an internal route intentionally needs the previous placeholder round-trip
136
+ behavior, opt in explicitly:
137
+
138
+ ```ts
139
+ const secured = agent.wrapOpenAI(openai, {
140
+ system_id: process.env.AGENTID_SYSTEM_ID!,
141
+ deanonymizeOutputForClient: true,
142
+ });
143
+ ```
144
+
145
+ Do not enable this for data-minimization deployments unless the application is
146
+ allowed to receive the original values back in the model response path.
147
+
132
148
  Important: this applies only to the wrapped call. If your app sends raw prompt
133
149
  or raw chat history through a separate direct provider call, AgentID cannot
134
150
  protect that bypass.
@@ -163,11 +179,33 @@ For chat apps and agent workflows, protect the full message history, not just
163
179
  the latest text field. If a previous user/assistant/tool/memory message contains
164
180
  raw PII, the model can still repeat it later.
165
181
 
182
+ Current wrapper scope note: `wrapOpenAI()` can protect full message history for
183
+ provider dispatch when SDK-side masking is enabled, but its preflight `guard()`
184
+ input is currently derived from the last user message text plus supported inline
185
+ attachments on that last user turn. If you need preflight evaluation over the
186
+ exact assembled multi-turn history today, use an explicit manual
187
+ `guard -> provider -> log` flow for that route.
188
+
166
189
  If you cannot use `wrapOpenAI()` and need a manual integration, call
167
190
  `protectMessageHistory()` on the exact history that will be sent to the
168
191
  provider. Then pass `protected.messages` to the provider, not the raw
169
192
  `body.messages`.
170
193
 
194
+ If your app uses Vercel AI SDK React `useChat()`, prefer
195
+ `agentid-vercel-sdk/react` and `useAgentIdChat()` instead of rebuilding
196
+ transport preparation in generic Node code.
197
+
198
+ Treat one provider call as one protected unit of work:
199
+
200
+ 1. Build the exact `messages` array for this model call.
201
+ 2. Run `protectMessageHistory()` once on that full array.
202
+ 3. Call `guard()` once for that same model call.
203
+ 4. Send `protectedHistory.messages` to the provider.
204
+
205
+ Do not loop over historical messages and call `guard()` once per prior turn.
206
+ That creates multiple guard events for one LLM call and can look like duplicated
207
+ or stale conversation logging.
208
+
171
209
  ```ts
172
210
  import { AgentID, protectMessageHistory } from "agentid-sdk";
173
211
 
@@ -204,9 +242,52 @@ const response = await openai.chat.completions.create({
204
242
  });
205
243
  ```
206
244
 
245
+ For non-Vercel chat UIs, use `protectChatState()` when you want one helper to
246
+ produce separate views for UI rendering, provider dispatch, and persistence:
247
+
248
+ ```ts
249
+ import { protectChatState } from "agentid-sdk";
250
+
251
+ const protectedChat = protectChatState(messages, {
252
+ transcript: {
253
+ ui: "masked",
254
+ provider: "masked",
255
+ persistence: "masked",
256
+ },
257
+ });
258
+
259
+ renderMessages(protectedChat.uiMessages);
260
+ await provider.chat.completions.create({
261
+ model: "gpt-4o-mini",
262
+ messages: protectedChat.providerMessages,
263
+ });
264
+ await saveTranscript(protectedChat.persistenceMessages);
265
+ ```
266
+
267
+ If your product intentionally shows the user's raw prompt locally, make that
268
+ explicit while keeping provider and persistence protected:
269
+
270
+ ```ts
271
+ const protectedChat = protectChatState(messages, {
272
+ transcript: { ui: "raw", provider: "masked", persistence: "masked" },
273
+ });
274
+ ```
275
+
276
+ The returned placeholder mapping is local to your process/session. Do not
277
+ persist it unless you have an explicit encrypted vault design.
278
+
207
279
  Wrapped OpenAI calls persist telemetry for both regular and streamed completions. For `stream: true`, logging happens when the stream finishes.
208
280
 
209
- > Scope note: AgentID compliance/risk controls apply to the specific SDK-wrapped LLM calls (`guard()`, `wrapOpenAI()`, LangChain callback-wrapped flows). They do not automatically classify unrelated code paths in your whole monolithic application.
281
+ > Scope note: AgentID compliance/risk controls apply to the specific SDK-wrapped LLM calls (`guard()`, `wrapOpenAI()`, LangChain callback-wrapped flows). They do not automatically classify unrelated code paths in your whole monolithic application.
282
+ >
283
+ > Enterprise rollout rule: the main production risk is not usually a weak classifier. It is an unwrapped provider call or helper that sends prompt/history outside `wrapOpenAI()`, LangChain callbacks, or an explicit `guard -> provider -> log` path. If your app also uses `responses.create`, Assistants, custom fetches, or a second raw OpenAI client, those paths must be integrated separately or treated as coverage gaps.
284
+
285
+ Before calling an integration enterprise-ready, verify all of these:
286
+
287
+ 1. Every production LLM callsite uses `wrapOpenAI()`, a LangChain callback-wrapped model, or an explicit manual `guard -> provider -> log` flow.
288
+ 2. No parallel raw provider call exists in the same request path.
289
+ 3. Chat and agent routes protect the full message history sent to the provider, not just the latest user text.
290
+ 4. Manual integrations set `full_history_protected=true` only when the exact provider payload was protected before dispatch.
210
291
 
211
292
  ### Vercel AI SDK Wrapper
212
293
 
@@ -42,6 +42,7 @@ interface GuardAttachment {
42
42
  }
43
43
  interface GuardParams {
44
44
  input: string;
45
+ prompt_context?: string;
45
46
  system_id: string;
46
47
  model?: string;
47
48
  user_id?: string;
@@ -54,6 +55,7 @@ interface GuardParams {
54
55
  capabilities: {
55
56
  has_feedback_handler: boolean;
56
57
  pii_masking_enabled: boolean;
58
+ secret_masking_enabled?: boolean;
57
59
  framework: string;
58
60
  };
59
61
  };
@@ -126,6 +128,7 @@ type AgentEventType = "start" | "complete" | "error" | "human_override" | "secur
126
128
  type InjectionScanRequestOptions = RequestOptions & {
127
129
  clientEventId?: string;
128
130
  systemId?: string;
131
+ attachments?: GuardAttachment[];
129
132
  };
130
133
  type PromptPreflightLogParams = {
131
134
  system_id: string;
@@ -153,6 +156,13 @@ interface WrapOpenAIOptions {
153
156
  apiKey?: string;
154
157
  api_key?: string;
155
158
  resolveApiKey?: (request: Record<string, unknown>) => string | undefined;
159
+ /**
160
+ * Opt-in legacy behavior: if the model returns AgentID placeholders that were
161
+ * produced from this request's input, restore them before returning to the
162
+ * application caller. Defaults to false so caller-facing output stays masked.
163
+ */
164
+ deanonymizeOutputForClient?: boolean;
165
+ deanonymize_output_for_client?: boolean;
156
166
  }
157
167
  interface LogParams {
158
168
  event_id?: string;
@@ -220,6 +230,7 @@ interface OperationLogParams {
220
230
  capabilities: {
221
231
  has_feedback_handler: boolean;
222
232
  pii_masking_enabled: boolean;
233
+ secret_masking_enabled?: boolean;
223
234
  framework: string;
224
235
  };
225
236
  };
@@ -263,6 +274,7 @@ declare class AgentID {
263
274
  private localEnforcer;
264
275
  private injectionScanner;
265
276
  private recentGuardVerdicts;
277
+ private pendingGuardRequests;
266
278
  constructor(config?: AgentIDConfig);
267
279
  get piiMasking(): boolean | undefined;
268
280
  get secretMasking(): boolean | undefined;
@@ -284,10 +296,13 @@ declare class AgentID {
284
296
  private buildFailOpenGuardVerdict;
285
297
  private maybeRaiseStrictIngestDependencyError;
286
298
  private shouldRunLocalInjectionScan;
299
+ private buildInlineAttachmentPromptScanInput;
300
+ private buildPromptInjectionScanInput;
287
301
  private refreshCapabilityConfigBeforeClientControl;
288
302
  private applyLocalPolicyChecks;
289
303
  prepareInputForDispatch(params: {
290
304
  input: string;
305
+ promptContext?: string;
291
306
  systemId: string;
292
307
  stream: boolean;
293
308
  skipInjectionScan?: boolean;
@@ -296,6 +311,7 @@ declare class AgentID {
296
311
  }, options?: RequestOptions): Promise<PreparedInput>;
297
312
  applyLocalFallbackForGuardFailure(params: {
298
313
  input: string;
314
+ promptContext?: string;
299
315
  systemId: string;
300
316
  stream: boolean;
301
317
  clientEventId?: string;
@@ -303,6 +319,20 @@ declare class AgentID {
303
319
  sdkConfigFetchMs?: number;
304
320
  telemetryMetadata?: AgentTelemetryContext;
305
321
  }, options?: RequestOptions): Promise<PreparedInput>;
322
+ runLocalPromptInjectionFallback(params: {
323
+ input: string;
324
+ promptContext?: string;
325
+ attachments?: GuardAttachment[];
326
+ systemId?: string;
327
+ clientEventId?: string;
328
+ capabilityConfig?: CapabilityConfig;
329
+ sdkConfigFetchMs?: number;
330
+ telemetryMetadata?: AgentTelemetryContext;
331
+ }, options?: RequestOptions): Promise<{
332
+ capabilityConfig: CapabilityConfig;
333
+ sdkConfigFetchMs: number;
334
+ sdkLocalScanMs: number;
335
+ }>;
306
336
  scanPromptInjection(input: string, options?: InjectionScanRequestOptions): Promise<void>;
307
337
  private withMaskedOpenAIRequest;
308
338
  private logSecurityPolicyViolation;
@@ -42,6 +42,7 @@ interface GuardAttachment {
42
42
  }
43
43
  interface GuardParams {
44
44
  input: string;
45
+ prompt_context?: string;
45
46
  system_id: string;
46
47
  model?: string;
47
48
  user_id?: string;
@@ -54,6 +55,7 @@ interface GuardParams {
54
55
  capabilities: {
55
56
  has_feedback_handler: boolean;
56
57
  pii_masking_enabled: boolean;
58
+ secret_masking_enabled?: boolean;
57
59
  framework: string;
58
60
  };
59
61
  };
@@ -126,6 +128,7 @@ type AgentEventType = "start" | "complete" | "error" | "human_override" | "secur
126
128
  type InjectionScanRequestOptions = RequestOptions & {
127
129
  clientEventId?: string;
128
130
  systemId?: string;
131
+ attachments?: GuardAttachment[];
129
132
  };
130
133
  type PromptPreflightLogParams = {
131
134
  system_id: string;
@@ -153,6 +156,13 @@ interface WrapOpenAIOptions {
153
156
  apiKey?: string;
154
157
  api_key?: string;
155
158
  resolveApiKey?: (request: Record<string, unknown>) => string | undefined;
159
+ /**
160
+ * Opt-in legacy behavior: if the model returns AgentID placeholders that were
161
+ * produced from this request's input, restore them before returning to the
162
+ * application caller. Defaults to false so caller-facing output stays masked.
163
+ */
164
+ deanonymizeOutputForClient?: boolean;
165
+ deanonymize_output_for_client?: boolean;
156
166
  }
157
167
  interface LogParams {
158
168
  event_id?: string;
@@ -220,6 +230,7 @@ interface OperationLogParams {
220
230
  capabilities: {
221
231
  has_feedback_handler: boolean;
222
232
  pii_masking_enabled: boolean;
233
+ secret_masking_enabled?: boolean;
223
234
  framework: string;
224
235
  };
225
236
  };
@@ -263,6 +274,7 @@ declare class AgentID {
263
274
  private localEnforcer;
264
275
  private injectionScanner;
265
276
  private recentGuardVerdicts;
277
+ private pendingGuardRequests;
266
278
  constructor(config?: AgentIDConfig);
267
279
  get piiMasking(): boolean | undefined;
268
280
  get secretMasking(): boolean | undefined;
@@ -284,10 +296,13 @@ declare class AgentID {
284
296
  private buildFailOpenGuardVerdict;
285
297
  private maybeRaiseStrictIngestDependencyError;
286
298
  private shouldRunLocalInjectionScan;
299
+ private buildInlineAttachmentPromptScanInput;
300
+ private buildPromptInjectionScanInput;
287
301
  private refreshCapabilityConfigBeforeClientControl;
288
302
  private applyLocalPolicyChecks;
289
303
  prepareInputForDispatch(params: {
290
304
  input: string;
305
+ promptContext?: string;
291
306
  systemId: string;
292
307
  stream: boolean;
293
308
  skipInjectionScan?: boolean;
@@ -296,6 +311,7 @@ declare class AgentID {
296
311
  }, options?: RequestOptions): Promise<PreparedInput>;
297
312
  applyLocalFallbackForGuardFailure(params: {
298
313
  input: string;
314
+ promptContext?: string;
299
315
  systemId: string;
300
316
  stream: boolean;
301
317
  clientEventId?: string;
@@ -303,6 +319,20 @@ declare class AgentID {
303
319
  sdkConfigFetchMs?: number;
304
320
  telemetryMetadata?: AgentTelemetryContext;
305
321
  }, options?: RequestOptions): Promise<PreparedInput>;
322
+ runLocalPromptInjectionFallback(params: {
323
+ input: string;
324
+ promptContext?: string;
325
+ attachments?: GuardAttachment[];
326
+ systemId?: string;
327
+ clientEventId?: string;
328
+ capabilityConfig?: CapabilityConfig;
329
+ sdkConfigFetchMs?: number;
330
+ telemetryMetadata?: AgentTelemetryContext;
331
+ }, options?: RequestOptions): Promise<{
332
+ capabilityConfig: CapabilityConfig;
333
+ sdkConfigFetchMs: number;
334
+ sdkLocalScanMs: number;
335
+ }>;
306
336
  scanPromptInjection(input: string, options?: InjectionScanRequestOptions): Promise<void>;
307
337
  private withMaskedOpenAIRequest;
308
338
  private logSecurityPolicyViolation;