prefix-safe-json 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,21 +4,25 @@
4
4
  [![CI](https://github.com/canblmz1/prefix-safe-json/actions/workflows/ci.yml/badge.svg)](https://github.com/canblmz1/prefix-safe-json/actions/workflows/ci.yml)
5
5
  [![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](#license)
6
6
 
7
- An incremental JSON parser and execution gate for **streamed LLM tool calls**.
7
+ Check original streamed arguments and terminal evidence **before your application
8
+ runs a tool**. `prefix-safe-json` refuses authority for incomplete input,
9
+ conflicting call identity, invalid schemas, or unsafe termination, even when a
10
+ parsed tool-call object looks usable.
8
11
 
9
- `prefix-safe-json` keeps incomplete, conflicting, or unconfirmed streamed arguments from being treated as final tool input. It is designed for callers that need to distinguish:
10
-
11
- 1. JSON that can be parsed right now,
12
- 2. values that are stable enough to expose, and
13
- 3. arguments that the provider actually completed and confirmed.
14
-
15
- It does not execute tools itself.
12
+ Your application consumes a decision once and performs the side effect itself.
13
+ PSJ never executes tools. Provider signals must accurately describe completion;
14
+ see the [provider-honesty limit](examples/openai-consumer/README.md).
16
15
 
17
16
  ```bash
18
17
  pnpm add prefix-safe-json ai zod
19
18
  # or: npm install prefix-safe-json ai zod
20
19
  ```
21
20
 
21
+ Try a runnable comparison first: [download the six-SDK trial ZIP](https://github.com/canblmz1/prefix-safe-json/releases/download/v0.5.4/prefix-safe-json-0.5.4-trials.zip),
22
+ extract it, then run `node scripts/try-npm-demo.mjs tanstack` with Node 22+.
23
+ It uses published packages, authored streams and harmless counters; no API key
24
+ or repository build is needed. [Choose another SDK](examples/README.md).
25
+
22
26
  ## Safe execution example
23
27
 
24
28
  ```javascript
@@ -31,7 +35,7 @@ import {
31
35
  } from "prefix-safe-json";
32
36
  import { fromStandardSchema } from "prefix-safe-json/standard-schema";
33
37
 
34
- const writeFileSchema = z.object({ path: z.string(), content: z.string() });
38
+ const writeFileSchema = z.object({ path: z.string(), content: z.string() }).strict();
35
39
 
36
40
  const tools = createAiSdkExecutionLock({
37
41
  write_file: {
@@ -53,7 +57,8 @@ const { decisions, diagnostics } = guard.finish();
53
57
  for (const decision of decisions) {
54
58
  const authority = guard.takeDecision(decision.internalId);
55
59
  if (authority) {
56
- await writeFile(authority.value.path, authority.value.content);
60
+ const input = writeFileSchema.parse(authority.value);
61
+ await writeFile(input.path, input.content);
57
62
  } else {
58
63
  console.warn(`skipped ${decision.name}: ${decision.action} (${decision.reason})`);
59
64
  }
@@ -67,6 +72,16 @@ if (decisions.length === 0 && diagnostics.length > 0) {
67
72
 
68
73
  Using `jsonSchema()` from `ai` instead of Zod? Give the guard the raw schema inside it: `schemas: { write_file: writeFileSchema.jsonSchema }`. The wrapper itself is refused at construction, because it would otherwise validate nothing.
69
74
 
75
+ ## Typed inputs and a complete agent loop
76
+
77
+ Experimental `createTypedAiSdkExecutionGuard` in
78
+ `prefix-safe-json/standard-schema` requires **PSJ 0.6.0+**.
79
+ The [strict TypeScript agent-loop example](examples/typed-agent-loop/) checks
80
+ inferred raw inputs, matching result IDs and a final model answer, plus four
81
+ refusal/error scenarios. It runs against the actual tarball without an API
82
+ key. The caller owns dispatch and continuation. Schema transformations,
83
+ defaults and removed keys are refused; [validation details](docs/VALIDATION.md#typed-raw-input-guard).
84
+
70
85
  ## When this adds value
71
86
 
72
87
  Use PSJ when your application owns tool dispatch and needs original-stream
@@ -94,10 +109,18 @@ checkout without model requests or tool dispatch.
94
109
  ## Run a standalone npm demo
95
110
 
96
111
  To try it without cloning this repository, download the
97
- [standalone trial ZIP](https://github.com/canblmz1/prefix-safe-json/releases/tag/trial-2026-10-14).
98
- It contains only the example sources and licenses; its release notes give
99
- the extraction and npm commands. It installs published PSJ `0.5.2`, not a new
100
- or unpublished package version.
112
+ [six-SDK trial ZIP](https://github.com/canblmz1/prefix-safe-json/releases/download/v0.5.4/prefix-safe-json-0.5.4-trials.zip)
113
+ and extract it. With Node 22+ and npm, run this from the extracted directory:
114
+
115
+ ```bash
116
+ node scripts/try-npm-demo.mjs tanstack
117
+ ```
118
+
119
+ Choose `ai-sdk`, `openai`, `anthropic`, `langchain`, `openrouter` or `tanstack`.
120
+ Every example installs published PSJ `0.5.4`; no API key or repository build
121
+ is needed. The ZIP contains example sources, the launcher and licenses;
122
+ dependencies are downloaded from npm. See the [trial index](examples/README.md)
123
+ for the SDK versions and checks. The earlier dated downloads remain unchanged.
101
124
 
102
125
  With Node 22+ and npm, you can run the published-package demo from this checkout
103
126
  without installing the repository's development dependencies:
@@ -119,7 +142,7 @@ npm ls prefix-safe-json ai zod
119
142
  npm start
120
143
  ```
121
144
 
122
- The example pins `prefix-safe-json@0.5.2`, `ai@7.0.77`, and `zod@4.4.3`.
145
+ The current checkout pins `prefix-safe-json@0.5.4`, `ai@7.0.77`, and `zod@4.4.3`.
123
146
  It needs no repository build, workspace aliases, or API key. It drives real
124
147
  `streamText().fullStream` using the SDK's official `MockLanguageModelV4` and
125
148
  imports the installed package's public entry point and `standard-schema`
@@ -161,6 +184,27 @@ It checks complete, token-limited, missing-`message_stop`, and post-terminal
161
184
  argument cases through the SDK's actual SSE parser. The LangChain comparison
162
185
  can also be launched with `node scripts/try-npm-demo.mjs langchain`.
163
186
 
187
+ Using the official OpenAI SDK? Run `node scripts/try-npm-demo.mjs openai` for
188
+ the [installed-package Chat Completions trial](examples/openai-consumer/README.md).
189
+ It checks complete and interrupted calls, duplicate IDs and late argument
190
+ evidence through `openai@7.34.0`. It also demonstrates a limit: PSJ cannot detect
191
+ upstream truncation when the provider supplies complete JSON and falsely
192
+ reports successful termination. These are mock-transport checks, not live
193
+ OpenAI or vLLM certification.
194
+
195
+ Using OpenRouter Agent? Run `node scripts/try-npm-demo.mjs openrouter` for the
196
+ [manual dispatch and continuation trial](examples/openrouter-consumer/README.md).
197
+ It checks that accepted tool results reach the next model request with matching
198
+ call IDs, while invalid batches cause zero effects and no continuation request.
199
+ It uses authored SSE through the installed SDK; no live model call is made.
200
+
201
+ Using TanStack AI with OpenRouter? Run `node scripts/try-npm-demo.mjs tanstack`
202
+ for the [installed-package comparison](examples/tanstack-consumer/README.md).
203
+ It checks raw native finish reasons, usage trailers and paired results using
204
+ published PSJ `0.5.4`, harmless counters and authored SSE. The
205
+ [native-first standalone trial](https://gist.github.com/canblmz1/ba1e62d792da37d3f420c328f56d81be)
206
+ also offers a PSJ-free baseline and an optional comparison from npm or source.
207
+
164
208
  ## Why parse success is not enough
165
209
 
166
210
  Tool-call arguments often arrive as partial JSON. A renderer may reasonably repair or close an unfinished prefix so it can show progressive UI. That is useful for display, but it answers a different question from whether a side effect should run.
@@ -0,0 +1,43 @@
1
+ import type { ExecutionGuardOptions, AiSdkExecutionGuard } from "./types.js";
2
+ import type { ExecuteDecision } from "../gate/types.js";
3
+ import type { JsonValue } from "../types.js";
4
+ import { type StandardSchemaV1Like } from "../validation/standard-schema-validator.js";
5
+ /** @public (Experimental) Synchronous Standard Schema input registry. */
6
+ export type ToolInputSchemas = Record<string, StandardSchemaV1Like>;
7
+ type SchemaOutput<T> = T extends {
8
+ readonly "~standard": {
9
+ readonly types?: {
10
+ readonly output: infer Output;
11
+ };
12
+ };
13
+ } ? Output : unknown;
14
+ /**
15
+ * @public (Experimental)
16
+ * A discriminated union of registered tool names and their validated raw
17
+ * inputs. Schema outputs that change the raw JSON value are refused at runtime.
18
+ */
19
+ export type TypedExecuteDecision<TSchemas extends ToolInputSchemas> = {
20
+ [Name in keyof TSchemas & string]: Omit<ExecuteDecision, "name" | "value"> & {
21
+ readonly name: Name;
22
+ readonly value: SchemaOutput<TSchemas[Name]> & JsonValue;
23
+ };
24
+ }[keyof TSchemas & string];
25
+ /** @public (Experimental) Typed authority consumption; snapshots remain observations. */
26
+ export type TypedAiSdkExecutionGuard<TSchemas extends ToolInputSchemas> = Omit<AiSdkExecutionGuard, "takeDecision"> & {
27
+ takeDecision(internalId: string): TypedExecuteDecision<TSchemas> | undefined;
28
+ };
29
+ /** @public (Experimental) Only registered, unchanged schema inputs can execute. */
30
+ export interface TypedAiSdkExecutionGuardOptions<TSchemas extends ToolInputSchemas> extends Omit<ExecutionGuardOptions, "schemas" | "validators"> {
31
+ readonly inputSchemas: TSchemas;
32
+ }
33
+ /**
34
+ * @public (Experimental)
35
+ * Retains Standard Schema output types without substituting transformed
36
+ * values for raw arguments. Validation is synchronous and must preserve JSON
37
+ * structure (including keys); use strict or passthrough object schemas.
38
+ * Unknown tool names receive no authority. Existing untyped guard behavior
39
+ * and fromStandardSchema's validation-only semantics are unchanged.
40
+ */
41
+ export declare function createTypedAiSdkExecutionGuard<const TSchemas extends ToolInputSchemas>(options: TypedAiSdkExecutionGuardOptions<TSchemas>): TypedAiSdkExecutionGuard<TSchemas>;
42
+ export {};
43
+ //# sourceMappingURL=typed-ai-sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-ai-sdk.d.ts","sourceRoot":"","sources":["../../src/guard/typed-ai-sdk.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,kBAAkB,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAiC,KAAK,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAEtH,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAEpE,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS;IAC/B,QAAQ,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CAC9E,GAAG,MAAM,GAAG,OAAO,CAAC;AAErB;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,CAAC,QAAQ,SAAS,gBAAgB,IAAI;KACnE,IAAI,IAAI,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG;QAC3E,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;QACpB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;KAC1D;CACF,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC;AAE3B,yFAAyF;AACzF,MAAM,MAAM,wBAAwB,CAAC,QAAQ,SAAS,gBAAgB,IAAI,IAAI,CAAC,mBAAmB,EAAE,cAAc,CAAC,GAAG;IACpH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;CAC9E,CAAC;AAEF,mFAAmF;AACnF,MAAM,WAAW,+BAA+B,CAAC,QAAQ,SAAS,gBAAgB,CAChF,SAAQ,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,YAAY,CAAC;IAC7D,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,CAAC,QAAQ,SAAS,gBAAgB,EACpF,OAAO,EAAE,+BAA+B,CAAC,QAAQ,CAAC,GACjD,wBAAwB,CAAC,QAAQ,CAAC,CA6CpC"}
@@ -0,0 +1,56 @@
1
+ import { createAiSdkExecutionGuard } from "./ai-sdk.js";
2
+ import { createStandardSchemaValidator } from "../validation/standard-schema-validator.js";
3
+ /**
4
+ * @public (Experimental)
5
+ * Retains Standard Schema output types without substituting transformed
6
+ * values for raw arguments. Validation is synchronous and must preserve JSON
7
+ * structure (including keys); use strict or passthrough object schemas.
8
+ * Unknown tool names receive no authority. Existing untyped guard behavior
9
+ * and fromStandardSchema's validation-only semantics are unchanged.
10
+ */
11
+ export function createTypedAiSdkExecutionGuard(options) {
12
+ // Extra properties survive structural typing and object spreads. Never
13
+ // silently ignore a caller's additional validation policy at runtime.
14
+ if ("schemas" in options || "validators" in options) {
15
+ throw new Error("createTypedAiSdkExecutionGuard: use inputSchemas only; schemas and validators cannot be combined with the typed guard.");
16
+ }
17
+ // Snapshot the registry: later caller mutations cannot change which names
18
+ // are allowed without changing the validators already held by the gate.
19
+ const validators = Object.fromEntries(Object.entries(options.inputSchemas).map(([name, schema]) => [name, createStandardSchemaValidator(schema, true)]));
20
+ const names = new Set(Object.keys(validators));
21
+ const guard = createAiSdkExecutionGuard({
22
+ validators, limits: options.limits, parserOptions: options.parserOptions,
23
+ });
24
+ const registered = (decision) => decision.name !== undefined && names.has(decision.name);
25
+ const observe = (decision) => {
26
+ if (decision.action !== "execute" || registered(decision))
27
+ return decision;
28
+ const { value: _value, ...rest } = decision;
29
+ return { ...rest, action: "reject", executable: false, reason: "schema_invalid" };
30
+ };
31
+ return {
32
+ push: part => guard.push(part),
33
+ snapshot: () => guard.snapshot().map(observe),
34
+ finish(meta) {
35
+ const final = guard.finish(meta);
36
+ const unknown = final.decisions.filter(d => !registered(d));
37
+ return {
38
+ decisions: final.decisions.map(observe),
39
+ diagnostics: [...final.diagnostics, ...unknown.map(d => ({
40
+ code: "E_UNREGISTERED_TOOL", severity: "error",
41
+ internalId: d.internalId,
42
+ message: "Typed guard has no input schema for this tool name.",
43
+ }))],
44
+ };
45
+ },
46
+ takeDecision(internalId) {
47
+ const decision = guard.takeDecision(internalId);
48
+ if (!decision || !registered(decision) || decision.evidence.schemaValid !== true)
49
+ return undefined;
50
+ // The registered validator checked the schema AND equality with raw
51
+ // input, and the underlying gate has consumed authority exactly once.
52
+ return decision;
53
+ },
54
+ };
55
+ }
56
+ //# sourceMappingURL=typed-ai-sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-ai-sdk.js","sourceRoot":"","sources":["../../src/guard/typed-ai-sdk.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,8 @@ import { ProviderStreamAdapter } from "./adapter.js";
3
3
  export interface OpenRouterChoice {
4
4
  index?: number;
5
5
  delta?: {
6
+ content?: string | null;
7
+ role?: string;
6
8
  tool_calls?: Array<{
7
9
  index?: number;
8
10
  id?: string;
@@ -15,17 +17,27 @@ export interface OpenRouterChoice {
15
17
  reasoning?: string;
16
18
  };
17
19
  finish_reason?: string | null;
20
+ native_finish_reason?: string | null;
18
21
  error?: unknown;
19
22
  }
20
23
  export interface OpenRouterEvent {
21
24
  choices?: OpenRouterChoice[];
22
25
  error?: unknown;
26
+ usage?: {
27
+ prompt_tokens?: number;
28
+ completion_tokens?: number;
29
+ total_tokens?: number;
30
+ };
23
31
  }
24
32
  export declare class OpenRouterStreamAdapter implements ProviderStreamAdapter<unknown> {
25
33
  readonly provider: ProviderName;
26
34
  private sequence;
27
35
  private compatibleAdapter;
28
36
  private finished;
37
+ private terminalChoices;
38
+ private accountingTrailerSeen;
39
+ private nativeOutputLimitReason;
40
+ private isAccountingTrailer;
29
41
  push(rawEvent: unknown): readonly NormalizedToolStreamEvent[];
30
42
  finish(meta?: {
31
43
  reason?: StreamEndReason;
@@ -1 +1 @@
1
- {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGrD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,KAAK,CAAC;YACjB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,EAAE,CAAC,EAAE,MAAM,CAAC;YACZ,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,QAAQ,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,SAAS,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;SAClD,CAAC,CAAC;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,uBAAwB,YAAW,qBAAqB,CAAC,OAAO,CAAC;IAC5E,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAK;IAGrB,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,yBAAyB,EAAE;IAwD7D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,yBAAyB,EAAE;CAO3G"}
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGrD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,KAAK,CAAC;YACjB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,EAAE,CAAC,EAAE,MAAM,CAAC;YACZ,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,QAAQ,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,SAAS,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;SAClD,CAAC,CAAC;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvF;AAcD,qBAAa,uBAAwB,YAAW,qBAAqB,CAAC,OAAO,CAAC;IAC5E,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAK;IAGrB,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,eAAe,CAAkF;IACzG,OAAO,CAAC,qBAAqB,CAAS;IACtC,OAAO,CAAC,uBAAuB,CAAqB;IAEpD,OAAO,CAAC,mBAAmB;IAkB3B,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,yBAAyB,EAAE;IAmE7D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,yBAAyB,EAAE;CAc3G"}
@@ -1,10 +1,45 @@
1
1
  import { OpenAICompatibleStreamAdapter } from "./openai-compatible.js";
2
+ // OpenRouter preserves the upstream finish reason separately from its normalized
3
+ // reason. A known output-limit signal cannot become successful execution merely
4
+ // because the router normalized that choice to `tool_calls` or `stop`.
5
+ const NATIVE_OUTPUT_LIMIT_REASONS = new Set(["max_output_tokens", "max_tokens", "MAX_TOKENS", "length"]);
6
+ function isAccountingDelta(delta) {
7
+ if (!delta || typeof delta !== "object" || Array.isArray(delta))
8
+ return false;
9
+ return Object.entries(delta).every(([key, value]) => (key === "content" && (value === "" || value === null)) ||
10
+ (key === "role" && value === "assistant"));
11
+ }
2
12
  export class OpenRouterStreamAdapter {
3
13
  provider = "openrouter";
4
14
  sequence = 0;
5
15
  // Delegate standard tool_call formats to compatible adapter
6
16
  compatibleAdapter = new OpenAICompatibleStreamAdapter();
7
17
  finished = false;
18
+ // Preserve coordinates unchanged; the compatible adapter owns index validity
19
+ // and duplicate-index diagnostics, even on a stripped accounting terminal.
20
+ terminalChoices = new Map();
21
+ accountingTrailerSeen = false;
22
+ nativeOutputLimitReason;
23
+ isAccountingTrailer(chunk) {
24
+ // The documented final usage chunk repeats the exact terminal metadata.
25
+ // Accept one content-free accounting frame only, for already-ended choices.
26
+ // Every other duplicate/conflicting terminal still reaches the strict
27
+ // compatible adapter, including errors, arguments and unknown choice IDs.
28
+ if (this.finished || this.accountingTrailerSeen || !Array.isArray(chunk.choices) || !chunk.choices.length ||
29
+ !chunk.usage || typeof chunk.usage !== "object" || Array.isArray(chunk.usage))
30
+ return false;
31
+ const usage = chunk.usage;
32
+ if (![usage.prompt_tokens, usage.completion_tokens, usage.total_tokens]
33
+ .every(value => typeof value === "number" && Number.isFinite(value) && value >= 0))
34
+ return false;
35
+ return chunk.choices.every(choice => {
36
+ if (choice.error || !isAccountingDelta(choice.delta))
37
+ return false;
38
+ const terminal = this.terminalChoices.get(choice.index);
39
+ return terminal !== undefined && choice.finish_reason === terminal.reason &&
40
+ (choice.native_finish_reason ?? null) === terminal.nativeReason;
41
+ });
42
+ }
8
43
  push(rawEvent) {
9
44
  // No `finished` early return here - see the identical fix and rationale
10
45
  // in AnthropicStreamAdapter.push()/OpenAIStreamAdapter.push() (same
@@ -50,7 +85,19 @@ export class OpenRouterStreamAdapter {
50
85
  this.finished = true;
51
86
  return events;
52
87
  }
53
- const compatibleEvents = this.compatibleAdapter.push(chunk);
88
+ const accounting = this.isAccountingTrailer(chunk);
89
+ if (accounting)
90
+ this.accountingTrailerSeen = true;
91
+ const choices = Array.isArray(chunk.choices) ? chunk.choices.map(choice => {
92
+ if (choice.finish_reason != null) {
93
+ this.terminalChoices.set(choice.index, { reason: choice.finish_reason, nativeReason: choice.native_finish_reason ?? null });
94
+ }
95
+ if (typeof choice.native_finish_reason === "string" && NATIVE_OUTPUT_LIMIT_REASONS.has(choice.native_finish_reason)) {
96
+ this.nativeOutputLimitReason ??= choice.native_finish_reason;
97
+ }
98
+ return accounting ? { ...choice, finish_reason: null } : choice;
99
+ }) : chunk.choices;
100
+ const compatibleEvents = this.compatibleAdapter.push({ ...chunk, choices });
54
101
  for (const e of compatibleEvents) {
55
102
  events.push({ ...e, provider: this.provider, sequence: ++this.sequence });
56
103
  }
@@ -60,7 +107,14 @@ export class OpenRouterStreamAdapter {
60
107
  if (this.finished)
61
108
  return [];
62
109
  this.finished = true;
63
- const compatibleEvents = this.compatibleAdapter.finish(meta);
110
+ // Aggregate native truncation with normalized choice reasons at the actual
111
+ // EOF boundary. Keep the raw reason for evidence instead of inventing a
112
+ // provider finish_reason string. Stronger caller failures retain priority.
113
+ const effectiveMeta = this.nativeOutputLimitReason !== undefined &&
114
+ (meta?.reason === undefined || meta.reason === "complete" || meta.reason === "cancelled" || meta.reason === "length")
115
+ ? { reason: "length", providerReason: this.nativeOutputLimitReason }
116
+ : meta;
117
+ const compatibleEvents = this.compatibleAdapter.finish(effectiveMeta);
64
118
  return compatibleEvents.map(e => ({ ...e, provider: this.provider, sequence: ++this.sequence }));
65
119
  }
66
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,4 @@
1
1
  export { fromStandardSchema } from "./validation/standard-schema-validator.js";
2
+ export { createTypedAiSdkExecutionGuard } from "./guard/typed-ai-sdk.js";
3
+ export type { ToolInputSchemas, TypedExecuteDecision, TypedAiSdkExecutionGuard, TypedAiSdkExecutionGuardOptions, } from "./guard/typed-ai-sdk.js";
2
4
  //# sourceMappingURL=standard-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"standard-schema.d.ts","sourceRoot":"","sources":["../src/standard-schema.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC"}
1
+ {"version":3,"file":"standard-schema.d.ts","sourceRoot":"","sources":["../src/standard-schema.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AACzE,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,+BAA+B,GAChC,MAAM,yBAAyB,CAAC"}
@@ -8,4 +8,5 @@
8
8
  // property the spec itself defines. See docs/VALIDATION.md.
9
9
  // ---------------------------------------------------------------------------
10
10
  export { fromStandardSchema } from "./validation/standard-schema-validator.js";
11
+ export { createTypedAiSdkExecutionGuard } from "./guard/typed-ai-sdk.js";
11
12
  //# sourceMappingURL=standard-schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"standard-schema.js","sourceRoot":"","sources":["../src/standard-schema.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,EAAE;AACF,mEAAmE;AACnE,4EAA4E;AAC5E,yEAAyE;AACzE,uEAAuE;AACvE,4DAA4D;AAC5D,8EAA8E;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC"}
1
+ {"version":3,"file":"standard-schema.js","sourceRoot":"","sources":["../src/standard-schema.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,EAAE;AACF,mEAAmE;AACnE,4EAA4E;AAC5E,yEAAyE;AACzE,uEAAuE;AACvE,4DAA4D;AAC5D,8EAA8E;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC"}
@@ -6,7 +6,7 @@ import type { ToolInputValidator } from "./types.js";
6
6
  * - just its documented shape, which Zod 4+, Valibot, ArkType, and others
7
7
  * already implement without any package of ours needing to know that.
8
8
  */
9
- interface StandardSchemaV1Like {
9
+ export interface StandardSchemaV1Like {
10
10
  readonly "~standard": {
11
11
  readonly version: 1;
12
12
  readonly vendor: string;
@@ -37,5 +37,6 @@ interface StandardSchemaV1Like {
37
37
  * `docs/VALIDATION.md#the-standard-schema-transformation-boundary`.
38
38
  */
39
39
  export declare function fromStandardSchema(schema: StandardSchemaV1Like): ToolInputValidator;
40
- export {};
40
+ /** @internal Typed guards additionally require an unchanged JSON output. */
41
+ export declare function createStandardSchemaValidator(schema: StandardSchemaV1Like, unchangedOutput?: boolean): ToolInputValidator;
41
42
  //# sourceMappingURL=standard-schema-validator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"standard-schema-validator.d.ts","sourceRoot":"","sources":["../../src/validation/standard-schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,YAAY,CAAC;AAE3E;;;;;;GAMG;AACH,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;KAChD,CAAC;CACH;AA6FD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,kBAAkB,CA8CnF"}
1
+ {"version":3,"file":"standard-schema-validator.d.ts","sourceRoot":"","sources":["../../src/validation/standard-schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,YAAY,CAAC;AAE3E;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;KAChD,CAAC;CACH;AA6FD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,kBAAkB,CAEnF;AAED,4EAA4E;AAC5E,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,oBAAoB,EAAE,eAAe,UAAQ,GAAG,kBAAkB,CAuDvH"}
@@ -90,12 +90,22 @@ function assertStandardSchemaV1(schema) {
90
90
  * `docs/VALIDATION.md#the-standard-schema-transformation-boundary`.
91
91
  */
92
92
  export function fromStandardSchema(schema) {
93
+ return createStandardSchemaValidator(schema);
94
+ }
95
+ /** @internal Typed guards additionally require an unchanged JSON output. */
96
+ export function createStandardSchemaValidator(schema, unchangedOutput = false) {
93
97
  assertStandardSchemaV1(schema);
94
98
  const standard = schema["~standard"];
95
99
  return {
96
100
  validate(value) {
97
- const result = standard.validate(value);
101
+ // A typed boundary validates a copy: defaults/coercions or a mutating
102
+ // validator must never alter the raw value against which we compare.
103
+ const candidate = unchangedOutput ? structuredClone(value) : value;
104
+ const result = standard.validate(candidate);
98
105
  if (isThenable(result)) {
106
+ // Reject synchronously, but also observe an eventual async rejection
107
+ // so a misconfigured validator cannot cause an unhandled rejection.
108
+ void Promise.resolve(result).catch(() => undefined);
99
109
  throw new Error("prefix-safe-json: fromStandardSchema() only supports synchronous Standard Schema validators. " +
100
110
  "This schema's validate() returned a Promise - implement ToolInputValidator directly if you " +
101
111
  "need async validation, and resolve it before the call reaches this coordinator.");
@@ -124,8 +134,38 @@ export function fromStandardSchema(schema) {
124
134
  '"value" nor "issues" - not a valid Standard Schema SuccessResult or FailureResult. Received: ' +
125
135
  describeForError(result));
126
136
  }
137
+ if (unchangedOutput && !sameJsonValue(value, result.value)) {
138
+ return { valid: false, errors: ["Typed input validation must preserve the raw JSON value; transformations, defaults and removed keys are not accepted."] };
139
+ }
127
140
  return { valid: true };
128
141
  },
129
142
  };
130
143
  }
144
+ /** Compare JSON structure without depending on object property order. */
145
+ function sameJsonValue(raw, output) {
146
+ const pending = [[raw, output]];
147
+ while (pending.length > 0) {
148
+ const [left, right] = pending.pop();
149
+ if (Object.is(left, right))
150
+ continue;
151
+ if (!isRecord(left) || !isRecord(right))
152
+ return false;
153
+ if (Array.isArray(left) !== Array.isArray(right))
154
+ return false;
155
+ const prototype = Object.getPrototypeOf(right);
156
+ if (prototype !== null && prototype !== Object.prototype && prototype !== Array.prototype)
157
+ return false;
158
+ const keys = Object.keys(left);
159
+ if (keys.length !== Object.keys(right).length)
160
+ return false;
161
+ if (Array.isArray(left) && left.length !== right["length"])
162
+ return false;
163
+ for (const key of keys) {
164
+ if (!Object.hasOwn(right, key))
165
+ return false;
166
+ pending.push([left[key], right[key]]);
167
+ }
168
+ }
169
+ return true;
170
+ }
131
171
  //# sourceMappingURL=standard-schema-validator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"standard-schema-validator.js","sourceRoot":"","sources":["../../src/validation/standard-schema-validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"standard-schema-validator.js","sourceRoot":"","sources":["../../src/validation/standard-schema-validator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prefix-safe-json",
3
- "version": "0.5.3",
3
+ "version": "0.6.0",
4
4
  "description": "Fail-closed execution integrity for streamed LLM tool calls — reject truncated or unconfirmed arguments before side effects",
5
5
  "keywords": [
6
6
  "json",
@@ -100,7 +100,7 @@
100
100
  "@stryker-mutator/vitest-runner": "^9.6.1",
101
101
  "@types/clarinet": "^0.12.3",
102
102
  "@types/node": "^26.1.2",
103
- "@vitest/coverage-v8": "^3.2.6",
103
+ "@vitest/coverage-v8": "^4.1.12",
104
104
  "ai-v5": "npm:ai@5.0.244",
105
105
  "ai-v6": "npm:ai@6.0.264",
106
106
  "ai-v7": "npm:ai@7.0.77",
@@ -114,15 +114,18 @@
114
114
  "tsx": "^4.16.0",
115
115
  "typescript": "^5.5.0",
116
116
  "typescript-eslint": "^8.0.0",
117
- "vitest": "^3.2.6",
117
+ "vitest": "^4.1.12",
118
118
  "zod": "4.4.3"
119
119
  },
120
120
  "pnpm": {
121
121
  "overrides": {
122
- "qs": "^6.15.2",
122
+ "qs": "^6.16.0",
123
123
  "vite": "^6.4.3",
124
124
  "nanoid": "^3.3.18",
125
- "undici": "^7.28.0"
125
+ "undici": "^7.29.1",
126
+ "brace-expansion@1": "^1.1.21",
127
+ "brace-expansion@5": "^5.0.12",
128
+ "js-yaml@4": "^4.3.2"
126
129
  }
127
130
  }
128
131
  }