prefix-safe-json 0.5.3 → 0.5.4
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,15 +4,14 @@
|
|
|
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
|
|
@@ -94,10 +93,10 @@ checkout without model requests or tool dispatch.
|
|
|
94
93
|
## Run a standalone npm demo
|
|
95
94
|
|
|
96
95
|
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-
|
|
96
|
+
[standalone trial ZIP](https://github.com/canblmz1/prefix-safe-json/releases/tag/trial-2026-10-16).
|
|
98
97
|
It contains only the example sources and licenses; its release notes give
|
|
99
|
-
the extraction and npm commands.
|
|
100
|
-
|
|
98
|
+
the extraction and npm commands. Choose an AI SDK, OpenAI, Anthropic or
|
|
99
|
+
LangChain consumer; each installs published PSJ `0.5.3`.
|
|
101
100
|
|
|
102
101
|
With Node 22+ and npm, you can run the published-package demo from this checkout
|
|
103
102
|
without installing the repository's development dependencies:
|
|
@@ -119,7 +118,7 @@ npm ls prefix-safe-json ai zod
|
|
|
119
118
|
npm start
|
|
120
119
|
```
|
|
121
120
|
|
|
122
|
-
The
|
|
121
|
+
The current checkout pins `prefix-safe-json@0.5.3`, `ai@7.0.77`, and `zod@4.4.3`.
|
|
123
122
|
It needs no repository build, workspace aliases, or API key. It drives real
|
|
124
123
|
`streamText().fullStream` using the SDK's official `MockLanguageModelV4` and
|
|
125
124
|
imports the installed package's public entry point and `standard-schema`
|
|
@@ -161,6 +160,25 @@ It checks complete, token-limited, missing-`message_stop`, and post-terminal
|
|
|
161
160
|
argument cases through the SDK's actual SSE parser. The LangChain comparison
|
|
162
161
|
can also be launched with `node scripts/try-npm-demo.mjs langchain`.
|
|
163
162
|
|
|
163
|
+
Using the official OpenAI SDK? Run `node scripts/try-npm-demo.mjs openai` for
|
|
164
|
+
the [installed-package Chat Completions trial](examples/openai-consumer/README.md).
|
|
165
|
+
It checks complete and interrupted calls, duplicate IDs and late argument
|
|
166
|
+
evidence through `openai@7.34.0`. It also demonstrates a limit: PSJ cannot detect
|
|
167
|
+
upstream truncation when the provider supplies complete JSON and falsely
|
|
168
|
+
reports successful termination. These are mock-transport checks, not live
|
|
169
|
+
OpenAI or vLLM certification.
|
|
170
|
+
|
|
171
|
+
Using OpenRouter Agent? Run `node scripts/try-npm-demo.mjs openrouter` for the
|
|
172
|
+
[manual dispatch and continuation trial](examples/openrouter-consumer/README.md).
|
|
173
|
+
It checks that accepted tool results reach the next model request with matching
|
|
174
|
+
call IDs, while invalid batches cause zero effects and no continuation request.
|
|
175
|
+
It uses authored SSE through the installed SDK; no live model call is made.
|
|
176
|
+
|
|
177
|
+
Using TanStack AI with OpenRouter? Run `node scripts/try-npm-demo.mjs tanstack`
|
|
178
|
+
for the [server-tool comparison](examples/tanstack-consumer/README.md), which
|
|
179
|
+
uses PSJ `0.5.4` to check raw native finish reasons, usage trailers and paired
|
|
180
|
+
results in the next request. It uses harmless counters and authored SSE.
|
|
181
|
+
|
|
164
182
|
## Why parse success is not enough
|
|
165
183
|
|
|
166
184
|
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.
|
|
@@ -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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prefix-safe-json",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
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
|
}
|