gsd-pi 2.73.1-dev.9a4cd44 → 2.73.1-dev.a2eb797

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.
Files changed (43) hide show
  1. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +59 -1
  2. package/dist/web/standalone/.next/BUILD_ID +1 -1
  3. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  4. package/dist/web/standalone/.next/build-manifest.json +2 -2
  5. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  6. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  7. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  10. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  15. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/index.html +1 -1
  23. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  30. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  32. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  33. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  34. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  35. package/package.json +1 -1
  36. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  37. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -2
  38. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  39. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -6
  40. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +95 -1
  41. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +88 -0
  42. /package/dist/web/standalone/.next/static/{ASJ2RGD7E1iiUYzA0xT2i → rCeJUc4hHW3VT0ARiIinf}/_buildManifest.js +0 -0
  43. /package/dist/web/standalone/.next/static/{ASJ2RGD7E1iiUYzA0xT2i → rCeJUc4hHW3VT0ARiIinf}/_ssgManifest.js +0 -0
@@ -97,6 +97,31 @@ interface ParsedTextInputField {
97
97
  secure: boolean;
98
98
  }
99
99
 
100
+ interface SDKInputImageBlock {
101
+ type: "image";
102
+ source: {
103
+ type: "base64";
104
+ media_type: string;
105
+ data: string;
106
+ };
107
+ }
108
+
109
+ interface SDKInputTextBlock {
110
+ type: "text";
111
+ text: string;
112
+ }
113
+
114
+ type SDKInputUserContentBlock = SDKInputImageBlock | SDKInputTextBlock;
115
+
116
+ interface SDKInputUserMessage {
117
+ type: "user";
118
+ message: {
119
+ role: "user";
120
+ content: SDKInputUserContentBlock[];
121
+ };
122
+ parent_tool_use_id: null;
123
+ }
124
+
100
125
  const OTHER_OPTION_LABEL = "None of the above";
101
126
  const SENSITIVE_FIELD_PATTERN = /(password|passphrase|secret|token|api[_\s-]*key|private[_\s-]*key|credential)/i;
102
127
 
@@ -223,6 +248,74 @@ export function buildPromptFromContext(context: Context): string {
223
248
  return parts.join("\n\n");
224
249
  }
225
250
 
251
+ function stripDataUriPrefix(value: string): string {
252
+ const commaIndex = value.indexOf(",");
253
+ if (value.startsWith("data:") && commaIndex !== -1) {
254
+ return value.slice(commaIndex + 1);
255
+ }
256
+ return value;
257
+ }
258
+
259
+ function inferMimeTypeFromDataUri(value: string): string | null {
260
+ const match = /^data:([^;,]+);base64,/.exec(value);
261
+ return match?.[1] ?? null;
262
+ }
263
+
264
+ export function extractImageBlocksFromContext(context: Context): SDKInputImageBlock[] {
265
+ const imageBlocks: SDKInputImageBlock[] = [];
266
+
267
+ for (const msg of context.messages) {
268
+ if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
269
+ for (const part of msg.content) {
270
+ if (!part || typeof part !== "object") continue;
271
+ const block = part as { type?: unknown; data?: unknown; mimeType?: unknown };
272
+ if (block.type !== "image" || typeof block.data !== "string") continue;
273
+
274
+ const mimeType =
275
+ typeof block.mimeType === "string" && block.mimeType.length > 0
276
+ ? block.mimeType
277
+ : inferMimeTypeFromDataUri(block.data);
278
+ if (!mimeType) continue;
279
+
280
+ imageBlocks.push({
281
+ type: "image",
282
+ source: {
283
+ type: "base64",
284
+ media_type: mimeType,
285
+ data: stripDataUriPrefix(block.data),
286
+ },
287
+ });
288
+ }
289
+ }
290
+
291
+ return imageBlocks;
292
+ }
293
+
294
+ export function buildSdkQueryPrompt(
295
+ context: Context,
296
+ textPrompt: string = buildPromptFromContext(context),
297
+ ): string | AsyncIterable<SDKInputUserMessage> {
298
+ const imageBlocks = extractImageBlocksFromContext(context);
299
+ if (imageBlocks.length === 0) {
300
+ return textPrompt;
301
+ }
302
+
303
+ const content: SDKInputUserContentBlock[] = [...imageBlocks];
304
+ if (textPrompt) {
305
+ content.push({ type: "text", text: textPrompt });
306
+ }
307
+
308
+ const sdkMessage: SDKInputUserMessage = {
309
+ type: "user",
310
+ message: { role: "user", content },
311
+ parent_tool_use_id: null,
312
+ };
313
+
314
+ return (async function* () {
315
+ yield sdkMessage;
316
+ })();
317
+ }
318
+
226
319
  // ---------------------------------------------------------------------------
