@caupulican/pi-agent-core 0.93.18 → 0.94.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.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAgC7D,OAAO,EAAE,uBAAuB,EAAsC,MAAM,iCAAiC,CAAC;AAE9G,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,YAAY,EAEZ,aAAa,EAGb,QAAQ,EACR,kBAAkB,EAClB,MAAM,YAAY,CAAC;AAIpB,OAAO,EACN,0BAA0B,EAC1B,sBAAsB,EACtB,gCAAgC,GAChC,MAAM,+BAA+B,CAAC;AAEvC,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAKzE,gGAAgG;AAChG,MAAM,WAAW,0BAA0B;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uBAAuB,EAAE,uBAAuB,CAAC;CACjD;AAED,wBAAgB,gCAAgC,IAAI,0BAA0B,CAE7E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAIzC;AAuBD,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,EACnB,iBAAiB,GAAE,0BAA+D,GAChF,OAAO,CAAC,YAAY,EAAE,CAAC,CAwBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,EACnB,iBAAiB,GAAE,0BAA+D,GAChF,OAAO,CAAC,YAAY,EAAE,CAAC,CAezB;AAmWD;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAExC;AA6iCD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,kBAAkB,GAAG,SAAS,CAO7F"}
1
+ {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAmC7D,OAAO,EAAE,uBAAuB,EAAsC,MAAM,iCAAiC,CAAC;AAE9G,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,YAAY,EAGZ,aAAa,EAGb,QAAQ,EACR,kBAAkB,EAElB,MAAM,YAAY,CAAC;AAIpB,OAAO,EACN,0BAA0B,EAC1B,sBAAsB,EACtB,gCAAgC,GAChC,MAAM,+BAA+B,CAAC;AAEvC,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAKzE,gGAAgG;AAChG,MAAM,WAAW,0BAA0B;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uBAAuB,EAAE,uBAAuB,CAAC;CACjD;AAED,wBAAgB,gCAAgC,IAAI,0BAA0B,CAE7E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAIzC;AAuBD,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,EACnB,iBAAiB,GAAE,0BAA+D,GAChF,OAAO,CAAC,YAAY,EAAE,CAAC,CAwBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,EACnB,iBAAiB,GAAE,0BAA+D,GAChF,OAAO,CAAC,YAAY,EAAE,CAAC,CAezB;AAsWD;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAExC;AA6lCD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,kBAAkB,GAAG,SAAS,CAO7F"}
@@ -6,7 +6,7 @@ import { EventStream } from "@caupulican/pi-ai/event-stream";
6
6
  import { formatToolRepairStandingRule, REPEATED_SUCCESSFUL_TOOL_CALL_FAILURE, } from "@caupulican/pi-ai/tool-repair-registry";
7
7
  import { ToolArgumentValidationError, validateToolArguments, } from "@caupulican/pi-ai/validation";
8
8
  import { assistantMessageText, collapseDegenerateAssistantMessage, shouldAbortDegenerateStream, } from "./degenerate-assistant-text.js";
9
- import { startPlannedAgentProviderRequest } from "./provider-request-planner.js";
9
+ import { startPlannedAgentProviderRequest, startPlannedAgentProviderRequestWithId, } from "./provider-request-planner.js";
10
10
  import { assessToolFailure, clearToolFailure, createRepeatedToolFailureResult, createToolFailureMemoryTracker, createToolFailureResult, describeOperationOutcome, getUnresolvedToolFailure, normalizeToolSignature, rememberToolFailure, toolFailureCorrection, } from "./tool-failure-memory.js";
11
11
  import { ToolFailureRecoveryGate } from "./tool-failure-recovery-gate.js";
12
12
  import { rejectNativeToolProtocolResidue, rejectToolCallsFromToolFreeResponse } from "./tool-protocol-residue.js";
@@ -239,7 +239,8 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
239
239
  // Process pending messages (inject before next assistant response).
240
240
  await processPendingMessages();
241
241
  continuationState.providerTurns++;
242
- const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFn);
242
+ const response = await streamAssistantResponse(currentContext, config, signal, emit, streamFn);
243
+ const message = response.message;
243
244
  newMessages.push(message);
