@codeworksh/aikit 0.7.2 → 0.8.0-dev.20260905193244
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/cli.mjs +5 -5
- package/cli.mjs.map +1 -1
- package/{codex-DyQHzQmn.mjs → codex-MtP1574D.mjs} +63 -50
- package/codex-MtP1574D.mjs.map +1 -0
- package/{failure-C0lCOdFE.d.mts → failure-5Wjd-qFH.d.mts} +6 -2
- package/{failure-xra3YPdY.mjs → failure-SAPyG-w2.mjs} +8 -77
- package/failure-SAPyG-w2.mjs.map +1 -0
- package/index.d.mts +120 -3898
- package/index.mjs +490 -559
- package/index.mjs.map +1 -1
- package/llm/failure.d.mts +1 -1
- package/llm/failure.mjs +2 -1
- package/model-CBnredXj.mjs +453 -0
- package/model-CBnredXj.mjs.map +1 -0
- package/{model-CKKq3s4y.d.mts → model-CpX11Oob.d.mts} +126 -46
- package/{modelgen-xolcfdfT.mjs → modelgen-BjSsusLQ.mjs} +78 -5
- package/modelgen-BjSsusLQ.mjs.map +1 -0
- package/modelgen.d.mts +1 -1
- package/modelgen.mjs +1 -1
- package/oauth/openai/codex.mjs +1 -1
- package/openai-codex-BRH4Qa7l.mjs +2 -0
- package/{openai-codex-_3XkJ4bs.mjs → openai-codex-t4B7g-gv.mjs} +542 -105
- package/openai-codex-t4B7g-gv.mjs.map +1 -0
- package/package.json +2 -2
- package/registry-DYdYTwFt.mjs +65 -0
- package/registry-DYdYTwFt.mjs.map +1 -0
- package/schema-rXSoWhic.mjs +80 -0
- package/schema-rXSoWhic.mjs.map +1 -0
- package/codex-DyQHzQmn.mjs.map +0 -1
- package/failure-xra3YPdY.mjs.map +0 -1
- package/modelgen-xolcfdfT.mjs.map +0 -1
- package/openai-codex-FcyE8vxh.mjs +0 -2
- package/openai-codex-_3XkJ4bs.mjs.map +0 -1
- package/registry-DHskX4NP.mjs +0 -5266
- package/registry-DHskX4NP.mjs.map +0 -1
package/index.mjs
CHANGED
|
@@ -1,349 +1,15 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { c as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { S as NamedError, _ as registry, a as KnownProviderEnumSchema, c as calculateCost, d as getModels, f as getProviders, g as optionsKey, i as KnownProviderEnum, l as clampThinkingLevel, m as modelsAreEqual, n as APIMethodEnumSchema, p as model_exports, r as ActiveThinkingLevel, s as ThinkingBudgets$1, u as getModel, v as thinkingTokenBudgetField } from "./model-CBnredXj.mjs";
|
|
3
|
+
import { C as ToolCallSchema, D as transformMessages, E as resolveJsonSchemaConstraint, S as AssistantMessageSchema, T as message_exports, g as shortHash, n as createOpenAICodex, r as openaiCodex, v as openAICodexTools, w as createAssistantMessage$1, x as resolveOpenAICodexToolConstraint } from "./openai-codex-t4B7g-gv.mjs";
|
|
4
|
+
import { r as normalize, t as failure_exports } from "./failure-SAPyG-w2.mjs";
|
|
5
|
+
import { i as packageForModel, o as resolveLanguageModel, r as loadProviderFactory } from "./registry-DYdYTwFt.mjs";
|
|
5
6
|
import Type$2, { Type, Type as Type$1 } from "typebox";
|
|
6
|
-
import { uuidv7 } from "uuidv7";
|
|
7
|
-
import Value from "typebox/value";
|
|
8
7
|
import { jsonSchema, streamText } from "ai";
|
|
9
8
|
import { parse } from "partial-json";
|
|
10
9
|
import Schema from "typebox/schema";
|
|
11
|
-
|
|
12
|
-
var message_exports = /* @__PURE__ */ __exportAll({
|
|
13
|
-
AssistantMessageSchema: () => AssistantMessageSchema,
|
|
14
|
-
ConstrainedSamplingSchema: () => ConstrainedSamplingSchema,
|
|
15
|
-
ContextSchema: () => ContextSchema,
|
|
16
|
-
GrammarVariantsSchema: () => GrammarVariantsSchema,
|
|
17
|
-
ImageContentSchema: () => ImageContentSchema,
|
|
18
|
-
MessageSchema: () => MessageSchema,
|
|
19
|
-
StopReasonSchema: () => StopReasonSchema,
|
|
20
|
-
TextContentSchema: () => TextContentSchema,
|
|
21
|
-
ThinkingContentSchema: () => ThinkingContentSchema,
|
|
22
|
-
ToolAbortedSchema: () => ToolAbortedSchema,
|
|
23
|
-
ToolCallAbortedPartSchema: () => ToolCallAbortedPartSchema,
|
|
24
|
-
ToolCallBaseSchema: () => ToolCallBaseSchema,
|
|
25
|
-
ToolCallCompletedPartSchema: () => ToolCallCompletedPartSchema,
|
|
26
|
-
ToolCallErrorPartSchema: () => ToolCallErrorPartSchema,
|
|
27
|
-
ToolCallInFlightSchema: () => ToolCallInFlightSchema,
|
|
28
|
-
ToolCallPendingPartSchema: () => ToolCallPendingPartSchema,
|
|
29
|
-
ToolCallRunningPartSchema: () => ToolCallRunningPartSchema,
|
|
30
|
-
ToolCallSchema: () => ToolCallSchema,
|
|
31
|
-
ToolCallSkippedPartSchema: () => ToolCallSkippedPartSchema,
|
|
32
|
-
ToolCallTerminalPartSchema: () => ToolCallTerminalPartSchema,
|
|
33
|
-
ToolCompletedSchema: () => ToolCompletedSchema,
|
|
34
|
-
ToolErrorResult: () => ToolErrorResult,
|
|
35
|
-
ToolErrorSchema: () => ToolErrorSchema,
|
|
36
|
-
ToolRunningPartial: () => ToolRunningPartial,
|
|
37
|
-
ToolRunningSchema: () => ToolRunningSchema,
|
|
38
|
-
ToolSchema: () => ToolSchema,
|
|
39
|
-
ToolSkippedSchema: () => ToolSkippedSchema,
|
|
40
|
-
ToolStatusEnum: () => ToolStatusEnum,
|
|
41
|
-
ToolSuccessResult: () => ToolSuccessResult,
|
|
42
|
-
UsageSchema: () => UsageSchema,
|
|
43
|
-
UserMessageSchema: () => UserMessageSchema,
|
|
44
|
-
createAssistantMessage: () => createAssistantMessage$1,
|
|
45
|
-
createMessageId: () => createMessageId,
|
|
46
|
-
createUserMessage: () => createUserMessage,
|
|
47
|
-
defineTool: () => defineTool,
|
|
48
|
-
transformMessages: () => transformMessages
|
|
49
|
-
});
|
|
50
|
-
const TextContentSchema = Type$2.Object({
|
|
51
|
-
type: Type$2.Literal("text"),
|
|
52
|
-
text: Type$2.String(),
|
|
53
|
-
textSignature: Type$2.Optional(Type$2.String())
|
|
54
|
-
});
|
|
55
|
-
const ImageContentSchema = Type$2.Object({
|
|
56
|
-
type: Type$2.Literal("image"),
|
|
57
|
-
data: Type$2.String(),
|
|
58
|
-
mimeType: Type$2.String()
|
|
59
|
-
});
|
|
60
|
-
const ThinkingContentSchema = Type$2.Object({
|
|
61
|
-
type: Type$2.Literal("thinking"),
|
|
62
|
-
thinking: Type$2.String(),
|
|
63
|
-
thinkingSignature: Type$2.Optional(Type$2.String()),
|
|
64
|
-
/** When true, the thinking content was redacted by safety filters. The opaque
|
|
65
|
-
* encrypted payload is stored in `thinkingSignature` so it can be passed back
|
|
66
|
-
* to the API for multi-turn continuity. */
|
|
67
|
-
redacted: Type$2.Optional(Type$2.Boolean())
|
|
68
|
-
});
|
|
69
|
-
const ToolCallBaseSchema = Type$2.Object({
|
|
70
|
-
type: Type$2.Literal("toolCall"),
|
|
71
|
-
callID: Type$2.String(),
|
|
72
|
-
name: Type$2.String(),
|
|
73
|
-
arguments: Type$2.Record(Type$2.String(), Type$2.Any()),
|
|
74
|
-
thoughtSignature: Type$2.Optional(Type$2.String()),
|
|
75
|
-
namespace: Type$2.Optional(Type$2.String()),
|
|
76
|
-
/** Names from Context.tools that became available after this tool result. */
|
|
77
|
-
addedToolNames: Type$2.Optional(Type$2.Array(Type$2.String())),
|
|
78
|
-
time: Type$2.Object({
|
|
79
|
-
start: Type$2.Number(),
|
|
80
|
-
end: Type$2.Number()
|
|
81
|
-
})
|
|
82
|
-
});
|
|
83
|
-
const ToolSuccessResult = Type$2.Object({
|
|
84
|
-
content: Type$2.Array(Type$2.Union([TextContentSchema, ImageContentSchema])),
|
|
85
|
-
details: Type$2.Optional(Type$2.Any()),
|
|
86
|
-
isError: Type$2.Literal(false)
|
|
87
|
-
});
|
|
88
|
-
const ToolErrorResult = Type$2.Object({
|
|
89
|
-
content: Type$2.Array(Type$2.Union([TextContentSchema, ImageContentSchema])),
|
|
90
|
-
details: Type$2.Optional(Type$2.Any()),
|
|
91
|
-
isError: Type$2.Literal(true)
|
|
92
|
-
});
|
|
93
|
-
const ToolRunningPartial = Type$2.Object({
|
|
94
|
-
content: Type$2.Optional(Type$2.Array(Type$2.Union([TextContentSchema, ImageContentSchema]))),
|
|
95
|
-
details: Type$2.Optional(Type$2.Any())
|
|
96
|
-
});
|
|
97
|
-
const ToolStatusEnum = {
|
|
98
|
-
pending: "pending",
|
|
99
|
-
running: "running",
|
|
100
|
-
completed: "completed",
|
|
101
|
-
error: "error",
|
|
102
|
-
skipped: "skipped",
|
|
103
|
-
aborted: "aborted"
|
|
104
|
-
};
|
|
105
|
-
const ToolRunningSchema = Type$2.Object({
|
|
106
|
-
status: Type$2.Literal(ToolStatusEnum.running),
|
|
107
|
-
partial: Type$2.Optional(ToolRunningPartial)
|
|
108
|
-
});
|
|
109
|
-
const ToolCompletedSchema = Type$2.Object({
|
|
110
|
-
status: Type$2.Literal(ToolStatusEnum.completed),
|
|
111
|
-
result: ToolSuccessResult
|
|
112
|
-
});
|
|
113
|
-
const ToolErrorSchema = Type$2.Object({
|
|
114
|
-
status: Type$2.Literal(ToolStatusEnum.error),
|
|
115
|
-
result: ToolErrorResult
|
|
116
|
-
});
|
|
117
|
-
const ToolSkippedSchema = Type$2.Object({
|
|
118
|
-
status: Type$2.Literal(ToolStatusEnum.skipped),
|
|
119
|
-
result: ToolErrorResult
|
|
120
|
-
});
|
|
121
|
-
const ToolAbortedSchema = Type$2.Object({
|
|
122
|
-
status: Type$2.Literal(ToolStatusEnum.aborted),
|
|
123
|
-
result: ToolErrorResult
|
|
124
|
-
});
|
|
125
|
-
const ToolCallPendingPartSchema = Type$2.Intersect([ToolCallBaseSchema, Type$2.Object({ status: Type$2.Literal(ToolStatusEnum.pending) })]);
|
|
126
|
-
const ToolCallRunningPartSchema = Type$2.Evaluate(Type$2.Intersect([ToolCallBaseSchema, ToolRunningSchema]));
|
|
127
|
-
const ToolCallCompletedPartSchema = Type$2.Evaluate(Type$2.Intersect([ToolCallBaseSchema, ToolCompletedSchema]));
|
|
128
|
-
const ToolCallErrorPartSchema = Type$2.Evaluate(Type$2.Intersect([ToolCallBaseSchema, ToolErrorSchema]));
|
|
129
|
-
const ToolCallSkippedPartSchema = Type$2.Evaluate(Type$2.Intersect([ToolCallBaseSchema, ToolSkippedSchema]));
|
|
130
|
-
const ToolCallAbortedPartSchema = Type$2.Evaluate(Type$2.Intersect([ToolCallBaseSchema, ToolAbortedSchema]));
|
|
131
|
-
const ToolCallTerminalPartSchema = Type$2.Union([
|
|
132
|
-
ToolCallCompletedPartSchema,
|
|
133
|
-
ToolCallErrorPartSchema,
|
|
134
|
-
ToolCallSkippedPartSchema,
|
|
135
|
-
ToolCallAbortedPartSchema
|
|
136
|
-
]);
|
|
137
|
-
const ToolCallInFlightSchema = Type$2.Object({
|
|
138
|
-
callID: Type$2.String(),
|
|
139
|
-
name: Type$2.String(),
|
|
140
|
-
rawArgs: Type$2.Record(Type$2.String(), Type$2.Unknown()),
|
|
141
|
-
args: Type$2.Optional(Type$2.Unknown())
|
|
142
|
-
});
|
|
143
|
-
const ToolCallSchema = Type$2.Union([
|
|
144
|
-
ToolCallPendingPartSchema,
|
|
145
|
-
ToolCallRunningPartSchema,
|
|
146
|
-
ToolCallTerminalPartSchema
|
|
147
|
-
]);
|
|
148
|
-
const UsageSchema = Type$2.Object({
|
|
149
|
-
input: Type$2.Number(),
|
|
150
|
-
output: Type$2.Number(),
|
|
151
|
-
cacheRead: Type$2.Number(),
|
|
152
|
-
cacheWrite: Type$2.Number(),
|
|
153
|
-
reasoning: Type$2.Optional(Type$2.Number()),
|
|
154
|
-
totalTokens: Type$2.Number(),
|
|
155
|
-
cost: Type$2.Object({
|
|
156
|
-
input: Type$2.Number(),
|
|
157
|
-
output: Type$2.Number(),
|
|
158
|
-
cacheRead: Type$2.Number(),
|
|
159
|
-
cacheWrite: Type$2.Number(),
|
|
160
|
-
total: Type$2.Number()
|
|
161
|
-
})
|
|
162
|
-
});
|
|
163
|
-
const StopReasonSchema = Type$2.Union([
|
|
164
|
-
Type$2.Literal("stop"),
|
|
165
|
-
Type$2.Literal("length"),
|
|
166
|
-
Type$2.Literal("toolUse"),
|
|
167
|
-
Type$2.Literal("error"),
|
|
168
|
-
Type$2.Literal("aborted")
|
|
169
|
-
]);
|
|
170
|
-
const UserMessageSchema = Type$2.Object({
|
|
171
|
-
messageId: Type$2.String(),
|
|
172
|
-
role: Type$2.Literal("user"),
|
|
173
|
-
time: Type$2.Object({ created: Type$2.Number() }),
|
|
174
|
-
parts: Type$2.Array(Type$2.Union([TextContentSchema, ImageContentSchema]))
|
|
175
|
-
});
|
|
176
|
-
const AssistantMessageSchema = Type$2.Object({
|
|
177
|
-
role: Type$2.Literal("assistant"),
|
|
178
|
-
protocol: KnownProviderEnumSchema,
|
|
179
|
-
provider: ProviderInfo,
|
|
180
|
-
model: Type$2.String(),
|
|
181
|
-
usage: UsageSchema,
|
|
182
|
-
stopReason: StopReasonSchema,
|
|
183
|
-
errorMessage: Type$2.Optional(Type$2.String()),
|
|
184
|
-
/** Structured, provider-independent details for a failed request. */
|
|
185
|
-
failure: Type$2.Optional(FailureSchema),
|
|
186
|
-
time: Type$2.Object({
|
|
187
|
-
created: Type$2.Number(),
|
|
188
|
-
completed: Type$2.Number()
|
|
189
|
-
}),
|
|
190
|
-
parts: Type$2.Array(Type$2.Union([
|
|
191
|
-
TextContentSchema,
|
|
192
|
-
ImageContentSchema,
|
|
193
|
-
ThinkingContentSchema,
|
|
194
|
-
ToolCallSchema
|
|
195
|
-
])),
|
|
196
|
-
responseId: Type$2.Optional(Type$2.String()),
|
|
197
|
-
responseModel: Type$2.Optional(Type$2.String()),
|
|
198
|
-
messageId: Type$2.String()
|
|
199
|
-
});
|
|
200
|
-
const MessageSchema = Type$2.Union([UserMessageSchema, AssistantMessageSchema]);
|
|
201
|
-
function createMessageId() {
|
|
202
|
-
return uuidv7();
|
|
203
|
-
}
|
|
204
|
-
function createUserMessage(message) {
|
|
205
|
-
const { messageId = createMessageId(), ...rest } = message;
|
|
206
|
-
return {
|
|
207
|
-
messageId,
|
|
208
|
-
...rest
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
function createAssistantMessage$1(message) {
|
|
212
|
-
const { messageId = createMessageId(), ...rest } = message;
|
|
213
|
-
return {
|
|
214
|
-
messageId,
|
|
215
|
-
...rest
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
const GrammarVariantsSchema = Type$2.Partial(Type$2.Object({
|
|
219
|
-
openai_lark: Type$2.String(),
|
|
220
|
-
openai_regex: Type$2.String()
|
|
221
|
-
}));
|
|
222
|
-
const ConstrainedSamplingSchema = Type$2.Union([Type$2.Object({
|
|
223
|
-
type: Type$2.Literal("json_schema"),
|
|
224
|
-
strict: Type$2.Union([Type$2.Literal("prefer"), Type$2.Literal("require")])
|
|
225
|
-
}), Type$2.Object({
|
|
226
|
-
type: Type$2.Literal("grammar"),
|
|
227
|
-
variants: GrammarVariantsSchema
|
|
228
|
-
})]);
|
|
229
|
-
/**
|
|
230
|
-
* Generic tool definition with typed parameter schema.
|
|
231
|
-
* Usage:
|
|
232
|
-
*
|
|
233
|
-
* const search = Message.defineTool({
|
|
234
|
-
* name: "search",
|
|
235
|
-
* description: "Search documents",
|
|
236
|
-
* parameters: Type.Object({
|
|
237
|
-
* query: Type.String(),
|
|
238
|
-
* limit: Type.Optional(Type.Number()),
|
|
239
|
-
* }),
|
|
240
|
-
* });
|
|
241
|
-
*
|
|
242
|
-
* type SearchParams = Static<typeof search.parameters>;
|
|
243
|
-
*/
|
|
244
|
-
const ToolSchema = Type$2.Object({
|
|
245
|
-
name: Type$2.String(),
|
|
246
|
-
description: Type$2.String(),
|
|
247
|
-
parameters: Type$2.Unsafe({}),
|
|
248
|
-
constrainedSampling: Type$2.Optional(Type$2.Union([Type$2.Literal(false), ConstrainedSamplingSchema]))
|
|
249
|
-
});
|
|
250
|
-
function defineTool(tool) {
|
|
251
|
-
return tool;
|
|
252
|
-
}
|
|
253
|
-
const ContextSchema = Type$2.Object({
|
|
254
|
-
systemPrompt: Type$2.Optional(Type$2.String()),
|
|
255
|
-
messages: Type$2.Array(MessageSchema),
|
|
256
|
-
tools: Type$2.Optional(Type$2.Array(ToolSchema))
|
|
257
|
-
});
|
|
258
|
-
function isUnresolvedToolCall(toolCall) {
|
|
259
|
-
return toolCall.status === ToolStatusEnum.pending || toolCall.status === ToolStatusEnum.running;
|
|
260
|
-
}
|
|
261
|
-
function syntheticSkippedToolCall(toolCall) {
|
|
262
|
-
const { status: _status, partial: _partial, ...base } = toolCall;
|
|
263
|
-
return {
|
|
264
|
-
...base,
|
|
265
|
-
status: ToolStatusEnum.skipped,
|
|
266
|
-
result: {
|
|
267
|
-
content: [{
|
|
268
|
-
type: "text",
|
|
269
|
-
text: "No result provided"
|
|
270
|
-
}],
|
|
271
|
-
isError: true
|
|
272
|
-
},
|
|
273
|
-
time: {
|
|
274
|
-
...toolCall.time,
|
|
275
|
-
end: Math.max(toolCall.time.end, Date.now())
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
function transformMessages(messages, model, normalizeToolCallId) {
|
|
280
|
-
const toolCallIDMap = /* @__PURE__ */ new Map();
|
|
281
|
-
const transformed = [];
|
|
282
|
-
for (const msg of messages) {
|
|
283
|
-
if (msg.role === "user") {
|
|
284
|
-
transformed.push(msg);
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
const assistantMsg = msg;
|
|
288
|
-
const isSameModel = assistantMsg.provider.id === model.provider.id && assistantMsg.protocol === model.protocol && assistantMsg.model === model.id;
|
|
289
|
-
const parts = assistantMsg.parts.flatMap((block) => {
|
|
290
|
-
if (block.type === "thinking") {
|
|
291
|
-
if (isSameModel && block.thinkingSignature) return block;
|
|
292
|
-
if (!block.thinking || block.thinking.trim() === "") return [];
|
|
293
|
-
if (isSameModel) return block;
|
|
294
|
-
return {
|
|
295
|
-
type: "text",
|
|
296
|
-
text: block.thinking
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
if (block.type === "text") {
|
|
300
|
-
if (isSameModel) return block;
|
|
301
|
-
return {
|
|
302
|
-
type: "text",
|
|
303
|
-
text: block.text
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
if (block.type === "toolCall") {
|
|
307
|
-
const toolCall = block;
|
|
308
|
-
let normalizedToolCall = toolCall;
|
|
309
|
-
if (!isSameModel && toolCall.thoughtSignature) {
|
|
310
|
-
normalizedToolCall = { ...toolCall };
|
|
311
|
-
delete normalizedToolCall.thoughtSignature;
|
|
312
|
-
}
|
|
313
|
-
const normalizedID = toolCallIDMap.get(block.callID);
|
|
314
|
-
if (normalizedID && normalizedID !== block.callID) normalizedToolCall = {
|
|
315
|
-
...normalizedToolCall,
|
|
316
|
-
callID: normalizedID
|
|
317
|
-
};
|
|
318
|
-
else if (!isSameModel && normalizeToolCallId) {
|
|
319
|
-
const nextID = normalizeToolCallId(toolCall.callID, model, assistantMsg);
|
|
320
|
-
if (nextID !== toolCall.callID) {
|
|
321
|
-
toolCallIDMap.set(toolCall.callID, nextID);
|
|
322
|
-
normalizedToolCall = {
|
|
323
|
-
...normalizedToolCall,
|
|
324
|
-
callID: nextID
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return normalizedToolCall;
|
|
329
|
-
}
|
|
330
|
-
return block;
|
|
331
|
-
}).map((block) => {
|
|
332
|
-
if (block.type === "toolCall" && isUnresolvedToolCall(block)) return syntheticSkippedToolCall(block);
|
|
333
|
-
return block;
|
|
334
|
-
});
|
|
335
|
-
transformed.push({
|
|
336
|
-
...assistantMsg,
|
|
337
|
-
parts
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
return transformed;
|
|
341
|
-
}
|
|
342
|
-
//#endregion
|
|
10
|
+
import Value from "typebox/value";
|
|
343
11
|
//#region src/event/event.ts
|
|
344
12
|
var event_exports = /* @__PURE__ */ __exportAll({
|
|
345
|
-
AgentEventSchema: () => AgentEventSchema,
|
|
346
|
-
AgentEventType: () => AgentEventType,
|
|
347
13
|
LLMMessageEventSchema: () => LLMMessageEventSchema,
|
|
348
14
|
LLMMessageEventType: () => LLMMessageEventType
|
|
349
15
|
});
|
|
@@ -447,122 +113,10 @@ const LLMMessageEventSchema = Type$2.Union([
|
|
|
447
113
|
error: AssistantMessageSchema
|
|
448
114
|
})
|
|
449
115
|
]);
|
|
450
|
-
const AgentEventType = {
|
|
451
|
-
agentStart: "agent.start",
|
|
452
|
-
agentEnd: "agent.end",
|
|
453
|
-
turnStart: "turn.start",
|
|
454
|
-
turnEnd: "turn.end",
|
|
455
|
-
messageStart: "message.start",
|
|
456
|
-
messagePartStart: "message.part.start",
|
|
457
|
-
messagePartUpdate: "message.part.update",
|
|
458
|
-
messagePartEnd: "message.part.end",
|
|
459
|
-
messageUpdate: "message.update",
|
|
460
|
-
messageEnd: "message.end",
|
|
461
|
-
toolExecutionStart: "tool.execution.start",
|
|
462
|
-
toolExecutionUpdate: "tool.execution.update",
|
|
463
|
-
toolExecutionEnd: "tool.execution.end"
|
|
464
|
-
};
|
|
465
|
-
const UserMessagePart = Type$2.Union([TextContentSchema, ImageContentSchema]);
|
|
466
|
-
const AssistantMessagePart = Type$2.Union([
|
|
467
|
-
TextContentSchema,
|
|
468
|
-
ImageContentSchema,
|
|
469
|
-
ThinkingContentSchema,
|
|
470
|
-
ToolCallSchema
|
|
471
|
-
]);
|
|
472
|
-
const UserMessagePartStart = Type$2.Object({
|
|
473
|
-
type: Type$2.Literal(AgentEventType.messagePartStart),
|
|
474
|
-
message: UserMessageSchema,
|
|
475
|
-
partIndex: Type$2.Number(),
|
|
476
|
-
part: UserMessagePart
|
|
477
|
-
});
|
|
478
|
-
const UserMessagePartEnd = Type$2.Object({
|
|
479
|
-
type: Type$2.Literal(AgentEventType.messagePartEnd),
|
|
480
|
-
message: UserMessageSchema,
|
|
481
|
-
partIndex: Type$2.Number(),
|
|
482
|
-
part: UserMessagePart
|
|
483
|
-
});
|
|
484
|
-
const AssistantMessagePartStart = Type$2.Object({
|
|
485
|
-
type: Type$2.Literal(AgentEventType.messagePartStart),
|
|
486
|
-
message: AssistantMessageSchema,
|
|
487
|
-
partIndex: Type$2.Number(),
|
|
488
|
-
part: AssistantMessagePart
|
|
489
|
-
});
|
|
490
|
-
const AssistantMessagePartLLMUpdate = Type$2.Object({
|
|
491
|
-
type: Type$2.Literal(AgentEventType.messagePartUpdate),
|
|
492
|
-
message: AssistantMessageSchema,
|
|
493
|
-
partIndex: Type$2.Number(),
|
|
494
|
-
part: AssistantMessagePart,
|
|
495
|
-
source: Type$2.Literal("llm")
|
|
496
|
-
});
|
|
497
|
-
const AssistantMessagePartToolUpdate = Type$2.Object({
|
|
498
|
-
type: Type$2.Literal(AgentEventType.messagePartUpdate),
|
|
499
|
-
message: AssistantMessageSchema,
|
|
500
|
-
partIndex: Type$2.Number(),
|
|
501
|
-
part: AssistantMessagePart,
|
|
502
|
-
source: Type$2.Literal("tool")
|
|
503
|
-
});
|
|
504
|
-
const AssistantMessagePartEnd = Type$2.Object({
|
|
505
|
-
type: Type$2.Literal(AgentEventType.messagePartEnd),
|
|
506
|
-
message: AssistantMessageSchema,
|
|
507
|
-
partIndex: Type$2.Number(),
|
|
508
|
-
part: AssistantMessagePart
|
|
509
|
-
});
|
|
510
|
-
const ToolExecutionStartSchema = Type$2.Object({
|
|
511
|
-
type: Type$2.Literal(AgentEventType.toolExecutionStart),
|
|
512
|
-
messageId: Type$2.String(),
|
|
513
|
-
partIndex: Type$2.Number(),
|
|
514
|
-
toolCall: ToolCallPendingPartSchema
|
|
515
|
-
});
|
|
516
|
-
const ToolExecutionUpdateSchema = Type$2.Object({
|
|
517
|
-
type: Type$2.Literal(AgentEventType.toolExecutionUpdate),
|
|
518
|
-
messageId: Type$2.String(),
|
|
519
|
-
partIndex: Type$2.Number(),
|
|
520
|
-
toolCall: ToolCallRunningPartSchema
|
|
521
|
-
});
|
|
522
|
-
const ToolExecutionEndSchema = Type$2.Object({
|
|
523
|
-
type: Type$2.Literal(AgentEventType.toolExecutionEnd),
|
|
524
|
-
messageId: Type$2.String(),
|
|
525
|
-
partIndex: Type$2.Number(),
|
|
526
|
-
toolCall: ToolCallTerminalPartSchema
|
|
527
|
-
});
|
|
528
116
|
/**
|
|
529
117
|
* Events emitted by the Agent lifecycle
|
|
530
118
|
* These events provide fine-grained lifecycle information for messages, turns, and tool execution.
|
|
531
119
|
*/
|
|
532
|
-
const AgentEventSchema = Type$2.Union([
|
|
533
|
-
Type$2.Object({ type: Type$2.Literal(AgentEventType.agentStart) }),
|
|
534
|
-
Type$2.Object({
|
|
535
|
-
type: Type$2.Literal(AgentEventType.agentEnd),
|
|
536
|
-
messages: Type$2.Array(MessageSchema)
|
|
537
|
-
}),
|
|
538
|
-
Type$2.Object({ type: Type$2.Literal(AgentEventType.turnStart) }),
|
|
539
|
-
Type$2.Object({
|
|
540
|
-
type: Type$2.Literal(AgentEventType.turnEnd),
|
|
541
|
-
message: AssistantMessageSchema
|
|
542
|
-
}),
|
|
543
|
-
Type$2.Object({
|
|
544
|
-
type: Type$2.Literal(AgentEventType.messageStart),
|
|
545
|
-
message: MessageSchema
|
|
546
|
-
}),
|
|
547
|
-
Type$2.Union([UserMessagePartStart, UserMessagePartEnd]),
|
|
548
|
-
Type$2.Union([
|
|
549
|
-
AssistantMessagePartStart,
|
|
550
|
-
AssistantMessagePartLLMUpdate,
|
|
551
|
-
AssistantMessagePartToolUpdate,
|
|
552
|
-
AssistantMessagePartEnd
|
|
553
|
-
]),
|
|
554
|
-
Type$2.Object({
|
|
555
|
-
type: Type$2.Literal(AgentEventType.messageUpdate),
|
|
556
|
-
message: MessageSchema
|
|
557
|
-
}),
|
|
558
|
-
Type$2.Object({
|
|
559
|
-
type: Type$2.Literal(AgentEventType.messageEnd),
|
|
560
|
-
message: MessageSchema
|
|
561
|
-
}),
|
|
562
|
-
ToolExecutionStartSchema,
|
|
563
|
-
ToolExecutionUpdateSchema,
|
|
564
|
-
ToolExecutionEndSchema
|
|
565
|
-
]);
|
|
566
120
|
//#endregion
|
|
567
121
|
//#region src/llm.ts
|
|
568
122
|
const llmImpl = async (provider, model, overrides) => getModel(provider, model, overrides);
|
|
@@ -641,6 +195,137 @@ function clearProtocolProviders() {
|
|
|
641
195
|
protocolRegistry.clear();
|
|
642
196
|
}
|
|
643
197
|
//#endregion
|
|
198
|
+
//#region src/utils/estimate.ts
|
|
199
|
+
/** Rough characters-per-token ratio across the tokenizers in use. */
|
|
200
|
+
const CHARS_PER_TOKEN = 4;
|
|
201
|
+
/** A base64 image costs far more than its own text length; this is a flat stand-in. */
|
|
202
|
+
const ESTIMATED_IMAGE_CHARS = 4800;
|
|
203
|
+
function calculateContextTokens(usage) {
|
|
204
|
+
return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
205
|
+
}
|
|
206
|
+
function safeJsonStringify(value) {
|
|
207
|
+
try {
|
|
208
|
+
return JSON.stringify(value) ?? "undefined";
|
|
209
|
+
} catch {
|
|
210
|
+
return "[unserializable]";
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function estimateTextTokens(text) {
|
|
214
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
215
|
+
}
|
|
216
|
+
function contentChars(content) {
|
|
217
|
+
let chars = 0;
|
|
218
|
+
for (const block of content) chars += block.type === "text" ? block.text.length : ESTIMATED_IMAGE_CHARS;
|
|
219
|
+
return chars;
|
|
220
|
+
}
|
|
221
|
+
function estimateContentTokens(content) {
|
|
222
|
+
return Math.ceil(contentChars(content) / CHARS_PER_TOKEN);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* A tool call costs its name, its arguments, and -- unlike providers that carry
|
|
226
|
+
* results in their own messages -- the result it already holds.
|
|
227
|
+
*/
|
|
228
|
+
function toolCallChars(part) {
|
|
229
|
+
return part.name.length + safeJsonStringify(part.arguments).length + toolResultChars(part);
|
|
230
|
+
}
|
|
231
|
+
function toolResultChars(part) {
|
|
232
|
+
return "result" in part && part.result ? contentChars(part.result.content) : 0;
|
|
233
|
+
}
|
|
234
|
+
function estimateMessageTokens(message) {
|
|
235
|
+
if (message.role === "user") return estimateContentTokens(message.parts);
|
|
236
|
+
let chars = 0;
|
|
237
|
+
for (const part of message.parts) switch (part.type) {
|
|
238
|
+
case "text":
|
|
239
|
+
chars += part.text.length;
|
|
240
|
+
break;
|
|
241
|
+
case "image":
|
|
242
|
+
chars += ESTIMATED_IMAGE_CHARS;
|
|
243
|
+
break;
|
|
244
|
+
case "thinking":
|
|
245
|
+
chars += part.thinking.length;
|
|
246
|
+
break;
|
|
247
|
+
case "toolCall": chars += toolCallChars(part);
|
|
248
|
+
}
|
|
249
|
+
return Math.ceil(chars / CHARS_PER_TOKEN);
|
|
250
|
+
}
|
|
251
|
+
function lastAssistantUsage(messages) {
|
|
252
|
+
let latestPrefixTime = Number.NEGATIVE_INFINITY;
|
|
253
|
+
let found;
|
|
254
|
+
for (let i = 0; i < messages.length; i++) {
|
|
255
|
+
const message = messages[i];
|
|
256
|
+
if (message.role === "assistant") {
|
|
257
|
+
if (message.time.created >= latestPrefixTime && message.stopReason !== "aborted" && message.stopReason !== "error" && calculateContextTokens(message.usage) > 0) found = {
|
|
258
|
+
usage: message.usage,
|
|
259
|
+
index: i
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
latestPrefixTime = Math.max(latestPrefixTime, message.time.created);
|
|
263
|
+
}
|
|
264
|
+
return found;
|
|
265
|
+
}
|
|
266
|
+
function estimateMessages(messages) {
|
|
267
|
+
const usage = lastAssistantUsage(messages);
|
|
268
|
+
if (usage) {
|
|
269
|
+
const usageTokens = calculateContextTokens(usage.usage);
|
|
270
|
+
const latest = messages[usage.index];
|
|
271
|
+
let resultChars = 0;
|
|
272
|
+
for (const part of latest.parts) if (part.type === "toolCall") resultChars += toolResultChars(part);
|
|
273
|
+
let trailingTokens = Math.ceil(resultChars / CHARS_PER_TOKEN);
|
|
274
|
+
for (let i = usage.index + 1; i < messages.length; i++) trailingTokens += estimateMessageTokens(messages[i]);
|
|
275
|
+
return {
|
|
276
|
+
tokens: usageTokens + trailingTokens,
|
|
277
|
+
usageTokens,
|
|
278
|
+
trailingTokens,
|
|
279
|
+
lastUsageIndex: usage.index
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
let tokens = 0;
|
|
283
|
+
for (const message of messages) tokens += estimateMessageTokens(message);
|
|
284
|
+
return {
|
|
285
|
+
tokens,
|
|
286
|
+
usageTokens: 0,
|
|
287
|
+
trailingTokens: tokens,
|
|
288
|
+
lastUsageIndex: null
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function estimateToolsTokens(tools) {
|
|
292
|
+
if (!tools || tools.length === 0) return 0;
|
|
293
|
+
return estimateTextTokens(safeJsonStringify(tools));
|
|
294
|
+
}
|
|
295
|
+
/** Tools discovered by execution of the given assistant turn or later turns. */
|
|
296
|
+
function toolNamesAddedAfter(messages, index) {
|
|
297
|
+
const names = /* @__PURE__ */ new Set();
|
|
298
|
+
for (let i = index; i < messages.length; i++) {
|
|
299
|
+
const message = messages[i];
|
|
300
|
+
if (message.role !== "assistant") continue;
|
|
301
|
+
for (const part of message.parts) {
|
|
302
|
+
if (part.type !== "toolCall") continue;
|
|
303
|
+
for (const name of part.addedToolNames ?? []) names.add(name);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return names;
|
|
307
|
+
}
|
|
308
|
+
function estimateContextTokens(context) {
|
|
309
|
+
const estimate = estimateMessages(context.messages);
|
|
310
|
+
if (estimate.lastUsageIndex !== null) {
|
|
311
|
+
const added = toolNamesAddedAfter(context.messages, estimate.lastUsageIndex);
|
|
312
|
+
const addedTokens = estimateToolsTokens(context.tools?.filter((tool) => added.has(tool.name)));
|
|
313
|
+
return {
|
|
314
|
+
tokens: estimate.tokens + addedTokens,
|
|
315
|
+
usageTokens: estimate.usageTokens,
|
|
316
|
+
trailingTokens: estimate.trailingTokens + addedTokens,
|
|
317
|
+
lastUsageIndex: estimate.lastUsageIndex
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
const prefixTokens = (context.systemPrompt ? estimateTextTokens(context.systemPrompt) : 0) + estimateToolsTokens(context.tools);
|
|
321
|
+
return {
|
|
322
|
+
tokens: estimate.tokens + prefixTokens,
|
|
323
|
+
usageTokens: estimate.usageTokens,
|
|
324
|
+
trailingTokens: estimate.trailingTokens + prefixTokens,
|
|
325
|
+
lastUsageIndex: estimate.lastUsageIndex
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
644
329
|
//#region src/llm/shared.ts
|
|
645
330
|
const CacheRetention = Type$1.Union([
|
|
646
331
|
Type$1.Literal("none"),
|
|
@@ -662,22 +347,76 @@ const HelperOptions = Type$1.Object({
|
|
|
662
347
|
onPayload: Type$1.Optional(Type$1.Unsafe({})),
|
|
663
348
|
metadata: Type$1.Optional(Type$1.Record(Type$1.String(), Type$1.Unknown()))
|
|
664
349
|
});
|
|
665
|
-
const ThinkingBudgets =
|
|
666
|
-
minimal: Type$1.Optional(Type$1.Number()),
|
|
667
|
-
low: Type$1.Optional(Type$1.Number()),
|
|
668
|
-
medium: Type$1.Optional(Type$1.Number()),
|
|
669
|
-
high: Type$1.Optional(Type$1.Number()),
|
|
670
|
-
xhigh: Type$1.Optional(Type$1.Number()),
|
|
671
|
-
max: Type$1.Optional(Type$1.Number())
|
|
672
|
-
});
|
|
350
|
+
const ThinkingBudgets = ThinkingBudgets$1;
|
|
673
351
|
const SharedOptions = Type$1.Evaluate(Type$1.Intersect([GenerationOptions, HelperOptions]));
|
|
674
|
-
|
|
675
|
-
const
|
|
352
|
+
/** Headroom left for the prompt when sizing a response against the context window. */
|
|
353
|
+
const CONTEXT_SAFETY_TOKENS = 4096;
|
|
354
|
+
const MIN_MAX_TOKENS = 1;
|
|
355
|
+
/**
|
|
356
|
+
* The model's own ceiling, unless the caller named a smaller one.
|
|
357
|
+
*
|
|
358
|
+
* No heuristic cap here: a catalog whose `maxTokens` spans the whole context
|
|
359
|
+
* window is handled by {@link clampMaxTokensToContext}, which knows what the
|
|
360
|
+
* prompt actually costs and does not have to guess.
|
|
361
|
+
*/
|
|
676
362
|
function applyDefaultMaxTokens(model, options) {
|
|
677
|
-
const defaultMaxTokens = model.maxTokens > 0 ? model.maxTokens >= model.contextWindow - CONTEXT_WINDOW_OUTPUT_TOLERANCE ? Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS) : model.maxTokens : void 0;
|
|
678
363
|
return {
|
|
679
364
|
...options,
|
|
680
|
-
maxTokens: options?.maxTokens ??
|
|
365
|
+
maxTokens: options?.maxTokens ?? (model.maxTokens > 0 ? model.maxTokens : void 0)
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Shrink a response ceiling to what is left of the context window.
|
|
370
|
+
*
|
|
371
|
+
* Without this a long session asks for an answer that cannot fit and takes a
|
|
372
|
+
* provider overflow error instead of a shorter answer.
|
|
373
|
+
*/
|
|
374
|
+
function clampMaxTokensToContext(model, context, maxTokens) {
|
|
375
|
+
if (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);
|
|
376
|
+
const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;
|
|
377
|
+
return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));
|
|
378
|
+
}
|
|
379
|
+
/** Tokens always left for the answer when a thinking budget shares the response ceiling. */
|
|
380
|
+
const MIN_ANSWER_TOKENS = 1024;
|
|
381
|
+
/**
|
|
382
|
+
* Default thinking budget per level, in tokens.
|
|
383
|
+
*
|
|
384
|
+
* Absolute rather than a fraction of `model.maxTokens`: a fraction turns one
|
|
385
|
+
* "medium" setting into wildly different budgets across models, and a budget is
|
|
386
|
+
* a property of how hard the task is, not of how large the model's ceiling is.
|
|
387
|
+
*/
|
|
388
|
+
const DEFAULT_THINKING_BUDGETS = {
|
|
389
|
+
minimal: 1024,
|
|
390
|
+
low: 2048,
|
|
391
|
+
medium: 8192,
|
|
392
|
+
high: 16384
|
|
393
|
+
};
|
|
394
|
+
/** `xhigh` and `max` fall back to `high`'s budget unless one is configured for them. */
|
|
395
|
+
function baseThinkingLevel(level) {
|
|
396
|
+
return level === "xhigh" || level === "max" ? "high" : level;
|
|
397
|
+
}
|
|
398
|
+
function thinkingBudgetForLevel(level, budgets) {
|
|
399
|
+
const base = baseThinkingLevel(level);
|
|
400
|
+
return budgets?.[level] ?? budgets?.[base] ?? DEFAULT_THINKING_BUDGETS[base];
|
|
401
|
+
}
|
|
402
|
+
/** Cap a thinking budget so at least {@link MIN_ANSWER_TOKENS} remain under a shared response ceiling. */
|
|
403
|
+
function clampThinkingBudgetToAnswerRoom(thinkingBudget, ceiling) {
|
|
404
|
+
return Math.min(thinkingBudget, Math.max(0, ceiling - MIN_ANSWER_TOKENS));
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Fit a thinking budget and an answer inside one response ceiling.
|
|
408
|
+
*
|
|
409
|
+
* The caller's `maxTokens` is the room they want for the *answer*, so thinking is
|
|
410
|
+
* added on top and the total is clamped to the model's ceiling. When even that
|
|
411
|
+
* does not fit, the budget gives way -- never the answer.
|
|
412
|
+
*/
|
|
413
|
+
function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, level, budgets) {
|
|
414
|
+
let thinkingBudget = thinkingBudgetForLevel(level, budgets);
|
|
415
|
+
const maxTokens = baseMaxTokens === void 0 ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
|
|
416
|
+
if (maxTokens <= thinkingBudget) thinkingBudget = clampThinkingBudgetToAnswerRoom(thinkingBudget, maxTokens);
|
|
417
|
+
return {
|
|
418
|
+
maxTokens,
|
|
419
|
+
thinkingBudget
|
|
681
420
|
};
|
|
682
421
|
}
|
|
683
422
|
Type$1.Evaluate(Type$1.Intersect([SharedOptions, Type$1.Object({
|
|
@@ -747,7 +486,7 @@ var AssistantMessageEventStream = class extends EventStream {
|
|
|
747
486
|
super((event) => event.type === "done" || event.type === "error", (event) => {
|
|
748
487
|
if (event.type === "done") return event.message;
|
|
749
488
|
else if (event.type === "error") return event.error;
|
|
750
|
-
throw new Error("
|
|
489
|
+
throw new Error("unexpected event type for final result");
|
|
751
490
|
});
|
|
752
491
|
}
|
|
753
492
|
};
|
|
@@ -771,6 +510,53 @@ function compact(value) {
|
|
|
771
510
|
return result;
|
|
772
511
|
}
|
|
773
512
|
//#endregion
|
|
513
|
+
//#region src/llm/pricing.ts
|
|
514
|
+
/** Protocols that price a request by the OpenAI service tier it was served at. */
|
|
515
|
+
const SERVICE_TIER_KEYS = /* @__PURE__ */ new Set(["openai", "openai-codex"]);
|
|
516
|
+
function asString(value) {
|
|
517
|
+
return typeof value === "string" ? value : void 0;
|
|
518
|
+
}
|
|
519
|
+
function bag(value, key) {
|
|
520
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
521
|
+
const nested = value[key];
|
|
522
|
+
return typeof nested === "object" && nested !== null ? nested : void 0;
|
|
523
|
+
}
|
|
524
|
+
/** The tier the request asked for, before the provider says which one it used. */
|
|
525
|
+
function requestedServiceTier(model, options, providerOptions) {
|
|
526
|
+
const key = optionsKey(model);
|
|
527
|
+
if (!SERVICE_TIER_KEYS.has(key)) return void 0;
|
|
528
|
+
return asString(providerOptions[key]?.serviceTier ?? options.factoryOptions?.serviceTier ?? model.options?.serviceTier);
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* The tier the response was actually served at, which is what gets billed.
|
|
532
|
+
*
|
|
533
|
+
* A `"default"` response to an explicit flex or priority request still bills at
|
|
534
|
+
* the requested tier: the Codex backend reports the fallback it used, not the
|
|
535
|
+
* rate it charged.
|
|
536
|
+
*/
|
|
537
|
+
function servedServiceTier(model, requested, providerMetadata) {
|
|
538
|
+
const key = optionsKey(model);
|
|
539
|
+
if (!SERVICE_TIER_KEYS.has(key)) return void 0;
|
|
540
|
+
const served = asString(bag(providerMetadata, key)?.serviceTier);
|
|
541
|
+
if (key === "openai-codex" && served === "default" && (requested === "flex" || requested === "priority")) return requested;
|
|
542
|
+
return served ?? requested;
|
|
543
|
+
}
|
|
544
|
+
function serviceTierCostMultiplier(model, serviceTier) {
|
|
545
|
+
return serviceTier === void 0 ? 1 : model.cost.serviceTierMultipliers?.[serviceTier] ?? 1;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Tokens Anthropic wrote with 1h retention, out of the total cache write.
|
|
549
|
+
*
|
|
550
|
+
* The AI SDK does not model the split, but it passes Anthropic's raw usage object
|
|
551
|
+
* through untouched, so read it from there.
|
|
552
|
+
*/
|
|
553
|
+
function cacheWrite1hTokens(providerMetadata) {
|
|
554
|
+
for (const key of ["anthropic", "google-vertex-anthropic"]) {
|
|
555
|
+
const tokens = bag(bag(bag(providerMetadata, key), "usage"), "cache_creation")?.ephemeral_1h_input_tokens;
|
|
556
|
+
if (typeof tokens === "number") return tokens;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
//#endregion
|
|
774
560
|
//#region src/llm/runtime.ts
|
|
775
561
|
function mergeHeaders(...headerSources) {
|
|
776
562
|
const merged = {};
|
|
@@ -804,7 +590,23 @@ function cleanHeaders(headers) {
|
|
|
804
590
|
function resolveBaseURL(model, options) {
|
|
805
591
|
return (options.baseURL ?? model.api?.url ?? model.baseUrl) || void 0;
|
|
806
592
|
}
|
|
807
|
-
|
|
593
|
+
/**
|
|
594
|
+
* Inject a thinking-token budget the AI SDK has no field for.
|
|
595
|
+
*
|
|
596
|
+
* `@ai-sdk/openai-compatible` validates provider options against a closed schema,
|
|
597
|
+
* so an endpoint-specific budget field cannot travel that way. `transformRequestBody`
|
|
598
|
+
* is the SDK's own hook for exactly this: the last edit before the body is sent.
|
|
599
|
+
*/
|
|
600
|
+
function thinkingTokenBudgetTransform(field, budget, existing) {
|
|
601
|
+
const chain = typeof existing === "function" ? existing : void 0;
|
|
602
|
+
return (body) => {
|
|
603
|
+
return {
|
|
604
|
+
...chain ? chain(body) : body,
|
|
605
|
+
[field]: budget
|
|
606
|
+
};
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
async function resolveAISDKLanguageModel(model, options, thinkingTokenBudget) {
|
|
808
610
|
const npm = packageForModel(model);
|
|
809
611
|
const createProvider = await loadProviderFactory(npm);
|
|
810
612
|
const apiKey = options.apiKey ?? getEnvApiKey(model.provider);
|
|
@@ -824,19 +626,171 @@ async function resolveAISDKLanguageModel(model, options) {
|
|
|
824
626
|
});
|
|
825
627
|
factoryOptions.name ??= model.provider.id;
|
|
826
628
|
factoryOptions.includeUsage ??= true;
|
|
629
|
+
const budgetField = thinkingTokenBudgetField(model);
|
|
630
|
+
if (budgetField && thinkingTokenBudget !== void 0 && thinkingTokenBudget > 0) factoryOptions.transformRequestBody = thinkingTokenBudgetTransform(budgetField, thinkingTokenBudget, factoryOptions.transformRequestBody);
|
|
827
631
|
}
|
|
828
632
|
if (npm === "@codeworksh/ai-sdk-openai-codex") {
|
|
829
633
|
const cacheDisabled = options.cacheRetention === "none" || typeof process !== "undefined" && process.env.CODEWORK_CACHE_RETENTION === "none";
|
|
830
634
|
if (options.sessionId && !cacheDisabled) factoryOptions.sessionId ??= options.sessionId;
|
|
831
|
-
factoryOptions.compat
|
|
635
|
+
factoryOptions.compat = {
|
|
832
636
|
...model.compat,
|
|
833
|
-
supportsImages: model.input.includes("image")
|
|
637
|
+
supportsImages: model.input.includes("image"),
|
|
638
|
+
...typeof factoryOptions.compat === "object" && factoryOptions.compat !== null ? factoryOptions.compat : {}
|
|
834
639
|
};
|
|
835
640
|
}
|
|
836
641
|
const provider = createProvider(factoryOptions);
|
|
837
642
|
return resolveLanguageModel(provider, model, options.method);
|
|
838
643
|
}
|
|
839
644
|
//#endregion
|
|
645
|
+
//#region src/llm/thinking.ts
|
|
646
|
+
/** Anthropic rejects an enabled thinking block whose budget is under 1024 tokens. */
|
|
647
|
+
const ANTHROPIC_MIN_THINKING_BUDGET = 1024;
|
|
648
|
+
/**
|
|
649
|
+
* The smallest budget this model will accept, for providers that take one at all.
|
|
650
|
+
*
|
|
651
|
+
* Adaptive models are exempt: they are sent an effort level and no budget, so
|
|
652
|
+
* there is no floor to fall under.
|
|
653
|
+
*/
|
|
654
|
+
function minimumThinkingBudget(model) {
|
|
655
|
+
const key = optionsKey(model);
|
|
656
|
+
if (key !== "anthropic" && key !== "google-vertex-anthropic") return 0;
|
|
657
|
+
return model.compat?.forceAdaptiveThinking ? 0 : ANTHROPIC_MIN_THINKING_BUDGET;
|
|
658
|
+
}
|
|
659
|
+
function resolvePlan(model, context, options) {
|
|
660
|
+
const clampToContext = (maxTokens) => maxTokens === void 0 ? void 0 : clampMaxTokensToContext(model, context, maxTokens);
|
|
661
|
+
const requested = options.reasoning;
|
|
662
|
+
const level = requested ? clampThinkingLevel(model, requested) : "off";
|
|
663
|
+
if (level === "off") return {
|
|
664
|
+
level,
|
|
665
|
+
budget: 0,
|
|
666
|
+
maxTokens: clampToContext(options.maxTokens),
|
|
667
|
+
explicit: false
|
|
668
|
+
};
|
|
669
|
+
const budgets = {
|
|
670
|
+
...model.thinkingBudgets,
|
|
671
|
+
...options.thinkingBudgets
|
|
672
|
+
};
|
|
673
|
+
const explicit = options.thinkingBudgets?.[level] !== void 0;
|
|
674
|
+
const key = optionsKey(model);
|
|
675
|
+
const usesGoogleBudget = (key === "google" || key === "google-vertex") && !model.compat?.supportsThinkingLevel;
|
|
676
|
+
const requestedBudget = thinkingBudgetForLevel(level, budgets);
|
|
677
|
+
if (model.maxTokens <= 0) return {
|
|
678
|
+
level,
|
|
679
|
+
budget: requestedBudget,
|
|
680
|
+
maxTokens: clampToContext(options.maxTokens),
|
|
681
|
+
explicit
|
|
682
|
+
};
|
|
683
|
+
const dynamic = usesGoogleBudget && requestedBudget === -1;
|
|
684
|
+
const adjusted = adjustMaxTokensForThinking(options.maxTokens, model.maxTokens, level, { [level]: dynamic ? 0 : requestedBudget });
|
|
685
|
+
const maxTokens = clampMaxTokensToContext(model, context, adjusted.maxTokens);
|
|
686
|
+
const budget = maxTokens < adjusted.maxTokens ? clampThinkingBudgetToAnswerRoom(adjusted.thinkingBudget, maxTokens) : adjusted.thinkingBudget;
|
|
687
|
+
if (budget < minimumThinkingBudget(model)) return {
|
|
688
|
+
level: "off",
|
|
689
|
+
budget: 0,
|
|
690
|
+
maxTokens,
|
|
691
|
+
explicit
|
|
692
|
+
};
|
|
693
|
+
return {
|
|
694
|
+
level,
|
|
695
|
+
budget: dynamic ? -1 : budget,
|
|
696
|
+
maxTokens,
|
|
697
|
+
explicit
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
function googleThinkingLevel(mapped) {
|
|
701
|
+
return mapped === "xhigh" || mapped === "max" ? "high" : mapped;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Turn thinking off, in the provider's own words.
|
|
705
|
+
*
|
|
706
|
+
* Several models reason by default, so declining to *ask* for thinking is not the
|
|
707
|
+
* same as asking for none: the caller ends up paying output tokens for reasoning
|
|
708
|
+
* they never requested.
|
|
709
|
+
*
|
|
710
|
+
* OpenRouter is deliberately left alone. It fronts hundreds of third-party
|
|
711
|
+
* endpoints whose support varies per endpoint -- several reject the request
|
|
712
|
+
* outright with "reasoning is mandatory for this endpoint and cannot be disabled"
|
|
713
|
+
* -- so its reasoning stays pass-through.
|
|
714
|
+
*/
|
|
715
|
+
function disabledProviderOptions(model) {
|
|
716
|
+
if (!model.reasoning) return {};
|
|
717
|
+
const key = optionsKey(model);
|
|
718
|
+
if (key === "anthropic" || key === "google-vertex-anthropic") return { [key]: { thinking: { type: "disabled" } } };
|
|
719
|
+
if (key === "google" || key === "google-vertex") {
|
|
720
|
+
if (model.thinkingLevelMap?.off === null) return {};
|
|
721
|
+
return { [key]: { thinkingConfig: googleDisabledThinkingConfig(model) } };
|
|
722
|
+
}
|
|
723
|
+
if (key === "openai" || key === "xai" || key === "openai-codex") {
|
|
724
|
+
const off = model.thinkingLevelMap?.off;
|
|
725
|
+
if (off === null) return {};
|
|
726
|
+
return { [key]: { reasoningEffort: off ?? "none" } };
|
|
727
|
+
}
|
|
728
|
+
return {};
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Gemini 3 Pro cannot disable thinking, and Gemini 3 Flash and Gemma 4 cannot
|
|
732
|
+
* fully disable it either. For those, ask for the lowest level and leave
|
|
733
|
+
* `includeThoughts` off so the thinking stays hidden. Gemini 2.x takes a zero budget.
|
|
734
|
+
*/
|
|
735
|
+
function googleDisabledThinkingConfig(model) {
|
|
736
|
+
if (model.compat?.supportsThinkingLevel) return { thinkingLevel: model.thinkingLevelMap?.off ?? "minimal" };
|
|
737
|
+
return { thinkingBudget: 0 };
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* The effort level an adaptive Claude model reasons at.
|
|
741
|
+
*
|
|
742
|
+
* A model's own `thinkingLevelMap` wins where it has an opinion -- that is where
|
|
743
|
+
* per-model support for `xhigh` and `max` is recorded -- and the rest collapse onto
|
|
744
|
+
* the three levels every adaptive model accepts.
|
|
745
|
+
*/
|
|
746
|
+
function anthropicEffort(model, level) {
|
|
747
|
+
const mapped = model.thinkingLevelMap?.[level];
|
|
748
|
+
if (typeof mapped === "string") return mapped;
|
|
749
|
+
switch (level) {
|
|
750
|
+
case "minimal":
|
|
751
|
+
case "low": return "low";
|
|
752
|
+
case "medium": return "medium";
|
|
753
|
+
case "xhigh": return "xhigh";
|
|
754
|
+
case "max": return "max";
|
|
755
|
+
default: return "high";
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
function reasoningProviderOptions(model, plan) {
|
|
759
|
+
const level = plan.level;
|
|
760
|
+
if (level === "off") return disabledProviderOptions(model);
|
|
761
|
+
const mapped = model.thinkingLevelMap?.[level] ?? level;
|
|
762
|
+
if (!mapped) return {};
|
|
763
|
+
const key = optionsKey(model);
|
|
764
|
+
const budget = plan.budget;
|
|
765
|
+
if (key === "openai" || key === "xai" || key === "openai-codex") return { [key]: { reasoningEffort: mapped } };
|
|
766
|
+
if (key === "openrouter") return { [key]: { reasoning: { effort: mapped === "off" ? "none" : mapped } } };
|
|
767
|
+
if (key === "google" || key === "google-vertex") {
|
|
768
|
+
const thinkingLevel = googleThinkingLevel(mapped);
|
|
769
|
+
if (model.compat?.supportsThinkingLevel) return { [key]: { thinkingConfig: {
|
|
770
|
+
thinkingLevel,
|
|
771
|
+
includeThoughts: true
|
|
772
|
+
} } };
|
|
773
|
+
return { [key]: { thinkingConfig: {
|
|
774
|
+
includeThoughts: true,
|
|
775
|
+
thinkingBudget: budget
|
|
776
|
+
} } };
|
|
777
|
+
}
|
|
778
|
+
if (key === "anthropic" || key === "google-vertex-anthropic") {
|
|
779
|
+
if (model.compat?.forceAdaptiveThinking) return { [key]: {
|
|
780
|
+
thinking: {
|
|
781
|
+
type: "adaptive",
|
|
782
|
+
display: "summarized"
|
|
783
|
+
},
|
|
784
|
+
effort: anthropicEffort(model, level)
|
|
785
|
+
} };
|
|
786
|
+
return { [key]: { thinking: {
|
|
787
|
+
type: "enabled",
|
|
788
|
+
budgetTokens: budget
|
|
789
|
+
} } };
|
|
790
|
+
}
|
|
791
|
+
return {};
|
|
792
|
+
}
|
|
793
|
+
//#endregion
|
|
840
794
|
//#region src/utils/jsonparse.ts
|
|
841
795
|
/**
|
|
842
796
|
* @description Helper function to parse partial jsons during LLM streaming.
|
|
@@ -1011,7 +965,7 @@ function toolResultOutput(toolCall) {
|
|
|
1011
965
|
const images = toolCall.result.content.filter((content) => content.type === "image");
|
|
1012
966
|
if (toolCall.result.isError) return {
|
|
1013
967
|
type: "error-text",
|
|
1014
|
-
value: text || "
|
|
968
|
+
value: text || "tool returned an error"
|
|
1015
969
|
};
|
|
1016
970
|
if (images.length === 0) return {
|
|
1017
971
|
type: "text",
|
|
@@ -1061,20 +1015,32 @@ function decodeOpenAIReasoningSignature(signature) {
|
|
|
1061
1015
|
itemId: parsed.itemId,
|
|
1062
1016
|
...typeof parsed.reasoningEncryptedContent === "string" || parsed.reasoningEncryptedContent === null ? { reasoningEncryptedContent: parsed.reasoningEncryptedContent } : {}
|
|
1063
1017
|
};
|
|
1064
|
-
} catch {
|
|
1065
|
-
|
|
1018
|
+
} catch {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
function googleThoughtSignature(metadata) {
|
|
1023
|
+
if (!isRecord(metadata)) return;
|
|
1024
|
+
for (const key of ["google", "google-vertex"]) {
|
|
1025
|
+
const provider = metadata[key];
|
|
1026
|
+
if (isRecord(provider) && typeof provider.thoughtSignature === "string") return provider.thoughtSignature;
|
|
1027
|
+
}
|
|
1066
1028
|
}
|
|
1067
1029
|
function assistantMessages(message, model) {
|
|
1068
1030
|
if (message.stopReason === "error" || message.stopReason === "aborted") return [];
|
|
1069
1031
|
const assistantContent = [];
|
|
1070
1032
|
const toolResults = [];
|
|
1033
|
+
const googleReplay = (model.protocol === "google" || model.protocol === "google-vertex") && message.protocol === model.protocol && message.provider.id === model.provider.id && message.model === model.id;
|
|
1034
|
+
const googleOptions = (signature) => googleReplay && signature ? { [optionsKey(model)]: { thoughtSignature: signature } } : void 0;
|
|
1071
1035
|
for (const part of message.parts) {
|
|
1036
|
+
const google = googleOptions(part.type === "text" ? part.textSignature : part.type === "thinking" ? part.thinkingSignature : part.type === "toolCall" ? part.thoughtSignature : void 0);
|
|
1072
1037
|
if (part.type === "text") {
|
|
1073
1038
|
const text = sanitizeSurrogates(part.text);
|
|
1074
1039
|
if (text.trim().length === 0) continue;
|
|
1075
1040
|
assistantContent.push({
|
|
1076
1041
|
type: "text",
|
|
1077
1042
|
text,
|
|
1043
|
+
...google ? { providerOptions: google } : {},
|
|
1078
1044
|
...part.textSignature && message.protocol === KnownProviderEnum.openaiCodex ? { providerOptions: { "openai-codex": { messageId: part.textSignature } } } : {}
|
|
1079
1045
|
});
|
|
1080
1046
|
continue;
|
|
@@ -1088,8 +1054,11 @@ function assistantMessages(message, model) {
|
|
|
1088
1054
|
};
|
|
1089
1055
|
if (message.protocol === KnownProviderEnum.openai) {
|
|
1090
1056
|
if (!part.thinkingSignature) continue;
|
|
1091
|
-
|
|
1092
|
-
|
|
1057
|
+
const openai = decodeOpenAIReasoningSignature(part.thinkingSignature);
|
|
1058
|
+
if (!openai) continue;
|
|
1059
|
+
reasoning.providerOptions = { openai };
|
|
1060
|
+
} else if (google) reasoning.providerOptions = google;
|
|
1061
|
+
else if (part.thinkingSignature && message.protocol !== "google" && message.protocol !== "google-vertex") reasoning.providerOptions = message.protocol === KnownProviderEnum.openaiCodex ? { "openai-codex": { reasoningItem: part.thinkingSignature } } : { anthropic: { signature: part.thinkingSignature } };
|
|
1093
1062
|
assistantContent.push(reasoning);
|
|
1094
1063
|
continue;
|
|
1095
1064
|
}
|
|
@@ -1102,6 +1071,7 @@ function assistantMessages(message, model) {
|
|
|
1102
1071
|
toolCallId: part.callID,
|
|
1103
1072
|
toolName: part.name,
|
|
1104
1073
|
input: sanitizeRecord(part.arguments ?? {}),
|
|
1074
|
+
...google ? { providerOptions: google } : {},
|
|
1105
1075
|
...Object.keys(codexToolMetadata).length > 0 ? { providerOptions: { "openai-codex": codexToolMetadata } } : {}
|
|
1106
1076
|
});
|
|
1107
1077
|
const terminal = part.status === "pending" || part.status === "running" ? void 0 : part;
|
|
@@ -1112,7 +1082,7 @@ function assistantMessages(message, model) {
|
|
|
1112
1082
|
...terminal?.addedToolNames?.length ? { providerOptions: { "openai-codex": { addedToolNames: terminal.addedToolNames } } } : {},
|
|
1113
1083
|
output: terminal ? toolResultOutput(terminal) : {
|
|
1114
1084
|
type: "error-text",
|
|
1115
|
-
value: "
|
|
1085
|
+
value: "no result provided"
|
|
1116
1086
|
}
|
|
1117
1087
|
});
|
|
1118
1088
|
}
|
|
@@ -1143,12 +1113,13 @@ function convertTools(tools, model) {
|
|
|
1143
1113
|
if (!tools || tools.length === 0) return;
|
|
1144
1114
|
const result = {};
|
|
1145
1115
|
for (const tool of tools) {
|
|
1146
|
-
const
|
|
1116
|
+
const jsonSchemaConstraint = resolveJsonSchemaConstraint(tool, model?.compat);
|
|
1117
|
+
const grammarConstraint = model?.protocol === KnownProviderEnum.openaiCodex ? resolveOpenAICodexToolConstraint(tool, model.compat) : void 0;
|
|
1147
1118
|
result[tool.name] = {
|
|
1148
1119
|
description: tool.description,
|
|
1149
1120
|
inputSchema: jsonSchema(tool.parameters),
|
|
1150
|
-
...
|
|
1151
|
-
...
|
|
1121
|
+
...jsonSchemaConstraint ? { strict: true } : {},
|
|
1122
|
+
...grammarConstraint?.type === "grammar" ? { providerOptions: { "openai-codex": { grammar: grammarConstraint } } } : {}
|
|
1152
1123
|
};
|
|
1153
1124
|
}
|
|
1154
1125
|
return result;
|
|
@@ -1163,9 +1134,10 @@ function mapFinishReason(reason) {
|
|
|
1163
1134
|
default: return "stop";
|
|
1164
1135
|
}
|
|
1165
1136
|
}
|
|
1166
|
-
function mapUsage(usage, model, costMultiplier = 1) {
|
|
1137
|
+
function mapUsage(usage, model, costMultiplier = 1, providerMetadata) {
|
|
1167
1138
|
const cacheRead = usage?.inputTokenDetails.cacheReadTokens ?? 0;
|
|
1168
1139
|
const cacheWrite = usage?.inputTokenDetails?.cacheWriteTokens ?? 0;
|
|
1140
|
+
const cacheWrite1h = cacheWrite1hTokens(providerMetadata);
|
|
1169
1141
|
const input = usage?.inputTokenDetails?.noCacheTokens ?? Math.max((usage?.inputTokens ?? 0) - cacheRead - cacheWrite, 0);
|
|
1170
1142
|
const output = usage?.outputTokens ?? 0;
|
|
1171
1143
|
const totalTokens = usage?.totalTokens ?? input + cacheRead + cacheWrite + output;
|
|
@@ -1174,6 +1146,7 @@ function mapUsage(usage, model, costMultiplier = 1) {
|
|
|
1174
1146
|
output,
|
|
1175
1147
|
cacheRead,
|
|
1176
1148
|
cacheWrite,
|
|
1149
|
+
...cacheWrite1h === void 0 ? {} : { cacheWrite1h },
|
|
1177
1150
|
...usage?.outputTokenDetails?.reasoningTokens !== void 0 ? { reasoning: usage.outputTokenDetails.reasoningTokens } : {},
|
|
1178
1151
|
totalTokens,
|
|
1179
1152
|
cost: {
|
|
@@ -1214,9 +1187,6 @@ function updateToolCallFromInput(block, partialJson) {
|
|
|
1214
1187
|
}
|
|
1215
1188
|
//#endregion
|
|
1216
1189
|
//#region src/llm/stream.ts
|
|
1217
|
-
function providerOptionsKey(model) {
|
|
1218
|
-
return model.providerOptionsKey ?? model.protocol;
|
|
1219
|
-
}
|
|
1220
1190
|
function mergeProviderOptions(...sources) {
|
|
1221
1191
|
const result = {};
|
|
1222
1192
|
for (const source of sources) {
|
|
@@ -1238,7 +1208,7 @@ function configuredCacheRetention(options) {
|
|
|
1238
1208
|
}
|
|
1239
1209
|
function cacheProviderOptions(model, options) {
|
|
1240
1210
|
const retention = configuredCacheRetention(options);
|
|
1241
|
-
const key =
|
|
1211
|
+
const key = optionsKey(model);
|
|
1242
1212
|
if (retention === "none") return {};
|
|
1243
1213
|
if (key === "openai") {
|
|
1244
1214
|
const openai = {};
|
|
@@ -1247,58 +1217,14 @@ function cacheProviderOptions(model, options) {
|
|
|
1247
1217
|
if (retention === "long") openai.promptCacheRetention = "24h";
|
|
1248
1218
|
return Object.keys(openai).length > 0 ? { [key]: openai } : {};
|
|
1249
1219
|
}
|
|
1250
|
-
if (key === "openai-codex" && options.sessionId) return { [key]: { promptCacheKey: options.sessionId } };
|
|
1251
1220
|
if ((key === "anthropic" || key === "google-vertex-anthropic") && retention) return { [key]: { cacheControl: {
|
|
1252
1221
|
type: "ephemeral",
|
|
1253
1222
|
...retention === "long" ? { ttl: "1h" } : {}
|
|
1254
1223
|
} } };
|
|
1255
1224
|
return {};
|
|
1256
1225
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
low: .1,
|
|
1260
|
-
medium: .25,
|
|
1261
|
-
high: .5,
|
|
1262
|
-
xhigh: .8,
|
|
1263
|
-
max: .95
|
|
1264
|
-
};
|
|
1265
|
-
const MIN_THINKING_BUDGET = 1024;
|
|
1266
|
-
function resolveThinkingBudget(model, options, level) {
|
|
1267
|
-
const explicit = options.thinkingBudgets?.[level];
|
|
1268
|
-
if (explicit !== void 0) return explicit;
|
|
1269
|
-
const key = providerOptionsKey(model);
|
|
1270
|
-
if (key === "anthropic" || key === "google-vertex-anthropic") {
|
|
1271
|
-
const fraction = DEFAULT_THINKING_BUDGET_FRACTIONS[level];
|
|
1272
|
-
return Math.max(Math.floor(model.maxTokens * fraction), MIN_THINKING_BUDGET);
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
function reasoningProviderOptions(model, options) {
|
|
1276
|
-
const requestedLevel = options.reasoning;
|
|
1277
|
-
if (!requestedLevel) return {};
|
|
1278
|
-
const level = clampThinkingLevel(model, requestedLevel);
|
|
1279
|
-
if (level === "off") return {};
|
|
1280
|
-
const mapped = model.thinkingLevelMap?.[level] ?? level;
|
|
1281
|
-
if (!mapped) return {};
|
|
1282
|
-
const key = providerOptionsKey(model);
|
|
1283
|
-
const budget = resolveThinkingBudget(model, options, level);
|
|
1284
|
-
if (key === "openai" || key === "xai" || key === "openai-codex") return { [key]: { reasoningEffort: mapped } };
|
|
1285
|
-
if (key === "openrouter") return { [key]: { reasoning: { effort: mapped === "off" ? "none" : mapped } } };
|
|
1286
|
-
if (key === "google" || key === "google-vertex") {
|
|
1287
|
-
const thinkingLevel = mapped === "xhigh" ? "high" : mapped;
|
|
1288
|
-
return { [key]: { thinkingConfig: {
|
|
1289
|
-
thinkingLevel,
|
|
1290
|
-
includeThoughts: true,
|
|
1291
|
-
...budget !== void 0 ? { thinkingBudget: budget } : {}
|
|
1292
|
-
} } };
|
|
1293
|
-
}
|
|
1294
|
-
if (key === "anthropic" || key === "google-vertex-anthropic") return { [key]: { thinking: {
|
|
1295
|
-
type: "enabled",
|
|
1296
|
-
budgetTokens: budget ?? MIN_THINKING_BUDGET
|
|
1297
|
-
} } };
|
|
1298
|
-
return {};
|
|
1299
|
-
}
|
|
1300
|
-
function resolveProviderOptions(model, options) {
|
|
1301
|
-
return mergeProviderOptions(model.providerOptions, cacheProviderOptions(model, options), reasoningProviderOptions(model, options), options.providerOptions);
|
|
1226
|
+
function resolveProviderOptions(model, options, plan) {
|
|
1227
|
+
return mergeProviderOptions(model.providerOptions, cacheProviderOptions(model, options), reasoningProviderOptions(model, plan), options.providerOptions);
|
|
1302
1228
|
}
|
|
1303
1229
|
function partIndex(output, block) {
|
|
1304
1230
|
return output.parts.indexOf(block);
|
|
@@ -1410,6 +1336,8 @@ function finalizeToolCall(output, part, stream) {
|
|
|
1410
1336
|
block.name = part.toolName;
|
|
1411
1337
|
block.arguments = typeof part.input === "object" && part.input !== null ? part.input : {};
|
|
1412
1338
|
const namespace = openAICodexMetadata(part.providerMetadata)?.namespace;
|
|
1339
|
+
const thoughtSignature = googleThoughtSignature(part.providerMetadata);
|
|
1340
|
+
if (thoughtSignature) block.thoughtSignature = thoughtSignature;
|
|
1413
1341
|
if (typeof namespace === "string") block.namespace = namespace;
|
|
1414
1342
|
block.time.end = Date.now();
|
|
1415
1343
|
delete block.partialJson;
|
|
@@ -1422,13 +1350,15 @@ function finalizeToolCall(output, part, stream) {
|
|
|
1422
1350
|
partial: output
|
|
1423
1351
|
});
|
|
1424
1352
|
}
|
|
1425
|
-
function handlePart(part, output, model, stream,
|
|
1353
|
+
function handlePart(part, output, model, stream, pricing) {
|
|
1426
1354
|
switch (part.type) {
|
|
1427
1355
|
case "text-start":
|
|
1428
1356
|
ensureTextBlock(output, part.id, stream);
|
|
1429
1357
|
break;
|
|
1430
1358
|
case "text-delta": {
|
|
1431
1359
|
const block = ensureTextBlock(output, part.id, stream);
|
|
1360
|
+
const signature = googleThoughtSignature(part.providerMetadata);
|
|
1361
|
+
if (signature) block.textSignature = signature;
|
|
1432
1362
|
block.text += part.text;
|
|
1433
1363
|
stream.push({
|
|
1434
1364
|
type: "text.delta",
|
|
@@ -1449,7 +1379,7 @@ function handlePart(part, output, model, stream, costMultiplier) {
|
|
|
1449
1379
|
case "reasoning-delta": {
|
|
1450
1380
|
const block = ensureThinkingBlock(output, part.id, stream);
|
|
1451
1381
|
block.thinking += part.text;
|
|
1452
|
-
const sig = (part.providerMetadata?.anthropic)?.signature ?? (part.providerMetadata?.["google-vertex-anthropic"])?.signature;
|
|
1382
|
+
const sig = (part.providerMetadata?.anthropic)?.signature ?? (part.providerMetadata?.["google-vertex-anthropic"])?.signature ?? googleThoughtSignature(part.providerMetadata);
|
|
1453
1383
|
if (typeof sig === "string") block.thinkingSignature = sig;
|
|
1454
1384
|
stream.push({
|
|
1455
1385
|
type: "thinking.delta",
|
|
@@ -1488,11 +1418,12 @@ function handlePart(part, output, model, stream, costMultiplier) {
|
|
|
1488
1418
|
case "finish-step":
|
|
1489
1419
|
output.responseId ||= part.response.id;
|
|
1490
1420
|
if (part.response.modelId && part.response.modelId !== model.id) output.responseModel ||= part.response.modelId;
|
|
1491
|
-
|
|
1421
|
+
pricing.providerMetadata = part.providerMetadata ?? pricing.providerMetadata;
|
|
1422
|
+
output.usage = mapUsage(part.usage, model, resolvePricing(model, pricing), pricing.providerMetadata);
|
|
1492
1423
|
output.stopReason = mapFinishReason(part.finishReason);
|
|
1493
1424
|
break;
|
|
1494
1425
|
case "finish":
|
|
1495
|
-
output.usage = mapUsage(part.totalUsage, model,
|
|
1426
|
+
output.usage = mapUsage(part.totalUsage, model, resolvePricing(model, pricing), pricing.providerMetadata);
|
|
1496
1427
|
output.stopReason = mapFinishReason(part.finishReason);
|
|
1497
1428
|
break;
|
|
1498
1429
|
case "abort":
|
|
@@ -1502,30 +1433,29 @@ function handlePart(part, output, model, stream, costMultiplier) {
|
|
|
1502
1433
|
case "error": throw part.error instanceof Error ? part.error : new Error(formatThrownError(part.error));
|
|
1503
1434
|
}
|
|
1504
1435
|
}
|
|
1505
|
-
function
|
|
1506
|
-
|
|
1507
|
-
const providerTier = providerOptions["openai-codex"]?.serviceTier;
|
|
1508
|
-
const factoryTier = options.factoryOptions?.serviceTier;
|
|
1509
|
-
const modelTier = model.options?.serviceTier;
|
|
1510
|
-
const serviceTier = providerTier ?? factoryTier ?? modelTier;
|
|
1511
|
-
if (serviceTier === "flex") return .5;
|
|
1512
|
-
if (serviceTier === "priority") return model.id === "gpt-5.5" ? 2.5 : 2;
|
|
1513
|
-
return 1;
|
|
1436
|
+
function resolvePricing(model, pricing) {
|
|
1437
|
+
return serviceTierCostMultiplier(model, servedServiceTier(model, pricing.requestedServiceTier, pricing.providerMetadata));
|
|
1514
1438
|
}
|
|
1515
1439
|
/**
|
|
1516
|
-
*
|
|
1517
|
-
*
|
|
1440
|
+
* The response ceiling to send, already fitted around the thinking budget by
|
|
1441
|
+
* {@link Thinking.resolvePlan}.
|
|
1442
|
+
*
|
|
1443
|
+
* `plan.maxTokens` is the whole response -- thinking and answer together, which is
|
|
1444
|
+
* what Anthropic's own `max_tokens` means. But `@ai-sdk/anthropic` treats
|
|
1445
|
+
* `maxOutputTokens` as the answer alone and adds the budget back on before sending
|
|
1446
|
+
* (`baseArgs.max_tokens = maxTokens + thinkingBudget`). Handing it the total there
|
|
1447
|
+
* would ask for the budget twice, so it gets the answer room and reconstructs the
|
|
1448
|
+
* total itself.
|
|
1449
|
+
*
|
|
1450
|
+
* That only applies when a budget is actually sent. An adaptive model is given an
|
|
1451
|
+
* effort level and no budget, so the SDK adds nothing and the total goes through
|
|
1452
|
+
* unchanged -- subtracting there would quietly under-ask by the whole budget.
|
|
1518
1453
|
*/
|
|
1519
|
-
function resolveMaxOutputTokens(model,
|
|
1520
|
-
const
|
|
1521
|
-
if (maxTokens === void 0) return void 0;
|
|
1522
|
-
const key = providerOptionsKey(model);
|
|
1454
|
+
function resolveMaxOutputTokens(model, plan) {
|
|
1455
|
+
const key = optionsKey(model);
|
|
1523
1456
|
if (key === "openai-codex") return void 0;
|
|
1524
|
-
if (
|
|
1525
|
-
|
|
1526
|
-
if (budgetTokens > 0 && maxTokens + budgetTokens > model.maxTokens) return Math.max(model.maxTokens - budgetTokens, 1);
|
|
1527
|
-
}
|
|
1528
|
-
return maxTokens;
|
|
1457
|
+
if (plan.maxTokens === void 0) return void 0;
|
|
1458
|
+
return (key === "anthropic" || key === "google-vertex-anthropic") && !model.compat?.forceAdaptiveThinking ? plan.maxTokens - plan.budget : plan.maxTokens;
|
|
1529
1459
|
}
|
|
1530
1460
|
const stream$1 = (model, context, options) => {
|
|
1531
1461
|
const stream = new AssistantMessageEventStream();
|
|
@@ -1533,11 +1463,12 @@ const stream$1 = (model, context, options) => {
|
|
|
1533
1463
|
(async () => {
|
|
1534
1464
|
const output = createAssistantMessage(model);
|
|
1535
1465
|
try {
|
|
1536
|
-
const
|
|
1466
|
+
const plan = resolvePlan(model, context, runtimeOptions);
|
|
1467
|
+
const languageModel = await resolveAISDKLanguageModel(model, runtimeOptions, plan.budget);
|
|
1537
1468
|
const tools = convertTools(context.tools, model);
|
|
1538
1469
|
const messages = convertMessages(context, model);
|
|
1539
|
-
const providerOptions = resolveProviderOptions(model, runtimeOptions);
|
|
1540
|
-
const
|
|
1470
|
+
const providerOptions = resolveProviderOptions(model, runtimeOptions, plan);
|
|
1471
|
+
const pricing = { requestedServiceTier: requestedServiceTier(model, runtimeOptions, providerOptions) };
|
|
1541
1472
|
const activeTools = runtimeOptions.activeTools?.filter((name) => !tools || name in tools);
|
|
1542
1473
|
let params = compact({
|
|
1543
1474
|
model: languageModel,
|
|
@@ -1546,7 +1477,7 @@ const stream$1 = (model, context, options) => {
|
|
|
1546
1477
|
tools,
|
|
1547
1478
|
toolChoice: runtimeOptions.toolChoice,
|
|
1548
1479
|
activeTools,
|
|
1549
|
-
maxOutputTokens: resolveMaxOutputTokens(model,
|
|
1480
|
+
maxOutputTokens: resolveMaxOutputTokens(model, plan),
|
|
1550
1481
|
temperature: runtimeOptions.temperature,
|
|
1551
1482
|
providerOptions,
|
|
1552
1483
|
abortSignal: runtimeOptions.signal,
|
|
@@ -1562,9 +1493,9 @@ const stream$1 = (model, context, options) => {
|
|
|
1562
1493
|
type: "start",
|
|
1563
1494
|
partial: output
|
|
1564
1495
|
});
|
|
1565
|
-
for await (const part of result.fullStream) handlePart(part, output, model, stream,
|
|
1566
|
-
if (runtimeOptions.signal?.aborted || output.stopReason === "aborted") throw new Error(output.errorMessage || "
|
|
1567
|
-
if (output.stopReason === "error") throw new Error(output.errorMessage || "
|
|
1496
|
+
for await (const part of result.fullStream) handlePart(part, output, model, stream, pricing);
|
|
1497
|
+
if (runtimeOptions.signal?.aborted || output.stopReason === "aborted") throw new Error(output.errorMessage || "request was aborted");
|
|
1498
|
+
if (output.stopReason === "error") throw new Error(output.errorMessage || "provider returned an error stop reason");
|
|
1568
1499
|
output.time.completed = Date.now();
|
|
1569
1500
|
stream.push({
|
|
1570
1501
|
type: "done",
|
|
@@ -1675,7 +1606,7 @@ function validateSchema(schema, value, label) {
|
|
|
1675
1606
|
*/
|
|
1676
1607
|
function validateToolCall(tools, toolExecution) {
|
|
1677
1608
|
const tool = tools.find((t) => t.name === toolExecution.name);
|
|
1678
|
-
if (!tool) throw new Error(`
|
|
1609
|
+
if (!tool) throw new Error(`tool "${toolExecution.name}" not found`);
|
|
1679
1610
|
return validateToolArguments(tool, toolExecution);
|
|
1680
1611
|
}
|
|
1681
1612
|
/**
|