@byfriends/kosong 0.1.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/LICENSE +28 -0
- package/README.md +11 -0
- package/dist/anthropic-Dm_GqFgS.d.mts +69 -0
- package/dist/capability-registry-CMBuEYcf.mjs +161 -0
- package/dist/chat-completions-stream-BuMu_xr9.mjs +62 -0
- package/dist/errors-DweKbIOf.d.mts +42 -0
- package/dist/errors-WFxxzL1B.mjs +80 -0
- package/dist/google-genai-hX0X6CF3.d.mts +98 -0
- package/dist/index.d.mts +161 -0
- package/dist/index.mjs +287 -0
- package/dist/openai-common-08qin3UI.mjs +278 -0
- package/dist/openai-common-B6cK2ig3.d.mts +105 -0
- package/dist/openai-compat-CMrIk-ib.d.mts +132 -0
- package/dist/openai-compat-CWbwO4b7.mjs +801 -0
- package/dist/openai-legacy-B6CVfLlr.d.mts +71 -0
- package/dist/openai-responses-BxOwxtd3.d.mts +65 -0
- package/dist/provider-DiJKWMsQ.d.mts +371 -0
- package/dist/providers/anthropic.d.mts +2 -0
- package/dist/providers/anthropic.mjs +720 -0
- package/dist/providers/google-genai.d.mts +2 -0
- package/dist/providers/google-genai.mjs +562 -0
- package/dist/providers/openai-common.d.mts +2 -0
- package/dist/providers/openai-common.mjs +2 -0
- package/dist/providers/openai-compat.d.mts +2 -0
- package/dist/providers/openai-compat.mjs +2 -0
- package/dist/providers/openai-legacy.d.mts +2 -0
- package/dist/providers/openai-legacy.mjs +248 -0
- package/dist/providers/openai-responses.d.mts +2 -0
- package/dist/providers/openai-responses.mjs +623 -0
- package/dist/request-auth-DCWSyCKI.mjs +63 -0
- package/package.json +89 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { S as StreamedMessagePart, a as StreamedMessage, b as Message, c as TokenUsage, i as ProviderRequestAuth, m as ModelCapability, n as FinishReason, o as ThinkingEffort, p as Tool, r as GenerateOptions, t as ChatProvider } from "./provider-DiJKWMsQ.mjs";
|
|
2
|
+
import { i as ToolMessageConversion } from "./openai-common-B6cK2ig3.mjs";
|
|
3
|
+
import OpenAI from "openai";
|
|
4
|
+
|
|
5
|
+
//#region src/providers/openai-legacy.d.ts
|
|
6
|
+
interface OpenAILegacyOptions {
|
|
7
|
+
apiKey?: string | undefined;
|
|
8
|
+
baseUrl?: string | undefined;
|
|
9
|
+
model: string;
|
|
10
|
+
stream?: boolean | undefined;
|
|
11
|
+
maxTokens?: number | undefined;
|
|
12
|
+
reasoningKey?: string | undefined;
|
|
13
|
+
httpClient?: unknown;
|
|
14
|
+
defaultHeaders?: Record<string, string>;
|
|
15
|
+
toolMessageConversion?: ToolMessageConversion | undefined;
|
|
16
|
+
clientFactory?: (auth: ProviderRequestAuth) => OpenAI;
|
|
17
|
+
}
|
|
18
|
+
interface OpenAILegacyGenerationKwargs {
|
|
19
|
+
max_tokens?: number | undefined;
|
|
20
|
+
temperature?: number | undefined;
|
|
21
|
+
top_p?: number | undefined;
|
|
22
|
+
n?: number | undefined;
|
|
23
|
+
presence_penalty?: number | undefined;
|
|
24
|
+
frequency_penalty?: number | undefined;
|
|
25
|
+
stop?: string | string[] | undefined;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
declare class OpenAILegacyStreamedMessage implements StreamedMessage {
|
|
29
|
+
private _id;
|
|
30
|
+
private _usage;
|
|
31
|
+
private _finishReason;
|
|
32
|
+
private _rawFinishReason;
|
|
33
|
+
private readonly _iter;
|
|
34
|
+
constructor(response: OpenAI.Chat.ChatCompletion | AsyncIterable<OpenAI.Chat.ChatCompletionChunk>, isStream: boolean, reasoningKey: string | undefined);
|
|
35
|
+
get id(): string | null;
|
|
36
|
+
get usage(): TokenUsage | null;
|
|
37
|
+
get finishReason(): FinishReason | null;
|
|
38
|
+
get rawFinishReason(): string | null;
|
|
39
|
+
[Symbol.asyncIterator](): AsyncIterator<StreamedMessagePart>;
|
|
40
|
+
private _captureFinishReason;
|
|
41
|
+
private _convertNonStreamResponse;
|
|
42
|
+
private _convertStreamResponse;
|
|
43
|
+
}
|
|
44
|
+
declare class OpenAILegacyChatProvider implements ChatProvider {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
private _model;
|
|
47
|
+
private _stream;
|
|
48
|
+
private _apiKey;
|
|
49
|
+
private _baseUrl;
|
|
50
|
+
private _defaultHeaders;
|
|
51
|
+
private _reasoningKey;
|
|
52
|
+
private _reasoningEffort;
|
|
53
|
+
private _generationKwargs;
|
|
54
|
+
private _toolMessageConversion;
|
|
55
|
+
private _client;
|
|
56
|
+
private _httpClient;
|
|
57
|
+
private _clientFactory;
|
|
58
|
+
constructor(options: OpenAILegacyOptions);
|
|
59
|
+
get modelName(): string;
|
|
60
|
+
get thinkingEffort(): ThinkingEffort | null;
|
|
61
|
+
get modelParameters(): Record<string, unknown>;
|
|
62
|
+
getCapability(model?: string): ModelCapability;
|
|
63
|
+
generate(systemPrompt: string, tools: Tool[], history: Message[], options?: GenerateOptions): Promise<StreamedMessage>;
|
|
64
|
+
withThinking(effort: ThinkingEffort): OpenAILegacyChatProvider;
|
|
65
|
+
withGenerationKwargs(kwargs: OpenAILegacyGenerationKwargs): OpenAILegacyChatProvider;
|
|
66
|
+
private _clone;
|
|
67
|
+
private _createClient;
|
|
68
|
+
private _buildClient;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { OpenAILegacyStreamedMessage as i, OpenAILegacyGenerationKwargs as n, OpenAILegacyOptions as r, OpenAILegacyChatProvider as t };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { S as StreamedMessagePart, a as StreamedMessage, b as Message, c as TokenUsage, i as ProviderRequestAuth, m as ModelCapability, n as FinishReason, o as ThinkingEffort, p as Tool, r as GenerateOptions, t as ChatProvider } from "./provider-DiJKWMsQ.mjs";
|
|
2
|
+
import { i as ToolMessageConversion } from "./openai-common-B6cK2ig3.mjs";
|
|
3
|
+
import OpenAI from "openai";
|
|
4
|
+
|
|
5
|
+
//#region src/providers/openai-responses.d.ts
|
|
6
|
+
interface OpenAIResponsesOptions {
|
|
7
|
+
apiKey?: string | undefined;
|
|
8
|
+
baseUrl?: string | undefined;
|
|
9
|
+
model: string;
|
|
10
|
+
maxOutputTokens?: number | undefined;
|
|
11
|
+
httpClient?: unknown;
|
|
12
|
+
defaultHeaders?: Record<string, string>;
|
|
13
|
+
toolMessageConversion?: ToolMessageConversion | undefined;
|
|
14
|
+
clientFactory?: (auth: ProviderRequestAuth) => OpenAI;
|
|
15
|
+
}
|
|
16
|
+
interface OpenAIResponsesGenerationKwargs {
|
|
17
|
+
max_output_tokens?: number | undefined;
|
|
18
|
+
temperature?: number | undefined;
|
|
19
|
+
top_p?: number | undefined;
|
|
20
|
+
reasoning_effort?: string | undefined;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
declare class OpenAIResponsesStreamedMessage implements StreamedMessage {
|
|
24
|
+
private _id;
|
|
25
|
+
private _usage;
|
|
26
|
+
private _finishReason;
|
|
27
|
+
private _rawFinishReason;
|
|
28
|
+
private readonly _iter;
|
|
29
|
+
constructor(response: unknown, isStream: boolean);
|
|
30
|
+
get id(): string | null;
|
|
31
|
+
get usage(): TokenUsage | null;
|
|
32
|
+
get finishReason(): FinishReason | null;
|
|
33
|
+
get rawFinishReason(): string | null;
|
|
34
|
+
[Symbol.asyncIterator](): AsyncIterator<StreamedMessagePart>;
|
|
35
|
+
private _captureFinishReasonFromResponse;
|
|
36
|
+
private _extractUsage;
|
|
37
|
+
private _convertNonStreamResponse;
|
|
38
|
+
private _convertStreamResponse;
|
|
39
|
+
}
|
|
40
|
+
declare class OpenAIResponsesChatProvider implements ChatProvider {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
private _model;
|
|
43
|
+
private _stream;
|
|
44
|
+
private _apiKey;
|
|
45
|
+
private _baseUrl;
|
|
46
|
+
private _defaultHeaders;
|
|
47
|
+
private _generationKwargs;
|
|
48
|
+
private _toolMessageConversion;
|
|
49
|
+
private _client;
|
|
50
|
+
private _httpClient;
|
|
51
|
+
private _clientFactory;
|
|
52
|
+
constructor(options: OpenAIResponsesOptions);
|
|
53
|
+
get modelName(): string;
|
|
54
|
+
get thinkingEffort(): ThinkingEffort | null;
|
|
55
|
+
get modelParameters(): Record<string, unknown>;
|
|
56
|
+
getCapability(model?: string): ModelCapability;
|
|
57
|
+
generate(systemPrompt: string, tools: Tool[], history: Message[], options?: GenerateOptions): Promise<StreamedMessage>;
|
|
58
|
+
withThinking(effort: ThinkingEffort): OpenAIResponsesChatProvider;
|
|
59
|
+
withGenerationKwargs(kwargs: OpenAIResponsesGenerationKwargs): OpenAIResponsesChatProvider;
|
|
60
|
+
private _clone;
|
|
61
|
+
private _createClient;
|
|
62
|
+
private _buildClient;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { OpenAIResponsesStreamedMessage as i, OpenAIResponsesGenerationKwargs as n, OpenAIResponsesOptions as r, OpenAIResponsesChatProvider as t };
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
//#region src/message.d.ts
|
|
2
|
+
type Role = 'system' | 'user' | 'assistant' | 'tool';
|
|
3
|
+
interface TextPart {
|
|
4
|
+
type: 'text';
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
interface ThinkPart {
|
|
8
|
+
type: 'think';
|
|
9
|
+
think: string;
|
|
10
|
+
encrypted?: string;
|
|
11
|
+
}
|
|
12
|
+
interface ImageURLPart {
|
|
13
|
+
type: 'image_url';
|
|
14
|
+
imageUrl: {
|
|
15
|
+
url: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface AudioURLPart {
|
|
20
|
+
type: 'audio_url';
|
|
21
|
+
audioUrl: {
|
|
22
|
+
url: string;
|
|
23
|
+
id?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface VideoURLPart {
|
|
27
|
+
type: 'video_url';
|
|
28
|
+
videoUrl: {
|
|
29
|
+
url: string;
|
|
30
|
+
id?: string | undefined;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A single piece of content within a {@link Message}.
|
|
35
|
+
*
|
|
36
|
+
* The union covers text, model reasoning ("think"), images, audio, and video.
|
|
37
|
+
* Providers convert these to their native content-block format during
|
|
38
|
+
* {@link ChatProvider.generate}.
|
|
39
|
+
*/
|
|
40
|
+
type ContentPart = TextPart | ThinkPart | ImageURLPart | AudioURLPart | VideoURLPart;
|
|
41
|
+
interface ToolCall {
|
|
42
|
+
type: 'function';
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
arguments: string | null;
|
|
46
|
+
extras?: Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Provider-specific streaming index used to route argument deltas to the
|
|
49
|
+
* correct parallel tool call. Set by streaming providers (OpenAI Chat
|
|
50
|
+
* Completions `index`, Responses API `item_id`). Consumed internally by
|
|
51
|
+
* {@link generate} and stripped before the ToolCall is stored on a Message.
|
|
52
|
+
*
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
_streamIndex?: number | string;
|
|
56
|
+
}
|
|
57
|
+
/** Streaming delta for tool call arguments. */
|
|
58
|
+
interface ToolCallPart {
|
|
59
|
+
type: 'tool_call_part';
|
|
60
|
+
argumentsPart: string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Provider-specific index for routing this streaming delta to the correct
|
|
63
|
+
* parallel tool call. Used by OpenAI Chat Completions (`index`) and
|
|
64
|
+
* Responses API (`item_id`/`output_index`). When absent, the delta is
|
|
65
|
+
* appended to the most-recently-seen ToolCall (single-tool-call fallback).
|
|
66
|
+
*/
|
|
67
|
+
index?: number | string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A single chunk yielded by {@link StreamedMessage}'s async iterator.
|
|
71
|
+
*
|
|
72
|
+
* During streaming, the generate loop receives a sequence of these parts and
|
|
73
|
+
* merges compatible consecutive parts (e.g. TextPart + TextPart) in-place so
|
|
74
|
+
* the final {@link Message} contains fully-assembled content.
|
|
75
|
+
*
|
|
76
|
+
* Tool-call completion is inferred from merge boundaries (a non-merging next
|
|
77
|
+
* part flushes the pending tool call) and from stream end. Provider adapters
|
|
78
|
+
* are responsible for translating their native "done" signals into this
|
|
79
|
+
* shape; they do not emit a separate done event.
|
|
80
|
+
*/
|
|
81
|
+
type StreamedMessagePart = ContentPart | ToolCall | ToolCallPart;
|
|
82
|
+
/**
|
|
83
|
+
* A single message in a conversation.
|
|
84
|
+
*
|
|
85
|
+
* Messages carry a {@link role} (system, user, assistant, or tool), an array
|
|
86
|
+
* of {@link ContentPart} content blocks, and optional {@link ToolCall} entries.
|
|
87
|
+
* Tool result messages set {@link toolCallId} to correlate with the originating
|
|
88
|
+
* call.
|
|
89
|
+
*/
|
|
90
|
+
interface Message {
|
|
91
|
+
/** The role of the message sender. */
|
|
92
|
+
role: Role;
|
|
93
|
+
/** Optional display name for the sender (used by some providers). */
|
|
94
|
+
name?: string;
|
|
95
|
+
/** Ordered content parts (text, images, thinking, etc.). */
|
|
96
|
+
content: ContentPart[];
|
|
97
|
+
/** Tool calls requested by the assistant in this message. */
|
|
98
|
+
toolCalls: ToolCall[];
|
|
99
|
+
/** For `tool` role messages, the ID of the tool call this result answers. */
|
|
100
|
+
toolCallId?: string;
|
|
101
|
+
/** When `true`, indicates the message was not fully received (e.g. stream interrupted). */
|
|
102
|
+
partial?: boolean;
|
|
103
|
+
}
|
|
104
|
+
/** Check if a streamed part is a ContentPart (text, think, image_url, audio_url, video_url). */
|
|
105
|
+
declare function isContentPart(part: StreamedMessagePart): part is ContentPart;
|
|
106
|
+
/** Check if a streamed part is a ToolCall. */
|
|
107
|
+
declare function isToolCall(part: StreamedMessagePart): part is ToolCall;
|
|
108
|
+
/** Check if a streamed part is a ToolCallPart (streaming argument delta). */
|
|
109
|
+
declare function isToolCallPart(part: StreamedMessagePart): part is ToolCallPart;
|
|
110
|
+
/**
|
|
111
|
+
* Merge `source` into `target` in-place for streaming accumulation.
|
|
112
|
+
*
|
|
113
|
+
* Supported combinations:
|
|
114
|
+
* - TextPart + TextPart -> concatenate text
|
|
115
|
+
* - ThinkPart + ThinkPart -> concatenate think (refuse if target.encrypted already set)
|
|
116
|
+
* - ToolCall + ToolCallPart -> append arguments
|
|
117
|
+
*
|
|
118
|
+
* **Routing for parallel tool calls**: When OpenAI (or compatible) APIs stream
|
|
119
|
+
* multiple tool calls in parallel, argument deltas may interleave across calls.
|
|
120
|
+
* To handle this, {@link generate} routes ToolCallParts by their optional
|
|
121
|
+
* {@link ToolCallPart.index} field (mirroring the provider's streaming index)
|
|
122
|
+
* to the correct pending ToolCall, rather than relying on sequential ordering.
|
|
123
|
+
* This function still performs sequential merging as a fallback when the
|
|
124
|
+
* pending part matches the incoming one.
|
|
125
|
+
*
|
|
126
|
+
* Returns `true` if the merge was performed, `false` otherwise.
|
|
127
|
+
*/
|
|
128
|
+
declare function mergeInPlace(target: StreamedMessagePart, source: StreamedMessagePart): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Extract the concatenated text from a message's content parts.
|
|
131
|
+
*
|
|
132
|
+
* @param message The message to extract text from.
|
|
133
|
+
* @param sep Separator between text parts. Defaults to empty string.
|
|
134
|
+
*/
|
|
135
|
+
declare function extractText(message: Message, sep?: string): string;
|
|
136
|
+
/** Create a simple user message with a single text part. */
|
|
137
|
+
declare function createUserMessage(content: string): Message;
|
|
138
|
+
/** Create an assistant message from content parts and optional tool calls. */
|
|
139
|
+
declare function createAssistantMessage(content: ContentPart[], toolCalls?: ToolCall[]): Message;
|
|
140
|
+
/** Create a tool result message. */
|
|
141
|
+
declare function createToolMessage(toolCallId: string, output: string | ContentPart[]): Message;
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/capability.d.ts
|
|
144
|
+
/**
|
|
145
|
+
* Declared capabilities for a specific model exposed by a {@link ChatProvider}.
|
|
146
|
+
*
|
|
147
|
+
* Providers return one of these from {@link ChatProvider.getCapability} so
|
|
148
|
+
* callers can gate requests against modalities the model does not accept
|
|
149
|
+
* without dispatching the request and watching it fail upstream.
|
|
150
|
+
*
|
|
151
|
+
* `max_context_tokens: 0` means "unknown"; callers that do not gate on
|
|
152
|
+
* context length can ignore the field.
|
|
153
|
+
*/
|
|
154
|
+
interface ModelCapability {
|
|
155
|
+
readonly image_in: boolean;
|
|
156
|
+
readonly video_in: boolean;
|
|
157
|
+
readonly audio_in: boolean;
|
|
158
|
+
readonly thinking: boolean;
|
|
159
|
+
readonly tool_use: boolean;
|
|
160
|
+
readonly max_context_tokens: number;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Shared read-only default returned when a provider has not catalogued a
|
|
164
|
+
* given model. Frozen so accidental mutation at one call site cannot leak
|
|
165
|
+
* into another.
|
|
166
|
+
*/
|
|
167
|
+
declare const UNKNOWN_CAPABILITY: ModelCapability;
|
|
168
|
+
declare function isUnknownCapability(capability: ModelCapability): boolean;
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/tool.d.ts
|
|
171
|
+
/**
|
|
172
|
+
* A tool that the model may invoke during generation.
|
|
173
|
+
*
|
|
174
|
+
* The definition is provider-agnostic; each provider implementation converts
|
|
175
|
+
* it to the appropriate wire format (e.g. OpenAI function-calling, Anthropic
|
|
176
|
+
* tool-use, Google function declarations).
|
|
177
|
+
*/
|
|
178
|
+
interface Tool {
|
|
179
|
+
/** Unique tool name used to match invocations. */
|
|
180
|
+
name: string;
|
|
181
|
+
/** Human-readable description shown to the model. */
|
|
182
|
+
description: string;
|
|
183
|
+
/** JSON Schema describing the tool's parameters. */
|
|
184
|
+
parameters: Record<string, unknown>;
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/usage.d.ts
|
|
188
|
+
/**
|
|
189
|
+
* Token usage breakdown for a single LLM generation.
|
|
190
|
+
*
|
|
191
|
+
* Providers map their native usage counters into this common shape so
|
|
192
|
+
* callers can aggregate costs without caring about the backend.
|
|
193
|
+
*/
|
|
194
|
+
interface TokenUsage {
|
|
195
|
+
/** Input tokens that were neither cache-read nor cache-created. */
|
|
196
|
+
inputOther: number;
|
|
197
|
+
/** Output (completion) tokens generated by the model. */
|
|
198
|
+
output: number;
|
|
199
|
+
/** Input tokens served from the provider's prompt cache. */
|
|
200
|
+
inputCacheRead: number;
|
|
201
|
+
/** Input tokens written into the provider's prompt cache. */
|
|
202
|
+
inputCacheCreation: number;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Compute total input tokens (other + cache read + cache creation).
|
|
206
|
+
*/
|
|
207
|
+
declare function inputTotal(usage: TokenUsage): number;
|
|
208
|
+
/**
|
|
209
|
+
* Compute grand total tokens (input total + output).
|
|
210
|
+
*/
|
|
211
|
+
declare function grandTotal(usage: TokenUsage): number;
|
|
212
|
+
/**
|
|
213
|
+
* Create a zero-valued TokenUsage.
|
|
214
|
+
*/
|
|
215
|
+
declare function emptyUsage(): TokenUsage;
|
|
216
|
+
/**
|
|
217
|
+
* Sum two TokenUsage values.
|
|
218
|
+
*/
|
|
219
|
+
declare function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/provider.d.ts
|
|
222
|
+
/**
|
|
223
|
+
* Normalized thinking effort level used across providers.
|
|
224
|
+
*
|
|
225
|
+
* Values above `high` are provider/model-specific and may be clamped by the
|
|
226
|
+
* adapter when the native API has no matching level. OpenAI maps `max` to its
|
|
227
|
+
* `xhigh` ceiling; Byf and Gemini cap `xhigh`/`max` at `high`; Anthropic
|
|
228
|
+
* supports `xhigh`/`max` only on selected models and otherwise clamps to
|
|
229
|
+
* `high`.
|
|
230
|
+
*/
|
|
231
|
+
type ThinkingEffort = 'off' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
232
|
+
/**
|
|
233
|
+
* Normalized finish-reason signal indicating why a generation stopped.
|
|
234
|
+
*
|
|
235
|
+
* Each provider's native stop value is mapped to one of these, and the
|
|
236
|
+
* unmapped original string is preserved in `rawFinishReason` as an escape
|
|
237
|
+
* hatch. `null` means the provider did not emit a finish_reason (e.g. the
|
|
238
|
+
* stream was cut off before the final event).
|
|
239
|
+
*
|
|
240
|
+
* - `'completed'`: normal completion (OpenAI `'stop'`, Anthropic
|
|
241
|
+
* `'end_turn'` / `'stop_sequence'`, Gemini `'STOP'`).
|
|
242
|
+
* - `'tool_calls'`: generation paused so the caller can dispatch tool
|
|
243
|
+
* calls and feed their results back. Note that the OpenAI Responses API
|
|
244
|
+
* and Google GenAI report `'completed'` here; only the Chat
|
|
245
|
+
* Completions–style providers and Anthropic surface a dedicated value.
|
|
246
|
+
* - `'truncated'`: token budget exhausted (OpenAI `'length'`, Anthropic
|
|
247
|
+
* `'max_tokens'`, Gemini `'MAX_TOKENS'`, Responses `'max_output_tokens'`).
|
|
248
|
+
* - `'filtered'`: content filter or safety policy blocked the response.
|
|
249
|
+
* - `'paused'`: Anthropic-specific `'pause_turn'`.
|
|
250
|
+
* - `'other'`: recognized non-null reason that does not fit the categories
|
|
251
|
+
* above.
|
|
252
|
+
*/
|
|
253
|
+
type FinishReason = 'completed' | 'tool_calls' | 'truncated' | 'filtered' | 'paused' | 'other';
|
|
254
|
+
/**
|
|
255
|
+
* An async-iterable stream of message parts produced by a single LLM response.
|
|
256
|
+
*
|
|
257
|
+
* Consumers iterate over the stream with `for await..of` to receive
|
|
258
|
+
* {@link StreamedMessagePart} chunks. After the iteration completes, the
|
|
259
|
+
* {@link id}, {@link usage}, {@link finishReason}, and
|
|
260
|
+
* {@link rawFinishReason} properties reflect the final values reported by
|
|
261
|
+
* the provider.
|
|
262
|
+
*/
|
|
263
|
+
interface StreamedMessage {
|
|
264
|
+
[Symbol.asyncIterator](): AsyncIterator<StreamedMessagePart>;
|
|
265
|
+
/** Provider-assigned response identifier, or `null` if not available. */
|
|
266
|
+
readonly id: string | null;
|
|
267
|
+
/** Token usage statistics, populated after the stream completes. */
|
|
268
|
+
readonly usage: TokenUsage | null;
|
|
269
|
+
/**
|
|
270
|
+
* Normalized finish reason, populated after the stream completes.
|
|
271
|
+
*
|
|
272
|
+
* `null` if the provider did not emit a finish_reason (for example, the
|
|
273
|
+
* stream was interrupted before the final event arrived).
|
|
274
|
+
*/
|
|
275
|
+
readonly finishReason: FinishReason | null;
|
|
276
|
+
/**
|
|
277
|
+
* Raw provider-specific finish_reason string, preserved verbatim as an
|
|
278
|
+
* escape hatch for callers that need the original wire value.
|
|
279
|
+
*
|
|
280
|
+
* `null` if the provider did not emit a finish_reason.
|
|
281
|
+
*/
|
|
282
|
+
readonly rawFinishReason: string | null;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Options that can be forwarded to a single {@link ChatProvider.generate} call.
|
|
286
|
+
*/
|
|
287
|
+
interface ProviderRequestAuth {
|
|
288
|
+
/** Bearer/API token resolved for this specific provider request. */
|
|
289
|
+
apiKey?: string;
|
|
290
|
+
/** Request-scoped headers. These override constructor-level default headers. */
|
|
291
|
+
headers?: Record<string, string>;
|
|
292
|
+
}
|
|
293
|
+
interface GenerateOptions {
|
|
294
|
+
/**
|
|
295
|
+
* An {@link AbortSignal} that, when aborted, requests cancellation of the
|
|
296
|
+
* in-flight generate call. Providers that accept a signal will forward it
|
|
297
|
+
* to their underlying HTTP client; the generate loop in
|
|
298
|
+
* {@link generate | generate()} also checks the signal between streamed
|
|
299
|
+
* parts.
|
|
300
|
+
*/
|
|
301
|
+
signal?: AbortSignal;
|
|
302
|
+
/**
|
|
303
|
+
* Request-scoped provider auth. Hosts should resolve this immediately before
|
|
304
|
+
* each request/retry so providers never retain mutable credential state.
|
|
305
|
+
*/
|
|
306
|
+
auth?: ProviderRequestAuth;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* In-memory video bytes for providers that require an uploaded file
|
|
310
|
+
* reference instead of an inline data URL.
|
|
311
|
+
*/
|
|
312
|
+
interface VideoUploadInput {
|
|
313
|
+
readonly data: Uint8Array;
|
|
314
|
+
readonly mimeType: string;
|
|
315
|
+
readonly filename?: string | undefined;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Unified interface for an LLM chat provider.
|
|
319
|
+
*
|
|
320
|
+
* Each provider implementation (Byf, OpenAI, Anthropic, Google GenAI, etc.)
|
|
321
|
+
* converts the common {@link Message} / {@link Tool} types into the
|
|
322
|
+
* provider-specific wire format, streams back a {@link StreamedMessage}, and
|
|
323
|
+
* exposes configuration helpers such as {@link withThinking}.
|
|
324
|
+
*/
|
|
325
|
+
interface ChatProvider {
|
|
326
|
+
/** Short identifier for the provider backend (e.g. `"byf"`, `"anthropic"`). */
|
|
327
|
+
readonly name: string;
|
|
328
|
+
/** Model name passed to the upstream API (e.g. `"byf-v1-auto"`). */
|
|
329
|
+
readonly modelName: string;
|
|
330
|
+
/** Current thinking-effort level, or `null` if thinking is not configured. */
|
|
331
|
+
readonly thinkingEffort: ThinkingEffort | null;
|
|
332
|
+
/**
|
|
333
|
+
* Send a conversation to the LLM and return a streamed response.
|
|
334
|
+
*
|
|
335
|
+
* @param systemPrompt - System-level instruction prepended to the request.
|
|
336
|
+
* @param tools - Tool definitions the model may invoke.
|
|
337
|
+
* @param history - The conversation history (user, assistant, tool messages).
|
|
338
|
+
* @param options - Optional per-call settings such as an {@link AbortSignal}.
|
|
339
|
+
*/
|
|
340
|
+
generate(systemPrompt: string, tools: Tool[], history: Message[], options?: GenerateOptions): Promise<StreamedMessage>;
|
|
341
|
+
/** Return a shallow copy of this provider with the given thinking effort. */
|
|
342
|
+
withThinking(effort: ThinkingEffort): ChatProvider;
|
|
343
|
+
/**
|
|
344
|
+
* Return a shallow copy of this provider with the per-request completion
|
|
345
|
+
* budget clamped to `maxCompletionTokens`. Optional because not every
|
|
346
|
+
* backend benefits from a client-computed cap.
|
|
347
|
+
*
|
|
348
|
+
* Implementations MUST NOT mutate or replace internal HTTP clients on the
|
|
349
|
+
* returned clone — the clone is expected to share transport state with the
|
|
350
|
+
* original. See `OpenAICompatChatProvider._clone()` for the rationale.
|
|
351
|
+
*/
|
|
352
|
+
withMaxCompletionTokens?(maxCompletionTokens: number): ChatProvider;
|
|
353
|
+
/** Upload a video and return a content part that can be sent to this provider. */
|
|
354
|
+
uploadVideo?(input: string | VideoUploadInput, options?: GenerateOptions): Promise<VideoURLPart>;
|
|
355
|
+
/**
|
|
356
|
+
* Return declared capabilities for `model` (defaults to `modelName`).
|
|
357
|
+
*
|
|
358
|
+
* Unknown / uncatalogued models return {@link UNKNOWN_CAPABILITY} rather
|
|
359
|
+
* than throwing, so capability checks stay non-fatal and operators can
|
|
360
|
+
* point at private/custom deployments without crashing.
|
|
361
|
+
*
|
|
362
|
+
* Optional on the interface so pre-existing test mocks (which predate
|
|
363
|
+
* the capability matrix) still structurally satisfy `ChatProvider`
|
|
364
|
+
* without churn. Callers that gate on modalities should fall back to
|
|
365
|
+
* {@link UNKNOWN_CAPABILITY} when a provider does not expose it.
|
|
366
|
+
*/
|
|
367
|
+
getCapability?(model?: string): ModelCapability;
|
|
368
|
+
getContextSizeLimit?(): number | undefined;
|
|
369
|
+
}
|
|
370
|
+
//#endregion
|
|
371
|
+
export { createUserMessage as A, TextPart as C, VideoURLPart as D, ToolCallPart as E, mergeInPlace as F, isContentPart as M, isToolCall as N, createAssistantMessage as O, isToolCallPart as P, StreamedMessagePart as S, ToolCall as T, AudioURLPart as _, StreamedMessage as a, Message as b, TokenUsage as c, grandTotal as d, inputTotal as f, isUnknownCapability as g, UNKNOWN_CAPABILITY as h, ProviderRequestAuth as i, extractText as j, createToolMessage as k, addUsage as l, ModelCapability as m, FinishReason as n, ThinkingEffort as o, Tool as p, GenerateOptions as r, VideoUploadInput as s, ChatProvider as t, emptyUsage as u, ContentPart as v, ThinkPart as w, Role as x, ImageURLPart as y };
|