@f5-sales-demo/pi-agent-core 20.2.7 → 20.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/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
+ <!-- markdownlint-configure-file { "MD024": { "siblings_only": true } } -->
2
+
1
3
  # Changelog
2
4
 
3
- ## [Unreleased]
5
+ ## [20.3.0] - 2026-08-04
6
+
7
+ ### Fixed
8
+
9
+ - Fixed successful tools with empty output being indistinguishable from missing results to the model ([#2874](https://github.com/f5-sales-demo/xcsh/issues/2874))
4
10
 
5
11
  ## [14.0.1] - 2026-04-08
6
12
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/pi-agent-core",
4
- "version": "20.2.7",
4
+ "version": "20.3.0",
5
5
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
6
6
  "homepage": "https://github.com/f5-sales-demo/xcsh",
7
7
  "author": "Can Boluk",
@@ -35,8 +35,8 @@
35
35
  "fmt": "biome format --write ."
36
36
  },
37
37
  "dependencies": {
38
- "@f5-sales-demo/pi-ai": "20.2.7",
39
- "@f5-sales-demo/pi-utils": "20.2.7"
38
+ "@f5-sales-demo/pi-ai": "20.3.0",
39
+ "@f5-sales-demo/pi-utils": "20.3.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@sinclair/typebox": "^0.34",
package/src/agent-loop.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  validateToolArguments,
12
12
  } from "@f5-sales-demo/pi-ai";
13
13
  import { logger } from "@f5-sales-demo/pi-utils";
14
+ import emptyToolSuccess from "./prompts/empty-tool-success.md" with { type: "text" };
14
15
  import type {
15
16
  AgentContext,
16
17
  AgentEvent,
@@ -500,6 +501,7 @@ async function executeToolCalls(
500
501
 
501
502
  const emitToolResult = (record: (typeof records)[number], result: AgentToolResult<any>, isError: boolean): void => {
502
503
  if (record.resultEmitted) return;
504
+ const normalizedResult = normalizeToolResult(result, isError);
503
505
  const { toolCall } = record;
504
506
  if (!record.started) {
505
507
  stream.push({
@@ -510,12 +512,12 @@ async function executeToolCalls(
510
512
  intent: toolCall.intent,
511
513
  });
512
514
  }
513
- const isWarning = Boolean(result.isWarning);
515
+ const isWarning = Boolean(normalizedResult.isWarning);
514
516
  stream.push({
515
517
  type: "tool_execution_end",
516
518
  toolCallId: toolCall.id,
517
519
  toolName: toolCall.name,
518
- result,
520
+ result: normalizedResult,
519
521
  isError,
520
522
  isWarning,
521
523
  });
@@ -524,13 +526,13 @@ async function executeToolCalls(
524
526
  role: "toolResult",
525
527
  toolCallId: toolCall.id,
526
528
  toolName: toolCall.name,
527
- content: result.content,
528
- details: result.details,
529
+ content: normalizedResult.content,
530
+ details: normalizedResult.details,
529
531
  isError,
530
532
  isWarning,
531
533
  timestamp: Date.now(),
532
534
  };
533
- record.result = result;
535
+ record.result = normalizedResult;
534
536
  record.isError = isError;
535
537
  record.toolResultMessage = toolResultMessage;
536
538
  record.resultEmitted = true;
@@ -705,3 +707,14 @@ function createSkippedToolResult(): AgentToolResult<any> {
705
707
  details: {},
706
708
  };
707
709
  }
710
+
711
+ function normalizeToolResult<T>(result: AgentToolResult<T>, isError: boolean): AgentToolResult<T> {
712
+ if (isError || result.content.some(content => content.type !== "text" || content.text.trim().length > 0)) {
713
+ return result;
714
+ }
715
+
716
+ return {
717
+ ...result,
718
+ content: [{ type: "text", text: emptyToolSuccess.trim() }],
719
+ };
720
+ }
@@ -0,0 +1 @@
1
+ Tool completed successfully and produced no output.