@absolutejs/ai 0.0.28 → 0.0.30

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/dist/ai/index.js CHANGED
@@ -3432,6 +3432,7 @@ var generateAIWithTools = async (options) => {
3432
3432
  };
3433
3433
  return runTurn(options.messages, maxTurns);
3434
3434
  };
3435
+ var DEFAULT_OBJECT_REPAIR_ATTEMPTS = 1;
3435
3436
  var generateObjectAI = async (options) => {
3436
3437
  const toolName = options.toolName ?? DEFAULT_OBJECT_TOOL_NAME;
3437
3438
  const tool = {
@@ -3439,26 +3440,218 @@ var generateObjectAI = async (options) => {
3439
3440
  input_schema: options.schema,
3440
3441
  name: toolName
3441
3442
  };
3442
- const { toolCalls, usage } = await generateAI({
3443
- cacheSystemPrompt: options.cacheSystemPrompt,
3444
- maxTokens: options.maxTokens,
3445
- messages: options.messages,
3446
- model: options.model,
3447
- promptCaching: options.promptCaching,
3448
- provider: options.provider,
3449
- reasoning: options.reasoning,
3450
- signal: options.signal,
3451
- systemPrompt: options.systemPrompt,
3452
- temperature: options.temperature,
3453
- toolChoice: { name: toolName },
3454
- tools: [tool]
3443
+ const maxRepairAttempts = Math.max(0, options.maxRepairAttempts ?? DEFAULT_OBJECT_REPAIR_ATTEMPTS);
3444
+ const messages = [...options.messages];
3445
+ let usage;
3446
+ let lastError;
3447
+ for (let attempt = 0;attempt <= maxRepairAttempts; attempt += 1) {
3448
+ const result = await generateAI({
3449
+ cacheSystemPrompt: options.cacheSystemPrompt,
3450
+ maxTokens: options.maxTokens,
3451
+ messages,
3452
+ model: options.model,
3453
+ promptCaching: options.promptCaching,
3454
+ provider: options.provider,
3455
+ reasoning: options.reasoning,
3456
+ signal: options.signal,
3457
+ systemPrompt: options.systemPrompt,
3458
+ temperature: options.temperature,
3459
+ toolChoice: { name: toolName },
3460
+ tools: [tool]
3461
+ });
3462
+ usage = mergeUsage(usage, result.usage);
3463
+ const call = result.toolCalls.find((toolCall) => toolCall.name === toolName);
3464
+ let failure;
3465
+ let object;
3466
+ if (!call) {
3467
+ lastError = new Error(`generateObjectAI: model did not call the "${toolName}" tool`);
3468
+ failure = `You did not call the "${toolName}" tool. Call it exactly once with the structured result.`;
3469
+ } else {
3470
+ try {
3471
+ object = options.validate ? options.validate(call.input) : call.input;
3472
+ } catch (error) {
3473
+ lastError = error;
3474
+ failure = `Your "${toolName}" output failed validation: ${error instanceof Error ? error.message : String(error)}. Call "${toolName}" again with corrected output that satisfies the schema.`;
3475
+ }
3476
+ }
3477
+ if (failure === undefined)
3478
+ return { object, usage };
3479
+ if (attempt >= maxRepairAttempts)
3480
+ break;
3481
+ if (call) {
3482
+ messages.push({
3483
+ content: [
3484
+ {
3485
+ id: call.id,
3486
+ input: call.input && typeof call.input === "object" ? call.input : {},
3487
+ name: toolName,
3488
+ type: "tool_use"
3489
+ }
3490
+ ],
3491
+ role: "assistant"
3492
+ }, {
3493
+ content: [
3494
+ { content: failure, tool_use_id: call.id, type: "tool_result" }
3495
+ ],
3496
+ role: "user"
3497
+ });
3498
+ } else {
3499
+ messages.push({ content: failure, role: "user" });
3500
+ }
3501
+ }
3502
+ throw lastError instanceof Error ? lastError : new Error(`generateObjectAI: failed to produce valid output`);
3503
+ };
3504
+
3505
+ // src/ai/streamAIWithTools.ts
3506
+ var DEFAULT_STREAM_TOOL_MAX_TURNS = 8;
3507
+ var toolCallKey = (call) => `${call.name}:${JSON.stringify(call.input)}`;
3508
+ var pushText = (blocks, content) => {
3509
+ const last = blocks[blocks.length - 1];
3510
+ if (last && last.type === "text") {
3511
+ last.content += content;
3512
+ return;
3513
+ }
3514
+ blocks.push({ content, type: "text" });
3515
+ };
3516
+ var flushThinking3 = (blocks, thinking) => {
3517
+ if (!thinking)
3518
+ return null;
3519
+ blocks.push({
3520
+ signature: thinking.signature || undefined,
3521
+ thinking: thinking.text,
3522
+ type: "thinking"
3455
3523
  });
3456
- const call = toolCalls.find((toolCall) => toolCall.name === toolName);
3457
- if (!call) {
3458
- throw new Error(`generateObjectAI: model did not call the "${toolName}" tool`);
3524
+ return null;
3525
+ };
3526
+ var executeToolHandler = async (tools, call) => {
3527
+ const definition = tools[call.name];
3528
+ if (!definition) {
3529
+ return { ok: false, result: `Error: unknown tool "${call.name}"` };
3530
+ }
3531
+ try {
3532
+ return { ok: true, result: await definition.handler(call.input) };
3533
+ } catch (err) {
3534
+ return {
3535
+ ok: false,
3536
+ result: `Error: ${err instanceof Error ? err.message : String(err)}`
3537
+ };
3459
3538
  }
3460
- const object = options.validate ? options.validate(call.input) : call.input;
3461
- return { object, usage };
3539
+ };
3540
+ var streamAIWithTools = async function* (options) {
3541
+ const {
3542
+ maxTurns = DEFAULT_STREAM_TOOL_MAX_TURNS,
3543
+ provider,
3544
+ toolChoice,
3545
+ tools,
3546
+ ...base
3547
+ } = options;
3548
+ const providerTools = toProviderTools(tools);
3549
+ const allToolCalls = [];
3550
+ const executedKeys = new Set;
3551
+ const messages = [...options.messages];
3552
+ let usage;
3553
+ let fullText = "";
3554
+ let turn = 0;
3555
+ const streamOneTurn = async function* () {
3556
+ const stream = provider.stream({
3557
+ cacheSystemPrompt: base.cacheSystemPrompt,
3558
+ maxTokens: base.maxTokens,
3559
+ messages,
3560
+ model: base.model,
3561
+ promptCaching: base.promptCaching,
3562
+ reasoning: base.reasoning,
3563
+ signal: base.signal,
3564
+ stopSequences: base.stopSequences,
3565
+ systemPrompt: base.systemPrompt,
3566
+ temperature: base.temperature,
3567
+ toolChoice: toolChoice ?? "auto",
3568
+ tools: providerTools,
3569
+ topP: base.topP
3570
+ });
3571
+ const blocks = [];
3572
+ const pending = [];
3573
+ let thinking = null;
3574
+ let turnUsage;
3575
+ for await (const chunk of stream) {
3576
+ if (base.signal?.aborted)
3577
+ break;
3578
+ if (chunk.type === "thinking") {
3579
+ if (chunk.content)
3580
+ yield { content: chunk.content, type: "thinking" };
3581
+ thinking = thinking ?? { signature: "", text: "" };
3582
+ thinking.text += chunk.content;
3583
+ if (chunk.signature)
3584
+ thinking.signature = chunk.signature;
3585
+ } else if (chunk.type === "text") {
3586
+ thinking = flushThinking3(blocks, thinking);
3587
+ fullText += chunk.content;
3588
+ pushText(blocks, chunk.content);
3589
+ yield { content: chunk.content, type: "text" };
3590
+ } else if (chunk.type === "tool_use") {
3591
+ thinking = flushThinking3(blocks, thinking);
3592
+ pending.push({ id: chunk.id, input: chunk.input, name: chunk.name });
3593
+ blocks.push({
3594
+ id: chunk.id,
3595
+ input: chunk.input && typeof chunk.input === "object" ? chunk.input : {},
3596
+ name: chunk.name,
3597
+ type: "tool_use"
3598
+ });
3599
+ } else if (chunk.type === "done") {
3600
+ thinking = flushThinking3(blocks, thinking);
3601
+ turnUsage = chunk.usage;
3602
+ }
3603
+ }
3604
+ thinking = flushThinking3(blocks, thinking);
3605
+ return { blocks, pending, usage: turnUsage };
3606
+ };
3607
+ while (turn < maxTurns) {
3608
+ turn += 1;
3609
+ const outcome = yield* streamOneTurn();
3610
+ usage = mergeUsage(usage, outcome.usage);
3611
+ yield { type: "turn", usage: outcome.usage };
3612
+ const { blocks, pending } = outcome;
3613
+ allToolCalls.push(...pending);
3614
+ const allRepeats = pending.length > 0 && pending.every((call) => executedKeys.has(toolCallKey(call)));
3615
+ const finished = pending.length === 0 || turn >= maxTurns || allRepeats || base.signal?.aborted === true;
3616
+ if (finished)
3617
+ break;
3618
+ messages.push({ content: blocks, role: "assistant" });
3619
+ const resultBlocks = [];
3620
+ for (const call of pending) {
3621
+ yield {
3622
+ id: call.id,
3623
+ input: call.input,
3624
+ name: call.name,
3625
+ type: "tool_start"
3626
+ };
3627
+ const startedAt = Date.now();
3628
+ const { ok, result } = await executeToolHandler(tools, call);
3629
+ executedKeys.add(toolCallKey(call));
3630
+ yield {
3631
+ id: call.id,
3632
+ input: call.input,
3633
+ ms: Date.now() - startedAt,
3634
+ name: call.name,
3635
+ ok,
3636
+ result,
3637
+ type: "tool_result"
3638
+ };
3639
+ resultBlocks.push({
3640
+ content: result,
3641
+ tool_use_id: call.id,
3642
+ type: "tool_result"
3643
+ });
3644
+ }
3645
+ messages.push({ content: resultBlocks, role: "user" });
3646
+ }
3647
+ const summary = {
3648
+ text: fullText,
3649
+ toolCalls: allToolCalls,
3650
+ turns: turn,
3651
+ usage
3652
+ };
3653
+ yield { ...summary, type: "done" };
3654
+ return summary;
3462
3655
  };
3463
3656
  // src/ai/conversationManager.ts
3464
3657
  var NOT_FOUND3 = -1;
@@ -4381,6 +4574,7 @@ var startProviderStatusMonitor = (options) => {
4381
4574
  export {
4382
4575
  xai,
4383
4576
  withResilience,
4577
+ streamAIWithTools,
4384
4578
  streamAIToSSE,
4385
4579
  streamAI,
4386
4580
  startProviderStatusMonitor,
@@ -4420,5 +4614,5 @@ export {
4420
4614
  PROVIDER_STATUS_PAGES
4421
4615
  };
4422
4616
 
4423
- //# debugId=CE76A2131808230464756E2164756E21
4617
+ //# debugId=488D46E6DE9AC4E164756E2164756E21
4424
4618
  //# sourceMappingURL=index.js.map