@f5-sales-demo/xcsh 19.86.0 → 19.87.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": "@f5-sales-demo/xcsh",
4
- "version": "19.86.0",
4
+ "version": "19.87.1",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5-sales-demo/xcsh",
7
7
  "author": "Can Boluk",
@@ -56,13 +56,13 @@
56
56
  "dependencies": {
57
57
  "@agentclientprotocol/sdk": "0.16.1",
58
58
  "@mozilla/readability": "^0.6",
59
- "@f5-sales-demo/xcsh-stats": "19.86.0",
60
- "@f5-sales-demo/pi-agent-core": "19.86.0",
61
- "@f5-sales-demo/pi-ai": "19.86.0",
62
- "@f5-sales-demo/pi-natives": "19.86.0",
63
- "@f5-sales-demo/pi-resource-management": "19.86.0",
64
- "@f5-sales-demo/pi-tui": "19.86.0",
65
- "@f5-sales-demo/pi-utils": "19.86.0",
59
+ "@f5-sales-demo/xcsh-stats": "19.87.1",
60
+ "@f5-sales-demo/pi-agent-core": "19.87.1",
61
+ "@f5-sales-demo/pi-ai": "19.87.1",
62
+ "@f5-sales-demo/pi-natives": "19.87.1",
63
+ "@f5-sales-demo/pi-resource-management": "19.87.1",
64
+ "@f5-sales-demo/pi-tui": "19.87.1",
65
+ "@f5-sales-demo/pi-utils": "19.87.1",
66
66
  "@sinclair/typebox": "^0.34",
67
67
  "@xterm/headless": "^6.0",
68
68
  "ajv": "^8.20",
@@ -1,4 +1,4 @@
1
- import type { AssistantMessage } from "@f5-sales-demo/pi-ai";
1
+ import type { AssistantMessage, ImageContent } from "@f5-sales-demo/pi-ai";
2
2
  import { DEFAULT_MODEL_ROLE } from "../config/settings-schema";
3
3
  import {
4
4
  isRpcHostToolResult,
@@ -165,10 +165,17 @@ export class ChatHandler {
165
165
  chat.unsubscribe = unsubscribe;
166
166
 
167
167
  const prompt = composeChatPrompt(req.text, req.context, req.mode, this.#server.clientHost);
168
+ // Photo/image attachments ride as base64 vision blocks (the model is
169
+ // vision-capable); text attachments are already folded into req.text upstream.
170
+ const images: ImageContent[] | undefined = req.images?.map(img => ({
171
+ type: "image",
172
+ data: img.data,
173
+ mimeType: img.mimeType,
174
+ }));
168
175
 
169
176
  try {
170
177
  chat.promptAt = Date.now();
171
- await this.#session.prompt(prompt, { expandPromptTemplates: false, synthetic: false });
178
+ await this.#session.prompt(prompt, { expandPromptTemplates: false, synthetic: false, images });
172
179
  } catch (err: unknown) {
173
180
  const message = err instanceof Error ? err.message : "unknown error";
174
181
  this.#sendTerminal(chat, { type: "chat_error", id, error: message, reason: classifyChatErrorReason(message) });
@@ -66,6 +66,16 @@ export interface ChatReference {
66
66
  // Inbound messages (extension → xcsh)
67
67
  // ---------------------------------------------------------------------------
68
68
 
69
+ /** A photo/image attachment on a chat turn (Office `+` → "Add files or photos").
70
+ * Base64 vision content; the handler maps it to an `ImageContent` block fed to the
71
+ * vision-capable model. */
72
+ export interface ChatImage {
73
+ /** Base64-encoded image bytes (no `data:` URL prefix). */
74
+ data: string;
75
+ /** MIME type — image/png | image/jpeg | image/gif | image/webp. */
76
+ mimeType: string;
77
+ }
78
+
69
79
  export interface ChatRequest {
70
80
  type: "chat_request";
71
81
  id: string;
@@ -73,6 +83,8 @@ export interface ChatRequest {
73
83
  context: PageContextSnapshot | null;
74
84
  mode: InteractionMode;
75
85
  history_hint?: string;
86
+ /** Optional photo/image attachments, sent to the model as vision blocks. */
87
+ images?: ChatImage[];
76
88
  }
77
89
 
78
90
  export interface ChatStop {
@@ -228,13 +240,25 @@ function hasChatIdPrefix(id: unknown): id is string {
228
240
  return typeof id === "string" && id.startsWith("c-");
229
241
  }
230
242
 
243
+ /** Optional `images` must be absent or an array of `{ data:string; mimeType:string }`. */
244
+ function isValidChatImages(v: unknown): boolean {
245
+ if (v === undefined) return true;
246
+ if (!Array.isArray(v)) return false;
247
+ return v.every(x => {
248
+ if (typeof x !== "object" || x === null) return false;
249
+ const img = x as Record<string, unknown>;
250
+ return typeof img.data === "string" && typeof img.mimeType === "string";
251
+ });
252
+ }
253
+
231
254
  export function isChatRequest(msg: Record<string, unknown>): boolean {
232
255
  return (
233
256
  msg.type === "chat_request" &&
234
257
  hasChatIdPrefix(msg.id) &&
235
258
  typeof msg.text === "string" &&
236
259
  typeof msg.mode === "string" &&
237
- VALID_MODES.has(msg.mode)
260
+ VALID_MODES.has(msg.mode) &&
261
+ isValidChatImages(msg.images)
238
262
  );
239
263
  }
240
264
 
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.86.0",
21
- "commit": "24a43f94c2aca0385cb3284227d0a503de320b32",
22
- "shortCommit": "24a43f9",
20
+ "version": "19.87.1",
21
+ "commit": "961f2b2d80f178d7165977576b0249907c21c68d",
22
+ "shortCommit": "961f2b2",
23
23
  "branch": "main",
24
- "tag": "v19.86.0",
25
- "commitDate": "2026-07-24T16:55:07Z",
26
- "buildDate": "2026-07-24T17:20:18.596Z",
24
+ "tag": "v19.87.1",
25
+ "commitDate": "2026-07-24T18:28:42Z",
26
+ "buildDate": "2026-07-24T18:54:10.232Z",
27
27
  "dirty": true,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5-sales-demo/xcsh",
30
30
  "repoSlug": "f5-sales-demo/xcsh",
31
- "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/24a43f94c2aca0385cb3284227d0a503de320b32",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.86.0"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/961f2b2d80f178d7165977576b0249907c21c68d",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.87.1"
33
33
  };