@codeworksh/aikit 0.2.0 → 0.3.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/README.md +117 -260
- package/agent/codemode/drivers/drivers.d.mts +7 -0
- package/agent/codemode/drivers/drivers.mjs +122 -0
- package/agent/codemode/drivers/drivers.mjs.map +1 -0
- package/codemode-z3ZIw-5q.d.mts +8234 -0
- package/index.d.mts +2 -8865
- package/index.mjs +1814 -1635
- package/index.mjs.map +1 -1
- package/package.json +11 -7
package/index.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
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";
|
|
2
|
+
import { Type, TypeGuard } from "@sinclair/typebox";
|
|
3
|
+
import { capitalize, keys, mapValues, pick, pipe } from "remeda";
|
|
6
4
|
import Ajv from "ajv";
|
|
7
5
|
import addFormats from "ajv-formats";
|
|
6
|
+
import { uuidv7 } from "uuidv7";
|
|
7
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
8
|
+
import { parse } from "partial-json";
|
|
9
|
+
import { transform } from "esbuild";
|
|
8
10
|
//#region src/provider/provider.ts
|
|
9
11
|
let Provider;
|
|
10
12
|
(function(_Provider) {
|
|
@@ -239,395 +241,78 @@ let Model;
|
|
|
239
241
|
_Model.modelsAreEqual = modelsAreEqual;
|
|
240
242
|
})(Model || (Model = {}));
|
|
241
243
|
//#endregion
|
|
242
|
-
//#region src/
|
|
243
|
-
let
|
|
244
|
-
(function(
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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"
|
|
244
|
+
//#region src/provider/stream.ts
|
|
245
|
+
let Stream;
|
|
246
|
+
(function(_Stream) {
|
|
247
|
+
const ProtocolProviderNotFoundError = _Stream.ProtocolProviderNotFoundError = NamedError.create("ProtocolProviderNotFoundError", Type.Object({ protocol: Model.KnownProtocolSchema }));
|
|
248
|
+
const ProtocolMismatchError = _Stream.ProtocolMismatchError = NamedError.create("ProtocolMismatchError", Type.Object({
|
|
249
|
+
actual: Model.KnownProtocolSchema,
|
|
250
|
+
expected: Model.KnownProtocolSchema
|
|
251
|
+
}));
|
|
252
|
+
const ThinkingLevelEnum = _Stream.ThinkingLevelEnum = {
|
|
253
|
+
off: "off",
|
|
254
|
+
minimal: "minimal",
|
|
255
|
+
low: "low",
|
|
256
|
+
medium: "medium",
|
|
257
|
+
high: "high",
|
|
258
|
+
xhigh: "xhigh"
|
|
293
259
|
};
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
|
260
|
+
const ThinkingLevelSchema = _Stream.ThinkingLevelSchema = Type.Union([
|
|
261
|
+
Type.Literal(ThinkingLevelEnum.off),
|
|
262
|
+
Type.Literal(ThinkingLevelEnum.minimal),
|
|
263
|
+
Type.Literal(ThinkingLevelEnum.low),
|
|
264
|
+
Type.Literal(ThinkingLevelEnum.medium),
|
|
265
|
+
Type.Literal(ThinkingLevelEnum.high),
|
|
266
|
+
Type.Literal(ThinkingLevelEnum.xhigh)
|
|
327
267
|
]);
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
})
|
|
268
|
+
const ThinkingBudgetsSchema = _Stream.ThinkingBudgetsSchema = Type.Object({
|
|
269
|
+
off: Type.Optional(Type.Number()),
|
|
270
|
+
minimal: Type.Optional(Type.Number()),
|
|
271
|
+
low: Type.Optional(Type.Number()),
|
|
272
|
+
medium: Type.Optional(Type.Number()),
|
|
273
|
+
high: Type.Optional(Type.Number())
|
|
341
274
|
});
|
|
342
|
-
const
|
|
343
|
-
Type.Literal("
|
|
344
|
-
Type.Literal("
|
|
345
|
-
Type.Literal("
|
|
346
|
-
Type.Literal("error"),
|
|
347
|
-
Type.Literal("aborted")
|
|
275
|
+
const CacheRetentionSchema = _Stream.CacheRetentionSchema = Type.Union([
|
|
276
|
+
Type.Literal("none"),
|
|
277
|
+
Type.Literal("short"),
|
|
278
|
+
Type.Literal("long")
|
|
348
279
|
]);
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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()
|
|
280
|
+
const TransportSchema = _Stream.TransportSchema = Type.Union([
|
|
281
|
+
Type.Literal("sse"),
|
|
282
|
+
Type.Literal("websocket"),
|
|
283
|
+
Type.Literal("auto")
|
|
284
|
+
]);
|
|
285
|
+
const OptionsSchema = _Stream.OptionsSchema = Type.Object({
|
|
286
|
+
temperature: Type.Optional(Type.Number()),
|
|
287
|
+
maxTokens: Type.Optional(Type.Number()),
|
|
288
|
+
signal: Type.Optional(Type.Unsafe()),
|
|
289
|
+
apiKey: Type.Optional(Type.String()),
|
|
290
|
+
transport: Type.Optional(TransportSchema),
|
|
291
|
+
cacheRetention: Type.Optional(CacheRetentionSchema),
|
|
292
|
+
sessionId: Type.Optional(Type.String()),
|
|
293
|
+
onPayload: Type.Optional(Type.Unsafe()),
|
|
294
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
295
|
+
maxRetryDelayMs: Type.Optional(Type.Number()),
|
|
296
|
+
metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
|
|
379
297
|
});
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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
|
-
};
|
|
298
|
+
_Stream.SimpleOptionsSchema = Type.Composite([OptionsSchema, Type.Object({
|
|
299
|
+
reasoning: Type.Optional(ThinkingLevelSchema),
|
|
300
|
+
thinkingBudgets: Type.Optional(ThinkingBudgetsSchema)
|
|
301
|
+
})]);
|
|
302
|
+
function buildBaseOptions(model, options, apiKey) {
|
|
303
|
+
return {
|
|
304
|
+
temperature: options?.temperature,
|
|
305
|
+
maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32e3),
|
|
306
|
+
signal: options?.signal,
|
|
307
|
+
apiKey: apiKey || options?.apiKey,
|
|
308
|
+
transport: options?.transport,
|
|
309
|
+
cacheRetention: options?.cacheRetention,
|
|
310
|
+
sessionId: options?.sessionId,
|
|
311
|
+
headers: options?.headers,
|
|
312
|
+
onPayload: options?.onPayload,
|
|
313
|
+
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
314
|
+
metadata: options?.metadata
|
|
315
|
+
};
|
|
631
316
|
}
|
|
632
317
|
_Stream.buildBaseOptions = buildBaseOptions;
|
|
633
318
|
function clampReasoning(effort) {
|
|
@@ -722,1099 +407,1439 @@ let Stream;
|
|
|
722
407
|
_Stream.clearProtocolProviders = clearProtocolProviders;
|
|
723
408
|
})(Stream || (Stream = {}));
|
|
724
409
|
//#endregion
|
|
725
|
-
//#region src/
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
const
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
410
|
+
//#region src/utils/eventstream.ts
|
|
411
|
+
var EventStream = class {
|
|
412
|
+
queue = [];
|
|
413
|
+
waiting = [];
|
|
414
|
+
done = false;
|
|
415
|
+
finalResultPromise;
|
|
416
|
+
resolveFinalResult;
|
|
417
|
+
constructor(isComplete, extractResult) {
|
|
418
|
+
this.isComplete = isComplete;
|
|
419
|
+
this.extractResult = extractResult;
|
|
420
|
+
this.finalResultPromise = new Promise((resolve) => {
|
|
421
|
+
this.resolveFinalResult = resolve;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
push(event) {
|
|
425
|
+
if (this.done) return;
|
|
426
|
+
if (this.isComplete(event)) {
|
|
427
|
+
this.done = true;
|
|
428
|
+
this.resolveFinalResult(this.extractResult(event));
|
|
429
|
+
}
|
|
430
|
+
const waiter = this.waiting.shift();
|
|
431
|
+
if (waiter) waiter({
|
|
432
|
+
value: event,
|
|
433
|
+
done: false
|
|
434
|
+
});
|
|
435
|
+
else this.queue.push(event);
|
|
436
|
+
}
|
|
437
|
+
end(result) {
|
|
438
|
+
this.done = true;
|
|
439
|
+
if (result !== void 0) this.resolveFinalResult(result);
|
|
440
|
+
while (this.waiting.length > 0) this.waiting.shift()({
|
|
441
|
+
value: void 0,
|
|
442
|
+
done: true
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
async *[Symbol.asyncIterator]() {
|
|
446
|
+
while (true) if (this.queue.length > 0) yield this.queue.shift();
|
|
447
|
+
else if (this.done) return;
|
|
448
|
+
else {
|
|
449
|
+
const result = await new Promise((resolve) => this.waiting.push(resolve));
|
|
450
|
+
if (result.done) return;
|
|
451
|
+
yield result.value;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
result() {
|
|
455
|
+
return this.finalResultPromise;
|
|
770
456
|
}
|
|
771
|
-
return name;
|
|
772
457
|
};
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
type
|
|
778
|
-
|
|
779
|
-
};
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
458
|
+
var AssistantMessageEventStream = class extends EventStream {
|
|
459
|
+
constructor() {
|
|
460
|
+
super((event) => event.type === "done" || event.type === "error", (event) => {
|
|
461
|
+
if (event.type === "done") return event.message;
|
|
462
|
+
else if (event.type === "error") return event.error;
|
|
463
|
+
throw new Error("Unexpected event type for final result");
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
//#endregion
|
|
468
|
+
//#region src/utils/validation.ts
|
|
469
|
+
const ajv = new Ajv({
|
|
470
|
+
allErrors: true,
|
|
471
|
+
strict: false,
|
|
472
|
+
coerceTypes: true
|
|
473
|
+
});
|
|
474
|
+
addFormats(ajv);
|
|
475
|
+
/**
|
|
476
|
+
* Validates an arbitrary value against a TypeBox schema and returns the coerced value.
|
|
477
|
+
*/
|
|
478
|
+
function validateSchema(schema, value, label) {
|
|
479
|
+
const validate = ajv.compile(schema);
|
|
480
|
+
const input = structuredClone(value);
|
|
481
|
+
if (validate(input)) return input;
|
|
482
|
+
const errors = validate.errors?.map((err) => {
|
|
483
|
+
return ` - ${err.instancePath ? err.instancePath.substring(1) : err.params?.missingProperty || "root"}: ${err.message}`;
|
|
484
|
+
}).join("\n") || "Unknown Validation Error";
|
|
485
|
+
throw new Error([
|
|
486
|
+
`Validation Failed For ${label}`,
|
|
487
|
+
`${errors}\n`,
|
|
488
|
+
"Received Value:",
|
|
489
|
+
`${JSON.stringify(value, null, 2)}\n`
|
|
490
|
+
].join("\n"));
|
|
799
491
|
}
|
|
800
|
-
|
|
801
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Validates tool call arguments against the tool's TypeBox schema
|
|
494
|
+
*/
|
|
495
|
+
function validateToolArguments(tool, toolExecution) {
|
|
496
|
+
return validateSchema(tool.parameters, toolExecution.rawArgs, `Tool "${toolExecution.name}"`);
|
|
802
497
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
498
|
+
//#endregion
|
|
499
|
+
//#region src/agent/loop.ts
|
|
500
|
+
let Loop;
|
|
501
|
+
(function(_Loop) {
|
|
502
|
+
function createAgentStream() {
|
|
503
|
+
return new EventStream((event) => event.type === "agent.end", (event) => event.type === "agent.end" ? event.messages : []);
|
|
504
|
+
}
|
|
505
|
+
const AgentContextError = _Loop.AgentContextError = NamedError.create("AgentContextError", Type.Object({ message: Type.String() }));
|
|
506
|
+
function snapshotAssistantMessage(message) {
|
|
507
|
+
return structuredClone(message);
|
|
508
|
+
}
|
|
509
|
+
function snapshotAssistantPartEvent(message, partIndex) {
|
|
510
|
+
const snapshot = snapshotAssistantMessage(message);
|
|
511
|
+
const part = snapshot.parts[partIndex];
|
|
512
|
+
if (!part) throw new Error(`Assistant message part at index ${partIndex} was not found`);
|
|
814
513
|
return {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
authToken: apiKey,
|
|
818
|
-
baseURL: model.baseUrl,
|
|
819
|
-
defaultHeaders,
|
|
820
|
-
dangerouslyAllowBrowser: true
|
|
821
|
-
}),
|
|
822
|
-
isOAuthToken: true
|
|
514
|
+
message: snapshot,
|
|
515
|
+
part
|
|
823
516
|
};
|
|
824
517
|
}
|
|
825
|
-
|
|
826
|
-
|
|
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");
|
|
518
|
+
async function emitEvent(emit, event) {
|
|
519
|
+
await emit(event);
|
|
856
520
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
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
|
|
521
|
+
async function streamAssistantResponse(config, context, emit, streamFn, signal) {
|
|
522
|
+
let messages = context.messages;
|
|
523
|
+
if (config.transformContext) messages = await config.transformContext(messages, signal);
|
|
524
|
+
const llmMessages = await config.convertToLlm(messages);
|
|
525
|
+
const llmContext = {
|
|
526
|
+
systemPrompt: context.systemPrompt,
|
|
527
|
+
messages: llmMessages,
|
|
528
|
+
tools: context.tools
|
|
529
|
+
};
|
|
530
|
+
const streamFunction = streamFn || Stream.streamSimple;
|
|
531
|
+
const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : void 0) || config.apiKey;
|
|
532
|
+
const events = await streamFunction(config.model, llmContext, {
|
|
533
|
+
...config,
|
|
534
|
+
apiKey: resolvedApiKey,
|
|
535
|
+
signal
|
|
536
|
+
});
|
|
537
|
+
let partialMessage = null;
|
|
538
|
+
let started = false;
|
|
539
|
+
const ensureMessageStarted = async (message) => {
|
|
540
|
+
if (started) return;
|
|
541
|
+
started = true;
|
|
542
|
+
await emitEvent(emit, {
|
|
543
|
+
type: "message.start",
|
|
544
|
+
message: snapshotAssistantMessage(message)
|
|
901
545
|
});
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
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)
|
|
546
|
+
};
|
|
547
|
+
const emitMessageUpdate = async (message) => {
|
|
548
|
+
await emitEvent(emit, {
|
|
549
|
+
type: "message.update",
|
|
550
|
+
message: snapshotAssistantMessage(message)
|
|
913
551
|
});
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
type: "
|
|
918
|
-
|
|
552
|
+
};
|
|
553
|
+
const emitPartStart = async (message, partIndex) => {
|
|
554
|
+
await emitEvent(emit, {
|
|
555
|
+
type: "message.part.start",
|
|
556
|
+
partIndex,
|
|
557
|
+
...snapshotAssistantPartEvent(message, partIndex)
|
|
919
558
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
type: "tool_use",
|
|
928
|
-
id: block.callID,
|
|
929
|
-
name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
|
|
930
|
-
input: block.arguments ?? {}
|
|
559
|
+
};
|
|
560
|
+
const emitPartUpdate = async (message, partIndex) => {
|
|
561
|
+
await emitEvent(emit, {
|
|
562
|
+
type: "message.part.update",
|
|
563
|
+
partIndex,
|
|
564
|
+
...snapshotAssistantPartEvent(message, partIndex),
|
|
565
|
+
source: "llm"
|
|
931
566
|
});
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
567
|
+
};
|
|
568
|
+
const emitPartEnd = async (message, partIndex) => {
|
|
569
|
+
await emitEvent(emit, {
|
|
570
|
+
type: "message.part.end",
|
|
571
|
+
partIndex,
|
|
572
|
+
...snapshotAssistantPartEvent(message, partIndex)
|
|
938
573
|
});
|
|
574
|
+
};
|
|
575
|
+
for await (const event of events) switch (event.type) {
|
|
576
|
+
case "start":
|
|
577
|
+
partialMessage = event.partial;
|
|
578
|
+
await ensureMessageStarted(partialMessage);
|
|
579
|
+
break;
|
|
580
|
+
case "text.start":
|
|
581
|
+
case "thinking.start":
|
|
582
|
+
case "toolcall.start":
|
|
583
|
+
partialMessage = event.partial;
|
|
584
|
+
await ensureMessageStarted(partialMessage);
|
|
585
|
+
await emitPartStart(partialMessage, event.partIndex);
|
|
586
|
+
break;
|
|
587
|
+
case "text.delta":
|
|
588
|
+
case "thinking.delta":
|
|
589
|
+
case "toolcall.delta":
|
|
590
|
+
partialMessage = event.partial;
|
|
591
|
+
await ensureMessageStarted(partialMessage);
|
|
592
|
+
await emitPartUpdate(partialMessage, event.partIndex);
|
|
593
|
+
break;
|
|
594
|
+
case "text.end":
|
|
595
|
+
case "thinking.end":
|
|
596
|
+
case "toolcall.end":
|
|
597
|
+
partialMessage = event.partial;
|
|
598
|
+
await ensureMessageStarted(partialMessage);
|
|
599
|
+
await emitPartEnd(partialMessage, event.partIndex);
|
|
600
|
+
await emitMessageUpdate(partialMessage);
|
|
601
|
+
break;
|
|
602
|
+
case "done":
|
|
603
|
+
await ensureMessageStarted(event.message);
|
|
604
|
+
await emitEvent(emit, {
|
|
605
|
+
type: "message.end",
|
|
606
|
+
message: snapshotAssistantMessage(event.message)
|
|
607
|
+
});
|
|
608
|
+
return event.message;
|
|
609
|
+
case "error":
|
|
610
|
+
await ensureMessageStarted(event.error);
|
|
611
|
+
await emitEvent(emit, {
|
|
612
|
+
type: "message.end",
|
|
613
|
+
message: snapshotAssistantMessage(event.error)
|
|
614
|
+
});
|
|
615
|
+
return event.error;
|
|
939
616
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
role: "user",
|
|
946
|
-
content: toolResults
|
|
617
|
+
const finalMessage = await events.result();
|
|
618
|
+
await ensureMessageStarted(finalMessage);
|
|
619
|
+
await emitEvent(emit, {
|
|
620
|
+
type: "message.end",
|
|
621
|
+
message: snapshotAssistantMessage(finalMessage)
|
|
947
622
|
});
|
|
623
|
+
return finalMessage;
|
|
948
624
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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 };
|
|
625
|
+
async function executeToolCalls(config, currentContext, message, toolCalls, emit, signal) {
|
|
626
|
+
if (config.toolExecution === "sequential") return executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal);
|
|
627
|
+
return executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal);
|
|
1024
628
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
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;
|
|
629
|
+
async function executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal) {
|
|
630
|
+
for (const toolCall of toolCalls) {
|
|
631
|
+
const toolCallInFlight = {
|
|
632
|
+
callID: toolCall.callID,
|
|
633
|
+
name: toolCall.name,
|
|
634
|
+
rawArgs: toolCall.arguments
|
|
635
|
+
};
|
|
636
|
+
await emitEvent(emit, {
|
|
637
|
+
type: "tool.execution.start",
|
|
638
|
+
...toolCallInFlight
|
|
639
|
+
});
|
|
640
|
+
const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
|
|
641
|
+
if (prepared.error) {
|
|
642
|
+
const error = {
|
|
643
|
+
status: "error",
|
|
644
|
+
result: {
|
|
645
|
+
content: [{
|
|
646
|
+
type: "text",
|
|
647
|
+
text: prepared.error.message
|
|
648
|
+
}],
|
|
649
|
+
details: prepared.error.details,
|
|
650
|
+
isError: true
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
|
|
1063
654
|
} else {
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
655
|
+
const runnable = {
|
|
656
|
+
toolCall,
|
|
657
|
+
runnable: prepared.runnable,
|
|
658
|
+
tool: prepared.tool
|
|
659
|
+
};
|
|
660
|
+
const executed = await executeRunnableToolCall(runnable, message, emit, signal);
|
|
661
|
+
if (executed.error) {
|
|
662
|
+
const error = {
|
|
663
|
+
status: "error",
|
|
664
|
+
result: {
|
|
665
|
+
content: [{
|
|
666
|
+
type: "text",
|
|
667
|
+
text: executed.error.message
|
|
668
|
+
}],
|
|
669
|
+
details: executed.error.details,
|
|
670
|
+
isError: true
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
|
|
674
|
+
} else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
|
|
1069
675
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
async function executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal) {
|
|
679
|
+
const runnables = [];
|
|
680
|
+
for (const toolCall of toolCalls) {
|
|
681
|
+
const toolCallInFlight = {
|
|
682
|
+
callID: toolCall.callID,
|
|
683
|
+
name: toolCall.name,
|
|
684
|
+
rawArgs: toolCall.arguments
|
|
685
|
+
};
|
|
686
|
+
await emitEvent(emit, {
|
|
687
|
+
type: "tool.execution.start",
|
|
688
|
+
...toolCallInFlight
|
|
1080
689
|
});
|
|
1081
|
-
const
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
690
|
+
const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
|
|
691
|
+
if (prepared.error) {
|
|
692
|
+
const error = {
|
|
693
|
+
status: "error",
|
|
694
|
+
result: {
|
|
695
|
+
content: [{
|
|
696
|
+
type: "text",
|
|
697
|
+
text: prepared.error.message
|
|
698
|
+
}],
|
|
699
|
+
details: prepared.error.details,
|
|
700
|
+
isError: true
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
|
|
704
|
+
} else runnables.push({
|
|
705
|
+
toolCall,
|
|
706
|
+
runnable: prepared.runnable,
|
|
707
|
+
tool: prepared.tool
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
const runningExecutions = runnables.map((runnable) => ({
|
|
711
|
+
runnable,
|
|
712
|
+
execution: executeRunnableToolCall(runnable, message, emit, signal)
|
|
713
|
+
}));
|
|
714
|
+
for (const running of runningExecutions) {
|
|
715
|
+
const executed = await running.execution;
|
|
716
|
+
const { runnable } = running;
|
|
717
|
+
if (executed.error) {
|
|
718
|
+
const error = {
|
|
719
|
+
status: "error",
|
|
720
|
+
result: {
|
|
721
|
+
content: [{
|
|
722
|
+
type: "text",
|
|
723
|
+
text: executed.error.message
|
|
724
|
+
}],
|
|
725
|
+
details: executed.error.details,
|
|
726
|
+
isError: true
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
|
|
730
|
+
} else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async function prepareToolCall(config, currentContext, assistantMessage, toolCallInFlight, signal) {
|
|
734
|
+
const tool = currentContext.tools?.find((t) => t.name === toolCallInFlight.name);
|
|
735
|
+
if (!tool) return {
|
|
736
|
+
error: {
|
|
737
|
+
kind: "error",
|
|
738
|
+
message: `Tool ${toolCallInFlight.name} Not Found`
|
|
739
|
+
},
|
|
740
|
+
runnable: toolCallInFlight
|
|
741
|
+
};
|
|
742
|
+
try {
|
|
743
|
+
toolCallInFlight.args = validateToolArguments(tool, toolCallInFlight);
|
|
744
|
+
if (config.beforeToolExecution) {
|
|
745
|
+
const beforeResult = await config.beforeToolExecution({
|
|
746
|
+
context: currentContext,
|
|
747
|
+
assistantMessage,
|
|
748
|
+
toolCall: toolCallInFlight
|
|
749
|
+
}, signal);
|
|
750
|
+
if (beforeResult?.block) return {
|
|
751
|
+
error: {
|
|
752
|
+
kind: "blocked",
|
|
753
|
+
message: beforeResult?.reason || "Tool Execution was Blocked",
|
|
754
|
+
details: beforeResult?.details
|
|
755
|
+
},
|
|
756
|
+
runnable: toolCallInFlight
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
return {
|
|
760
|
+
runnable: toolCallInFlight,
|
|
761
|
+
tool
|
|
762
|
+
};
|
|
763
|
+
} catch (err) {
|
|
764
|
+
return {
|
|
765
|
+
error: {
|
|
766
|
+
kind: "error",
|
|
767
|
+
message: err instanceof Error ? err.message : String(err)
|
|
768
|
+
},
|
|
769
|
+
runnable: toolCallInFlight
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
async function executeRunnableToolCall(toolCallRunnable, message, emit, signal) {
|
|
774
|
+
const { toolCall, runnable, tool } = toolCallRunnable;
|
|
775
|
+
const { partIndex, ...pendingPart } = toolCall;
|
|
776
|
+
try {
|
|
777
|
+
return { result: await tool.execute(runnable.callID, runnable.args, signal, async (result) => {
|
|
778
|
+
const runningResult = {
|
|
779
|
+
status: "running",
|
|
780
|
+
partial: result.partial
|
|
781
|
+
};
|
|
782
|
+
await emitEvent(emit, {
|
|
783
|
+
type: "tool.execution.update",
|
|
784
|
+
...runnable,
|
|
785
|
+
...runningResult
|
|
786
|
+
});
|
|
787
|
+
const runningPart = {
|
|
788
|
+
...pendingPart,
|
|
789
|
+
...runningResult
|
|
790
|
+
};
|
|
791
|
+
message.parts[partIndex] = runningPart;
|
|
792
|
+
await emitEvent(emit, {
|
|
793
|
+
type: "message.part.update",
|
|
794
|
+
message,
|
|
795
|
+
partIndex,
|
|
796
|
+
part: runningPart,
|
|
797
|
+
source: "tool"
|
|
798
|
+
});
|
|
799
|
+
}) };
|
|
800
|
+
} catch (err) {
|
|
801
|
+
return { error: { message: err instanceof Error ? err.message : String(err) } };
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
async function emitToolCallTerminalResult(toolCall, runnable, message, emit, result) {
|
|
805
|
+
const { partIndex, ...pendingPart } = toolCall;
|
|
806
|
+
const { time } = pendingPart;
|
|
807
|
+
await emitEvent(emit, {
|
|
808
|
+
type: "tool.execution.end",
|
|
809
|
+
...runnable,
|
|
810
|
+
...result
|
|
811
|
+
});
|
|
812
|
+
const part = {
|
|
813
|
+
...pendingPart,
|
|
814
|
+
...result,
|
|
815
|
+
time: {
|
|
816
|
+
start: time.start,
|
|
817
|
+
end: Date.now()
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
message.parts[partIndex] = part;
|
|
821
|
+
await emitEvent(emit, {
|
|
822
|
+
type: "message.part.start",
|
|
823
|
+
message,
|
|
824
|
+
partIndex,
|
|
825
|
+
part
|
|
826
|
+
});
|
|
827
|
+
await emitEvent(emit, {
|
|
828
|
+
type: "message.part.end",
|
|
829
|
+
message,
|
|
830
|
+
partIndex,
|
|
831
|
+
part
|
|
832
|
+
});
|
|
833
|
+
await emitEvent(emit, {
|
|
834
|
+
type: "message.update",
|
|
835
|
+
message
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
async function finalizeExecutedToolCall(config, currentContext, toolCall, runnable, message, emit, result, signal) {
|
|
839
|
+
if (config.afterToolExecution) {
|
|
840
|
+
const afterResult = await config.afterToolExecution({
|
|
841
|
+
context: currentContext,
|
|
842
|
+
assistantMessage: message,
|
|
843
|
+
toolCall: runnable,
|
|
844
|
+
result
|
|
845
|
+
}, signal);
|
|
846
|
+
if (afterResult) {
|
|
847
|
+
await emitToolCallTerminalResult(toolCall, runnable, message, emit, afterResult);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
await emitToolCallTerminalResult(toolCall, runnable, message, emit, result);
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Main core loop shared by run and runContinue.
|
|
855
|
+
*/
|
|
856
|
+
async function runLoop(config, currentContext, newMessages, emit, streamFn, signal) {
|
|
857
|
+
let firstTurn = true;
|
|
858
|
+
let pendingMessages = await config.getSteeringMessages?.() || [];
|
|
859
|
+
while (true) {
|
|
860
|
+
let hasMoreToolCalls = true;
|
|
861
|
+
while (hasMoreToolCalls || pendingMessages.length > 0) {
|
|
862
|
+
if (!firstTurn) await emitEvent(emit, { type: "turn.start" });
|
|
863
|
+
else firstTurn = false;
|
|
864
|
+
if (pendingMessages.length > 0) {
|
|
865
|
+
for (const message of pendingMessages) {
|
|
866
|
+
await emitEvent(emit, {
|
|
867
|
+
type: "message.start",
|
|
868
|
+
message
|
|
869
|
+
});
|
|
870
|
+
for (const [partIndex, part] of message.parts.entries()) {
|
|
871
|
+
await emitEvent(emit, {
|
|
872
|
+
type: "message.part.start",
|
|
873
|
+
message,
|
|
874
|
+
partIndex,
|
|
875
|
+
part
|
|
876
|
+
});
|
|
877
|
+
await emitEvent(emit, {
|
|
878
|
+
type: "message.part.end",
|
|
879
|
+
message,
|
|
880
|
+
partIndex,
|
|
881
|
+
part
|
|
882
|
+
});
|
|
883
|
+
await emitEvent(emit, {
|
|
884
|
+
type: "message.update",
|
|
885
|
+
message
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
await emitEvent(emit, {
|
|
889
|
+
type: "message.end",
|
|
890
|
+
message
|
|
891
|
+
});
|
|
892
|
+
currentContext.messages.push(message);
|
|
893
|
+
newMessages.push(message);
|
|
894
|
+
}
|
|
895
|
+
pendingMessages = [];
|
|
896
|
+
}
|
|
897
|
+
const message = await streamAssistantResponse(config, currentContext, emit, streamFn, signal);
|
|
898
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
899
|
+
currentContext.messages.push(message);
|
|
900
|
+
newMessages.push(message);
|
|
901
|
+
await emitEvent(emit, {
|
|
902
|
+
type: "turn.end",
|
|
903
|
+
message
|
|
1102
904
|
});
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
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
|
|
905
|
+
await emitEvent(emit, {
|
|
906
|
+
type: "agent.end",
|
|
907
|
+
messages: newMessages
|
|
1149
908
|
});
|
|
909
|
+
return;
|
|
1150
910
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
911
|
+
const toolCalls = message.parts.map((part, index) => ({
|
|
912
|
+
...part,
|
|
913
|
+
partIndex: index
|
|
914
|
+
})).filter((part) => part.type === "toolCall" && part.status === "pending");
|
|
915
|
+
hasMoreToolCalls = toolCalls.length > 0;
|
|
916
|
+
if (hasMoreToolCalls) await executeToolCalls(config, currentContext, message, toolCalls, emit, signal);
|
|
917
|
+
currentContext.messages.push(message);
|
|
918
|
+
newMessages.push(message);
|
|
919
|
+
await emitEvent(emit, {
|
|
920
|
+
type: "turn.end",
|
|
921
|
+
message
|
|
922
|
+
});
|
|
923
|
+
pendingMessages = await config.getSteeringMessages?.() || [];
|
|
924
|
+
}
|
|
925
|
+
const followUpMessages = await config.getFollowUpMessages?.() || [];
|
|
926
|
+
if (followUpMessages.length > 0) {
|
|
927
|
+
pendingMessages = followUpMessages;
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
await emitEvent(emit, {
|
|
933
|
+
type: "agent.end",
|
|
934
|
+
messages: newMessages
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
async function runAgentLoop(config, context, prompts, emit, streamFn, signal) {
|
|
938
|
+
/**
|
|
939
|
+
* maintain 2 arrays to represent state, `context` the actual full state sent to the LLM,
|
|
940
|
+
* `newMessages` for intermediate current loop state.
|
|
941
|
+
* think of newMessages as subset of context.messages for the running current loop.
|
|
942
|
+
* they do move at the same speed staring with initial user prompts.
|
|
943
|
+
* */
|
|
944
|
+
const newMessages = [...prompts];
|
|
945
|
+
const currentContext = {
|
|
946
|
+
...context,
|
|
947
|
+
messages: [...context.messages, ...prompts]
|
|
948
|
+
};
|
|
949
|
+
await emitEvent(emit, { type: "agent.start" });
|
|
950
|
+
await emitEvent(emit, { type: "turn.start" });
|
|
951
|
+
for (const prompt of prompts) {
|
|
952
|
+
await emitEvent(emit, {
|
|
953
|
+
type: "message.start",
|
|
954
|
+
message: prompt
|
|
955
|
+
});
|
|
956
|
+
for (const [partIndex, part] of prompt.parts.entries()) {
|
|
957
|
+
await emitEvent(emit, {
|
|
958
|
+
type: "message.part.start",
|
|
959
|
+
message: prompt,
|
|
960
|
+
partIndex,
|
|
961
|
+
part
|
|
962
|
+
});
|
|
963
|
+
await emitEvent(emit, {
|
|
964
|
+
type: "message.part.end",
|
|
965
|
+
message: prompt,
|
|
966
|
+
partIndex,
|
|
967
|
+
part
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
await emitEvent(emit, {
|
|
971
|
+
type: "message.end",
|
|
972
|
+
message: prompt
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
await runLoop(config, currentContext, newMessages, emit, streamFn, signal);
|
|
976
|
+
return newMessages;
|
|
977
|
+
}
|
|
978
|
+
_Loop.runAgentLoop = runAgentLoop;
|
|
979
|
+
async function runAgentLoopContinue(config, context, emit, streamFn, signal) {
|
|
980
|
+
if (context.messages.length === 0) throw new AgentContextError({ message: "connot continue: no messages in context" });
|
|
981
|
+
if (context.messages[context.messages.length - 1]?.role === "assistant") throw new AgentContextError({ message: "cannot continue from message role: assistant" });
|
|
982
|
+
const newMessages = [];
|
|
983
|
+
const currentContext = { ...context };
|
|
984
|
+
await emitEvent(emit, { type: "agent.start" });
|
|
985
|
+
await emitEvent(emit, { type: "turn.start" });
|
|
986
|
+
await runLoop(config, currentContext, newMessages, emit, streamFn, signal);
|
|
987
|
+
return newMessages;
|
|
988
|
+
}
|
|
989
|
+
_Loop.runAgentLoopContinue = runAgentLoopContinue;
|
|
990
|
+
function run(config, context, prompts, streamFn, signal) {
|
|
991
|
+
const stream = createAgentStream();
|
|
992
|
+
runAgentLoop(config, context, prompts, async (event) => {
|
|
993
|
+
stream.push(event);
|
|
994
|
+
}, streamFn, signal).then((messages) => {
|
|
995
|
+
stream.end(messages);
|
|
996
|
+
});
|
|
997
|
+
return stream;
|
|
998
|
+
}
|
|
999
|
+
_Loop.run = run;
|
|
1000
|
+
function runContinue(config, context, streamFn, signal) {
|
|
1001
|
+
const stream = createAgentStream();
|
|
1002
|
+
runAgentLoopContinue(config, context, async (event) => {
|
|
1003
|
+
stream.push(event);
|
|
1004
|
+
}, streamFn, signal).then((messages) => {
|
|
1005
|
+
stream.end(messages);
|
|
1006
|
+
});
|
|
1007
|
+
return stream;
|
|
1008
|
+
}
|
|
1009
|
+
_Loop.runContinue = runContinue;
|
|
1010
|
+
})(Loop || (Loop = {}));
|
|
1011
|
+
//#endregion
|
|
1012
|
+
//#region src/agent.ts
|
|
1013
|
+
const agent = {
|
|
1014
|
+
loop: Loop.run,
|
|
1015
|
+
loopContinue: Loop.runContinue
|
|
1016
|
+
};
|
|
1017
|
+
//#endregion
|
|
1018
|
+
//#region src/message/message.ts
|
|
1019
|
+
let Message;
|
|
1020
|
+
(function(_Message) {
|
|
1021
|
+
const TextContentSchema = _Message.TextContentSchema = Type.Object({
|
|
1022
|
+
type: Type.Literal("text"),
|
|
1023
|
+
text: Type.String(),
|
|
1024
|
+
textSignature: Type.Optional(Type.String())
|
|
1025
|
+
});
|
|
1026
|
+
const ImageContentSchema = _Message.ImageContentSchema = Type.Object({
|
|
1027
|
+
type: Type.Literal("image"),
|
|
1028
|
+
data: Type.String(),
|
|
1029
|
+
mimeType: Type.String()
|
|
1030
|
+
});
|
|
1031
|
+
const ThinkingContentSchema = _Message.ThinkingContentSchema = Type.Object({
|
|
1032
|
+
type: Type.Literal("thinking"),
|
|
1033
|
+
thinking: Type.String(),
|
|
1034
|
+
thinkingSignature: Type.Optional(Type.String()),
|
|
1035
|
+
redacted: Type.Optional(Type.Boolean())
|
|
1036
|
+
});
|
|
1037
|
+
const ToolCallBaseSchema = _Message.ToolCallBaseSchema = Type.Object({
|
|
1038
|
+
type: Type.Literal("toolCall"),
|
|
1039
|
+
callID: Type.String(),
|
|
1040
|
+
name: Type.String(),
|
|
1041
|
+
arguments: Type.Record(Type.String(), Type.Any()),
|
|
1042
|
+
thoughtSignature: Type.Optional(Type.String()),
|
|
1043
|
+
time: Type.Object({
|
|
1044
|
+
start: Type.Number(),
|
|
1045
|
+
end: Type.Number()
|
|
1046
|
+
})
|
|
1047
|
+
});
|
|
1048
|
+
const ToolSuccessResult = _Message.ToolSuccessResult = Type.Object({
|
|
1049
|
+
content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
|
|
1050
|
+
details: Type.Optional(Type.Any()),
|
|
1051
|
+
isError: Type.Literal(false)
|
|
1052
|
+
});
|
|
1053
|
+
const ToolErrorResult = _Message.ToolErrorResult = Type.Object({
|
|
1054
|
+
content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
|
|
1055
|
+
details: Type.Optional(Type.Any()),
|
|
1056
|
+
isError: Type.Literal(true)
|
|
1057
|
+
});
|
|
1058
|
+
const ToolRunningPartial = _Message.ToolRunningPartial = Type.Object({
|
|
1059
|
+
content: Type.Optional(Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))),
|
|
1060
|
+
details: Type.Optional(Type.Any())
|
|
1061
|
+
});
|
|
1062
|
+
const ToolStatusEnum = _Message.ToolStatusEnum = {
|
|
1063
|
+
pending: "pending",
|
|
1064
|
+
running: "running",
|
|
1065
|
+
completed: "completed",
|
|
1066
|
+
error: "error",
|
|
1067
|
+
skipped: "skipped",
|
|
1068
|
+
aborted: "aborted"
|
|
1069
|
+
};
|
|
1070
|
+
const ToolRunningSchema = _Message.ToolRunningSchema = Type.Object({
|
|
1071
|
+
status: Type.Literal(ToolStatusEnum.running),
|
|
1072
|
+
partial: Type.Optional(ToolRunningPartial)
|
|
1073
|
+
});
|
|
1074
|
+
const ToolCompletedSchema = _Message.ToolCompletedSchema = Type.Object({
|
|
1075
|
+
status: Type.Literal(ToolStatusEnum.completed),
|
|
1076
|
+
result: ToolSuccessResult
|
|
1077
|
+
});
|
|
1078
|
+
const ToolErrorSchema = _Message.ToolErrorSchema = Type.Object({
|
|
1079
|
+
status: Type.Literal(ToolStatusEnum.error),
|
|
1080
|
+
result: ToolErrorResult
|
|
1081
|
+
});
|
|
1082
|
+
const ToolSkippedSchema = _Message.ToolSkippedSchema = Type.Object({
|
|
1083
|
+
status: Type.Literal(ToolStatusEnum.skipped),
|
|
1084
|
+
result: ToolErrorResult
|
|
1085
|
+
});
|
|
1086
|
+
const ToolAbortedSchema = _Message.ToolAbortedSchema = Type.Object({
|
|
1087
|
+
status: Type.Literal(ToolStatusEnum.aborted),
|
|
1088
|
+
result: ToolErrorResult
|
|
1089
|
+
});
|
|
1090
|
+
const ToolCallPendingPart = Type.Intersect([ToolCallBaseSchema, Type.Object({ status: Type.Literal(ToolStatusEnum.pending) })]);
|
|
1091
|
+
const ToolCallRunningPart = Type.Composite([ToolCallBaseSchema, ToolRunningSchema]);
|
|
1092
|
+
const ToolCallCompletedPart = Type.Composite([ToolCallBaseSchema, ToolCompletedSchema]);
|
|
1093
|
+
const ToolCallErrorPart = Type.Composite([ToolCallBaseSchema, ToolErrorSchema]);
|
|
1094
|
+
const ToolCallSkippedPart = Type.Composite([ToolCallBaseSchema, ToolSkippedSchema]);
|
|
1095
|
+
const ToolCallAbortedPart = Type.Composite([ToolCallBaseSchema, ToolAbortedSchema]);
|
|
1096
|
+
const ToolCallSchema = _Message.ToolCallSchema = Type.Union([
|
|
1097
|
+
ToolCallPendingPart,
|
|
1098
|
+
ToolCallRunningPart,
|
|
1099
|
+
ToolCallCompletedPart,
|
|
1100
|
+
ToolCallErrorPart,
|
|
1101
|
+
ToolCallSkippedPart,
|
|
1102
|
+
ToolCallAbortedPart
|
|
1103
|
+
]);
|
|
1104
|
+
const UsageSchema = _Message.UsageSchema = Type.Object({
|
|
1105
|
+
input: Type.Number(),
|
|
1106
|
+
output: Type.Number(),
|
|
1107
|
+
cacheRead: Type.Number(),
|
|
1108
|
+
cacheWrite: Type.Number(),
|
|
1109
|
+
totalTokens: Type.Number(),
|
|
1110
|
+
cost: Type.Object({
|
|
1111
|
+
input: Type.Number(),
|
|
1112
|
+
output: Type.Number(),
|
|
1113
|
+
cacheRead: Type.Number(),
|
|
1114
|
+
cacheWrite: Type.Number(),
|
|
1115
|
+
total: Type.Number()
|
|
1116
|
+
})
|
|
1117
|
+
});
|
|
1118
|
+
const StopReasonSchema = _Message.StopReasonSchema = Type.Union([
|
|
1119
|
+
Type.Literal("stop"),
|
|
1120
|
+
Type.Literal("length"),
|
|
1121
|
+
Type.Literal("toolUse"),
|
|
1122
|
+
Type.Literal("error"),
|
|
1123
|
+
Type.Literal("aborted")
|
|
1124
|
+
]);
|
|
1125
|
+
const UserMessageSchema = _Message.UserMessageSchema = Type.Object({
|
|
1126
|
+
messageId: Type.String(),
|
|
1127
|
+
role: Type.Literal("user"),
|
|
1128
|
+
time: Type.Object({ created: Type.Number() }),
|
|
1129
|
+
parts: Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))
|
|
1130
|
+
});
|
|
1131
|
+
const AssistantMessageSchema = _Message.AssistantMessageSchema = Type.Object({
|
|
1132
|
+
role: Type.Literal("assistant"),
|
|
1133
|
+
protocol: Model.KnownProtocolSchema,
|
|
1134
|
+
provider: Provider.Info,
|
|
1135
|
+
model: Type.String(),
|
|
1136
|
+
usage: UsageSchema,
|
|
1137
|
+
stopReason: StopReasonSchema,
|
|
1138
|
+
errorMessage: Type.Optional(Type.String()),
|
|
1139
|
+
time: Type.Object({
|
|
1140
|
+
created: Type.Number(),
|
|
1141
|
+
completed: Type.Number()
|
|
1142
|
+
}),
|
|
1143
|
+
parts: Type.Array(Type.Union([
|
|
1144
|
+
TextContentSchema,
|
|
1145
|
+
ImageContentSchema,
|
|
1146
|
+
ThinkingContentSchema,
|
|
1147
|
+
ToolCallSchema
|
|
1148
|
+
])),
|
|
1149
|
+
responseId: Type.Optional(Type.String()),
|
|
1150
|
+
messageId: Type.String()
|
|
1151
|
+
});
|
|
1152
|
+
const MessageSchema = _Message.MessageSchema = Type.Union([UserMessageSchema, AssistantMessageSchema]);
|
|
1153
|
+
function createMessageId() {
|
|
1154
|
+
return uuidv7();
|
|
1155
|
+
}
|
|
1156
|
+
_Message.createMessageId = createMessageId;
|
|
1157
|
+
function createUserMessage(message) {
|
|
1158
|
+
const { messageId = createMessageId(), ...rest } = message;
|
|
1159
|
+
return {
|
|
1160
|
+
messageId,
|
|
1161
|
+
...rest
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
_Message.createUserMessage = createUserMessage;
|
|
1165
|
+
function createAssistantMessage(message) {
|
|
1166
|
+
const { messageId = createMessageId(), ...rest } = message;
|
|
1167
|
+
return {
|
|
1168
|
+
messageId,
|
|
1169
|
+
...rest
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
_Message.createAssistantMessage = createAssistantMessage;
|
|
1173
|
+
const ToolSchema = _Message.ToolSchema = Type.Object({
|
|
1174
|
+
name: Type.String(),
|
|
1175
|
+
description: Type.String(),
|
|
1176
|
+
parameters: Type.Unsafe()
|
|
1177
|
+
});
|
|
1178
|
+
function defineTool(tool) {
|
|
1179
|
+
return tool;
|
|
1180
|
+
}
|
|
1181
|
+
_Message.defineTool = defineTool;
|
|
1182
|
+
_Message.ContextSchema = Type.Object({
|
|
1183
|
+
systemPrompt: Type.Optional(Type.String()),
|
|
1184
|
+
messages: Type.Array(MessageSchema),
|
|
1185
|
+
tools: Type.Optional(Type.Array(ToolSchema))
|
|
1186
|
+
});
|
|
1187
|
+
function transformMessages(messages, model, normalizeToolCallId) {
|
|
1188
|
+
const toolCallIDMap = /* @__PURE__ */ new Map();
|
|
1189
|
+
const transformed = [];
|
|
1190
|
+
for (const msg of messages) {
|
|
1191
|
+
if (msg.role === "user") {
|
|
1192
|
+
transformed.push(msg);
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
const assistantMsg = msg;
|
|
1196
|
+
const isSameModel = assistantMsg.provider.id === model.provider.id && assistantMsg.protocol === model.protocol && assistantMsg.model === model.id;
|
|
1197
|
+
const parts = assistantMsg.parts.flatMap((block) => {
|
|
1198
|
+
if (block.type === "thinking") {
|
|
1199
|
+
if (isSameModel && block.thinkingSignature) return block;
|
|
1200
|
+
if (!block.thinking || block.thinking.trim() === "") return [];
|
|
1201
|
+
if (isSameModel) return block;
|
|
1202
|
+
return {
|
|
1203
|
+
type: "text",
|
|
1204
|
+
text: block.thinking
|
|
1205
|
+
};
|
|
1183
1206
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1207
|
+
if (block.type === "text") {
|
|
1208
|
+
if (isSameModel) return block;
|
|
1209
|
+
return {
|
|
1210
|
+
type: "text",
|
|
1211
|
+
text: block.text
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
if (block.type === "toolCall") {
|
|
1215
|
+
const toolCall = block;
|
|
1216
|
+
let normalizedToolCall = toolCall;
|
|
1217
|
+
if (!isSameModel && toolCall.thoughtSignature) {
|
|
1218
|
+
normalizedToolCall = { ...toolCall };
|
|
1219
|
+
delete normalizedToolCall.thoughtSignature;
|
|
1220
|
+
}
|
|
1221
|
+
const normalizedID = toolCallIDMap.get(block.callID);
|
|
1222
|
+
if (normalizedID && normalizedID !== block.callID) normalizedToolCall = {
|
|
1223
|
+
...normalizedToolCall,
|
|
1224
|
+
callID: normalizedID
|
|
1225
|
+
};
|
|
1226
|
+
else if (!isSameModel && normalizeToolCallId) {
|
|
1227
|
+
const nextID = normalizeToolCallId(toolCall.callID, model, assistantMsg);
|
|
1228
|
+
if (nextID !== toolCall.callID) {
|
|
1229
|
+
toolCallIDMap.set(toolCall.callID, nextID);
|
|
1230
|
+
normalizedToolCall = {
|
|
1231
|
+
...normalizedToolCall,
|
|
1232
|
+
callID: nextID
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1210
1235
|
}
|
|
1236
|
+
return normalizedToolCall;
|
|
1211
1237
|
}
|
|
1212
|
-
|
|
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
|
|
1238
|
+
return block;
|
|
1228
1239
|
});
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
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
|
|
1240
|
+
transformed.push({
|
|
1241
|
+
...assistantMsg,
|
|
1242
|
+
parts
|
|
1239
1243
|
});
|
|
1240
|
-
stream.end();
|
|
1241
1244
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
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);
|
|
1245
|
+
return transformed;
|
|
1246
|
+
}
|
|
1247
|
+
_Message.transformMessages = transformMessages;
|
|
1248
|
+
})(Message || (Message = {}));
|
|
1269
1249
|
//#endregion
|
|
1270
|
-
//#region src/utils/
|
|
1250
|
+
//#region src/utils/jsonparse.ts
|
|
1271
1251
|
/**
|
|
1272
|
-
* @description
|
|
1252
|
+
* @description Helper function to parse partial jsons during LLM streaming.
|
|
1273
1253
|
*/
|
|
1274
|
-
const ajv = new Ajv({
|
|
1275
|
-
allErrors: true,
|
|
1276
|
-
strict: false,
|
|
1277
|
-
coerceTypes: true
|
|
1278
|
-
});
|
|
1279
|
-
addFormats(ajv);
|
|
1280
1254
|
/**
|
|
1281
|
-
*
|
|
1255
|
+
* Attempts to parse potentially incomplete JSON during streaming.
|
|
1256
|
+
* Always returns a valid object, even if the JSON is incomplete.
|
|
1257
|
+
*
|
|
1258
|
+
* @param partialJson The partial JSON string from streaming
|
|
1259
|
+
* @returns Parsed object or empty object if parsing fails
|
|
1282
1260
|
*/
|
|
1283
|
-
function
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1261
|
+
function parseStreamingJson(partialJson) {
|
|
1262
|
+
if (!partialJson || partialJson.trim() === "") return {};
|
|
1263
|
+
try {
|
|
1264
|
+
return JSON.parse(partialJson);
|
|
1265
|
+
} catch {
|
|
1266
|
+
try {
|
|
1267
|
+
return parse(partialJson) ?? {};
|
|
1268
|
+
} catch {
|
|
1269
|
+
return {};
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1287
1272
|
}
|
|
1273
|
+
//#endregion
|
|
1274
|
+
//#region src/utils/sanitize.ts
|
|
1288
1275
|
/**
|
|
1289
|
-
*
|
|
1276
|
+
* Removes unpaired Unicode surrogate characters from a string.
|
|
1277
|
+
*
|
|
1278
|
+
* Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
|
|
1279
|
+
* or vice versa) cause JSON serialization errors in many API providers.
|
|
1280
|
+
*
|
|
1281
|
+
* Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
|
|
1282
|
+
* surrogates and will NOT be affected by this function.
|
|
1283
|
+
*
|
|
1284
|
+
* @param text - The text to sanitize
|
|
1285
|
+
* @returns The sanitized text with unpaired surrogates removed
|
|
1286
|
+
*
|
|
1287
|
+
* @example
|
|
1288
|
+
* // Valid emoji (properly paired surrogates) are preserved
|
|
1289
|
+
* sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
|
|
1290
|
+
*
|
|
1291
|
+
* // Unpaired high surrogate is removed
|
|
1292
|
+
* const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
|
|
1293
|
+
* sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
|
|
1290
1294
|
*/
|
|
1291
|
-
function
|
|
1292
|
-
|
|
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"));
|
|
1295
|
+
function sanitizeSurrogates(text) {
|
|
1296
|
+
return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
|
|
1304
1297
|
}
|
|
1305
1298
|
//#endregion
|
|
1306
|
-
//#region src/
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1299
|
+
//#region src/provider/providers/anthropic/index.ts
|
|
1300
|
+
function getEnvApiKey(_provider) {}
|
|
1301
|
+
function resolveCacheRetention(cacheRetention) {
|
|
1302
|
+
if (cacheRetention) return cacheRetention;
|
|
1303
|
+
if (typeof process !== "undefined" && process.env.CODEWORK_CACHE_RETENTION === "long") return "long";
|
|
1304
|
+
return "short";
|
|
1305
|
+
}
|
|
1306
|
+
function getCacheControl(baseUrl, cacheRetention) {
|
|
1307
|
+
const retention = resolveCacheRetention(cacheRetention);
|
|
1308
|
+
if (retention === "none") return { retention };
|
|
1309
|
+
const ttl = retention === "long" && baseUrl.includes("api.anthropic.com") ? "1h" : void 0;
|
|
1310
|
+
return {
|
|
1311
|
+
retention,
|
|
1312
|
+
cacheControl: {
|
|
1313
|
+
type: "ephemeral",
|
|
1314
|
+
...ttl && { ttl }
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
const claudeCodeVersion = "2.1.2";
|
|
1319
|
+
const ccToolLookup = new Map([
|
|
1320
|
+
"Read",
|
|
1321
|
+
"Write",
|
|
1322
|
+
"Edit",
|
|
1323
|
+
"Bash",
|
|
1324
|
+
"Grep",
|
|
1325
|
+
"Glob",
|
|
1326
|
+
"AskUserQuestion",
|
|
1327
|
+
"EnterPlanMode",
|
|
1328
|
+
"ExitPlanMode",
|
|
1329
|
+
"KillShell",
|
|
1330
|
+
"NotebookEdit",
|
|
1331
|
+
"Skill",
|
|
1332
|
+
"Task",
|
|
1333
|
+
"TaskOutput",
|
|
1334
|
+
"TodoWrite",
|
|
1335
|
+
"WebFetch",
|
|
1336
|
+
"WebSearch"
|
|
1337
|
+
].map((t) => [t.toLowerCase(), t]));
|
|
1338
|
+
const toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;
|
|
1339
|
+
const fromClaudeCodeName = (name, tools) => {
|
|
1340
|
+
if (tools && tools.length > 0) {
|
|
1341
|
+
const lowerName = name.toLowerCase();
|
|
1342
|
+
const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
|
|
1343
|
+
if (matchedTool) return matchedTool.name;
|
|
1327
1344
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
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
|
-
});
|
|
1345
|
+
return name;
|
|
1346
|
+
};
|
|
1347
|
+
function convertContentBlocks(content) {
|
|
1348
|
+
if (!content.some((c) => c.type === "image")) return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
|
|
1349
|
+
const blocks = content.map((block) => {
|
|
1350
|
+
if (block.type === "text") return {
|
|
1351
|
+
type: "text",
|
|
1352
|
+
text: sanitizeSurrogates(block.text)
|
|
1366
1353
|
};
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
}
|
|
1354
|
+
return {
|
|
1355
|
+
type: "image",
|
|
1356
|
+
source: {
|
|
1357
|
+
type: "base64",
|
|
1358
|
+
media_type: block.mimeType,
|
|
1359
|
+
data: block.data
|
|
1360
|
+
}
|
|
1374
1361
|
};
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1362
|
+
});
|
|
1363
|
+
if (!blocks.some((b) => b.type === "text")) blocks.unshift({
|
|
1364
|
+
type: "text",
|
|
1365
|
+
text: "(see attached image)"
|
|
1366
|
+
});
|
|
1367
|
+
return blocks;
|
|
1368
|
+
}
|
|
1369
|
+
function mergeHeaders(...headerSources) {
|
|
1370
|
+
const merged = {};
|
|
1371
|
+
for (const headers of headerSources) if (headers) Object.assign(merged, headers);
|
|
1372
|
+
return merged;
|
|
1373
|
+
}
|
|
1374
|
+
function isOAuthToken(apiKey) {
|
|
1375
|
+
return apiKey.includes("sk-ant-oat");
|
|
1376
|
+
}
|
|
1377
|
+
function createClient(model, apiKey, interleavedThinking, optionsHeaders) {
|
|
1378
|
+
const betaFeatures = ["fine-grained-tool-streaming-2025-05-14"];
|
|
1379
|
+
if (interleavedThinking) betaFeatures.push("interleaved-thinking-2025-05-14");
|
|
1380
|
+
if (isOAuthToken(apiKey)) {
|
|
1381
|
+
const defaultHeaders = mergeHeaders({
|
|
1382
|
+
accept: "application/json",
|
|
1383
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
1384
|
+
"anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}`,
|
|
1385
|
+
"user-agent": `claude-cli/${claudeCodeVersion} (external, cli)`,
|
|
1386
|
+
"x-app": "cli"
|
|
1387
|
+
}, model.headers, optionsHeaders);
|
|
1388
|
+
return {
|
|
1389
|
+
client: new Anthropic({
|
|
1390
|
+
apiKey: null,
|
|
1391
|
+
authToken: apiKey,
|
|
1392
|
+
baseURL: model.baseUrl,
|
|
1393
|
+
defaultHeaders,
|
|
1394
|
+
dangerouslyAllowBrowser: true
|
|
1395
|
+
}),
|
|
1396
|
+
isOAuthToken: true
|
|
1381
1397
|
};
|
|
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
1398
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
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
|
-
}
|
|
1399
|
+
const defaultHeaders = mergeHeaders({
|
|
1400
|
+
accept: "application/json",
|
|
1401
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
1402
|
+
"anthropic-beta": betaFeatures.join(",")
|
|
1403
|
+
}, model.headers, optionsHeaders);
|
|
1404
|
+
return {
|
|
1405
|
+
client: new Anthropic({
|
|
1406
|
+
apiKey,
|
|
1407
|
+
baseURL: model.baseUrl,
|
|
1408
|
+
dangerouslyAllowBrowser: true,
|
|
1409
|
+
defaultHeaders
|
|
1410
|
+
}),
|
|
1411
|
+
isOAuthToken: false
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
function normalizeToolCallId(id) {
|
|
1415
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
1416
|
+
}
|
|
1417
|
+
function assertReplayableAssistant(message) {
|
|
1418
|
+
let sawToolCall = false;
|
|
1419
|
+
let sawNonTerminalToolCall = false;
|
|
1420
|
+
let sawTerminalToolCall = false;
|
|
1421
|
+
for (const part of message.parts) {
|
|
1422
|
+
if (part.type === "image") throw new Error("Anthropic replay does not support assistant image parts");
|
|
1423
|
+
if (part.type === "toolCall") {
|
|
1424
|
+
sawToolCall = true;
|
|
1425
|
+
if (part.status === "pending" || part.status === "running") sawNonTerminalToolCall = true;
|
|
1426
|
+
else sawTerminalToolCall = true;
|
|
1427
|
+
continue;
|
|
1483
1428
|
}
|
|
1429
|
+
if (sawToolCall) throw new Error("Assistant parts after a toolCall are not replayable for Anthropic");
|
|
1484
1430
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1431
|
+
if (sawToolCall && message.stopReason !== "toolUse") throw new Error("Assistant message with tool calls must have stopReason 'toolUse'");
|
|
1432
|
+
if (!sawToolCall && message.stopReason === "toolUse") throw new Error("Assistant message with stopReason 'toolUse' must contain at least one toolCall");
|
|
1433
|
+
if (sawTerminalToolCall && sawNonTerminalToolCall) throw new Error("Assistant message cannot mix terminal and non-terminal toolCall states");
|
|
1434
|
+
}
|
|
1435
|
+
function buildSyntheticToolResult(block) {
|
|
1436
|
+
return {
|
|
1437
|
+
type: "tool_result",
|
|
1438
|
+
tool_use_id: block.callID,
|
|
1439
|
+
content: convertContentBlocks([{
|
|
1440
|
+
type: "text",
|
|
1441
|
+
text: [
|
|
1442
|
+
"<result>",
|
|
1443
|
+
"No Result Provided",
|
|
1444
|
+
"</result>"
|
|
1445
|
+
].join("\n")
|
|
1446
|
+
}]),
|
|
1447
|
+
is_error: true
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function convertMessages(messages, model, isOAuthToken, cacheControl) {
|
|
1451
|
+
const params = [];
|
|
1452
|
+
const transformedMessages = Message.transformMessages(messages, model, normalizeToolCallId);
|
|
1453
|
+
for (const msg of transformedMessages) {
|
|
1454
|
+
if (msg.role === "user") {
|
|
1455
|
+
const blocks = msg.parts.map((item) => {
|
|
1456
|
+
if (item.type === "text") return {
|
|
1457
|
+
type: "text",
|
|
1458
|
+
text: sanitizeSurrogates(item.text)
|
|
1459
|
+
};
|
|
1460
|
+
return {
|
|
1461
|
+
type: "image",
|
|
1462
|
+
source: {
|
|
1463
|
+
type: "base64",
|
|
1464
|
+
media_type: item.mimeType,
|
|
1465
|
+
data: item.data
|
|
1508
1466
|
}
|
|
1509
1467
|
};
|
|
1510
|
-
await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
|
|
1511
|
-
} else runnables.push({
|
|
1512
|
-
toolCall,
|
|
1513
|
-
runnable: prepared.runnable,
|
|
1514
|
-
tool: prepared.tool
|
|
1515
1468
|
});
|
|
1469
|
+
let filteredBlocks = !model.input.includes("image") ? blocks.filter((b) => b.type !== "image") : blocks;
|
|
1470
|
+
filteredBlocks = filteredBlocks.filter((b) => b.type === "text" ? b.text.trim().length > 0 : true);
|
|
1471
|
+
if (filteredBlocks.length === 0) continue;
|
|
1472
|
+
params.push({
|
|
1473
|
+
role: "user",
|
|
1474
|
+
content: filteredBlocks
|
|
1475
|
+
});
|
|
1476
|
+
continue;
|
|
1516
1477
|
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
for (const
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1478
|
+
if (msg.stopReason === "error" || msg.stopReason === "aborted") continue;
|
|
1479
|
+
assertReplayableAssistant(msg);
|
|
1480
|
+
const assistantBlocks = [];
|
|
1481
|
+
const toolResults = [];
|
|
1482
|
+
for (const block of msg.parts) if (block.type === "text") {
|
|
1483
|
+
if (block.text.trim().length === 0) continue;
|
|
1484
|
+
assistantBlocks.push({
|
|
1485
|
+
type: "text",
|
|
1486
|
+
text: sanitizeSurrogates(block.text)
|
|
1487
|
+
});
|
|
1488
|
+
} else if (block.type === "thinking") {
|
|
1489
|
+
if (block.thinking.trim().length === 0) continue;
|
|
1490
|
+
if (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) assistantBlocks.push({
|
|
1491
|
+
type: "text",
|
|
1492
|
+
text: sanitizeSurrogates(block.thinking)
|
|
1493
|
+
});
|
|
1494
|
+
else assistantBlocks.push({
|
|
1495
|
+
type: "thinking",
|
|
1496
|
+
thinking: sanitizeSurrogates(block.thinking),
|
|
1497
|
+
signature: block.thinkingSignature
|
|
1498
|
+
});
|
|
1499
|
+
} else if (block.type === "toolCall") {
|
|
1500
|
+
assistantBlocks.push({
|
|
1501
|
+
type: "tool_use",
|
|
1502
|
+
id: block.callID,
|
|
1503
|
+
name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
|
|
1504
|
+
input: block.arguments ?? {}
|
|
1505
|
+
});
|
|
1506
|
+
if (block.status === "pending" || block.status === "running") toolResults.push(buildSyntheticToolResult(block));
|
|
1507
|
+
else toolResults.push({
|
|
1508
|
+
type: "tool_result",
|
|
1509
|
+
tool_use_id: block.callID,
|
|
1510
|
+
content: convertContentBlocks(block.result.content),
|
|
1511
|
+
is_error: block.result.isError
|
|
1512
|
+
});
|
|
1538
1513
|
}
|
|
1514
|
+
if (assistantBlocks.length > 0) params.push({
|
|
1515
|
+
role: "assistant",
|
|
1516
|
+
content: assistantBlocks
|
|
1517
|
+
});
|
|
1518
|
+
if (toolResults.length > 0) params.push({
|
|
1519
|
+
role: "user",
|
|
1520
|
+
content: toolResults
|
|
1521
|
+
});
|
|
1539
1522
|
}
|
|
1540
|
-
|
|
1541
|
-
const
|
|
1542
|
-
if (
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
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
|
-
};
|
|
1523
|
+
if (cacheControl && params.length > 0) {
|
|
1524
|
+
const lastMessage = params[params.length - 1];
|
|
1525
|
+
if (lastMessage.role === "user") {
|
|
1526
|
+
if (Array.isArray(lastMessage.content)) {
|
|
1527
|
+
const lastBlock = lastMessage.content[lastMessage.content.length - 1];
|
|
1528
|
+
if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) lastBlock.cache_control = cacheControl;
|
|
1529
|
+
} else if (typeof lastMessage.content === "string") lastMessage.content = [{
|
|
1530
|
+
type: "text",
|
|
1531
|
+
text: lastMessage.content,
|
|
1532
|
+
cache_control: cacheControl
|
|
1533
|
+
}];
|
|
1578
1534
|
}
|
|
1579
1535
|
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
} catch (err) {
|
|
1608
|
-
return { error: { message: err instanceof Error ? err.message : String(err) } };
|
|
1609
|
-
}
|
|
1536
|
+
return params;
|
|
1537
|
+
}
|
|
1538
|
+
function convertTools(tools, isOAuthToken) {
|
|
1539
|
+
if (!tools) return [];
|
|
1540
|
+
return tools.map((tool) => {
|
|
1541
|
+
const jsonSchema = tool.parameters;
|
|
1542
|
+
return {
|
|
1543
|
+
name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name,
|
|
1544
|
+
description: tool.description,
|
|
1545
|
+
input_schema: {
|
|
1546
|
+
type: "object",
|
|
1547
|
+
properties: jsonSchema.properties || {},
|
|
1548
|
+
required: jsonSchema.required || []
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
function mapStopReason(reason) {
|
|
1554
|
+
switch (reason) {
|
|
1555
|
+
case "end_turn": return "stop";
|
|
1556
|
+
case "max_tokens": return "length";
|
|
1557
|
+
case "tool_use": return "toolUse";
|
|
1558
|
+
case "pause_turn":
|
|
1559
|
+
case "stop_sequence": return "stop";
|
|
1560
|
+
case "refusal":
|
|
1561
|
+
case "sensitive": return "error";
|
|
1562
|
+
default: throw new Error("Unhandled Anthropic stop reason");
|
|
1610
1563
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1564
|
+
}
|
|
1565
|
+
function buildParams(model, context, isOAuthToken, options) {
|
|
1566
|
+
const { cacheControl } = getCacheControl(model.baseUrl, options?.cacheRetention);
|
|
1567
|
+
const params = {
|
|
1568
|
+
model: model.id,
|
|
1569
|
+
messages: convertMessages(context.messages, model, isOAuthToken, cacheControl),
|
|
1570
|
+
max_tokens: options?.maxTokens || model.maxTokens / 3 | 0,
|
|
1571
|
+
stream: true
|
|
1572
|
+
};
|
|
1573
|
+
if (isOAuthToken) {
|
|
1574
|
+
params.system = [{
|
|
1575
|
+
type: "text",
|
|
1576
|
+
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
|
1577
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
1578
|
+
}];
|
|
1579
|
+
if (context.systemPrompt) params.system.push({
|
|
1580
|
+
type: "text",
|
|
1581
|
+
text: sanitizeSurrogates(context.systemPrompt),
|
|
1582
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
1618
1583
|
});
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1584
|
+
} else if (context.systemPrompt) params.system = [{
|
|
1585
|
+
type: "text",
|
|
1586
|
+
text: sanitizeSurrogates(context.systemPrompt),
|
|
1587
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
1588
|
+
}];
|
|
1589
|
+
if (options?.temperature !== void 0 && !options?.thinkingEnabled) params.temperature = options.temperature;
|
|
1590
|
+
if (context.tools) params.tools = convertTools(context.tools, isOAuthToken);
|
|
1591
|
+
if (options?.thinkingEnabled && model.reasoning) params.thinking = {
|
|
1592
|
+
type: "enabled",
|
|
1593
|
+
budget_tokens: options.thinkingBudgetTokens || 1024
|
|
1594
|
+
};
|
|
1595
|
+
if (options?.metadata) {
|
|
1596
|
+
const userId = options.metadata.user_id;
|
|
1597
|
+
if (typeof userId === "string") params.metadata = { user_id: userId };
|
|
1598
|
+
}
|
|
1599
|
+
if (options?.toolChoice) params.tool_choice = typeof options.toolChoice === "string" ? { type: options.toolChoice } : options.toolChoice;
|
|
1600
|
+
return params;
|
|
1601
|
+
}
|
|
1602
|
+
const streamAnthropic = (model, context, options) => {
|
|
1603
|
+
const stream = new AssistantMessageEventStream();
|
|
1604
|
+
(async () => {
|
|
1605
|
+
const output = Message.createAssistantMessage({
|
|
1606
|
+
role: "assistant",
|
|
1607
|
+
parts: [],
|
|
1608
|
+
protocol: model.protocol,
|
|
1609
|
+
provider: model.provider,
|
|
1610
|
+
model: model.id,
|
|
1611
|
+
usage: {
|
|
1612
|
+
input: 0,
|
|
1613
|
+
output: 0,
|
|
1614
|
+
cacheRead: 0,
|
|
1615
|
+
cacheWrite: 0,
|
|
1616
|
+
totalTokens: 0,
|
|
1617
|
+
cost: {
|
|
1618
|
+
input: 0,
|
|
1619
|
+
output: 0,
|
|
1620
|
+
cacheRead: 0,
|
|
1621
|
+
cacheWrite: 0,
|
|
1622
|
+
total: 0
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
stopReason: "stop",
|
|
1622
1626
|
time: {
|
|
1623
|
-
|
|
1624
|
-
|
|
1627
|
+
created: Date.now(),
|
|
1628
|
+
completed: Date.now()
|
|
1625
1629
|
}
|
|
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
1630
|
});
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1631
|
+
try {
|
|
1632
|
+
let client;
|
|
1633
|
+
let isOAuthToken;
|
|
1634
|
+
if (options?.client) {
|
|
1635
|
+
client = options.client;
|
|
1636
|
+
isOAuthToken = false;
|
|
1637
|
+
} else {
|
|
1638
|
+
const apiKey = options?.apiKey ?? getEnvApiKey(model.provider);
|
|
1639
|
+
if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
|
|
1640
|
+
const created = createClient(model, apiKey, options?.interleavedThinking ?? true, options?.headers);
|
|
1641
|
+
client = created.client;
|
|
1642
|
+
isOAuthToken = created.isOAuthToken;
|
|
1656
1643
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1644
|
+
let params = buildParams(model, context, isOAuthToken, options);
|
|
1645
|
+
const nextParams = await options?.onPayload?.(params, model);
|
|
1646
|
+
if (nextParams !== void 0) params = nextParams;
|
|
1647
|
+
const anthropicStream = client.messages.stream({
|
|
1648
|
+
...params,
|
|
1649
|
+
stream: true
|
|
1650
|
+
}, { signal: options?.signal });
|
|
1651
|
+
stream.push({
|
|
1652
|
+
type: "start",
|
|
1653
|
+
partial: output
|
|
1654
|
+
});
|
|
1655
|
+
const blocks = output.parts;
|
|
1656
|
+
for await (const event of anthropicStream) if (event.type === "message_start") {
|
|
1657
|
+
output.responseId = event.message.id;
|
|
1658
|
+
output.usage.input = event.message.usage.input_tokens || 0;
|
|
1659
|
+
output.usage.output = event.message.usage.output_tokens || 0;
|
|
1660
|
+
output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
|
|
1661
|
+
output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
|
|
1662
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
1663
|
+
Model.calculateCost(model, output.usage);
|
|
1664
|
+
} else if (event.type === "content_block_start") {
|
|
1665
|
+
if (event.content_block.type === "text") {
|
|
1666
|
+
const block = {
|
|
1667
|
+
type: "text",
|
|
1668
|
+
text: "",
|
|
1669
|
+
index: event.index
|
|
1670
|
+
};
|
|
1671
|
+
output.parts.push(block);
|
|
1672
|
+
stream.push({
|
|
1673
|
+
type: "text.start",
|
|
1674
|
+
partIndex: output.parts.length - 1,
|
|
1675
|
+
partial: output
|
|
1676
|
+
});
|
|
1677
|
+
} else if (event.content_block.type === "thinking") {
|
|
1678
|
+
const block = {
|
|
1679
|
+
type: "thinking",
|
|
1680
|
+
thinking: "",
|
|
1681
|
+
thinkingSignature: "",
|
|
1682
|
+
index: event.index
|
|
1683
|
+
};
|
|
1684
|
+
output.parts.push(block);
|
|
1685
|
+
stream.push({
|
|
1686
|
+
type: "thinking.start",
|
|
1687
|
+
partIndex: output.parts.length - 1,
|
|
1688
|
+
partial: output
|
|
1689
|
+
});
|
|
1690
|
+
} else if (event.content_block.type === "redacted_thinking") {
|
|
1691
|
+
const block = {
|
|
1692
|
+
type: "thinking",
|
|
1693
|
+
thinking: "[Reasoning redacted]",
|
|
1694
|
+
thinkingSignature: event.content_block.data,
|
|
1695
|
+
redacted: true,
|
|
1696
|
+
index: event.index
|
|
1697
|
+
};
|
|
1698
|
+
output.parts.push(block);
|
|
1699
|
+
stream.push({
|
|
1700
|
+
type: "thinking.start",
|
|
1701
|
+
partIndex: output.parts.length - 1,
|
|
1702
|
+
partial: output
|
|
1703
|
+
});
|
|
1704
|
+
} else if (event.content_block.type === "tool_use") {
|
|
1705
|
+
const block = {
|
|
1706
|
+
type: "toolCall",
|
|
1707
|
+
callID: event.content_block.id,
|
|
1708
|
+
name: isOAuthToken ? fromClaudeCodeName(event.content_block.name, context.tools) : event.content_block.name,
|
|
1709
|
+
arguments: event.content_block.input ?? {},
|
|
1710
|
+
partialJson: "",
|
|
1711
|
+
status: "pending",
|
|
1712
|
+
time: {
|
|
1713
|
+
start: Date.now(),
|
|
1714
|
+
end: Date.now()
|
|
1715
|
+
},
|
|
1716
|
+
index: event.index
|
|
1717
|
+
};
|
|
1718
|
+
output.parts.push(block);
|
|
1719
|
+
stream.push({
|
|
1720
|
+
type: "toolcall.start",
|
|
1721
|
+
partIndex: output.parts.length - 1,
|
|
1722
|
+
partial: output
|
|
1723
|
+
});
|
|
1703
1724
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1725
|
+
} else if (event.type === "content_block_delta") {
|
|
1726
|
+
const partIndex = blocks.findIndex((b) => b.index === event.index);
|
|
1727
|
+
const block = blocks[partIndex];
|
|
1728
|
+
if (!block) continue;
|
|
1729
|
+
if (event.delta.type === "text_delta" && block.type === "text") {
|
|
1730
|
+
block.text += event.delta.text;
|
|
1731
|
+
stream.push({
|
|
1732
|
+
type: "text.delta",
|
|
1733
|
+
partIndex,
|
|
1734
|
+
delta: event.delta.text,
|
|
1735
|
+
partial: output
|
|
1711
1736
|
});
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1737
|
+
} else if (event.delta.type === "thinking_delta" && block.type === "thinking") {
|
|
1738
|
+
block.thinking += event.delta.thinking;
|
|
1739
|
+
stream.push({
|
|
1740
|
+
type: "thinking.delta",
|
|
1741
|
+
partIndex,
|
|
1742
|
+
delta: event.delta.thinking,
|
|
1743
|
+
partial: output
|
|
1744
|
+
});
|
|
1745
|
+
} else if (event.delta.type === "input_json_delta" && block.type === "toolCall") {
|
|
1746
|
+
block.partialJson += event.delta.partial_json;
|
|
1747
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
1748
|
+
stream.push({
|
|
1749
|
+
type: "toolcall.delta",
|
|
1750
|
+
partIndex,
|
|
1751
|
+
delta: event.delta.partial_json,
|
|
1752
|
+
partial: output
|
|
1753
|
+
});
|
|
1754
|
+
} else if (event.delta.type === "signature_delta" && block.type === "thinking") {
|
|
1755
|
+
block.thinkingSignature = block.thinkingSignature || "";
|
|
1756
|
+
block.thinkingSignature += event.delta.signature;
|
|
1757
|
+
}
|
|
1758
|
+
} else if (event.type === "content_block_stop") {
|
|
1759
|
+
const partIndex = blocks.findIndex((b) => b.index === event.index);
|
|
1760
|
+
const block = blocks[partIndex];
|
|
1761
|
+
if (block) {
|
|
1762
|
+
delete block.index;
|
|
1763
|
+
if (block.type === "text") stream.push({
|
|
1764
|
+
type: "text.end",
|
|
1765
|
+
partIndex,
|
|
1766
|
+
content: block.text,
|
|
1767
|
+
partial: output
|
|
1768
|
+
});
|
|
1769
|
+
else if (block.type === "thinking") stream.push({
|
|
1770
|
+
type: "thinking.end",
|
|
1771
|
+
partIndex,
|
|
1772
|
+
content: block.thinking,
|
|
1773
|
+
partial: output
|
|
1715
1774
|
});
|
|
1716
|
-
|
|
1775
|
+
else if (block.type === "toolCall") {
|
|
1776
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
1777
|
+
delete block.partialJson;
|
|
1778
|
+
stream.push({
|
|
1779
|
+
type: "toolcall.end",
|
|
1780
|
+
partIndex,
|
|
1781
|
+
toolCall: block,
|
|
1782
|
+
partial: output
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1717
1785
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
if (
|
|
1724
|
-
|
|
1725
|
-
|
|
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;
|
|
1786
|
+
} else if (event.type === "message_delta") {
|
|
1787
|
+
if (event.delta.stop_reason) output.stopReason = mapStopReason(event.delta.stop_reason);
|
|
1788
|
+
if (event.usage.input_tokens != null) output.usage.input = event.usage.input_tokens;
|
|
1789
|
+
if (event.usage.output_tokens != null) output.usage.output = event.usage.output_tokens;
|
|
1790
|
+
if (event.usage.cache_read_input_tokens != null) output.usage.cacheRead = event.usage.cache_read_input_tokens;
|
|
1791
|
+
if (event.usage.cache_creation_input_tokens != null) output.usage.cacheWrite = event.usage.cache_creation_input_tokens;
|
|
1792
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
1793
|
+
Model.calculateCost(model, output.usage);
|
|
1736
1794
|
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
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
|
|
1795
|
+
if (options?.signal?.aborted) throw new Error("Request was aborted");
|
|
1796
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
|
|
1797
|
+
output.time.completed = Date.now();
|
|
1798
|
+
stream.push({
|
|
1799
|
+
type: "done",
|
|
1800
|
+
reason: output.stopReason,
|
|
1801
|
+
message: output
|
|
1762
1802
|
});
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
partIndex,
|
|
1774
|
-
part
|
|
1775
|
-
});
|
|
1776
|
-
}
|
|
1777
|
-
await emitEvent(emit, {
|
|
1778
|
-
type: "message.end",
|
|
1779
|
-
message: prompt
|
|
1803
|
+
stream.end();
|
|
1804
|
+
} catch (error) {
|
|
1805
|
+
for (const block of output.parts) delete block.index;
|
|
1806
|
+
output.time.completed = Date.now();
|
|
1807
|
+
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
1808
|
+
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
1809
|
+
stream.push({
|
|
1810
|
+
type: "error",
|
|
1811
|
+
reason: output.stopReason,
|
|
1812
|
+
error: output
|
|
1780
1813
|
});
|
|
1814
|
+
stream.end();
|
|
1781
1815
|
}
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
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 = {}));
|
|
1816
|
+
})();
|
|
1817
|
+
return stream;
|
|
1818
|
+
};
|
|
1819
|
+
const streamSimpleAnthropic = (model, context, options) => {
|
|
1820
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider);
|
|
1821
|
+
if (!apiKey) throw new Error(`No API key for provider: ${model.provider.id}`);
|
|
1822
|
+
const base = Stream.buildBaseOptions(model, options, apiKey);
|
|
1823
|
+
if (!options?.reasoning) return streamAnthropic(model, context, {
|
|
1824
|
+
...base,
|
|
1825
|
+
thinkingEnabled: false
|
|
1826
|
+
});
|
|
1827
|
+
const adjusted = Stream.adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options.thinkingBudgets);
|
|
1828
|
+
return streamAnthropic(model, context, {
|
|
1829
|
+
...base,
|
|
1830
|
+
maxTokens: adjusted.maxTokens,
|
|
1831
|
+
thinkingEnabled: true,
|
|
1832
|
+
thinkingBudgetTokens: adjusted.thinkingBudget
|
|
1833
|
+
});
|
|
1834
|
+
};
|
|
1835
|
+
//#endregion
|
|
1836
|
+
//#region src/provider/register.ts
|
|
1837
|
+
const providerModules = [["providers/anthropic/index.ts", {
|
|
1838
|
+
protocol: Model.KnownProtocolEnum.anthropicMessages,
|
|
1839
|
+
stream: streamAnthropic,
|
|
1840
|
+
streamSimple: streamSimpleAnthropic
|
|
1841
|
+
}]];
|
|
1842
|
+
for (const [path, provider] of providerModules) Stream.registerProtocolProvider(provider, path);
|
|
1818
1843
|
//#endregion
|
|
1819
1844
|
//#region src/agent/agent.ts
|
|
1820
1845
|
let Agent;
|
|
@@ -1849,7 +1874,6 @@ let Agent;
|
|
|
1849
1874
|
_state;
|
|
1850
1875
|
listeners = /* @__PURE__ */ new Set();
|
|
1851
1876
|
abortController;
|
|
1852
|
-
activeAssistantIndex;
|
|
1853
1877
|
convertToLlm;
|
|
1854
1878
|
transformContext;
|
|
1855
1879
|
steeringQueue = [];
|
|
@@ -2001,19 +2025,34 @@ let Agent;
|
|
|
2001
2025
|
}
|
|
2002
2026
|
replaceMessages(ms) {
|
|
2003
2027
|
this._state.messages = ms.slice();
|
|
2004
|
-
this.activeAssistantIndex = void 0;
|
|
2005
2028
|
}
|
|
2006
2029
|
appendMessage(m) {
|
|
2007
2030
|
this._state.messages = [...this._state.messages, m];
|
|
2008
2031
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2032
|
+
findMessageIndexById(messageId) {
|
|
2033
|
+
return this._state.messages.findIndex((message) => message.messageId === messageId);
|
|
2034
|
+
}
|
|
2035
|
+
replaceMessageById(message) {
|
|
2036
|
+
const messageIndex = this.findMessageIndexById(message.messageId);
|
|
2037
|
+
if (messageIndex === -1) return false;
|
|
2038
|
+
const messages = this._state.messages.slice();
|
|
2039
|
+
messages[messageIndex] = message;
|
|
2040
|
+
this._state.messages = messages;
|
|
2041
|
+
return true;
|
|
2042
|
+
}
|
|
2043
|
+
upsertMessage(message) {
|
|
2044
|
+
if (this.replaceMessageById(message)) return;
|
|
2045
|
+
this.appendMessage(message);
|
|
2046
|
+
}
|
|
2047
|
+
patchStoredAssistantPart(messageId, partIndex, part) {
|
|
2048
|
+
const messageIndex = this.findMessageIndexById(messageId);
|
|
2049
|
+
if (messageIndex === -1) return false;
|
|
2011
2050
|
const messages = this._state.messages.slice();
|
|
2012
|
-
const existing = messages[
|
|
2051
|
+
const existing = messages[messageIndex];
|
|
2013
2052
|
if (!existing || existing.role !== "assistant") return false;
|
|
2014
2053
|
const nextParts = existing.parts.slice();
|
|
2015
2054
|
nextParts[partIndex] = part;
|
|
2016
|
-
messages[
|
|
2055
|
+
messages[messageIndex] = {
|
|
2017
2056
|
...existing,
|
|
2018
2057
|
parts: nextParts
|
|
2019
2058
|
};
|
|
@@ -2076,7 +2115,6 @@ let Agent;
|
|
|
2076
2115
|
}
|
|
2077
2116
|
clearMessages() {
|
|
2078
2117
|
this._state.messages = [];
|
|
2079
|
-
this.activeAssistantIndex = void 0;
|
|
2080
2118
|
}
|
|
2081
2119
|
abort() {
|
|
2082
2120
|
this.abortController?.abort();
|
|
@@ -2090,7 +2128,6 @@ let Agent;
|
|
|
2090
2128
|
this._state.streamMessage = null;
|
|
2091
2129
|
this._state.pendingToolCalls = /* @__PURE__ */ new Set();
|
|
2092
2130
|
this._state.error = void 0;
|
|
2093
|
-
this.activeAssistantIndex = void 0;
|
|
2094
2131
|
this.steeringQueue = [];
|
|
2095
2132
|
this.followUpQueue = [];
|
|
2096
2133
|
}
|
|
@@ -2147,7 +2184,7 @@ let Agent;
|
|
|
2147
2184
|
if (messages) await Loop.runAgentLoop(config, context, messages, async (e) => this._processLoopEvent(e), this.streamFn, this.abortController.signal);
|
|
2148
2185
|
else await Loop.runAgentLoopContinue(config, context, async (e) => this._processLoopEvent(e), this.streamFn, this.abortController.signal);
|
|
2149
2186
|
} catch (err) {
|
|
2150
|
-
const message = {
|
|
2187
|
+
const message = Message.createAssistantMessage({
|
|
2151
2188
|
role: "assistant",
|
|
2152
2189
|
protocol: model.protocol,
|
|
2153
2190
|
provider: model.provider,
|
|
@@ -2173,7 +2210,7 @@ let Agent;
|
|
|
2173
2210
|
completed: Date.now()
|
|
2174
2211
|
},
|
|
2175
2212
|
parts: []
|
|
2176
|
-
};
|
|
2213
|
+
});
|
|
2177
2214
|
this.appendMessage(message);
|
|
2178
2215
|
this._state.error = err?.message || String(err);
|
|
2179
2216
|
this.emit({
|
|
@@ -2201,32 +2238,31 @@ let Agent;
|
|
|
2201
2238
|
async prompt(messages, images) {
|
|
2202
2239
|
this.ensureIdle();
|
|
2203
2240
|
if (!this._state.model) throw new ModelNotConfiguredErr({ message: "no model configured yet." });
|
|
2204
|
-
const message = {
|
|
2241
|
+
const message = Message.createUserMessage({
|
|
2205
2242
|
role: "user",
|
|
2206
2243
|
time: { created: Date.now() },
|
|
2207
2244
|
parts: [...messages, ...images ?? []]
|
|
2208
|
-
};
|
|
2245
|
+
});
|
|
2209
2246
|
await this.loop([message]);
|
|
2210
2247
|
}
|
|
2211
2248
|
_processLoopEvent(event) {
|
|
2212
2249
|
switch (event.type) {
|
|
2213
2250
|
case "message.start":
|
|
2214
2251
|
this._state.streamMessage = event.message;
|
|
2215
|
-
if (event.message.role === "assistant") this.activeAssistantIndex = void 0;
|
|
2216
2252
|
break;
|
|
2217
2253
|
case "message.part.start":
|
|
2218
2254
|
case "message.part.update":
|
|
2219
2255
|
case "message.part.end":
|
|
2220
2256
|
this._state.streamMessage = event.message;
|
|
2221
|
-
if (event.message.role === "assistant") this.patchStoredAssistantPart(event.partIndex, event.part);
|
|
2257
|
+
if (event.message.role === "assistant") this.patchStoredAssistantPart(event.message.messageId, event.partIndex, event.part);
|
|
2222
2258
|
break;
|
|
2223
2259
|
case "message.update":
|
|
2224
2260
|
this._state.streamMessage = event.message;
|
|
2261
|
+
this.replaceMessageById(event.message);
|
|
2225
2262
|
break;
|
|
2226
2263
|
case "message.end":
|
|
2227
2264
|
this._state.streamMessage = null;
|
|
2228
|
-
this.
|
|
2229
|
-
if (event.message.role === "assistant") this.activeAssistantIndex = this._state.messages.length - 1;
|
|
2265
|
+
this.upsertMessage(event.message);
|
|
2230
2266
|
break;
|
|
2231
2267
|
case "tool.execution.start": {
|
|
2232
2268
|
const pendingToolCalls = new Set(this._state.pendingToolCalls);
|
|
@@ -2271,207 +2307,353 @@ let Agent;
|
|
|
2271
2307
|
_Agent.create = create;
|
|
2272
2308
|
})(Agent || (Agent = {}));
|
|
2273
2309
|
//#endregion
|
|
2274
|
-
//#region src/agent.ts
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
};
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
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")
|
|
2310
|
+
//#region src/agent/codemode/codemode.ts
|
|
2311
|
+
let CodeMode;
|
|
2312
|
+
(function(_CodeMode) {
|
|
2313
|
+
const ToolDefinitionErr = _CodeMode.ToolDefinitionErr = NamedError.create("ToolDefinitionErr", Type.Object({ message: Type.String() }));
|
|
2314
|
+
const toolFnPrefix = process.env.CODEWORK_CODEMODE_FN_PREFIX ?? "external_";
|
|
2315
|
+
const SandboxExecutionInputSchema = _CodeMode.SandboxExecutionInputSchema = Type.Object({ typescriptCode: Type.String({ description: "TypeScript code to execute in the sandbox." }) });
|
|
2316
|
+
const SandboxExecutionOutputSchema = _CodeMode.SandboxExecutionOutputSchema = Type.Object({
|
|
2317
|
+
result: Type.Optional(Type.Unknown()),
|
|
2318
|
+
logs: Type.Optional(Type.Array(Type.String()))
|
|
2422
2319
|
});
|
|
2423
|
-
const
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2320
|
+
const SandboxExecutionErrorSchema = _CodeMode.SandboxExecutionErrorSchema = Type.Object({
|
|
2321
|
+
message: Type.String(),
|
|
2322
|
+
name: Type.Optional(Type.String()),
|
|
2323
|
+
stack: Type.Optional(Type.String()),
|
|
2324
|
+
line: Type.Optional(Type.Number()),
|
|
2325
|
+
logs: Type.Optional(Type.Array(Type.String()))
|
|
2428
2326
|
});
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2327
|
+
function withMessageInStack(message, stack) {
|
|
2328
|
+
if (!stack) return void 0;
|
|
2329
|
+
return stack.includes(message) ? stack : `${message}\n${stack}`;
|
|
2330
|
+
}
|
|
2331
|
+
function normalizeExecutionError(error) {
|
|
2332
|
+
if (error instanceof Error) return {
|
|
2333
|
+
name: error.name,
|
|
2334
|
+
message: error.message,
|
|
2335
|
+
stack: withMessageInStack(error.message, error.stack),
|
|
2336
|
+
line: parseErrorLine(error.stack)
|
|
2337
|
+
};
|
|
2338
|
+
if (typeof error === "object" && error !== null) {
|
|
2339
|
+
const candidate = error;
|
|
2340
|
+
return {
|
|
2341
|
+
name: typeof candidate.name === "string" ? candidate.name : void 0,
|
|
2342
|
+
message: typeof candidate.message === "string" ? candidate.message : JSON.stringify(candidate) || "Unknown execution error",
|
|
2343
|
+
stack: typeof candidate.stack === "string" ? withMessageInStack(typeof candidate.message === "string" ? candidate.message : JSON.stringify(candidate) || "Unknown execution error", candidate.stack) : void 0,
|
|
2344
|
+
line: typeof candidate.line === "number" ? candidate.line : parseErrorLine(candidate.stack)
|
|
2345
|
+
};
|
|
2346
|
+
}
|
|
2347
|
+
return {
|
|
2348
|
+
name: "Error",
|
|
2349
|
+
message: String(error)
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
function parseErrorLine(stack) {
|
|
2353
|
+
if (typeof stack !== "string") return void 0;
|
|
2354
|
+
const lineMatch = stack.match(/:(\d+)(?::\d+)?\)?$/m);
|
|
2355
|
+
return lineMatch ? Number(lineMatch[1]) : void 0;
|
|
2356
|
+
}
|
|
2357
|
+
function serializeForContent(value) {
|
|
2358
|
+
return JSON.stringify(value, (_key, currentValue) => typeof currentValue === "bigint" ? currentValue.toString() : currentValue, 2);
|
|
2359
|
+
}
|
|
2360
|
+
function toolContentToText(result) {
|
|
2361
|
+
return result.content.filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n").trim();
|
|
2362
|
+
}
|
|
2363
|
+
function unwrapToolResult(tool, result) {
|
|
2364
|
+
if (result.status === "completed") {
|
|
2365
|
+
if (tool.outputSchema) return validateSchema(tool.outputSchema, result.result.details, `Tool "${tool.name}" output`);
|
|
2366
|
+
return result.result.details;
|
|
2367
|
+
}
|
|
2368
|
+
if (tool.errorSchema && result.result.details !== void 0) validateSchema(tool.errorSchema, result.result.details, `Tool "${tool.name}" error`);
|
|
2369
|
+
const message = toolContentToText(result.result) || `Tool "${tool.name}" failed`;
|
|
2370
|
+
const error = new Error(message);
|
|
2371
|
+
if (result.result.details !== void 0) error.cause = result.result.details;
|
|
2372
|
+
throw error;
|
|
2373
|
+
}
|
|
2374
|
+
function toolToBinding(tool, prefix = "") {
|
|
2375
|
+
const inputSchema = TypeGuard.IsSchema(tool.parameters) ? tool.parameters : Type.Object({});
|
|
2376
|
+
const outputSchema = TypeGuard.IsSchema(tool.outputSchema) ? tool.outputSchema : void 0;
|
|
2377
|
+
const errorSchema = TypeGuard.IsSchema(tool.errorSchema) ? tool.errorSchema : void 0;
|
|
2378
|
+
if (!("execute" in tool) || typeof tool.execute !== "function") throw new ToolDefinitionErr({ message: `tool "${tool.name}" does not have an execute function. code mode requires tools with implementation` });
|
|
2379
|
+
return {
|
|
2380
|
+
name: `${prefix}${tool.name}`,
|
|
2381
|
+
description: tool.description,
|
|
2382
|
+
inputSchema,
|
|
2383
|
+
outputSchema,
|
|
2384
|
+
errorSchema,
|
|
2385
|
+
execute: async (callID, params, signal) => {
|
|
2386
|
+
const validatedParams = validateSchema(inputSchema, params, `Tool "${tool.name}" input`);
|
|
2387
|
+
return unwrapToolResult(tool, await tool.execute(callID, validatedParams, signal));
|
|
2388
|
+
}
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2391
|
+
function toolsForBinding(tools, prefix) {
|
|
2392
|
+
const bindings = {};
|
|
2393
|
+
for (const tool of tools) {
|
|
2394
|
+
const name = `${prefix}${tool.name}`;
|
|
2395
|
+
bindings[name] = toolToBinding(tool, prefix);
|
|
2396
|
+
}
|
|
2397
|
+
return bindings;
|
|
2398
|
+
}
|
|
2399
|
+
function indent(value, depth = 1) {
|
|
2400
|
+
const prefix = " ".repeat(depth);
|
|
2401
|
+
return value.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
2402
|
+
}
|
|
2403
|
+
function toPropertyKey(name) {
|
|
2404
|
+
return /^[$A-Z_a-z][$\w]*$/i.test(name) ? name : JSON.stringify(name);
|
|
2405
|
+
}
|
|
2406
|
+
function schemaToTypeScript(schema) {
|
|
2407
|
+
if (TypeGuard.IsAny(schema)) return "any";
|
|
2408
|
+
if (TypeGuard.IsUnknown(schema)) return "unknown";
|
|
2409
|
+
if (TypeGuard.IsString(schema)) return "string";
|
|
2410
|
+
if (TypeGuard.IsNumber(schema) || TypeGuard.IsInteger(schema)) return "number";
|
|
2411
|
+
if (TypeGuard.IsBoolean(schema)) return "boolean";
|
|
2412
|
+
if (TypeGuard.IsNull(schema)) return "null";
|
|
2413
|
+
if (TypeGuard.IsUndefined(schema) || TypeGuard.IsVoid(schema)) return "undefined";
|
|
2414
|
+
if (TypeGuard.IsLiteral(schema)) return JSON.stringify(schema.const);
|
|
2415
|
+
if (TypeGuard.IsArray(schema)) return `Array<${schemaToTypeScript(schema.items)}>`;
|
|
2416
|
+
if (TypeGuard.IsTuple(schema)) return `[${(schema.items ?? []).map((item) => schemaToTypeScript(item)).join(", ")}]`;
|
|
2417
|
+
if (TypeGuard.IsUnion(schema)) return schema.anyOf.map((item) => schemaToTypeScript(item)).join(" | ");
|
|
2418
|
+
if (TypeGuard.IsIntersect(schema)) return schema.allOf.map((item) => schemaToTypeScript(item)).join(" & ");
|
|
2419
|
+
if (TypeGuard.IsRecord(schema)) return `Record<string, ${schemaToTypeScript(Object.values(schema.patternProperties ?? {}).find(TypeGuard.IsSchema) ?? (schema.additionalProperties && TypeGuard.IsSchema(schema.additionalProperties) ? schema.additionalProperties : Type.Unknown()))}>`;
|
|
2420
|
+
if (TypeGuard.IsObject(schema)) {
|
|
2421
|
+
const required = new Set(schema.required ?? []);
|
|
2422
|
+
const properties = Object.entries(schema.properties ?? {}).map(([key, value]) => {
|
|
2423
|
+
const optional = required.has(key) ? "" : "?";
|
|
2424
|
+
return `${toPropertyKey(key)}${optional}: ${schemaToTypeScript(value)};`;
|
|
2425
|
+
});
|
|
2426
|
+
if (schema.additionalProperties === true) properties.push("[key: string]: unknown;");
|
|
2427
|
+
else if (schema.additionalProperties && TypeGuard.IsSchema(schema.additionalProperties)) properties.push(`[key: string]: ${schemaToTypeScript(schema.additionalProperties)};`);
|
|
2428
|
+
if (properties.length === 0) return "{}";
|
|
2429
|
+
return `{\n${indent(properties.join("\n"))}\n}`;
|
|
2430
|
+
}
|
|
2431
|
+
return "unknown";
|
|
2432
|
+
}
|
|
2433
|
+
function generateTypeStubs(bindings, options = {}) {
|
|
2434
|
+
const { includeDescriptions = true } = options;
|
|
2435
|
+
const declarations = [];
|
|
2436
|
+
for (const [name, binding] of Object.entries(bindings)) {
|
|
2437
|
+
const inputTypeName = `${capitalize(name)}Input`;
|
|
2438
|
+
const outputTypeName = `${capitalize(name)}Output`;
|
|
2439
|
+
declarations.push(`type ${inputTypeName} = ${schemaToTypeScript(binding.inputSchema)};`);
|
|
2440
|
+
let outputTypeRef = "unknown";
|
|
2441
|
+
if (binding.outputSchema !== void 0) {
|
|
2442
|
+
declarations.push(`type ${outputTypeName} = ${schemaToTypeScript(binding.outputSchema)};`);
|
|
2443
|
+
outputTypeRef = outputTypeName;
|
|
2444
|
+
}
|
|
2445
|
+
const description = includeDescriptions && binding.description ? `/** ${binding.description} */\n` : "";
|
|
2446
|
+
declarations.push(`${description}declare function ${name}(input: ${inputTypeName}): Promise<${outputTypeRef}>;`);
|
|
2447
|
+
}
|
|
2448
|
+
return declarations.join("\n\n");
|
|
2449
|
+
}
|
|
2450
|
+
_CodeMode.generateTypeStubs = generateTypeStubs;
|
|
2451
|
+
function buildExampleSnippet() {
|
|
2452
|
+
return [
|
|
2453
|
+
"```typescript",
|
|
2454
|
+
"const numbers = [12, 24, 36];",
|
|
2455
|
+
"const total = numbers.reduce((sum, value) => sum + value, 0);",
|
|
2456
|
+
"",
|
|
2457
|
+
"return {",
|
|
2458
|
+
" count: numbers.length,",
|
|
2459
|
+
" average: total / numbers.length,",
|
|
2460
|
+
"};",
|
|
2461
|
+
"```"
|
|
2462
|
+
];
|
|
2463
|
+
}
|
|
2464
|
+
function generateSystemPrompt(config) {
|
|
2465
|
+
const fnPrefix = config.fnPrefix ?? toolFnPrefix;
|
|
2466
|
+
const bindings = toolsForBinding(config.tools, fnPrefix);
|
|
2467
|
+
const typeStubs = generateTypeStubs(bindings);
|
|
2468
|
+
return [
|
|
2469
|
+
"## Code Execution Tool",
|
|
2470
|
+
"",
|
|
2471
|
+
"You have access to `sandbox_execute_typescript` which runs TypeScript code in a sandboxed environment.",
|
|
2472
|
+
"",
|
|
2473
|
+
"### When to Use",
|
|
2474
|
+
"",
|
|
2475
|
+
"Use `sandbox_execute_typescript` when you need to:",
|
|
2476
|
+
"- Process data with loops, conditionals, or complex logic",
|
|
2477
|
+
"- Make multiple tool calls in parallel with `Promise.all(...)`",
|
|
2478
|
+
"- Transform, filter, or aggregate data",
|
|
2479
|
+
"- Perform calculations or data analysis",
|
|
2480
|
+
"",
|
|
2481
|
+
"For simple operations, prefer calling tools directly.",
|
|
2482
|
+
"",
|
|
2483
|
+
"### Available External APIs",
|
|
2484
|
+
"",
|
|
2485
|
+
"Inside your TypeScript code, you can call these async functions:",
|
|
2486
|
+
"",
|
|
2487
|
+
Object.entries(bindings).map(([name, binding]) => `- \`${name}(input)\`: ${binding.description}`).join("\n") || "- No external APIs available for this run.",
|
|
2488
|
+
"",
|
|
2489
|
+
"### Type Definitions",
|
|
2490
|
+
"",
|
|
2491
|
+
"```typescript",
|
|
2492
|
+
typeStubs,
|
|
2493
|
+
"```",
|
|
2494
|
+
"",
|
|
2495
|
+
"### Example",
|
|
2496
|
+
"",
|
|
2497
|
+
...buildExampleSnippet(),
|
|
2498
|
+
"",
|
|
2499
|
+
"### Important Notes",
|
|
2500
|
+
"",
|
|
2501
|
+
`- All\`${fnPrefix}\`*calls are async, so always use \`await\``,
|
|
2502
|
+
"- Return a value to pass results back to you",
|
|
2503
|
+
"- Use `console.log()` for debugging (logs are captured)",
|
|
2504
|
+
"- The sandbox is isolated - no network access or file system",
|
|
2505
|
+
"- Each execution is isolated and does not share state with previous runs",
|
|
2506
|
+
""
|
|
2507
|
+
].join("\n");
|
|
2508
|
+
}
|
|
2509
|
+
_CodeMode.generateSystemPrompt = generateSystemPrompt;
|
|
2510
|
+
async function transpileTypeScript(typescriptCode) {
|
|
2511
|
+
return (await transform([
|
|
2512
|
+
"(async () => {",
|
|
2513
|
+
" const __codemodeNormalizeError = (error: unknown) => {",
|
|
2514
|
+
" if (error instanceof Error) return { name: error.name, message: error.message, stack: error.stack };",
|
|
2515
|
+
" if (typeof error === 'object' && error !== null) {",
|
|
2516
|
+
" const candidate = error as { name?: unknown; message?: unknown; stack?: unknown };",
|
|
2517
|
+
" return {",
|
|
2518
|
+
" name: typeof candidate.name === 'string' ? candidate.name : 'Error',",
|
|
2519
|
+
" message:",
|
|
2520
|
+
" typeof candidate.message === 'string'",
|
|
2521
|
+
" ? candidate.message",
|
|
2522
|
+
" : JSON.stringify(candidate) || 'Unknown execution error',",
|
|
2523
|
+
" stack: typeof candidate.stack === 'string' ? candidate.stack : undefined,",
|
|
2524
|
+
" };",
|
|
2525
|
+
" }",
|
|
2526
|
+
" return { name: 'Error', message: String(error) };",
|
|
2527
|
+
" };",
|
|
2528
|
+
" try {",
|
|
2529
|
+
typescriptCode,
|
|
2530
|
+
" } catch (error) {",
|
|
2531
|
+
" throw __codemodeNormalizeError(error);",
|
|
2532
|
+
" }",
|
|
2533
|
+
"})()"
|
|
2534
|
+
].join("\n"), {
|
|
2535
|
+
loader: "ts",
|
|
2536
|
+
target: "es2022",
|
|
2537
|
+
sourcefile: "script.ts",
|
|
2538
|
+
minify: false,
|
|
2539
|
+
keepNames: false
|
|
2540
|
+
})).code;
|
|
2541
|
+
}
|
|
2542
|
+
function buildToolDescription(tools, fnPrefix = toolFnPrefix) {
|
|
2543
|
+
return [
|
|
2544
|
+
"Execute TypeScript code in a secure sandbox environment. ",
|
|
2545
|
+
"The code can use these external API functions:",
|
|
2546
|
+
"<functions>",
|
|
2547
|
+
` ${tools.map((tool) => `${fnPrefix}${tool.name}`).join("\n")}`,
|
|
2548
|
+
"</functions>",
|
|
2549
|
+
`All ${fnPrefix}* calls are async and must be awaited. `,
|
|
2550
|
+
"Return a value to pass results back. Use console.log() for debugging."
|
|
2551
|
+
].join("\n");
|
|
2552
|
+
}
|
|
2553
|
+
function createCodeModeTool(config) {
|
|
2554
|
+
if (config.tools.length === 0) throw new ToolDefinitionErr({ message: "at least one tool must be provided to `createCodeModeTool`" });
|
|
2555
|
+
return Agent.defineTool({
|
|
2556
|
+
name: "sandbox_execute_typescript",
|
|
2557
|
+
label: "Sandbox TypeScript",
|
|
2558
|
+
description: buildToolDescription(config.tools, config.fnPrefix),
|
|
2559
|
+
parameters: SandboxExecutionInputSchema,
|
|
2560
|
+
outputSchema: SandboxExecutionOutputSchema,
|
|
2561
|
+
errorSchema: SandboxExecutionErrorSchema,
|
|
2562
|
+
async execute(_callID, params, signal, onUpdate) {
|
|
2563
|
+
const bindings = toolsForBinding(config.tools, config.fnPrefix ?? toolFnPrefix);
|
|
2564
|
+
let context;
|
|
2565
|
+
try {
|
|
2566
|
+
await onUpdate?.({
|
|
2567
|
+
status: "running",
|
|
2568
|
+
partial: { content: [{
|
|
2569
|
+
type: "text",
|
|
2570
|
+
text: "Transpiling TypeScript for sandbox execution"
|
|
2571
|
+
}] }
|
|
2572
|
+
});
|
|
2573
|
+
const javascriptCode = await transpileTypeScript(params.typescriptCode);
|
|
2574
|
+
await onUpdate?.({
|
|
2575
|
+
status: "running",
|
|
2576
|
+
partial: { content: [{
|
|
2577
|
+
type: "text",
|
|
2578
|
+
text: "Executing code in sandbox runtime"
|
|
2579
|
+
}] }
|
|
2580
|
+
});
|
|
2581
|
+
context = await config.driver.createContext({
|
|
2582
|
+
bindings,
|
|
2583
|
+
timeout: config.timeout,
|
|
2584
|
+
memoryLimit: config.memoryLimit,
|
|
2585
|
+
signal
|
|
2586
|
+
});
|
|
2587
|
+
const executionResult = await context.execute(javascriptCode);
|
|
2588
|
+
if (executionResult.success) {
|
|
2589
|
+
const details = {
|
|
2590
|
+
result: executionResult.value,
|
|
2591
|
+
...executionResult.logs && executionResult.logs.length > 0 ? { logs: executionResult.logs } : {}
|
|
2592
|
+
};
|
|
2593
|
+
return {
|
|
2594
|
+
status: "completed",
|
|
2595
|
+
result: {
|
|
2596
|
+
content: [{
|
|
2597
|
+
type: "text",
|
|
2598
|
+
text: serializeForContent(details)
|
|
2599
|
+
}],
|
|
2600
|
+
details,
|
|
2601
|
+
isError: false
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
const details = {
|
|
2606
|
+
message: executionResult.error?.message || "sandbox execution failed",
|
|
2607
|
+
...executionResult.error?.name ? { name: executionResult.error.name } : {},
|
|
2608
|
+
...executionResult.error?.stack ? { stack: executionResult.error.stack } : {},
|
|
2609
|
+
...executionResult.error?.line != null ? { line: executionResult.error.line } : {},
|
|
2610
|
+
...executionResult.logs && executionResult.logs.length > 0 ? { logs: executionResult.logs } : {}
|
|
2611
|
+
};
|
|
2612
|
+
return {
|
|
2613
|
+
status: "error",
|
|
2614
|
+
result: {
|
|
2615
|
+
content: [{
|
|
2616
|
+
type: "text",
|
|
2617
|
+
text: serializeForContent(details)
|
|
2618
|
+
}],
|
|
2619
|
+
details,
|
|
2620
|
+
isError: true
|
|
2621
|
+
}
|
|
2622
|
+
};
|
|
2623
|
+
} catch (error) {
|
|
2624
|
+
const normalizedError = normalizeExecutionError(error);
|
|
2625
|
+
const details = {
|
|
2626
|
+
message: normalizedError.message,
|
|
2627
|
+
...normalizedError.name ? { name: normalizedError.name } : {},
|
|
2628
|
+
...normalizedError.stack ? { stack: normalizedError.stack } : {},
|
|
2629
|
+
...normalizedError.line != null ? { line: normalizedError.line } : {}
|
|
2630
|
+
};
|
|
2631
|
+
return {
|
|
2632
|
+
status: "error",
|
|
2633
|
+
result: {
|
|
2634
|
+
content: [{
|
|
2635
|
+
type: "text",
|
|
2636
|
+
text: serializeForContent(details)
|
|
2637
|
+
}],
|
|
2638
|
+
details,
|
|
2639
|
+
isError: true
|
|
2640
|
+
}
|
|
2641
|
+
};
|
|
2642
|
+
} finally {
|
|
2643
|
+
await context?.dispose();
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
_CodeMode.createCodeModeTool = createCodeModeTool;
|
|
2649
|
+
async function create(config) {
|
|
2650
|
+
return {
|
|
2651
|
+
tool: createCodeModeTool(config),
|
|
2652
|
+
systemPrompt: generateSystemPrompt(config)
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
_CodeMode.create = create;
|
|
2656
|
+
})(CodeMode || (CodeMode = {}));
|
|
2475
2657
|
//#endregion
|
|
2476
2658
|
//#region src/llm.ts
|
|
2477
2659
|
const llmImpl = async (provider, model) => Model.getModel(provider, model);
|
|
@@ -2503,13 +2685,10 @@ const stream = Object.assign(streamImpl, {
|
|
|
2503
2685
|
completeSimple: Stream.completeSimple,
|
|
2504
2686
|
resolveProtocolProvider: Stream.resolveProtocolProvider
|
|
2505
2687
|
});
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
const streamSimple = Stream.streamSimple;
|
|
2510
|
-
/** Resolve a simplified stream request directly to the final assistant message. */
|
|
2511
|
-
const completeSimple = Stream.completeSimple;
|
|
2688
|
+
Stream.complete;
|
|
2689
|
+
Stream.streamSimple;
|
|
2690
|
+
Stream.completeSimple;
|
|
2512
2691
|
//#endregion
|
|
2513
|
-
export { Agent,
|
|
2692
|
+
export { Agent, CodeMode, Message, agent, llm, stream };
|
|
2514
2693
|
|
|
2515
2694
|
//# sourceMappingURL=index.mjs.map
|