@codeworksh/aikit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs ADDED
@@ -0,0 +1,2515 @@
1
+ import { Filesystem, NamedError, lazy } from "@codeworksh/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { keys, mapValues, pick, pipe } from "remeda";
4
+ import Anthropic from "@anthropic-ai/sdk";
5
+ import { parse } from "partial-json";
6
+ import Ajv from "ajv";
7
+ import addFormats from "ajv-formats";
8
+ //#region src/provider/provider.ts
9
+ let Provider;
10
+ (function(_Provider) {
11
+ const KnownProviderEnum = _Provider.KnownProviderEnum = {
12
+ anthropic: "anthropic",
13
+ openai: "openai"
14
+ };
15
+ const KnownProviderSchema = _Provider.KnownProviderSchema = Type.Union([Type.Literal(KnownProviderEnum.anthropic), Type.Literal(KnownProviderEnum.openai)]);
16
+ _Provider.Info = Type.Object({
17
+ id: KnownProviderSchema,
18
+ name: Type.String(),
19
+ env: Type.Array(Type.String()),
20
+ key: Type.Optional(Type.String()),
21
+ options: Type.Optional(Type.Record(Type.String(), Type.Any()))
22
+ });
23
+ _Provider.ReasoningEffortMapSchema = Type.Object({
24
+ minimal: Type.Optional(Type.String()),
25
+ low: Type.Optional(Type.String()),
26
+ medium: Type.Optional(Type.String()),
27
+ high: Type.Optional(Type.String()),
28
+ xhigh: Type.Optional(Type.String())
29
+ });
30
+ _Provider.OpenRouterRoutingSchema = Type.Object({
31
+ only: Type.Optional(Type.Array(Type.String())),
32
+ order: Type.Optional(Type.Array(Type.String()))
33
+ });
34
+ _Provider.VercelGatewayRoutingSchema = Type.Object({
35
+ only: Type.Optional(Type.Array(Type.String())),
36
+ order: Type.Optional(Type.Array(Type.String()))
37
+ });
38
+ })(Provider || (Provider = {}));
39
+ //#endregion
40
+ //#region src/model/catalog.ts
41
+ let ModelCatalog;
42
+ (function(_ModelCatalog) {
43
+ function modelsDevURL() {
44
+ return process.env.OPENCODE_MODELS_URL || "https://models.dev";
45
+ }
46
+ function modelsDevPath() {
47
+ return process.env.CODEWORK_AIKIT_MODELS_PATH;
48
+ }
49
+ const modelsDevData = _ModelCatalog.modelsDevData = lazy(async () => {
50
+ const path = modelsDevPath();
51
+ if (path) {
52
+ const result = await Filesystem.readJson(path).catch(() => void 0);
53
+ if (result) return result;
54
+ }
55
+ const json = await fetch(`${modelsDevURL()}/api.json`).then((x) => x.text());
56
+ return JSON.parse(json);
57
+ });
58
+ async function get() {
59
+ return modelsDevData();
60
+ }
61
+ _ModelCatalog.get = get;
62
+ async function refresh() {
63
+ const result = await fetch(`${modelsDevURL()}/api.json`, { signal: AbortSignal.timeout(10 * 1e3) }).catch(() => void 0);
64
+ if (!result?.ok) return;
65
+ const json = await result.text();
66
+ const path = modelsDevPath();
67
+ if (path) await Filesystem.write(path, json);
68
+ modelsDevData.reset();
69
+ }
70
+ _ModelCatalog.refresh = refresh;
71
+ ModelCatalog.refresh();
72
+ setInterval(async () => {
73
+ await ModelCatalog.refresh();
74
+ }, 60 * 1e3 * 60).unref();
75
+ })(ModelCatalog || (ModelCatalog = {}));
76
+ //#endregion
77
+ //#region src/model/model.ts
78
+ let Model;
79
+ (function(_Model) {
80
+ const KnownProtocolEnum = _Model.KnownProtocolEnum = {
81
+ anthropicMessages: "anthropic-messages",
82
+ openaiCompletions: "openai-completions",
83
+ openaiResponses: "openai-responses"
84
+ };
85
+ _Model.KnownProtocolSchema = Type.Union([
86
+ Type.Literal(KnownProtocolEnum.anthropicMessages),
87
+ Type.Literal(KnownProtocolEnum.openaiCompletions),
88
+ Type.Literal(KnownProtocolEnum.openaiResponses)
89
+ ]);
90
+ const InputSchema = Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]));
91
+ const CostSchema = Type.Object({
92
+ input: Type.Number(),
93
+ output: Type.Number(),
94
+ cacheRead: Type.Number(),
95
+ cacheWrite: Type.Number()
96
+ });
97
+ const HeadersSchema = Type.Optional(Type.Record(Type.String(), Type.String()));
98
+ const BaseSchema = _Model.BaseSchema = Type.Object({
99
+ id: Type.String(),
100
+ name: Type.String(),
101
+ provider: Provider.Info,
102
+ baseUrl: Type.String(),
103
+ reasoning: Type.Boolean(),
104
+ input: InputSchema,
105
+ cost: CostSchema,
106
+ contextWindow: Type.Number(),
107
+ maxTokens: Type.Number(),
108
+ headers: HeadersSchema
109
+ });
110
+ const OpenAICompletionsCompatSchema = _Model.OpenAICompletionsCompatSchema = Type.Object({
111
+ supportsStore: Type.Optional(Type.Boolean()),
112
+ supportsDeveloperRole: Type.Optional(Type.Boolean()),
113
+ supportsReasoningEffort: Type.Optional(Type.Boolean()),
114
+ reasoningEffortMap: Type.Optional(Provider.ReasoningEffortMapSchema),
115
+ supportsUsageInStreaming: Type.Optional(Type.Boolean()),
116
+ maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
117
+ requiresToolResultName: Type.Optional(Type.Boolean()),
118
+ requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
119
+ requiresThinkingAsText: Type.Optional(Type.Boolean()),
120
+ thinkingFormat: Type.Optional(Type.Union([
121
+ Type.Literal("openai"),
122
+ Type.Literal("openrouter"),
123
+ Type.Literal("zai"),
124
+ Type.Literal("qwen"),
125
+ Type.Literal("qwen-chat-template")
126
+ ])),
127
+ openRouterRouting: Type.Optional(Provider.OpenRouterRoutingSchema),
128
+ vercelGatewayRouting: Type.Optional(Provider.VercelGatewayRoutingSchema),
129
+ supportsStrictMode: Type.Optional(Type.Boolean())
130
+ });
131
+ const OpenAIResponsesCompatSchema = _Model.OpenAIResponsesCompatSchema = Type.Object({});
132
+ _Model.OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
133
+ const AnthropicSchema = _Model.AnthropicSchema = Type.Composite([BaseSchema, Type.Object({ protocol: Type.Literal(KnownProtocolEnum.anthropicMessages) })]);
134
+ const OpenAICompletionsSchema = _Model.OpenAICompletionsSchema = Type.Composite([BaseSchema, Type.Object({
135
+ protocol: Type.Literal(KnownProtocolEnum.openaiCompletions),
136
+ compat: Type.Optional(OpenAICompletionsCompatSchema)
137
+ })]);
138
+ const OpenAIResponsesSchema = _Model.OpenAIResponsesSchema = Type.Composite([BaseSchema, Type.Object({
139
+ protocol: Type.Literal(KnownProtocolEnum.openaiResponses),
140
+ compat: Type.Optional(OpenAIResponsesCompatSchema)
141
+ })]);
142
+ _Model.Schema = Type.Union([
143
+ AnthropicSchema,
144
+ OpenAICompletionsSchema,
145
+ OpenAIResponsesSchema
146
+ ]);
147
+ const BUILTINS = keys(Provider.KnownProviderEnum);
148
+ function calculateCost(model, usage) {
149
+ usage.cost.input = usage.input / 1e6 * model.cost.input;
150
+ usage.cost.output = usage.output / 1e6 * model.cost.output;
151
+ usage.cost.cacheRead = usage.cacheRead / 1e6 * model.cost.cacheRead;
152
+ usage.cost.cacheWrite = usage.cacheWrite / 1e6 * model.cost.cacheWrite;
153
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
154
+ }
155
+ _Model.calculateCost = calculateCost;
156
+ function resolveProtocol(providerId) {
157
+ switch (providerId) {
158
+ case Provider.KnownProviderEnum.anthropic: return KnownProtocolEnum.anthropicMessages;
159
+ case Provider.KnownProviderEnum.openai: return KnownProtocolEnum.openaiResponses;
160
+ }
161
+ }
162
+ function normalizeInput(input) {
163
+ const normalized = /* @__PURE__ */ new Set();
164
+ for (const modality of input ?? ["text"]) if (modality === "text" || modality === "image") normalized.add(modality);
165
+ if (normalized.size === 0) normalized.add("text");
166
+ return [...normalized];
167
+ }
168
+ function toProviderInfo(providerId, provider) {
169
+ return {
170
+ id: providerId,
171
+ name: provider.name,
172
+ env: provider.env,
173
+ key: provider.key,
174
+ options: provider.headers
175
+ };
176
+ }
177
+ function toModelValue(providerId, provider, model) {
178
+ const baseUrl = model.baseUrl ?? provider.baseUrl ?? provider.api;
179
+ return {
180
+ id: model.id,
181
+ name: model.name,
182
+ provider: toProviderInfo(providerId, provider),
183
+ baseUrl,
184
+ reasoning: Boolean(model.reasoning),
185
+ input: normalizeInput(model.modalities.input),
186
+ cost: {
187
+ input: model.cost?.input ?? 0,
188
+ output: model.cost?.output ?? 0,
189
+ cacheRead: model.cost?.cache_read ?? 0,
190
+ cacheWrite: model.cost?.cache_write ?? 0
191
+ },
192
+ contextWindow: model.limit?.context ?? 0,
193
+ maxTokens: model.limit?.output ?? 0,
194
+ headers: model.headers ?? provider.headers,
195
+ protocol: resolveProtocol(providerId)
196
+ };
197
+ }
198
+ async function getBuiltInModels() {
199
+ return pipe(await ModelCatalog.get(), pick(BUILTINS), mapValues((provider, providerId) => mapValues(provider.models, (model) => toModelValue(providerId, provider, model))));
200
+ }
201
+ _Model.getBuiltInModels = getBuiltInModels;
202
+ const registry = _Model.registry = lazy(async () => {
203
+ const registry = /* @__PURE__ */ new Map();
204
+ const models = await getBuiltInModels();
205
+ for (const [provider, value] of Object.entries(models)) {
206
+ const providerModels = /* @__PURE__ */ new Map();
207
+ for (const [id, model] of Object.entries(value)) providerModels.set(id, model);
208
+ registry.set(provider, providerModels);
209
+ }
210
+ return registry;
211
+ });
212
+ async function getModel(provider, model) {
213
+ return (await registry()).get(provider)?.get(model);
214
+ }
215
+ _Model.getModel = getModel;
216
+ async function getProviders() {
217
+ const data = await registry();
218
+ return Array.from(data.keys());
219
+ }
220
+ _Model.getProviders = getProviders;
221
+ async function getModels(provider) {
222
+ const models = (await registry()).get(provider);
223
+ return models ? Array.from(models.values()) : [];
224
+ }
225
+ _Model.getModels = getModels;
226
+ function isGpt5OrLater(modelID) {
227
+ const match = /^gpt-(\d+)/.exec(modelID);
228
+ if (!match) return false;
229
+ return Number(match[1]) >= 5;
230
+ }
231
+ function supportsXhigh(model) {
232
+ return isGpt5OrLater(model.id);
233
+ }
234
+ _Model.supportsXhigh = supportsXhigh;
235
+ function modelsAreEqual(a, b) {
236
+ if (!a || !b) return false;
237
+ return a.id === b.id && a.provider.id === b.provider.id;
238
+ }
239
+ _Model.modelsAreEqual = modelsAreEqual;
240
+ })(Model || (Model = {}));
241
+ //#endregion
242
+ //#region src/message/message.ts
243
+ let Message;
244
+ (function(_Message) {
245
+ const TextContentSchema = _Message.TextContentSchema = Type.Object({
246
+ type: Type.Literal("text"),
247
+ text: Type.String(),
248
+ textSignature: Type.Optional(Type.String())
249
+ });
250
+ const ImageContentSchema = _Message.ImageContentSchema = Type.Object({
251
+ type: Type.Literal("image"),
252
+ data: Type.String(),
253
+ mimeType: Type.String()
254
+ });
255
+ const ThinkingContentSchema = _Message.ThinkingContentSchema = Type.Object({
256
+ type: Type.Literal("thinking"),
257
+ thinking: Type.String(),
258
+ thinkingSignature: Type.Optional(Type.String()),
259
+ redacted: Type.Optional(Type.Boolean())
260
+ });
261
+ const ToolCallBaseSchema = _Message.ToolCallBaseSchema = Type.Object({
262
+ type: Type.Literal("toolCall"),
263
+ callID: Type.String(),
264
+ name: Type.String(),
265
+ arguments: Type.Record(Type.String(), Type.Any()),
266
+ thoughtSignature: Type.Optional(Type.String()),
267
+ time: Type.Object({
268
+ start: Type.Number(),
269
+ end: Type.Number()
270
+ })
271
+ });
272
+ const ToolSuccessResult = _Message.ToolSuccessResult = Type.Object({
273
+ content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
274
+ details: Type.Optional(Type.Any()),
275
+ isError: Type.Literal(false)
276
+ });
277
+ const ToolErrorResult = _Message.ToolErrorResult = Type.Object({
278
+ content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
279
+ details: Type.Optional(Type.Any()),
280
+ isError: Type.Literal(true)
281
+ });
282
+ const ToolRunningPartial = _Message.ToolRunningPartial = Type.Object({
283
+ content: Type.Optional(Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))),
284
+ details: Type.Optional(Type.Any())
285
+ });
286
+ const ToolStatusEnum = _Message.ToolStatusEnum = {
287
+ pending: "pending",
288
+ running: "running",
289
+ completed: "completed",
290
+ error: "error",
291
+ skipped: "skipped",
292
+ aborted: "aborted"
293
+ };
294
+ const ToolRunningSchema = _Message.ToolRunningSchema = Type.Object({
295
+ status: Type.Literal(ToolStatusEnum.running),
296
+ partial: Type.Optional(ToolRunningPartial)
297
+ });
298
+ const ToolCompletedSchema = _Message.ToolCompletedSchema = Type.Object({
299
+ status: Type.Literal(ToolStatusEnum.completed),
300
+ result: ToolSuccessResult
301
+ });
302
+ const ToolErrorSchema = _Message.ToolErrorSchema = Type.Object({
303
+ status: Type.Literal(ToolStatusEnum.error),
304
+ result: ToolErrorResult
305
+ });
306
+ const ToolSkippedSchema = _Message.ToolSkippedSchema = Type.Object({
307
+ status: Type.Literal(ToolStatusEnum.skipped),
308
+ result: ToolErrorResult
309
+ });
310
+ const ToolAbortedSchema = _Message.ToolAbortedSchema = Type.Object({
311
+ status: Type.Literal(ToolStatusEnum.aborted),
312
+ result: ToolErrorResult
313
+ });
314
+ const ToolCallPendingPart = Type.Intersect([ToolCallBaseSchema, Type.Object({ status: Type.Literal(ToolStatusEnum.pending) })]);
315
+ const ToolCallRunningPart = Type.Composite([ToolCallBaseSchema, ToolRunningSchema]);
316
+ const ToolCallCompletedPart = Type.Composite([ToolCallBaseSchema, ToolCompletedSchema]);
317
+ const ToolCallErrorPart = Type.Composite([ToolCallBaseSchema, ToolErrorSchema]);
318
+ const ToolCallSkippedPart = Type.Composite([ToolCallBaseSchema, ToolSkippedSchema]);
319
+ const ToolCallAbortedPart = Type.Composite([ToolCallBaseSchema, ToolAbortedSchema]);
320
+ const ToolCallSchema = _Message.ToolCallSchema = Type.Union([
321
+ ToolCallPendingPart,
322
+ ToolCallRunningPart,
323
+ ToolCallCompletedPart,
324
+ ToolCallErrorPart,
325
+ ToolCallSkippedPart,
326
+ ToolCallAbortedPart
327
+ ]);
328
+ const UsageSchema = _Message.UsageSchema = Type.Object({
329
+ input: Type.Number(),
330
+ output: Type.Number(),
331
+ cacheRead: Type.Number(),
332
+ cacheWrite: Type.Number(),
333
+ totalTokens: Type.Number(),
334
+ cost: Type.Object({
335
+ input: Type.Number(),
336
+ output: Type.Number(),
337
+ cacheRead: Type.Number(),
338
+ cacheWrite: Type.Number(),
339
+ total: Type.Number()
340
+ })
341
+ });
342
+ const StopReasonSchema = _Message.StopReasonSchema = Type.Union([
343
+ Type.Literal("stop"),
344
+ Type.Literal("length"),
345
+ Type.Literal("toolUse"),
346
+ Type.Literal("error"),
347
+ Type.Literal("aborted")
348
+ ]);
349
+ const UserMessageSchema = _Message.UserMessageSchema = Type.Object({
350
+ role: Type.Literal("user"),
351
+ time: Type.Object({ created: Type.Number() }),
352
+ parts: Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))
353
+ });
354
+ const AssistantMessageSchema = _Message.AssistantMessageSchema = Type.Object({
355
+ role: Type.Literal("assistant"),
356
+ protocol: Model.KnownProtocolSchema,
357
+ provider: Provider.Info,
358
+ model: Type.String(),
359
+ usage: UsageSchema,
360
+ stopReason: StopReasonSchema,
361
+ errorMessage: Type.Optional(Type.String()),
362
+ time: Type.Object({
363
+ created: Type.Number(),
364
+ completed: Type.Number()
365
+ }),
366
+ parts: Type.Array(Type.Union([
367
+ TextContentSchema,
368
+ ImageContentSchema,
369
+ ThinkingContentSchema,
370
+ ToolCallSchema
371
+ ])),
372
+ responseID: Type.Optional(Type.String())
373
+ });
374
+ const MessageSchema = _Message.MessageSchema = Type.Union([UserMessageSchema, AssistantMessageSchema]);
375
+ const ToolSchema = _Message.ToolSchema = Type.Object({
376
+ name: Type.String(),
377
+ description: Type.String(),
378
+ parameters: Type.Unsafe()
379
+ });
380
+ function defineTool(tool) {
381
+ return tool;
382
+ }
383
+ _Message.defineTool = defineTool;
384
+ _Message.ContextSchema = Type.Object({
385
+ systemPrompt: Type.Optional(Type.String()),
386
+ messages: Type.Array(MessageSchema),
387
+ tools: Type.Optional(Type.Array(ToolSchema))
388
+ });
389
+ function transformMessages(messages, model, normalizeToolCallId) {
390
+ const toolCallIDMap = /* @__PURE__ */ new Map();
391
+ const transformed = [];
392
+ for (const msg of messages) {
393
+ if (msg.role === "user") {
394
+ transformed.push(msg);
395
+ continue;
396
+ }
397
+ const assistantMsg = msg;
398
+ const isSameModel = assistantMsg.provider.id === model.provider.id && assistantMsg.protocol === model.protocol && assistantMsg.model === model.id;
399
+ const parts = assistantMsg.parts.flatMap((block) => {
400
+ if (block.type === "thinking") {
401
+ if (isSameModel && block.thinkingSignature) return block;
402
+ if (!block.thinking || block.thinking.trim() === "") return [];
403
+ if (isSameModel) return block;
404
+ return {
405
+ type: "text",
406
+ text: block.thinking
407
+ };
408
+ }
409
+ if (block.type === "text") {
410
+ if (isSameModel) return block;
411
+ return {
412
+ type: "text",
413
+ text: block.text
414
+ };
415
+ }
416
+ if (block.type === "toolCall") {
417
+ const toolCall = block;
418
+ let normalizedToolCall = toolCall;
419
+ if (!isSameModel && toolCall.thoughtSignature) {
420
+ normalizedToolCall = { ...toolCall };
421
+ delete normalizedToolCall.thoughtSignature;
422
+ }
423
+ const normalizedID = toolCallIDMap.get(block.callID);
424
+ if (normalizedID && normalizedID !== block.callID) normalizedToolCall = {
425
+ ...normalizedToolCall,
426
+ callID: normalizedID
427
+ };
428
+ else if (!isSameModel && normalizeToolCallId) {
429
+ const nextID = normalizeToolCallId(toolCall.callID, model, assistantMsg);
430
+ if (nextID !== toolCall.callID) {
431
+ toolCallIDMap.set(toolCall.callID, nextID);
432
+ normalizedToolCall = {
433
+ ...normalizedToolCall,
434
+ callID: nextID
435
+ };
436
+ }
437
+ }
438
+ return normalizedToolCall;
439
+ }
440
+ return block;
441
+ });
442
+ transformed.push({
443
+ ...assistantMsg,
444
+ parts
445
+ });
446
+ }
447
+ return transformed;
448
+ }
449
+ _Message.transformMessages = transformMessages;
450
+ })(Message || (Message = {}));
451
+ //#endregion
452
+ //#region src/utils/eventstream.ts
453
+ var EventStream = class {
454
+ queue = [];
455
+ waiting = [];
456
+ done = false;
457
+ finalResultPromise;
458
+ resolveFinalResult;
459
+ constructor(isComplete, extractResult) {
460
+ this.isComplete = isComplete;
461
+ this.extractResult = extractResult;
462
+ this.finalResultPromise = new Promise((resolve) => {
463
+ this.resolveFinalResult = resolve;
464
+ });
465
+ }
466
+ push(event) {
467
+ if (this.done) return;
468
+ if (this.isComplete(event)) {
469
+ this.done = true;
470
+ this.resolveFinalResult(this.extractResult(event));
471
+ }
472
+ const waiter = this.waiting.shift();
473
+ if (waiter) waiter({
474
+ value: event,
475
+ done: false
476
+ });
477
+ else this.queue.push(event);
478
+ }
479
+ end(result) {
480
+ this.done = true;
481
+ if (result !== void 0) this.resolveFinalResult(result);
482
+ while (this.waiting.length > 0) this.waiting.shift()({
483
+ value: void 0,
484
+ done: true
485
+ });
486
+ }
487
+ async *[Symbol.asyncIterator]() {
488
+ while (true) if (this.queue.length > 0) yield this.queue.shift();
489
+ else if (this.done) return;
490
+ else {
491
+ const result = await new Promise((resolve) => this.waiting.push(resolve));
492
+ if (result.done) return;
493
+ yield result.value;
494
+ }
495
+ }
496
+ result() {
497
+ return this.finalResultPromise;
498
+ }
499
+ };
500
+ var AssistantMessageEventStream = class extends EventStream {
501
+ constructor() {
502
+ super((event) => event.type === "done" || event.type === "error", (event) => {
503
+ if (event.type === "done") return event.message;
504
+ else if (event.type === "error") return event.error;
505
+ throw new Error("Unexpected event type for final result");
506
+ });
507
+ }
508
+ };
509
+ //#endregion
510
+ //#region src/utils/jsonparse.ts
511
+ /**
512
+ * @description Helper function to parse partial jsons during LLM streaming.
513
+ */
514
+ /**
515
+ * Attempts to parse potentially incomplete JSON during streaming.
516
+ * Always returns a valid object, even if the JSON is incomplete.
517
+ *
518
+ * @param partialJson The partial JSON string from streaming
519
+ * @returns Parsed object or empty object if parsing fails
520
+ */
521
+ function parseStreamingJson(partialJson) {
522
+ if (!partialJson || partialJson.trim() === "") return {};
523
+ try {
524
+ return JSON.parse(partialJson);
525
+ } catch {
526
+ try {
527
+ return parse(partialJson) ?? {};
528
+ } catch {
529
+ return {};
530
+ }
531
+ }
532
+ }
533
+ //#endregion
534
+ //#region src/utils/sanitize.ts
535
+ /**
536
+ * Removes unpaired Unicode surrogate characters from a string.
537
+ *
538
+ * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
539
+ * or vice versa) cause JSON serialization errors in many API providers.
540
+ *
541
+ * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
542
+ * surrogates and will NOT be affected by this function.
543
+ *
544
+ * @param text - The text to sanitize
545
+ * @returns The sanitized text with unpaired surrogates removed
546
+ *
547
+ * @example
548
+ * // Valid emoji (properly paired surrogates) are preserved
549
+ * sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
550
+ *
551
+ * // Unpaired high surrogate is removed
552
+ * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
553
+ * sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
554
+ */
555
+ function sanitizeSurrogates(text) {
556
+ return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
557
+ }
558
+ //#endregion
559
+ //#region src/provider/stream.ts
560
+ let Stream;
561
+ (function(_Stream) {
562
+ const ProtocolProviderNotFoundError = _Stream.ProtocolProviderNotFoundError = NamedError.create("ProtocolProviderNotFoundError", Type.Object({ protocol: Model.KnownProtocolSchema }));
563
+ const ProtocolMismatchError = _Stream.ProtocolMismatchError = NamedError.create("ProtocolMismatchError", Type.Object({
564
+ actual: Model.KnownProtocolSchema,
565
+ expected: Model.KnownProtocolSchema
566
+ }));
567
+ const ThinkingLevelEnum = _Stream.ThinkingLevelEnum = {
568
+ off: "off",
569
+ minimal: "minimal",
570
+ low: "low",
571
+ medium: "medium",
572
+ high: "high",
573
+ xhigh: "xhigh"
574
+ };
575
+ const ThinkingLevelSchema = _Stream.ThinkingLevelSchema = Type.Union([
576
+ Type.Literal(ThinkingLevelEnum.off),
577
+ Type.Literal(ThinkingLevelEnum.minimal),
578
+ Type.Literal(ThinkingLevelEnum.low),
579
+ Type.Literal(ThinkingLevelEnum.medium),
580
+ Type.Literal(ThinkingLevelEnum.high),
581
+ Type.Literal(ThinkingLevelEnum.xhigh)
582
+ ]);
583
+ const ThinkingBudgetsSchema = _Stream.ThinkingBudgetsSchema = Type.Object({
584
+ off: Type.Optional(Type.Number()),
585
+ minimal: Type.Optional(Type.Number()),
586
+ low: Type.Optional(Type.Number()),
587
+ medium: Type.Optional(Type.Number()),
588
+ high: Type.Optional(Type.Number())
589
+ });
590
+ const CacheRetentionSchema = _Stream.CacheRetentionSchema = Type.Union([
591
+ Type.Literal("none"),
592
+ Type.Literal("short"),
593
+ Type.Literal("long")
594
+ ]);
595
+ const TransportSchema = _Stream.TransportSchema = Type.Union([
596
+ Type.Literal("sse"),
597
+ Type.Literal("websocket"),
598
+ Type.Literal("auto")
599
+ ]);
600
+ const OptionsSchema = _Stream.OptionsSchema = Type.Object({
601
+ temperature: Type.Optional(Type.Number()),
602
+ maxTokens: Type.Optional(Type.Number()),
603
+ signal: Type.Optional(Type.Unsafe()),
604
+ apiKey: Type.Optional(Type.String()),
605
+ transport: Type.Optional(TransportSchema),
606
+ cacheRetention: Type.Optional(CacheRetentionSchema),
607
+ sessionId: Type.Optional(Type.String()),
608
+ onPayload: Type.Optional(Type.Unsafe()),
609
+ headers: Type.Optional(Type.Record(Type.String(), Type.String())),
610
+ maxRetryDelayMs: Type.Optional(Type.Number()),
611
+ metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
612
+ });
613
+ _Stream.SimpleOptionsSchema = Type.Composite([OptionsSchema, Type.Object({
614
+ reasoning: Type.Optional(ThinkingLevelSchema),
615
+ thinkingBudgets: Type.Optional(ThinkingBudgetsSchema)
616
+ })]);
617
+ function buildBaseOptions(model, options, apiKey) {
618
+ return {
619
+ temperature: options?.temperature,
620
+ maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32e3),
621
+ signal: options?.signal,
622
+ apiKey: apiKey || options?.apiKey,
623
+ transport: options?.transport,
624
+ cacheRetention: options?.cacheRetention,
625
+ sessionId: options?.sessionId,
626
+ headers: options?.headers,
627
+ onPayload: options?.onPayload,
628
+ maxRetryDelayMs: options?.maxRetryDelayMs,
629
+ metadata: options?.metadata
630
+ };
631
+ }
632
+ _Stream.buildBaseOptions = buildBaseOptions;
633
+ function clampReasoning(effort) {
634
+ return effort === ThinkingLevelEnum.xhigh ? ThinkingLevelEnum.high : effort;
635
+ }
636
+ _Stream.clampReasoning = clampReasoning;
637
+ function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
638
+ const budgets = {
639
+ minimal: 1024,
640
+ low: 2048,
641
+ medium: 8192,
642
+ high: 16384,
643
+ ...customBudgets
644
+ };
645
+ const minOutputTokens = 1024;
646
+ let thinkingBudget = budgets[clampReasoning(reasoningLevel)];
647
+ const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
648
+ if (maxTokens <= thinkingBudget) thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
649
+ return {
650
+ maxTokens,
651
+ thinkingBudget
652
+ };
653
+ }
654
+ _Stream.adjustMaxTokensForThinking = adjustMaxTokensForThinking;
655
+ const protocolProviderRegistry = /* @__PURE__ */ new Map();
656
+ function wrapStream(protocol, stream) {
657
+ return (model, context, options) => {
658
+ if (model.protocol !== protocol) throw new ProtocolMismatchError({
659
+ actual: model.protocol,
660
+ expected: protocol
661
+ });
662
+ return stream(model, context, options);
663
+ };
664
+ }
665
+ function wrapStreamSimple(protocol, streamSimple) {
666
+ return (model, context, options) => {
667
+ if (model.protocol !== protocol) throw new ProtocolMismatchError({
668
+ actual: model.protocol,
669
+ expected: protocol
670
+ });
671
+ return streamSimple(model, context, options);
672
+ };
673
+ }
674
+ function registerProtocolProvider(provider, sourceId) {
675
+ protocolProviderRegistry.set(provider.protocol, {
676
+ provider: {
677
+ protocol: provider.protocol,
678
+ stream: wrapStream(provider.protocol, provider.stream),
679
+ streamSimple: wrapStreamSimple(provider.protocol, provider.streamSimple)
680
+ },
681
+ sourceId
682
+ });
683
+ }
684
+ _Stream.registerProtocolProvider = registerProtocolProvider;
685
+ function getProtocolProvider(protocol) {
686
+ return protocolProviderRegistry.get(protocol)?.provider;
687
+ }
688
+ _Stream.getProtocolProvider = getProtocolProvider;
689
+ function resolveProtocolProvider(model) {
690
+ const provider = getProtocolProvider(model.protocol);
691
+ if (!provider) throw new ProtocolProviderNotFoundError({ protocol: model.protocol });
692
+ return provider;
693
+ }
694
+ _Stream.resolveProtocolProvider = resolveProtocolProvider;
695
+ function stream(model, context, options) {
696
+ return resolveProtocolProvider(model).stream(model, context, options);
697
+ }
698
+ _Stream.stream = stream;
699
+ async function complete(model, context, options) {
700
+ return stream(model, context, options).result();
701
+ }
702
+ _Stream.complete = complete;
703
+ function streamSimple(model, context, options) {
704
+ return resolveProtocolProvider(model).streamSimple(model, context, options);
705
+ }
706
+ _Stream.streamSimple = streamSimple;
707
+ async function completeSimple(model, context, options) {
708
+ return streamSimple(model, context, options).result();
709
+ }
710
+ _Stream.completeSimple = completeSimple;
711
+ function getApiProviders() {
712
+ return Array.from(protocolProviderRegistry.values(), (entry) => entry.provider);
713
+ }
714
+ _Stream.getApiProviders = getApiProviders;
715
+ function unregisterProtocolProviders(sourceId) {
716
+ for (const [api, entry] of protocolProviderRegistry.entries()) if (entry.sourceId === sourceId) protocolProviderRegistry.delete(api);
717
+ }
718
+ _Stream.unregisterProtocolProviders = unregisterProtocolProviders;
719
+ function clearProtocolProviders() {
720
+ protocolProviderRegistry.clear();
721
+ }
722
+ _Stream.clearProtocolProviders = clearProtocolProviders;
723
+ })(Stream || (Stream = {}));
724
+ //#endregion
725
+ //#region src/provider/providers/anthropic/index.ts
726
+ function getEnvApiKey(_provider) {}
727
+ function resolveCacheRetention(cacheRetention) {
728
+ if (cacheRetention) return cacheRetention;
729
+ if (typeof process !== "undefined" && process.env.CODEWORK_CACHE_RETENTION === "long") return "long";
730
+ return "short";
731
+ }
732
+ function getCacheControl(baseUrl, cacheRetention) {
733
+ const retention = resolveCacheRetention(cacheRetention);
734
+ if (retention === "none") return { retention };
735
+ const ttl = retention === "long" && baseUrl.includes("api.anthropic.com") ? "1h" : void 0;
736
+ return {
737
+ retention,
738
+ cacheControl: {
739
+ type: "ephemeral",
740
+ ...ttl && { ttl }
741
+ }
742
+ };
743
+ }
744
+ const claudeCodeVersion = "2.1.2";
745
+ const ccToolLookup = new Map([
746
+ "Read",
747
+ "Write",
748
+ "Edit",
749
+ "Bash",
750
+ "Grep",
751
+ "Glob",
752
+ "AskUserQuestion",
753
+ "EnterPlanMode",
754
+ "ExitPlanMode",
755
+ "KillShell",
756
+ "NotebookEdit",
757
+ "Skill",
758
+ "Task",
759
+ "TaskOutput",
760
+ "TodoWrite",
761
+ "WebFetch",
762
+ "WebSearch"
763
+ ].map((t) => [t.toLowerCase(), t]));
764
+ const toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;
765
+ const fromClaudeCodeName = (name, tools) => {
766
+ if (tools && tools.length > 0) {
767
+ const lowerName = name.toLowerCase();
768
+ const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
769
+ if (matchedTool) return matchedTool.name;
770
+ }
771
+ return name;
772
+ };
773
+ function convertContentBlocks(content) {
774
+ if (!content.some((c) => c.type === "image")) return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
775
+ const blocks = content.map((block) => {
776
+ if (block.type === "text") return {
777
+ type: "text",
778
+ text: sanitizeSurrogates(block.text)
779
+ };
780
+ return {
781
+ type: "image",
782
+ source: {
783
+ type: "base64",
784
+ media_type: block.mimeType,
785
+ data: block.data
786
+ }
787
+ };
788
+ });
789
+ if (!blocks.some((b) => b.type === "text")) blocks.unshift({
790
+ type: "text",
791
+ text: "(see attached image)"
792
+ });
793
+ return blocks;
794
+ }
795
+ function mergeHeaders(...headerSources) {
796
+ const merged = {};
797
+ for (const headers of headerSources) if (headers) Object.assign(merged, headers);
798
+ return merged;
799
+ }
800
+ function isOAuthToken(apiKey) {
801
+ return apiKey.includes("sk-ant-oat");
802
+ }
803
+ function createClient(model, apiKey, interleavedThinking, optionsHeaders) {
804
+ const betaFeatures = ["fine-grained-tool-streaming-2025-05-14"];
805
+ if (interleavedThinking) betaFeatures.push("interleaved-thinking-2025-05-14");
806
+ if (isOAuthToken(apiKey)) {
807
+ const defaultHeaders = mergeHeaders({
808
+ accept: "application/json",
809
+ "anthropic-dangerous-direct-browser-access": "true",
810
+ "anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}`,
811
+ "user-agent": `claude-cli/${claudeCodeVersion} (external, cli)`,
812
+ "x-app": "cli"
813
+ }, model.headers, optionsHeaders);
814
+ return {
815
+ client: new Anthropic({
816
+ apiKey: null,
817
+ authToken: apiKey,
818
+ baseURL: model.baseUrl,
819
+ defaultHeaders,
820
+ dangerouslyAllowBrowser: true
821
+ }),
822
+ isOAuthToken: true
823
+ };
824
+ }
825
+ const defaultHeaders = mergeHeaders({
826
+ accept: "application/json",
827
+ "anthropic-dangerous-direct-browser-access": "true",
828
+ "anthropic-beta": betaFeatures.join(",")
829
+ }, model.headers, optionsHeaders);
830
+ return {
831
+ client: new Anthropic({
832
+ apiKey,
833
+ baseURL: model.baseUrl,
834
+ dangerouslyAllowBrowser: true,
835
+ defaultHeaders
836
+ }),
837
+ isOAuthToken: false
838
+ };
839
+ }
840
+ function normalizeToolCallId(id) {
841
+ return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
842
+ }
843
+ function assertReplayableAssistant(message) {
844
+ let sawToolCall = false;
845
+ let sawNonTerminalToolCall = false;
846
+ let sawTerminalToolCall = false;
847
+ for (const part of message.parts) {
848
+ if (part.type === "image") throw new Error("Anthropic replay does not support assistant image parts");
849
+ if (part.type === "toolCall") {
850
+ sawToolCall = true;
851
+ if (part.status === "pending" || part.status === "running") sawNonTerminalToolCall = true;
852
+ else sawTerminalToolCall = true;
853
+ continue;
854
+ }
855
+ if (sawToolCall) throw new Error("Assistant parts after a toolCall are not replayable for Anthropic");
856
+ }
857
+ if (sawToolCall && message.stopReason !== "toolUse") throw new Error("Assistant message with tool calls must have stopReason 'toolUse'");
858
+ if (!sawToolCall && message.stopReason === "toolUse") throw new Error("Assistant message with stopReason 'toolUse' must contain at least one toolCall");
859
+ if (sawTerminalToolCall && sawNonTerminalToolCall) throw new Error("Assistant message cannot mix terminal and non-terminal toolCall states");
860
+ }
861
+ function buildSyntheticToolResult(block) {
862
+ return {
863
+ type: "tool_result",
864
+ tool_use_id: block.callID,
865
+ content: convertContentBlocks([{
866
+ type: "text",
867
+ text: [
868
+ "<result>",
869
+ "No Result Provided",
870
+ "</result>"
871
+ ].join("\n")
872
+ }]),
873
+ is_error: true
874
+ };
875
+ }
876
+ function convertMessages(messages, model, isOAuthToken, cacheControl) {
877
+ const params = [];
878
+ const transformedMessages = Message.transformMessages(messages, model, normalizeToolCallId);
879
+ for (const msg of transformedMessages) {
880
+ if (msg.role === "user") {
881
+ const blocks = msg.parts.map((item) => {
882
+ if (item.type === "text") return {
883
+ type: "text",
884
+ text: sanitizeSurrogates(item.text)
885
+ };
886
+ return {
887
+ type: "image",
888
+ source: {
889
+ type: "base64",
890
+ media_type: item.mimeType,
891
+ data: item.data
892
+ }
893
+ };
894
+ });
895
+ let filteredBlocks = !model.input.includes("image") ? blocks.filter((b) => b.type !== "image") : blocks;
896
+ filteredBlocks = filteredBlocks.filter((b) => b.type === "text" ? b.text.trim().length > 0 : true);
897
+ if (filteredBlocks.length === 0) continue;
898
+ params.push({
899
+ role: "user",
900
+ content: filteredBlocks
901
+ });
902
+ continue;
903
+ }
904
+ if (msg.stopReason === "error" || msg.stopReason === "aborted") continue;
905
+ assertReplayableAssistant(msg);
906
+ const assistantBlocks = [];
907
+ const toolResults = [];
908
+ for (const block of msg.parts) if (block.type === "text") {
909
+ if (block.text.trim().length === 0) continue;
910
+ assistantBlocks.push({
911
+ type: "text",
912
+ text: sanitizeSurrogates(block.text)
913
+ });
914
+ } else if (block.type === "thinking") {
915
+ if (block.thinking.trim().length === 0) continue;
916
+ if (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) assistantBlocks.push({
917
+ type: "text",
918
+ text: sanitizeSurrogates(block.thinking)
919
+ });
920
+ else assistantBlocks.push({
921
+ type: "thinking",
922
+ thinking: sanitizeSurrogates(block.thinking),
923
+ signature: block.thinkingSignature
924
+ });
925
+ } else if (block.type === "toolCall") {
926
+ assistantBlocks.push({
927
+ type: "tool_use",
928
+ id: block.callID,
929
+ name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
930
+ input: block.arguments ?? {}
931
+ });
932
+ if (block.status === "pending" || block.status === "running") toolResults.push(buildSyntheticToolResult(block));
933
+ else toolResults.push({
934
+ type: "tool_result",
935
+ tool_use_id: block.callID,
936
+ content: convertContentBlocks(block.result.content),
937
+ is_error: block.result.isError
938
+ });
939
+ }
940
+ if (assistantBlocks.length > 0) params.push({
941
+ role: "assistant",
942
+ content: assistantBlocks
943
+ });
944
+ if (toolResults.length > 0) params.push({
945
+ role: "user",
946
+ content: toolResults
947
+ });
948
+ }
949
+ if (cacheControl && params.length > 0) {
950
+ const lastMessage = params[params.length - 1];
951
+ if (lastMessage.role === "user") {
952
+ if (Array.isArray(lastMessage.content)) {
953
+ const lastBlock = lastMessage.content[lastMessage.content.length - 1];
954
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) lastBlock.cache_control = cacheControl;
955
+ } else if (typeof lastMessage.content === "string") lastMessage.content = [{
956
+ type: "text",
957
+ text: lastMessage.content,
958
+ cache_control: cacheControl
959
+ }];
960
+ }
961
+ }
962
+ return params;
963
+ }
964
+ function convertTools(tools, isOAuthToken) {
965
+ if (!tools) return [];
966
+ return tools.map((tool) => {
967
+ const jsonSchema = tool.parameters;
968
+ return {
969
+ name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name,
970
+ description: tool.description,
971
+ input_schema: {
972
+ type: "object",
973
+ properties: jsonSchema.properties || {},
974
+ required: jsonSchema.required || []
975
+ }
976
+ };
977
+ });
978
+ }
979
+ function mapStopReason(reason) {
980
+ switch (reason) {
981
+ case "end_turn": return "stop";
982
+ case "max_tokens": return "length";
983
+ case "tool_use": return "toolUse";
984
+ case "pause_turn":
985
+ case "stop_sequence": return "stop";
986
+ case "refusal":
987
+ case "sensitive": return "error";
988
+ default: throw new Error("Unhandled Anthropic stop reason");
989
+ }
990
+ }
991
+ function buildParams(model, context, isOAuthToken, options) {
992
+ const { cacheControl } = getCacheControl(model.baseUrl, options?.cacheRetention);
993
+ const params = {
994
+ model: model.id,
995
+ messages: convertMessages(context.messages, model, isOAuthToken, cacheControl),
996
+ max_tokens: options?.maxTokens || model.maxTokens / 3 | 0,
997
+ stream: true
998
+ };
999
+ if (isOAuthToken) {
1000
+ params.system = [{
1001
+ type: "text",
1002
+ text: "You are Claude Code, Anthropic's official CLI for Claude.",
1003
+ ...cacheControl ? { cache_control: cacheControl } : {}
1004
+ }];
1005
+ if (context.systemPrompt) params.system.push({
1006
+ type: "text",
1007
+ text: sanitizeSurrogates(context.systemPrompt),
1008
+ ...cacheControl ? { cache_control: cacheControl } : {}
1009
+ });
1010
+ } else if (context.systemPrompt) params.system = [{
1011
+ type: "text",
1012
+ text: sanitizeSurrogates(context.systemPrompt),
1013
+ ...cacheControl ? { cache_control: cacheControl } : {}
1014
+ }];
1015
+ if (options?.temperature !== void 0 && !options?.thinkingEnabled) params.temperature = options.temperature;
1016
+ if (context.tools) params.tools = convertTools(context.tools, isOAuthToken);
1017
+ if (options?.thinkingEnabled && model.reasoning) params.thinking = {
1018
+ type: "enabled",
1019
+ budget_tokens: options.thinkingBudgetTokens || 1024
1020
+ };
1021
+ if (options?.metadata) {
1022
+ const userId = options.metadata.user_id;
1023
+ if (typeof userId === "string") params.metadata = { user_id: userId };
1024
+ }
1025
+ if (options?.toolChoice) params.tool_choice = typeof options.toolChoice === "string" ? { type: options.toolChoice } : options.toolChoice;
1026
+ return params;
1027
+ }
1028
+ const streamAnthropic = (model, context, options) => {
1029
+ const stream = new AssistantMessageEventStream();
1030
+ (async () => {
1031
+ const output = {
1032
+ role: "assistant",
1033
+ parts: [],
1034
+ protocol: model.protocol,
1035
+ provider: model.provider,
1036
+ model: model.id,
1037
+ usage: {
1038
+ input: 0,
1039
+ output: 0,
1040
+ cacheRead: 0,
1041
+ cacheWrite: 0,
1042
+ totalTokens: 0,
1043
+ cost: {
1044
+ input: 0,
1045
+ output: 0,
1046
+ cacheRead: 0,
1047
+ cacheWrite: 0,
1048
+ total: 0
1049
+ }
1050
+ },
1051
+ stopReason: "stop",
1052
+ time: {
1053
+ created: Date.now(),
1054
+ completed: Date.now()
1055
+ }
1056
+ };
1057
+ try {
1058
+ let client;
1059
+ let isOAuthToken;
1060
+ if (options?.client) {
1061
+ client = options.client;
1062
+ isOAuthToken = false;
1063
+ } else {
1064
+ const apiKey = options?.apiKey ?? getEnvApiKey(model.provider);
1065
+ if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
1066
+ const created = createClient(model, apiKey, options?.interleavedThinking ?? true, options?.headers);
1067
+ client = created.client;
1068
+ isOAuthToken = created.isOAuthToken;
1069
+ }
1070
+ let params = buildParams(model, context, isOAuthToken, options);
1071
+ const nextParams = await options?.onPayload?.(params, model);
1072
+ if (nextParams !== void 0) params = nextParams;
1073
+ const anthropicStream = client.messages.stream({
1074
+ ...params,
1075
+ stream: true
1076
+ }, { signal: options?.signal });
1077
+ stream.push({
1078
+ type: "start",
1079
+ partial: output
1080
+ });
1081
+ const blocks = output.parts;
1082
+ for await (const event of anthropicStream) if (event.type === "message_start") {
1083
+ output.responseID = event.message.id;
1084
+ output.usage.input = event.message.usage.input_tokens || 0;
1085
+ output.usage.output = event.message.usage.output_tokens || 0;
1086
+ output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
1087
+ output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
1088
+ output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
1089
+ Model.calculateCost(model, output.usage);
1090
+ } else if (event.type === "content_block_start") {
1091
+ if (event.content_block.type === "text") {
1092
+ const block = {
1093
+ type: "text",
1094
+ text: "",
1095
+ index: event.index
1096
+ };
1097
+ output.parts.push(block);
1098
+ stream.push({
1099
+ type: "text.start",
1100
+ partIndex: output.parts.length - 1,
1101
+ partial: output
1102
+ });
1103
+ } else if (event.content_block.type === "thinking") {
1104
+ const block = {
1105
+ type: "thinking",
1106
+ thinking: "",
1107
+ thinkingSignature: "",
1108
+ index: event.index
1109
+ };
1110
+ output.parts.push(block);
1111
+ stream.push({
1112
+ type: "thinking.start",
1113
+ partIndex: output.parts.length - 1,
1114
+ partial: output
1115
+ });
1116
+ } else if (event.content_block.type === "redacted_thinking") {
1117
+ const block = {
1118
+ type: "thinking",
1119
+ thinking: "[Reasoning redacted]",
1120
+ thinkingSignature: event.content_block.data,
1121
+ redacted: true,
1122
+ index: event.index
1123
+ };
1124
+ output.parts.push(block);
1125
+ stream.push({
1126
+ type: "thinking.start",
1127
+ partIndex: output.parts.length - 1,
1128
+ partial: output
1129
+ });
1130
+ } else if (event.content_block.type === "tool_use") {
1131
+ const block = {
1132
+ type: "toolCall",
1133
+ callID: event.content_block.id,
1134
+ name: isOAuthToken ? fromClaudeCodeName(event.content_block.name, context.tools) : event.content_block.name,
1135
+ arguments: event.content_block.input ?? {},
1136
+ partialJson: "",
1137
+ status: "pending",
1138
+ time: {
1139
+ start: Date.now(),
1140
+ end: Date.now()
1141
+ },
1142
+ index: event.index
1143
+ };
1144
+ output.parts.push(block);
1145
+ stream.push({
1146
+ type: "toolcall.start",
1147
+ partIndex: output.parts.length - 1,
1148
+ partial: output
1149
+ });
1150
+ }
1151
+ } else if (event.type === "content_block_delta") {
1152
+ const partIndex = blocks.findIndex((b) => b.index === event.index);
1153
+ const block = blocks[partIndex];
1154
+ if (!block) continue;
1155
+ if (event.delta.type === "text_delta" && block.type === "text") {
1156
+ block.text += event.delta.text;
1157
+ stream.push({
1158
+ type: "text.delta",
1159
+ partIndex,
1160
+ delta: event.delta.text,
1161
+ partial: output
1162
+ });
1163
+ } else if (event.delta.type === "thinking_delta" && block.type === "thinking") {
1164
+ block.thinking += event.delta.thinking;
1165
+ stream.push({
1166
+ type: "thinking.delta",
1167
+ partIndex,
1168
+ delta: event.delta.thinking,
1169
+ partial: output
1170
+ });
1171
+ } else if (event.delta.type === "input_json_delta" && block.type === "toolCall") {
1172
+ block.partialJson += event.delta.partial_json;
1173
+ block.arguments = parseStreamingJson(block.partialJson);
1174
+ stream.push({
1175
+ type: "toolcall.delta",
1176
+ partIndex,
1177
+ delta: event.delta.partial_json,
1178
+ partial: output
1179
+ });
1180
+ } else if (event.delta.type === "signature_delta" && block.type === "thinking") {
1181
+ block.thinkingSignature = block.thinkingSignature || "";
1182
+ block.thinkingSignature += event.delta.signature;
1183
+ }
1184
+ } else if (event.type === "content_block_stop") {
1185
+ const partIndex = blocks.findIndex((b) => b.index === event.index);
1186
+ const block = blocks[partIndex];
1187
+ if (block) {
1188
+ delete block.index;
1189
+ if (block.type === "text") stream.push({
1190
+ type: "text.end",
1191
+ partIndex,
1192
+ content: block.text,
1193
+ partial: output
1194
+ });
1195
+ else if (block.type === "thinking") stream.push({
1196
+ type: "thinking.end",
1197
+ partIndex,
1198
+ content: block.thinking,
1199
+ partial: output
1200
+ });
1201
+ else if (block.type === "toolCall") {
1202
+ block.arguments = parseStreamingJson(block.partialJson);
1203
+ delete block.partialJson;
1204
+ stream.push({
1205
+ type: "toolcall.end",
1206
+ partIndex,
1207
+ toolCall: block,
1208
+ partial: output
1209
+ });
1210
+ }
1211
+ }
1212
+ } else if (event.type === "message_delta") {
1213
+ if (event.delta.stop_reason) output.stopReason = mapStopReason(event.delta.stop_reason);
1214
+ if (event.usage.input_tokens != null) output.usage.input = event.usage.input_tokens;
1215
+ if (event.usage.output_tokens != null) output.usage.output = event.usage.output_tokens;
1216
+ if (event.usage.cache_read_input_tokens != null) output.usage.cacheRead = event.usage.cache_read_input_tokens;
1217
+ if (event.usage.cache_creation_input_tokens != null) output.usage.cacheWrite = event.usage.cache_creation_input_tokens;
1218
+ output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
1219
+ Model.calculateCost(model, output.usage);
1220
+ }
1221
+ if (options?.signal?.aborted) throw new Error("Request was aborted");
1222
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
1223
+ output.time.completed = Date.now();
1224
+ stream.push({
1225
+ type: "done",
1226
+ reason: output.stopReason,
1227
+ message: output
1228
+ });
1229
+ stream.end();
1230
+ } catch (error) {
1231
+ for (const block of output.parts) delete block.index;
1232
+ output.time.completed = Date.now();
1233
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
1234
+ output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
1235
+ stream.push({
1236
+ type: "error",
1237
+ reason: output.stopReason,
1238
+ error: output
1239
+ });
1240
+ stream.end();
1241
+ }
1242
+ })();
1243
+ return stream;
1244
+ };
1245
+ const streamSimpleAnthropic = (model, context, options) => {
1246
+ const apiKey = options?.apiKey || getEnvApiKey(model.provider);
1247
+ if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
1248
+ const base = Stream.buildBaseOptions(model, options, apiKey);
1249
+ if (!options?.reasoning) return streamAnthropic(model, context, {
1250
+ ...base,
1251
+ thinkingEnabled: false
1252
+ });
1253
+ const adjusted = Stream.adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options.thinkingBudgets);
1254
+ return streamAnthropic(model, context, {
1255
+ ...base,
1256
+ maxTokens: adjusted.maxTokens,
1257
+ thinkingEnabled: true,
1258
+ thinkingBudgetTokens: adjusted.thinkingBudget
1259
+ });
1260
+ };
1261
+ //#endregion
1262
+ //#region src/provider/register.ts
1263
+ const providerModules = [["providers/anthropic/index.ts", {
1264
+ protocol: Model.KnownProtocolEnum.anthropicMessages,
1265
+ stream: streamAnthropic,
1266
+ streamSimple: streamSimpleAnthropic
1267
+ }]];
1268
+ for (const [path, provider] of providerModules) Stream.registerProtocolProvider(provider, path);
1269
+ //#endregion
1270
+ //#region src/utils/validation.ts
1271
+ /**
1272
+ * @description Validation powered by ajv, TypeBox natively doesn't provide data validation.
1273
+ */
1274
+ const ajv = new Ajv({
1275
+ allErrors: true,
1276
+ strict: false,
1277
+ coerceTypes: true
1278
+ });
1279
+ addFormats(ajv);
1280
+ /**
1281
+ * Finds a tool by name and validates the tool call arguments against its TypeBox schema
1282
+ */
1283
+ function validateToolCall(tools, toolExecution) {
1284
+ const tool = tools.find((t) => t.name === toolExecution.name);
1285
+ if (!tool) throw new Error(`Tool "${toolExecution.name}" not found`);
1286
+ return validateToolArguments(tool, toolExecution);
1287
+ }
1288
+ /**
1289
+ * Validates tool call arguments against the tool's TypeBox schema
1290
+ */
1291
+ function validateToolArguments(tool, toolExecution) {
1292
+ const validate = ajv.compile(tool.parameters);
1293
+ const args = structuredClone(toolExecution.rawArgs);
1294
+ if (validate(args)) return args;
1295
+ const errors = validate.errors?.map((err) => {
1296
+ return ` - ${err.instancePath ? err.instancePath.substring(1) : err.params?.missingProperty || "root"}: ${err.message}`;
1297
+ }).join("\n") || "Unknown Validation Error";
1298
+ throw new Error([
1299
+ `Validation Failed For Tool "${toolExecution.name}"`,
1300
+ `${errors}\n`,
1301
+ "Received Arguments:",
1302
+ `${JSON.stringify(toolExecution.rawArgs, null, 2)}\n`
1303
+ ].join("\n"));
1304
+ }
1305
+ //#endregion
1306
+ //#region src/agent/loop.ts
1307
+ let Loop;
1308
+ (function(_Loop) {
1309
+ function createAgentStream() {
1310
+ return new EventStream((event) => event.type === "agent.end", (event) => event.type === "agent.end" ? event.messages : []);
1311
+ }
1312
+ const AgentContextError = _Loop.AgentContextError = NamedError.create("AgentContextError", Type.Object({ message: Type.String() }));
1313
+ function snapshotAssistantMessage(message) {
1314
+ return structuredClone(message);
1315
+ }
1316
+ function snapshotAssistantPartEvent(message, partIndex) {
1317
+ const snapshot = snapshotAssistantMessage(message);
1318
+ const part = snapshot.parts[partIndex];
1319
+ if (!part) throw new Error(`Assistant message part at index ${partIndex} was not found`);
1320
+ return {
1321
+ message: snapshot,
1322
+ part
1323
+ };
1324
+ }
1325
+ async function emitEvent(emit, event) {
1326
+ await emit(event);
1327
+ }
1328
+ async function streamAssistantResponse(config, context, emit, streamFn, signal) {
1329
+ let messages = context.messages;
1330
+ if (config.transformContext) messages = await config.transformContext(messages, signal);
1331
+ const llmMessages = await config.convertToLlm(messages);
1332
+ const llmContext = {
1333
+ systemPrompt: context.systemPrompt,
1334
+ messages: llmMessages,
1335
+ tools: context.tools
1336
+ };
1337
+ const streamFunction = streamFn || Stream.streamSimple;
1338
+ const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : void 0) || config.apiKey;
1339
+ const events = await streamFunction(config.model, llmContext, {
1340
+ ...config,
1341
+ apiKey: resolvedApiKey,
1342
+ signal
1343
+ });
1344
+ let partialMessage = null;
1345
+ let started = false;
1346
+ const ensureMessageStarted = async (message) => {
1347
+ if (started) return;
1348
+ started = true;
1349
+ await emitEvent(emit, {
1350
+ type: "message.start",
1351
+ message: snapshotAssistantMessage(message)
1352
+ });
1353
+ };
1354
+ const emitMessageUpdate = async (message) => {
1355
+ await emitEvent(emit, {
1356
+ type: "message.update",
1357
+ message: snapshotAssistantMessage(message)
1358
+ });
1359
+ };
1360
+ const emitPartStart = async (message, partIndex) => {
1361
+ await emitEvent(emit, {
1362
+ type: "message.part.start",
1363
+ partIndex,
1364
+ ...snapshotAssistantPartEvent(message, partIndex)
1365
+ });
1366
+ };
1367
+ const emitPartUpdate = async (message, partIndex) => {
1368
+ await emitEvent(emit, {
1369
+ type: "message.part.update",
1370
+ partIndex,
1371
+ ...snapshotAssistantPartEvent(message, partIndex),
1372
+ source: "llm"
1373
+ });
1374
+ };
1375
+ const emitPartEnd = async (message, partIndex) => {
1376
+ await emitEvent(emit, {
1377
+ type: "message.part.end",
1378
+ partIndex,
1379
+ ...snapshotAssistantPartEvent(message, partIndex)
1380
+ });
1381
+ };
1382
+ for await (const event of events) switch (event.type) {
1383
+ case "start":
1384
+ partialMessage = event.partial;
1385
+ await ensureMessageStarted(partialMessage);
1386
+ break;
1387
+ case "text.start":
1388
+ case "thinking.start":
1389
+ case "toolcall.start":
1390
+ partialMessage = event.partial;
1391
+ await ensureMessageStarted(partialMessage);
1392
+ await emitPartStart(partialMessage, event.partIndex);
1393
+ break;
1394
+ case "text.delta":
1395
+ case "thinking.delta":
1396
+ case "toolcall.delta":
1397
+ partialMessage = event.partial;
1398
+ await ensureMessageStarted(partialMessage);
1399
+ await emitPartUpdate(partialMessage, event.partIndex);
1400
+ break;
1401
+ case "text.end":
1402
+ case "thinking.end":
1403
+ case "toolcall.end":
1404
+ partialMessage = event.partial;
1405
+ await ensureMessageStarted(partialMessage);
1406
+ await emitPartEnd(partialMessage, event.partIndex);
1407
+ await emitMessageUpdate(partialMessage);
1408
+ break;
1409
+ case "done":
1410
+ await ensureMessageStarted(event.message);
1411
+ await emitEvent(emit, {
1412
+ type: "message.end",
1413
+ message: snapshotAssistantMessage(event.message)
1414
+ });
1415
+ return event.message;
1416
+ case "error":
1417
+ await ensureMessageStarted(event.error);
1418
+ await emitEvent(emit, {
1419
+ type: "message.end",
1420
+ message: snapshotAssistantMessage(event.error)
1421
+ });
1422
+ return event.error;
1423
+ }
1424
+ const finalMessage = await events.result();
1425
+ await ensureMessageStarted(finalMessage);
1426
+ await emitEvent(emit, {
1427
+ type: "message.end",
1428
+ message: snapshotAssistantMessage(finalMessage)
1429
+ });
1430
+ return finalMessage;
1431
+ }
1432
+ async function executeToolCalls(config, currentContext, message, toolCalls, emit, signal) {
1433
+ if (config.toolExecution === "sequential") return executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal);
1434
+ return executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal);
1435
+ }
1436
+ async function executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal) {
1437
+ for (const toolCall of toolCalls) {
1438
+ const toolCallInFlight = {
1439
+ callID: toolCall.callID,
1440
+ name: toolCall.name,
1441
+ rawArgs: toolCall.arguments
1442
+ };
1443
+ await emitEvent(emit, {
1444
+ type: "tool.execution.start",
1445
+ ...toolCallInFlight
1446
+ });
1447
+ const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
1448
+ if (prepared.error) {
1449
+ const error = {
1450
+ status: "error",
1451
+ result: {
1452
+ content: [{
1453
+ type: "text",
1454
+ text: prepared.error.message
1455
+ }],
1456
+ details: prepared.error.details,
1457
+ isError: true
1458
+ }
1459
+ };
1460
+ await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
1461
+ } else {
1462
+ const runnable = {
1463
+ toolCall,
1464
+ runnable: prepared.runnable,
1465
+ tool: prepared.tool
1466
+ };
1467
+ const executed = await executeRunnableToolCall(runnable, message, emit, signal);
1468
+ if (executed.error) {
1469
+ const error = {
1470
+ status: "error",
1471
+ result: {
1472
+ content: [{
1473
+ type: "text",
1474
+ text: executed.error.message
1475
+ }],
1476
+ details: executed.error.details,
1477
+ isError: true
1478
+ }
1479
+ };
1480
+ await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
1481
+ } else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
1482
+ }
1483
+ }
1484
+ }
1485
+ async function executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal) {
1486
+ const runnables = [];
1487
+ for (const toolCall of toolCalls) {
1488
+ const toolCallInFlight = {
1489
+ callID: toolCall.callID,
1490
+ name: toolCall.name,
1491
+ rawArgs: toolCall.arguments
1492
+ };
1493
+ await emitEvent(emit, {
1494
+ type: "tool.execution.start",
1495
+ ...toolCallInFlight
1496
+ });
1497
+ const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
1498
+ if (prepared.error) {
1499
+ const error = {
1500
+ status: "error",
1501
+ result: {
1502
+ content: [{
1503
+ type: "text",
1504
+ text: prepared.error.message
1505
+ }],
1506
+ details: prepared.error.details,
1507
+ isError: true
1508
+ }
1509
+ };
1510
+ await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
1511
+ } else runnables.push({
1512
+ toolCall,
1513
+ runnable: prepared.runnable,
1514
+ tool: prepared.tool
1515
+ });
1516
+ }
1517
+ const runningExecutions = runnables.map((runnable) => ({
1518
+ runnable,
1519
+ execution: executeRunnableToolCall(runnable, message, emit, signal)
1520
+ }));
1521
+ for (const running of runningExecutions) {
1522
+ const executed = await running.execution;
1523
+ const { runnable } = running;
1524
+ if (executed.error) {
1525
+ const error = {
1526
+ status: "error",
1527
+ result: {
1528
+ content: [{
1529
+ type: "text",
1530
+ text: executed.error.message
1531
+ }],
1532
+ details: executed.error.details,
1533
+ isError: true
1534
+ }
1535
+ };
1536
+ await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
1537
+ } else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
1538
+ }
1539
+ }
1540
+ async function prepareToolCall(config, currentContext, assistantMessage, toolCallInFlight, signal) {
1541
+ const tool = currentContext.tools?.find((t) => t.name === toolCallInFlight.name);
1542
+ if (!tool) return {
1543
+ error: {
1544
+ kind: "error",
1545
+ message: `Tool ${toolCallInFlight.name} Not Found`
1546
+ },
1547
+ runnable: toolCallInFlight
1548
+ };
1549
+ try {
1550
+ toolCallInFlight.args = validateToolArguments(tool, toolCallInFlight);
1551
+ if (config.beforeToolExecution) {
1552
+ const beforeResult = await config.beforeToolExecution({
1553
+ context: currentContext,
1554
+ assistantMessage,
1555
+ toolCall: toolCallInFlight
1556
+ }, signal);
1557
+ if (beforeResult?.block) return {
1558
+ error: {
1559
+ kind: "blocked",
1560
+ message: beforeResult?.reason || "Tool Execution was Blocked",
1561
+ details: beforeResult?.details
1562
+ },
1563
+ runnable: toolCallInFlight
1564
+ };
1565
+ }
1566
+ return {
1567
+ runnable: toolCallInFlight,
1568
+ tool
1569
+ };
1570
+ } catch (err) {
1571
+ return {
1572
+ error: {
1573
+ kind: "error",
1574
+ message: err instanceof Error ? err.message : String(err)
1575
+ },
1576
+ runnable: toolCallInFlight
1577
+ };
1578
+ }
1579
+ }
1580
+ async function executeRunnableToolCall(toolCallRunnable, message, emit, signal) {
1581
+ const { toolCall, runnable, tool } = toolCallRunnable;
1582
+ const { partIndex, ...pendingPart } = toolCall;
1583
+ try {
1584
+ return { result: await tool.execute(runnable.callID, runnable.args, signal, async (result) => {
1585
+ const runningResult = {
1586
+ status: "running",
1587
+ partial: result.partial
1588
+ };
1589
+ await emitEvent(emit, {
1590
+ type: "tool.execution.update",
1591
+ ...runnable,
1592
+ ...runningResult
1593
+ });
1594
+ const runningPart = {
1595
+ ...pendingPart,
1596
+ ...runningResult
1597
+ };
1598
+ message.parts[partIndex] = runningPart;
1599
+ await emitEvent(emit, {
1600
+ type: "message.part.update",
1601
+ message,
1602
+ partIndex,
1603
+ part: runningPart,
1604
+ source: "tool"
1605
+ });
1606
+ }) };
1607
+ } catch (err) {
1608
+ return { error: { message: err instanceof Error ? err.message : String(err) } };
1609
+ }
1610
+ }
1611
+ async function emitToolCallTerminalResult(toolCall, runnable, message, emit, result) {
1612
+ const { partIndex, ...pendingPart } = toolCall;
1613
+ const { time } = pendingPart;
1614
+ await emitEvent(emit, {
1615
+ type: "tool.execution.end",
1616
+ ...runnable,
1617
+ ...result
1618
+ });
1619
+ const part = {
1620
+ ...pendingPart,
1621
+ ...result,
1622
+ time: {
1623
+ start: time.start,
1624
+ end: Date.now()
1625
+ }
1626
+ };
1627
+ message.parts[partIndex] = part;
1628
+ await emitEvent(emit, {
1629
+ type: "message.part.start",
1630
+ message,
1631
+ partIndex,
1632
+ part
1633
+ });
1634
+ await emitEvent(emit, {
1635
+ type: "message.part.end",
1636
+ message,
1637
+ partIndex,
1638
+ part
1639
+ });
1640
+ await emitEvent(emit, {
1641
+ type: "message.update",
1642
+ message
1643
+ });
1644
+ }
1645
+ async function finalizeExecutedToolCall(config, currentContext, toolCall, runnable, message, emit, result, signal) {
1646
+ if (config.afterToolExecution) {
1647
+ const afterResult = await config.afterToolExecution({
1648
+ context: currentContext,
1649
+ assistantMessage: message,
1650
+ toolCall: runnable,
1651
+ result
1652
+ }, signal);
1653
+ if (afterResult) {
1654
+ await emitToolCallTerminalResult(toolCall, runnable, message, emit, afterResult);
1655
+ return;
1656
+ }
1657
+ }
1658
+ await emitToolCallTerminalResult(toolCall, runnable, message, emit, result);
1659
+ }
1660
+ /**
1661
+ * Main core loop shared by run and runContinue.
1662
+ */
1663
+ async function runLoop(config, currentContext, newMessages, emit, streamFn, signal) {
1664
+ let firstTurn = true;
1665
+ let pendingMessages = await config.getSteeringMessages?.() || [];
1666
+ while (true) {
1667
+ let hasMoreToolCalls = true;
1668
+ while (hasMoreToolCalls || pendingMessages.length > 0) {
1669
+ if (!firstTurn) await emitEvent(emit, { type: "turn.start" });
1670
+ else firstTurn = false;
1671
+ if (pendingMessages.length > 0) {
1672
+ for (const message of pendingMessages) {
1673
+ await emitEvent(emit, {
1674
+ type: "message.start",
1675
+ message
1676
+ });
1677
+ for (const [partIndex, part] of message.parts.entries()) {
1678
+ await emitEvent(emit, {
1679
+ type: "message.part.start",
1680
+ message,
1681
+ partIndex,
1682
+ part
1683
+ });
1684
+ await emitEvent(emit, {
1685
+ type: "message.part.end",
1686
+ message,
1687
+ partIndex,
1688
+ part
1689
+ });
1690
+ await emitEvent(emit, {
1691
+ type: "message.update",
1692
+ message
1693
+ });
1694
+ }
1695
+ await emitEvent(emit, {
1696
+ type: "message.end",
1697
+ message
1698
+ });
1699
+ currentContext.messages.push(message);
1700
+ newMessages.push(message);
1701
+ }
1702
+ pendingMessages = [];
1703
+ }
1704
+ const message = await streamAssistantResponse(config, currentContext, emit, streamFn, signal);
1705
+ if (message.stopReason === "error" || message.stopReason === "aborted") {
1706
+ currentContext.messages.push(message);
1707
+ newMessages.push(message);
1708
+ await emitEvent(emit, {
1709
+ type: "turn.end",
1710
+ message
1711
+ });
1712
+ await emitEvent(emit, {
1713
+ type: "agent.end",
1714
+ messages: newMessages
1715
+ });
1716
+ return;
1717
+ }
1718
+ const toolCalls = message.parts.map((part, index) => ({
1719
+ ...part,
1720
+ partIndex: index
1721
+ })).filter((part) => part.type === "toolCall" && part.status === "pending");
1722
+ hasMoreToolCalls = toolCalls.length > 0;
1723
+ if (hasMoreToolCalls) await executeToolCalls(config, currentContext, message, toolCalls, emit, signal);
1724
+ currentContext.messages.push(message);
1725
+ newMessages.push(message);
1726
+ await emitEvent(emit, {
1727
+ type: "turn.end",
1728
+ message
1729
+ });
1730
+ pendingMessages = await config.getSteeringMessages?.() || [];
1731
+ }
1732
+ const followUpMessages = await config.getFollowUpMessages?.() || [];
1733
+ if (followUpMessages.length > 0) {
1734
+ pendingMessages = followUpMessages;
1735
+ continue;
1736
+ }
1737
+ break;
1738
+ }
1739
+ await emitEvent(emit, {
1740
+ type: "agent.end",
1741
+ messages: newMessages
1742
+ });
1743
+ }
1744
+ async function runAgentLoop(config, context, prompts, emit, streamFn, signal) {
1745
+ /**
1746
+ * maintain 2 arrays to represent state, `context` the actual full state sent to the LLM,
1747
+ * `newMessages` for intermediate current loop state.
1748
+ * think of newMessages as subset of context.messages for the running current loop.
1749
+ * they do move at the same speed staring with initial user prompts.
1750
+ * */
1751
+ const newMessages = [...prompts];
1752
+ const currentContext = {
1753
+ ...context,
1754
+ messages: [...context.messages, ...prompts]
1755
+ };
1756
+ await emitEvent(emit, { type: "agent.start" });
1757
+ await emitEvent(emit, { type: "turn.start" });
1758
+ for (const prompt of prompts) {
1759
+ await emitEvent(emit, {
1760
+ type: "message.start",
1761
+ message: prompt
1762
+ });
1763
+ for (const [partIndex, part] of prompt.parts.entries()) {
1764
+ await emitEvent(emit, {
1765
+ type: "message.part.start",
1766
+ message: prompt,
1767
+ partIndex,
1768
+ part
1769
+ });
1770
+ await emitEvent(emit, {
1771
+ type: "message.part.end",
1772
+ message: prompt,
1773
+ partIndex,
1774
+ part
1775
+ });
1776
+ }
1777
+ await emitEvent(emit, {
1778
+ type: "message.end",
1779
+ message: prompt
1780
+ });
1781
+ }
1782
+ await runLoop(config, currentContext, newMessages, emit, streamFn, signal);
1783
+ return newMessages;
1784
+ }
1785
+ _Loop.runAgentLoop = runAgentLoop;
1786
+ async function runAgentLoopContinue(config, context, emit, streamFn, signal) {
1787
+ if (context.messages.length === 0) throw new AgentContextError({ message: "connot continue: no messages in context" });
1788
+ if (context.messages[context.messages.length - 1]?.role === "assistant") throw new AgentContextError({ message: "cannot continue from message role: assistant" });
1789
+ const newMessages = [];
1790
+ const currentContext = { ...context };
1791
+ await emitEvent(emit, { type: "agent.start" });
1792
+ await emitEvent(emit, { type: "turn.start" });
1793
+ await runLoop(config, currentContext, newMessages, emit, streamFn, signal);
1794
+ return newMessages;
1795
+ }
1796
+ _Loop.runAgentLoopContinue = runAgentLoopContinue;
1797
+ function run(config, context, prompts, streamFn, signal) {
1798
+ const stream = createAgentStream();
1799
+ runAgentLoop(config, context, prompts, async (event) => {
1800
+ stream.push(event);
1801
+ }, streamFn, signal).then((messages) => {
1802
+ stream.end(messages);
1803
+ });
1804
+ return stream;
1805
+ }
1806
+ _Loop.run = run;
1807
+ function runContinue(config, context, streamFn, signal) {
1808
+ const stream = createAgentStream();
1809
+ runAgentLoopContinue(config, context, async (event) => {
1810
+ stream.push(event);
1811
+ }, streamFn, signal).then((messages) => {
1812
+ stream.end(messages);
1813
+ });
1814
+ return stream;
1815
+ }
1816
+ _Loop.runContinue = runContinue;
1817
+ })(Loop || (Loop = {}));
1818
+ //#endregion
1819
+ //#region src/agent/agent.ts
1820
+ let Agent;
1821
+ (function(_Agent) {
1822
+ _Agent.ToolTerminalResultSchema = Type.Union([Message.ToolCompletedSchema, Message.ToolErrorSchema]);
1823
+ _Agent.ToolResultSchema = Type.Union([
1824
+ Message.ToolRunningSchema,
1825
+ Message.ToolCompletedSchema,
1826
+ Message.ToolErrorSchema
1827
+ ]);
1828
+ function defineTool(tool) {
1829
+ return tool;
1830
+ }
1831
+ _Agent.defineTool = defineTool;
1832
+ _Agent.ToolCallInFlightSchema = Type.Object({
1833
+ callID: Type.String(),
1834
+ name: Type.String(),
1835
+ rawArgs: Type.Record(Type.String(), Type.Unknown()),
1836
+ args: Type.Optional(Type.Unknown())
1837
+ });
1838
+ const ModelNotFoundErr = _Agent.ModelNotFoundErr = NamedError.create("ModelNotFoundErr", Type.Object({
1839
+ message: Type.String(),
1840
+ provider: Type.String(),
1841
+ model: Type.String()
1842
+ }));
1843
+ const ModelNotConfiguredErr = _Agent.ModelNotConfiguredErr = NamedError.create("ModelNotConfiguredErr", Type.Object({ message: Type.String() }));
1844
+ const AgentInStreamingErr = _Agent.AgentInStreamingErr = NamedError.create("AgentInStreamingErr", Type.Object({
1845
+ message: Type.String(),
1846
+ name: Type.String()
1847
+ }));
1848
+ class Instance {
1849
+ _state;
1850
+ listeners = /* @__PURE__ */ new Set();
1851
+ abortController;
1852
+ activeAssistantIndex;
1853
+ convertToLlm;
1854
+ transformContext;
1855
+ steeringQueue = [];
1856
+ followUpQueue = [];
1857
+ steeringMode;
1858
+ followUpMode;
1859
+ streamFn;
1860
+ _sessionId;
1861
+ getApiKey;
1862
+ _onPayload;
1863
+ runningPrompt;
1864
+ resolveRunningPrompt;
1865
+ _thinkingBudgets;
1866
+ _transport;
1867
+ _maxRetryDelayMs;
1868
+ _toolExecution;
1869
+ _beforeToolExecution;
1870
+ _afterToolExecution;
1871
+ constructor(name, model, opts = {}) {
1872
+ this._state = {
1873
+ systemPrompt: "",
1874
+ thinkingLevel: "off",
1875
+ tools: [],
1876
+ messages: [],
1877
+ isStreaming: false,
1878
+ streamMessage: null,
1879
+ pendingToolCalls: /* @__PURE__ */ new Set(),
1880
+ error: void 0,
1881
+ ...opts.initialState,
1882
+ name,
1883
+ model
1884
+ };
1885
+ /**
1886
+ * Transformation logic to prepare messages for the LLM.
1887
+ * * @remarks
1888
+ * Currently just forwards messages as-is. Modify this logic when
1889
+ * specific formatting or filtering is required.
1890
+ * A good example is using user message parts with custom content
1891
+ * * @default
1892
+ * forwards messages as is.
1893
+ */
1894
+ this.convertToLlm = opts.convertToLlm || ((messages) => messages);
1895
+ this.transformContext = opts.transformContext;
1896
+ this.steeringMode = opts.steeringMode || "one-at-a-time";
1897
+ this.followUpMode = opts.followUpMode || "one-at-a-time";
1898
+ this.streamFn = opts.streamFn || Stream.streamSimple;
1899
+ this._sessionId = opts.sessionId;
1900
+ this.getApiKey = opts.getApiKey;
1901
+ this._onPayload = opts.onPayload;
1902
+ this._thinkingBudgets = opts.thinkingBudgets;
1903
+ this._transport = opts.transport ?? "sse";
1904
+ this._maxRetryDelayMs = opts.maxRetryDelayMs;
1905
+ this._toolExecution = opts.toolExecution ?? "parallel";
1906
+ this._beforeToolExecution = opts.beforeToolExecution;
1907
+ this._afterToolExecution = opts.afterToolExecution;
1908
+ }
1909
+ /**
1910
+ * Get the current session ID used for provider caching.
1911
+ */
1912
+ get sessionId() {
1913
+ return this._sessionId;
1914
+ }
1915
+ /**
1916
+ * Set the session ID for provider caching.
1917
+ * Call this when switching sessions (new session, branch, resume, etc).
1918
+ */
1919
+ set sessionId(value) {
1920
+ this._sessionId = value;
1921
+ }
1922
+ /**
1923
+ * Get the current thinking budgets.
1924
+ */
1925
+ get thinkingBudgets() {
1926
+ return this._thinkingBudgets;
1927
+ }
1928
+ /**
1929
+ * Set custom thinking budgets for token-based providers.
1930
+ */
1931
+ set thinkingBudgets(value) {
1932
+ this._thinkingBudgets = value;
1933
+ }
1934
+ /**
1935
+ * Get the current preferred transport.
1936
+ */
1937
+ get transport() {
1938
+ return this._transport;
1939
+ }
1940
+ /**
1941
+ * Set the preferred transport.
1942
+ */
1943
+ setTransport(value) {
1944
+ this._transport = value;
1945
+ }
1946
+ /**
1947
+ * Get the current max retry delay in milliseconds.
1948
+ */
1949
+ get maxRetryDelayMs() {
1950
+ return this._maxRetryDelayMs;
1951
+ }
1952
+ /**
1953
+ * Set the maximum delay to wait for server-requested retries.
1954
+ * Set to 0 to disable the cap.
1955
+ */
1956
+ set maxRetryDelayMs(value) {
1957
+ this._maxRetryDelayMs = value;
1958
+ }
1959
+ get toolExecution() {
1960
+ return this._toolExecution;
1961
+ }
1962
+ setToolExecution(value) {
1963
+ this._toolExecution = value;
1964
+ }
1965
+ setBeforeToolExecution(value) {
1966
+ this._beforeToolExecution = value;
1967
+ }
1968
+ setAfterToolExecution(value) {
1969
+ this._afterToolExecution = value;
1970
+ }
1971
+ get state() {
1972
+ return this._state;
1973
+ }
1974
+ subscribe(fn) {
1975
+ this.listeners.add(fn);
1976
+ return () => this.listeners.delete(fn);
1977
+ }
1978
+ setSystemPrompt(v) {
1979
+ this._state.systemPrompt = v;
1980
+ }
1981
+ setModel(m) {
1982
+ this._state.model = m;
1983
+ }
1984
+ setThinkingLevel(l) {
1985
+ this._state.thinkingLevel = l;
1986
+ }
1987
+ setSteeringMode(mode) {
1988
+ this.steeringMode = mode;
1989
+ }
1990
+ getSteeringMode() {
1991
+ return this.steeringMode;
1992
+ }
1993
+ setFollowUpMode(mode) {
1994
+ this.followUpMode = mode;
1995
+ }
1996
+ getFollowUpMode() {
1997
+ return this.followUpMode;
1998
+ }
1999
+ setTools(t) {
2000
+ this._state.tools = t;
2001
+ }
2002
+ replaceMessages(ms) {
2003
+ this._state.messages = ms.slice();
2004
+ this.activeAssistantIndex = void 0;
2005
+ }
2006
+ appendMessage(m) {
2007
+ this._state.messages = [...this._state.messages, m];
2008
+ }
2009
+ patchStoredAssistantPart(partIndex, part) {
2010
+ if (this.activeAssistantIndex === void 0) return false;
2011
+ const messages = this._state.messages.slice();
2012
+ const existing = messages[this.activeAssistantIndex];
2013
+ if (!existing || existing.role !== "assistant") return false;
2014
+ const nextParts = existing.parts.slice();
2015
+ nextParts[partIndex] = part;
2016
+ messages[this.activeAssistantIndex] = {
2017
+ ...existing,
2018
+ parts: nextParts
2019
+ };
2020
+ this._state.messages = messages;
2021
+ return true;
2022
+ }
2023
+ /**
2024
+ * Queue a steering message while the agent is running.
2025
+ * Delivered after the current assistant turn finishes executing its tool calls,
2026
+ * before the next LLM call.
2027
+ */
2028
+ steer(m) {
2029
+ this.steeringQueue.push(m);
2030
+ }
2031
+ /**
2032
+ * Queue a follow-up message to be processed after the agent finishes.
2033
+ * Delivered only when agent has no more tool calls or steering messages.
2034
+ */
2035
+ followUp(m) {
2036
+ this.followUpQueue.push(m);
2037
+ }
2038
+ clearSteeringQueue() {
2039
+ this.steeringQueue = [];
2040
+ }
2041
+ clearFollowUpQueue() {
2042
+ this.followUpQueue = [];
2043
+ }
2044
+ clearAllQueues() {
2045
+ this.steeringQueue = [];
2046
+ this.followUpQueue = [];
2047
+ }
2048
+ hasQueuedMessages() {
2049
+ return this.steeringQueue.length > 0 || this.followUpQueue.length > 0;
2050
+ }
2051
+ dequeueSteeringMessages() {
2052
+ if (this.steeringMode === "one-at-a-time") {
2053
+ if (this.steeringQueue.length > 0) {
2054
+ const first = this.steeringQueue[0];
2055
+ this.steeringQueue = this.steeringQueue.slice(1);
2056
+ return [first];
2057
+ }
2058
+ return [];
2059
+ }
2060
+ const steering = this.steeringQueue.slice();
2061
+ this.steeringQueue = [];
2062
+ return steering;
2063
+ }
2064
+ dequeueFollowUpMessages() {
2065
+ if (this.followUpMode === "one-at-a-time") {
2066
+ if (this.followUpQueue.length > 0) {
2067
+ const first = this.followUpQueue[0];
2068
+ this.followUpQueue = this.followUpQueue.slice(1);
2069
+ return [first];
2070
+ }
2071
+ return [];
2072
+ }
2073
+ const followUp = this.followUpQueue.slice();
2074
+ this.followUpQueue = [];
2075
+ return followUp;
2076
+ }
2077
+ clearMessages() {
2078
+ this._state.messages = [];
2079
+ this.activeAssistantIndex = void 0;
2080
+ }
2081
+ abort() {
2082
+ this.abortController?.abort();
2083
+ }
2084
+ waitForIdle() {
2085
+ return this.runningPrompt ?? Promise.resolve();
2086
+ }
2087
+ reset() {
2088
+ this._state.messages = [];
2089
+ this._state.isStreaming = false;
2090
+ this._state.streamMessage = null;
2091
+ this._state.pendingToolCalls = /* @__PURE__ */ new Set();
2092
+ this._state.error = void 0;
2093
+ this.activeAssistantIndex = void 0;
2094
+ this.steeringQueue = [];
2095
+ this.followUpQueue = [];
2096
+ }
2097
+ getName() {
2098
+ return this._state.name;
2099
+ }
2100
+ ensureIdle() {
2101
+ if (this._state.isStreaming) throw new AgentInStreamingErr({
2102
+ message: "agent is already processing a prompt. Use steer() or followup() to queue messages, or wait for completion.",
2103
+ name: this._state.name
2104
+ });
2105
+ }
2106
+ async _runLoop(messages, opts) {
2107
+ const model = this._state.model;
2108
+ if (!model) throw new ModelNotConfiguredErr({ message: "no model configured yet" });
2109
+ this.runningPrompt = new Promise((resolve) => {
2110
+ this.resolveRunningPrompt = resolve;
2111
+ });
2112
+ this.abortController = new AbortController();
2113
+ this._state.isStreaming = true;
2114
+ this._state.streamMessage = null;
2115
+ this._state.error = void 0;
2116
+ const reasoning = this.state.thinkingLevel === "off" ? void 0 : this._state.thinkingLevel;
2117
+ const context = {
2118
+ systemPrompt: this._state.systemPrompt,
2119
+ messages: this._state.messages.slice(),
2120
+ tools: this._state.tools
2121
+ };
2122
+ let skipInitialSteeringPoll = opts?.skipInitialSteeringPoll === true;
2123
+ const config = {
2124
+ model,
2125
+ reasoning,
2126
+ sessionId: this._sessionId,
2127
+ onPayload: this._onPayload,
2128
+ transport: this._transport,
2129
+ thinkingBudgets: this._thinkingBudgets,
2130
+ maxRetryDelayMs: this._maxRetryDelayMs,
2131
+ toolExecution: this._toolExecution,
2132
+ beforeToolExecution: this._beforeToolExecution,
2133
+ afterToolExecution: this._afterToolExecution,
2134
+ convertToLlm: this.convertToLlm,
2135
+ transformContext: this.transformContext,
2136
+ getApiKey: this.getApiKey,
2137
+ getSteeringMessages: async () => {
2138
+ if (skipInitialSteeringPoll) {
2139
+ skipInitialSteeringPoll = false;
2140
+ return [];
2141
+ }
2142
+ return this.dequeueSteeringMessages();
2143
+ },
2144
+ getFollowUpMessages: async () => this.dequeueFollowUpMessages()
2145
+ };
2146
+ try {
2147
+ if (messages) await Loop.runAgentLoop(config, context, messages, async (e) => this._processLoopEvent(e), this.streamFn, this.abortController.signal);
2148
+ else await Loop.runAgentLoopContinue(config, context, async (e) => this._processLoopEvent(e), this.streamFn, this.abortController.signal);
2149
+ } catch (err) {
2150
+ const message = {
2151
+ role: "assistant",
2152
+ protocol: model.protocol,
2153
+ provider: model.provider,
2154
+ model: model.id,
2155
+ usage: {
2156
+ input: 0,
2157
+ output: 0,
2158
+ cacheRead: 0,
2159
+ cacheWrite: 0,
2160
+ totalTokens: 0,
2161
+ cost: {
2162
+ input: 0,
2163
+ output: 0,
2164
+ cacheRead: 0,
2165
+ cacheWrite: 0,
2166
+ total: 0
2167
+ }
2168
+ },
2169
+ stopReason: this.abortController.signal.aborted ? "aborted" : "error",
2170
+ errorMessage: err?.message || String(err),
2171
+ time: {
2172
+ created: Date.now(),
2173
+ completed: Date.now()
2174
+ },
2175
+ parts: []
2176
+ };
2177
+ this.appendMessage(message);
2178
+ this._state.error = err?.message || String(err);
2179
+ this.emit({
2180
+ type: "agent.end",
2181
+ messages: [message]
2182
+ });
2183
+ } finally {
2184
+ this._state.isStreaming = false;
2185
+ this._state.streamMessage = null;
2186
+ this._state.pendingToolCalls = /* @__PURE__ */ new Set();
2187
+ this.abortController = void 0;
2188
+ this.resolveRunningPrompt?.();
2189
+ this.runningPrompt = void 0;
2190
+ this.resolveRunningPrompt = void 0;
2191
+ }
2192
+ }
2193
+ async loop(messages) {
2194
+ this.ensureIdle();
2195
+ await this._runLoop(messages);
2196
+ }
2197
+ async loopContinue() {
2198
+ this.ensureIdle();
2199
+ await this._runLoop();
2200
+ }
2201
+ async prompt(messages, images) {
2202
+ this.ensureIdle();
2203
+ if (!this._state.model) throw new ModelNotConfiguredErr({ message: "no model configured yet." });
2204
+ const message = {
2205
+ role: "user",
2206
+ time: { created: Date.now() },
2207
+ parts: [...messages, ...images ?? []]
2208
+ };
2209
+ await this.loop([message]);
2210
+ }
2211
+ _processLoopEvent(event) {
2212
+ switch (event.type) {
2213
+ case "message.start":
2214
+ this._state.streamMessage = event.message;
2215
+ if (event.message.role === "assistant") this.activeAssistantIndex = void 0;
2216
+ break;
2217
+ case "message.part.start":
2218
+ case "message.part.update":
2219
+ case "message.part.end":
2220
+ this._state.streamMessage = event.message;
2221
+ if (event.message.role === "assistant") this.patchStoredAssistantPart(event.partIndex, event.part);
2222
+ break;
2223
+ case "message.update":
2224
+ this._state.streamMessage = event.message;
2225
+ break;
2226
+ case "message.end":
2227
+ this._state.streamMessage = null;
2228
+ this.appendMessage(event.message);
2229
+ if (event.message.role === "assistant") this.activeAssistantIndex = this._state.messages.length - 1;
2230
+ break;
2231
+ case "tool.execution.start": {
2232
+ const pendingToolCalls = new Set(this._state.pendingToolCalls);
2233
+ pendingToolCalls.add(event.callID);
2234
+ this._state.pendingToolCalls = pendingToolCalls;
2235
+ break;
2236
+ }
2237
+ case "tool.execution.end": {
2238
+ const pendingToolCalls = new Set(this._state.pendingToolCalls);
2239
+ pendingToolCalls.delete(event.callID);
2240
+ this._state.pendingToolCalls = pendingToolCalls;
2241
+ break;
2242
+ }
2243
+ case "turn.end":
2244
+ if (event.message.role === "assistant" && event.message.parts.length > 0) this._state.error = event.message.errorMessage;
2245
+ break;
2246
+ case "agent.end":
2247
+ this._state.isStreaming = false;
2248
+ this._state.streamMessage = null;
2249
+ break;
2250
+ }
2251
+ this.emit(event);
2252
+ }
2253
+ emit(e) {
2254
+ for (const listener of this.listeners) listener(e);
2255
+ }
2256
+ }
2257
+ _Agent.Instance = Instance;
2258
+ async function create(options) {
2259
+ let resolvedModel;
2260
+ if ("provider" in options) {
2261
+ const result = await Model.getModel(options.provider, options.model);
2262
+ if (!result) throw new ModelNotFoundErr({
2263
+ message: "model not found or not configured yet",
2264
+ provider: options.provider,
2265
+ model: options.model
2266
+ });
2267
+ resolvedModel = result;
2268
+ } else resolvedModel = options.model;
2269
+ return new Instance(options.name ?? "main", resolvedModel, options);
2270
+ }
2271
+ _Agent.create = create;
2272
+ })(Agent || (Agent = {}));
2273
+ //#endregion
2274
+ //#region src/agent.ts
2275
+ const agent = {
2276
+ create: Agent.create,
2277
+ loop: Loop.run,
2278
+ loopContinue: Loop.runContinue
2279
+ };
2280
+ //#endregion
2281
+ //#region src/event/event.ts
2282
+ let Event;
2283
+ (function(_Event) {
2284
+ const LLMMessageEventType = _Event.LLMMessageEventType = {
2285
+ start: "start",
2286
+ textStart: "text.start",
2287
+ textDelta: "text.delta",
2288
+ textEnd: "text.end",
2289
+ thinkingStart: "thinking.start",
2290
+ thinkingDelta: "thinking.delta",
2291
+ thinkingEnd: "thinking.end",
2292
+ toolcallStart: "toolcall.start",
2293
+ toolcallDelta: "toolcall.delta",
2294
+ toolcallEnd: "toolcall.end",
2295
+ done: "done",
2296
+ error: "error"
2297
+ };
2298
+ _Event.LLMMessageEventSchema = Type.Union([
2299
+ Type.Object({
2300
+ type: Type.Literal(LLMMessageEventType.start),
2301
+ partial: Message.AssistantMessageSchema
2302
+ }),
2303
+ Type.Object({
2304
+ type: Type.Literal(LLMMessageEventType.textStart),
2305
+ partIndex: Type.Number(),
2306
+ partial: Message.AssistantMessageSchema
2307
+ }),
2308
+ Type.Object({
2309
+ type: Type.Literal(LLMMessageEventType.textDelta),
2310
+ partIndex: Type.Number(),
2311
+ delta: Type.String(),
2312
+ partial: Message.AssistantMessageSchema
2313
+ }),
2314
+ Type.Object({
2315
+ type: Type.Literal(LLMMessageEventType.textEnd),
2316
+ partIndex: Type.Number(),
2317
+ content: Type.String(),
2318
+ partial: Message.AssistantMessageSchema
2319
+ }),
2320
+ Type.Object({
2321
+ type: Type.Literal(LLMMessageEventType.thinkingStart),
2322
+ partIndex: Type.Number(),
2323
+ partial: Message.AssistantMessageSchema
2324
+ }),
2325
+ Type.Object({
2326
+ type: Type.Literal(LLMMessageEventType.thinkingDelta),
2327
+ partIndex: Type.Number(),
2328
+ delta: Type.String(),
2329
+ partial: Message.AssistantMessageSchema
2330
+ }),
2331
+ Type.Object({
2332
+ type: Type.Literal(LLMMessageEventType.thinkingEnd),
2333
+ partIndex: Type.Number(),
2334
+ content: Type.String(),
2335
+ partial: Message.AssistantMessageSchema
2336
+ }),
2337
+ Type.Object({
2338
+ type: Type.Literal(LLMMessageEventType.toolcallStart),
2339
+ partIndex: Type.Number(),
2340
+ partial: Message.AssistantMessageSchema
2341
+ }),
2342
+ Type.Object({
2343
+ type: Type.Literal(LLMMessageEventType.toolcallDelta),
2344
+ partIndex: Type.Number(),
2345
+ delta: Type.String(),
2346
+ partial: Message.AssistantMessageSchema
2347
+ }),
2348
+ Type.Object({
2349
+ type: Type.Literal(LLMMessageEventType.toolcallEnd),
2350
+ partIndex: Type.Number(),
2351
+ toolCall: Message.ToolCallSchema,
2352
+ partial: Message.AssistantMessageSchema
2353
+ }),
2354
+ Type.Object({
2355
+ type: Type.Literal(LLMMessageEventType.done),
2356
+ reason: Type.Union([
2357
+ Type.Literal("stop"),
2358
+ Type.Literal("length"),
2359
+ Type.Literal("toolUse")
2360
+ ]),
2361
+ message: Message.AssistantMessageSchema
2362
+ }),
2363
+ Type.Object({
2364
+ type: Type.Literal(LLMMessageEventType.error),
2365
+ reason: Type.Union([Type.Literal("aborted"), Type.Literal("error")]),
2366
+ error: Message.AssistantMessageSchema
2367
+ })
2368
+ ]);
2369
+ const AgentEventType = _Event.AgentEventType = {
2370
+ agentStart: "agent.start",
2371
+ agentEnd: "agent.end",
2372
+ turnStart: "turn.start",
2373
+ turnEnd: "turn.end",
2374
+ messageStart: "message.start",
2375
+ messagePartStart: "message.part.start",
2376
+ messagePartUpdate: "message.part.update",
2377
+ messagePartEnd: "message.part.end",
2378
+ messageUpdate: "message.update",
2379
+ messageEnd: "message.end",
2380
+ toolExecutionStart: "tool.execution.start",
2381
+ toolExecutionUpdate: "tool.execution.update",
2382
+ toolExecutionEnd: "tool.execution.end"
2383
+ };
2384
+ const UserMessagePart = Type.Union([Message.TextContentSchema, Message.ImageContentSchema]);
2385
+ const AssistantMessagePart = Type.Union([
2386
+ Message.TextContentSchema,
2387
+ Message.ImageContentSchema,
2388
+ Message.ThinkingContentSchema,
2389
+ Message.ToolCallSchema
2390
+ ]);
2391
+ const UserMessagePartStart = Type.Object({
2392
+ type: Type.Literal(AgentEventType.messagePartStart),
2393
+ message: Message.UserMessageSchema,
2394
+ partIndex: Type.Number(),
2395
+ part: UserMessagePart
2396
+ });
2397
+ const UserMessagePartEnd = Type.Object({
2398
+ type: Type.Literal(AgentEventType.messagePartEnd),
2399
+ message: Message.UserMessageSchema,
2400
+ partIndex: Type.Number(),
2401
+ part: UserMessagePart
2402
+ });
2403
+ const AssistantMessagePartStart = Type.Object({
2404
+ type: Type.Literal(AgentEventType.messagePartStart),
2405
+ message: Message.AssistantMessageSchema,
2406
+ partIndex: Type.Number(),
2407
+ part: AssistantMessagePart
2408
+ });
2409
+ const AssistantMessagePartLLMUpdate = Type.Object({
2410
+ type: Type.Literal(AgentEventType.messagePartUpdate),
2411
+ message: Message.AssistantMessageSchema,
2412
+ partIndex: Type.Number(),
2413
+ part: AssistantMessagePart,
2414
+ source: Type.Literal("llm")
2415
+ });
2416
+ const AssistantMessagePartToolUpdate = Type.Object({
2417
+ type: Type.Literal(AgentEventType.messagePartUpdate),
2418
+ message: Message.AssistantMessageSchema,
2419
+ partIndex: Type.Number(),
2420
+ part: AssistantMessagePart,
2421
+ source: Type.Literal("tool")
2422
+ });
2423
+ const AssistantMessagePartEnd = Type.Object({
2424
+ type: Type.Literal(AgentEventType.messagePartEnd),
2425
+ message: Message.AssistantMessageSchema,
2426
+ partIndex: Type.Number(),
2427
+ part: AssistantMessagePart
2428
+ });
2429
+ const ToolExecutionStartSchema = Type.Composite([Agent.ToolCallInFlightSchema, Type.Object({ type: Type.Literal(AgentEventType.toolExecutionStart) })]);
2430
+ const ToolExecutionUpdateSchema = Type.Composite([
2431
+ Agent.ToolCallInFlightSchema,
2432
+ Type.Object({ type: Type.Literal(AgentEventType.toolExecutionUpdate) }),
2433
+ Message.ToolRunningSchema
2434
+ ]);
2435
+ const ToolExecutionEndSchema = Type.Composite([
2436
+ Agent.ToolCallInFlightSchema,
2437
+ Type.Object({ type: Type.Literal(AgentEventType.toolExecutionEnd) }),
2438
+ Type.Union([Message.ToolCompletedSchema, Message.ToolErrorSchema])
2439
+ ]);
2440
+ _Event.AgentEventSchema = Type.Union([
2441
+ Type.Object({ type: Type.Literal(AgentEventType.agentStart) }),
2442
+ Type.Object({
2443
+ type: Type.Literal(AgentEventType.agentEnd),
2444
+ messages: Type.Array(Message.MessageSchema)
2445
+ }),
2446
+ Type.Object({ type: Type.Literal(AgentEventType.turnStart) }),
2447
+ Type.Object({
2448
+ type: Type.Literal(AgentEventType.turnEnd),
2449
+ message: Message.AssistantMessageSchema
2450
+ }),
2451
+ Type.Object({
2452
+ type: Type.Literal(AgentEventType.messageStart),
2453
+ message: Message.MessageSchema
2454
+ }),
2455
+ Type.Union([UserMessagePartStart, UserMessagePartEnd]),
2456
+ Type.Union([
2457
+ AssistantMessagePartStart,
2458
+ AssistantMessagePartLLMUpdate,
2459
+ AssistantMessagePartToolUpdate,
2460
+ AssistantMessagePartEnd
2461
+ ]),
2462
+ Type.Object({
2463
+ type: Type.Literal(AgentEventType.messageUpdate),
2464
+ message: Message.MessageSchema
2465
+ }),
2466
+ Type.Object({
2467
+ type: Type.Literal(AgentEventType.messageEnd),
2468
+ message: Message.MessageSchema
2469
+ }),
2470
+ ToolExecutionStartSchema,
2471
+ ToolExecutionUpdateSchema,
2472
+ ToolExecutionEndSchema
2473
+ ]);
2474
+ })(Event || (Event = {}));
2475
+ //#endregion
2476
+ //#region src/llm.ts
2477
+ const llmImpl = async (provider, model) => Model.getModel(provider, model);
2478
+ const llm = Object.assign(llmImpl, {
2479
+ model: Model.getModel,
2480
+ models: Model.getModels,
2481
+ providers: Model.getProviders,
2482
+ registry: Model.registry,
2483
+ supportsXhigh: Model.supportsXhigh,
2484
+ modelsAreEqual: Model.modelsAreEqual
2485
+ });
2486
+ //#endregion
2487
+ //#region src/stream.ts
2488
+ const streamImpl = (model, context, options) => Stream.stream(model, context, options);
2489
+ /**
2490
+ * Start a streaming assistant response for a model/context pair.
2491
+ *
2492
+ * This is the main streaming entrypoint.
2493
+ * Attached helpers:
2494
+ *
2495
+ * - `stream.complete(...)` resolves the final assistant message without manually iterating events.
2496
+ * - `stream.simple(...)` uses `Stream.SimpleOptions` for higher-level reasoning controls.
2497
+ * - `stream.completeSimple(...)` is the non-streaming counterpart to `stream.simple(...)`.
2498
+ * - `stream.resolveProtocolProvider(...)` exposes protocol resolution for advanced integrations.
2499
+ */
2500
+ const stream = Object.assign(streamImpl, {
2501
+ complete: Stream.complete,
2502
+ simple: Stream.streamSimple,
2503
+ completeSimple: Stream.completeSimple,
2504
+ resolveProtocolProvider: Stream.resolveProtocolProvider
2505
+ });
2506
+ /** Resolve a streamed response directly to the final assistant message. */
2507
+ const complete = Stream.complete;
2508
+ /** Start a stream using the simplified options surface. */
2509
+ const streamSimple = Stream.streamSimple;
2510
+ /** Resolve a simplified stream request directly to the final assistant message. */
2511
+ const completeSimple = Stream.completeSimple;
2512
+ //#endregion
2513
+ export { Agent, Event, Message, Model, ModelCatalog, Stream, agent, complete, completeSimple, llm, stream, streamSimple, validateToolArguments, validateToolCall };
2514
+
2515
+ //# sourceMappingURL=index.mjs.map