@f5xc-salesdemos/xcsh 17.3.0 → 17.4.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/xcsh",
4
- "version": "17.3.0",
4
+ "version": "17.4.1",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5xc-salesdemos/xcsh",
7
7
  "author": "Can Boluk",
@@ -46,12 +46,12 @@
46
46
  "dependencies": {
47
47
  "@agentclientprotocol/sdk": "0.16.1",
48
48
  "@mozilla/readability": "^0.6",
49
- "@f5xc-salesdemos/xcsh-stats": "17.3.0",
50
- "@f5xc-salesdemos/pi-agent-core": "17.3.0",
51
- "@f5xc-salesdemos/pi-ai": "17.3.0",
52
- "@f5xc-salesdemos/pi-natives": "17.3.0",
53
- "@f5xc-salesdemos/pi-tui": "17.3.0",
54
- "@f5xc-salesdemos/pi-utils": "17.3.0",
49
+ "@f5xc-salesdemos/xcsh-stats": "17.4.1",
50
+ "@f5xc-salesdemos/pi-agent-core": "17.4.1",
51
+ "@f5xc-salesdemos/pi-ai": "17.4.1",
52
+ "@f5xc-salesdemos/pi-natives": "17.4.1",
53
+ "@f5xc-salesdemos/pi-tui": "17.4.1",
54
+ "@f5xc-salesdemos/pi-utils": "17.4.1",
55
55
  "@sinclair/typebox": "^0.34",
56
56
  "@xterm/headless": "^6.0",
57
57
  "ajv": "^8.18",
@@ -1313,6 +1313,15 @@ export const SETTINGS_SCHEMA = {
1313
1313
  default: true,
1314
1314
  ui: { tab: "tools", label: "Web Search", description: "Enable the web_search tool for web searching" },
1315
1315
  },
1316
+ "web_search.verbose": {
1317
+ type: "boolean",
1318
+ default: false,
1319
+ ui: {
1320
+ tab: "tools",
1321
+ label: "Web Search Verbose",
1322
+ description: "Show detailed search panels (sources, metadata, tokens). When disabled, uses compact output.",
1323
+ },
1324
+ },
1316
1325
 
1317
1326
  "browser.enabled": {
1318
1327
  type: "boolean",
@@ -192,6 +192,7 @@ async function executeSearch(
192
192
  for (const provider of providers) {
193
193
  lastProvider = provider;
194
194
  try {
195
+ const searchStart = performance.now();
195
196
  const response = await provider.search({
196
197
  query: params.query.replace(/202\d/g, String(new Date().getFullYear())), // LUL
197
198
  limit: params.limit,
@@ -205,6 +206,7 @@ async function executeSearch(
205
206
  maxUses: params.max_uses,
206
207
  userLocation: params.user_location,
207
208
  });
209
+ response.durationMs = performance.now() - searchStart;
208
210
 
209
211
  const text = formatForLLM(response);
210
212
 
@@ -290,7 +292,9 @@ export const webSearchCustomTool: CustomTool<typeof webSearchSchema, SearchRende
290
292
  renderResult(result, options: RenderResultOptions, theme: Theme) {
291
293
  return renderSearchResult(result, options, theme);
292
294
  },
293
- };
295
+
296
+ mergeCallAndResult: true as const,
297
+ } as CustomTool<typeof webSearchSchema, SearchRenderDetails> & { mergeCallAndResult: true };
294
298
 
295
299
  export function getSearchTools(): CustomTool<any, any>[] {
296
300
  return [webSearchCustomTool];
@@ -6,6 +6,7 @@
6
6
 
7
7
  import type { Component } from "@f5xc-salesdemos/pi-tui";
8
8
  import { Text, visibleWidth, wrapTextWithAnsi } from "@f5xc-salesdemos/pi-tui";
9
+ import { Settings } from "../../config/settings";
9
10
  import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
10
11
  import type { Theme } from "../../modes/theme/theme";
11
12
  import {
@@ -25,6 +26,14 @@ import { CachedOutputBlock } from "../../tui/output-block";
25
26
  import { getSearchProvider } from "./provider";
26
27
  import type { SearchResponse } from "./types";
27
28
 
29
+ function getVerboseSetting(): boolean {
30
+ try {
31
+ return Settings.instance.get("web_search.verbose");
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
36
+
28
37
  const MAX_COLLAPSED_ANSWER_LINES = PREVIEW_LIMITS.COLLAPSED_LINES;
29
38
  const MAX_EXPANDED_ANSWER_LINES = PREVIEW_LIMITS.EXPANDED_LINES;
30
39
  const MAX_ANSWER_LINE_LEN = TRUNCATE_LENGTHS.LINE;
@@ -92,13 +101,34 @@ export function renderSearchResult(
92
101
  return renderFallbackText(rawText, options.expanded, theme);
93
102
  }
94
103
 
104
+ const searchQueries = Array.isArray(response.searchQueries)
105
+ ? response.searchQueries.filter(item => typeof item === "string")
106
+ : [];
107
+
108
+ const verbose = getVerboseSetting();
109
+ if (!verbose) {
110
+ const searches = response.usage?.searchRequests ?? 1;
111
+ const plural = searches !== 1 ? "es" : "";
112
+ const dur =
113
+ response.durationMs !== undefined
114
+ ? response.durationMs >= 1000
115
+ ? `${Math.round(response.durationMs / 1000)}s`
116
+ : `${Math.round(response.durationMs)}ms`
117
+ : "";
118
+ const queryPreview = args?.query
119
+ ? truncateToWidth(args.query, 80)
120
+ : searchQueries[0]
121
+ ? truncateToWidth(searchQueries[0], 80)
122
+ : undefined;
123
+ const header = queryPreview ? `Web Search("${queryPreview}")` : "Web Search";
124
+ const summary = ` \u23BF Did ${searches} search${plural}${dur ? ` in ${dur}` : ""}`;
125
+ return new Text(`${theme.fg("text", header)}\n${theme.fg("dim", summary)}`, 0, 0);
126
+ }
127
+
95
128
  const sources = Array.isArray(response.sources) ? response.sources : [];
96
129
  const sourceCount = sources.length;
97
130
  const citations = Array.isArray(response.citations) ? response.citations : [];
98
131
  const citationCount = citations.length;
99
- const searchQueries = Array.isArray(response.searchQueries)
100
- ? response.searchQueries.filter(item => typeof item === "string")
101
- : [];
102
132
  const provider = response.provider;
103
133
 
104
134
  // Get answer text
@@ -288,6 +318,10 @@ export function renderSearchCall(
288
318
  theme: Theme,
289
319
  ): Component {
290
320
  const query = truncateToWidth(args.query ?? "", 80);
321
+ const verbose = getVerboseSetting();
322
+ if (!verbose) {
323
+ return new Text(`${theme.fg("text", `Web Search("${query}")`)}`, 0, 0);
324
+ }
291
325
  const text = renderStatusLine({ icon: "pending", title: "Web Search", description: query }, theme);
292
326
  return new Text(text, 0, 0);
293
327
  }
@@ -94,6 +94,8 @@ export interface SearchResponse {
94
94
  requestId?: string;
95
95
  /** Authentication mode used by the provider (e.g. oauth, api-key) */
96
96
  authMode?: string;
97
+ /** Wall-clock duration of the search request in milliseconds */
98
+ durationMs?: number;
97
99
  }
98
100
 
99
101
  /** Provider-specific error with optional HTTP status */