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 +59 -15
- package/dist/guard/typed-ai-sdk.d.ts +43 -0
- package/dist/guard/typed-ai-sdk.d.ts.map +1 -0
- package/dist/guard/typed-ai-sdk.js +56 -0
- package/dist/guard/typed-ai-sdk.js.map +1 -0
- package/dist/providers/openrouter.d.ts +12 -0
- package/dist/providers/openrouter.d.ts.map +1 -1
- package/dist/providers/openrouter.js +56 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/standard-schema.d.ts +2 -0
- package/dist/standard-schema.d.ts.map +1 -1
- package/dist/standard-schema.js +1 -0
- package/dist/standard-schema.js.map +1 -1
- package/dist/validation/standard-schema-validator.d.ts +3 -2
- package/dist/validation/standard-schema-validator.d.ts.map +1 -1
- package/dist/validation/standard-schema-validator.js +41 -1
- package/dist/validation/standard-schema-validator.js.map +1 -1
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -4,21 +4,25 @@
|
|
|
4
4
|
[](https://github.com/canblmz1/prefix-safe-json/actions/workflows/ci.yml)
|
|
5
5
|
[](#license)
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
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
|
-
[
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
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;
|
|
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
|
|
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
|
-
|
|
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":"AAEA,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;
|
|
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"}
|
package/dist/standard-schema.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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": "^
|
|
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": "^
|
|
117
|
+
"vitest": "^4.1.12",
|
|
118
118
|
"zod": "4.4.3"
|
|
119
119
|
},
|
|
120
120
|
"pnpm": {
|
|
121
121
|
"overrides": {
|
|
122
|
-
"qs": "^6.
|
|
122
|
+
"qs": "^6.16.0",
|
|
123
123
|
"vite": "^6.4.3",
|
|
124
124
|
"nanoid": "^3.3.18",
|
|
125
|
-
"undici": "^7.
|
|
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
|
}
|