@f5xc-salesdemos/xcsh 17.1.4 → 17.2.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/xcsh",
4
- "version": "17.1.4",
4
+ "version": "17.2.0",
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.1.4",
50
- "@f5xc-salesdemos/pi-agent-core": "17.1.4",
51
- "@f5xc-salesdemos/pi-ai": "17.1.4",
52
- "@f5xc-salesdemos/pi-natives": "17.1.4",
53
- "@f5xc-salesdemos/pi-tui": "17.1.4",
54
- "@f5xc-salesdemos/pi-utils": "17.1.4",
49
+ "@f5xc-salesdemos/xcsh-stats": "17.2.0",
50
+ "@f5xc-salesdemos/pi-agent-core": "17.2.0",
51
+ "@f5xc-salesdemos/pi-ai": "17.2.0",
52
+ "@f5xc-salesdemos/pi-natives": "17.2.0",
53
+ "@f5xc-salesdemos/pi-tui": "17.2.0",
54
+ "@f5xc-salesdemos/pi-utils": "17.2.0",
55
55
  "@sinclair/typebox": "^0.34",
56
56
  "@xterm/headless": "^6.0",
57
57
  "ajv": "^8.18",
@@ -114,7 +114,7 @@ happens under load, in a degraded state, or with an adversarial payload?"
114
114
 
115
115
  <stakes>
116
116
  The operator works in live infrastructure. Routing changes, firewall rules, TLS configurations,
117
- API deployments, traffic policies... Misconfigurations → outages, security exposures, or
117
+ API deployments, traffic policies Misconfigurations → outages, security exposures, or
118
118
  systems that fail under adversarial conditions.
119
119
  - You **MUST NOT** yield incomplete or unvalidated configurations.
120
120
  - You **MUST** only recommend operations and configurations you can defend.
@@ -322,7 +322,6 @@ These are inviolable. Violation is system failure.
322
322
 
323
323
  Configuration integrity means infrastructure tells the truth about what is actually deployed.
324
324
  Every stale config left in IaC without a corresponding live object is a lie to the next operator.
325
-
326
325
  - **The unit of change is the infrastructure decision, not the ticket.** When topology changes,
327
326
  every dependent config, policy reference, and IaC file changes in the same commit. Work is
328
327
  complete when the configuration is coherent, not when the API accepts it.
@@ -38,6 +38,21 @@ export const webSearchSchema = Type.Object({
38
38
  max_tokens: Type.Optional(Type.Number({ description: "Maximum output tokens" })),
39
39
  temperature: Type.Optional(Type.Number({ description: "Sampling temperature" })),
40
40
  num_search_results: Type.Optional(Type.Number({ description: "Number of search results to retrieve" })),
41
+ allowed_domains: Type.Optional(Type.Array(Type.String(), { description: "Only return results from these domains" })),
42
+ blocked_domains: Type.Optional(Type.Array(Type.String(), { description: "Exclude results from these domains" })),
43
+ max_uses: Type.Optional(Type.Number({ description: "Maximum number of web searches per request" })),
44
+ user_location: Type.Optional(
45
+ Type.Object(
46
+ {
47
+ type: Type.Literal("approximate"),
48
+ city: Type.Optional(Type.String()),
49
+ region: Type.Optional(Type.String()),
50
+ country: Type.Optional(Type.String()),
51
+ timezone: Type.Optional(Type.String()),
52
+ },
53
+ { description: "Approximate user location for localized results" },
54
+ ),
55
+ ),
41
56
  });
42
57
 
