@draht/ai 2026.3.2-2
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 +1185 -0
- package/dist/api-registry.d.ts +20 -0
- package/dist/api-registry.d.ts.map +1 -0
- package/dist/api-registry.js +44 -0
- package/dist/api-registry.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +116 -0
- package/dist/cli.js.map +1 -0
- package/dist/env-api-keys.d.ts +9 -0
- package/dist/env-api-keys.d.ts.map +1 -0
- package/dist/env-api-keys.js +99 -0
- package/dist/env-api-keys.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +24 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.generated.d.ts +13133 -0
- package/dist/models.generated.d.ts.map +1 -0
- package/dist/models.generated.js +12939 -0
- package/dist/models.generated.js.map +1 -0
- package/dist/models.js +55 -0
- package/dist/models.js.map +1 -0
- package/dist/providers/amazon-bedrock.d.ts +15 -0
- package/dist/providers/amazon-bedrock.d.ts.map +1 -0
- package/dist/providers/amazon-bedrock.js +585 -0
- package/dist/providers/amazon-bedrock.js.map +1 -0
- package/dist/providers/anthropic.d.ts +33 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +729 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/azure-openai-responses.d.ts +15 -0
- package/dist/providers/azure-openai-responses.d.ts.map +1 -0
- package/dist/providers/azure-openai-responses.js +184 -0
- package/dist/providers/azure-openai-responses.js.map +1 -0
- package/dist/providers/github-copilot-headers.d.ts +8 -0
- package/dist/providers/github-copilot-headers.d.ts.map +1 -0
- package/dist/providers/github-copilot-headers.js +29 -0
- package/dist/providers/github-copilot-headers.js.map +1 -0
- package/dist/providers/google-gemini-cli.d.ts +74 -0
- package/dist/providers/google-gemini-cli.d.ts.map +1 -0
- package/dist/providers/google-gemini-cli.js +735 -0
- package/dist/providers/google-gemini-cli.js.map +1 -0
- package/dist/providers/google-shared.d.ts +65 -0
- package/dist/providers/google-shared.d.ts.map +1 -0
- package/dist/providers/google-shared.js +306 -0
- package/dist/providers/google-shared.js.map +1 -0
- package/dist/providers/google-vertex.d.ts +15 -0
- package/dist/providers/google-vertex.d.ts.map +1 -0
- package/dist/providers/google-vertex.js +371 -0
- package/dist/providers/google-vertex.js.map +1 -0
- package/dist/providers/google.d.ts +13 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +352 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/openai-codex-responses.d.ts +9 -0
- package/dist/providers/openai-codex-responses.d.ts.map +1 -0
- package/dist/providers/openai-codex-responses.js +699 -0
- package/dist/providers/openai-codex-responses.js.map +1 -0
- package/dist/providers/openai-completions.d.ts +15 -0
- package/dist/providers/openai-completions.d.ts.map +1 -0
- package/dist/providers/openai-completions.js +712 -0
- package/dist/providers/openai-completions.js.map +1 -0
- package/dist/providers/openai-responses-shared.d.ts +17 -0
- package/dist/providers/openai-responses-shared.d.ts.map +1 -0
- package/dist/providers/openai-responses-shared.js +427 -0
- package/dist/providers/openai-responses-shared.js.map +1 -0
- package/dist/providers/openai-responses.d.ts +13 -0
- package/dist/providers/openai-responses.d.ts.map +1 -0
- package/dist/providers/openai-responses.js +198 -0
- package/dist/providers/openai-responses.js.map +1 -0
- package/dist/providers/register-builtins.d.ts +3 -0
- package/dist/providers/register-builtins.d.ts.map +1 -0
- package/dist/providers/register-builtins.js +63 -0
- package/dist/providers/register-builtins.js.map +1 -0
- package/dist/providers/simple-options.d.ts +8 -0
- package/dist/providers/simple-options.d.ts.map +1 -0
- package/dist/providers/simple-options.js +35 -0
- package/dist/providers/simple-options.js.map +1 -0
- package/dist/providers/transform-messages.d.ts +8 -0
- package/dist/providers/transform-messages.d.ts.map +1 -0
- package/dist/providers/transform-messages.js +155 -0
- package/dist/providers/transform-messages.js.map +1 -0
- package/dist/stream.d.ts +9 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +28 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +279 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/event-stream.d.ts +21 -0
- package/dist/utils/event-stream.d.ts.map +1 -0
- package/dist/utils/event-stream.js +81 -0
- package/dist/utils/event-stream.js.map +1 -0
- package/dist/utils/http-proxy.d.ts +2 -0
- package/dist/utils/http-proxy.d.ts.map +1 -0
- package/dist/utils/http-proxy.js +15 -0
- package/dist/utils/http-proxy.js.map +1 -0
- package/dist/utils/json-parse.d.ts +9 -0
- package/dist/utils/json-parse.d.ts.map +1 -0
- package/dist/utils/json-parse.js +29 -0
- package/dist/utils/json-parse.js.map +1 -0
- package/dist/utils/oauth/anthropic.d.ts +17 -0
- package/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/dist/utils/oauth/anthropic.js +104 -0
- package/dist/utils/oauth/anthropic.js.map +1 -0
- package/dist/utils/oauth/github-copilot.d.ts +30 -0
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -0
- package/dist/utils/oauth/github-copilot.js +281 -0
- package/dist/utils/oauth/github-copilot.js.map +1 -0
- package/dist/utils/oauth/google-antigravity.d.ts +26 -0
- package/dist/utils/oauth/google-antigravity.d.ts.map +1 -0
- package/dist/utils/oauth/google-antigravity.js +373 -0
- package/dist/utils/oauth/google-antigravity.js.map +1 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts +26 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -0
- package/dist/utils/oauth/google-gemini-cli.js +478 -0
- package/dist/utils/oauth/google-gemini-cli.js.map +1 -0
- package/dist/utils/oauth/index.d.ts +62 -0
- package/dist/utils/oauth/index.d.ts.map +1 -0
- package/dist/utils/oauth/index.js +133 -0
- package/dist/utils/oauth/index.js.map +1 -0
- package/dist/utils/oauth/openai-codex.d.ts +34 -0
- package/dist/utils/oauth/openai-codex.d.ts.map +1 -0
- package/dist/utils/oauth/openai-codex.js +380 -0
- package/dist/utils/oauth/openai-codex.js.map +1 -0
- package/dist/utils/oauth/pkce.d.ts +13 -0
- package/dist/utils/oauth/pkce.d.ts.map +1 -0
- package/dist/utils/oauth/pkce.js +31 -0
- package/dist/utils/oauth/pkce.js.map +1 -0
- package/dist/utils/oauth/types.d.ts +47 -0
- package/dist/utils/oauth/types.d.ts.map +1 -0
- package/dist/utils/oauth/types.js +2 -0
- package/dist/utils/oauth/types.js.map +1 -0
- package/dist/utils/overflow.d.ts +52 -0
- package/dist/utils/overflow.d.ts.map +1 -0
- package/dist/utils/overflow.js +115 -0
- package/dist/utils/overflow.js.map +1 -0
- package/dist/utils/sanitize-unicode.d.ts +22 -0
- package/dist/utils/sanitize-unicode.d.ts.map +1 -0
- package/dist/utils/sanitize-unicode.js +26 -0
- package/dist/utils/sanitize-unicode.js.map +1 -0
- package/dist/utils/typebox-helpers.d.ts +17 -0
- package/dist/utils/typebox-helpers.d.ts.map +1 -0
- package/dist/utils/typebox-helpers.js +21 -0
- package/dist/utils/typebox-helpers.js.map +1 -0
- package/dist/utils/validation.d.ts +18 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +72 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize tool call ID for cross-provider compatibility.
|
|
3
|
+
* OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.
|
|
4
|
+
* Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).
|
|
5
|
+
*/
|
|
6
|
+
export function transformMessages(messages, model, normalizeToolCallId) {
|
|
7
|
+
// Build a map of original tool call IDs to normalized IDs
|
|
8
|
+
const toolCallIdMap = new Map();
|
|
9
|
+
// First pass: transform messages (thinking blocks, tool call ID normalization)
|
|
10
|
+
const transformed = messages.map((msg) => {
|
|
11
|
+
// User messages pass through unchanged
|
|
12
|
+
if (msg.role === "user") {
|
|
13
|
+
return msg;
|
|
14
|
+
}
|
|
15
|
+
// Handle toolResult messages - normalize toolCallId if we have a mapping
|
|
16
|
+
if (msg.role === "toolResult") {
|
|
17
|
+
const normalizedId = toolCallIdMap.get(msg.toolCallId);
|
|
18
|
+
if (normalizedId && normalizedId !== msg.toolCallId) {
|
|
19
|
+
return { ...msg, toolCallId: normalizedId };
|
|
20
|
+
}
|
|
21
|
+
return msg;
|
|
22
|
+
}
|
|
23
|
+
// Assistant messages need transformation check
|
|
24
|
+
if (msg.role === "assistant") {
|
|
25
|
+
const assistantMsg = msg;
|
|
26
|
+
const isSameModel = assistantMsg.provider === model.provider &&
|
|
27
|
+
assistantMsg.api === model.api &&
|
|
28
|
+
assistantMsg.model === model.id;
|
|
29
|
+
const transformedContent = assistantMsg.content.flatMap((block) => {
|
|
30
|
+
if (block.type === "thinking") {
|
|
31
|
+
// Redacted thinking is opaque encrypted content, only valid for the same model.
|
|
32
|
+
// Drop it for cross-model to avoid API errors.
|
|
33
|
+
if (block.redacted) {
|
|
34
|
+
return isSameModel ? block : [];
|
|
35
|
+
}
|
|
36
|
+
// For same model: keep thinking blocks with signatures (needed for replay)
|
|
37
|
+
// even if the thinking text is empty (OpenAI encrypted reasoning)
|
|
38
|
+
if (isSameModel && block.thinkingSignature)
|
|
39
|
+
return block;
|
|
40
|
+
// Skip empty thinking blocks, convert others to plain text
|
|
41
|
+
if (!block.thinking || block.thinking.trim() === "")
|
|
42
|
+
return [];
|
|
43
|
+
if (isSameModel)
|
|
44
|
+
return block;
|
|
45
|
+
return {
|
|
46
|
+
type: "text",
|
|
47
|
+
text: block.thinking,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (block.type === "text") {
|
|
51
|
+
if (isSameModel)
|
|
52
|
+
return block;
|
|
53
|
+
return {
|
|
54
|
+
type: "text",
|
|
55
|
+
text: block.text,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (block.type === "toolCall") {
|
|
59
|
+
const toolCall = block;
|
|
60
|
+
let normalizedToolCall = toolCall;
|
|
61
|
+
if (!isSameModel && toolCall.thoughtSignature) {
|
|
62
|
+
normalizedToolCall = { ...toolCall };
|
|
63
|
+
delete normalizedToolCall.thoughtSignature;
|
|
64
|
+
}
|
|
65
|
+
if (!isSameModel && normalizeToolCallId) {
|
|
66
|
+
const normalizedId = normalizeToolCallId(toolCall.id, model, assistantMsg);
|
|
67
|
+
if (normalizedId !== toolCall.id) {
|
|
68
|
+
toolCallIdMap.set(toolCall.id, normalizedId);
|
|
69
|
+
normalizedToolCall = { ...normalizedToolCall, id: normalizedId };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return normalizedToolCall;
|
|
73
|
+
}
|
|
74
|
+
return block;
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
...assistantMsg,
|
|
78
|
+
content: transformedContent,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return msg;
|
|
82
|
+
});
|
|
83
|
+
// Second pass: insert synthetic empty tool results for orphaned tool calls
|
|
84
|
+
// This preserves thinking signatures and satisfies API requirements
|
|
85
|
+
const result = [];
|
|
86
|
+
let pendingToolCalls = [];
|
|
87
|
+
let existingToolResultIds = new Set();
|
|
88
|
+
for (let i = 0; i < transformed.length; i++) {
|
|
89
|
+
const msg = transformed[i];
|
|
90
|
+
if (msg.role === "assistant") {
|
|
91
|
+
// If we have pending orphaned tool calls from a previous assistant, insert synthetic results now
|
|
92
|
+
if (pendingToolCalls.length > 0) {
|
|
93
|
+
for (const tc of pendingToolCalls) {
|
|
94
|
+
if (!existingToolResultIds.has(tc.id)) {
|
|
95
|
+
result.push({
|
|
96
|
+
role: "toolResult",
|
|
97
|
+
toolCallId: tc.id,
|
|
98
|
+
toolName: tc.name,
|
|
99
|
+
content: [{ type: "text", text: "No result provided" }],
|
|
100
|
+
isError: true,
|
|
101
|
+
timestamp: Date.now(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
pendingToolCalls = [];
|
|
106
|
+
existingToolResultIds = new Set();
|
|
107
|
+
}
|
|
108
|
+
// Skip errored/aborted assistant messages entirely.
|
|
109
|
+
// These are incomplete turns that shouldn't be replayed:
|
|
110
|
+
// - May have partial content (reasoning without message, incomplete tool calls)
|
|
111
|
+
// - Replaying them can cause API errors (e.g., OpenAI "reasoning without following item")
|
|
112
|
+
// - The model should retry from the last valid state
|
|
113
|
+
const assistantMsg = msg;
|
|
114
|
+
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Track tool calls from this assistant message
|
|
118
|
+
const toolCalls = assistantMsg.content.filter((b) => b.type === "toolCall");
|
|
119
|
+
if (toolCalls.length > 0) {
|
|
120
|
+
pendingToolCalls = toolCalls;
|
|
121
|
+
existingToolResultIds = new Set();
|
|
122
|
+
}
|
|
123
|
+
result.push(msg);
|
|
124
|
+
}
|
|
125
|
+
else if (msg.role === "toolResult") {
|
|
126
|
+
existingToolResultIds.add(msg.toolCallId);
|
|
127
|
+
result.push(msg);
|
|
128
|
+
}
|
|
129
|
+
else if (msg.role === "user") {
|
|
130
|
+
// User message interrupts tool flow - insert synthetic results for orphaned calls
|
|
131
|
+
if (pendingToolCalls.length > 0) {
|
|
132
|
+
for (const tc of pendingToolCalls) {
|
|
133
|
+
if (!existingToolResultIds.has(tc.id)) {
|
|
134
|
+
result.push({
|
|
135
|
+
role: "toolResult",
|
|
136
|
+
toolCallId: tc.id,
|
|
137
|
+
toolName: tc.name,
|
|
138
|
+
content: [{ type: "text", text: "No result provided" }],
|
|
139
|
+
isError: true,
|
|
140
|
+
timestamp: Date.now(),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
pendingToolCalls = [];
|
|
145
|
+
existingToolResultIds = new Set();
|
|
146
|
+
}
|
|
147
|
+
result.push(msg);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
result.push(msg);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=transform-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-messages.js","sourceRoot":"","sources":["../../src/providers/transform-messages.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, AssistantMessage, Message, Model, ToolCall, ToolResultMessage } from \"../types.js\";\n\n/**\n * Normalize tool call ID for cross-provider compatibility.\n * OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.\n * Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).\n */\nexport function transformMessages<TApi extends Api>(\n\tmessages: Message[],\n\tmodel: Model<TApi>,\n\tnormalizeToolCallId?: (id: string, model: Model<TApi>, source: AssistantMessage) => string,\n): Message[] {\n\t// Build a map of original tool call IDs to normalized IDs\n\tconst toolCallIdMap = new Map<string, string>();\n\n\t// First pass: transform messages (thinking blocks, tool call ID normalization)\n\tconst transformed = messages.map((msg) => {\n\t\t// User messages pass through unchanged\n\t\tif (msg.role === \"user\") {\n\t\t\treturn msg;\n\t\t}\n\n\t\t// Handle toolResult messages - normalize toolCallId if we have a mapping\n\t\tif (msg.role === \"toolResult\") {\n\t\t\tconst normalizedId = toolCallIdMap.get(msg.toolCallId);\n\t\t\tif (normalizedId && normalizedId !== msg.toolCallId) {\n\t\t\t\treturn { ...msg, toolCallId: normalizedId };\n\t\t\t}\n\t\t\treturn msg;\n\t\t}\n\n\t\t// Assistant messages need transformation check\n\t\tif (msg.role === \"assistant\") {\n\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\tconst isSameModel =\n\t\t\t\tassistantMsg.provider === model.provider &&\n\t\t\t\tassistantMsg.api === model.api &&\n\t\t\t\tassistantMsg.model === model.id;\n\n\t\t\tconst transformedContent = assistantMsg.content.flatMap((block) => {\n\t\t\t\tif (block.type === \"thinking\") {\n\t\t\t\t\t// Redacted thinking is opaque encrypted content, only valid for the same model.\n\t\t\t\t\t// Drop it for cross-model to avoid API errors.\n\t\t\t\t\tif (block.redacted) {\n\t\t\t\t\t\treturn isSameModel ? block : [];\n\t\t\t\t\t}\n\t\t\t\t\t// For same model: keep thinking blocks with signatures (needed for replay)\n\t\t\t\t\t// even if the thinking text is empty (OpenAI encrypted reasoning)\n\t\t\t\t\tif (isSameModel && block.thinkingSignature) return block;\n\t\t\t\t\t// Skip empty thinking blocks, convert others to plain text\n\t\t\t\t\tif (!block.thinking || block.thinking.trim() === \"\") return [];\n\t\t\t\t\tif (isSameModel) return block;\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: block.thinking,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\tif (isSameModel) return block;\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: block.text,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (block.type === \"toolCall\") {\n\t\t\t\t\tconst toolCall = block as ToolCall;\n\t\t\t\t\tlet normalizedToolCall: ToolCall = toolCall;\n\n\t\t\t\t\tif (!isSameModel && toolCall.thoughtSignature) {\n\t\t\t\t\t\tnormalizedToolCall = { ...toolCall };\n\t\t\t\t\t\tdelete (normalizedToolCall as { thoughtSignature?: string }).thoughtSignature;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!isSameModel && normalizeToolCallId) {\n\t\t\t\t\t\tconst normalizedId = normalizeToolCallId(toolCall.id, model, assistantMsg);\n\t\t\t\t\t\tif (normalizedId !== toolCall.id) {\n\t\t\t\t\t\t\ttoolCallIdMap.set(toolCall.id, normalizedId);\n\t\t\t\t\t\t\tnormalizedToolCall = { ...normalizedToolCall, id: normalizedId };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn normalizedToolCall;\n\t\t\t\t}\n\n\t\t\t\treturn block;\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\t...assistantMsg,\n\t\t\t\tcontent: transformedContent,\n\t\t\t};\n\t\t}\n\t\treturn msg;\n\t});\n\n\t// Second pass: insert synthetic empty tool results for orphaned tool calls\n\t// This preserves thinking signatures and satisfies API requirements\n\tconst result: Message[] = [];\n\tlet pendingToolCalls: ToolCall[] = [];\n\tlet existingToolResultIds = new Set<string>();\n\n\tfor (let i = 0; i < transformed.length; i++) {\n\t\tconst msg = transformed[i];\n\n\t\tif (msg.role === \"assistant\") {\n\t\t\t// If we have pending orphaned tool calls from a previous assistant, insert synthetic results now\n\t\t\tif (pendingToolCalls.length > 0) {\n\t\t\t\tfor (const tc of pendingToolCalls) {\n\t\t\t\t\tif (!existingToolResultIds.has(tc.id)) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\trole: \"toolResult\",\n\t\t\t\t\t\t\ttoolCallId: tc.id,\n\t\t\t\t\t\t\ttoolName: tc.name,\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No result provided\" }],\n\t\t\t\t\t\t\tisError: true,\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t} as ToolResultMessage);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpendingToolCalls = [];\n\t\t\t\texistingToolResultIds = new Set();\n\t\t\t}\n\n\t\t\t// Skip errored/aborted assistant messages entirely.\n\t\t\t// These are incomplete turns that shouldn't be replayed:\n\t\t\t// - May have partial content (reasoning without message, incomplete tool calls)\n\t\t\t// - Replaying them can cause API errors (e.g., OpenAI \"reasoning without following item\")\n\t\t\t// - The model should retry from the last valid state\n\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Track tool calls from this assistant message\n\t\t\tconst toolCalls = assistantMsg.content.filter((b) => b.type === \"toolCall\") as ToolCall[];\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tpendingToolCalls = toolCalls;\n\t\t\t\texistingToolResultIds = new Set();\n\t\t\t}\n\n\t\t\tresult.push(msg);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\texistingToolResultIds.add(msg.toolCallId);\n\t\t\tresult.push(msg);\n\t\t} else if (msg.role === \"user\") {\n\t\t\t// User message interrupts tool flow - insert synthetic results for orphaned calls\n\t\t\tif (pendingToolCalls.length > 0) {\n\t\t\t\tfor (const tc of pendingToolCalls) {\n\t\t\t\t\tif (!existingToolResultIds.has(tc.id)) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\trole: \"toolResult\",\n\t\t\t\t\t\t\ttoolCallId: tc.id,\n\t\t\t\t\t\t\ttoolName: tc.name,\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No result provided\" }],\n\t\t\t\t\t\t\tisError: true,\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t} as ToolResultMessage);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpendingToolCalls = [];\n\t\t\t\texistingToolResultIds = new Set();\n\t\t\t}\n\t\t\tresult.push(msg);\n\t\t} else {\n\t\t\tresult.push(msg);\n\t\t}\n\t}\n\n\treturn result;\n}\n"]}
|
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "./providers/register-builtins.js";
|
|
2
|
+
import "./utils/http-proxy.js";
|
|
3
|
+
import type { Api, AssistantMessage, AssistantMessageEventStream, Context, Model, ProviderStreamOptions, SimpleStreamOptions } from "./types.js";
|
|
4
|
+
export { getEnvApiKey } from "./env-api-keys.js";
|
|
5
|
+
export declare function stream<TApi extends Api>(model: Model<TApi>, context: Context, options?: ProviderStreamOptions): AssistantMessageEventStream;
|
|
6
|
+
export declare function complete<TApi extends Api>(model: Model<TApi>, context: Context, options?: ProviderStreamOptions): Promise<AssistantMessage>;
|
|
7
|
+
export declare function streamSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
|
8
|
+
export declare function completeSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): Promise<AssistantMessage>;
|
|
9
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAC1C,OAAO,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAChB,2BAA2B,EAC3B,OAAO,EACP,KAAK,EACL,qBAAqB,EACrB,mBAAmB,EAEnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,wBAAgB,MAAM,CAAC,IAAI,SAAS,GAAG,EACtC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,2BAA2B,CAG7B;AAED,wBAAsB,QAAQ,CAAC,IAAI,SAAS,GAAG,EAC9C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAS,GAAG,EAC5C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,2BAA2B,CAG7B;AAED,wBAAsB,cAAc,CAAC,IAAI,SAAS,GAAG,EACpD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAG3B","sourcesContent":["import \"./providers/register-builtins.js\";\nimport \"./utils/http-proxy.js\";\n\nimport { getApiProvider } from \"./api-registry.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tModel,\n\tProviderStreamOptions,\n\tSimpleStreamOptions,\n\tStreamOptions,\n} from \"./types.js\";\n\nexport { getEnvApiKey } from \"./env-api-keys.js\";\n\nfunction resolveApiProvider(api: Api) {\n\tconst provider = getApiProvider(api);\n\tif (!provider) {\n\t\tthrow new Error(`No API provider registered for api: ${api}`);\n\t}\n\treturn provider;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\treturn provider.stream(model, context, options as StreamOptions);\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\treturn provider.streamSimple(model, context, options);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n"]}
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "./providers/register-builtins.js";
|
|
2
|
+
import "./utils/http-proxy.js";
|
|
3
|
+
import { getApiProvider } from "./api-registry.js";
|
|
4
|
+
export { getEnvApiKey } from "./env-api-keys.js";
|
|
5
|
+
function resolveApiProvider(api) {
|
|
6
|
+
const provider = getApiProvider(api);
|
|
7
|
+
if (!provider) {
|
|
8
|
+
throw new Error(`No API provider registered for api: ${api}`);
|
|
9
|
+
}
|
|
10
|
+
return provider;
|
|
11
|
+
}
|
|
12
|
+
export function stream(model, context, options) {
|
|
13
|
+
const provider = resolveApiProvider(model.api);
|
|
14
|
+
return provider.stream(model, context, options);
|
|
15
|
+
}
|
|
16
|
+
export async function complete(model, context, options) {
|
|
17
|
+
const s = stream(model, context, options);
|
|
18
|
+
return s.result();
|
|
19
|
+
}
|
|
20
|
+
export function streamSimple(model, context, options) {
|
|
21
|
+
const provider = resolveApiProvider(model.api);
|
|
22
|
+
return provider.streamSimple(model, context, options);
|
|
23
|
+
}
|
|
24
|
+
export async function completeSimple(model, context, options) {
|
|
25
|
+
const s = streamSimple(model, context, options);
|
|
26
|
+
return s.result();
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAC1C,OAAO,uBAAuB,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAYnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,SAAS,kBAAkB,CAAC,GAAQ,EAAE;IACrC,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,MAAM,UAAU,MAAM,CACrB,KAAkB,EAClB,OAAgB,EAChB,OAA+B,EACD;IAC9B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAwB,CAAC,CAAC;AAAA,CACjE;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC7B,KAAkB,EAClB,OAAgB,EAChB,OAA+B,EACH;IAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;AAAA,CAClB;AAED,MAAM,UAAU,YAAY,CAC3B,KAAkB,EAClB,OAAgB,EAChB,OAA6B,EACC;IAC9B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAAA,CACtD;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,KAAkB,EAClB,OAAgB,EAChB,OAA6B,EACD;IAC5B,MAAM,CAAC,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;AAAA,CAClB","sourcesContent":["import \"./providers/register-builtins.js\";\nimport \"./utils/http-proxy.js\";\n\nimport { getApiProvider } from \"./api-registry.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tModel,\n\tProviderStreamOptions,\n\tSimpleStreamOptions,\n\tStreamOptions,\n} from \"./types.js\";\n\nexport { getEnvApiKey } from \"./env-api-keys.js\";\n\nfunction resolveApiProvider(api: Api) {\n\tconst provider = getApiProvider(api);\n\tif (!provider) {\n\t\tthrow new Error(`No API provider registered for api: ${api}`);\n\t}\n\treturn provider;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\treturn provider.stream(model, context, options as StreamOptions);\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\treturn provider.streamSimple(model, context, options);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
2
|
+
export type { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
3
|
+
export type KnownApi = "openai-completions" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" | "anthropic-messages" | "bedrock-converse-stream" | "google-generative-ai" | "google-gemini-cli" | "google-vertex";
|
|
4
|
+
export type Api = KnownApi | (string & {});
|
|
5
|
+
export type KnownProvider = "amazon-bedrock" | "anthropic" | "google" | "google-gemini-cli" | "google-antigravity" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "huggingface" | "opencode" | "kimi-coding";
|
|
6
|
+
export type Provider = KnownProvider | string;
|
|
7
|
+
export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
8
|
+
/** Token budgets for each thinking level (token-based providers only) */
|
|
9
|
+
export interface ThinkingBudgets {
|
|
10
|
+
minimal?: number;
|
|
11
|
+
low?: number;
|
|
12
|
+
medium?: number;
|
|
13
|
+
high?: number;
|
|
14
|
+
}
|
|
15
|
+
export type CacheRetention = "none" | "short" | "long";
|
|
16
|
+
export type Transport = "sse" | "websocket" | "auto";
|
|
17
|
+
export interface StreamOptions {
|
|
18
|
+
temperature?: number;
|
|
19
|
+
maxTokens?: number;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Preferred transport for providers that support multiple transports.
|
|
24
|
+
* Providers that do not support this option ignore it.
|
|
25
|
+
*/
|
|
26
|
+
transport?: Transport;
|
|
27
|
+
/**
|
|
28
|
+
* Prompt cache retention preference. Providers map this to their supported values.
|
|
29
|
+
* Default: "short".
|
|
30
|
+
*/
|
|
31
|
+
cacheRetention?: CacheRetention;
|
|
32
|
+
/**
|
|
33
|
+
* Optional session identifier for providers that support session-based caching.
|
|
34
|
+
* Providers can use this to enable prompt caching, request routing, or other
|
|
35
|
+
* session-aware features. Ignored by providers that don't support it.
|
|
36
|
+
*/
|
|
37
|
+
sessionId?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Optional callback for inspecting provider payloads before sending.
|
|
40
|
+
*/
|
|
41
|
+
onPayload?: (payload: unknown) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Optional custom HTTP headers to include in API requests.
|
|
44
|
+
* Merged with provider defaults; can override default headers.
|
|
45
|
+
* Not supported by all providers (e.g., AWS Bedrock uses SDK auth).
|
|
46
|
+
*/
|
|
47
|
+
headers?: Record<string, string>;
|
|
48
|
+
/**
|
|
49
|
+
* Maximum delay in milliseconds to wait for a retry when the server requests a long wait.
|
|
50
|
+
* If the server's requested delay exceeds this value, the request fails immediately
|
|
51
|
+
* with an error containing the requested delay, allowing higher-level retry logic
|
|
52
|
+
* to handle it with user visibility.
|
|
53
|
+
* Default: 60000 (60 seconds). Set to 0 to disable the cap.
|
|
54
|
+
*/
|
|
55
|
+
maxRetryDelayMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Optional metadata to include in API requests.
|
|
58
|
+
* Providers extract the fields they understand and ignore the rest.
|
|
59
|
+
* For example, Anthropic uses `user_id` for abuse tracking and rate limiting.
|
|
60
|
+
*/
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
export type ProviderStreamOptions = StreamOptions & Record<string, unknown>;
|
|
64
|
+
export interface SimpleStreamOptions extends StreamOptions {
|
|
65
|
+
reasoning?: ThinkingLevel;
|
|
66
|
+
/** Custom token budgets for thinking levels (token-based providers only) */
|
|
67
|
+
thinkingBudgets?: ThinkingBudgets;
|
|
68
|
+
}
|
|
69
|
+
export type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (model: Model<TApi>, context: Context, options?: TOptions) => AssistantMessageEventStream;
|
|
70
|
+
export interface TextContent {
|
|
71
|
+
type: "text";
|
|
72
|
+
text: string;
|
|
73
|
+
textSignature?: string;
|
|
74
|
+
}
|
|
75
|
+
export interface ThinkingContent {
|
|
76
|
+
type: "thinking";
|
|
77
|
+
thinking: string;
|
|
78
|
+
thinkingSignature?: string;
|
|
79
|
+
/** When true, the thinking content was redacted by safety filters. The opaque
|
|
80
|
+
* encrypted payload is stored in `thinkingSignature` so it can be passed back
|
|
81
|
+
* to the API for multi-turn continuity. */
|
|
82
|
+
redacted?: boolean;
|
|
83
|
+
}
|
|
84
|
+
export interface ImageContent {
|
|
85
|
+
type: "image";
|
|
86
|
+
data: string;
|
|
87
|
+
mimeType: string;
|
|
88
|
+
}
|
|
89
|
+
export interface ToolCall {
|
|
90
|
+
type: "toolCall";
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
arguments: Record<string, any>;
|
|
94
|
+
thoughtSignature?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface Usage {
|
|
97
|
+
input: number;
|
|
98
|
+
output: number;
|
|
99
|
+
cacheRead: number;
|
|
100
|
+
cacheWrite: number;
|
|
101
|
+
totalTokens: number;
|
|
102
|
+
cost: {
|
|
103
|
+
input: number;
|
|
104
|
+
output: number;
|
|
105
|
+
cacheRead: number;
|
|
106
|
+
cacheWrite: number;
|
|
107
|
+
total: number;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export type StopReason = "stop" | "length" | "toolUse" | "error" | "aborted";
|
|
111
|
+
export interface UserMessage {
|
|
112
|
+
role: "user";
|
|
113
|
+
content: string | (TextContent | ImageContent)[];
|
|
114
|
+
timestamp: number;
|
|
115
|
+
}
|
|
116
|
+
export interface AssistantMessage {
|
|
117
|
+
role: "assistant";
|
|
118
|
+
content: (TextContent | ThinkingContent | ToolCall)[];
|
|
119
|
+
api: Api;
|
|
120
|
+
provider: Provider;
|
|
121
|
+
model: string;
|
|
122
|
+
usage: Usage;
|
|
123
|
+
stopReason: StopReason;
|
|
124
|
+
errorMessage?: string;
|
|
125
|
+
timestamp: number;
|
|
126
|
+
}
|
|
127
|
+
export interface ToolResultMessage<TDetails = any> {
|
|
128
|
+
role: "toolResult";
|
|
129
|
+
toolCallId: string;
|
|
130
|
+
toolName: string;
|
|
131
|
+
content: (TextContent | ImageContent)[];
|
|
132
|
+
details?: TDetails;
|
|
133
|
+
isError: boolean;
|
|
134
|
+
timestamp: number;
|
|
135
|
+
}
|
|
136
|
+
export type Message = UserMessage | AssistantMessage | ToolResultMessage;
|
|
137
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
138
|
+
export interface Tool<TParameters extends TSchema = TSchema> {
|
|
139
|
+
name: string;
|
|
140
|
+
description: string;
|
|
141
|
+
parameters: TParameters;
|
|
142
|
+
}
|
|
143
|
+
export interface Context {
|
|
144
|
+
systemPrompt?: string;
|
|
145
|
+
messages: Message[];
|
|
146
|
+
tools?: Tool[];
|
|
147
|
+
}
|
|
148
|
+
export type AssistantMessageEvent = {
|
|
149
|
+
type: "start";
|
|
150
|
+
partial: AssistantMessage;
|
|
151
|
+
} | {
|
|
152
|
+
type: "text_start";
|
|
153
|
+
contentIndex: number;
|
|
154
|
+
partial: AssistantMessage;
|
|
155
|
+
} | {
|
|
156
|
+
type: "text_delta";
|
|
157
|
+
contentIndex: number;
|
|
158
|
+
delta: string;
|
|
159
|
+
partial: AssistantMessage;
|
|
160
|
+
} | {
|
|
161
|
+
type: "text_end";
|
|
162
|
+
contentIndex: number;
|
|
163
|
+
content: string;
|
|
164
|
+
partial: AssistantMessage;
|
|
165
|
+
} | {
|
|
166
|
+
type: "thinking_start";
|
|
167
|
+
contentIndex: number;
|
|
168
|
+
partial: AssistantMessage;
|
|
169
|
+
} | {
|
|
170
|
+
type: "thinking_delta";
|
|
171
|
+
contentIndex: number;
|
|
172
|
+
delta: string;
|
|
173
|
+
partial: AssistantMessage;
|
|
174
|
+
} | {
|
|
175
|
+
type: "thinking_end";
|
|
176
|
+
contentIndex: number;
|
|
177
|
+
content: string;
|
|
178
|
+
partial: AssistantMessage;
|
|
179
|
+
} | {
|
|
180
|
+
type: "toolcall_start";
|
|
181
|
+
contentIndex: number;
|
|
182
|
+
partial: AssistantMessage;
|
|
183
|
+
} | {
|
|
184
|
+
type: "toolcall_delta";
|
|
185
|
+
contentIndex: number;
|
|
186
|
+
delta: string;
|
|
187
|
+
partial: AssistantMessage;
|
|
188
|
+
} | {
|
|
189
|
+
type: "toolcall_end";
|
|
190
|
+
contentIndex: number;
|
|
191
|
+
toolCall: ToolCall;
|
|
192
|
+
partial: AssistantMessage;
|
|
193
|
+
} | {
|
|
194
|
+
type: "done";
|
|
195
|
+
reason: Extract<StopReason, "stop" | "length" | "toolUse">;
|
|
196
|
+
message: AssistantMessage;
|
|
197
|
+
} | {
|
|
198
|
+
type: "error";
|
|
199
|
+
reason: Extract<StopReason, "aborted" | "error">;
|
|
200
|
+
error: AssistantMessage;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Compatibility settings for OpenAI-compatible completions APIs.
|
|
204
|
+
* Use this to override URL-based auto-detection for custom providers.
|
|
205
|
+
*/
|
|
206
|
+
export interface OpenAICompletionsCompat {
|
|
207
|
+
/** Whether the provider supports the `store` field. Default: auto-detected from URL. */
|
|
208
|
+
supportsStore?: boolean;
|
|
209
|
+
/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */
|
|
210
|
+
supportsDeveloperRole?: boolean;
|
|
211
|
+
/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */
|
|
212
|
+
supportsReasoningEffort?: boolean;
|
|
213
|
+
/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */
|
|
214
|
+
supportsUsageInStreaming?: boolean;
|
|
215
|
+
/** Which field to use for max tokens. Default: auto-detected from URL. */
|
|
216
|
+
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
217
|
+
/** Whether tool results require the `name` field. Default: auto-detected from URL. */
|
|
218
|
+
requiresToolResultName?: boolean;
|
|
219
|
+
/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */
|
|
220
|
+
requiresAssistantAfterToolResult?: boolean;
|
|
221
|
+
/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */
|
|
222
|
+
requiresThinkingAsText?: boolean;
|
|
223
|
+
/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */
|
|
224
|
+
requiresMistralToolIds?: boolean;
|
|
225
|
+
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "zai" uses thinking: { type: "enabled" }, "qwen" uses enable_thinking: boolean. Default: "openai". */
|
|
226
|
+
thinkingFormat?: "openai" | "zai" | "qwen";
|
|
227
|
+
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
|
|
228
|
+
openRouterRouting?: OpenRouterRouting;
|
|
229
|
+
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
|
|
230
|
+
vercelGatewayRouting?: VercelGatewayRouting;
|
|
231
|
+
/** Whether the provider supports the `strict` field in tool definitions. Default: true. */
|
|
232
|
+
supportsStrictMode?: boolean;
|
|
233
|
+
}
|
|
234
|
+
/** Compatibility settings for OpenAI Responses APIs. */
|
|
235
|
+
export interface OpenAIResponsesCompat {
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* OpenRouter provider routing preferences.
|
|
239
|
+
* Controls which upstream providers OpenRouter routes requests to.
|
|
240
|
+
* @see https://openrouter.ai/docs/provider-routing
|
|
241
|
+
*/
|
|
242
|
+
export interface OpenRouterRouting {
|
|
243
|
+
/** List of provider slugs to exclusively use for this request (e.g., ["amazon-bedrock", "anthropic"]). */
|
|
244
|
+
only?: string[];
|
|
245
|
+
/** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */
|
|
246
|
+
order?: string[];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Vercel AI Gateway routing preferences.
|
|
250
|
+
* Controls which upstream providers the gateway routes requests to.
|
|
251
|
+
* @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options
|
|
252
|
+
*/
|
|
253
|
+
export interface VercelGatewayRouting {
|
|
254
|
+
/** List of provider slugs to exclusively use for this request (e.g., ["bedrock", "anthropic"]). */
|
|
255
|
+
only?: string[];
|
|
256
|
+
/** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */
|
|
257
|
+
order?: string[];
|
|
258
|
+
}
|
|
259
|
+
export interface Model<TApi extends Api> {
|
|
260
|
+
id: string;
|
|
261
|
+
name: string;
|
|
262
|
+
api: TApi;
|
|
263
|
+
provider: Provider;
|
|
264
|
+
baseUrl: string;
|
|
265
|
+
reasoning: boolean;
|
|
266
|
+
input: ("text" | "image")[];
|
|
267
|
+
cost: {
|
|
268
|
+
input: number;
|
|
269
|
+
output: number;
|
|
270
|
+
cacheRead: number;
|
|
271
|
+
cacheWrite: number;
|
|
272
|
+
};
|
|
273
|
+
contextWindow: number;
|
|
274
|
+
maxTokens: number;
|
|
275
|
+
headers?: Record<string, string>;
|
|
276
|
+
/** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */
|
|
277
|
+
compat?: TApi extends "openai-completions" ? OpenAICompletionsCompat : TApi extends "openai-responses" ? OpenAIResponsesCompat : never;
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type KnownApi =\n\t| \"openai-completions\"\n\t| \"openai-responses\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex-responses\"\n\t| \"anthropic-messages\"\n\t| \"bedrock-converse-stream\"\n\t| \"google-generative-ai\"\n\t| \"google-gemini-cli\"\n\t| \"google-vertex\";\n\nexport type Api = KnownApi | (string & {});\n\nexport type KnownProvider =\n\t| \"amazon-bedrock\"\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"google-gemini-cli\"\n\t| \"google-antigravity\"\n\t| \"google-vertex\"\n\t| \"openai\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"vercel-ai-gateway\"\n\t| \"zai\"\n\t| \"mistral\"\n\t| \"minimax\"\n\t| \"minimax-cn\"\n\t| \"huggingface\"\n\t| \"opencode\"\n\t| \"kimi-coding\";\nexport type Provider = KnownProvider | string;\n\nexport type ThinkingLevel = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n/** Token budgets for each thinking level (token-based providers only) */\nexport interface ThinkingBudgets {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\n// Base options all providers share\nexport type CacheRetention = \"none\" | \"short\" | \"long\";\n\nexport type Transport = \"sse\" | \"websocket\" | \"auto\";\n\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n\t/**\n\t * Preferred transport for providers that support multiple transports.\n\t * Providers that do not support this option ignore it.\n\t */\n\ttransport?: Transport;\n\t/**\n\t * Prompt cache retention preference. Providers map this to their supported values.\n\t * Default: \"short\".\n\t */\n\tcacheRetention?: CacheRetention;\n\t/**\n\t * Optional session identifier for providers that support session-based caching.\n\t * Providers can use this to enable prompt caching, request routing, or other\n\t * session-aware features. Ignored by providers that don't support it.\n\t */\n\tsessionId?: string;\n\t/**\n\t * Optional callback for inspecting provider payloads before sending.\n\t */\n\tonPayload?: (payload: unknown) => void;\n\t/**\n\t * Optional custom HTTP headers to include in API requests.\n\t * Merged with provider defaults; can override default headers.\n\t * Not supported by all providers (e.g., AWS Bedrock uses SDK auth).\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Maximum delay in milliseconds to wait for a retry when the server requests a long wait.\n\t * If the server's requested delay exceeds this value, the request fails immediately\n\t * with an error containing the requested delay, allowing higher-level retry logic\n\t * to handle it with user visibility.\n\t * Default: 60000 (60 seconds). Set to 0 to disable the cap.\n\t */\n\tmaxRetryDelayMs?: number;\n\t/**\n\t * Optional metadata to include in API requests.\n\t * Providers extract the fields they understand and ignore the rest.\n\t * For example, Anthropic uses `user_id` for abuse tracking and rate limiting.\n\t */\n\tmetadata?: Record<string, unknown>;\n}\n\nexport type ProviderStreamOptions = StreamOptions & Record<string, unknown>;\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ThinkingLevel;\n\t/** Custom token budgets for thinking levels (token-based providers only) */\n\tthinkingBudgets?: ThinkingBudgets;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: TOptions,\n) => AssistantMessageEventStream;\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, the message ID\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n\t/** When true, the thinking content was redacted by safety filters. The opaque\n\t * encrypted payload is stored in `thinkingSignature` so it can be passed back\n\t * to the API for multi-turn continuity. */\n\tredacted?: boolean;\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for OpenAI-compatible completions APIs.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompletionsCompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */\n\tsupportsUsageInStreaming?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */\n\trequiresMistralToolIds?: boolean;\n\t/** Format for reasoning/thinking parameter. \"openai\" uses reasoning_effort, \"zai\" uses thinking: { type: \"enabled\" }, \"qwen\" uses enable_thinking: boolean. Default: \"openai\". */\n\tthinkingFormat?: \"openai\" | \"zai\" | \"qwen\";\n\t/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */\n\topenRouterRouting?: OpenRouterRouting;\n\t/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */\n\tvercelGatewayRouting?: VercelGatewayRouting;\n\t/** Whether the provider supports the `strict` field in tool definitions. Default: true. */\n\tsupportsStrictMode?: boolean;\n}\n\n/** Compatibility settings for OpenAI Responses APIs. */\nexport interface OpenAIResponsesCompat {\n\t// Reserved for future use\n}\n\n/**\n * OpenRouter provider routing preferences.\n * Controls which upstream providers OpenRouter routes requests to.\n * @see https://openrouter.ai/docs/provider-routing\n */\nexport interface OpenRouterRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"amazon-bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n/**\n * Vercel AI Gateway routing preferences.\n * Controls which upstream providers the gateway routes requests to.\n * @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options\n */\nexport interface VercelGatewayRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\"\n\t\t? OpenAICompletionsCompat\n\t\t: TApi extends \"openai-responses\"\n\t\t\t? OpenAIResponsesCompat\n\t\t\t: never;\n}\n"]}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type KnownApi =\n\t| \"openai-completions\"\n\t| \"openai-responses\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex-responses\"\n\t| \"anthropic-messages\"\n\t| \"bedrock-converse-stream\"\n\t| \"google-generative-ai\"\n\t| \"google-gemini-cli\"\n\t| \"google-vertex\";\n\nexport type Api = KnownApi | (string & {});\n\nexport type KnownProvider =\n\t| \"amazon-bedrock\"\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"google-gemini-cli\"\n\t| \"google-antigravity\"\n\t| \"google-vertex\"\n\t| \"openai\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"vercel-ai-gateway\"\n\t| \"zai\"\n\t| \"mistral\"\n\t| \"minimax\"\n\t| \"minimax-cn\"\n\t| \"huggingface\"\n\t| \"opencode\"\n\t| \"kimi-coding\";\nexport type Provider = KnownProvider | string;\n\nexport type ThinkingLevel = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n/** Token budgets for each thinking level (token-based providers only) */\nexport interface ThinkingBudgets {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\n// Base options all providers share\nexport type CacheRetention = \"none\" | \"short\" | \"long\";\n\nexport type Transport = \"sse\" | \"websocket\" | \"auto\";\n\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n\t/**\n\t * Preferred transport for providers that support multiple transports.\n\t * Providers that do not support this option ignore it.\n\t */\n\ttransport?: Transport;\n\t/**\n\t * Prompt cache retention preference. Providers map this to their supported values.\n\t * Default: \"short\".\n\t */\n\tcacheRetention?: CacheRetention;\n\t/**\n\t * Optional session identifier for providers that support session-based caching.\n\t * Providers can use this to enable prompt caching, request routing, or other\n\t * session-aware features. Ignored by providers that don't support it.\n\t */\n\tsessionId?: string;\n\t/**\n\t * Optional callback for inspecting provider payloads before sending.\n\t */\n\tonPayload?: (payload: unknown) => void;\n\t/**\n\t * Optional custom HTTP headers to include in API requests.\n\t * Merged with provider defaults; can override default headers.\n\t * Not supported by all providers (e.g., AWS Bedrock uses SDK auth).\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Maximum delay in milliseconds to wait for a retry when the server requests a long wait.\n\t * If the server's requested delay exceeds this value, the request fails immediately\n\t * with an error containing the requested delay, allowing higher-level retry logic\n\t * to handle it with user visibility.\n\t * Default: 60000 (60 seconds). Set to 0 to disable the cap.\n\t */\n\tmaxRetryDelayMs?: number;\n\t/**\n\t * Optional metadata to include in API requests.\n\t * Providers extract the fields they understand and ignore the rest.\n\t * For example, Anthropic uses `user_id` for abuse tracking and rate limiting.\n\t */\n\tmetadata?: Record<string, unknown>;\n}\n\nexport type ProviderStreamOptions = StreamOptions & Record<string, unknown>;\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ThinkingLevel;\n\t/** Custom token budgets for thinking levels (token-based providers only) */\n\tthinkingBudgets?: ThinkingBudgets;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: TOptions,\n) => AssistantMessageEventStream;\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, the message ID\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n\t/** When true, the thinking content was redacted by safety filters. The opaque\n\t * encrypted payload is stored in `thinkingSignature` so it can be passed back\n\t * to the API for multi-turn continuity. */\n\tredacted?: boolean;\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for OpenAI-compatible completions APIs.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompletionsCompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */\n\tsupportsUsageInStreaming?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */\n\trequiresMistralToolIds?: boolean;\n\t/** Format for reasoning/thinking parameter. \"openai\" uses reasoning_effort, \"zai\" uses thinking: { type: \"enabled\" }, \"qwen\" uses enable_thinking: boolean. Default: \"openai\". */\n\tthinkingFormat?: \"openai\" | \"zai\" | \"qwen\";\n\t/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */\n\topenRouterRouting?: OpenRouterRouting;\n\t/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */\n\tvercelGatewayRouting?: VercelGatewayRouting;\n\t/** Whether the provider supports the `strict` field in tool definitions. Default: true. */\n\tsupportsStrictMode?: boolean;\n}\n\n/** Compatibility settings for OpenAI Responses APIs. */\nexport interface OpenAIResponsesCompat {\n\t// Reserved for future use\n}\n\n/**\n * OpenRouter provider routing preferences.\n * Controls which upstream providers OpenRouter routes requests to.\n * @see https://openrouter.ai/docs/provider-routing\n */\nexport interface OpenRouterRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"amazon-bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n/**\n * Vercel AI Gateway routing preferences.\n * Controls which upstream providers the gateway routes requests to.\n * @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options\n */\nexport interface VercelGatewayRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\"\n\t\t? OpenAICompletionsCompat\n\t\t: TApi extends \"openai-responses\"\n\t\t\t? OpenAIResponsesCompat\n\t\t\t: never;\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AssistantMessage, AssistantMessageEvent } from "../types.js";
|
|
2
|
+
export declare class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
3
|
+
private isComplete;
|
|
4
|
+
private extractResult;
|
|
5
|
+
private queue;
|
|
6
|
+
private waiting;
|
|
7
|
+
private done;
|
|
8
|
+
private finalResultPromise;
|
|
9
|
+
private resolveFinalResult;
|
|
10
|
+
constructor(isComplete: (event: T) => boolean, extractResult: (event: T) => R);
|
|
11
|
+
push(event: T): void;
|
|
12
|
+
end(result?: R): void;
|
|
13
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
14
|
+
result(): Promise<R>;
|
|
15
|
+
}
|
|
16
|
+
export declare class AssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
|
|
17
|
+
constructor();
|
|
18
|
+
}
|
|
19
|
+
/** Factory function for AssistantMessageEventStream (for use in extensions) */
|
|
20
|
+
export declare function createAssistantMessageEventStream(): AssistantMessageEventStream;
|
|
21
|
+
//# sourceMappingURL=event-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-stream.d.ts","sourceRoot":"","sources":["../../src/utils/event-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAG3E,qBAAa,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAQ5D,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,aAAa;IARtB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,kBAAkB,CAAuB;IAEjD,YACS,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,EACjC,aAAa,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAKtC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAenB;IAED,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAUpB;IAEM,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAYhD;IAED,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,CAEnB;CACD;AAED,qBAAa,2BAA4B,SAAQ,WAAW,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;IACpG,cAYC;CACD;AAED,+EAA+E;AAC/E,wBAAgB,iCAAiC,IAAI,2BAA2B,CAE/E","sourcesContent":["import type { AssistantMessage, AssistantMessageEvent } from \"../types.js\";\n\n// Generic event stream class for async iteration\nexport class EventStream<T, R = T> implements AsyncIterable<T> {\n\tprivate queue: T[] = [];\n\tprivate waiting: ((value: IteratorResult<T>) => void)[] = [];\n\tprivate done = false;\n\tprivate finalResultPromise: Promise<R>;\n\tprivate resolveFinalResult!: (result: R) => void;\n\n\tconstructor(\n\t\tprivate isComplete: (event: T) => boolean,\n\t\tprivate extractResult: (event: T) => R,\n\t) {\n\t\tthis.finalResultPromise = new Promise((resolve) => {\n\t\t\tthis.resolveFinalResult = resolve;\n\t\t});\n\t}\n\n\tpush(event: T): void {\n\t\tif (this.done) return;\n\n\t\tif (this.isComplete(event)) {\n\t\t\tthis.done = true;\n\t\t\tthis.resolveFinalResult(this.extractResult(event));\n\t\t}\n\n\t\t// Deliver to waiting consumer or queue it\n\t\tconst waiter = this.waiting.shift();\n\t\tif (waiter) {\n\t\t\twaiter({ value: event, done: false });\n\t\t} else {\n\t\t\tthis.queue.push(event);\n\t\t}\n\t}\n\n\tend(result?: R): void {\n\t\tthis.done = true;\n\t\tif (result !== undefined) {\n\t\t\tthis.resolveFinalResult(result);\n\t\t}\n\t\t// Notify all waiting consumers that we're done\n\t\twhile (this.waiting.length > 0) {\n\t\t\tconst waiter = this.waiting.shift()!;\n\t\t\twaiter({ value: undefined as any, done: true });\n\t\t}\n\t}\n\n\tasync *[Symbol.asyncIterator](): AsyncIterator<T> {\n\t\twhile (true) {\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tyield this.queue.shift()!;\n\t\t\t} else if (this.done) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tconst result = await new Promise<IteratorResult<T>>((resolve) => this.waiting.push(resolve));\n\t\t\t\tif (result.done) return;\n\t\t\t\tyield result.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tresult(): Promise<R> {\n\t\treturn this.finalResultPromise;\n\t}\n}\n\nexport class AssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") {\n\t\t\t\t\treturn event.message;\n\t\t\t\t} else if (event.type === \"error\") {\n\t\t\t\t\treturn event.error;\n\t\t\t\t}\n\t\t\t\tthrow new Error(\"Unexpected event type for final result\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/** Factory function for AssistantMessageEventStream (for use in extensions) */\nexport function createAssistantMessageEventStream(): AssistantMessageEventStream {\n\treturn new AssistantMessageEventStream();\n}\n"]}
|