@codeworksh/aikit 0.2.1 → 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/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 -8844
- package/index.mjs +1805 -1453
- package/index.mjs.map +1 -1
- package/package.json +9 -6
package/index.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Filesystem, NamedError, lazy } from "@codeworksh/utils";
|
|
2
|
-
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { Type, TypeGuard } from "@sinclair/typebox";
|
|
3
|
+
import { capitalize, keys, mapValues, pick, pipe } from "remeda";
|
|
4
|
+
import Ajv from "ajv";
|
|
5
|
+
import addFormats from "ajv-formats";
|
|
3
6
|
import { uuidv7 } from "uuidv7";
|
|
4
|
-
import { keys, mapValues, pick, pipe } from "remeda";
|
|
5
7
|
import Anthropic from "@anthropic-ai/sdk";
|
|
6
8
|
import { parse } from "partial-json";
|
|
7
|
-
import
|
|
8
|
-
import addFormats from "ajv-formats";
|
|
9
|
+
import { transform } from "esbuild";
|
|
9
10
|
//#region src/provider/provider.ts
|
|
10
11
|
let Provider;
|
|
11
12
|
(function(_Provider) {
|
|
@@ -240,237 +241,171 @@ let Model;
|
|
|
240
241
|
_Model.modelsAreEqual = modelsAreEqual;
|
|
241
242
|
})(Model || (Model = {}));
|
|
242
243
|
//#endregion
|
|
243
|
-
//#region src/
|
|
244
|
-
let
|
|
245
|
-
(function(
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
});
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
thinking: Type.String(),
|
|
259
|
-
thinkingSignature: Type.Optional(Type.String()),
|
|
260
|
-
redacted: Type.Optional(Type.Boolean())
|
|
261
|
-
});
|
|
262
|
-
const ToolCallBaseSchema = _Message.ToolCallBaseSchema = Type.Object({
|
|
263
|
-
type: Type.Literal("toolCall"),
|
|
264
|
-
callID: Type.String(),
|
|
265
|
-
name: Type.String(),
|
|
266
|
-
arguments: Type.Record(Type.String(), Type.Any()),
|
|
267
|
-
thoughtSignature: Type.Optional(Type.String()),
|
|
268
|
-
time: Type.Object({
|
|
269
|
-
start: Type.Number(),
|
|
270
|
-
end: Type.Number()
|
|
271
|
-
})
|
|
272
|
-
});
|
|
273
|
-
const ToolSuccessResult = _Message.ToolSuccessResult = Type.Object({
|
|
274
|
-
content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
|
|
275
|
-
details: Type.Optional(Type.Any()),
|
|
276
|
-
isError: Type.Literal(false)
|
|
277
|
-
});
|
|
278
|
-
const ToolErrorResult = _Message.ToolErrorResult = Type.Object({
|
|
279
|
-
content: Type.Array(Type.Union([TextContentSchema, ImageContentSchema])),
|
|
280
|
-
details: Type.Optional(Type.Any()),
|
|
281
|
-
isError: Type.Literal(true)
|
|
282
|
-
});
|
|
283
|
-
const ToolRunningPartial = _Message.ToolRunningPartial = Type.Object({
|
|
284
|
-
content: Type.Optional(Type.Array(Type.Union([TextContentSchema, ImageContentSchema]))),
|
|
285
|
-
details: Type.Optional(Type.Any())
|
|
286
|
-
});
|
|
287
|
-
const ToolStatusEnum = _Message.ToolStatusEnum = {
|
|
288
|
-
pending: "pending",
|
|
289
|
-
running: "running",
|
|
290
|
-
completed: "completed",
|
|
291
|
-
error: "error",
|
|
292
|
-
skipped: "skipped",
|
|
293
|
-
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"
|
|
294
259
|
};
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
});
|
|
303
|
-
const ToolErrorSchema = _Message.ToolErrorSchema = Type.Object({
|
|
304
|
-
status: Type.Literal(ToolStatusEnum.error),
|
|
305
|
-
result: ToolErrorResult
|
|
306
|
-
});
|
|
307
|
-
const ToolSkippedSchema = _Message.ToolSkippedSchema = Type.Object({
|
|
308
|
-
status: Type.Literal(ToolStatusEnum.skipped),
|
|
309
|
-
result: ToolErrorResult
|
|
310
|
-
});
|
|
311
|
-
const ToolAbortedSchema = _Message.ToolAbortedSchema = Type.Object({
|
|
312
|
-
status: Type.Literal(ToolStatusEnum.aborted),
|
|
313
|
-
result: ToolErrorResult
|
|
314
|
-
});
|
|
315
|
-
const ToolCallPendingPart = Type.Intersect([ToolCallBaseSchema, Type.Object({ status: Type.Literal(ToolStatusEnum.pending) })]);
|
|
316
|
-
const ToolCallRunningPart = Type.Composite([ToolCallBaseSchema, ToolRunningSchema]);
|
|
317
|
-
const ToolCallCompletedPart = Type.Composite([ToolCallBaseSchema, ToolCompletedSchema]);
|
|
318
|
-
const ToolCallErrorPart = Type.Composite([ToolCallBaseSchema, ToolErrorSchema]);
|
|
319
|
-
const ToolCallSkippedPart = Type.Composite([ToolCallBaseSchema, ToolSkippedSchema]);
|
|
320
|
-
const ToolCallAbortedPart = Type.Composite([ToolCallBaseSchema, ToolAbortedSchema]);
|
|
321
|
-
const ToolCallSchema = _Message.ToolCallSchema = Type.Union([
|
|
322
|
-
ToolCallPendingPart,
|
|
323
|
-
ToolCallRunningPart,
|
|
324
|
-
ToolCallCompletedPart,
|
|
325
|
-
ToolCallErrorPart,
|
|
326
|
-
ToolCallSkippedPart,
|
|
327
|
-
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)
|
|
328
267
|
]);
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
cost: Type.Object({
|
|
336
|
-
input: Type.Number(),
|
|
337
|
-
output: Type.Number(),
|
|
338
|
-
cacheRead: Type.Number(),
|
|
339
|
-
cacheWrite: Type.Number(),
|
|
340
|
-
total: Type.Number()
|
|
341
|
-
})
|
|
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())
|
|
342
274
|
});
|
|
343
|
-
const
|
|
344
|
-
Type.Literal("
|
|
345
|
-
Type.Literal("
|
|
346
|
-
Type.Literal("
|
|
347
|
-
Type.Literal("error"),
|
|
348
|
-
Type.Literal("aborted")
|
|
275
|
+
const CacheRetentionSchema = _Stream.CacheRetentionSchema = Type.Union([
|
|
276
|
+
Type.Literal("none"),
|
|
277
|
+
Type.Literal("short"),
|
|
278
|
+
Type.Literal("long")
|
|
349
279
|
]);
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}),
|
|
368
|
-
parts: Type.Array(Type.Union([
|
|
369
|
-
TextContentSchema,
|
|
370
|
-
ImageContentSchema,
|
|
371
|
-
ThinkingContentSchema,
|
|
372
|
-
ToolCallSchema
|
|
373
|
-
])),
|
|
374
|
-
responseId: Type.Optional(Type.String()),
|
|
375
|
-
messageId: Type.String()
|
|
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()))
|
|
376
297
|
});
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function createUserMessage(message) {
|
|
383
|
-
const { messageId = createMessageId(), ...rest } = message;
|
|
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) {
|
|
384
303
|
return {
|
|
385
|
-
|
|
386
|
-
|
|
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
|
|
387
315
|
};
|
|
388
316
|
}
|
|
389
|
-
|
|
390
|
-
function
|
|
391
|
-
|
|
317
|
+
_Stream.buildBaseOptions = buildBaseOptions;
|
|
318
|
+
function clampReasoning(effort) {
|
|
319
|
+
return effort === ThinkingLevelEnum.xhigh ? ThinkingLevelEnum.high : effort;
|
|
320
|
+
}
|
|
321
|
+
_Stream.clampReasoning = clampReasoning;
|
|
322
|
+
function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
|
|
323
|
+
const budgets = {
|
|
324
|
+
minimal: 1024,
|
|
325
|
+
low: 2048,
|
|
326
|
+
medium: 8192,
|
|
327
|
+
high: 16384,
|
|
328
|
+
...customBudgets
|
|
329
|
+
};
|
|
330
|
+
const minOutputTokens = 1024;
|
|
331
|
+
let thinkingBudget = budgets[clampReasoning(reasoningLevel)];
|
|
332
|
+
const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
|
|
333
|
+
if (maxTokens <= thinkingBudget) thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
|
|
392
334
|
return {
|
|
393
|
-
|
|
394
|
-
|
|
335
|
+
maxTokens,
|
|
336
|
+
thinkingBudget
|
|
395
337
|
};
|
|
396
338
|
}
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
339
|
+
_Stream.adjustMaxTokensForThinking = adjustMaxTokensForThinking;
|
|
340
|
+
const protocolProviderRegistry = /* @__PURE__ */ new Map();
|
|
341
|
+
function wrapStream(protocol, stream) {
|
|
342
|
+
return (model, context, options) => {
|
|
343
|
+
if (model.protocol !== protocol) throw new ProtocolMismatchError({
|
|
344
|
+
actual: model.protocol,
|
|
345
|
+
expected: protocol
|
|
346
|
+
});
|
|
347
|
+
return stream(model, context, options);
|
|
348
|
+
};
|
|
405
349
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
});
|
|
412
|
-
function transformMessages(messages, model, normalizeToolCallId) {
|
|
413
|
-
const toolCallIDMap = /* @__PURE__ */ new Map();
|
|
414
|
-
const transformed = [];
|
|
415
|
-
for (const msg of messages) {
|
|
416
|
-
if (msg.role === "user") {
|
|
417
|
-
transformed.push(msg);
|
|
418
|
-
continue;
|
|
419
|
-
}
|
|
420
|
-
const assistantMsg = msg;
|
|
421
|
-
const isSameModel = assistantMsg.provider.id === model.provider.id && assistantMsg.protocol === model.protocol && assistantMsg.model === model.id;
|
|
422
|
-
const parts = assistantMsg.parts.flatMap((block) => {
|
|
423
|
-
if (block.type === "thinking") {
|
|
424
|
-
if (isSameModel && block.thinkingSignature) return block;
|
|
425
|
-
if (!block.thinking || block.thinking.trim() === "") return [];
|
|
426
|
-
if (isSameModel) return block;
|
|
427
|
-
return {
|
|
428
|
-
type: "text",
|
|
429
|
-
text: block.thinking
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
if (block.type === "text") {
|
|
433
|
-
if (isSameModel) return block;
|
|
434
|
-
return {
|
|
435
|
-
type: "text",
|
|
436
|
-
text: block.text
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
if (block.type === "toolCall") {
|
|
440
|
-
const toolCall = block;
|
|
441
|
-
let normalizedToolCall = toolCall;
|
|
442
|
-
if (!isSameModel && toolCall.thoughtSignature) {
|
|
443
|
-
normalizedToolCall = { ...toolCall };
|
|
444
|
-
delete normalizedToolCall.thoughtSignature;
|
|
445
|
-
}
|
|
446
|
-
const normalizedID = toolCallIDMap.get(block.callID);
|
|
447
|
-
if (normalizedID && normalizedID !== block.callID) normalizedToolCall = {
|
|
448
|
-
...normalizedToolCall,
|
|
449
|
-
callID: normalizedID
|
|
450
|
-
};
|
|
451
|
-
else if (!isSameModel && normalizeToolCallId) {
|
|
452
|
-
const nextID = normalizeToolCallId(toolCall.callID, model, assistantMsg);
|
|
453
|
-
if (nextID !== toolCall.callID) {
|
|
454
|
-
toolCallIDMap.set(toolCall.callID, nextID);
|
|
455
|
-
normalizedToolCall = {
|
|
456
|
-
...normalizedToolCall,
|
|
457
|
-
callID: nextID
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return normalizedToolCall;
|
|
462
|
-
}
|
|
463
|
-
return block;
|
|
464
|
-
});
|
|
465
|
-
transformed.push({
|
|
466
|
-
...assistantMsg,
|
|
467
|
-
parts
|
|
350
|
+
function wrapStreamSimple(protocol, streamSimple) {
|
|
351
|
+
return (model, context, options) => {
|
|
352
|
+
if (model.protocol !== protocol) throw new ProtocolMismatchError({
|
|
353
|
+
actual: model.protocol,
|
|
354
|
+
expected: protocol
|
|
468
355
|
});
|
|
469
|
-
|
|
470
|
-
|
|
356
|
+
return streamSimple(model, context, options);
|
|
357
|
+
};
|
|
471
358
|
}
|
|
472
|
-
|
|
473
|
-
|
|
359
|
+
function registerProtocolProvider(provider, sourceId) {
|
|
360
|
+
protocolProviderRegistry.set(provider.protocol, {
|
|
361
|
+
provider: {
|
|
362
|
+
protocol: provider.protocol,
|
|
363
|
+
stream: wrapStream(provider.protocol, provider.stream),
|
|
364
|
+
streamSimple: wrapStreamSimple(provider.protocol, provider.streamSimple)
|
|
365
|
+
},
|
|
366
|
+
sourceId
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
_Stream.registerProtocolProvider = registerProtocolProvider;
|
|
370
|
+
function getProtocolProvider(protocol) {
|
|
371
|
+
return protocolProviderRegistry.get(protocol)?.provider;
|
|
372
|
+
}
|
|
373
|
+
_Stream.getProtocolProvider = getProtocolProvider;
|
|
374
|
+
function resolveProtocolProvider(model) {
|
|
375
|
+
const provider = getProtocolProvider(model.protocol);
|
|
376
|
+
if (!provider) throw new ProtocolProviderNotFoundError({ protocol: model.protocol });
|
|
377
|
+
return provider;
|
|
378
|
+
}
|
|
379
|
+
_Stream.resolveProtocolProvider = resolveProtocolProvider;
|
|
380
|
+
function stream(model, context, options) {
|
|
381
|
+
return resolveProtocolProvider(model).stream(model, context, options);
|
|
382
|
+
}
|
|
383
|
+
_Stream.stream = stream;
|
|
384
|
+
async function complete(model, context, options) {
|
|
385
|
+
return stream(model, context, options).result();
|
|
386
|
+
}
|
|
387
|
+
_Stream.complete = complete;
|
|
388
|
+
function streamSimple(model, context, options) {
|
|
389
|
+
return resolveProtocolProvider(model).streamSimple(model, context, options);
|
|
390
|
+
}
|
|
391
|
+
_Stream.streamSimple = streamSimple;
|
|
392
|
+
async function completeSimple(model, context, options) {
|
|
393
|
+
return streamSimple(model, context, options).result();
|
|
394
|
+
}
|
|
395
|
+
_Stream.completeSimple = completeSimple;
|
|
396
|
+
function getApiProviders() {
|
|
397
|
+
return Array.from(protocolProviderRegistry.values(), (entry) => entry.provider);
|
|
398
|
+
}
|
|
399
|
+
_Stream.getApiProviders = getApiProviders;
|
|
400
|
+
function unregisterProtocolProviders(sourceId) {
|
|
401
|
+
for (const [api, entry] of protocolProviderRegistry.entries()) if (entry.sourceId === sourceId) protocolProviderRegistry.delete(api);
|
|
402
|
+
}
|
|
403
|
+
_Stream.unregisterProtocolProviders = unregisterProtocolProviders;
|
|
404
|
+
function clearProtocolProviders() {
|
|
405
|
+
protocolProviderRegistry.clear();
|
|
406
|
+
}
|
|
407
|
+
_Stream.clearProtocolProviders = clearProtocolProviders;
|
|
408
|
+
})(Stream || (Stream = {}));
|
|
474
409
|
//#endregion
|
|
475
410
|
//#region src/utils/eventstream.ts
|
|
476
411
|
var EventStream = class {
|
|
@@ -530,1306 +465,1381 @@ var AssistantMessageEventStream = class extends EventStream {
|
|
|
530
465
|
}
|
|
531
466
|
};
|
|
532
467
|
//#endregion
|
|
533
|
-
//#region src/utils/
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
468
|
+
//#region src/utils/validation.ts
|
|
469
|
+
const ajv = new Ajv({
|
|
470
|
+
allErrors: true,
|
|
471
|
+
strict: false,
|
|
472
|
+
coerceTypes: true
|
|
473
|
+
});
|
|
474
|
+
addFormats(ajv);
|
|
537
475
|
/**
|
|
538
|
-
*
|
|
539
|
-
* Always returns a valid object, even if the JSON is incomplete.
|
|
540
|
-
*
|
|
541
|
-
* @param partialJson The partial JSON string from streaming
|
|
542
|
-
* @returns Parsed object or empty object if parsing fails
|
|
476
|
+
* Validates an arbitrary value against a TypeBox schema and returns the coerced value.
|
|
543
477
|
*/
|
|
544
|
-
function
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
|
|
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"));
|
|
555
491
|
}
|
|
556
|
-
//#endregion
|
|
557
|
-
//#region src/utils/sanitize.ts
|
|
558
492
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
|
|
562
|
-
* or vice versa) cause JSON serialization errors in many API providers.
|
|
563
|
-
*
|
|
564
|
-
* Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
|
|
565
|
-
* surrogates and will NOT be affected by this function.
|
|
566
|
-
*
|
|
567
|
-
* @param text - The text to sanitize
|
|
568
|
-
* @returns The sanitized text with unpaired surrogates removed
|
|
569
|
-
*
|
|
570
|
-
* @example
|
|
571
|
-
* // Valid emoji (properly paired surrogates) are preserved
|
|
572
|
-
* sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
|
|
573
|
-
*
|
|
574
|
-
* // Unpaired high surrogate is removed
|
|
575
|
-
* const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
|
|
576
|
-
* sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
|
|
493
|
+
* Validates tool call arguments against the tool's TypeBox schema
|
|
577
494
|
*/
|
|
578
|
-
function
|
|
579
|
-
return
|
|
495
|
+
function validateToolArguments(tool, toolExecution) {
|
|
496
|
+
return validateSchema(tool.parameters, toolExecution.rawArgs, `Tool "${toolExecution.name}"`);
|
|
580
497
|
}
|
|
581
498
|
//#endregion
|
|
582
|
-
//#region src/
|
|
583
|
-
let
|
|
584
|
-
(function(
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
actual: Model.KnownProtocolSchema,
|
|
588
|
-
expected: Model.KnownProtocolSchema
|
|
589
|
-
}));
|
|
590
|
-
const ThinkingLevelEnum = _Stream.ThinkingLevelEnum = {
|
|
591
|
-
off: "off",
|
|
592
|
-
minimal: "minimal",
|
|
593
|
-
low: "low",
|
|
594
|
-
medium: "medium",
|
|
595
|
-
high: "high",
|
|
596
|
-
xhigh: "xhigh"
|
|
597
|
-
};
|
|
598
|
-
const ThinkingLevelSchema = _Stream.ThinkingLevelSchema = Type.Union([
|
|
599
|
-
Type.Literal(ThinkingLevelEnum.off),
|
|
600
|
-
Type.Literal(ThinkingLevelEnum.minimal),
|
|
601
|
-
Type.Literal(ThinkingLevelEnum.low),
|
|
602
|
-
Type.Literal(ThinkingLevelEnum.medium),
|
|
603
|
-
Type.Literal(ThinkingLevelEnum.high),
|
|
604
|
-
Type.Literal(ThinkingLevelEnum.xhigh)
|
|
605
|
-
]);
|
|
606
|
-
const ThinkingBudgetsSchema = _Stream.ThinkingBudgetsSchema = Type.Object({
|
|
607
|
-
off: Type.Optional(Type.Number()),
|
|
608
|
-
minimal: Type.Optional(Type.Number()),
|
|
609
|
-
low: Type.Optional(Type.Number()),
|
|
610
|
-
medium: Type.Optional(Type.Number()),
|
|
611
|
-
high: Type.Optional(Type.Number())
|
|
612
|
-
});
|
|
613
|
-
const CacheRetentionSchema = _Stream.CacheRetentionSchema = Type.Union([
|
|
614
|
-
Type.Literal("none"),
|
|
615
|
-
Type.Literal("short"),
|
|
616
|
-
Type.Literal("long")
|
|
617
|
-
]);
|
|
618
|
-
const TransportSchema = _Stream.TransportSchema = Type.Union([
|
|
619
|
-
Type.Literal("sse"),
|
|
620
|
-
Type.Literal("websocket"),
|
|
621
|
-
Type.Literal("auto")
|
|
622
|
-
]);
|
|
623
|
-
const OptionsSchema = _Stream.OptionsSchema = Type.Object({
|
|
624
|
-
temperature: Type.Optional(Type.Number()),
|
|
625
|
-
maxTokens: Type.Optional(Type.Number()),
|
|
626
|
-
signal: Type.Optional(Type.Unsafe()),
|
|
627
|
-
apiKey: Type.Optional(Type.String()),
|
|
628
|
-
transport: Type.Optional(TransportSchema),
|
|
629
|
-
cacheRetention: Type.Optional(CacheRetentionSchema),
|
|
630
|
-
sessionId: Type.Optional(Type.String()),
|
|
631
|
-
onPayload: Type.Optional(Type.Unsafe()),
|
|
632
|
-
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
633
|
-
maxRetryDelayMs: Type.Optional(Type.Number()),
|
|
634
|
-
metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
|
|
635
|
-
});
|
|
636
|
-
_Stream.SimpleOptionsSchema = Type.Composite([OptionsSchema, Type.Object({
|
|
637
|
-
reasoning: Type.Optional(ThinkingLevelSchema),
|
|
638
|
-
thinkingBudgets: Type.Optional(ThinkingBudgetsSchema)
|
|
639
|
-
})]);
|
|
640
|
-
function buildBaseOptions(model, options, apiKey) {
|
|
641
|
-
return {
|
|
642
|
-
temperature: options?.temperature,
|
|
643
|
-
maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32e3),
|
|
644
|
-
signal: options?.signal,
|
|
645
|
-
apiKey: apiKey || options?.apiKey,
|
|
646
|
-
transport: options?.transport,
|
|
647
|
-
cacheRetention: options?.cacheRetention,
|
|
648
|
-
sessionId: options?.sessionId,
|
|
649
|
-
headers: options?.headers,
|
|
650
|
-
onPayload: options?.onPayload,
|
|
651
|
-
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
652
|
-
metadata: options?.metadata
|
|
653
|
-
};
|
|
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 : []);
|
|
654
504
|
}
|
|
655
|
-
|
|
656
|
-
function
|
|
657
|
-
return
|
|
505
|
+
const AgentContextError = _Loop.AgentContextError = NamedError.create("AgentContextError", Type.Object({ message: Type.String() }));
|
|
506
|
+
function snapshotAssistantMessage(message) {
|
|
507
|
+
return structuredClone(message);
|
|
658
508
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
low: 2048,
|
|
664
|
-
medium: 8192,
|
|
665
|
-
high: 16384,
|
|
666
|
-
...customBudgets
|
|
667
|
-
};
|
|
668
|
-
const minOutputTokens = 1024;
|
|
669
|
-
let thinkingBudget = budgets[clampReasoning(reasoningLevel)];
|
|
670
|
-
const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
|
|
671
|
-
if (maxTokens <= thinkingBudget) thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
|
|
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`);
|
|
672
513
|
return {
|
|
673
|
-
|
|
674
|
-
|
|
514
|
+
message: snapshot,
|
|
515
|
+
part
|
|
675
516
|
};
|
|
676
517
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
518
|
+
async function emitEvent(emit, event) {
|
|
519
|
+
await emit(event);
|
|
520
|
+
}
|
|
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)
|
|
684
545
|
});
|
|
685
|
-
return stream(model, context, options);
|
|
686
546
|
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
actual: model.protocol,
|
|
692
|
-
expected: protocol
|
|
547
|
+
const emitMessageUpdate = async (message) => {
|
|
548
|
+
await emitEvent(emit, {
|
|
549
|
+
type: "message.update",
|
|
550
|
+
message: snapshotAssistantMessage(message)
|
|
693
551
|
});
|
|
694
|
-
return streamSimple(model, context, options);
|
|
695
552
|
};
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
553
|
+
const emitPartStart = async (message, partIndex) => {
|
|
554
|
+
await emitEvent(emit, {
|
|
555
|
+
type: "message.part.start",
|
|
556
|
+
partIndex,
|
|
557
|
+
...snapshotAssistantPartEvent(message, partIndex)
|
|
558
|
+
});
|
|
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"
|
|
566
|
+
});
|
|
567
|
+
};
|
|
568
|
+
const emitPartEnd = async (message, partIndex) => {
|
|
569
|
+
await emitEvent(emit, {
|
|
570
|
+
type: "message.part.end",
|
|
571
|
+
partIndex,
|
|
572
|
+
...snapshotAssistantPartEvent(message, partIndex)
|
|
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;
|
|
616
|
+
}
|
|
617
|
+
const finalMessage = await events.result();
|
|
618
|
+
await ensureMessageStarted(finalMessage);
|
|
619
|
+
await emitEvent(emit, {
|
|
620
|
+
type: "message.end",
|
|
621
|
+
message: snapshotAssistantMessage(finalMessage)
|
|
705
622
|
});
|
|
623
|
+
return finalMessage;
|
|
706
624
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
return
|
|
710
|
-
}
|
|
711
|
-
_Stream.getProtocolProvider = getProtocolProvider;
|
|
712
|
-
function resolveProtocolProvider(model) {
|
|
713
|
-
const provider = getProtocolProvider(model.protocol);
|
|
714
|
-
if (!provider) throw new ProtocolProviderNotFoundError({ protocol: model.protocol });
|
|
715
|
-
return provider;
|
|
716
|
-
}
|
|
717
|
-
_Stream.resolveProtocolProvider = resolveProtocolProvider;
|
|
718
|
-
function stream(model, context, options) {
|
|
719
|
-
return resolveProtocolProvider(model).stream(model, context, options);
|
|
720
|
-
}
|
|
721
|
-
_Stream.stream = stream;
|
|
722
|
-
async function complete(model, context, options) {
|
|
723
|
-
return stream(model, context, options).result();
|
|
724
|
-
}
|
|
725
|
-
_Stream.complete = complete;
|
|
726
|
-
function streamSimple(model, context, options) {
|
|
727
|
-
return resolveProtocolProvider(model).streamSimple(model, context, options);
|
|
728
|
-
}
|
|
729
|
-
_Stream.streamSimple = streamSimple;
|
|
730
|
-
async function completeSimple(model, context, options) {
|
|
731
|
-
return streamSimple(model, context, options).result();
|
|
732
|
-
}
|
|
733
|
-
_Stream.completeSimple = completeSimple;
|
|
734
|
-
function getApiProviders() {
|
|
735
|
-
return Array.from(protocolProviderRegistry.values(), (entry) => entry.provider);
|
|
736
|
-
}
|
|
737
|
-
_Stream.getApiProviders = getApiProviders;
|
|
738
|
-
function unregisterProtocolProviders(sourceId) {
|
|
739
|
-
for (const [api, entry] of protocolProviderRegistry.entries()) if (entry.sourceId === sourceId) protocolProviderRegistry.delete(api);
|
|
740
|
-
}
|
|
741
|
-
_Stream.unregisterProtocolProviders = unregisterProtocolProviders;
|
|
742
|
-
function clearProtocolProviders() {
|
|
743
|
-
protocolProviderRegistry.clear();
|
|
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);
|
|
744
628
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
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);
|
|
654
|
+
} else {
|
|
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);
|
|
675
|
+
}
|
|
764
676
|
}
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
const claudeCodeVersion = "2.1.2";
|
|
768
|
-
const ccToolLookup = new Map([
|
|
769
|
-
"Read",
|
|
770
|
-
"Write",
|
|
771
|
-
"Edit",
|
|
772
|
-
"Bash",
|
|
773
|
-
"Grep",
|
|
774
|
-
"Glob",
|
|
775
|
-
"AskUserQuestion",
|
|
776
|
-
"EnterPlanMode",
|
|
777
|
-
"ExitPlanMode",
|
|
778
|
-
"KillShell",
|
|
779
|
-
"NotebookEdit",
|
|
780
|
-
"Skill",
|
|
781
|
-
"Task",
|
|
782
|
-
"TaskOutput",
|
|
783
|
-
"TodoWrite",
|
|
784
|
-
"WebFetch",
|
|
785
|
-
"WebSearch"
|
|
786
|
-
].map((t) => [t.toLowerCase(), t]));
|
|
787
|
-
const toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;
|
|
788
|
-
const fromClaudeCodeName = (name, tools) => {
|
|
789
|
-
if (tools && tools.length > 0) {
|
|
790
|
-
const lowerName = name.toLowerCase();
|
|
791
|
-
const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
|
|
792
|
-
if (matchedTool) return matchedTool.name;
|
|
793
|
-
}
|
|
794
|
-
return name;
|
|
795
|
-
};
|
|
796
|
-
function convertContentBlocks(content) {
|
|
797
|
-
if (!content.some((c) => c.type === "image")) return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
|
|
798
|
-
const blocks = content.map((block) => {
|
|
799
|
-
if (block.type === "text") return {
|
|
800
|
-
type: "text",
|
|
801
|
-
text: sanitizeSurrogates(block.text)
|
|
802
|
-
};
|
|
803
|
-
return {
|
|
804
|
-
type: "image",
|
|
805
|
-
source: {
|
|
806
|
-
type: "base64",
|
|
807
|
-
media_type: block.mimeType,
|
|
808
|
-
data: block.data
|
|
809
|
-
}
|
|
810
|
-
};
|
|
811
|
-
});
|
|
812
|
-
if (!blocks.some((b) => b.type === "text")) blocks.unshift({
|
|
813
|
-
type: "text",
|
|
814
|
-
text: "(see attached image)"
|
|
815
|
-
});
|
|
816
|
-
return blocks;
|
|
817
|
-
}
|
|
818
|
-
function mergeHeaders(...headerSources) {
|
|
819
|
-
const merged = {};
|
|
820
|
-
for (const headers of headerSources) if (headers) Object.assign(merged, headers);
|
|
821
|
-
return merged;
|
|
822
|
-
}
|
|
823
|
-
function isOAuthToken(apiKey) {
|
|
824
|
-
return apiKey.includes("sk-ant-oat");
|
|
825
|
-
}
|
|
826
|
-
function createClient(model, apiKey, interleavedThinking, optionsHeaders) {
|
|
827
|
-
const betaFeatures = ["fine-grained-tool-streaming-2025-05-14"];
|
|
828
|
-
if (interleavedThinking) betaFeatures.push("interleaved-thinking-2025-05-14");
|
|
829
|
-
if (isOAuthToken(apiKey)) {
|
|
830
|
-
const defaultHeaders = mergeHeaders({
|
|
831
|
-
accept: "application/json",
|
|
832
|
-
"anthropic-dangerous-direct-browser-access": "true",
|
|
833
|
-
"anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}`,
|
|
834
|
-
"user-agent": `claude-cli/${claudeCodeVersion} (external, cli)`,
|
|
835
|
-
"x-app": "cli"
|
|
836
|
-
}, model.headers, optionsHeaders);
|
|
837
|
-
return {
|
|
838
|
-
client: new Anthropic({
|
|
839
|
-
apiKey: null,
|
|
840
|
-
authToken: apiKey,
|
|
841
|
-
baseURL: model.baseUrl,
|
|
842
|
-
defaultHeaders,
|
|
843
|
-
dangerouslyAllowBrowser: true
|
|
844
|
-
}),
|
|
845
|
-
isOAuthToken: true
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
const defaultHeaders = mergeHeaders({
|
|
849
|
-
accept: "application/json",
|
|
850
|
-
"anthropic-dangerous-direct-browser-access": "true",
|
|
851
|
-
"anthropic-beta": betaFeatures.join(",")
|
|
852
|
-
}, model.headers, optionsHeaders);
|
|
853
|
-
return {
|
|
854
|
-
client: new Anthropic({
|
|
855
|
-
apiKey,
|
|
856
|
-
baseURL: model.baseUrl,
|
|
857
|
-
dangerouslyAllowBrowser: true,
|
|
858
|
-
defaultHeaders
|
|
859
|
-
}),
|
|
860
|
-
isOAuthToken: false
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
function normalizeToolCallId(id) {
|
|
864
|
-
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
865
|
-
}
|
|
866
|
-
function assertReplayableAssistant(message) {
|
|
867
|
-
let sawToolCall = false;
|
|
868
|
-
let sawNonTerminalToolCall = false;
|
|
869
|
-
let sawTerminalToolCall = false;
|
|
870
|
-
for (const part of message.parts) {
|
|
871
|
-
if (part.type === "image") throw new Error("Anthropic replay does not support assistant image parts");
|
|
872
|
-
if (part.type === "toolCall") {
|
|
873
|
-
sawToolCall = true;
|
|
874
|
-
if (part.status === "pending" || part.status === "running") sawNonTerminalToolCall = true;
|
|
875
|
-
else sawTerminalToolCall = true;
|
|
876
|
-
continue;
|
|
877
|
-
}
|
|
878
|
-
if (sawToolCall) throw new Error("Assistant parts after a toolCall are not replayable for Anthropic");
|
|
879
677
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
if (msg.role === "user") {
|
|
904
|
-
const blocks = msg.parts.map((item) => {
|
|
905
|
-
if (item.type === "text") return {
|
|
906
|
-
type: "text",
|
|
907
|
-
text: sanitizeSurrogates(item.text)
|
|
908
|
-
};
|
|
909
|
-
return {
|
|
910
|
-
type: "image",
|
|
911
|
-
source: {
|
|
912
|
-
type: "base64",
|
|
913
|
-
media_type: item.mimeType,
|
|
914
|
-
data: item.data
|
|
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
|
|
689
|
+
});
|
|
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
|
|
915
701
|
}
|
|
916
702
|
};
|
|
703
|
+
await emitToolCallTerminalResult(toolCall, prepared.runnable, message, emit, error);
|
|
704
|
+
} else runnables.push({
|
|
705
|
+
toolCall,
|
|
706
|
+
runnable: prepared.runnable,
|
|
707
|
+
tool: prepared.tool
|
|
917
708
|
});
|
|
918
|
-
let filteredBlocks = !model.input.includes("image") ? blocks.filter((b) => b.type !== "image") : blocks;
|
|
919
|
-
filteredBlocks = filteredBlocks.filter((b) => b.type === "text" ? b.text.trim().length > 0 : true);
|
|
920
|
-
if (filteredBlocks.length === 0) continue;
|
|
921
|
-
params.push({
|
|
922
|
-
role: "user",
|
|
923
|
-
content: filteredBlocks
|
|
924
|
-
});
|
|
925
|
-
continue;
|
|
926
709
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
for (const
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
});
|
|
948
|
-
} else if (block.type === "toolCall") {
|
|
949
|
-
assistantBlocks.push({
|
|
950
|
-
type: "tool_use",
|
|
951
|
-
id: block.callID,
|
|
952
|
-
name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
|
|
953
|
-
input: block.arguments ?? {}
|
|
954
|
-
});
|
|
955
|
-
if (block.status === "pending" || block.status === "running") toolResults.push(buildSyntheticToolResult(block));
|
|
956
|
-
else toolResults.push({
|
|
957
|
-
type: "tool_result",
|
|
958
|
-
tool_use_id: block.callID,
|
|
959
|
-
content: convertContentBlocks(block.result.content),
|
|
960
|
-
is_error: block.result.isError
|
|
961
|
-
});
|
|
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);
|
|
962
731
|
}
|
|
963
|
-
if (assistantBlocks.length > 0) params.push({
|
|
964
|
-
role: "assistant",
|
|
965
|
-
content: assistantBlocks
|
|
966
|
-
});
|
|
967
|
-
if (toolResults.length > 0) params.push({
|
|
968
|
-
role: "user",
|
|
969
|
-
content: toolResults
|
|
970
|
-
});
|
|
971
732
|
}
|
|
972
|
-
|
|
973
|
-
const
|
|
974
|
-
if (
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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
|
+
};
|
|
983
771
|
}
|
|
984
772
|
}
|
|
985
|
-
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
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
|
+
}
|
|
1012
803
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
stream: true
|
|
1021
|
-
};
|
|
1022
|
-
if (isOAuthToken) {
|
|
1023
|
-
params.system = [{
|
|
1024
|
-
type: "text",
|
|
1025
|
-
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
|
1026
|
-
...cacheControl ? { cache_control: cacheControl } : {}
|
|
1027
|
-
}];
|
|
1028
|
-
if (context.systemPrompt) params.system.push({
|
|
1029
|
-
type: "text",
|
|
1030
|
-
text: sanitizeSurrogates(context.systemPrompt),
|
|
1031
|
-
...cacheControl ? { cache_control: cacheControl } : {}
|
|
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
|
|
1032
811
|
});
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
...cacheControl ? { cache_control: cacheControl } : {}
|
|
1037
|
-
}];
|
|
1038
|
-
if (options?.temperature !== void 0 && !options?.thinkingEnabled) params.temperature = options.temperature;
|
|
1039
|
-
if (context.tools) params.tools = convertTools(context.tools, isOAuthToken);
|
|
1040
|
-
if (options?.thinkingEnabled && model.reasoning) params.thinking = {
|
|
1041
|
-
type: "enabled",
|
|
1042
|
-
budget_tokens: options.thinkingBudgetTokens || 1024
|
|
1043
|
-
};
|
|
1044
|
-
if (options?.metadata) {
|
|
1045
|
-
const userId = options.metadata.user_id;
|
|
1046
|
-
if (typeof userId === "string") params.metadata = { user_id: userId };
|
|
1047
|
-
}
|
|
1048
|
-
if (options?.toolChoice) params.tool_choice = typeof options.toolChoice === "string" ? { type: options.toolChoice } : options.toolChoice;
|
|
1049
|
-
return params;
|
|
1050
|
-
}
|
|
1051
|
-
const streamAnthropic = (model, context, options) => {
|
|
1052
|
-
const stream = new AssistantMessageEventStream();
|
|
1053
|
-
(async () => {
|
|
1054
|
-
const output = Message.createAssistantMessage({
|
|
1055
|
-
role: "assistant",
|
|
1056
|
-
parts: [],
|
|
1057
|
-
protocol: model.protocol,
|
|
1058
|
-
provider: model.provider,
|
|
1059
|
-
model: model.id,
|
|
1060
|
-
usage: {
|
|
1061
|
-
input: 0,
|
|
1062
|
-
output: 0,
|
|
1063
|
-
cacheRead: 0,
|
|
1064
|
-
cacheWrite: 0,
|
|
1065
|
-
totalTokens: 0,
|
|
1066
|
-
cost: {
|
|
1067
|
-
input: 0,
|
|
1068
|
-
output: 0,
|
|
1069
|
-
cacheRead: 0,
|
|
1070
|
-
cacheWrite: 0,
|
|
1071
|
-
total: 0
|
|
1072
|
-
}
|
|
1073
|
-
},
|
|
1074
|
-
stopReason: "stop",
|
|
812
|
+
const part = {
|
|
813
|
+
...pendingPart,
|
|
814
|
+
...result,
|
|
1075
815
|
time: {
|
|
1076
|
-
|
|
1077
|
-
|
|
816
|
+
start: time.start,
|
|
817
|
+
end: Date.now()
|
|
1078
818
|
}
|
|
819
|
+
};
|
|
820
|
+
message.parts[partIndex] = part;
|
|
821
|
+
await emitEvent(emit, {
|
|
822
|
+
type: "message.part.start",
|
|
823
|
+
message,
|
|
824
|
+
partIndex,
|
|
825
|
+
part
|
|
1079
826
|
});
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
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;
|
|
1092
849
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
} else if (event.content_block.type === "redacted_thinking") {
|
|
1140
|
-
const block = {
|
|
1141
|
-
type: "thinking",
|
|
1142
|
-
thinking: "[Reasoning redacted]",
|
|
1143
|
-
thinkingSignature: event.content_block.data,
|
|
1144
|
-
redacted: true,
|
|
1145
|
-
index: event.index
|
|
1146
|
-
};
|
|
1147
|
-
output.parts.push(block);
|
|
1148
|
-
stream.push({
|
|
1149
|
-
type: "thinking.start",
|
|
1150
|
-
partIndex: output.parts.length - 1,
|
|
1151
|
-
partial: output
|
|
1152
|
-
});
|
|
1153
|
-
} else if (event.content_block.type === "tool_use") {
|
|
1154
|
-
const block = {
|
|
1155
|
-
type: "toolCall",
|
|
1156
|
-
callID: event.content_block.id,
|
|
1157
|
-
name: isOAuthToken ? fromClaudeCodeName(event.content_block.name, context.tools) : event.content_block.name,
|
|
1158
|
-
arguments: event.content_block.input ?? {},
|
|
1159
|
-
partialJson: "",
|
|
1160
|
-
status: "pending",
|
|
1161
|
-
time: {
|
|
1162
|
-
start: Date.now(),
|
|
1163
|
-
end: Date.now()
|
|
1164
|
-
},
|
|
1165
|
-
index: event.index
|
|
1166
|
-
};
|
|
1167
|
-
output.parts.push(block);
|
|
1168
|
-
stream.push({
|
|
1169
|
-
type: "toolcall.start",
|
|
1170
|
-
partIndex: output.parts.length - 1,
|
|
1171
|
-
partial: output
|
|
1172
|
-
});
|
|
1173
|
-
}
|
|
1174
|
-
} else if (event.type === "content_block_delta") {
|
|
1175
|
-
const partIndex = blocks.findIndex((b) => b.index === event.index);
|
|
1176
|
-
const block = blocks[partIndex];
|
|
1177
|
-
if (!block) continue;
|
|
1178
|
-
if (event.delta.type === "text_delta" && block.type === "text") {
|
|
1179
|
-
block.text += event.delta.text;
|
|
1180
|
-
stream.push({
|
|
1181
|
-
type: "text.delta",
|
|
1182
|
-
partIndex,
|
|
1183
|
-
delta: event.delta.text,
|
|
1184
|
-
partial: output
|
|
1185
|
-
});
|
|
1186
|
-
} else if (event.delta.type === "thinking_delta" && block.type === "thinking") {
|
|
1187
|
-
block.thinking += event.delta.thinking;
|
|
1188
|
-
stream.push({
|
|
1189
|
-
type: "thinking.delta",
|
|
1190
|
-
partIndex,
|
|
1191
|
-
delta: event.delta.thinking,
|
|
1192
|
-
partial: output
|
|
1193
|
-
});
|
|
1194
|
-
} else if (event.delta.type === "input_json_delta" && block.type === "toolCall") {
|
|
1195
|
-
block.partialJson += event.delta.partial_json;
|
|
1196
|
-
block.arguments = parseStreamingJson(block.partialJson);
|
|
1197
|
-
stream.push({
|
|
1198
|
-
type: "toolcall.delta",
|
|
1199
|
-
partIndex,
|
|
1200
|
-
delta: event.delta.partial_json,
|
|
1201
|
-
partial: output
|
|
1202
|
-
});
|
|
1203
|
-
} else if (event.delta.type === "signature_delta" && block.type === "thinking") {
|
|
1204
|
-
block.thinkingSignature = block.thinkingSignature || "";
|
|
1205
|
-
block.thinkingSignature += event.delta.signature;
|
|
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 = [];
|
|
1206
896
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
partIndex,
|
|
1215
|
-
content: block.text,
|
|
1216
|
-
partial: output
|
|
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
|
|
1217
904
|
});
|
|
1218
|
-
|
|
1219
|
-
type: "
|
|
1220
|
-
|
|
1221
|
-
content: block.thinking,
|
|
1222
|
-
partial: output
|
|
905
|
+
await emitEvent(emit, {
|
|
906
|
+
type: "agent.end",
|
|
907
|
+
messages: newMessages
|
|
1223
908
|
});
|
|
1224
|
-
|
|
1225
|
-
block.arguments = parseStreamingJson(block.partialJson);
|
|
1226
|
-
delete block.partialJson;
|
|
1227
|
-
stream.push({
|
|
1228
|
-
type: "toolcall.end",
|
|
1229
|
-
partIndex,
|
|
1230
|
-
toolCall: block,
|
|
1231
|
-
partial: output
|
|
1232
|
-
});
|
|
1233
|
-
}
|
|
909
|
+
return;
|
|
1234
910
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1242
|
-
|
|
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?.() || [];
|
|
1243
924
|
}
|
|
1244
|
-
|
|
1245
|
-
if (
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
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
|
|
1251
955
|
});
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
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
|
|
1262
973
|
});
|
|
1263
|
-
stream.end();
|
|
1264
974
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
...
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
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 = {}));
|
|
1292
1011
|
//#endregion
|
|
1293
|
-
//#region src/
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
allErrors: true,
|
|
1299
|
-
strict: false,
|
|
1300
|
-
coerceTypes: true
|
|
1301
|
-
});
|
|
1302
|
-
addFormats(ajv);
|
|
1303
|
-
/**
|
|
1304
|
-
* Validates tool call arguments against the tool's TypeBox schema
|
|
1305
|
-
*/
|
|
1306
|
-
function validateToolArguments(tool, toolExecution) {
|
|
1307
|
-
const validate = ajv.compile(tool.parameters);
|
|
1308
|
-
const args = structuredClone(toolExecution.rawArgs);
|
|
1309
|
-
if (validate(args)) return args;
|
|
1310
|
-
const errors = validate.errors?.map((err) => {
|
|
1311
|
-
return ` - ${err.instancePath ? err.instancePath.substring(1) : err.params?.missingProperty || "root"}: ${err.message}`;
|
|
1312
|
-
}).join("\n") || "Unknown Validation Error";
|
|
1313
|
-
throw new Error([
|
|
1314
|
-
`Validation Failed For Tool "${toolExecution.name}"`,
|
|
1315
|
-
`${errors}\n`,
|
|
1316
|
-
"Received Arguments:",
|
|
1317
|
-
`${JSON.stringify(toolExecution.rawArgs, null, 2)}\n`
|
|
1318
|
-
].join("\n"));
|
|
1319
|
-
}
|
|
1012
|
+
//#region src/agent.ts
|
|
1013
|
+
const agent = {
|
|
1014
|
+
loop: Loop.run,
|
|
1015
|
+
loopContinue: Loop.runContinue
|
|
1016
|
+
};
|
|
1320
1017
|
//#endregion
|
|
1321
|
-
//#region src/
|
|
1322
|
-
let
|
|
1323
|
-
(function(
|
|
1324
|
-
|
|
1325
|
-
|
|
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();
|
|
1326
1155
|
}
|
|
1327
|
-
|
|
1328
|
-
function
|
|
1329
|
-
|
|
1156
|
+
_Message.createMessageId = createMessageId;
|
|
1157
|
+
function createUserMessage(message) {
|
|
1158
|
+
const { messageId = createMessageId(), ...rest } = message;
|
|
1159
|
+
return {
|
|
1160
|
+
messageId,
|
|
1161
|
+
...rest
|
|
1162
|
+
};
|
|
1330
1163
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
const
|
|
1334
|
-
if (!part) throw new Error(`Assistant message part at index ${partIndex} was not found`);
|
|
1164
|
+
_Message.createUserMessage = createUserMessage;
|
|
1165
|
+
function createAssistantMessage(message) {
|
|
1166
|
+
const { messageId = createMessageId(), ...rest } = message;
|
|
1335
1167
|
return {
|
|
1336
|
-
|
|
1337
|
-
|
|
1168
|
+
messageId,
|
|
1169
|
+
...rest
|
|
1338
1170
|
};
|
|
1339
1171
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
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;
|
|
1342
1180
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
const
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
const emitPartUpdate = async (message, partIndex) => {
|
|
1383
|
-
await emitEvent(emit, {
|
|
1384
|
-
type: "message.part.update",
|
|
1385
|
-
partIndex,
|
|
1386
|
-
...snapshotAssistantPartEvent(message, partIndex),
|
|
1387
|
-
source: "llm"
|
|
1388
|
-
});
|
|
1389
|
-
};
|
|
1390
|
-
const emitPartEnd = async (message, partIndex) => {
|
|
1391
|
-
await emitEvent(emit, {
|
|
1392
|
-
type: "message.part.end",
|
|
1393
|
-
partIndex,
|
|
1394
|
-
...snapshotAssistantPartEvent(message, partIndex)
|
|
1395
|
-
});
|
|
1396
|
-
};
|
|
1397
|
-
for await (const event of events) switch (event.type) {
|
|
1398
|
-
case "start":
|
|
1399
|
-
partialMessage = event.partial;
|
|
1400
|
-
await ensureMessageStarted(partialMessage);
|
|
1401
|
-
break;
|
|
1402
|
-
case "text.start":
|
|
1403
|
-
case "thinking.start":
|
|
1404
|
-
case "toolcall.start":
|
|
1405
|
-
partialMessage = event.partial;
|
|
1406
|
-
await ensureMessageStarted(partialMessage);
|
|
1407
|
-
await emitPartStart(partialMessage, event.partIndex);
|
|
1408
|
-
break;
|
|
1409
|
-
case "text.delta":
|
|
1410
|
-
case "thinking.delta":
|
|
1411
|
-
case "toolcall.delta":
|
|
1412
|
-
partialMessage = event.partial;
|
|
1413
|
-
await ensureMessageStarted(partialMessage);
|
|
1414
|
-
await emitPartUpdate(partialMessage, event.partIndex);
|
|
1415
|
-
break;
|
|
1416
|
-
case "text.end":
|
|
1417
|
-
case "thinking.end":
|
|
1418
|
-
case "toolcall.end":
|
|
1419
|
-
partialMessage = event.partial;
|
|
1420
|
-
await ensureMessageStarted(partialMessage);
|
|
1421
|
-
await emitPartEnd(partialMessage, event.partIndex);
|
|
1422
|
-
await emitMessageUpdate(partialMessage);
|
|
1423
|
-
break;
|
|
1424
|
-
case "done":
|
|
1425
|
-
await ensureMessageStarted(event.message);
|
|
1426
|
-
await emitEvent(emit, {
|
|
1427
|
-
type: "message.end",
|
|
1428
|
-
message: snapshotAssistantMessage(event.message)
|
|
1429
|
-
});
|
|
1430
|
-
return event.message;
|
|
1431
|
-
case "error":
|
|
1432
|
-
await ensureMessageStarted(event.error);
|
|
1433
|
-
await emitEvent(emit, {
|
|
1434
|
-
type: "message.end",
|
|
1435
|
-
message: snapshotAssistantMessage(event.error)
|
|
1436
|
-
});
|
|
1437
|
-
return event.error;
|
|
1438
|
-
}
|
|
1439
|
-
const finalMessage = await events.result();
|
|
1440
|
-
await ensureMessageStarted(finalMessage);
|
|
1441
|
-
await emitEvent(emit, {
|
|
1442
|
-
type: "message.end",
|
|
1443
|
-
message: snapshotAssistantMessage(finalMessage)
|
|
1444
|
-
});
|
|
1445
|
-
return finalMessage;
|
|
1446
|
-
}
|
|
1447
|
-
async function executeToolCalls(config, currentContext, message, toolCalls, emit, signal) {
|
|
1448
|
-
if (config.toolExecution === "sequential") return executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal);
|
|
1449
|
-
return executeToolCallsParallel(config, currentContext, message, toolCalls, emit, signal);
|
|
1450
|
-
}
|
|
1451
|
-
async function executeToolCallsSequential(config, currentContext, message, toolCalls, emit, signal) {
|
|
1452
|
-
for (const toolCall of toolCalls) {
|
|
1453
|
-
const toolCallInFlight = {
|
|
1454
|
-
callID: toolCall.callID,
|
|
1455
|
-
name: toolCall.name,
|
|
1456
|
-
rawArgs: toolCall.arguments
|
|
1457
|
-
};
|
|
1458
|
-
await emitEvent(emit, {
|
|
1459
|
-
type: "tool.execution.start",
|
|
1460
|
-
...toolCallInFlight
|
|
1461
|
-
});
|
|
1462
|
-
const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
|
|
1463
|
-
if (prepared.error) {
|
|
1464
|
-
const error = {
|
|
1465
|
-
status: "error",
|
|
1466
|
-
result: {
|
|
1467
|
-
content: [{
|
|
1468
|
-
type: "text",
|
|
1469
|
-
text: prepared.error.message
|
|
1470
|
-
}],
|
|
1471
|
-
details: prepared.error.details,
|
|
1472
|
-
isError: true
|
|
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
|
+
};
|
|
1206
|
+
}
|
|
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;
|
|
1473
1220
|
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
toolCall,
|
|
1479
|
-
runnable: prepared.runnable,
|
|
1480
|
-
tool: prepared.tool
|
|
1481
|
-
};
|
|
1482
|
-
const executed = await executeRunnableToolCall(runnable, message, emit, signal);
|
|
1483
|
-
if (executed.error) {
|
|
1484
|
-
const error = {
|
|
1485
|
-
status: "error",
|
|
1486
|
-
result: {
|
|
1487
|
-
content: [{
|
|
1488
|
-
type: "text",
|
|
1489
|
-
text: executed.error.message
|
|
1490
|
-
}],
|
|
1491
|
-
details: executed.error.details,
|
|
1492
|
-
isError: true
|
|
1493
|
-
}
|
|
1221
|
+
const normalizedID = toolCallIDMap.get(block.callID);
|
|
1222
|
+
if (normalizedID && normalizedID !== block.callID) normalizedToolCall = {
|
|
1223
|
+
...normalizedToolCall,
|
|
1224
|
+
callID: normalizedID
|
|
1494
1225
|
};
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
callID: toolCall.callID,
|
|
1505
|
-
name: toolCall.name,
|
|
1506
|
-
rawArgs: toolCall.arguments
|
|
1507
|
-
};
|
|
1508
|
-
await emitEvent(emit, {
|
|
1509
|
-
type: "tool.execution.start",
|
|
1510
|
-
...toolCallInFlight
|
|
1511
|
-
});
|
|
1512
|
-
const prepared = await prepareToolCall(config, currentContext, message, toolCallInFlight, signal);
|
|
1513
|
-
if (prepared.error) {
|
|
1514
|
-
const error = {
|
|
1515
|
-
status: "error",
|
|
1516
|
-
result: {
|
|
1517
|
-
content: [{
|
|
1518
|
-
type: "text",
|
|
1519
|
-
text: prepared.error.message
|
|
1520
|
-
}],
|
|
1521
|
-
details: prepared.error.details,
|
|
1522
|
-
isError: true
|
|
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
|
+
}
|
|
1523
1235
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1236
|
+
return normalizedToolCall;
|
|
1237
|
+
}
|
|
1238
|
+
return block;
|
|
1239
|
+
});
|
|
1240
|
+
transformed.push({
|
|
1241
|
+
...assistantMsg,
|
|
1242
|
+
parts
|
|
1530
1243
|
});
|
|
1531
1244
|
}
|
|
1532
|
-
|
|
1533
|
-
runnable,
|
|
1534
|
-
execution: executeRunnableToolCall(runnable, message, emit, signal)
|
|
1535
|
-
}));
|
|
1536
|
-
for (const running of runningExecutions) {
|
|
1537
|
-
const executed = await running.execution;
|
|
1538
|
-
const { runnable } = running;
|
|
1539
|
-
if (executed.error) {
|
|
1540
|
-
const error = {
|
|
1541
|
-
status: "error",
|
|
1542
|
-
result: {
|
|
1543
|
-
content: [{
|
|
1544
|
-
type: "text",
|
|
1545
|
-
text: executed.error.message
|
|
1546
|
-
}],
|
|
1547
|
-
details: executed.error.details,
|
|
1548
|
-
isError: true
|
|
1549
|
-
}
|
|
1550
|
-
};
|
|
1551
|
-
await emitToolCallTerminalResult(runnable.toolCall, runnable.runnable, message, emit, error);
|
|
1552
|
-
} else await finalizeExecutedToolCall(config, currentContext, runnable.toolCall, runnable.runnable, message, emit, executed.result);
|
|
1553
|
-
}
|
|
1245
|
+
return transformed;
|
|
1554
1246
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1247
|
+
_Message.transformMessages = transformMessages;
|
|
1248
|
+
})(Message || (Message = {}));
|
|
1249
|
+
//#endregion
|
|
1250
|
+
//#region src/utils/jsonparse.ts
|
|
1251
|
+
/**
|
|
1252
|
+
* @description Helper function to parse partial jsons during LLM streaming.
|
|
1253
|
+
*/
|
|
1254
|
+
/**
|
|
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
|
|
1260
|
+
*/
|
|
1261
|
+
function parseStreamingJson(partialJson) {
|
|
1262
|
+
if (!partialJson || partialJson.trim() === "") return {};
|
|
1263
|
+
try {
|
|
1264
|
+
return JSON.parse(partialJson);
|
|
1265
|
+
} catch {
|
|
1564
1266
|
try {
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
context: currentContext,
|
|
1569
|
-
assistantMessage,
|
|
1570
|
-
toolCall: toolCallInFlight
|
|
1571
|
-
}, signal);
|
|
1572
|
-
if (beforeResult?.block) return {
|
|
1573
|
-
error: {
|
|
1574
|
-
kind: "blocked",
|
|
1575
|
-
message: beforeResult?.reason || "Tool Execution was Blocked",
|
|
1576
|
-
details: beforeResult?.details
|
|
1577
|
-
},
|
|
1578
|
-
runnable: toolCallInFlight
|
|
1579
|
-
};
|
|
1580
|
-
}
|
|
1581
|
-
return {
|
|
1582
|
-
runnable: toolCallInFlight,
|
|
1583
|
-
tool
|
|
1584
|
-
};
|
|
1585
|
-
} catch (err) {
|
|
1586
|
-
return {
|
|
1587
|
-
error: {
|
|
1588
|
-
kind: "error",
|
|
1589
|
-
message: err instanceof Error ? err.message : String(err)
|
|
1590
|
-
},
|
|
1591
|
-
runnable: toolCallInFlight
|
|
1592
|
-
};
|
|
1267
|
+
return parse(partialJson) ?? {};
|
|
1268
|
+
} catch {
|
|
1269
|
+
return {};
|
|
1593
1270
|
}
|
|
1594
1271
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1272
|
+
}
|
|
1273
|
+
//#endregion
|
|
1274
|
+
//#region src/utils/sanitize.ts
|
|
1275
|
+
/**
|
|
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"
|
|
1294
|
+
*/
|
|
1295
|
+
function sanitizeSurrogates(text) {
|
|
1296
|
+
return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
|
|
1297
|
+
}
|
|
1298
|
+
//#endregion
|
|
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 }
|
|
1624
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;
|
|
1625
1344
|
}
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
const part = {
|
|
1635
|
-
...pendingPart,
|
|
1636
|
-
...result,
|
|
1637
|
-
time: {
|
|
1638
|
-
start: time.start,
|
|
1639
|
-
end: Date.now()
|
|
1640
|
-
}
|
|
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)
|
|
1641
1353
|
};
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
});
|
|
1649
|
-
await emitEvent(emit, {
|
|
1650
|
-
type: "message.part.end",
|
|
1651
|
-
message,
|
|
1652
|
-
partIndex,
|
|
1653
|
-
part
|
|
1654
|
-
});
|
|
1655
|
-
await emitEvent(emit, {
|
|
1656
|
-
type: "message.update",
|
|
1657
|
-
message
|
|
1658
|
-
});
|
|
1659
|
-
}
|
|
1660
|
-
async function finalizeExecutedToolCall(config, currentContext, toolCall, runnable, message, emit, result, signal) {
|
|
1661
|
-
if (config.afterToolExecution) {
|
|
1662
|
-
const afterResult = await config.afterToolExecution({
|
|
1663
|
-
context: currentContext,
|
|
1664
|
-
assistantMessage: message,
|
|
1665
|
-
toolCall: runnable,
|
|
1666
|
-
result
|
|
1667
|
-
}, signal);
|
|
1668
|
-
if (afterResult) {
|
|
1669
|
-
await emitToolCallTerminalResult(toolCall, runnable, message, emit, afterResult);
|
|
1670
|
-
return;
|
|
1354
|
+
return {
|
|
1355
|
+
type: "image",
|
|
1356
|
+
source: {
|
|
1357
|
+
type: "base64",
|
|
1358
|
+
media_type: block.mimeType,
|
|
1359
|
+
data: block.data
|
|
1671
1360
|
}
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1361
|
+
};
|
|
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
|
|
1397
|
+
};
|
|
1674
1398
|
}
|
|
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
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
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;
|
|
1428
|
+
}
|
|
1429
|
+
if (sawToolCall) throw new Error("Assistant parts after a toolCall are not replayable for Anthropic");
|
|
1430
|
+
}
|
|
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
|
|
1716
1466
|
}
|
|
1717
|
-
|
|
1467
|
+
};
|
|
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;
|
|
1477
|
+
}
|
|
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
|
+
});
|
|
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
|
+
});
|
|
1522
|
+
}
|
|
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
|
+
}];
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
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");
|
|
1563
|
+
}
|
|
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 } : {}
|
|
1583
|
+
});
|
|
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",
|
|
1626
|
+
time: {
|
|
1627
|
+
created: Date.now(),
|
|
1628
|
+
completed: Date.now()
|
|
1629
|
+
}
|
|
1630
|
+
});
|
|
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;
|
|
1643
|
+
}
|
|
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
|
+
});
|
|
1724
|
+
}
|
|
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
|
|
1736
|
+
});
|
|
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;
|
|
1718
1757
|
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
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
|
|
1726
1768
|
});
|
|
1727
|
-
|
|
1728
|
-
type: "
|
|
1729
|
-
|
|
1769
|
+
else if (block.type === "thinking") stream.push({
|
|
1770
|
+
type: "thinking.end",
|
|
1771
|
+
partIndex,
|
|
1772
|
+
content: block.thinking,
|
|
1773
|
+
partial: output
|
|
1730
1774
|
});
|
|
1731
|
-
|
|
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
|
+
}
|
|
1732
1785
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
if (
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
await emitEvent(emit, {
|
|
1742
|
-
type: "turn.end",
|
|
1743
|
-
message
|
|
1744
|
-
});
|
|
1745
|
-
pendingMessages = await config.getSteeringMessages?.() || [];
|
|
1746
|
-
}
|
|
1747
|
-
const followUpMessages = await config.getFollowUpMessages?.() || [];
|
|
1748
|
-
if (followUpMessages.length > 0) {
|
|
1749
|
-
pendingMessages = followUpMessages;
|
|
1750
|
-
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);
|
|
1751
1794
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
async function runAgentLoop(config, context, prompts, emit, streamFn, signal) {
|
|
1760
|
-
/**
|
|
1761
|
-
* maintain 2 arrays to represent state, `context` the actual full state sent to the LLM,
|
|
1762
|
-
* `newMessages` for intermediate current loop state.
|
|
1763
|
-
* think of newMessages as subset of context.messages for the running current loop.
|
|
1764
|
-
* they do move at the same speed staring with initial user prompts.
|
|
1765
|
-
* */
|
|
1766
|
-
const newMessages = [...prompts];
|
|
1767
|
-
const currentContext = {
|
|
1768
|
-
...context,
|
|
1769
|
-
messages: [...context.messages, ...prompts]
|
|
1770
|
-
};
|
|
1771
|
-
await emitEvent(emit, { type: "agent.start" });
|
|
1772
|
-
await emitEvent(emit, { type: "turn.start" });
|
|
1773
|
-
for (const prompt of prompts) {
|
|
1774
|
-
await emitEvent(emit, {
|
|
1775
|
-
type: "message.start",
|
|
1776
|
-
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
|
|
1777
1802
|
});
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
partIndex,
|
|
1789
|
-
part
|
|
1790
|
-
});
|
|
1791
|
-
}
|
|
1792
|
-
await emitEvent(emit, {
|
|
1793
|
-
type: "message.end",
|
|
1794
|
-
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
|
|
1795
1813
|
});
|
|
1814
|
+
stream.end();
|
|
1796
1815
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
runAgentLoopContinue(config, context, async (event) => {
|
|
1825
|
-
stream.push(event);
|
|
1826
|
-
}, streamFn, signal).then((messages) => {
|
|
1827
|
-
stream.end(messages);
|
|
1828
|
-
});
|
|
1829
|
-
return stream;
|
|
1830
|
-
}
|
|
1831
|
-
_Loop.runContinue = runContinue;
|
|
1832
|
-
})(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);
|
|
1833
1843
|
//#endregion
|
|
1834
1844
|
//#region src/agent/agent.ts
|
|
1835
1845
|
let Agent;
|
|
@@ -2297,11 +2307,353 @@ let Agent;
|
|
|
2297
2307
|
_Agent.create = create;
|
|
2298
2308
|
})(Agent || (Agent = {}));
|
|
2299
2309
|
//#endregion
|
|
2300
|
-
//#region src/agent.ts
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
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()))
|
|
2319
|
+
});
|
|
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()))
|
|
2326
|
+
});
|
|
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 = {}));
|
|
2305
2657
|
//#endregion
|
|
2306
2658
|
//#region src/llm.ts
|
|
2307
2659
|
const llmImpl = async (provider, model) => Model.getModel(provider, model);
|
|
@@ -2337,6 +2689,6 @@ Stream.complete;
|
|
|
2337
2689
|
Stream.streamSimple;
|
|
2338
2690
|
Stream.completeSimple;
|
|
2339
2691
|
//#endregion
|
|
2340
|
-
export { Agent, Message, agent, llm, stream };
|
|
2692
|
+
export { Agent, CodeMode, Message, agent, llm, stream };
|
|
2341
2693
|
|
|
2342
2694
|
//# sourceMappingURL=index.mjs.map
|