@codeworksh/aikit 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +73 -81
  2. package/{agent → dist/pack/agent}/codemode/drivers/drivers.d.mts +1 -1
  3. package/dist/pack/codemode-BEDXG7WN.d.mts +8736 -0
  4. package/{index.d.mts → dist/pack/index.d.mts} +1 -1
  5. package/dist/pack/index.mjs +8226 -0
  6. package/dist/pack/index.mjs.map +1 -0
  7. package/package.json +31 -24
  8. package/src/agent/agent.ts +790 -0
  9. package/src/agent/codemode/codemode.ts +561 -0
  10. package/src/agent/codemode/drivers/drivers.ts +1 -0
  11. package/src/agent/codemode/drivers/quickjs-wasi-driver.ts +149 -0
  12. package/src/agent/codemode/index.ts +1 -0
  13. package/src/agent/loop.ts +903 -0
  14. package/src/agent.ts +11 -0
  15. package/src/event/event.ts +277 -0
  16. package/src/index.ts +6 -0
  17. package/src/llm.ts +31 -0
  18. package/src/message/message.ts +311 -0
  19. package/src/model/catalog.ts +94 -0
  20. package/src/model/model.ts +250 -0
  21. package/src/model/transform.ts +59 -0
  22. package/src/provider/provider.ts +60 -0
  23. package/src/provider/providers/anthropic/index.ts +792 -0
  24. package/src/provider/providers/github/github.ts +34 -0
  25. package/src/provider/providers/openai/completions.ts +953 -0
  26. package/src/provider/providers/utils.ts +7 -0
  27. package/src/provider/register.ts +6 -0
  28. package/src/provider/stream.ts +278 -0
  29. package/src/stream.ts +72 -0
  30. package/src/utils/eventstream.ts +95 -0
  31. package/src/utils/helpers.ts +24 -0
  32. package/src/utils/jsonparse.ts +32 -0
  33. package/src/utils/overflow.ts +121 -0
  34. package/src/utils/sanitize.ts +25 -0
  35. package/src/utils/validation.ts +87 -0
  36. package/LICENSE +0 -21
  37. package/codemode-SiETGR3z.d.mts +0 -8410
  38. package/index.mjs +0 -3381
  39. package/index.mjs.map +0 -1
  40. /package/{agent → dist/pack/agent}/codemode/drivers/drivers.mjs +0 -0
  41. /package/{agent → dist/pack/agent}/codemode/drivers/drivers.mjs.map +0 -0
