@trim21/personal-pi-extensions 0.0.173 → 0.0.175

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@trim21/personal-pi-extensions",
3
- "version": "0.0.173",
3
+ "version": "0.0.175",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -223,6 +223,39 @@ export function isMultimodal(model: { input?: readonly string[] } | undefined):
223
223
  return !!model && Array.isArray(model.input) && model.input.includes("image");
224
224
  }
225
225
 
226
+ /**
227
+ * 把识别结果整理成 pendant 渲染用的 markdown。
228
+ * description 格式为 callVision 拼装的 `[label]\n<正文>\n[模型: ...]`,
229
+ * 第一行是图片标签、最后一行是模型/ token 元信息,中间是视觉模型输出正文。
230
+ */
231
+ export function buildPendantMarkdown(params: {
232
+ paths: string[];
233
+ prompt: string;
234
+ description: string;
235
+ provider: string;
236
+ model: string;
237
+ }): string {
238
+ const lines = params.description.split("\n");
239
+ const labels = lines[0]?.trim().replaceAll(/^\[|\]$/g, "") ?? "";
240
+ const footer = lines.at(-1)?.trim() ?? "";
241
+ const body = lines.slice(1, -1).join("\n").trim();
242
+ const files = params.paths.map((p) => `\`${basename(p)}\``).join(", ");
243
+ return [
244
+ "## 图片识别",
245
+ "",
246
+ `**图片**: ${files || labels}`,
247
+ `**视觉模型**: \`${params.provider}/${params.model}\``,
248
+ `**Prompt**: ${params.prompt}`,
249
+ "",
250
+ "### 识别结果",
251
+ "",
252
+ body || params.description,
253
+ footer ? `\n---\n${footer}` : "",
254
+ ]
255
+ .join("\n")
256
+ .trim();
257
+ }
258
+
226
259
  // ── 图片加载与 API 调用 ─────────────────────────────────────────────────────
227
260
 
228
261
  /** 按文件头识别真实图片类型,识别不出返回 undefined */
@@ -457,7 +490,7 @@ export default function visionAgent(pi: ExtensionAPI) {
457
490
  ),
458
491
  }),
459
492
 
460
- async execute(_toolCallId, params, signal, _onUpdate, ctx) {
493
+ async execute(_toolCallId, params, signal, onUpdate, ctx) {
461
494
  try {
462
495
  const paths = resolveImagePaths({ path: params.path });
463
496
  if (paths.length === 0) {
@@ -502,19 +535,39 @@ export default function visionAgent(pi: ExtensionAPI) {
502
535
  };
503
536
  }
504
537
 
538
+ const prompt = buildPrompt(params.prompt, paths.length);
539
+ // 把发给视觉模型的 prompt 实时透传给主会话,识别要求对主模型可见
540
+ onUpdate?.({
541
+ content: [{ type: "text", text: `视觉识别 prompt: ${prompt}` }],
542
+ details: { prompt },
543
+ });
544
+
505
545
  const description = await callVision(
506
546
  { ...provider, model: visionConfig.model },
507
547
  paths,
508
- buildPrompt(params.prompt, paths.length),
548
+ prompt,
509
549
  signal ?? ctx.signal,
510
550
  );
551
+ const markdown = buildPendantMarkdown({
552
+ paths,
553
+ prompt,
554
+ description,
555
+ provider: providerName,
556
+ model: visionConfig.model,
557
+ });
511
558
  return {
512
559
  content: [{ type: "text", text: description }],
513
560
  details: {
514
561
  provider: providerName,
515
562
  model: visionConfig.model,
563
+ prompt,
564
+ output: description,
516
565
  paths,
517
566
  count: paths.length,
567
+ pendant: {
568
+ markdown,
569
+ expanded: true,
570
+ },
518
571
  },
519
572
  };
520
573
  } catch (error) {
@@ -529,7 +582,13 @@ export default function visionAgent(pi: ExtensionAPI) {
529
582
  return {
530
583
  isError: true,
531
584
  content: [{ type: "text", text: `识别失败: ${message}` }],
532
- details: { error: message },
585
+ details: {
586
+ error: message,
587
+ pendant: {
588
+ markdown: `## 图片识别失败\n\n${message}`,
589
+ expanded: true,
590
+ },
591
+ },
533
592
  };
534
593
  }
535
594
  },