43
58
  export type SearchToolParams = {
@@ -50,6 +65,16 @@ export type SearchToolParams = {
50
65
  temperature?: number;
51
66
  /** Number of search results to retrieve. Defaults to 10. */
52
67
  num_search_results?: number;
68
+ allowed_domains?: string[];
69
+ blocked_domains?: string[];
70
+ max_uses?: number;
71
+ user_location?: {
72
+ type: "approximate";
73
+ city?: string;
74
+ region?: string;
75
+ country?: string;
76
+ timezone?: string;
77
+ };
53
78
  };
54
79
 
55
80
  export interface SearchQueryParams extends SearchToolParams {
@@ -143,10 +168,13 @@ async function executeSearch(
143
168
  _toolCallId: string,
144
169
  params: SearchQueryParams,
145
170
  ): Promise<{ content: Array<{ type: "text"; text: string }>; details: SearchRenderDetails }> {
171
+ const hasDomainFilter = params.allowed_domains?.length || params.blocked_domains?.length;
172
+ const effectiveProvider =
173
+ hasDomainFilter && (!params.provider || params.provider === "auto") ? "anthropic" : params.provider;
146
174
  const providers =
147
- params.provider && params.provider !== "auto"
148
- ? (await getSearchProvider(params.provider).isAvailable())
149
- ? [getSearchProvider(params.provider)]
175
+ effectiveProvider && effectiveProvider !== "auto"
176
+ ? (await getSearchProvider(effectiveProvider).isAvailable())
177
+ ? [getSearchProvider(effectiveProvider)]
150
178
  : await resolveProviderChain("auto")
151
179
  : await resolveProviderChain();
152
180
  if (providers.length === 0) {
@@ -171,6 +199,10 @@ async function executeSearch(
171
199
  maxOutputTokens: params.max_tokens,
172
200
  numSearchResults: params.num_search_results,
173
201
  temperature: params.temperature,
202
+ allowedDomains: params.allowed_domains,
203
+ blockedDomains: params.blocked_domains,
204
+ maxUses: params.max_uses,
205
+ userLocation: params.user_location,
174
206
  });
175
207
 
176
208
  const text = formatForLLM(response);
@@ -30,6 +30,14 @@ const DEFAULT_MAX_TOKENS = 4096;
30
30
  const WEB_SEARCH_TOOL_NAME = "web_search";
31
31
  const WEB_SEARCH_TOOL_TYPE = "web_search_20250305";
32
32
 
33
+ export interface AnthropicUserLocation {
34
+ type: "approximate";
35
+ city?: string;
36
+ region?: string;
37
+ country?: string;
38
+ timezone?: string;
39
+ }
40
+
33
41
  export interface AnthropicSearchParams {
34
42
  query: string;
35
43
  system_prompt?: string;
@@ -38,6 +46,31 @@ export interface AnthropicSearchParams {
38
46
  max_tokens?: number;
39
47
  /** Sampling temperature (0–1). Lower = more focused/factual. */
40
48
  temperature?: number;
49
+ allowed_domains?: string[];
50
+ blocked_domains?: string[];
51
+ max_uses?: number;
52
+ user_location?: AnthropicUserLocation;
53
+ }
54
+
55
+ interface WebSearchToolConfig {
56
+ allowed_domains?: string[];
57
+ blocked_domains?: string[];
58
+ max_uses?: number;
59
+ user_location?: AnthropicUserLocation;
60
+ }
61
+
62
+ export function extractSiteOperators(query: string): { cleanQuery: string; domains: string[] } {
63
+ const sitePattern = /\bsite:(\S+)/gi;
64
+ const domains: string[] = [];
65
+ const cleanQuery = query
66
+ .replace(sitePattern, (_, domain) => {
67
+ domains.push(domain);
68
+ return "";
69
+ })
70
+ .replace(/\s{2,}/g, " ")
71
+ .trim();
72
+ const fallback = domains.length > 0 ? domains.join(" ") : query;
73
+ return { cleanQuery: cleanQuery || fallback, domains };
41
74
  }
42
75
 
43
76
  /**
@@ -86,22 +119,27 @@ async function callSearch(
86
119
  systemPrompt?: string,
87
120
  maxTokens?: number,
88
121
  temperature?: number,
122
+ toolConfig?: WebSearchToolConfig,
89
123
  ): Promise<AnthropicApiResponse> {
90
124
  const url = buildAnthropicUrl(auth);
91
125
  const headers = buildAnthropicSearchHeaders(auth);
92
126
 
93
127
  const systemBlocks = buildSystemBlocks(auth, model, systemPrompt);
94
128
 
129
+ const tool: Record<string, unknown> = {
130
+ type: WEB_SEARCH_TOOL_TYPE,
131
+ name: WEB_SEARCH_TOOL_NAME,
132
+ };
133
+ if (toolConfig?.allowed_domains?.length) tool.allowed_domains = toolConfig.allowed_domains;
134
+ if (toolConfig?.blocked_domains?.length) tool.blocked_domains = toolConfig.blocked_domains;
135
+ if (toolConfig?.max_uses) tool.max_uses = toolConfig.max_uses;
136
+ if (toolConfig?.user_location) tool.user_location = toolConfig.user_location;
137
+
95
138
  const body: Record<string, unknown> = {
96
139
  model,
97
140
  max_tokens: maxTokens ?? DEFAULT_MAX_TOKENS,
98
141
  messages: [{ role: "user", content: query }],
99
- tools: [
100
- {
101
- type: WEB_SEARCH_TOOL_TYPE,
102
- name: WEB_SEARCH_TOOL_NAME,
103
- },
104
- ],
142
+ tools: [tool],
105
143
  };
106
144
 
107
145
  if (temperature !== undefined) {
@@ -246,13 +284,23 @@ export async function searchAnthropic(params: AnthropicSearchParams): Promise<Se
246
284
  }
247
285
 
248
286
  const model = getModel();
287
+
288
+ const { cleanQuery, domains: siteDomains } = extractSiteOperators(params.query);
289
+ const allAllowedDomains = [...(params.allowed_domains ?? []), ...siteDomains];
290
+
249
291
  const response = await callSearch(
250
292
  auth,
251
293
  model,
252
- params.query,
294
+ cleanQuery,
253
295
  params.system_prompt,
254
296
  params.max_tokens,
255
297
  params.temperature,
298
+ {
299
+ allowed_domains: allAllowedDomains.length > 0 ? allAllowedDomains : undefined,
300
+ blocked_domains: params.blocked_domains,
301
+ max_uses: params.max_uses,
302
+ user_location: params.user_location,
303
+ },
256
304
  );
257
305
 
258
306
  const result = parseResponse(response);
@@ -281,6 +329,10 @@ export class AnthropicProvider extends SearchProvider {
281
329
  num_results: params.numSearchResults ?? params.limit,
282
330
  max_tokens: params.maxOutputTokens,
283
331
  temperature: params.temperature,
332
+ allowed_domains: params.allowedDomains,
333
+ blocked_domains: params.blockedDomains,
334
+ max_uses: params.maxUses,
335
+ user_location: params.userLocation,
284
336
  });
285
337
  }
286
338
  }
@@ -10,6 +10,16 @@ export interface SearchParams {
10
10
  maxOutputTokens?: number;
11
11
  numSearchResults?: number;
12
12
  temperature?: number;
13
+ allowedDomains?: string[];
14
+ blockedDomains?: string[];
15
+ maxUses?: number;
16
+ userLocation?: {
17
+ type: "approximate";
18
+ city?: string;
19
+ region?: string;
20
+ country?: string;
21
+ timezone?: string;
22
+ };
13
23
  googleSearch?: Record<string, unknown>;
14
24
  codeExecution?: Record<string, unknown>;
15
25
  urlContext?: Record<string, unknown>;