@vincemakes/kiso-provider-openai 0.15.11 → 0.16.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/dist/index.d.ts +16 -1
- package/dist/index.js +44 -5
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,18 @@ import type { Adapter } from "@vincemakes/kiso-core";
|
|
|
20
20
|
export interface OpenAICompatProviderConfig {
|
|
21
21
|
readonly apiKey?: string;
|
|
22
22
|
readonly baseUrl?: string;
|
|
23
|
+
/** MG-1 (A5): the adapter's replay identity — providerId as the runtime
|
|
24
|
+
* resolved it (deepseek / zai / openai / custom). Absent = "custom"
|
|
25
|
+
* with the baseUrl origin as the endpoint term. */
|
|
26
|
+
readonly scope?: OpenAICompatScope;
|
|
27
|
+
}
|
|
28
|
+
/** MG-1 (A5): the compat adapter's own half of the continuation scope.
|
|
29
|
+
* apiId is constant ("openai-chat") and modelId is per-request; only the
|
|
30
|
+
* provider identity and (for custom) the endpoint origin need injecting —
|
|
31
|
+
* the generic compat wire cannot know WHICH provider it is. */
|
|
32
|
+
export interface OpenAICompatScope {
|
|
33
|
+
readonly providerId: string;
|
|
34
|
+
readonly endpoint?: string;
|
|
23
35
|
}
|
|
24
36
|
/**
|
|
25
37
|
* High-level factory (round 7): builds the adapter FROM CONFIG, owning the SDK
|
|
@@ -29,5 +41,8 @@ export interface OpenAICompatProviderConfig {
|
|
|
29
41
|
* through a hoisted root.
|
|
30
42
|
*/
|
|
31
43
|
export declare function createOpenAICompatProvider(config?: OpenAICompatProviderConfig): Adapter;
|
|
32
|
-
export
|
|
44
|
+
export interface OpenAICompatAdapterOptions {
|
|
45
|
+
readonly scope?: OpenAICompatScope;
|
|
46
|
+
}
|
|
47
|
+
export declare function createOpenAICompatAdapter(client: OpenAI, adapterOpts?: OpenAICompatAdapterOptions): Adapter;
|
|
33
48
|
export type { ChatCompletionChunk };
|
package/dist/index.js
CHANGED
|
@@ -29,9 +29,21 @@ export function createOpenAICompatProvider(config = {}) {
|
|
|
29
29
|
...(config.apiKey !== undefined ? { apiKey: config.apiKey } : {}),
|
|
30
30
|
...(config.baseUrl !== undefined ? { baseURL: config.baseUrl } : {}),
|
|
31
31
|
});
|
|
32
|
-
|
|
32
|
+
const origin = (() => {
|
|
33
|
+
if (config.baseUrl === undefined)
|
|
34
|
+
return undefined;
|
|
35
|
+
try {
|
|
36
|
+
return new URL(config.baseUrl).origin;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
const scope = config.scope ?? (origin !== undefined ? { providerId: "custom", endpoint: origin } : undefined);
|
|
43
|
+
return createOpenAICompatAdapter(client, { ...(scope !== undefined ? { scope } : {}) });
|
|
33
44
|
}
|
|
34
|
-
export function createOpenAICompatAdapter(client) {
|
|
45
|
+
export function createOpenAICompatAdapter(client, adapterOpts = {}) {
|
|
46
|
+
const ownScope = adapterOpts.scope;
|
|
35
47
|
return {
|
|
36
48
|
async *stream(options) {
|
|
37
49
|
// The explicit streaming params type keeps the `stream: true`
|
|
@@ -39,7 +51,17 @@ export function createOpenAICompatAdapter(client) {
|
|
|
39
51
|
// create() call as the NON-streaming variant (TS2504).
|
|
40
52
|
const body = {
|
|
41
53
|
model: options.model,
|
|
42
|
-
messages: toOpenAIMessages(options.messages, options.systemPrompt),
|
|
54
|
+
messages: toOpenAIMessages(options.messages, options.systemPrompt, options.model, ownScope),
|
|
55
|
+
// XP-1: the resolved setting, DeepSeek V4 shape (the
|
|
56
|
+
// thinking-mode guide, read 2026-08-26): top-level
|
|
57
|
+
// thinking:{type} + reasoning_effort. Absent adds NO key.
|
|
58
|
+
// The `thinking` extension is absent from the SDK's param
|
|
59
|
+
// type; the spread rides a cast — the reasoning_content
|
|
60
|
+
// precedent, one object over.
|
|
61
|
+
...({
|
|
62
|
+
...(options.reasoning?.thinking !== undefined ? { thinking: { type: options.reasoning.thinking } } : {}),
|
|
63
|
+
...(options.reasoning?.effort !== undefined ? { reasoning_effort: options.reasoning.effort } : {}),
|
|
64
|
+
}),
|
|
43
65
|
stream: true,
|
|
44
66
|
// D5: request real streaming usage — without this the
|
|
45
67
|
// provider never sends a usage chunk and we would
|
|
@@ -317,7 +339,24 @@ function toOpenAIToolResultContent(content) {
|
|
|
317
339
|
: `[image omitted — OpenAI tool results accept text only: ${b.sourceType === "base64" ? `${b.mediaType ?? "image"} (${b.data?.length ?? 0} base64 chars)` : `url ${b.url ?? ""}`}]`)
|
|
318
340
|
.join("");
|
|
319
341
|
}
|
|
320
|
-
|
|
342
|
+
/** A5: the reasoning text replays ONLY when the turn's envelope matches
|
|
343
|
+
* THIS binding — provider AND api AND model AND (for custom) the endpoint
|
|
344
|
+
* origin. Foreign content is withheld as "" so the monotone PRESENCE
|
|
345
|
+
* discipline (below) holds byte-stably. A turn with NO envelope is the
|
|
346
|
+
* grandfather: pre-A5 logs replay under the pre-existing rule verbatim. */
|
|
347
|
+
function reasoningFor(msg, model, ownScope) {
|
|
348
|
+
const c = msg.continuation;
|
|
349
|
+
if (c === undefined)
|
|
350
|
+
return msg.reasoning ?? "";
|
|
351
|
+
const s = c.scope;
|
|
352
|
+
const providerId = ownScope?.providerId ?? "custom";
|
|
353
|
+
const matches = s.apiId === "openai-chat" &&
|
|
354
|
+
s.providerId === providerId &&
|
|
355
|
+
s.modelId === model &&
|
|
356
|
+
(s.providerId !== "custom" || s.endpoint === ownScope?.endpoint);
|
|
357
|
+
return matches ? (msg.reasoning ?? "") : "";
|
|
358
|
+
}
|
|
359
|
+
function toOpenAIMessages(messages, systemPrompt, model = "", ownScope) {
|
|
321
360
|
const out = [];
|
|
322
361
|
// The OpenAI API takes the system prompt as a system-role message; compat
|
|
323
362
|
// providers (GLM/Kimi/DeepSeek/OpenRouter) follow the same shape. It was
|
|
@@ -366,7 +405,7 @@ function toOpenAIMessages(messages, systemPrompt) {
|
|
|
366
405
|
// added via spread so the literal stays assignable (the union
|
|
367
406
|
// type carries the extra key). Presence follows hasReasoning
|
|
368
407
|
// (the monotone rule above — the field never flips mid-history).
|
|
369
|
-
...(hasReasoning ? { reasoning_content: msg
|
|
408
|
+
...(hasReasoning ? { reasoning_content: reasoningFor(msg, model, ownScope) } : {}),
|
|
370
409
|
});
|
|
371
410
|
}
|
|
372
411
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-provider-openai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
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.16.0",
|
|
25
25
|
"openai": "^7.3.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|