package/index.mjs DELETED
@@ -1,3381 +0,0 @@
1
- import { Filesystem, NamedError, lazy } from "@codeworksh/utils";
2
- import { Type, TypeGuard } from "@sinclair/typebox";
3
- import { capitalize, keys, mapValues, pick, pipe } from "remeda";
4
- import Ajv from "ajv";
5
- import addFormats from "ajv-formats";
6
- import { uuidv7 } from "uuidv7";
7
- import Anthropic from "@anthropic-ai/sdk";
8
- import { parse } from "partial-json";
9
- import OpenAI from "openai";
10
- import { transform } from "esbuild";
11
- //#region src/provider/provider.ts
12
- let Provider;
13
- (function(_Provider) {
14
- const KnownProviderEnum = _Provider.KnownProviderEnum = {
15
- anthropic: "anthropic",
16
- openai: "openai",
17
- githubCopilot: "github-copilot",
18
- openrouter: "openrouter",
19
- groq: "groq",
20
- xai: "xai",
21
- cerebras: "cerebras",
22
- zai: "zai",
23
- opencode: "opencode"
24
- };
25
- const KnownProviderSchema = _Provider.KnownProviderSchema = Type.Union([
26
- Type.Literal(KnownProviderEnum.anthropic),
27
- Type.Literal(KnownProviderEnum.openai),
28
- Type.Literal(KnownProviderEnum.githubCopilot),
29
- Type.Literal(KnownProviderEnum.openrouter),
30
- Type.Literal(KnownProviderEnum.groq),
31
- Type.Literal(KnownProviderEnum.xai),
32
- Type.Literal(KnownProviderEnum.cerebras),
33
- Type.Literal(KnownProviderEnum.zai),
34
- Type.Literal(KnownProviderEnum.opencode)
35
- ]);
36
- _Provider.Info = Type.Object({
37
- id: KnownProviderSchema,
38
- name: Type.String(),
39
- env: Type.Array(Type.String()),
40
- key: Type.Optional(Type.String()),
41
- options: Type.Optional(Type.Record(Type.String(), Type.Any()))
42
- });
43
- _Provider.ReasoningEffortMapSchema = Type.Object({
44
- minimal: Type.Optional(Type.String()),
45
- low: Type.Optional(Type.String()),
46
- medium: Type.Optional(Type.String()),
47
- high: Type.Optional(Type.String()),
48
- xhigh: Type.Optional(Type.String())
49
- });
50
- _Provider.OpenRouterRoutingSchema = Type.Object({
51
- only: Type.Optional(Type.Array(Type.String())),
52
- order: Type.Optional(Type.Array(Type.String()))
53
- });
54
- _Provider.VercelGatewayRoutingSchema = Type.Object({
55
- only: Type.Optional(Type.Array(Type.String())),
56
- order: Type.Optional(Type.Array(Type.String()))
57
- });
58
- })(Provider || (Provider = {}));
59
- //#endregion
60
- //#region src/model/catalog.ts
61
- let ModelCatalog;
62
- (function(_ModelCatalog) {
63
- function modelsDevURL() {
64
- return process.env.OPENCODE_MODELS_URL || "https://models.dev";
65
- }
66
- function modelsDevPath() {
67
- return process.env.CODEWORK_AIKIT_MODELS_PATH;
68
- }
69
- const modelsDevData = _ModelCatalog.modelsDevData = lazy(async () => {
70
- const path = modelsDevPath();
71
- if (path) {
72
- const result = await Filesystem.readJson(path).catch(() => void 0);
73
- if (result) return result;
74
- }
75
- const json = await fetch(`${modelsDevURL()}/api.json`).then((x) => x.text());
76
- return JSON.parse(json);
77
- });
78
- async function get() {
79
- return modelsDevData();
80
- }
81
- _ModelCatalog.get = get;
82
- async function refresh() {
83
- const result = await fetch(`${modelsDevURL()}/api.json`, { signal: AbortSignal.timeout(10 * 1e3) }).catch(() => void 0);
84
- if (!result?.ok) return;
85
- const json = await result.text();
86
- const path = modelsDevPath();
87
- if (path) await Filesystem.write(path, json);
88
- modelsDevData.reset();
89
- }
90
- _ModelCatalog.refresh = refresh;
91
- ModelCatalog.refresh();
92
- setInterval(async () => {
93
- await ModelCatalog.refresh();
94
- }, 60 * 1e3 * 60).unref();
95
- })(ModelCatalog || (ModelCatalog = {}));
96
- //#endregion
97
- //#region src/model/transform.ts
98
- function defaultBaseUrl(providerId) {
99
- switch (providerId) {
100
- case Provider.KnownProviderEnum.openai: return "https://api.openai.com/v1";
101
- default: return;
102
- }
103
- }
104
- function resolveDefaultProtocol(providerId) {
105
- switch (providerId) {
106
- case Provider.KnownProviderEnum.anthropic: return Model.KnownProtocolEnum.anthropicMessages;
107
- case Provider.KnownProviderEnum.openai: return Model.KnownProtocolEnum.openaiResponses;
108
- default: return Model.KnownProtocolEnum.openaiCompletions;
109
- }
110
- }
111
- function applyModification(providerId, provider, model) {
112
- const baseUrl = model.baseUrl ?? provider.baseUrl ?? provider.api ?? defaultBaseUrl(providerId);
113
- const normalized = {
114
- id: model.id,
115
- name: model.name,
116
- provider: Model.toProviderInfo(providerId, provider),
117
- baseUrl,
118
- reasoning: Boolean(model.reasoning),
119
- input: Model.normalizeInput(model.modalities.input),
120
- cost: {
121
- input: model.cost?.input ?? 0,
122
- output: model.cost?.output ?? 0,
123
- cacheRead: model.cost?.cache_read ?? 0,
124
- cacheWrite: model.cost?.cache_write ?? 0
125
- },
126
- contextWindow: model.limit?.context ?? 0,
127
- maxTokens: model.limit?.output ?? 0,
128
- headers: model.headers ?? provider.headers,
129
- protocol: resolveDefaultProtocol(providerId)
130
- };
131
- if (providerId === Provider.KnownProviderEnum.openai) {
132
- normalized.supportedProtocols = { openaiCompletions: Model.KnownProtocolEnum.openaiCompletions };
133
- return normalized;
134
- } else return normalized;
135
- }
136
- //#endregion
137
- //#region src/model/model.ts
138
- let Model;
139
- (function(_Model) {
140
- const KnownProtocolEnum = _Model.KnownProtocolEnum = {
141
- anthropicMessages: "anthropic-messages",
142
- openaiCompletions: "openai-completions",
143
- openaiResponses: "openai-responses"
144
- };
145
- _Model.KnownProtocolSchema = Type.Union([
146
- Type.Literal(KnownProtocolEnum.anthropicMessages),
147
- Type.Literal(KnownProtocolEnum.openaiCompletions),
148
- Type.Literal(KnownProtocolEnum.openaiResponses)
149
- ]);
150
- const InputSchema = Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]));
151
- const CostSchema = Type.Object({
152
- input: Type.Number(),
153
- output: Type.Number(),
154
- cacheRead: Type.Number(),
155
- cacheWrite: Type.Number()
156
- });
157
- const HeadersSchema = Type.Optional(Type.Record(Type.String(), Type.String()));
158
- const SupportedProtocolsSchema = _Model.SupportedProtocolsSchema = Type.Object({
159
- anthropicMessages: Type.Optional(Type.Literal(KnownProtocolEnum.anthropicMessages)),
160
- openaiCompletions: Type.Optional(Type.Literal(KnownProtocolEnum.openaiCompletions)),
161
- openaiResponses: Type.Optional(Type.Literal(KnownProtocolEnum.openaiResponses))
162
- });
163
- const BaseSchema = _Model.BaseSchema = Type.Object({
164
- id: Type.String(),
165
- name: Type.String(),
166
- provider: Provider.Info,
167
- baseUrl: Type.String(),
168
- reasoning: Type.Boolean(),
169
- input: InputSchema,
170
- cost: CostSchema,
171
- contextWindow: Type.Number(),
172
- maxTokens: Type.Number(),
173
- headers: HeadersSchema,
174
- supportedProtocols: Type.Optional(Type.Partial(SupportedProtocolsSchema))
175
- });
176
- const OpenAICompletionsCompatSchema = _Model.OpenAICompletionsCompatSchema = Type.Object({
177
- supportsStore: Type.Optional(Type.Boolean()),
178
- supportsDeveloperRole: Type.Optional(Type.Boolean()),
179
- supportsReasoningEffort: Type.Optional(Type.Boolean()),
180
- reasoningEffortMap: Type.Optional(Provider.ReasoningEffortMapSchema),
181
- supportsUsageInStreaming: Type.Optional(Type.Boolean()),
182
- maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
183
- requiresToolResultName: Type.Optional(Type.Boolean()),
184
- requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
185
- requiresThinkingAsText: Type.Optional(Type.Boolean()),
186
- thinkingFormat: Type.Optional(Type.Union([
187
- Type.Literal("openai"),
188
- Type.Literal("openrouter"),
189
- Type.Literal("zai"),
190
- Type.Literal("qwen"),
191
- Type.Literal("qwen-chat-template")
192
- ])),
193
- openRouterRouting: Type.Optional(Provider.OpenRouterRoutingSchema),
194
- vercelGatewayRouting: Type.Optional(Provider.VercelGatewayRoutingSchema),
195
- zaiToolStream: Type.Optional(Type.Boolean()),
196
- supportsStrictMode: Type.Optional(Type.Boolean())
197
- });
198
- const OpenAIResponsesCompatSchema = _Model.OpenAIResponsesCompatSchema = Type.Object({});
199
- _Model.OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
200
- const AnthropicSchema = _Model.AnthropicSchema = Type.Composite([BaseSchema, Type.Object({ protocol: Type.Literal(KnownProtocolEnum.anthropicMessages) })]);
201
- const OpenAICompletionsSchema = _Model.OpenAICompletionsSchema = Type.Composite([BaseSchema, Type.Object({
202
- protocol: Type.Literal(KnownProtocolEnum.openaiCompletions),
203
- compat: Type.Optional(OpenAICompletionsCompatSchema)
204
- })]);
205
- const OpenAIResponsesSchema = _Model.OpenAIResponsesSchema = Type.Composite([BaseSchema, Type.Object({
206
- protocol: Type.Literal(KnownProtocolEnum.openaiResponses),
207
- compat: Type.Optional(OpenAIResponsesCompatSchema)
208
- })]);
209
- _Model.Info = Type.Union([
210
- AnthropicSchema,
211
- OpenAICompletionsSchema,
212
- OpenAIResponsesSchema
213
- ]);
214
- const BUILTINS = keys(Provider.KnownProviderEnum);
215
- function calculateCost(model, usage) {
216
- usage.cost.input = usage.input / 1e6 * model.cost.input;
217
- usage.cost.output = usage.output / 1e6 * model.cost.output;
218
- usage.cost.cacheRead = usage.cacheRead / 1e6 * model.cost.cacheRead;
219
- usage.cost.cacheWrite = usage.cacheWrite / 1e6 * model.cost.cacheWrite;
220
- usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
221
- }
222
- _Model.calculateCost = calculateCost;
223
- function normalizeInput(input) {
224
- const normalized = /* @__PURE__ */ new Set();
225
- for (const modality of input ?? ["text"]) if (modality === "text" || modality === "image") normalized.add(modality);
226
- if (normalized.size === 0) normalized.add("text");
227
- return [...normalized];
228
- }
229
- _Model.normalizeInput = normalizeInput;
230
- function toProviderInfo(providerId, provider) {
231
- return {
232
- id: providerId,
233
- name: provider.name,
234
- env: provider.env,
235
- key: provider.key,
236
- options: provider.headers
237
- };
238
- }
239
- _Model.toProviderInfo = toProviderInfo;
240
- function toModelValue(providerId, provider, model) {
241
- return applyModification(providerId, provider, model);
242
- }
243
- async function getBuiltInModels() {
244
- return pipe(await ModelCatalog.get(), pick(BUILTINS), mapValues((provider, providerId) => mapValues(provider.models, (model) => toModelValue(providerId, provider, model))));
245
- }
246
- _Model.getBuiltInModels = getBuiltInModels;
247
- const registry = _Model.registry = lazy(async () => {
248
- const registry = /* @__PURE__ */ new Map();
249
- const models = await getBuiltInModels();
250
- for (const [provider, value] of Object.entries(models)) {
251
- const providerModels = /* @__PURE__ */ new Map();
252
- for (const [id, model] of Object.entries(value)) providerModels.set(id, model);
253
- registry.set(provider, providerModels);
254
- }
255
- return registry;
256
- });
257
- async function getModel(provider, model, overrides) {
258
- const result = (await registry()).get(provider)?.get(model);
259
- if (result && overrides) return {
260
- ...result,
261
- ...overrides
262
- };
263
- return result;
264
- }
265
- _Model.getModel = getModel;
266
- async function getProviders() {
267
- const data = await registry();
268
- return Array.from(data.keys());
269
- }
270
- _Model.getProviders = getProviders;
271
- async function getModels(provider) {
272
- const models = (await registry()).get(provider);
273
- return models ? Array.from(models.values()) : [];
274
- }
275
- _Model.getModels = getModels;
276
- function isGpt5OrLater(modelID) {
277
- const match = /^gpt-(\d+)/.exec(modelID);
278
- if (!match) return false;
279
- return Number(match[1]) >= 5;
280
- }
281
- function supportsXhigh(model) {
282
- return isGpt5OrLater(model.id);
283
- }
284
- _Model.supportsXhigh = supportsXhigh;
285
- function modelsAreEqual(a, b) {
286
- if (!a || !b) return false;
287
- return a.id === b.id && a.provider.id === b.provider.id;
288
- }
289
- _Model.modelsAreEqual = modelsAreEqual;
290
- })(Model || (Model = {}));
291
- //#endregion
292
- //#region src/provider/stream.ts
293
- let Stream;
294
- (function(_Stream) {
295
- const ProtocolProviderNotFoundError = _Stream.ProtocolProviderNotFoundError = NamedError.create("ProtocolProviderNotFoundError", Type.Object({ protocol: Model.KnownProtocolSchema }));
296
- const ProtocolMismatchError = _Stream.ProtocolMismatchError = NamedError.create("ProtocolMismatchError", Type.Object({
297
- actual: Model.KnownProtocolSchema,
298
- expected: Model.KnownProtocolSchema
299
- }));
300
- const ThinkingLevelEnum = _Stream.ThinkingLevelEnum = {
301
- off: "off",
302
- minimal: "minimal",
303
- low: "low",
304
- medium: "medium",
305
- high: "high",
306
- xhigh: "xhigh"
307
- };
308
- const ThinkingLevelSchema = _Stream.ThinkingLevelSchema = Type.Union([
309
- Type.Literal(ThinkingLevelEnum.off),
310
- Type.Literal(ThinkingLevelEnum.minimal),
311
- Type.Literal(ThinkingLevelEnum.low),
312
- Type.Literal(ThinkingLevelEnum.medium),
313
- Type.Literal(ThinkingLevelEnum.high),
314
- Type.Literal(ThinkingLevelEnum.xhigh)
315
- ]);
316
- const ThinkingBudgetsSchema = _Stream.ThinkingBudgetsSchema = Type.Object({
317
- off: Type.Optional(Type.Number()),
318
- minimal: Type.Optional(Type.Number()),
319
- low: Type.Optional(Type.Number()),
320
- medium: Type.Optional(Type.Number()),
321
- high: Type.Optional(Type.Number())
322
- });
323
- const CacheRetentionSchema = _Stream.CacheRetentionSchema = Type.Union([
324
- Type.Literal("none"),
325
- Type.Literal("short"),
326
- Type.Literal("long")
327
- ]);
328
- const TransportSchema = _Stream.TransportSchema = Type.Union([
329
- Type.Literal("sse"),
330
- Type.Literal("websocket"),
331
- Type.Literal("auto")
332
- ]);
333
- const OptionsSchema = _Stream.OptionsSchema = Type.Object({
334
- temperature: Type.Optional(Type.Number()),
335
- maxTokens: Type.Optional(Type.Number()),
336
- signal: Type.Optional(Type.Unsafe()),
337
- apiKey: Type.Optional(Type.String()),
338
- transport: Type.Optional(TransportSchema),
339
- cacheRetention: Type.Optional(CacheRetentionSchema),
340
- sessionId: Type.Optional(Type.String()),
341
- onPayload: Type.Optional(Type.Unsafe()),
342
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
343
- maxRetryDelayMs: Type.Optional(Type.Number()),
344
- metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
345
- });
346
- _Stream.SimpleOptionsSchema = Type.Composite([OptionsSchema, Type.Object({
347
- reasoning: Type.Optional(ThinkingLevelSchema),
348
- thinkingBudgets: Type.Optional(ThinkingBudgetsSchema)
349
- })]);
350
- function buildBaseOptions(model, options, apiKey) {
351
- return {
352
- temperature: options?.temperature,
353
- maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32e3),
354
- signal: options?.signal,
355
- apiKey: apiKey || options?.apiKey,
356
- transport: options?.transport,
357
- cacheRetention: options?.cacheRetention,
358
- sessionId: options?.sessionId,
359
- headers: options?.headers,
360
- onPayload: options?.onPayload,
361
- maxRetryDelayMs: options?.maxRetryDelayMs,
362
- metadata: options?.metadata
363
- };
364
- }
365
- _Stream.buildBaseOptions = buildBaseOptions;
366
- function clampReasoning(effort) {
367
- return effort === ThinkingLevelEnum.xhigh ? ThinkingLevelEnum.high : effort;
368
- }
369
- _Stream.clampReasoning = clampReasoning;
370
- function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
371
- const budgets = {
372
- minimal: 1024,
373
- low: 2048,
374
- medium: 8192,
375
- high: 16384,
376
- ...customBudgets
377
- };
378
- const minOutputTokens = 1024;
379
- let thinkingBudget = budgets[clampReasoning(reasoningLevel)];
380
- const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
381
- if (maxTokens <= thinkingBudget) thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
382
- return {
383
- maxTokens,
384
- thinkingBudget
385
- };
386
- }
387
- _Stream.adjustMaxTokensForThinking = adjustMaxTokensForThinking;
388
- const protocolProviderRegistry = /* @__PURE__ */ new Map();
389
- function wrapStream(protocol, stream) {
390
- return (model, context, options) => {
391
- if (model.protocol !== protocol) throw new ProtocolMismatchError({
392
- actual: model.protocol,
393
- expected: protocol
394
- });
395
- return stream(model, context, options);
396
- };
397
- }
398
- function wrapStreamSimple(protocol, streamSimple) {
399
- return (model, context, options) => {
400
- if (model.protocol !== protocol) throw new ProtocolMismatchError({
401
- actual: model.protocol,
402
- expected: protocol
403
- });
404
- return streamSimple(model, context, options);
405
- };
406
- }
407
- function registerProtocolProvider(provider, sourceId) {
408
- protocolProviderRegistry.set(provider.protocol, {
409
- provider: {
410
- protocol: provider.protocol,
411
- stream: wrapStream(provider.protocol, provider.stream),
412
- streamSimple: wrapStreamSimple(provider.protocol, provider.streamSimple)
413
- },
414
- sourceId
415
- });
416
- }
417
- _Stream.registerProtocolProvider = registerProtocolProvider;
418
- function getProtocolProvider(protocol) {
419
- return protocolProviderRegistry.get(protocol)?.provider;
420
- }
421
- _Stream.getProtocolProvider = getProtocolProvider;
422
- function resolveProtocolProvider(model) {
423
- const provider = getProtocolProvider(model.protocol);
424
- if (!provider) throw new ProtocolProviderNotFoundError({ protocol: model.protocol });
425
- return provider;
426
- }
427
- _Stream.resolveProtocolProvider = resolveProtocolProvider;
428
- function stream(model, context, options) {
429
- return resolveProtocolProvider(model).stream(model, context, options);
430
- }
431
- _Stream.stream = stream;
432
- async function complete(model, context, options) {
433
- return stream(model, context, options).result();
434
- }
435
- _Stream.complete = complete;
436
- function streamSimple(model, context, options) {
437
- return resolveProtocolProvider(model).streamSimple(model, context, options);
438
- }
439
- _Stream.streamSimple = streamSimple;
440
- async function completeSimple(model, context, options) {
441
- return streamSimple(model, context, options).result();
442
- }
443
- _Stream.completeSimple = completeSimple;
444
- function getApiProviders() {
445
- return Array.from(protocolProviderRegistry.values(), (entry) => entry.provider);
446
- }
447
- _Stream.getApiProviders = getApiProviders;
448
- function unregisterProtocolProviders(sourceId) {
449
- for (const [api, entry] of protocolProviderRegistry.entries()) if (entry.sourceId === sourceId) protocolProviderRegistry.delete(api);
450
- }
451
- _Stream.unregisterProtocolProviders = unregisterProtocolProviders;
452
- function clearProtocolProviders() {
453
- protocolProviderRegistry.clear();
454
- }
455
- _Stream.clearProtocolProviders = clearProtocolProviders;
456
- })(Stream || (Stream = {}));
457
- //#endregion
458
- //#region src/utils/eventstream.ts
459
- var EventStream = class {
460
- queue = [];
461
- waiting = [];
462
- done = false;
463
- finalResultPromise;
464
- resolveFinalResult;
465
- constructor(isComplete, extractResult) {
466
- this.isComplete = isComplete;
467
- this.extractResult = extractResult;
468
- this.finalResultPromise = new Promise((resolve) => {
469
- this.resolveFinalResult = resolve;
470
- });
471
- }
472
- push(event) {
473
- if (this.done) return;
474
- if (this.isComplete(event)) {
475
- this.done = true;
476
- this.resolveFinalResult(this.extractResult(event));
477
- }
478
- const waiter = this.waiting.shift();
479
- if (waiter) waiter({
480
- value: event,
481
- done: false
482
- });
483
- else this.queue.push(event);
484
- }
485
- end(result) {
486
- this.done = true;
487
- if (result !== void 0) this.resolveFinalResult(result);
488
- while (this.waiting.length > 0) this.waiting.shift()({
489
- value: void 0,
490
- done: true
491
- });
492
- }
493
- async *[Symbol.asyncIterator]() {
494
- while (true) if (this.queue.length > 0) yield this.queue.shift();
495
- else if (this.done) return;
496
- else {
497
- const result = await new Promise((resolve) => this.waiting.push(resolve));
498
- if (result.done) return;
499
- yield result.value;
500
- }
501
- }
502
- result() {
503
- return this.finalResultPromise;
504
- }
505
- };
506
- var AssistantMessageEventStream = class extends EventStream {
507
- constructor() {
508
- super((event) => event.type === "done" || event.type === "error", (event) => {
509
- if (event.type === "done") return event.message;
510
- else if (event.type === "error") return event.error;
511
- throw new Error("Unexpected event type for final result");
512
- });
513
- }
514
- };
515
- //#endregion
516
- //#region src/utils/validation.ts
517
- const ajv = new Ajv({
518
- allErrors: true,
519
- strict: false,
520
- coerceTypes: true
521
- });
522
- addFormats(ajv);
523
- /**
524
- * Validates an arbitrary value against a TypeBox schema and returns the coerced value.
525
- */
526
- function validateSchema(schema, value, label) {
527
- const validate = ajv.compile(schema);
528
- const input = structuredClone(value);
529
- if (validate(input)) return input;
530
- const errors = validate.errors?.map((err) => {
531
- return ` - ${err.instancePath ? err.instancePath.substring(1) : err.params?.missingProperty || "root"}: ${err.message}`;
532
- }).join("\n") || "Unknown Validation Error";
533
- throw new Error([
534
- `Validation Failed For ${label}`,
535
- `${errors}\n`,
536
- "Received Value:",
537
- `${JSON.stringify(value, null, 2)}\n`
538
- ].join("\n"));
539
- }
540
- /**
541
- * Validates tool call arguments against the tool's TypeBox schema
542
- */
543
- function validateToolArguments(tool, toolExecution) {
544
- return validateSchema(tool.parameters, toolExecution.rawArgs, `Tool "${toolExecution.name}"`);
545
- }
546
- //#endregion
547
- //#region src/agent/loop.ts
548
- let Loop;
549
- (function(_Loop) {
550
- function createAgentStream() {
551
- return new EventStream((event) => event.type === "agent.end", (event) => event.type === "agent.end" ? event.messages : []);
552
- }
553
- const AgentContextError = _Loop.AgentContextError = NamedError.create("AgentContextError", Type.Object({ message: Type.String() }));
554
- function snapshotAssistantMessage(message) {
555
- return structuredClone(message);
556
- }
557
- function snapshotAssistantPartEvent(message, partIndex) {
558
- const snapshot = snapshotAssistantMessage(message);
559
- const part = snapshot.parts[partIndex];
560
- if (!part) throw new Error(`Assistant message part at index ${partIndex} was not found`);
561
- return {
562
- message: snapshot,
563
- part
564
- };
565
- }
566
- async function emitEvent(emit, event) {
567
- await emit(event);
568
- }
569
- async function streamAssistantResponse(config, context, emit, streamFn, signal) {
570
- let messages = context.messages;
571
- if (config.transformContext) messages = await config.transformContext(messages, signal);
572
- const llmMessages = await config.convertToLlm(messages);
573
- const llmContext = {
574
- systemPrompt: context.systemPrompt,
575
- messages: llmMessages,
576
- tools: context.tools
577
- };
578
- const streamFunction = streamFn || Stream.streamSimple;
579
- const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : void 0) || config.apiKey;
580
- const events = await streamFunction(config.model, llmContext, {
581
- ...config,
582
- apiKey: resolvedApiKey,
583
- signal
584
- });
585
- let partialMessage = null;
586
- let started = false;
587
- const ensureMessageStarted = async (message) => {
588
- if (started) return;
589
- started = true;
590
- await emitEvent(emit, {
591
- type: "message.start",
592
- message: snapshotAssistantMessage(message)
593
- });
594
- };
595
- const emitMessageUpdate = async (message) => {
596
- await emitEvent(emit, {
597
- type: "message.update",
598
- message: snapshotAssistantMessage(message)
599
- });
600
- };
601
- const emitPartStart = async (message, partIndex) => {
602
- await emitEvent(emit, {
603
- type: "message.part.start",
604
- partIndex,
605
- ...snapshotAssistantPartEvent(message, partIndex)
606
- });
607
- };
608
- const emitPartUpdate = async (message, partIndex) => {
609
- await emitEvent(emit, {
610
- type: "message.part.update",
611
- partIndex,
612
- ...snapshotAssistantPartEvent(message, partIndex),
613
- source: "llm"
614
- });
615
- };
616
- const emitPartEnd = async (message, partIndex) => {
617
- await emitEvent(emit, {
618
- type: "message.part.end",
619
- partIndex,
620
- ...snapshotAssistantPartEvent(message, partIndex)
621
- });
622
- };
623
- for await (const event of events) switch (event.type) {
624
- case "start":
625
- partialMessage = event.partial;
626
- await ensureMessageStarted(partialMessage);
627
- break;
628
- case "text.start":
629
- case "thinking.start":
630
- case "toolcall.start":
631
- partialMessage = event.partial;
632
- await ensureMessageStarted(partialMessage);
633
- await emitPartStart(partialMessage, event.partIndex);
634
- break;
635
- case "text.delta":
636
- case "thinking.delta":
637
- case "toolcall.delta":
638
- partialMessage = event.partial;
639
- await ensureMessageStarted(partialMessage);
640
- await emitPartUpdate(partialMessage, event.partIndex);
641
- break;
642
- case "text.end":
643
- case "thinking.end":
644
- case "toolcall.end":
645
- partialMessage = event.partial;
646
- await ensureMessageStarted(partialMessage);
647
- await emitPartEnd(partialMessage, event.partIndex);
648
- await emitMessageUpdate(partialMessage);
649
- break;
650
- case "done":
651
- await ensureMessageStarted(event.message);
652
- await emitEvent(emit, {
653
- type: "message.end",
654
- message: snapshotAssistantMessage(event.message)
655
- });
656
- return event.message;
657
- case "error":
658
- await ensureMessageStarted(event.error);
659
- await emitEvent(emit, {
660
- type: "message.end",
661
- message: snapshotAssistantMessage(event.error)
662
- });
663
- return event.error;
664
- }
665
- const finalMessage = await events.result();
666
- await ensureMessageStarted(finalMessage);
667
- await emitEvent(emit, {
668
- type: "message.end",
669
- message: snapshotAssistantMessage(finalMessage)
670
- });
671
- return finalMessage;
672
- }
673
- async function executeToolCalls(config, currentContext, message, toolCalls, emit, signal) {
674
- if (config.toolExecution === "sequential") return executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal);
675
- return executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal);
676
- }
677
- async function executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal) {
678
- for (const toolCall of toolCalls) {
679
- const toolCallInFlight = {
680
- callID: toolCall.callID,
681
- name: toolCall.name,
682
- rawArgs: toolCall.arguments
683
- };
684
- await emitEvent(emit, {
685
- type: "tool.execution.start",
686
- ...toolCallInFlight
687
- });
688
- const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
689
- if (prepared.error) {
690
- const error = {
691
- status: "error",
692
- result: {
693
- content: [{
694
- type: "text",
695
- text: prepared.error.message
696
- }],
697
- details: prepared.error.details,
698
- isError: true
699
- }
700
- };
701
- await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
702
- } else {
703
- const runnable = {
704
- toolCall,
705
- runnable: prepared.runnable,
706
- tool: prepared.tool
707
- };
708
- const executed = await executeRunnableToolCall(runnable, message, emit, signal);
709
- if (executed.error) {
710
- const error = {
711
- status: "error",
712
- result: {
713
- content: [{
714
- type: "text",
715
- text: executed.error.message
716
- }],
717
- details: executed.error.details,
718
- isError: true
719
- }
720
- };
721
- await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
722
- } else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
723
- }
724
- }
725
- }
726
- async function executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal) {
727
- const runnables = [];
728
- for (const toolCall of toolCalls) {
729
- const toolCallInFlight = {
730
- callID: toolCall.callID,
731
- name: toolCall.name,
732
- rawArgs: toolCall.arguments
733
- };
734
- await emitEvent(emit, {
735
- type: "tool.execution.start",
736
- ...toolCallInFlight
737
- });
738
- const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
739
- if (prepared.error) {
740
- const error = {
741
- status: "error",
742
- result: {
743
- content: [{
744
- type: "text",
745
- text: prepared.error.message
746
- }],
747
- details: prepared.error.details,
748
- isError: true
749
- }
750
- };
751
- await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
752
- } else runnables.push({
753
- toolCall,
754
- runnable: prepared.runnable,
755
- tool: prepared.tool
756
- });
757
- }
758
- const runningExecutions = runnables.map((runnable) => ({
759
- runnable,
760
- execution: executeRunnableToolCall(runnable, message, emit, signal)
761
- }));
762
- for (const running of runningExecutions) {
763
- const executed = await running.execution;
764
- const { runnable } = running;
765
- if (executed.error) {
766
- const error = {
767
- status: "error",
768
- result: {
769
- content: [{
770
- type: "text",
771
- text: executed.error.message
772
- }],
773
- details: executed.error.details,
774
- isError: true
775
- }
776
- };
777
- await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
778
- } else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
779
- }
780
- }
781
- async function prepareToolCall(config, currentContext, assistantMessage, toolCallInFlight, signal) {
782
- const tool = currentContext.tools?.find((t) => t.name === toolCallInFlight.name);
783
- if (!tool) return {
784
- error: {
785
- kind: "error",
786
- message: `Tool ${toolCallInFlight.name} Not Found`
787
- },
788
- runnable: toolCallInFlight
789
- };
790
- try {
791
- toolCallInFlight.args = validateToolArguments(tool, toolCallInFlight);
792
- if (config.beforeToolExecution) {
793
- const beforeResult = await config.beforeToolExecution({
794
- context: currentContext,
795
- assistantMessage,
796
- toolCall: toolCallInFlight
797
- }, signal);
798
- if (beforeResult?.block) return {
799
- error: {
800
- kind: "blocked",
801
- message: beforeResult?.reason || "Tool Execution was Blocked",
802
- details: beforeResult?.details
803
- },
804
- runnable: toolCallInFlight
805
- };
806
- }
807
- return {
808
- runnable: toolCallInFlight,
809
- tool
810
- };
811
- } catch (err) {
812
- return {
813
- error: {
814
- kind: "error",
815
- message: err instanceof Error ? err.message : String(err)
816
- },
817
- runnable: toolCallInFlight
818
- };
819
- }
820
- }
821
- async function executeRunnableToolCall(toolCallRunnable, message, emit, signal) {
822
- const { toolCall, runnable, tool } = toolCallRunnable;
823
- const { partIndex, ...pendingPart } = toolCall;
824
- try {
825
- return { result: await tool.execute(runnable.callID, runnable.args, signal, async (result) => {
826
- const runningResult = {
827
- status: "running",
828
- partial: result.partial
829
- };
830
- await emitEvent(emit, {
831
- type: "tool.execution.update",
832
- ...runnable,
833
- ...runningResult
834
- });
835
- const runningPart = {
836
- ...pendingPart,
837
- ...runningResult
838
- };
839
- message.parts[partIndex] = runningPart;
840
- await emitEvent(emit, {
841
- type: "message.part.update",
842
- message,
843
- partIndex,
844
- part: runningPart,
845
- source: "tool"
846
- });
847
- }) };
848
- } catch (err) {
849
- return { error: { message: err instanceof Error ? err.message : String(err) } };
850
- }
851
- }
852
- async function emitToolCallTerminalResult(toolCall, runnable, message, emit, result) {
853
- const { partIndex, ...pendingPart } = toolCall;
854
- const { time } = pendingPart;
855
- await emitEvent(emit, {
856
- type: "tool.execution.end",
857
- ...runnable,
858
- ...result
859
- });
860
- const part = {
861
- ...pendingPart,
862
- ...result,
863
- time: {
864
- start: time.start,
865
- end: Date.now()
866
- }
867
- };
868
- message.parts[partIndex] = part;
869
- await emitEvent(emit, {
870
- type: "message.part.start",
871
- message,
872
- partIndex,
873
- part
874
- });
875
- await emitEvent(emit, {
876
- type: "message.part.end",
877
- message,
878
- partIndex,
879
- part
880
- });
881
- await emitEvent(emit, {
882
- type: "message.update",
883
- message
884
- });
885
- }
886
- async function finalizeExecutedToolCall(config, currentContext, toolCall, runnable, message, emit, result, signal) {
887
- if (config.afterToolExecution) {
888
- const afterResult = await config.afterToolExecution({
889
- context: currentContext,
890
- assistantMessage: message,
891
- toolCall: runnable,
892
- result
893
- }, signal);
894
- if (afterResult) {
895
- await emitToolCallTerminalResult(toolCall, runnable, message, emit, afterResult);
896
- return;
897
- }
898
- }
899
- await emitToolCallTerminalResult(toolCall, runnable, message, emit, result);
900
- }
901
- /**
902
- * Main core loop shared by run and runContinue.
903
- */
904
- async function runLoop(config, currentContext, newMessages, emit, streamFn, signal) {
905
- let firstTurn = true;
906
- let pendingMessages = await config.getSteeringMessages?.() || [];
907
- while (true) {
908
- let hasMoreToolCalls = true;
909
- while (hasMoreToolCalls || pendingMessages.length > 0) {
910
- if (!firstTurn) await emitEvent(emit, { type: "turn.start" });
911
- else firstTurn = false;
912
- if (pendingMessages.length > 0) {
913
- for (const message of pendingMessages) {
914
- await emitEvent(emit, {
915
- type: "message.start",
916
- message
917
- });
918
- for (const [partIndex, part] of message.parts.entries()) {
919
- await emitEvent(emit, {
920
- type: "message.part.start",
921
- message,
922
- partIndex,
923
- part
924
- });
925
- await emitEvent(emit, {
926
- type: "message.part.end",
927
- message,
928
- partIndex,
929
- part
930
- });
931
- await emitEvent(emit, {
932
- type: "message.update",
933
- message
934
- });
935
- }
936
- await emitEvent(emit, {
937
- type: "message.end",
938
- message
939
- });
940
- currentContext.messages.push(message);
941
- newMessages.push(message);
942
- }
943
- pendingMessages = [];
944
- }
945
- const message = await streamAssistantResponse(config, currentContext, emit, streamFn, signal);
946
- if (message.stopReason === "error" || message.stopReason === "aborted") {
947
- currentContext.messages.push(message);
948
- newMessages.push(message);
949
- await emitEvent(emit, {
950
- type: "turn.end",
951
- message
952
- });
953
- await emitEvent(emit, {
954
- type: "agent.end",
955
- messages: newMessages
956
- });
957
- return;
958
- }
959
- const toolCalls = message.parts.map((part, index) => ({
960
- ...part,
961
- partIndex: index
962
- })).filter((part) => part.type === "toolCall" && part.status === "pending");
963
- hasMoreToolCalls = toolCalls.length > 0;
964
- if (hasMoreToolCalls) await executeToolCalls(config, currentContext, message, toolCalls, emit, signal);
965
- currentContext.messages.push(message);
966
- newMessages.push(message);
967
- await emitEvent(emit, {
968
- type: "turn.end",
969
- message
970
- });
971
- pendingMessages = await config.getSteeringMessages?.() || [];
972
- }
973
- const followUpMessages = await config.getFollowUpMessages?.() || [];
974
- if (followUpMessages.length > 0) {
975
- pendingMessages = followUpMessages;
976
- continue;
977
- }
978
- break;
979
- }
980
- await emitEvent(emit, {
981
- type: "agent.end",
982
- messages: newMessages
983
- });
984
- }
985
- async function runAgentLoop(config, context, prompts, emit, streamFn, signal) {
986
- /**
987
- * maintain 2 arrays to represent state, `context` the actual full state sent to the LLM,
988
- * `newMessages` for intermediate current loop state.
989
- * think of newMessages as subset of context.messages for the running current loop.
990
- * they do move at the same speed staring with initial user prompts.
991
- * */
992
- const newMessages = [...prompts];
993
- const currentContext = {
994
- ...context,
995
- messages: [...context.messages, ...prompts]
996
- };
997
- await emitEvent(emit, { type: "agent.start" });
998
- await emitEvent(emit, { type: "turn.start" });
999
- for (const prompt of prompts) {
1000
- await emitEvent(emit, {
1001
- type: "message.start",
1002
- message: prompt
1003
- });
1004
- for (const [partIndex, part] of prompt.parts.entries()) {
1005
- await emitEvent(emit, {
1006
- type: "message.part.start",
1007
- message: prompt,
1008
- partIndex,
1009
- part
1010
- });
1011
- await emitEvent(emit, {
1012
- type: "message.part.end",
1013
- message: prompt,
1014
- partIndex,
1015
- part
1016
- });
1017
- }
1018
- await emitEvent(emit, {
1019
- type: "message.end",
1020
- message: prompt
1021
- });
1022
- }
1023
- await runLoop(config, currentContext, newMessages, emit, streamFn, signal);
1024
- return newMessages;
1025
- }
1026
- _Loop.runAgentLoop = runAgentLoop;
1027
- async function runAgentLoopContinue(config, context, emit, streamFn, signal) {
1028
- if (context.messages.length === 0) throw new AgentContextError({ message: "connot continue: no messages in context" });
1029
- if (context.messages[context.messages.length - 1]?.role === "assistant") throw new AgentContextError({ message: "cannot continue from message role: assistant" });
1030
- const newMessages = [];
1031
- const currentContext = { ...context };
1032
- await emitEvent(emit, { type: "agent.start" });
1033
- await emitEvent(emit, { type: "turn.start" });
1034
- await runLoop(config, currentContext, newMessages, emit, streamFn, signal);
1035
- return newMessages;
1036
- }
1037
- _Loop.runAgentLoopContinue = runAgentLoopContinue;
1038
- function run(config, context, prompts, streamFn, signal) {
1039
- const stream = createAgentStream();
1040
- runAgentLoop(config, context, prompts, async (event) => {
1041
- stream.push(event);
1042
- }, streamFn, signal).then((messages) => {
1043
- stream.end(messages);
1044
- });
1045
- return stream;
1046
- }
1047
- _Loop.run = run;
1048
- function runContinue(config, context, streamFn, signal) {
1049
- const stream = createAgentStream();
1050
- runAgentLoopContinue(config, context, async (event) => {
1051
- stream.push(event);
1052
- }, streamFn, signal).then((messages) => {
1053
- stream.end(messages);
1054
- });
1055
- return stream;
1056
- }
1057
- _Loop.runContinue = runContinue;
1058
- })(Loop || (Loop = {}));
1059
- //#endregion
1060
- //#region src/agent.ts
1061
- const agent = {
1062
- loop: Loop.run,
1063
- loopContinue: Loop.runContinue
1064
- };
1065
- //#endregion
1066
- //#region src/message/message.ts
1067
- let Message;
1068
- (function(_Message) {
1069
- const TextContentSchema = _Message.TextContentSchema = Type.Object({
1070
- type: Type.Literal("text"),
1071
- text: Type.String(),
1072
- textSignature: Type.Optional(Type.String())
1073
- });
1074
- const ImageContentSchema = _Message.ImageContentSchema = Type.Object({
1075
- type: Type.Literal("image"),
1076
- data: Type.String(),
1077
- mimeType: Type.String()
1078
- });
1079
- const ThinkingContentSchema = _Message.ThinkingContentSchema = Type.Object({
1080
- type: Type.Literal("thinking"),
1081
- thinking: Type.String(),
1082
- thinkingSignature: Type.Optional(Type.String()),
1083
- redacted: Type.Optional(Type.Boolean())
1084
- });
1085
- const ToolCallBaseSchema = _Message.ToolCallBaseSchema = Type.Object({
1086
- type: Type.Literal("toolCall"),
1087
- callID: Type.String(),
1088
- name: Type.String(),
1089
- arguments: Type.Record(Type.String(), Type.Any()),
1090
- thoughtSignature: Type.Optional(Type.String()),
1091
- time: Type.Object({
1092
- start: Type.Number(),
1093
- end: Type.Number()
1094
- })
1095
- });
1096
- const ToolSuccessResult = _Message.ToolSuccessResult = Type.Object({
1097
- content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
1098
- details: Type.Optional(Type.Any()),
1099
- isError: Type.Literal(false)
1100
- });
1101
- const ToolErrorResult = _Message.ToolErrorResult = Type.Object({
1102
- content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
1103
- details: Type.Optional(Type.Any()),
1104
- isError: Type.Literal(true)
1105
- });
1106
- const ToolRunningPartial = _Message.ToolRunningPartial = Type.Object({
1107
- content: Type.Optional(Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))),
1108
- details: Type.Optional(Type.Any())
1109
- });
1110
- const ToolStatusEnum = _Message.ToolStatusEnum = {
1111
- pending: "pending",
1112
- running: "running",
1113
- completed: "completed",
1114
- error: "error",
1115
- skipped: "skipped",
1116
- aborted: "aborted"
1117
- };
1118
- const ToolRunningSchema = _Message.ToolRunningSchema = Type.Object({
1119
- status: Type.Literal(ToolStatusEnum.running),
1120
- partial: Type.Optional(ToolRunningPartial)
1121
- });
1122
- const ToolCompletedSchema = _Message.ToolCompletedSchema = Type.Object({
1123
- status: Type.Literal(ToolStatusEnum.completed),
1124
- result: ToolSuccessResult
1125
- });
1126
- const ToolErrorSchema = _Message.ToolErrorSchema = Type.Object({
1127
- status: Type.Literal(ToolStatusEnum.error),
1128
- result: ToolErrorResult
1129
- });
1130
- const ToolSkippedSchema = _Message.ToolSkippedSchema = Type.Object({
1131
- status: Type.Literal(ToolStatusEnum.skipped),
1132
- result: ToolErrorResult
1133
- });
1134
- const ToolAbortedSchema = _Message.ToolAbortedSchema = Type.Object({
1135
- status: Type.Literal(ToolStatusEnum.aborted),
1136
- result: ToolErrorResult
1137
- });
1138
- const ToolCallPendingPart = Type.Intersect([ToolCallBaseSchema, Type.Object({ status: Type.Literal(ToolStatusEnum.pending) })]);
1139
- const ToolCallRunningPart = Type.Composite([ToolCallBaseSchema, ToolRunningSchema]);
1140
- const ToolCallCompletedPart = Type.Composite([ToolCallBaseSchema, ToolCompletedSchema]);
1141
- const ToolCallErrorPart = Type.Composite([ToolCallBaseSchema, ToolErrorSchema]);
1142
- const ToolCallSkippedPart = Type.Composite([ToolCallBaseSchema, ToolSkippedSchema]);
1143
- const ToolCallAbortedPart = Type.Composite([ToolCallBaseSchema, ToolAbortedSchema]);
1144
- const ToolCallSchema = _Message.ToolCallSchema = Type.Union([
1145
- ToolCallPendingPart,
1146
- ToolCallRunningPart,
1147
- ToolCallCompletedPart,
1148
- ToolCallErrorPart,
1149
- ToolCallSkippedPart,
1150
- ToolCallAbortedPart
1151
- ]);
1152
- const UsageSchema = _Message.UsageSchema = Type.Object({
1153
- input: Type.Number(),
1154
- output: Type.Number(),
1155
- cacheRead: Type.Number(),
1156
- cacheWrite: Type.Number(),
1157
- totalTokens: Type.Number(),
1158
- cost: Type.Object({
1159
- input: Type.Number(),
1160
- output: Type.Number(),
1161
- cacheRead: Type.Number(),
1162
- cacheWrite: Type.Number(),
1163
- total: Type.Number()
1164
- })
1165
- });
1166
- const StopReasonSchema = _Message.StopReasonSchema = Type.Union([
1167
- Type.Literal("stop"),
1168
- Type.Literal("length"),
1169
- Type.Literal("toolUse"),
1170
- Type.Literal("error"),
1171
- Type.Literal("aborted")
1172
- ]);
1173
- const UserMessageSchema = _Message.UserMessageSchema = Type.Object({
1174
- messageId: Type.String(),
1175
- role: Type.Literal("user"),
1176
- time: Type.Object({ created: Type.Number() }),
1177
- parts: Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))
1178
- });
1179
- const AssistantMessageSchema = _Message.AssistantMessageSchema = Type.Object({
1180
- role: Type.Literal("assistant"),
1181
- protocol: Model.KnownProtocolSchema,
1182
- provider: Provider.Info,
1183
- model: Type.String(),
1184
- usage: UsageSchema,
1185
- stopReason: StopReasonSchema,
1186
- errorMessage: Type.Optional(Type.String()),
1187
- time: Type.Object({
1188
- created: Type.Number(),
1189
- completed: Type.Number()
1190
- }),
1191
- parts: Type.Array(Type.Union([
1192
- TextContentSchema,
1193
- ImageContentSchema,
1194
- ThinkingContentSchema,
1195
- ToolCallSchema
1196
- ])),
1197
- responseId: Type.Optional(Type.String()),
1198
- messageId: Type.String()
1199
- });
1200
- const MessageSchema = _Message.MessageSchema = Type.Union([UserMessageSchema, AssistantMessageSchema]);
1201
- function createMessageId() {
1202
- return uuidv7();
1203
- }
1204
- _Message.createMessageId = createMessageId;
1205
- function createUserMessage(message) {
1206
- const { messageId = createMessageId(), ...rest } = message;
1207
- return {
1208
- messageId,
1209
- ...rest
1210
- };
1211
- }
1212
- _Message.createUserMessage = createUserMessage;
1213
- function createAssistantMessage(message) {
1214
- const { messageId = createMessageId(), ...rest } = message;
1215
- return {
1216
- messageId,
1217
- ...rest
1218
- };
1219
- }
1220
- _Message.createAssistantMessage = createAssistantMessage;
1221
- const ToolSchema = _Message.ToolSchema = Type.Object({
1222
- name: Type.String(),
1223
- description: Type.String(),
1224
- parameters: Type.Unsafe()
1225
- });
1226
- function defineTool(tool) {
1227
- return tool;
1228
- }
1229
- _Message.defineTool = defineTool;
1230
- _Message.ContextSchema = Type.Object({
1231
- systemPrompt: Type.Optional(Type.String()),
1232
- messages: Type.Array(MessageSchema),
1233
- tools: Type.Optional(Type.Array(ToolSchema))
1234
- });
1235
- function transformMessages(messages, model, normalizeToolCallId) {
1236
- const toolCallIDMap = /* @__PURE__ */ new Map();
1237
- const transformed = [];
1238
- for (const msg of messages) {
1239
- if (msg.role === "user") {
1240
- transformed.push(msg);
1241
- continue;
1242
- }
1243
- const assistantMsg = msg;
1244
- const isSameModel = assistantMsg.provider.id === model.provider.id && assistantMsg.protocol === model.protocol && assistantMsg.model === model.id;
1245
- const parts = assistantMsg.parts.flatMap((block) => {
1246
- if (block.type === "thinking") {
1247
- if (isSameModel && block.thinkingSignature) return block;
1248
- if (!block.thinking || block.thinking.trim() === "") return [];
1249
- if (isSameModel) return block;
1250
- return {
1251
- type: "text",
1252
- text: block.thinking
1253
- };
1254
- }
1255
- if (block.type === "text") {
1256
- if (isSameModel) return block;
1257
- return {
1258
- type: "text",
1259
- text: block.text
1260
- };
1261
- }
1262
- if (block.type === "toolCall") {
1263
- const toolCall = block;
1264
- let normalizedToolCall = toolCall;
1265
- if (!isSameModel && toolCall.thoughtSignature) {
1266
- normalizedToolCall = { ...toolCall };
1267
- delete normalizedToolCall.thoughtSignature;
1268
- }
1269
- const normalizedID = toolCallIDMap.get(block.callID);
1270
- if (normalizedID && normalizedID !== block.callID) normalizedToolCall = {
1271
- ...normalizedToolCall,
1272
- callID: normalizedID
1273
- };
1274
- else if (!isSameModel && normalizeToolCallId) {
1275
- const nextID = normalizeToolCallId(toolCall.callID, model, assistantMsg);
1276
- if (nextID !== toolCall.callID) {
1277
- toolCallIDMap.set(toolCall.callID, nextID);
1278
- normalizedToolCall = {
1279
- ...normalizedToolCall,
1280
- callID: nextID
1281
- };
1282
- }
1283
- }
1284
- return normalizedToolCall;
1285
- }
1286
- return block;
1287
- });
1288
- transformed.push({
1289
- ...assistantMsg,
1290
- parts
1291
- });
1292
- }
1293
- return transformed;
1294
- }
1295
- _Message.transformMessages = transformMessages;
1296
- })(Message || (Message = {}));
1297
- //#endregion
1298
- //#region src/utils/jsonparse.ts
1299
- /**
1300
- * @description Helper function to parse partial jsons during LLM streaming.
1301
- */
1302
- /**
1303
- * Attempts to parse potentially incomplete JSON during streaming.
1304
- * Always returns a valid object, even if the JSON is incomplete.
1305
- *
1306
- * @param partialJson The partial JSON string from streaming
1307
- * @returns Parsed object or empty object if parsing fails
1308
- */
1309
- function parseStreamingJson(partialJson) {
1310
- if (!partialJson || partialJson.trim() === "") return {};
1311
- try {
1312
- return JSON.parse(partialJson);
1313
- } catch {
1314
- try {
1315
- return parse(partialJson) ?? {};
1316
- } catch {
1317
- return {};
1318
- }
1319
- }
1320
- }
1321
- //#endregion
1322
- //#region src/utils/sanitize.ts
1323
- /**
1324
- * Removes unpaired Unicode surrogate characters from a string.
1325
- *
1326
- * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
1327
- * or vice versa) cause JSON serialization errors in many API providers.
1328
- *
1329
- * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
1330
- * surrogates and will NOT be affected by this function.
1331
- *
1332
- * @param text - The text to sanitize
1333
- * @returns The sanitized text with unpaired surrogates removed
1334
- *
1335
- * @example
1336
- * // Valid emoji (properly paired surrogates) are preserved
1337
- * sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
1338
- *
1339
- * // Unpaired high surrogate is removed
1340
- * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
1341
- * sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
1342
- */
1343
- function sanitizeSurrogates(text) {
1344
- return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
1345
- }
1346
- //#endregion
1347
- //#region src/provider/providers/utils.ts
1348
- function getEnvApiKey(_provider) {}
1349
- //#endregion
1350
- //#region src/provider/providers/anthropic/index.ts
1351
- function resolveCacheRetention(cacheRetention) {
1352
- if (cacheRetention) return cacheRetention;
1353
- if (typeof process !== "undefined" && process.env.CODEWORK_CACHE_RETENTION === "long") return "long";
1354
- return "short";
1355
- }
1356
- function getCacheControl(baseUrl, cacheRetention) {
1357
- const retention = resolveCacheRetention(cacheRetention);
1358
- if (retention === "none") return { retention };
1359
- const ttl = retention === "long" && baseUrl.includes("api.anthropic.com") ? "1h" : void 0;
1360
- return {
1361
- retention,
1362
- cacheControl: {
1363
- type: "ephemeral",
1364
- ...ttl && { ttl }
1365
- }
1366
- };
1367
- }
1368
- const claudeCodeVersion = "2.1.2";
1369
- const ccToolLookup = new Map([
1370
- "Read",
1371
- "Write",
1372
- "Edit",
1373
- "Bash",
1374
- "Grep",
1375
- "Glob",
1376
- "AskUserQuestion",
1377
- "EnterPlanMode",
1378
- "ExitPlanMode",
1379
- "KillShell",
1380
- "NotebookEdit",
1381
- "Skill",
1382
- "Task",
1383
- "TaskOutput",
1384
- "TodoWrite",
1385
- "WebFetch",
1386
- "WebSearch"
1387
- ].map((t) => [t.toLowerCase(), t]));
1388
- const toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;
1389
- const fromClaudeCodeName = (name, tools) => {
1390
- if (tools && tools.length > 0) {
1391
- const lowerName = name.toLowerCase();
1392
- const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
1393
- if (matchedTool) return matchedTool.name;
1394
- }
1395
- return name;
1396
- };
1397
- function convertContentBlocks(content) {
1398
- if (!content.some((c) => c.type === "image")) return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
1399
- const blocks = content.map((block) => {
1400
- if (block.type === "text") return {
1401
- type: "text",
1402
- text: sanitizeSurrogates(block.text)
1403
- };
1404
- return {
1405
- type: "image",
1406
- source: {
1407
- type: "base64",
1408
- media_type: block.mimeType,
1409
- data: block.data
1410
- }
1411
- };
1412
- });
1413
- if (!blocks.some((b) => b.type === "text")) blocks.unshift({
1414
- type: "text",
1415
- text: "(see attached image)"
1416
- });
1417
- return blocks;
1418
- }
1419
- function mergeHeaders(...headerSources) {
1420
- const merged = {};
1421
- for (const headers of headerSources) if (headers) Object.assign(merged, headers);
1422
- return merged;
1423
- }
1424
- function isOAuthToken(apiKey) {
1425
- return apiKey.includes("sk-ant-oat");
1426
- }
1427
- function createClient$1(model, apiKey, interleavedThinking, optionsHeaders) {
1428
- const betaFeatures = ["fine-grained-tool-streaming-2025-05-14"];
1429
- if (interleavedThinking) betaFeatures.push("interleaved-thinking-2025-05-14");
1430
- if (isOAuthToken(apiKey)) {
1431
- const defaultHeaders = mergeHeaders({
1432
- accept: "application/json",
1433
- "anthropic-dangerous-direct-browser-access": "true",
1434
- "anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}`,
1435
- "user-agent": `claude-cli/${claudeCodeVersion} (external, cli)`,
1436
- "x-app": "cli"
1437
- }, model.headers, optionsHeaders);
1438
- return {
1439
- client: new Anthropic({
1440
- apiKey: null,
1441
- authToken: apiKey,
1442
- baseURL: model.baseUrl,
1443
- defaultHeaders,
1444
- dangerouslyAllowBrowser: true
1445
- }),
1446
- isOAuthToken: true
1447
- };
1448
- }
1449
- const defaultHeaders = mergeHeaders({
1450
- accept: "application/json",
1451
- "anthropic-dangerous-direct-browser-access": "true",
1452
- "anthropic-beta": betaFeatures.join(",")
1453
- }, model.headers, optionsHeaders);
1454
- return {
1455
- client: new Anthropic({
1456
- apiKey,
1457
- baseURL: model.baseUrl,
1458
- dangerouslyAllowBrowser: true,
1459
- defaultHeaders
1460
- }),
1461
- isOAuthToken: false
1462
- };
1463
- }
1464
- function normalizeToolCallId(id) {
1465
- return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
1466
- }
1467
- function assertReplayableAssistant(message) {
1468
- let sawToolCall = false;
1469
- let sawNonTerminalToolCall = false;
1470
- let sawTerminalToolCall = false;
1471
- for (const part of message.parts) {
1472
- if (part.type === "image") throw new Error("Anthropic replay does not support assistant image parts");
1473
- if (part.type === "toolCall") {
1474
- sawToolCall = true;
1475
- if (part.status === "pending" || part.status === "running") sawNonTerminalToolCall = true;
1476
- else sawTerminalToolCall = true;
1477
- continue;
1478
- }
1479
- if (sawToolCall) throw new Error("Assistant parts after a toolCall are not replayable for Anthropic");
1480
- }
1481
- if (sawToolCall && message.stopReason !== "toolUse") throw new Error("Assistant message with tool calls must have stopReason 'toolUse'");
1482
- if (!sawToolCall && message.stopReason === "toolUse") throw new Error("Assistant message with stopReason 'toolUse' must contain at least one toolCall");
1483
- if (sawTerminalToolCall && sawNonTerminalToolCall) throw new Error("Assistant message cannot mix terminal and non-terminal toolCall states");
1484
- }
1485
- function buildSyntheticToolResult$1(block) {
1486
- return {
1487
- type: "tool_result",
1488
- tool_use_id: block.callID,
1489
- content: convertContentBlocks([{
1490
- type: "text",
1491
- text: [
1492
- "<result>",
1493
- "No Result Provided",
1494
- "</result>"
1495
- ].join("\n")
1496
- }]),
1497
- is_error: true
1498
- };
1499
- }
1500
- function convertMessages$1(messages, model, isOAuthToken, cacheControl) {
1501
- const params = [];
1502
- const transformedMessages = Message.transformMessages(messages, model, normalizeToolCallId);
1503
- for (const msg of transformedMessages) {
1504
- if (msg.role === "user") {
1505
- const blocks = msg.parts.map((item) => {
1506
- if (item.type === "text") return {
1507
- type: "text",
1508
- text: sanitizeSurrogates(item.text)
1509
- };
1510
- return {
1511
- type: "image",
1512
- source: {
1513
- type: "base64",
1514
- media_type: item.mimeType,
1515
- data: item.data
1516
- }
1517
- };
1518
- });
1519
- let filteredBlocks = !model.input.includes("image") ? blocks.filter((b) => b.type !== "image") : blocks;
1520
- filteredBlocks = filteredBlocks.filter((b) => b.type === "text" ? b.text.trim().length > 0 : true);
1521
- if (filteredBlocks.length === 0) continue;
1522
- params.push({
1523
- role: "user",
1524
- content: filteredBlocks
1525
- });
1526
- continue;
1527
- }
1528
- if (msg.stopReason === "error" || msg.stopReason === "aborted") continue;
1529
- assertReplayableAssistant(msg);
1530
- const assistantBlocks = [];
1531
- const toolResults = [];
1532
- for (const block of msg.parts) if (block.type === "text") {
1533
- if (block.text.trim().length === 0) continue;
1534
- assistantBlocks.push({
1535
- type: "text",
1536
- text: sanitizeSurrogates(block.text)
1537
- });
1538
- } else if (block.type === "thinking") {
1539
- if (block.thinking.trim().length === 0) continue;
1540
- if (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) assistantBlocks.push({
1541
- type: "text",
1542
- text: sanitizeSurrogates(block.thinking)
1543
- });
1544
- else assistantBlocks.push({
1545
- type: "thinking",
1546
- thinking: sanitizeSurrogates(block.thinking),
1547
- signature: block.thinkingSignature
1548
- });
1549
- } else if (block.type === "toolCall") {
1550
- assistantBlocks.push({
1551
- type: "tool_use",
1552
- id: block.callID,
1553
- name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
1554
- input: block.arguments ?? {}
1555
- });
1556
- if (block.status === "pending" || block.status === "running") toolResults.push(buildSyntheticToolResult$1(block));
1557
- else toolResults.push({
1558
- type: "tool_result",
1559
- tool_use_id: block.callID,
1560
- content: convertContentBlocks(block.result.content),
1561
- is_error: block.result.isError
1562
- });
1563
- }
1564
- if (assistantBlocks.length > 0) params.push({
1565
- role: "assistant",
1566
- content: assistantBlocks
1567
- });
1568
- if (toolResults.length > 0) params.push({
1569
- role: "user",
1570
- content: toolResults
1571
- });
1572
- }
1573
- if (cacheControl && params.length > 0) {
1574
- const lastMessage = params[params.length - 1];
1575
- if (lastMessage.role === "user") {
1576
- if (Array.isArray(lastMessage.content)) {
1577
- const lastBlock = lastMessage.content[lastMessage.content.length - 1];
1578
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) lastBlock.cache_control = cacheControl;
1579
- } else if (typeof lastMessage.content === "string") lastMessage.content = [{
1580
- type: "text",
1581
- text: lastMessage.content,
1582
- cache_control: cacheControl
1583
- }];
1584
- }
1585
- }
1586
- return params;
1587
- }
1588
- function convertTools$1(tools, isOAuthToken) {
1589
- if (!tools) return [];
1590
- return tools.map((tool) => {
1591
- const jsonSchema = tool.parameters;
1592
- return {
1593
- name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name,
1594
- description: tool.description,
1595
- input_schema: {
1596
- type: "object",
1597
- properties: jsonSchema.properties || {},
1598
- required: jsonSchema.required || []
1599
- }
1600
- };
1601
- });
1602
- }
1603
- function mapStopReason$1(reason) {
1604
- switch (reason) {
1605
- case "end_turn": return "stop";
1606
- case "max_tokens": return "length";
1607
- case "tool_use": return "toolUse";
1608
- case "pause_turn":
1609
- case "stop_sequence": return "stop";
1610
- case "refusal":
1611
- case "sensitive": return "error";
1612
- default: throw new Error("Unhandled Anthropic stop reason");
1613
- }
1614
- }
1615
- function buildParams$1(model, context, isOAuthToken, options) {
1616
- const { cacheControl } = getCacheControl(model.baseUrl, options?.cacheRetention);
1617
- const params = {
1618
- model: model.id,
1619
- messages: convertMessages$1(context.messages, model, isOAuthToken, cacheControl),
1620
- max_tokens: options?.maxTokens || model.maxTokens / 3 | 0,
1621
- stream: true
1622
- };
1623
- if (isOAuthToken) {
1624
- params.system = [{
1625
- type: "text",
1626
- text: "You are Claude Code, Anthropic's official CLI for Claude.",
1627
- ...cacheControl ? { cache_control: cacheControl } : {}
1628
- }];
1629
- if (context.systemPrompt) params.system.push({
1630
- type: "text",
1631
- text: sanitizeSurrogates(context.systemPrompt),
1632
- ...cacheControl ? { cache_control: cacheControl } : {}
1633
- });
1634
- } else if (context.systemPrompt) params.system = [{
1635
- type: "text",
1636
- text: sanitizeSurrogates(context.systemPrompt),
1637
- ...cacheControl ? { cache_control: cacheControl } : {}
1638
- }];
1639
- if (options?.temperature !== void 0 && !options?.thinkingEnabled) params.temperature = options.temperature;
1640
- if (context.tools) params.tools = convertTools$1(context.tools, isOAuthToken);
1641
- if (options?.thinkingEnabled && model.reasoning) params.thinking = {
1642
- type: "enabled",
1643
- budget_tokens: options.thinkingBudgetTokens || 1024
1644
- };
1645
- if (options?.metadata) {
1646
- const userId = options.metadata.user_id;
1647
- if (typeof userId === "string") params.metadata = { user_id: userId };
1648
- }
1649
- if (options?.toolChoice) params.tool_choice = typeof options.toolChoice === "string" ? { type: options.toolChoice } : options.toolChoice;
1650
- return params;
1651
- }
1652
- const streamAnthropic = (model, context, options) => {
1653
- const stream = new AssistantMessageEventStream();
1654
- (async () => {
1655
- const output = Message.createAssistantMessage({
1656
- role: "assistant",
1657
- parts: [],
1658
- protocol: model.protocol,
1659
- provider: model.provider,
1660
- model: model.id,
1661
- usage: {
1662
- input: 0,
1663
- output: 0,
1664
- cacheRead: 0,
1665
- cacheWrite: 0,
1666
- totalTokens: 0,
1667
- cost: {
1668
- input: 0,
1669
- output: 0,
1670
- cacheRead: 0,
1671
- cacheWrite: 0,
1672
- total: 0
1673
- }
1674
- },
1675
- stopReason: "stop",
1676
- time: {
1677
- created: Date.now(),
1678
- completed: Date.now()
1679
- }
1680
- });
1681
- try {
1682
- let client;
1683
- let isOAuthToken;
1684
- if (options?.client) {
1685
- client = options.client;
1686
- isOAuthToken = false;
1687
- } else {
1688
- const apiKey = options?.apiKey ?? /* @__PURE__ */ getEnvApiKey(model.provider);
1689
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
1690
- const created = createClient$1(model, apiKey, options?.interleavedThinking ?? true, options?.headers);
1691
- client = created.client;
1692
- isOAuthToken = created.isOAuthToken;
1693
- }
1694
- let params = buildParams$1(model, context, isOAuthToken, options);
1695
- const nextParams = await options?.onPayload?.(params, model);
1696
- if (nextParams !== void 0) params = nextParams;
1697
- const anthropicStream = client.messages.stream({
1698
- ...params,
1699
- stream: true
1700
- }, { signal: options?.signal });
1701
- stream.push({
1702
- type: "start",
1703
- partial: output
1704
- });
1705
- const blocks = output.parts;
1706
- for await (const event of anthropicStream) if (event.type === "message_start") {
1707
- output.responseId = event.message.id;
1708
- output.usage.input = event.message.usage.input_tokens || 0;
1709
- output.usage.output = event.message.usage.output_tokens || 0;
1710
- output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
1711
- output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
1712
- output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
1713
- Model.calculateCost(model, output.usage);
1714
- } else if (event.type === "content_block_start") {
1715
- if (event.content_block.type === "text") {
1716
- const block = {
1717
- type: "text",
1718
- text: "",
1719
- index: event.index
1720
- };
1721
- output.parts.push(block);
1722
- stream.push({
1723
- type: "text.start",
1724
- partIndex: output.parts.length - 1,
1725
- partial: output
1726
- });
1727
- } else if (event.content_block.type === "thinking") {
1728
- const block = {
1729
- type: "thinking",
1730
- thinking: "",
1731
- thinkingSignature: "",
1732
- index: event.index
1733
- };
1734
- output.parts.push(block);
1735
- stream.push({
1736
- type: "thinking.start",
1737
- partIndex: output.parts.length - 1,
1738
- partial: output
1739
- });
1740
- } else if (event.content_block.type === "redacted_thinking") {
1741
- const block = {
1742
- type: "thinking",
1743
- thinking: "[Reasoning redacted]",
1744
- thinkingSignature: event.content_block.data,
1745
- redacted: true,
1746
- index: event.index
1747
- };
1748
- output.parts.push(block);
1749
- stream.push({
1750
- type: "thinking.start",
1751
- partIndex: output.parts.length - 1,
1752
- partial: output
1753
- });
1754
- } else if (event.content_block.type === "tool_use") {
1755
- const block = {
1756
- type: "toolCall",
1757
- callID: event.content_block.id,
1758
- name: isOAuthToken ? fromClaudeCodeName(event.content_block.name, context.tools) : event.content_block.name,
1759
- arguments: event.content_block.input ?? {},
1760
- partialJson: "",
1761
- status: "pending",
1762
- time: {
1763
- start: Date.now(),
1764
- end: Date.now()
1765
- },
1766
- index: event.index
1767
- };
1768
- output.parts.push(block);
1769
- stream.push({
1770
- type: "toolcall.start",
1771
- partIndex: output.parts.length - 1,
1772
- partial: output
1773
- });
1774
- }
1775
- } else if (event.type === "content_block_delta") {
1776
- const partIndex = blocks.findIndex((b) => b.index === event.index);
1777
- const block = blocks[partIndex];
1778
- if (!block) continue;
1779
- if (event.delta.type === "text_delta" && block.type === "text") {
1780
- block.text += event.delta.text;
1781
- stream.push({
1782
- type: "text.delta",
1783
- partIndex,
1784
- delta: event.delta.text,
1785
- partial: output
1786
- });
1787
- } else if (event.delta.type === "thinking_delta" && block.type === "thinking") {
1788
- block.thinking += event.delta.thinking;
1789
- stream.push({
1790
- type: "thinking.delta",
1791
- partIndex,
1792
- delta: event.delta.thinking,
1793
- partial: output
1794
- });
1795
- } else if (event.delta.type === "input_json_delta" && block.type === "toolCall") {
1796
- block.partialJson += event.delta.partial_json;
1797
- block.arguments = parseStreamingJson(block.partialJson);
1798
- stream.push({
1799
- type: "toolcall.delta",
1800
- partIndex,
1801
- delta: event.delta.partial_json,
1802
- partial: output
1803
- });
1804
- } else if (event.delta.type === "signature_delta" && block.type === "thinking") {
1805
- block.thinkingSignature = block.thinkingSignature || "";
1806
- block.thinkingSignature += event.delta.signature;
1807
- }
1808
- } else if (event.type === "content_block_stop") {
1809
- const partIndex = blocks.findIndex((b) => b.index === event.index);
1810
- const block = blocks[partIndex];
1811
- if (block) {
1812
- delete block.index;
1813
- if (block.type === "text") stream.push({
1814
- type: "text.end",
1815
- partIndex,
1816
- content: block.text,
1817
- partial: output
1818
- });
1819
- else if (block.type === "thinking") stream.push({
1820
- type: "thinking.end",
1821
- partIndex,
1822
- content: block.thinking,
1823
- partial: output
1824
- });
1825
- else if (block.type === "toolCall") {
1826
- block.arguments = parseStreamingJson(block.partialJson);
1827
- delete block.partialJson;
1828
- stream.push({
1829
- type: "toolcall.end",
1830
- partIndex,
1831
- toolCall: block,
1832
- partial: output
1833
- });
1834
- }
1835
- }
1836
- } else if (event.type === "message_delta") {
1837
- if (event.delta.stop_reason) output.stopReason = mapStopReason$1(event.delta.stop_reason);
1838
- if (event.usage.input_tokens != null) output.usage.input = event.usage.input_tokens;
1839
- if (event.usage.output_tokens != null) output.usage.output = event.usage.output_tokens;
1840
- if (event.usage.cache_read_input_tokens != null) output.usage.cacheRead = event.usage.cache_read_input_tokens;
1841
- if (event.usage.cache_creation_input_tokens != null) output.usage.cacheWrite = event.usage.cache_creation_input_tokens;
1842
- output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
1843
- Model.calculateCost(model, output.usage);
1844
- }
1845
- if (options?.signal?.aborted) throw new Error("Request was aborted");
1846
- if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
1847
- output.time.completed = Date.now();
1848
- stream.push({
1849
- type: "done",
1850
- reason: output.stopReason,
1851
- message: output
1852
- });
1853
- stream.end();
1854
- } catch (error) {
1855
- for (const block of output.parts) delete block.index;
1856
- output.time.completed = Date.now();
1857
- output.stopReason = options?.signal?.aborted ? "aborted" : "error";
1858
- output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
1859
- stream.push({
1860
- type: "error",
1861
- reason: output.stopReason,
1862
- error: output
1863
- });
1864
- stream.end();
1865
- }
1866
- })();
1867
- return stream;
1868
- };
1869
- const streamSimpleAnthropic = (model, context, options) => {
1870
- const apiKey = options?.apiKey || /* @__PURE__ */ getEnvApiKey(model.provider);
1871
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
1872
- const base = Stream.buildBaseOptions(model, options, apiKey);
1873
- if (!options?.reasoning) return streamAnthropic(model, context, {
1874
- ...base,
1875
- thinkingEnabled: false
1876
- });
1877
- const adjusted = Stream.adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options.thinkingBudgets);
1878
- return streamAnthropic(model, context, {
1879
- ...base,
1880
- maxTokens: adjusted.maxTokens,
1881
- thinkingEnabled: true,
1882
- thinkingBudgetTokens: adjusted.thinkingBudget
1883
- });
1884
- };
1885
- const anthropicProtocolProvider = {
1886
- protocol: Model.KnownProtocolEnum.anthropicMessages,
1887
- stream: streamAnthropic,
1888
- streamSimple: streamSimpleAnthropic
1889
- };
1890
- //#endregion
1891
- //#region src/provider/providers/github/github.ts
1892
- function inferCopilotInitiator(messages) {
1893
- const last = messages[messages.length - 1];
1894
- return last && last.role !== "user" ? "agent" : "user";
1895
- }
1896
- function hasCopilotVisionInput(messages) {
1897
- return messages.some((msg) => {
1898
- if (msg.role === "user") return msg.parts.some((c) => c.type === "image");
1899
- return false;
1900
- });
1901
- }
1902
- function buildCopilotDynamicHeaders(params) {
1903
- const headers = {
1904
- "X-Initiator": inferCopilotInitiator(params.messages),
1905
- "Openai-Intent": "conversation-edits"
1906
- };
1907
- if (params.hasImages) headers["Copilot-Vision-Request"] = "true";
1908
- return headers;
1909
- }
1910
- //#endregion
1911
- //#region src/provider/providers/openai/completions.ts
1912
- function hasToolHistory(messages) {
1913
- for (const msg of messages) {
1914
- if (msg.role !== "assistant") continue;
1915
- if (msg.parts.some((block) => block.type === "toolCall")) return true;
1916
- }
1917
- return false;
1918
- }
1919
- function buildSyntheticToolResult(block, compat) {
1920
- const message = {
1921
- role: "tool",
1922
- content: [
1923
- "<result>",
1924
- "No Result Provided",
1925
- "</result>"
1926
- ].join("\n"),
1927
- tool_call_id: block.callID
1928
- };
1929
- if (compat.requiresToolResultName) message.name = block.name;
1930
- return message;
1931
- }
1932
- function resolveBaseUrl(model) {
1933
- return model.baseUrl || (model.provider.id === Provider.KnownProviderEnum.openai ? "https://api.openai.com/v1" : "");
1934
- }
1935
- const streamOpenAICompletions = (model, context, options) => {
1936
- const stream = new AssistantMessageEventStream();
1937
- (async () => {
1938
- const output = Message.createAssistantMessage({
1939
- role: "assistant",
1940
- parts: [],
1941
- protocol: model.protocol,
1942
- provider: model.provider,
1943
- model: model.id,
1944
- usage: {
1945
- input: 0,
1946
- output: 0,
1947
- cacheRead: 0,
1948
- cacheWrite: 0,
1949
- totalTokens: 0,
1950
- cost: {
1951
- input: 0,
1952
- output: 0,
1953
- cacheRead: 0,
1954
- cacheWrite: 0,
1955
- total: 0
1956
- }
1957
- },
1958
- stopReason: "stop",
1959
- time: {
1960
- created: Date.now(),
1961
- completed: Date.now()
1962
- }
1963
- });
1964
- try {
1965
- const client = createClient(model, context, options?.apiKey || /* @__PURE__ */ getEnvApiKey(model.provider) || "", options?.headers);
1966
- let params = buildParams(model, context, options);
1967
- const nextParams = await options?.onPayload?.(params, model);
1968
- if (nextParams !== void 0) params = nextParams;
1969
- const openaiStream = await client.chat.completions.create(params, { signal: options?.signal });
1970
- stream.push({
1971
- type: "start",
1972
- partial: output
1973
- });
1974
- let currentBlock = null;
1975
- const blocks = output.parts;
1976
- const activeToolCalls = /* @__PURE__ */ new Map();
1977
- const finishCurrentBlock = (block) => {
1978
- if (block) {
1979
- const partIndex = block.index ?? blocks.indexOf(block);
1980
- delete block.index;
1981
- if (block.type === "text") stream.push({
1982
- type: "text.end",
1983
- partIndex,
1984
- content: block.text,
1985
- partial: output
1986
- });
1987
- else if (block.type === "thinking") stream.push({
1988
- type: "thinking.end",
1989
- partIndex,
1990
- content: block.thinking,
1991
- partial: output
1992
- });
1993
- else if (block.type === "toolCall") {
1994
- if (block.streamIndex !== void 0) activeToolCalls.delete(block.streamIndex);
1995
- block.arguments = parseStreamingJson(block.partialArgs);
1996
- delete block.partialArgs;
1997
- delete block.streamIndex;
1998
- stream.push({
1999
- type: "toolcall.end",
2000
- partIndex,
2001
- toolCall: block,
2002
- partial: output
2003
- });
2004
- }
2005
- }
2006
- };
2007
- const flushActiveToolCalls = () => {
2008
- for (const toolBlock of [...activeToolCalls.values()].sort((a, b) => (a.index ?? 0) - (b.index ?? 0))) finishCurrentBlock(toolBlock);
2009
- };
2010
- for await (const chunk of openaiStream) {
2011
- if (!chunk || typeof chunk !== "object") continue;
2012
- output.responseId ||= chunk.id;
2013
- if (chunk.usage) output.usage = parseChunkUsage(chunk.usage, model);
2014
- const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
2015
- if (!choice) continue;
2016
- const choiceWithUsage = choice;
2017
- if (!chunk.usage && choiceWithUsage.usage) output.usage = parseChunkUsage(choiceWithUsage.usage, model);
2018
- if (choice.finish_reason) {
2019
- const finishReasonResult = mapStopReason(choice.finish_reason);
2020
- output.stopReason = finishReasonResult.stopReason;
2021
- if (finishReasonResult.errorMessage) output.errorMessage = finishReasonResult.errorMessage;
2022
- }
2023
- if (!choice.delta) continue;
2024
- if (choice.delta.content !== null && choice.delta.content !== void 0 && choice.delta.content.length > 0) {
2025
- if (activeToolCalls.size > 0) flushActiveToolCalls();
2026
- if (!currentBlock || currentBlock.type !== "text") {
2027
- finishCurrentBlock(currentBlock);
2028
- currentBlock = {
2029
- type: "text",
2030
- text: "",
2031
- index: output.parts.length
2032
- };
2033
- output.parts.push(currentBlock);
2034
- stream.push({
2035
- type: "text.start",
2036
- partIndex: currentBlock.index,
2037
- partial: output
2038
- });
2039
- }
2040
- if (currentBlock.type === "text") {
2041
- currentBlock.text += choice.delta.content;
2042
- stream.push({
2043
- type: "text.delta",
2044
- partIndex: currentBlock.index,
2045
- delta: choice.delta.content,
2046
- partial: output
2047
- });
2048
- }
2049
- }
2050
- const reasoningFields = [
2051
- "reasoning_content",
2052
- "reasoning",
2053
- "reasoning_text"
2054
- ];
2055
- let foundReasoningField = null;
2056
- for (const field of reasoningFields) {
2057
- const value = choice.delta[field];
2058
- if (typeof value === "string" && value.length > 0) {
2059
- foundReasoningField = field;
2060
- break;
2061
- }
2062
- }
2063
- if (foundReasoningField) {
2064
- if (activeToolCalls.size > 0) flushActiveToolCalls();
2065
- if (!currentBlock || currentBlock.type !== "thinking") {
2066
- finishCurrentBlock(currentBlock);
2067
- currentBlock = {
2068
- type: "thinking",
2069
- thinking: "",
2070
- thinkingSignature: foundReasoningField,
2071
- index: output.parts.length
2072
- };
2073
- output.parts.push(currentBlock);
2074
- stream.push({
2075
- type: "thinking.start",
2076
- partIndex: currentBlock.index,
2077
- partial: output
2078
- });
2079
- }
2080
- if (currentBlock.type === "thinking") {
2081
- const delta = choice.delta[foundReasoningField];
2082
- if (typeof delta === "string") {
2083
- currentBlock.thinking += delta;
2084
- stream.push({
2085
- type: "thinking.delta",
2086
- partIndex: currentBlock.index,
2087
- delta,
2088
- partial: output
2089
- });
2090
- }
2091
- }
2092
- }
2093
- if (choice.delta.tool_calls) {
2094
- if (currentBlock) {
2095
- finishCurrentBlock(currentBlock);
2096
- currentBlock = null;
2097
- }
2098
- for (const toolCall of choice.delta.tool_calls) {
2099
- const streamIndex = toolCall.index ?? activeToolCalls.size;
2100
- let toolBlock = activeToolCalls.get(streamIndex);
2101
- if (!toolBlock) {
2102
- toolBlock = {
2103
- type: "toolCall",
2104
- callID: toolCall.id || "",
2105
- name: toolCall.function?.name || "",
2106
- arguments: {},
2107
- partialArgs: "",
2108
- index: output.parts.length,
2109
- streamIndex,
2110
- status: "pending",
2111
- time: {
2112
- start: Date.now(),
2113
- end: Date.now()
2114
- }
2115
- };
2116
- activeToolCalls.set(streamIndex, toolBlock);
2117
- output.parts.push(toolBlock);
2118
- stream.push({
2119
- type: "toolcall.start",
2120
- partIndex: toolBlock.index,
2121
- partial: output
2122
- });
2123
- }
2124
- if (toolCall.id) toolBlock.callID = toolCall.id;
2125
- if (toolCall.function?.name) toolBlock.name = toolCall.function.name;
2126
- let delta = "";
2127
- if (toolCall.function?.arguments) {
2128
- delta = toolCall.function.arguments;
2129
- toolBlock.partialArgs = (toolBlock.partialArgs || "") + delta;
2130
- toolBlock.arguments = parseStreamingJson(toolBlock.partialArgs);
2131
- }
2132
- toolBlock.time.end = Date.now();
2133
- stream.push({
2134
- type: "toolcall.delta",
2135
- partIndex: toolBlock.index,
2136
- delta,
2137
- partial: output
2138
- });
2139
- }
2140
- }
2141
- const reasoningDetails = choice.delta.reasoning_details;
2142
- if (reasoningDetails && Array.isArray(reasoningDetails)) {
2143
- for (const detail of reasoningDetails) if (detail.type === "reasoning.encrypted" && typeof detail.id === "string" && detail.data !== void 0) {
2144
- const matchingToolCall = output.parts.find((block) => block.type === "toolCall" && block.callID === detail.id);
2145
- if (matchingToolCall) matchingToolCall.thoughtSignature = JSON.stringify(detail);
2146
- }
2147
- }
2148
- }
2149
- finishCurrentBlock(currentBlock);
2150
- flushActiveToolCalls();
2151
- if (options?.signal?.aborted) throw new Error("Request was aborted");
2152
- if (output.stopReason === "aborted") throw new Error("Request was aborted");
2153
- if (output.stopReason === "error") throw new Error(output.errorMessage || "Provider returned an error stop reason");
2154
- output.time.completed = Date.now();
2155
- stream.push({
2156
- type: "done",
2157
- reason: output.stopReason,
2158
- message: output
2159
- });
2160
- stream.end();
2161
- } catch (error) {
2162
- for (const block of output.parts) {
2163
- delete block.index;
2164
- delete block.partialArgs;
2165
- delete block.streamIndex;
2166
- }
2167
- output.time.completed = Date.now();
2168
- output.stopReason = options?.signal?.aborted ? "aborted" : "error";
2169
- output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
2170
- const rawMetadata = error?.error?.metadata?.raw;
2171
- if (rawMetadata) output.errorMessage += `\n${rawMetadata}`;
2172
- stream.push({
2173
- type: "error",
2174
- reason: output.stopReason,
2175
- error: output
2176
- });
2177
- stream.end();
2178
- }
2179
- })();
2180
- return stream;
2181
- };
2182
- const streamSimpleOpenAICompletions = (model, context, options) => {
2183
- const apiKey = options?.apiKey || /* @__PURE__ */ getEnvApiKey(model.provider);
2184
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
2185
- const base = Stream.buildBaseOptions(model, options, apiKey);
2186
- const simpleReasoning = Model.supportsXhigh(model) ? options?.reasoning : Stream.clampReasoning(options?.reasoning);
2187
- const reasoningEffort = simpleReasoning && simpleReasoning !== Stream.ThinkingLevelEnum.off ? simpleReasoning : void 0;
2188
- const toolChoice = options?.toolChoice;
2189
- return streamOpenAICompletions(model, context, {
2190
- ...base,
2191
- reasoningEffort,
2192
- toolChoice
2193
- });
2194
- };
2195
- function buildParams(model, context, options) {
2196
- const compat = getCompat(model);
2197
- const messages = convertMessages(model, context, compat);
2198
- maybeAddOpenRouterAnthropicCacheControl(model, messages);
2199
- const baseUrl = resolveBaseUrl(model);
2200
- const params = {
2201
- model: model.id,
2202
- messages,
2203
- stream: true
2204
- };
2205
- if (compat.supportsUsageInStreaming !== false) params.stream_options = { include_usage: true };
2206
- if (compat.supportsStore) params.store = false;
2207
- if (options?.maxTokens) if (compat.maxTokensField === "max_tokens") params.max_tokens = options.maxTokens;
2208
- else params.max_completion_tokens = options.maxTokens;
2209
- if (options?.temperature !== void 0) params.temperature = options.temperature;
2210
- if (context.tools) {
2211
- params.tools = convertTools(context.tools, compat);
2212
- if (compat.zaiToolStream) params.tool_stream = true;
2213
- } else if (hasToolHistory(context.messages)) params.tools = [];
2214
- if (options?.toolChoice) params.tool_choice = options.toolChoice;
2215
- if ((compat.thinkingFormat === "zai" || compat.thinkingFormat === "qwen") && model.reasoning) params.enable_thinking = !!options?.reasoningEffort;
2216
- else if (compat.thinkingFormat === "qwen-chat-template" && model.reasoning) params.chat_template_kwargs = { enable_thinking: !!options?.reasoningEffort };
2217
- else if (compat.thinkingFormat === "openrouter" && model.reasoning) {
2218
- const openRouterParams = params;
2219
- if (options?.reasoningEffort) openRouterParams.reasoning = { effort: mapReasoningEffort(options.reasoningEffort, compat.reasoningEffortMap) };
2220
- else openRouterParams.reasoning = { effort: "none" };
2221
- } else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) params.reasoning_effort = mapReasoningEffort(options.reasoningEffort, compat.reasoningEffortMap);
2222
- if (baseUrl.includes("openrouter.ai") && model.compat?.openRouterRouting) params.provider = model.compat.openRouterRouting;
2223
- if (baseUrl.includes("ai-gateway.vercel.sh") && model.compat?.vercelGatewayRouting) {
2224
- const routing = model.compat.vercelGatewayRouting;
2225
- if (routing.only || routing.order) {
2226
- const gatewayOptions = {};
2227
- if (routing.only) gatewayOptions.only = routing.only;
2228
- if (routing.order) gatewayOptions.order = routing.order;
2229
- params.providerOptions = { gateway: gatewayOptions };
2230
- }
2231
- }
2232
- return params;
2233
- }
2234
- function createClient(model, context, apiKey, optsHeaders) {
2235
- const baseUrl = resolveBaseUrl(model);
2236
- if (!apiKey) {
2237
- if (!process.env.OPENAI_API_KEY) throw new Error("OpenAI API key is required. set OPENAI_API_KEY environment variable or pass it as an argument");
2238
- apiKey = process.env.OPENAI_API_KEY;
2239
- }
2240
- const headers = { ...model.headers };
2241
- if (model.provider.id === Provider.KnownProviderEnum.githubCopilot) {
2242
- const hasImages = hasCopilotVisionInput(context.messages);
2243
- const copilotHeaders = buildCopilotDynamicHeaders({
2244
- messages: context.messages,
2245
- hasImages
2246
- });
2247
- Object.assign(headers, copilotHeaders);
2248
- }
2249
- if (optsHeaders) Object.assign(headers, optsHeaders);
2250
- return new OpenAI({
2251
- apiKey,
2252
- baseURL: baseUrl,
2253
- dangerouslyAllowBrowser: true,
2254
- defaultHeaders: headers
2255
- });
2256
- }
2257
- function mapReasoningEffort(effort, reasoningEffortMap) {
2258
- return reasoningEffortMap[effort] ?? effort;
2259
- }
2260
- function maybeAddOpenRouterAnthropicCacheControl(model, messages) {
2261
- if (model.provider.id !== Provider.KnownProviderEnum.openrouter || !model.id.startsWith("anthropic/")) return;
2262
- for (let i = messages.length - 1; i >= 0; i--) {
2263
- const msg = messages[i];
2264
- if (!msg) continue;
2265
- if (msg.role !== "user" && msg.role !== "assistant") continue;
2266
- const content = msg.content;
2267
- if (typeof content === "string") {
2268
- msg.content = [Object.assign({
2269
- type: "text",
2270
- text: content
2271
- }, { cache_control: { type: "ephemeral" } })];
2272
- return;
2273
- }
2274
- if (!Array.isArray(content)) continue;
2275
- for (let j = content.length - 1; j >= 0; j--) {
2276
- const part = content[j];
2277
- if (part?.type === "text") {
2278
- Object.assign(part, { cache_control: { type: "ephemeral" } });
2279
- return;
2280
- }
2281
- }
2282
- }
2283
- }
2284
- function convertMessages(model, context, compat) {
2285
- const params = [];
2286
- const normalizeToolCallId = (id) => {
2287
- if (id.includes("|")) return (id.split("|")[0] ?? id).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 40);
2288
- if (model.provider.id === Provider.KnownProviderEnum.openai) return id.length > 40 ? id.slice(0, 40) : id;
2289
- return id;
2290
- };
2291
- const transformedMessages = Message.transformMessages(context.messages, model, normalizeToolCallId);
2292
- if (context.systemPrompt) {
2293
- const role = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
2294
- params.push({
2295
- role,
2296
- content: sanitizeSurrogates(context.systemPrompt)
2297
- });
2298
- }
2299
- let lastRole = null;
2300
- for (const msg of transformedMessages) {
2301
- if (compat.requiresAssistantAfterToolResult && lastRole === "tool" && msg.role === "user") {
2302
- params.push({
2303
- role: "assistant",
2304
- content: "I have processed the tool results."
2305
- });
2306
- lastRole = "assistant";
2307
- }
2308
- if (msg.role === "user") {
2309
- const content = msg.parts.flatMap((item) => {
2310
- if (item.type === "text") {
2311
- const text = sanitizeSurrogates(item.text);
2312
- if (text.trim().length === 0) return [];
2313
- return [{
2314
- type: "text",
2315
- text
2316
- }];
2317
- }
2318
- if (!model.input.includes("image")) return [];
2319
- return [{
2320
- type: "image_url",
2321
- image_url: { url: `data:${item.mimeType};base64,${item.data}` }
2322
- }];
2323
- });
2324
- if (content.length === 0) continue;
2325
- params.push({
2326
- role: "user",
2327
- content
2328
- });
2329
- lastRole = "user";
2330
- continue;
2331
- }
2332
- const assistantMsg = {
2333
- role: "assistant",
2334
- content: compat.requiresAssistantAfterToolResult ? "" : null
2335
- };
2336
- const textSegments = msg.parts.filter((block) => block.type === "text").map((block) => sanitizeSurrogates(block.text)).filter((text) => text.trim().length > 0);
2337
- const nonEmptyThinkingBlocks = msg.parts.filter((block) => block.type === "thinking").filter((block) => block.thinking.trim().length > 0);
2338
- if (compat.requiresThinkingAsText && nonEmptyThinkingBlocks.length > 0) textSegments.unshift(...nonEmptyThinkingBlocks.map((block) => sanitizeSurrogates(block.thinking)));
2339
- else if (nonEmptyThinkingBlocks.length > 0) {
2340
- const signature = nonEmptyThinkingBlocks[0]?.thinkingSignature;
2341
- if (signature && signature.length > 0) assistantMsg[signature] = nonEmptyThinkingBlocks.map((block) => sanitizeSurrogates(block.thinking)).join("\n");
2342
- }
2343
- if (textSegments.length > 0) assistantMsg.content = textSegments.join("");
2344
- const toolCalls = msg.parts.filter((block) => block.type === "toolCall");
2345
- if (toolCalls.length > 0) {
2346
- assistantMsg.tool_calls = toolCalls.map((toolCall) => ({
2347
- id: toolCall.callID,
2348
- type: "function",
2349
- function: {
2350
- name: toolCall.name,
2351
- arguments: JSON.stringify(toolCall.arguments)
2352
- }
2353
- }));
2354
- const reasoningDetails = toolCalls.filter((toolCall) => toolCall.thoughtSignature).map((toolCall) => {
2355
- try {
2356
- return JSON.parse(toolCall.thoughtSignature);
2357
- } catch {
2358
- return null;
2359
- }
2360
- }).filter(Boolean);
2361
- if (reasoningDetails.length > 0) assistantMsg.reasoning_details = reasoningDetails;
2362
- }
2363
- const assistantContent = assistantMsg.content;
2364
- if (!(assistantContent !== null && assistantContent !== void 0 && (typeof assistantContent === "string" ? assistantContent.length > 0 : assistantContent.length > 0)) && !assistantMsg.tool_calls) continue;
2365
- params.push(assistantMsg);
2366
- lastRole = "assistant";
2367
- const imageBlocks = [];
2368
- for (const toolCall of toolCalls) {
2369
- if (toolCall.status === "pending" || toolCall.status === "running") {
2370
- params.push(buildSyntheticToolResult(toolCall, compat));
2371
- lastRole = "tool";
2372
- continue;
2373
- }
2374
- const textResult = toolCall.result.content.filter((content) => content.type === "text").map((content) => content.text).join("\n");
2375
- const hasImages = toolCall.result.content.some((content) => content.type === "image");
2376
- const toolResultMsg = {
2377
- role: "tool",
2378
- content: sanitizeSurrogates(textResult.length > 0 ? textResult : "(see attached image)"),
2379
- tool_call_id: toolCall.callID
2380
- };
2381
- if (compat.requiresToolResultName) toolResultMsg.name = toolCall.name;
2382
- params.push(toolResultMsg);
2383
- lastRole = "tool";
2384
- if (hasImages && model.input.includes("image")) {
2385
- for (const block of toolCall.result.content) if (block.type === "image") imageBlocks.push({
2386
- type: "image_url",
2387
- image_url: { url: `data:${block.mimeType};base64,${block.data}` }
2388
- });
2389
- }
2390
- }
2391
- if (imageBlocks.length > 0) {
2392
- if (compat.requiresAssistantAfterToolResult) params.push({
2393
- role: "assistant",
2394
- content: "I have processed the tool results."
2395
- });
2396
- params.push({
2397
- role: "user",
2398
- content: [{
2399
- type: "text",
2400
- text: "Attached image(s) from tool result:"
2401
- }, ...imageBlocks]
2402
- });
2403
- lastRole = "user";
2404
- }
2405
- }
2406
- return params;
2407
- }
2408
- function convertTools(tools, compat) {
2409
- return tools.map((tool) => ({
2410
- type: "function",
2411
- function: {
2412
- name: tool.name,
2413
- description: tool.description,
2414
- parameters: tool.parameters,
2415
- ...compat.supportsStrictMode !== false && { strict: false }
2416
- }
2417
- }));
2418
- }
2419
- function parseChunkUsage(rawUsage, model) {
2420
- const promptTokens = rawUsage.prompt_tokens || 0;
2421
- const reportedCachedTokens = rawUsage.prompt_tokens_details?.cached_tokens || 0;
2422
- const cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;
2423
- const reasoningTokens = rawUsage.completion_tokens_details?.reasoning_tokens || 0;
2424
- const cacheReadTokens = cacheWriteTokens > 0 ? Math.max(0, reportedCachedTokens - cacheWriteTokens) : reportedCachedTokens;
2425
- const input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);
2426
- const outputTokens = (rawUsage.completion_tokens || 0) + reasoningTokens;
2427
- const usage = {
2428
- input,
2429
- output: outputTokens,
2430
- cacheRead: cacheReadTokens,
2431
- cacheWrite: cacheWriteTokens,
2432
- totalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,
2433
- cost: {
2434
- input: 0,
2435
- output: 0,
2436
- cacheRead: 0,
2437
- cacheWrite: 0,
2438
- total: 0
2439
- }
2440
- };
2441
- Model.calculateCost(model, usage);
2442
- return usage;
2443
- }
2444
- function mapStopReason(reason) {
2445
- if (reason === null) return { stopReason: "stop" };
2446
- switch (reason) {
2447
- case "stop":
2448
- case "end": return { stopReason: "stop" };
2449
- case "length": return { stopReason: "length" };
2450
- case "function_call":
2451
- case "tool_calls": return { stopReason: "toolUse" };
2452
- case "content_filter": return {
2453
- stopReason: "error",
2454
- errorMessage: "Provider finish_reason: content_filter"
2455
- };
2456
- case "network_error": return {
2457
- stopReason: "error",
2458
- errorMessage: "Provider finish_reason: network_error"
2459
- };
2460
- default: return {
2461
- stopReason: "error",
2462
- errorMessage: `Provider finish_reason: ${reason}`
2463
- };
2464
- }
2465
- }
2466
- function detectCompat(model) {
2467
- const provider = model.provider.id;
2468
- const baseUrl = resolveBaseUrl(model);
2469
- const isZai = provider === "zai" || baseUrl.includes("api.z.ai");
2470
- const isNonStandard = provider === "cerebras" || baseUrl.includes("cerebras.ai") || provider === "xai" || baseUrl.includes("api.x.ai") || baseUrl.includes("chutes.ai") || baseUrl.includes("deepseek.com") || isZai || provider === "opencode" || baseUrl.includes("opencode.ai");
2471
- const useMaxTokens = baseUrl.includes("chutes.ai");
2472
- const isGrok = provider === "xai" || baseUrl.includes("api.x.ai");
2473
- const reasoningEffortMap = (provider === "groq" || baseUrl.includes("groq.com")) && model.id === "qwen/qwen3-32b" ? {
2474
- minimal: "default",
2475
- low: "default",
2476
- medium: "default",
2477
- high: "default",
2478
- xhigh: "default"
2479
- } : {};
2480
- return {
2481
- supportsStore: !isNonStandard,
2482
- supportsDeveloperRole: !isNonStandard,
2483
- supportsReasoningEffort: !isGrok && !isZai,
2484
- reasoningEffortMap,
2485
- supportsUsageInStreaming: true,
2486
- maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
2487
- requiresToolResultName: false,
2488
- requiresAssistantAfterToolResult: false,
2489
- requiresThinkingAsText: false,
2490
- thinkingFormat: isZai ? "zai" : provider === "openrouter" || baseUrl.includes("openrouter.ai") ? "openrouter" : "openai",
2491
- openRouterRouting: {},
2492
- vercelGatewayRouting: {},
2493
- zaiToolStream: false,
2494
- supportsStrictMode: true
2495
- };
2496
- }
2497
- /**
2498
- * Get resolved compatibility settings for a model.
2499
- * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.
2500
- */
2501
- function getCompat(model) {
2502
- const detected = detectCompat(model);
2503
- if (!model.compat) return detected;
2504
- return {
2505
- supportsStore: model.compat.supportsStore ?? detected.supportsStore,
2506
- supportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,
2507
- supportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,
2508
- reasoningEffortMap: model.compat.reasoningEffortMap ?? detected.reasoningEffortMap,
2509
- supportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,
2510
- maxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,
2511
- requiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,
2512
- requiresAssistantAfterToolResult: model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,
2513
- requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
2514
- thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
2515
- openRouterRouting: model.compat.openRouterRouting ?? {},
2516
- vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
2517
- zaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,
2518
- supportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode
2519
- };
2520
- }
2521
- const openAICompletionsProtocolProvider = {
2522
- protocol: Model.KnownProtocolEnum.openaiCompletions,
2523
- stream: streamOpenAICompletions,
2524
- streamSimple: streamSimpleOpenAICompletions
2525
- };
2526
- //#endregion
2527
- //#region src/provider/register.ts
2528
- Stream.registerProtocolProvider(anthropicProtocolProvider, "providers/anthropic/index.ts");
2529
- Stream.registerProtocolProvider(openAICompletionsProtocolProvider, "providers/openai/completions.ts");
2530
- //#endregion
2531
- //#region src/agent/agent.ts
2532
- let Agent;
2533
- (function(_Agent) {
2534
- _Agent.ToolTerminalResultSchema = Type.Union([Message.ToolCompletedSchema, Message.ToolErrorSchema]);
2535
- _Agent.ToolResultSchema = Type.Union([
2536
- Message.ToolRunningSchema,
2537
- Message.ToolCompletedSchema,
2538
- Message.ToolErrorSchema
2539
- ]);
2540
- function defineTool(tool) {
2541
- return tool;
2542
- }
2543
- _Agent.defineTool = defineTool;
2544
- _Agent.ToolCallInFlightSchema = Type.Object({
2545
- callID: Type.String(),
2546
- name: Type.String(),
2547
- rawArgs: Type.Record(Type.String(), Type.Unknown()),
2548
- args: Type.Optional(Type.Unknown())
2549
- });
2550
- const ModelNotFoundErr = _Agent.ModelNotFoundErr = NamedError.create("ModelNotFoundErr", Type.Object({
2551
- message: Type.String(),
2552
- provider: Type.String(),
2553
- model: Type.String()
2554
- }));
2555
- const ModelNotConfiguredErr = _Agent.ModelNotConfiguredErr = NamedError.create("ModelNotConfiguredErr", Type.Object({ message: Type.String() }));
2556
- const AgentInStreamingErr = _Agent.AgentInStreamingErr = NamedError.create("AgentInStreamingErr", Type.Object({
2557
- message: Type.String(),
2558
- name: Type.String()
2559
- }));
2560
- class Instance {
2561
- _state;
2562
- listeners = /* @__PURE__ */ new Set();
2563
- abortController;
2564
- convertToLlm;
2565
- transformContext;
2566
- steeringQueue = [];
2567
- followUpQueue = [];
2568
- steeringMode;
2569
- followUpMode;
2570
- streamFn;
2571
- _sessionId;
2572
- getApiKey;
2573
- _onPayload;
2574
- runningPrompt;
2575
- resolveRunningPrompt;
2576
- _thinkingBudgets;
2577
- _transport;
2578
- _maxRetryDelayMs;
2579
- _toolExecution;
2580
- _beforeToolExecution;
2581
- _afterToolExecution;
2582
- constructor(name, model, opts = {}) {
2583
- this._state = {
2584
- systemPrompt: "",
2585
- thinkingLevel: "off",
2586
- tools: [],
2587
- messages: [],
2588
- isStreaming: false,
2589
- streamMessage: null,
2590
- pendingToolCalls: /* @__PURE__ */ new Set(),
2591
- error: void 0,
2592
- ...opts.initialState,
2593
- name,
2594
- model
2595
- };
2596
- /**
2597
- * Transformation logic to prepare messages for the LLM.
2598
- * * @remarks
2599
- * Currently just forwards messages as-is. Modify this logic when
2600
- * specific formatting or filtering is required.
2601
- * A good example is using user message parts with custom content
2602
- * * @default
2603
- * forwards messages as is.
2604
- */
2605
- this.convertToLlm = opts.convertToLlm || ((messages) => messages);
2606
- this.transformContext = opts.transformContext;
2607
- this.steeringMode = opts.steeringMode || "one-at-a-time";
2608
- this.followUpMode = opts.followUpMode || "one-at-a-time";
2609
- this.streamFn = opts.streamFn || Stream.streamSimple;
2610
- this._sessionId = opts.sessionId;
2611
- this.getApiKey = opts.getApiKey;
2612
- this._onPayload = opts.onPayload;
2613
- this._thinkingBudgets = opts.thinkingBudgets;
2614
- this._transport = opts.transport ?? "sse";
2615
- this._maxRetryDelayMs = opts.maxRetryDelayMs;
2616
- this._toolExecution = opts.toolExecution ?? "parallel";
2617
- this._beforeToolExecution = opts.beforeToolExecution;
2618
- this._afterToolExecution = opts.afterToolExecution;
2619
- }
2620
- /**
2621
- * Get the current session ID used for provider caching.
2622
- */
2623
- get sessionId() {
2624
- return this._sessionId;
2625
- }
2626
- /**
2627
- * Set the session ID for provider caching.
2628
- * Call this when switching sessions (new session, branch, resume, etc).
2629
- */
2630
- set sessionId(value) {
2631
- this._sessionId = value;
2632
- }
2633
- /**
2634
- * Get the current thinking budgets.
2635
- */
2636
- get thinkingBudgets() {
2637
- return this._thinkingBudgets;
2638
- }
2639
- /**
2640
- * Set custom thinking budgets for token-based providers.
2641
- */
2642
- set thinkingBudgets(value) {
2643
- this._thinkingBudgets = value;
2644
- }
2645
- /**
2646
- * Get the current preferred transport.
2647
- */
2648
- get transport() {
2649
- return this._transport;
2650
- }
2651
- /**
2652
- * Set the preferred transport.
2653
- */
2654
- setTransport(value) {
2655
- this._transport = value;
2656
- }
2657
- /**
2658
- * Get the current max retry delay in milliseconds.
2659
- */
2660
- get maxRetryDelayMs() {
2661
- return this._maxRetryDelayMs;
2662
- }
2663
- /**
2664
- * Set the maximum delay to wait for server-requested retries.
2665
- * Set to 0 to disable the cap.
2666
- */
2667
- set maxRetryDelayMs(value) {
2668
- this._maxRetryDelayMs = value;
2669
- }
2670
- get toolExecution() {
2671
- return this._toolExecution;
2672
- }
2673
- setToolExecution(value) {
2674
- this._toolExecution = value;
2675
- }
2676
- setBeforeToolExecution(value) {
2677
- this._beforeToolExecution = value;
2678
- }
2679
- setAfterToolExecution(value) {
2680
- this._afterToolExecution = value;
2681
- }
2682
- get state() {
2683
- return this._state;
2684
- }
2685
- subscribe(fn) {
2686
- this.listeners.add(fn);
2687
- return () => this.listeners.delete(fn);
2688
- }
2689
- setSystemPrompt(v) {
2690
- this._state.systemPrompt = v;
2691
- }
2692
- setModel(m) {
2693
- this._state.model = m;
2694
- }
2695
- setThinkingLevel(l) {
2696
- this._state.thinkingLevel = l;
2697
- }
2698
- setSteeringMode(mode) {
2699
- this.steeringMode = mode;
2700
- }
2701
- getSteeringMode() {
2702
- return this.steeringMode;
2703
- }
2704
- setFollowUpMode(mode) {
2705
- this.followUpMode = mode;
2706
- }
2707
- getFollowUpMode() {
2708
- return this.followUpMode;
2709
- }
2710
- setTools(t) {
2711
- this._state.tools = t;
2712
- }
2713
- replaceMessages(ms) {
2714
- this._state.messages = ms.slice();
2715
- }
2716
- appendMessage(m) {
2717
- this._state.messages = [...this._state.messages, m];
2718
- }
2719
- findMessageIndexById(messageId) {
2720
- return this._state.messages.findIndex((message) => message.messageId === messageId);
2721
- }
2722
- replaceMessageById(message) {
2723
- const messageIndex = this.findMessageIndexById(message.messageId);
2724
- if (messageIndex === -1) return false;
2725
- const messages = this._state.messages.slice();
2726
- messages[messageIndex] = message;
2727
- this._state.messages = messages;
2728
- return true;
2729
- }
2730
- upsertMessage(message) {
2731
- if (this.replaceMessageById(message)) return;
2732
- this.appendMessage(message);
2733
- }
2734
- patchStoredAssistantPart(messageId, partIndex, part) {
2735
- const messageIndex = this.findMessageIndexById(messageId);
2736
- if (messageIndex === -1) return false;
2737
- const messages = this._state.messages.slice();
2738
- const existing = messages[messageIndex];
2739
- if (!existing || existing.role !== "assistant") return false;
2740
- const nextParts = existing.parts.slice();
2741
- nextParts[partIndex] = part;
2742
- messages[messageIndex] = {
2743
- ...existing,
2744
- parts: nextParts
2745
- };
2746
- this._state.messages = messages;
2747
- return true;
2748
- }
2749
- /**
2750
- * Queue a steering message while the agent is running.
2751
- * Delivered after the current assistant turn finishes executing its tool calls,
2752
- * before the next LLM call.
2753
- */
2754
- steer(m) {
2755
- this.steeringQueue.push(m);
2756
- }
2757
- /**
2758
- * Queue a follow-up message to be processed after the agent finishes.
2759
- * Delivered only when agent has no more tool calls or steering messages.
2760
- */
2761
- followUp(m) {
2762
- this.followUpQueue.push(m);
2763
- }
2764
- clearSteeringQueue() {
2765
- this.steeringQueue = [];
2766
- }
2767
- clearFollowUpQueue() {
2768
- this.followUpQueue = [];
2769
- }
2770
- clearAllQueues() {
2771
- this.steeringQueue = [];
2772
- this.followUpQueue = [];
2773
- }
2774
- hasQueuedMessages() {
2775
- return this.steeringQueue.length > 0 || this.followUpQueue.length > 0;
2776
- }
2777
- dequeueSteeringMessages() {
2778
- if (this.steeringMode === "one-at-a-time") {
2779
- if (this.steeringQueue.length > 0) {
2780
- const first = this.steeringQueue[0];
2781
- this.steeringQueue = this.steeringQueue.slice(1);
2782
- return [first];
2783
- }
2784
- return [];
2785
- }
2786
- const steering = this.steeringQueue.slice();
2787
- this.steeringQueue = [];
2788
- return steering;
2789
- }
2790
- dequeueFollowUpMessages() {
2791
- if (this.followUpMode === "one-at-a-time") {
2792
- if (this.followUpQueue.length > 0) {
2793
- const first = this.followUpQueue[0];
2794
- this.followUpQueue = this.followUpQueue.slice(1);
2795
- return [first];
2796
- }
2797
- return [];
2798
- }
2799
- const followUp = this.followUpQueue.slice();
2800
- this.followUpQueue = [];
2801
- return followUp;
2802
- }
2803
- clearMessages() {
2804
- this._state.messages = [];
2805
- }
2806
- abort() {
2807
- this.abortController?.abort();
2808
- }
2809
- waitForIdle() {
2810
- return this.runningPrompt ?? Promise.resolve();
2811
- }
2812
- reset() {
2813
- this._state.messages = [];
2814
- this._state.isStreaming = false;
2815
- this._state.streamMessage = null;
2816
- this._state.pendingToolCalls = /* @__PURE__ */ new Set();
2817
- this._state.error = void 0;
2818
- this.steeringQueue = [];
2819
- this.followUpQueue = [];
2820
- }
2821
- getName() {
2822
- return this._state.name;
2823
- }
2824
- ensureIdle() {
2825
- if (this._state.isStreaming) throw new AgentInStreamingErr({
2826
- message: "agent is already processing a prompt. Use steer() or followup() to queue messages, or wait for completion.",
2827
- name: this._state.name
2828
- });
2829
- }
2830
- async _runLoop(messages, opts) {
2831
- const model = this._state.model;
2832
- if (!model) throw new ModelNotConfiguredErr({ message: "no model configured yet" });
2833
- this.runningPrompt = new Promise((resolve) => {
2834
- this.resolveRunningPrompt = resolve;
2835
- });
2836
- this.abortController = new AbortController();
2837
- this._state.isStreaming = true;
2838
- this._state.streamMessage = null;
2839
- this._state.error = void 0;
2840
- const reasoning = this.state.thinkingLevel === "off" ? void 0 : this._state.thinkingLevel;
2841
- const context = {
2842
- systemPrompt: this._state.systemPrompt,
2843
- messages: this._state.messages.slice(),
2844
- tools: this._state.tools
2845
- };
2846
- let skipInitialSteeringPoll = opts?.skipInitialSteeringPoll === true;
2847
- const config = {
2848
- model,
2849
- reasoning,
2850
- sessionId: this._sessionId,
2851
- onPayload: this._onPayload,
2852
- transport: this._transport,
2853
- thinkingBudgets: this._thinkingBudgets,
2854
- maxRetryDelayMs: this._maxRetryDelayMs,
2855
- toolExecution: this._toolExecution,
2856
- beforeToolExecution: this._beforeToolExecution,
2857
- afterToolExecution: this._afterToolExecution,
2858
- convertToLlm: this.convertToLlm,
2859
- transformContext: this.transformContext,
2860
- getApiKey: this.getApiKey,
2861
- getSteeringMessages: async () => {
2862
- if (skipInitialSteeringPoll) {
2863
- skipInitialSteeringPoll = false;
2864
- return [];
2865
- }
2866
- return this.dequeueSteeringMessages();
2867
- },
2868
- getFollowUpMessages: async () => this.dequeueFollowUpMessages()
2869
- };
2870
- try {
2871
- if (messages) await Loop.runAgentLoop(config, context, messages, async (e) => this._processLoopEvent(e), this.streamFn, this.abortController.signal);
2872
- else await Loop.runAgentLoopContinue(config, context, async (e) => this._processLoopEvent(e), this.streamFn, this.abortController.signal);
2873
- } catch (err) {
2874
- const message = Message.createAssistantMessage({
2875
- role: "assistant",
2876
- protocol: model.protocol,
2877
- provider: model.provider,
2878
- model: model.id,
2879
- usage: {
2880
- input: 0,
2881
- output: 0,
2882
- cacheRead: 0,
2883
- cacheWrite: 0,
2884
- totalTokens: 0,
2885
- cost: {
2886
- input: 0,
2887
- output: 0,
2888
- cacheRead: 0,
2889
- cacheWrite: 0,
2890
- total: 0
2891
- }
2892
- },
2893
- stopReason: this.abortController.signal.aborted ? "aborted" : "error",
2894
- errorMessage: err?.message || String(err),
2895
- time: {
2896
- created: Date.now(),
2897
- completed: Date.now()
2898
- },
2899
- parts: []
2900
- });
2901
- this.appendMessage(message);
2902
- this._state.error = err?.message || String(err);
2903
- this.emit({
2904
- type: "agent.end",
2905
- messages: [message]
2906
- });
2907
- } finally {
2908
- this._state.isStreaming = false;
2909
- this._state.streamMessage = null;
2910
- this._state.pendingToolCalls = /* @__PURE__ */ new Set();
2911
- this.abortController = void 0;
2912
- this.resolveRunningPrompt?.();
2913
- this.runningPrompt = void 0;
2914
- this.resolveRunningPrompt = void 0;
2915
- }
2916
- }
2917
- async loop(messages) {
2918
- this.ensureIdle();
2919
- await this._runLoop(messages);
2920
- }
2921
- async loopContinue() {
2922
- this.ensureIdle();
2923
- await this._runLoop();
2924
- }
2925
- async prompt(messages, images) {
2926
- this.ensureIdle();
2927
- if (!this._state.model) throw new ModelNotConfiguredErr({ message: "no model configured yet." });
2928
- const message = Message.createUserMessage({
2929
- role: "user",
2930
- time: { created: Date.now() },
2931
- parts: [...messages, ...images ?? []]
2932
- });
2933
- await this.loop([message]);
2934
- }
2935
- _processLoopEvent(event) {
2936
- switch (event.type) {
2937
- case "message.start":
2938
- this._state.streamMessage = event.message;
2939
- break;
2940
- case "message.part.start":
2941
- case "message.part.update":
2942
- case "message.part.end":
2943
- this._state.streamMessage = event.message;
2944
- if (event.message.role === "assistant") this.patchStoredAssistantPart(event.message.messageId, event.partIndex, event.part);
2945
- break;
2946
- case "message.update":
2947
- this._state.streamMessage = event.message;
2948
- this.replaceMessageById(event.message);
2949
- break;
2950
- case "message.end":
2951
- this._state.streamMessage = null;
2952
- this.upsertMessage(event.message);
2953
- break;
2954
- case "tool.execution.start": {
2955
- const pendingToolCalls = new Set(this._state.pendingToolCalls);
2956
- pendingToolCalls.add(event.callID);
2957
- this._state.pendingToolCalls = pendingToolCalls;
2958
- break;
2959
- }
2960
- case "tool.execution.end": {
2961
- const pendingToolCalls = new Set(this._state.pendingToolCalls);
2962
- pendingToolCalls.delete(event.callID);
2963
- this._state.pendingToolCalls = pendingToolCalls;
2964
- break;
2965
- }
2966
- case "turn.end":
2967
- if (event.message.role === "assistant" && event.message.parts.length > 0) this._state.error = event.message.errorMessage;
2968
- break;
2969
- case "agent.end":
2970
- this._state.isStreaming = false;
2971
- this._state.streamMessage = null;
2972
- break;
2973
- }
2974
- this.emit(event);
2975
- }
2976
- emit(e) {
2977
- for (const listener of this.listeners) listener(e);
2978
- }
2979
- }
2980
- _Agent.Instance = Instance;
2981
- async function create(options) {
2982
- let resolvedModel;
2983
- if ("provider" in options) {
2984
- const result = await Model.getModel(options.provider, options.model);
2985
- if (!result) throw new ModelNotFoundErr({
2986
- message: "model not found or not configured yet",
2987
- provider: options.provider,
2988
- model: options.model
2989
- });
2990
- resolvedModel = result;
2991
- } else resolvedModel = options.model;
2992
- return new Instance(options.name ?? "main", resolvedModel, options);
2993
- }
2994
- _Agent.create = create;
2995
- })(Agent || (Agent = {}));
2996
- //#endregion
2997
- //#region src/agent/codemode/codemode.ts
2998
- let CodeMode;
2999
- (function(_CodeMode) {
3000
- const ToolDefinitionErr = _CodeMode.ToolDefinitionErr = NamedError.create("ToolDefinitionErr", Type.Object({ message: Type.String() }));
3001
- const toolFnPrefix = process.env.CODEWORK_CODEMODE_FN_PREFIX ?? "external_";
3002
- const SandboxExecutionInputSchema = _CodeMode.SandboxExecutionInputSchema = Type.Object({ typescriptCode: Type.String({ description: "TypeScript code to execute in the sandbox." }) });
3003
- const SandboxExecutionOutputSchema = _CodeMode.SandboxExecutionOutputSchema = Type.Object({
3004
- result: Type.Optional(Type.Unknown()),
3005
- logs: Type.Optional(Type.Array(Type.String()))
3006
- });
3007
- const SandboxExecutionErrorSchema = _CodeMode.SandboxExecutionErrorSchema = Type.Object({
3008
- message: Type.String(),
3009
- name: Type.Optional(Type.String()),
3010
- stack: Type.Optional(Type.String()),
3011
- line: Type.Optional(Type.Number()),
3012
- logs: Type.Optional(Type.Array(Type.String()))
3013
- });
3014
- function withMessageInStack(message, stack) {
3015
- if (!stack) return void 0;
3016
- return stack.includes(message) ? stack : `${message}\n${stack}`;
3017
- }
3018
- function normalizeExecutionError(error) {
3019
- if (error instanceof Error) return {
3020
- name: error.name,
3021
- message: error.message,
3022
- stack: withMessageInStack(error.message, error.stack),
3023
- line: parseErrorLine(error.stack)
3024
- };
3025
- if (typeof error === "object" && error !== null) {
3026
- const candidate = error;
3027
- return {
3028
- name: typeof candidate.name === "string" ? candidate.name : void 0,
3029
- message: typeof candidate.message === "string" ? candidate.message : JSON.stringify(candidate) || "Unknown execution error",
3030
- stack: typeof candidate.stack === "string" ? withMessageInStack(typeof candidate.message === "string" ? candidate.message : JSON.stringify(candidate) || "Unknown execution error", candidate.stack) : void 0,
3031
- line: typeof candidate.line === "number" ? candidate.line : parseErrorLine(candidate.stack)
3032
- };
3033
- }
3034
- return {
3035
- name: "Error",
3036
- message: String(error)
3037
- };
3038
- }
3039
- function parseErrorLine(stack) {
3040
- if (typeof stack !== "string") return void 0;
3041
- const lineMatch = stack.match(/:(\d+)(?::\d+)?\)?$/m);
3042
- return lineMatch ? Number(lineMatch[1]) : void 0;
3043
- }
3044
- function serializeForContent(value) {
3045
- return JSON.stringify(value, (_key, currentValue) => typeof currentValue === "bigint" ? currentValue.toString() : currentValue, 2);
3046
- }
3047
- function toolContentToText(result) {
3048
- return result.content.filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n").trim();
3049
- }
3050
- function unwrapToolResult(tool, result) {
3051
- if (result.status === "completed") {
3052
- if (tool.outputSchema) return validateSchema(tool.outputSchema, result.result.details, `Tool "${tool.name}" output`);
3053
- return result.result.details;
3054
- }
3055
- if (tool.errorSchema && result.result.details !== void 0) validateSchema(tool.errorSchema, result.result.details, `Tool "${tool.name}" error`);
3056
- const message = toolContentToText(result.result) || `Tool "${tool.name}" failed`;
3057
- const error = new Error(message);
3058
- if (result.result.details !== void 0) error.cause = result.result.details;
3059
- throw error;
3060
- }
3061
- function toolToBinding(tool, prefix = "") {
3062
- const inputSchema = TypeGuard.IsSchema(tool.parameters) ? tool.parameters : Type.Object({});
3063
- const outputSchema = TypeGuard.IsSchema(tool.outputSchema) ? tool.outputSchema : void 0;
3064
- const errorSchema = TypeGuard.IsSchema(tool.errorSchema) ? tool.errorSchema : void 0;
3065
- if (!("execute" in tool) || typeof tool.execute !== "function") throw new ToolDefinitionErr({ message: `tool "${tool.name}" does not have an execute function. code mode requires tools with implementation` });
3066
- return {
3067
- name: `${prefix}${tool.name}`,
3068
- description: tool.description,
3069
- inputSchema,
3070
- outputSchema,
3071
- errorSchema,
3072
- execute: async (callID, params, signal) => {
3073
- const validatedParams = validateSchema(inputSchema, params, `Tool "${tool.name}" input`);
3074
- return unwrapToolResult(tool, await tool.execute(callID, validatedParams, signal));
3075
- }
3076
- };
3077
- }
3078
- function toolsForBinding(tools, prefix) {
3079
- const bindings = {};
3080
- for (const tool of tools) {
3081
- const name = `${prefix}${tool.name}`;
3082
- bindings[name] = toolToBinding(tool, prefix);
3083
- }
3084
- return bindings;
3085
- }
3086
- function indent(value, depth = 1) {
3087
- const prefix = " ".repeat(depth);
3088
- return value.split("\n").map((line) => `${prefix}${line}`).join("\n");
3089
- }
3090
- function toPropertyKey(name) {
3091
- return /^[$A-Z_a-z][$\w]*$/i.test(name) ? name : JSON.stringify(name);
3092
- }
3093
- function schemaToTypeScript(schema) {
3094
- if (TypeGuard.IsAny(schema)) return "any";
3095
- if (TypeGuard.IsUnknown(schema)) return "unknown";
3096
- if (TypeGuard.IsString(schema)) return "string";
3097
- if (TypeGuard.IsNumber(schema) || TypeGuard.IsInteger(schema)) return "number";
3098
- if (TypeGuard.IsBoolean(schema)) return "boolean";
3099
- if (TypeGuard.IsNull(schema)) return "null";
3100
- if (TypeGuard.IsUndefined(schema) || TypeGuard.IsVoid(schema)) return "undefined";
3101
- if (TypeGuard.IsLiteral(schema)) return JSON.stringify(schema.const);
3102
- if (TypeGuard.IsArray(schema)) return `Array<${schemaToTypeScript(schema.items)}>`;
3103
- if (TypeGuard.IsTuple(schema)) return `[${(schema.items ?? []).map((item) => schemaToTypeScript(item)).join(", ")}]`;
3104
- if (TypeGuard.IsUnion(schema)) return schema.anyOf.map((item) => schemaToTypeScript(item)).join(" | ");
3105
- if (TypeGuard.IsIntersect(schema)) return schema.allOf.map((item) => schemaToTypeScript(item)).join(" & ");
3106
- if (TypeGuard.IsRecord(schema)) return `Record<string, ${schemaToTypeScript(Object.values(schema.patternProperties ?? {}).find(TypeGuard.IsSchema) ?? (schema.additionalProperties && TypeGuard.IsSchema(schema.additionalProperties) ? schema.additionalProperties : Type.Unknown()))}>`;
3107
- if (TypeGuard.IsObject(schema)) {
3108
- const required = new Set(schema.required ?? []);
3109
- const properties = Object.entries(schema.properties ?? {}).map(([key, value]) => {
3110
- const optional = required.has(key) ? "" : "?";
3111
- return `${toPropertyKey(key)}${optional}: ${schemaToTypeScript(value)};`;
3112
- });
3113
- if (schema.additionalProperties === true) properties.push("[key: string]: unknown;");
3114
- else if (schema.additionalProperties && TypeGuard.IsSchema(schema.additionalProperties)) properties.push(`[key: string]: ${schemaToTypeScript(schema.additionalProperties)};`);
3115
- if (properties.length === 0) return "{}";
3116
- return `{\n${indent(properties.join("\n"))}\n}`;
3117
- }
3118
- return "unknown";
3119
- }
3120
- function generateTypeStubs(bindings, options = {}) {
3121
- const { includeDescriptions = true } = options;
3122
- const declarations = [];
3123
- for (const [name, binding] of Object.entries(bindings)) {
3124
- const inputTypeName = `${capitalize(name)}Input`;
3125
- const outputTypeName = `${capitalize(name)}Output`;
3126
- declarations.push(`type ${inputTypeName} = ${schemaToTypeScript(binding.inputSchema)};`);
3127
- let outputTypeRef = "unknown";
3128
- if (binding.outputSchema !== void 0) {
3129
- declarations.push(`type ${outputTypeName} = ${schemaToTypeScript(binding.outputSchema)};`);
3130
- outputTypeRef = outputTypeName;
3131
- }
3132
- const description = includeDescriptions && binding.description ? `/** ${binding.description} */\n` : "";
3133
- declarations.push(`${description}declare function ${name}(input: ${inputTypeName}): Promise<${outputTypeRef}>;`);
3134
- }
3135
- return declarations.join("\n\n");
3136
- }
3137
- _CodeMode.generateTypeStubs = generateTypeStubs;
3138
- function buildExampleSnippet() {
3139
- return [
3140
- "```typescript",
3141
- "const numbers = [12, 24, 36];",
3142
- "const total = numbers.reduce((sum, value) => sum + value, 0);",
3143
- "",
3144
- "return {",
3145
- " count: numbers.length,",
3146
- " average: total / numbers.length,",
3147
- "};",
3148
- "```"
3149
- ];
3150
- }
3151
- function generateSystemPrompt(config) {
3152
- const fnPrefix = config.fnPrefix ?? toolFnPrefix;
3153
- const bindings = toolsForBinding(config.tools, fnPrefix);
3154
- const typeStubs = generateTypeStubs(bindings);
3155
- return [
3156
- "## Code Execution Tool",
3157
- "",
3158
- "You have access to `sandbox_execute_typescript` which runs TypeScript code in a sandboxed environment.",
3159
- "",
3160
- "### When to Use",
3161
- "",
3162
- "Use `sandbox_execute_typescript` when you need to:",
3163
- "- Process data with loops, conditionals, or complex logic",
3164
- "- Make multiple tool calls in parallel with `Promise.all(...)`",
3165
- "- Transform, filter, or aggregate data",
3166
- "- Perform calculations or data analysis",
3167
- "",
3168
- "For simple operations, prefer calling tools directly.",
3169
- "",
3170
- "### Available External APIs",
3171
- "",
3172
- "Inside your TypeScript code, you can call these async functions:",
3173
- "",
3174
- Object.entries(bindings).map(([name, binding]) => `- \`${name}(input)\`: ${binding.description}`).join("\n") || "- No external APIs available for this run.",
3175
- "",
3176
- "### Type Definitions",
3177
- "",
3178
- "```typescript",
3179
- typeStubs,
3180
- "```",
3181
- "",
3182
- "### Example",
3183
- "",
3184
- ...buildExampleSnippet(),
3185
- "",
3186
- "### Important Notes",
3187
- "",
3188
- `- All\`${fnPrefix}\`*calls are async, so always use \`await\``,
3189
- "- Return a value to pass results back to you",
3190
- "- Use `console.log()` for debugging (logs are captured)",
3191
- "- The sandbox is isolated - no network access or file system",
3192
- "- Each execution is isolated and does not share state with previous runs",
3193
- ""
3194
- ].join("\n");
3195
- }
3196
- _CodeMode.generateSystemPrompt = generateSystemPrompt;
3197
- async function transpileTypeScript(typescriptCode) {
3198
- return (await transform([
3199
- "(async () => {",
3200
- " const __codemodeNormalizeError = (error: unknown) => {",
3201
- " if (error instanceof Error) return { name: error.name, message: error.message, stack: error.stack };",
3202
- " if (typeof error === 'object' && error !== null) {",
3203
- " const candidate = error as { name?: unknown; message?: unknown; stack?: unknown };",
3204
- " return {",
3205
- " name: typeof candidate.name === 'string' ? candidate.name : 'Error',",
3206
- " message:",
3207
- " typeof candidate.message === 'string'",
3208
- " ? candidate.message",
3209
- " : JSON.stringify(candidate) || 'Unknown execution error',",
3210
- " stack: typeof candidate.stack === 'string' ? candidate.stack : undefined,",
3211
- " };",
3212
- " }",
3213
- " return { name: 'Error', message: String(error) };",
3214
- " };",
3215
- " try {",
3216
- typescriptCode,
3217
- " } catch (error) {",
3218
- " throw __codemodeNormalizeError(error);",
3219
- " }",
3220
- "})()"
3221
- ].join("\n"), {
3222
- loader: "ts",
3223
- target: "es2022",
3224
- sourcefile: "script.ts",
3225
- minify: false,
3226
- keepNames: false
3227
- })).code;
3228
- }
3229
- function buildToolDescription(tools, fnPrefix = toolFnPrefix) {
3230
- return [
3231
- "Execute TypeScript code in a secure sandbox environment. ",
3232
- "The code can use these external API functions:",
3233
- "<functions>",
3234
- ` ${tools.map((tool) => `${fnPrefix}${tool.name}`).join("\n")}`,
3235
- "</functions>",
3236
- `All ${fnPrefix}* calls are async and must be awaited. `,
3237
- "Return a value to pass results back. Use console.log() for debugging."
3238
- ].join("\n");
3239
- }
3240
- function createCodeModeTool(config) {
3241
- if (config.tools.length === 0) throw new ToolDefinitionErr({ message: "at least one tool must be provided to `createCodeModeTool`" });
3242
- return Agent.defineTool({
3243
- name: "sandbox_execute_typescript",
3244
- label: "Sandbox TypeScript",
3245
- description: buildToolDescription(config.tools, config.fnPrefix),
3246
- parameters: SandboxExecutionInputSchema,
3247
- outputSchema: SandboxExecutionOutputSchema,
3248
- errorSchema: SandboxExecutionErrorSchema,
3249
- async execute(_callID, params, signal, onUpdate) {
3250
- const bindings = toolsForBinding(config.tools, config.fnPrefix ?? toolFnPrefix);
3251
- let context;
3252
- try {
3253
- await onUpdate?.({
3254
- status: "running",
3255
- partial: { content: [{
3256
- type: "text",
3257
- text: "Transpiling TypeScript for sandbox execution"
3258
- }] }
3259
- });
3260
- const javascriptCode = await transpileTypeScript(params.typescriptCode);
3261
- await onUpdate?.({
3262
- status: "running",
3263
- partial: { content: [{
3264
- type: "text",
3265
- text: "Executing code in sandbox runtime"
3266
- }] }
3267
- });
3268
- context = await config.driver.createContext({
3269
- bindings,
3270
- timeout: config.timeout,
3271
- memoryLimit: config.memoryLimit,
3272
- signal
3273
- });
3274
- const executionResult = await context.execute(javascriptCode);
3275
- if (executionResult.success) {
3276
- const details = {
3277
- result: executionResult.value,
3278
- ...executionResult.logs && executionResult.logs.length > 0 ? { logs: executionResult.logs } : {}
3279
- };
3280
- return {
3281
- status: "completed",
3282
- result: {
3283
- content: [{
3284
- type: "text",
3285
- text: serializeForContent(details)
3286
- }],
3287
- details,
3288
- isError: false
3289
- }
3290
- };
3291
- }
3292
- const details = {
3293
- message: executionResult.error?.message || "sandbox execution failed",
3294
- ...executionResult.error?.name ? { name: executionResult.error.name } : {},
3295
- ...executionResult.error?.stack ? { stack: executionResult.error.stack } : {},
3296
- ...executionResult.error?.line != null ? { line: executionResult.error.line } : {},
3297
- ...executionResult.logs && executionResult.logs.length > 0 ? { logs: executionResult.logs } : {}
3298
- };
3299
- return {
3300
- status: "error",
3301
- result: {
3302
- content: [{
3303
- type: "text",
3304
- text: serializeForContent(details)
3305
- }],
3306
- details,
3307
- isError: true
3308
- }
3309
- };
3310
- } catch (error) {
3311
- const normalizedError = normalizeExecutionError(error);
3312
- const details = {
3313
- message: normalizedError.message,
3314
- ...normalizedError.name ? { name: normalizedError.name } : {},
3315
- ...normalizedError.stack ? { stack: normalizedError.stack } : {},
3316
- ...normalizedError.line != null ? { line: normalizedError.line } : {}
3317
- };
3318
- return {
3319
- status: "error",
3320
- result: {
3321
- content: [{
3322
- type: "text",
3323
- text: serializeForContent(details)
3324
- }],
3325
- details,
3326
- isError: true
3327
- }
3328
- };
3329
- } finally {
3330
- await context?.dispose();
3331
- }
3332
- }
3333
- });
3334
- }
3335
- _CodeMode.createCodeModeTool = createCodeModeTool;
3336
- async function create(config) {
3337
- return {
3338
- tool: createCodeModeTool(config),
3339
- systemPrompt: generateSystemPrompt(config)
3340
- };
3341
- }
3342
- _CodeMode.create = create;
3343
- })(CodeMode || (CodeMode = {}));
3344
- //#endregion
3345
- //#region src/llm.ts
3346
- const llmImpl = async (provider, model, overrides) => Model.getModel(provider, model, overrides);
3347
- const llm = Object.assign(llmImpl, {
3348
- model: Model.getModel,
3349
- models: Model.getModels,
3350
- providers: Model.getProviders,
3351
- registry: Model.registry,
3352
- supportsXhigh: Model.supportsXhigh,
3353
- modelsAreEqual: Model.modelsAreEqual
3354
- });
3355
- //#endregion
3356
- //#region src/stream.ts
3357
- const streamImpl = (model, context, options) => Stream.stream(model, context, options);
3358
- /**
3359
- * Start a streaming assistant response for a model/context pair.
3360
- *
3361
- * This is the main streaming entrypoint.
3362
- * Attached helpers:
3363
- *
3364
- * - `stream.complete(...)` resolves the final assistant message without manually iterating events.
3365
- * - `stream.simple(...)` uses `Stream.SimpleOptions` for higher-level reasoning controls.
3366
- * - `stream.completeSimple(...)` is the non-streaming counterpart to `stream.simple(...)`.
3367
- * - `stream.resolveProtocolProvider(...)` exposes protocol resolution for advanced integrations.
3368
- */
3369
- const stream = Object.assign(streamImpl, {
3370
- complete: Stream.complete,
3371
- simple: Stream.streamSimple,
3372
- completeSimple: Stream.completeSimple,
3373
- resolveProtocolProvider: Stream.resolveProtocolProvider
3374
- });
3375
- Stream.complete;
3376
- Stream.streamSimple;
3377
- Stream.completeSimple;
3378
- //#endregion
3379
- export { Agent, CodeMode, Message, agent, llm, stream };
3380
-
3381
- //# sourceMappingURL=index.mjs.map