@vincemakes/kiso-provider-openai 0.38.0 → 0.39.1
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/dist/index.js +33 -6
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { join } from "node:path";
|
|
18
18
|
import OpenAI from "openai";
|
|
19
|
-
import { mapApiError, parseRetryAfter } from "@vincemakes/kiso-core";
|
|
19
|
+
import { mapApiError, parseRetryAfter, streamFailure } from "@vincemakes/kiso-core";
|
|
20
20
|
/**
|
|
21
21
|
* High-level factory (round 7): builds the adapter FROM CONFIG, owning the SDK
|
|
22
22
|
* inside this package. Consumers (and the runtime's lazy provider path)
|
|
@@ -258,6 +258,33 @@ export function createOpenAICompatAdapter(client, adapterOpts = {}) {
|
|
|
258
258
|
catch (err) {
|
|
259
259
|
throw toOpenAIError(err, options.model);
|
|
260
260
|
}
|
|
261
|
+
// 0.39.1 — the verdict is read BEFORE anything is emitted. A
|
|
262
|
+
// stream that ended with NO finish_reason produced none: the
|
|
263
|
+
// protocol mandates one, so its absence is a failure somewhere
|
|
264
|
+
// in the path (a gateway ending a response its upstream
|
|
265
|
+
// abandoned is how a long session dies), never the provider's
|
|
266
|
+
// answer. It used to become `stop { reason: "error" }` — which
|
|
267
|
+
// the kernel reads as `unknown / provider stopped with an
|
|
268
|
+
// error`, non-retryable — so the run ended and a human had to
|
|
269
|
+
// restart it. `streamFailure` states the rule and the kernel's
|
|
270
|
+
// mid-stream recovery takes it from there.
|
|
271
|
+
//
|
|
272
|
+
// Placed ABOVE the close-out on purpose: the pending calls at
|
|
273
|
+
// this point are TRUNCATED. Emitting them launches them (the
|
|
274
|
+
// kernel starts an execution on `tool_call_end`), which would
|
|
275
|
+
// both run a tool on a half-arrived argument list and, once
|
|
276
|
+
// something has started, block the very retry this throw exists
|
|
277
|
+
// to reach (`unsafeStartedInDraft`).
|
|
278
|
+
//
|
|
279
|
+
// An abort keeps its existing path below: COMPAT-F1's early end
|
|
280
|
+
// is the caller's act, classified by the kernel from the throw
|
|
281
|
+
// with the signal set, and nothing here changes it. An
|
|
282
|
+
// UNRECOGNIZED finish_reason is the other non-case — the
|
|
283
|
+
// provider answered, we just do not know the word, and it still
|
|
284
|
+
// stops.
|
|
285
|
+
if (finishReason === null && !options.signal?.aborted) {
|
|
286
|
+
throw streamFailure(`[${vendorOf(options.model)}] request failed: the stream ended with no finish reason`);
|
|
287
|
+
}
|
|
261
288
|
// Close out any streamed tool calls.
|
|
262
289
|
for (const call of [...pending.values()].sort((a, b) => a.index - b.index)) {
|
|
263
290
|
let input = null;
|
|
@@ -286,8 +313,8 @@ export function createOpenAICompatAdapter(client, adapterOpts = {}) {
|
|
|
286
313
|
yield { seq: 0, type: "usage", inputTokens: null, outputTokens: null, cacheRead: null, cacheWrite: null, known: false, ...(served !== null ? { servedModel: served } : {}) };
|
|
287
314
|
}
|
|
288
315
|
// Area 6 hardening (review finding 4): a stream that ended with
|
|
289
|
-
// NO finish_reason is a TRUNCATED turn —
|
|
290
|
-
//
|
|
316
|
+
// NO finish_reason is a TRUNCATED turn — never a default
|
|
317
|
+
// end_turn/completed.
|
|
291
318
|
// COMPAT-F1 (2026-09-09, the GLM leg): the SDK closes an ABORTED
|
|
292
319
|
// stream quietly — the iterator just ends, no finish_reason — and
|
|
293
320
|
// that used to read as the provider's failure below, so esc on a
|
|
@@ -295,13 +322,13 @@ export function createOpenAICompatAdapter(client, adapterOpts = {}) {
|
|
|
295
322
|
// durable void. The kernel classifies an abort only when the
|
|
296
323
|
// adapter THROWS while the signal is set (its catch asks
|
|
297
324
|
// `aborted()` first), which is what the Responses adapter does.
|
|
298
|
-
// An early end WITHOUT an abort
|
|
325
|
+
// An early end WITHOUT an abort is the transport's failure.
|
|
299
326
|
if (options.signal?.aborted) {
|
|
300
327
|
const err = new Error("stream aborted by the caller");
|
|
301
328
|
err.name = "AbortError";
|
|
302
329
|
throw err;
|
|
303
330
|
}
|
|
304
|
-
yield { seq: 0, type: "stop", reason:
|
|
331
|
+
yield { seq: 0, type: "stop", reason: stopReason };
|
|
305
332
|
},
|
|
306
333
|
};
|
|
307
334
|
}
|
|
@@ -518,7 +545,7 @@ function toOpenAIError(err, model) {
|
|
|
518
545
|
// The name is fetch's, not the vendor's, so it is a transport failure by
|
|
519
546
|
// construction — the same class as APIConnectionError above.
|
|
520
547
|
if (err instanceof TypeError && (err.message === "terminated" || err.message === "fetch failed")) {
|
|
521
|
-
return
|
|
548
|
+
return streamFailure(label + err.message);
|
|
522
549
|
}
|
|
523
550
|
return err;
|
|
524
551
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-provider-openai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.1",
|
|
4
4
|
"description": "kiso OpenAI-compatible adapter \u2014 OpenAI + the compat family (GLM, Kimi, DeepSeek, OpenRouter) via base_url swap, reasoning dialects digested.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"test": "vitest run"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@vincemakes/kiso-core": "0.
|
|
24
|
+
"@vincemakes/kiso-core": "0.39.1",
|
|
25
25
|
"openai": "^7.3.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|