244
245
  if (message.stopReason === "error" || message.stopReason === "aborted") {
245
246
  await emit({ type: "turn_end", message, toolResults: [] });
@@ -257,7 +258,7 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
257
258
  repeatsSuccessfulTextProtocolBatch(incomingBatchSignature, toolCalls, lastSuccessfulTextProtocolBatch)
258
259
  ? lastSuccessfulTextProtocolBatch?.messages
259
260
  : undefined;
260
- const executedToolBatch = await executeToolCalls(currentContext, message, config, validationFailureTracker, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, previousSuccessfulTextProtocolResults, signal, emit);
261
+ const executedToolBatch = await executeToolCalls(currentContext, message, response.requestId, config, validationFailureTracker, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, previousSuccessfulTextProtocolResults, signal, emit);
261
262
  toolResults.push(...executedToolBatch.messages);
262
263
  hasMoreToolCalls = !executedToolBatch.terminate;
263
264
  for (const result of toolResults) {
@@ -365,9 +366,10 @@ async function streamToollessClosingTurn(currentContext, newMessages, config, co
365
366
  : RUNAWAY_STOP_CLOSING_SYSTEM_PROMPT,
366
367
  tools: [],
367
368
  };
368
- const message = await streamAssistantResponse(closingContext, config, signal, emit, streamFn, {
369
+ const response = await streamAssistantResponse(closingContext, config, signal, emit, streamFn, {
369
370
  rejectToolCalls: true,
370
371
  });
372
+ const message = response.message;
371
373
  newMessages.push(message);
372
374
  await emit({ type: "turn_end", message, toolResults: [] });
373
375
  }
@@ -392,11 +394,11 @@ async function streamAssistantResponse(context, config, signal, emit, streamFn,
392
394
  degenerationAbort.abort();
393
395
  else
394
396
  signal?.addEventListener("abort", onOuterAbort, { once: true });
395
- const response = await startAgentProviderRequest(context, config, degenerationAbort.signal, streamFn);
397
+ const response = await startPlannedAgentProviderRequestWithId(context, config, degenerationAbort.signal, streamFn);
396
398
  let partialMessage = null;
397
399
  let addedPartial = false;
398
400
  let abortedForDegeneration = false;
399
- responseEvents: for await (const event of response) {
401
+ responseEvents: for await (const event of response.stream) {
400
402
  switch (event.type) {
401
403
  case "start":
402
404
  partialMessage = event.partial;
@@ -436,7 +438,7 @@ async function streamAssistantResponse(context, config, signal, emit, streamFn,
436
438
  }
437
439
  }
438
440
  signal?.removeEventListener("abort", onOuterAbort);
439
- const providerMessage = await response.result();
441
+ const providerMessage = await response.stream.result();
440
442
  let finalMessage = policy?.rejectToolCalls
441
443
  ? rejectToolCallsFromToolFreeResponse(providerMessage)
442
444
  : rejectNativeToolProtocolResidue(providerMessage, context.tools ?? [], Boolean(config.textToolCallProtocol));
@@ -453,17 +455,18 @@ async function streamAssistantResponse(context, config, signal, emit, streamFn,
453
455
  await emit({ type: "message_start", message: { ...finalMessage } });
454
456
  }
455
457
  await emit({ type: "message_end", message: finalMessage });
456
- return finalMessage;
458
+ return { message: finalMessage, requestId: response.requestId };
457
459
  }
458
460
  /**
459
461
  * Execute tool calls from an assistant message.
460
462
  */
461
- async function executeToolCalls(currentContext, assistantMessage, config, validationFailureTracker, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, previousSuccessfulTextProtocolResults, signal, emit) {
463
+ async function executeToolCalls(currentContext, assistantMessage, requestId, config, validationFailureTracker, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, previousSuccessfulTextProtocolResults, signal, emit) {
462
464
  const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
463
465
  const hasSequentialToolCall = toolCalls.some((tc) => currentContext.tools?.find((t) => t.name === tc.name)?.executionMode === "sequential");
464
466
  const execCtx = {
465
467
  context: currentContext,
466
468
  assistantMessage,
469
+ requestId,
467
470
  config,
468
471
  validationFailureTracker,
469
472
  repairTeachTracker,
@@ -481,9 +484,9 @@ async function executeToolCalls(currentContext, assistantMessage, config, valida
481
484
  async function prepareAndStartToolCall(execCtx, toolCall, index) {
482
485
  const preparation = execCtx.previousSuccessfulResults
483
486
  ? createRepeatedSuccessfulToolCallOutcome(execCtx.previousSuccessfulResults[index])
484
- : await prepareToolCall(execCtx.context, execCtx.assistantMessage, toolCall, execCtx.config, execCtx.validationFailureTracker, execCtx.toolFailureMemory, execCtx.toolFailureRecoveryGate, execCtx.signal);
485
- await emitToolExecutionStart(toolCall, execCtx.emit);
487
+ : await prepareToolCall(execCtx.context, execCtx.assistantMessage, toolCall, execCtx.config, execCtx.validationFailureTracker, execCtx.toolFailureMemory, execCtx.toolFailureRecoveryGate, execCtx.signal, execCtx.requestId);
486
488
  if (preparation.kind === "immediate") {
489
+ await emitToolExecutionStart(toolCall, execCtx.emit);
487
490
  emitToolArgumentValidationTelemetry(execCtx.config, preparation.validationEvent, "not_run", "none");
488
491
  return {
489
492
  kind: "finalized",
@@ -495,13 +498,37 @@ async function prepareAndStartToolCall(execCtx, toolCall, index) {
495
498
  async function finalizeStartedToolCall(execCtx, started) {
496
499
  if (started.kind === "finalized")
497
500
  return started.finalized;
498
- return executeAndFinalizePreparedToolCall(execCtx.context, execCtx.assistantMessage, started.preparation, execCtx.config, execCtx.repairTeachTracker, execCtx.toolFailureMemory, execCtx.toolFailureRecoveryGate, execCtx.signal, execCtx.emit);
501
+ return executeAndFinalizePreparedToolCall(execCtx.context, execCtx.assistantMessage, started.preparation, execCtx.requestId, execCtx.config, execCtx.repairTeachTracker, execCtx.toolFailureMemory, execCtx.toolFailureRecoveryGate, execCtx.signal, execCtx.emit);
502
+ }
503
+ async function reservePreparedToolCalls(execCtx, preparedCalls) {
504
+ if (preparedCalls.length === 0)
505
+ return;
506
+ execCtx.signal?.throwIfAborted();
507
+ if (execCtx.config.onToolCallStart) {
508
+ const calls = preparedCalls.map((prepared) => ({
509
+ requestId: execCtx.requestId,
510
+ callId: prepared.toolCall.id,
511
+ toolName: prepared.toolCall.name,
512
+ assistantMessage: execCtx.assistantMessage,
513
+ toolCall: prepared.toolCall,
514
+ args: prepared.args,
515
+ context: execCtx.context,
516
+ }));
517
+ await execCtx.config.onToolCallStart(calls, execCtx.signal);
518
+ }
519
+ execCtx.signal?.throwIfAborted();
520
+ for (const prepared of preparedCalls) {
521
+ await emitToolExecutionStart(prepared.toolCall, execCtx.emit);
522
+ }
499
523
  }
500
524
  async function executeToolCallsSequential(execCtx, toolCalls) {
501
525
  const finalizedCalls = [];
502
526
  const messages = [];
503
527
  for (const [index, toolCall] of toolCalls.entries()) {
504
528
  const started = await prepareAndStartToolCall(execCtx, toolCall, index);
529
+ if (started.kind === "prepared") {
530
+ await reservePreparedToolCalls(execCtx, [started.preparation]);
531
+ }
505
532
  const finalized = await finalizeStartedToolCall(execCtx, started);
506
533
  execCtx.toolFailureRecoveryGate.apply(finalized.executionGateEffect);
507
534
  await emitToolExecutionEnd(finalized, execCtx.emit);
@@ -523,6 +550,7 @@ async function executeToolCallsParallel(execCtx, toolCalls) {
523
550
  while (nextIndex < toolCalls.length && !execCtx.signal?.aborted) {
524
551
  const waveEnd = Math.min(nextIndex + TOOL_EXECUTION_WAVE_SIZE, toolCalls.length);
525
552
  const wave = [];
553
+ const preparedWave = [];
526
554
  const completionOrder = [];
527
555
  for (; nextIndex < waveEnd; nextIndex++) {
528
556
  const toolCall = toolCalls[nextIndex];
@@ -532,6 +560,7 @@ async function executeToolCallsParallel(execCtx, toolCalls) {
532
560
  wave.push(started.finalized);
533
561
  }
534
562
  else {
563
+ preparedWave.push(started.preparation);
535
564
  wave.push(async () => {
536
565
  const finalized = await finalizeStartedToolCall(execCtx, started);
537
566
  completionOrder.push(finalized);
@@ -543,6 +572,7 @@ async function executeToolCallsParallel(execCtx, toolCalls) {
543
572
  break;
544
573
  }
545
574
  }
575
+ await reservePreparedToolCalls(execCtx, preparedWave);
546
576
  const finalizedWave = await Promise.all(wave.map((entry) => (typeof entry === "function" ? entry() : Promise.resolve(entry))));
547
577
  for (const finalized of finalizedWave)
548
578
  execCtx.toolFailureRecoveryGate.apply(finalized.executionGateEffect);
@@ -687,7 +717,7 @@ function handleValidationFailure(error, config, tracker) {
687
717
  });
688
718
  return `${error.message}\n\nRepeated validation failure (${tracker.repeats} identical attempts). Use this full schema and example before retrying:\n${error.enrichment}`;
689
719
  }
690
- async function prepareToolCall(currentContext, assistantMessage, toolCall, config, validationFailureTracker, toolFailureMemory, toolFailureRecoveryGate, signal) {
720
+ async function prepareToolCall(currentContext, assistantMessage, toolCall, config, validationFailureTracker, toolFailureMemory, toolFailureRecoveryGate, signal, requestId) {
691
721
  const tool = currentContext.tools?.find((candidate) => candidate.name === toolCall.name);
692
722
  if (!tool) {
693
723
  return {
@@ -750,6 +780,7 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
750
780
  }
751
781
  if (config.beforeToolCall) {
752
782
  const beforeResult = await config.beforeToolCall({
783
+ requestId,
753
784
  assistantMessage,
754
785
  toolCall,
755
786
  args: validatedArgs,
@@ -866,12 +897,12 @@ function getBackgroundToolCallDelay(config) {
866
897
  return undefined;
867
898
  return delay;
868
899
  }
869
- async function executeAndFinalizePreparedToolCall(currentContext, assistantMessage, prepared, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, foregroundSignal, emit) {
900
+ async function executeAndFinalizePreparedToolCall(currentContext, assistantMessage, prepared, requestId, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, foregroundSignal, emit) {
870
901
  const backgroundDelay = getBackgroundToolCallDelay(config);
871
902
  if (!config.handoffToolCall ||
872
903
  (backgroundDelay === undefined && config.subscribeToolCallHandoffRequest === undefined)) {
873
904
  const executed = await executePreparedToolCall(prepared, foregroundSignal, emit);
874
- return finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, foregroundSignal);
905
+ return finalizeExecutedToolCall(currentContext, assistantMessage, prepared, requestId, executed, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, foregroundSignal);
875
906
  }
876
907
  const executionAbort = createLinkedToolAbort(foregroundSignal);
877
908
  const startedAt = Date.now();
@@ -881,7 +912,7 @@ async function executeAndFinalizePreparedToolCall(currentContext, assistantMessa
881
912
  if (emitForegroundUpdates)
882
913
  return emit(event);
883
914
  });
884
- const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, executionAbort.signal);
915
+ const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, prepared, requestId, executed, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, executionAbort.signal);
885
916
  return finalized;
886
917
  })();
887
918
  completion.then(executionAbort.detachForeground, executionAbort.detachForeground);
@@ -930,6 +961,7 @@ async function executeAndFinalizePreparedToolCall(currentContext, assistantMessa
930
961
  let handoff;
931
962
  try {
932
963
  handoff = config.handoffToolCall({
964
+ requestId,
933
965
  assistantMessage,
934
966
  toolCall: prepared.toolCall,
935
967
  args: prepared.args,
@@ -1015,7 +1047,7 @@ function appendRepairTeachNotes(result, toolCall, tracker, config) {
1015
1047
  taught: true,
1016
1048
  };
1017
1049
  }
1018
- async function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, signal) {
1050
+ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, requestId, executed, config, repairTeachTracker, toolFailureMemory, toolFailureRecoveryGate, signal) {
1019
1051
  let result = executed.result;
1020
1052
  let isError = executed.isError;
1021
1053
  let failureMessage = executed.failureMessage ?? "";
@@ -1027,6 +1059,7 @@ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepar
1027
1059
  if (config.afterToolCall) {
1028
1060
  try {
1029
1061
  const afterResult = await config.afterToolCall({
1062
+ requestId,
1030
1063
  assistantMessage,
1031
1064
  toolCall: prepared.toolCall,
1032
1065
  args: prepared.args,