227
320
  // Error helper
228
321
  // ---------------------------------------------------------------------------
@@ -828,6 +921,7 @@ async function pumpSdkMessages(
828
921
  }
829
922
 
830
923
  const prompt = buildPromptFromContext(context);
924
+ const queryPrompt = buildSdkQueryPrompt(context, prompt);
831
925
  const permissionMode = await resolveClaudePermissionMode();
832
926
  const sdkOpts = buildSdkOptions(
833
927
  modelId,
@@ -844,7 +938,7 @@ async function pumpSdkMessages(
844
938
  );
845
939
 
846
940
  const queryResult = sdk.query({
847
- prompt,
941
+ prompt: queryPrompt,
848
942
  options: {
849
943
  ...sdkOpts,
850
944
  abortController: controller,
@@ -10,8 +10,10 @@ import {
10
10
  mergePendingToolCalls,
11
11
  resolveClaudePermissionMode,
12
12
  buildPromptFromContext,
13
+ buildSdkQueryPrompt,
13
14
  buildSdkOptions,
14
15
  createClaudeCodeElicitationHandler,
16
+ extractImageBlocksFromContext,
15
17
  extractToolResultsFromSdkUserMessage,
16
18
  getClaudeLookupCommand,
17
19
  parseAskUserQuestionsElicitation,
@@ -167,6 +169,92 @@ describe("stream-adapter — full context prompt (#2859)", () => {
167
169
  });
168
170
  });
169
171
 
172
+ describe("stream-adapter — image prompt forwarding (#4183)", () => {
173
+ test("extractImageBlocksFromContext maps user image parts to Anthropic base64 image blocks", () => {
174
+ const context: Context = {
175
+ messages: [
176
+ {
177
+ role: "user",
178
+ content: [
179
+ { type: "text", text: "look" },
180
+ {
181
+ type: "image",
182
+ data: "data:image/png;base64,abc123",
183
+ mimeType: "image/png",
184
+ },
185
+ ],
186
+ } as Message,
187
+ ],
188
+ };
189
+
190
+ const imageBlocks = extractImageBlocksFromContext(context);
191
+ assert.deepEqual(imageBlocks, [
192
+ {
193
+ type: "image",
194
+ source: {
195
+ type: "base64",
196
+ media_type: "image/png",
197
+ data: "abc123",
198
+ },
199
+ },
200
+ ]);
201
+ });
202
+
203
+ test("buildSdkQueryPrompt returns plain string when no images exist in context", () => {
204
+ const context: Context = {
205
+ messages: [{ role: "user", content: "hello" } as Message],
206
+ };
207
+ const textPrompt = buildPromptFromContext(context);
208
+
209
+ const prompt = buildSdkQueryPrompt(context, textPrompt);
210
+ assert.equal(typeof prompt, "string");
211
+ assert.equal(prompt, textPrompt);
212
+ });
213
+
214
+ test("buildSdkQueryPrompt wraps images and prompt text in an SDK user message iterable", async () => {
215
+ const context: Context = {
216
+ messages: [
217
+ {
218
+ role: "user",
219
+ content: [
220
+ { type: "image", data: "ZmFrZQ==", mimeType: "image/jpeg" },
221
+ { type: "text", text: "What is in this image?" },
222
+ ],
223
+ } as Message,
224
+ ],
225
+ };
226
+ const textPrompt = buildPromptFromContext(context);
227
+
228
+ const prompt = buildSdkQueryPrompt(context, textPrompt);
229
+ assert.notEqual(typeof prompt, "string");
230
+ assert.ok(prompt && typeof (prompt as any)[Symbol.asyncIterator] === "function");
231
+
232
+ const messages: any[] = [];
233
+ for await (const item of prompt as AsyncIterable<any>) {
234
+ messages.push(item);
235
+ }
236
+ assert.equal(messages.length, 1);
237
+ assert.deepEqual(messages[0], {
238
+ type: "user",
239
+ message: {
240
+ role: "user",
241
+ content: [
242
+ {
243
+ type: "image",
244
+ source: {
245
+ type: "base64",
246
+ media_type: "image/jpeg",
247
+ data: "ZmFrZQ==",
248
+ },
249
+ },
250
+ { type: "text", text: textPrompt },
251
+ ],
252
+ },
253
+ parent_tool_use_id: null,
254
+ });
255
+ });
256
+ });
257
+
170
258
  // ---------------------------------------------------------------------------
171
259
  // Bug #4102 — transcript fabrication regression tests
172
260
  // ---------------------------------------------------------------------------