@hachej/boring-agent 0.1.86 → 0.1.88

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.
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-AQBXNPMD.js";
5
5
  import {
6
6
  ErrorCode
7
- } from "./chunk-HDIRWHJB.js";
7
+ } from "./chunk-GOM3VJOJ.js";
8
8
 
9
9
  // src/server/harness/pi-coding-agent/createHarness.ts
10
10
  import { AsyncLocalStorage } from "async_hooks";
@@ -559,9 +559,22 @@ var PiSessionStore = class {
559
559
  */
560
560
  async loadEntries(ctx, sessionId) {
561
561
  const resolved = await this.resolveSessionTranscript(ctx, sessionId);
562
- const messages = resolved.transcriptEntries.filter((entry) => entry.type === "message").map((entry) => entry.message);
562
+ const messages = resolved.transcriptEntries.filter((entry) => entry.type === "message").map((entry) => withStableMessageId(entry.message, entry.id));
563
563
  return { id: resolved.resolvedSessionId, messages };
564
564
  }
565
+ async loadAttachment(ctx, sessionId, messageId, index) {
566
+ const resolved = await this.resolveSessionTranscript(ctx, sessionId);
567
+ const entry = resolved.transcriptEntries.filter((item) => item.type === "message").find((item) => item.id === messageId || messageIdFromPiMessage(item.message) === messageId);
568
+ const part = entry ? piImagePartAt(entry.message, index) : null;
569
+ if (!part) throw new Error(`Session attachment not found: ${sessionId}`);
570
+ const data = imagePartBuffer(part);
571
+ if (!data) throw new Error(`Session attachment not found: ${sessionId}`);
572
+ return {
573
+ data,
574
+ mediaType: part.mimeType ?? "application/octet-stream",
575
+ ...part.filename ? { filename: part.filename } : {}
576
+ };
577
+ }
565
578
  async resolveSessionTranscript(ctx, sessionId) {
566
579
  const filepath = await this.resolveSessionFile(sessionId, ctx);
567
580
  let content;
@@ -1143,6 +1156,42 @@ function textFromPiContent(content) {
1143
1156
  return item?.type === "text" && typeof item.text === "string" ? item.text : "";
1144
1157
  }).join("");
1145
1158
  }
1159
+ function withStableMessageId(message, entryId) {
1160
+ if (!entryId || !message || typeof message !== "object" || Array.isArray(message)) return message;
1161
+ if (typeof message.id === "string") return message;
1162
+ return { ...message, id: entryId };
1163
+ }
1164
+ function messageIdFromPiMessage(message) {
1165
+ if (!message || typeof message !== "object" || Array.isArray(message)) return void 0;
1166
+ const id = message.id;
1167
+ return typeof id === "string" && id.length > 0 ? id : void 0;
1168
+ }
1169
+ function piImagePartAt(message, index) {
1170
+ if (!Number.isInteger(index) || index < 0) return null;
1171
+ if (!message || typeof message !== "object" || Array.isArray(message)) return null;
1172
+ const content = message.content;
1173
+ if (!Array.isArray(content)) return null;
1174
+ const part = content[index];
1175
+ if (!part || typeof part !== "object" || Array.isArray(part)) return null;
1176
+ const record = part;
1177
+ if (record.type !== "image") return null;
1178
+ return {
1179
+ type: "image",
1180
+ ...typeof record.data === "string" ? { data: record.data } : {},
1181
+ ...typeof record.mimeType === "string" && record.mimeType.length > 0 ? { mimeType: record.mimeType } : {},
1182
+ ...typeof record.filename === "string" && record.filename.length > 0 ? { filename: record.filename } : {}
1183
+ };
1184
+ }
1185
+ function imagePartBuffer(part) {
1186
+ const raw = part.data;
1187
+ if (!raw) return null;
1188
+ const match = raw.match(/^data:[^;]+;base64,(.+)$/);
1189
+ try {
1190
+ return Buffer.from(match ? match[1] : raw, "base64");
1191
+ } catch {
1192
+ return null;
1193
+ }
1194
+ }
1146
1195
 
1147
1196
  // src/server/models/modelConfig.ts
1148
1197
  import { getAgentDir, SettingsManager } from "@mariozechner/pi-coding-agent";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ErrorCode
3
- } from "./chunk-HDIRWHJB.js";
3
+ } from "./chunk-GOM3VJOJ.js";
4
4
 
5
5
  // src/shared/tool-ui.ts
6
6
  function isRecord(value) {
@@ -13,11 +13,11 @@ import {
13
13
  validateAgentDefinition,
14
14
  validateAgentDeployment,
15
15
  validateTool
16
- } from "./chunk-YONTHCD7.js";
16
+ } from "./chunk-XPQEF32D.js";
17
17
  import {
18
18
  AgentEffectAdmissionError,
19
19
  createAgentRuntimeBridge
20
- } from "./chunk-LYBTHR7J.js";
20
+ } from "./chunk-M32FXCIN.js";
21
21
  import {
22
22
  sessionStreamPath
23
23
  } from "./chunk-WSQ5QNIY.js";
@@ -32,7 +32,7 @@ import {
32
32
  StopReceiptSchema,
33
33
  extractToolUiMetadata,
34
34
  sanitizeToolUiMetadata2 as sanitizeToolUiMetadata
35
- } from "./chunk-6O5ADR57.js";
35
+ } from "./chunk-BDYXKHWY.js";
36
36
  import {
37
37
  createLogger,
38
38
  createPiCodingAgentHarness,
@@ -43,7 +43,7 @@ import {
43
43
  registerConfiguredModelProviders,
44
44
  setEnvDefault,
45
45
  withPiHarnessDefaults
46
- } from "./chunk-ZUDWQAAB.js";
46
+ } from "./chunk-3LW57KYG.js";
47
47
  import {
48
48
  safeCapture
49
49
  } from "./chunk-AQBXNPMD.js";
@@ -51,7 +51,7 @@ import {
51
51
  AgentDefinitionErrorCode,
52
52
  AgentDeploymentErrorCode,
53
53
  ErrorCode
54
- } from "./chunk-HDIRWHJB.js";
54
+ } from "./chunk-GOM3VJOJ.js";
55
55
 
56
56
  // src/server/sandbox/direct/createDirectSandbox.ts
57
57
  import { spawn } from "child_process";
@@ -6044,18 +6044,19 @@ function textFromContent(content) {
6044
6044
  }).join("");
6045
6045
  return text.length > 0 ? text : void 0;
6046
6046
  }
6047
- function filePartsFromContent(content, messageId) {
6047
+ function filePartsFromContent(content, messageId, options) {
6048
6048
  if (!Array.isArray(content)) return [];
6049
6049
  return content.flatMap((part, index) => {
6050
6050
  if (!isRecord(part) || part.type !== "image") return [];
6051
6051
  const mediaType = optionalString(part.mimeType);
6052
+ const url = options?.attachmentUrl?.({ messageId, index }) ?? imagePartUrl(part, mediaType);
6052
6053
  return [
6053
6054
  {
6054
6055
  type: "file",
6055
6056
  id: `${messageId}:file:${index}`,
6056
6057
  ...optionalString(part.filename) ? { filename: optionalString(part.filename) } : {},
6057
6058
  ...mediaType ? { mediaType } : {},
6058
- ...imagePartUrl(part, mediaType) ? { url: imagePartUrl(part, mediaType) } : {},
6059
+ ...url ? { url } : {},
6059
6060
  ...optionalString(part.path) ? { path: optionalString(part.path) } : {}
6060
6061
  }
6061
6062
  ];
@@ -6069,11 +6070,11 @@ function imagePartUrl(part, mediaType) {
6069
6070
  if (data.startsWith("data:")) return data;
6070
6071
  return `data:${mediaType ?? "application/octet-stream"};base64,${data}`;
6071
6072
  }
6072
- function userParts(message, messageId) {
6073
+ function userParts(message, messageId, options) {
6073
6074
  const parts = [];
6074
6075
  const text = textFromContent(message.content);
6075
6076
  if (text !== void 0) parts.push({ type: "text", id: `${messageId}:text:0`, text });
6076
- parts.push(...filePartsFromContent(message.content, messageId));
6077
+ parts.push(...filePartsFromContent(message.content, messageId, options));
6077
6078
  return parts;
6078
6079
  }
6079
6080
  function systemParts(message, messageId) {
@@ -6176,7 +6177,7 @@ function buildPiChatHistory(entries, options) {
6176
6177
  turnId: optionalString(entry.message.turnId) ?? options.messageTurnIds?.get(id) ?? options.turnId
6177
6178
  };
6178
6179
  if (role === "user") {
6179
- messages.push({ ...base, role: "user", status: "done", parts: userParts(entry.message, id) });
6180
+ messages.push({ ...base, role: "user", status: "done", parts: userParts(entry.message, id, options) });
6180
6181
  return;
6181
6182
  }
6182
6183
  if (role === "assistant") {
@@ -7821,6 +7822,16 @@ var HarnessPiChatService = class {
7821
7822
  }
7822
7823
  if (teardownError) throw teardownError;
7823
7824
  }
7825
+ async readAttachment(ctx, sessionId, messageId, index) {
7826
+ return this.lifecycle.run(async () => {
7827
+ if (!this.sessionStore.loadAttachment) throw Object.assign(new Error("session attachment not found"), { code: ErrorCode.enum.SESSION_NOT_FOUND });
7828
+ try {
7829
+ return await this.sessionStore.loadAttachment(toSessionCtx(ctx), sessionId, messageId, index);
7830
+ } catch {
7831
+ throw Object.assign(new Error("attachment not found"), { code: ErrorCode.enum.SESSION_NOT_FOUND });
7832
+ }
7833
+ });
7834
+ }
7824
7835
  async readState(ctx, sessionId) {
7825
7836
  return this.lifecycle.run(() => this.readStateBeforeDispose(ctx, sessionId));
7826
7837
  }
@@ -7852,7 +7863,10 @@ var HarnessPiChatService = class {
7852
7863
  sessionId: id,
7853
7864
  seq: await this.readDurableLatestPiChatSeq(sessionStreamPath(this.sessionKey(ctx, id))),
7854
7865
  status: "idle",
7855
- messages: buildPiChatHistory(messages, { sessionId: id }),
7866
+ messages: buildPiChatHistory(messages, {
7867
+ sessionId: id,
7868
+ attachmentUrl: ({ messageId, index }) => `/api/v1/agent/pi-chat/${encodeURIComponent(id)}/attachments/${encodeURIComponent(messageId)}/${index}`
7869
+ }),
7856
7870
  queue: { followUps: [] },
7857
7871
  followUpMode: "one-at-a-time"
7858
7872
  };
@@ -8511,7 +8525,7 @@ function createAgentRuntimeBridge2(config, options = {}) {
8511
8525
  });
8512
8526
  }
8513
8527
  async function createRuntime(config, options) {
8514
- const harnessFactory = config.harnessFactory ?? (await import("./createHarness-MJ5GEL6J.js")).createPiCodingAgentHarness;
8528
+ const harnessFactory = config.harnessFactory ?? (await import("./createHarness-2VVUQ3CK.js")).createPiCodingAgentHarness;
8515
8529
  const harnessInput = {
8516
8530
  tools: config.tools ?? [],
8517
8531
  cwd: config.workdir ?? DEFAULT_WORKDIR,
@@ -12024,6 +12038,13 @@ var SAFE_SESSION_LIST_INCLUDE_ID = /^[a-zA-Z0-9_-]{1,128}$/;
12024
12038
  var SessionParamsSchema = z3.object({
12025
12039
  sessionId: z3.string().min(1).max(128)
12026
12040
  });
12041
+ var AttachmentParamsSchema = SessionParamsSchema.extend({
12042
+ messageId: z3.string().min(1).max(512),
12043
+ index: z3.preprocess((value) => {
12044
+ if (typeof value === "string" && value.length > 0) return Number(value);
12045
+ return value;
12046
+ }, z3.number().int().nonnegative())
12047
+ });
12027
12048
  var CursorValueSchema = z3.preprocess((value) => {
12028
12049
  if (value === void 0) return 0;
12029
12050
  if (typeof value === "string" && value.length > 0) return Number(value);
@@ -12094,6 +12115,21 @@ function piChatRoutes(app, opts, done) {
12094
12115
  return sendRouteError(reply, err, "read pi chat state failed");
12095
12116
  }
12096
12117
  });
12118
+ app.get("/api/v1/agent/pi-chat/:sessionId/attachments/:messageId/:index", async (request, reply) => {
12119
+ const params = parseWithSchema(AttachmentParamsSchema, request.params, reply, "params");
12120
+ if (!params) return;
12121
+ try {
12122
+ const service = await resolveService(opts, request);
12123
+ if (!service.readAttachment) throw unsupportedServiceMethod("read Pi chat attachment");
12124
+ const attachment = await service.readAttachment(getRequestContext(request), params.sessionId, params.messageId, params.index);
12125
+ if (!attachment.mediaType.startsWith("image/")) {
12126
+ throw new PiChatRouteError({ statusCode: 404, code: ErrorCode.enum.SESSION_NOT_FOUND, message: "attachment not found" });
12127
+ }
12128
+ return reply.header("Content-Type", attachment.mediaType).header("Cache-Control", "private, max-age=300").header("X-Content-Type-Options", "nosniff").send(Buffer.from(attachment.data));
12129
+ } catch (err) {
12130
+ return sendRouteError(reply, err, "read pi chat attachment failed");
12131
+ }
12132
+ });
12097
12133
  app.get("/api/v1/agent/pi-chat/:sessionId/events", async (request, reply) => {
12098
12134
  const params = parseParams(request, reply);
12099
12135
  if (!params) return;
@@ -14591,7 +14627,7 @@ var registerAgentRoutes = async (app, opts) => {
14591
14627
  try {
14592
14628
  workspaceId = (await opts.getWorkspaceId(request)).trim();
14593
14629
  } catch (error) {
14594
- if (typeof error === "object" && error !== null && "status" in error && error.status === 421 && "code" in error && error.code === ErrorCode.enum.D1_HOST_SCOPE_VIOLATION) {
14630
+ if (typeof error === "object" && error !== null && "status" in error && error.status === 421 && "code" in error && error.code === ErrorCode.enum.AGENT_HOST_SCOPE_VIOLATION) {
14595
14631
  throw error;
14596
14632
  }
14597
14633
  const statusCode = typeof error?.statusCode === "number" ? error.statusCode : 400;
@@ -17,7 +17,7 @@ var ErrorCode = z.enum([
17
17
  "PATH_NOT_WRITABLE",
18
18
  "WORKSPACE_UNINITIALIZED",
19
19
  "WORKSPACE_NOT_READY",
20
- "D1_HOST_SCOPE_VIOLATION",
20
+ "AGENT_HOST_SCOPE_VIOLATION",
21
21
  // Agent runtime / provisioning
22
22
  "AGENT_RUNTIME_NOT_READY",
23
23
  "AGENT_BINDING_DISPOSED",
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-WSQ5QNIY.js";
4
4
  import {
5
5
  ErrorCode
6
- } from "./chunk-HDIRWHJB.js";
6
+ } from "./chunk-GOM3VJOJ.js";
7
7
 
8
8
  // src/core/piChatSessionService.ts
9
9
  var AgentEffectAdmissionError = class extends Error {
@@ -37,6 +37,7 @@ function withAgentEffectAdmission(service, admit) {
37
37
  await admit(ctx);
38
38
  return service.deleteSession(ctx, sessionId);
39
39
  },
40
+ ...service.readAttachment ? { readAttachment: (ctx, sessionId, messageId, index) => service.readAttachment(ctx, sessionId, messageId, index) } : {},
40
41
  readState: (ctx, sessionId) => service.readState(ctx, sessionId),
41
42
  subscribe: (ctx, sessionId, cursor, subscriber) => service.subscribe(ctx, sessionId, cursor, subscriber),
42
43
  async prompt(ctx, sessionId, payload) {
@@ -2,7 +2,7 @@ import {
2
2
  AgentDefinitionErrorCode,
3
3
  AgentDeploymentErrorCode,
4
4
  ErrorCode
5
- } from "./chunk-HDIRWHJB.js";
5
+ } from "./chunk-GOM3VJOJ.js";
6
6
 
7
7
  // src/shared/agent-definition.ts
8
8
  import { z as z2 } from "zod";
@@ -1,8 +1,8 @@
1
- import { A as AgentHarness, a as AgentReadiness, b as Agent } from '../harness-RhGbdGWY.js';
2
- export { c as AGENT_NOT_IMPLEMENTED_UNTIL_T1, d as AgentActor, e as AgentCoreHarness, f as AgentCoreHarnessFactory, g as AgentCorePromptInput, h as AgentCoreSessionAdapter, i as AgentCoreSessionSnapshot, j as AgentEvent, k as AgentMessageContent, l as AgentMessagePart, m as AgentNotImplementedError, n as AgentReadinessStatus, o as AgentResolveInputResponse, p as AgentSendInput, q as AgentStartReceipt, r as AgentStreamOptions } from '../harness-RhGbdGWY.js';
3
- import { S as SessionStore } from '../piChatEvent-CUTKRaZD.js';
4
- import { A as AgentCoreSessionService, a as AgentEffectAdmission } from '../piChatSessionService-iBtx32ya.js';
5
- export { b as AGENT_EFFECT_METHODS, c as AgentEffectAdmissionError, P as PiChatEventStreamResult, d as PiChatEventStreamSubscription, e as PiChatEventSubscriber, f as PiChatReplayRangeError, g as PiChatSessionService, h as PiSessionCreateInit, i as PiSessionRequestContext, w as withAgentEffectAdmission } from '../piChatSessionService-iBtx32ya.js';
1
+ import { A as AgentHarness, a as AgentReadiness, b as Agent } from '../harness-VvP0l5Mj.js';
2
+ export { c as AGENT_NOT_IMPLEMENTED_UNTIL_T1, d as AgentActor, e as AgentCoreHarness, f as AgentCoreHarnessFactory, g as AgentCorePromptInput, h as AgentCoreSessionAdapter, i as AgentCoreSessionSnapshot, j as AgentEvent, k as AgentMessageContent, l as AgentMessagePart, m as AgentNotImplementedError, n as AgentReadinessStatus, o as AgentResolveInputResponse, p as AgentSendInput, q as AgentStartReceipt, r as AgentStreamOptions } from '../harness-VvP0l5Mj.js';
3
+ import { S as SessionStore } from '../piChatEvent-nmOBSNU9.js';
4
+ import { A as AgentCoreSessionService, a as AgentEffectAdmission } from '../piChatSessionService-DPjJ0g71.js';
5
+ export { b as AGENT_EFFECT_METHODS, c as AgentEffectAdmissionError, P as PiChatEventStreamResult, d as PiChatEventStreamSubscription, e as PiChatEventSubscriber, f as PiChatReplayRangeError, g as PiChatSessionService, h as PiSessionCreateInit, i as PiSessionRequestContext, w as withAgentEffectAdmission } from '../piChatSessionService-DPjJ0g71.js';
6
6
  import '@mariozechner/pi-coding-agent';
7
7
  import 'zod';
8
8
 
@@ -3,12 +3,12 @@ import {
3
3
  AgentEffectAdmissionError,
4
4
  createAgent,
5
5
  withAgentEffectAdmission
6
- } from "../chunk-LYBTHR7J.js";
6
+ } from "../chunk-M32FXCIN.js";
7
7
  import {
8
8
  AGENT_NOT_IMPLEMENTED_UNTIL_T1,
9
9
  AgentNotImplementedError
10
10
  } from "../chunk-WSQ5QNIY.js";
11
- import "../chunk-HDIRWHJB.js";
11
+ import "../chunk-GOM3VJOJ.js";
12
12
  export {
13
13
  AGENT_EFFECT_METHODS,
14
14
  AGENT_NOT_IMPLEMENTED_UNTIL_T1,
@@ -4,9 +4,9 @@ import {
4
4
  deriveSourcePlugin,
5
5
  mergePiPackageSources,
6
6
  withPiHarnessDefaults
7
- } from "./chunk-ZUDWQAAB.js";
7
+ } from "./chunk-3LW57KYG.js";
8
8
  import "./chunk-AQBXNPMD.js";
9
- import "./chunk-HDIRWHJB.js";
9
+ import "./chunk-GOM3VJOJ.js";
10
10
  export {
11
11
  createPiCodingAgentHarness,
12
12
  createResourceSettingsManager,
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ComponentProps, HTMLAttributes, FormEvent, ReactNode, ComponentType } from 'react';
3
3
  import { FileUIPart, ChatStatus, UIMessage } from 'ai';
4
- import { T as ToolUiMetadata, B as BoringChatPart, a as BoringChatMessage, P as PiChatStatus, Q as QueuedUserMessage, C as ChatError, b as PiChatEvent, c as PromptPayload, d as PromptReceipt, F as FollowUpPayload, e as FollowUpReceipt, f as QueueClearPayload, g as QueueClearReceipt, I as InterruptPayload, h as CommandReceipt, i as StopPayload, j as StopReceipt, k as SessionSummary } from '../piChatEvent-CUTKRaZD.js';
4
+ import { T as ToolUiMetadata, B as BoringChatPart, a as BoringChatMessage, P as PiChatStatus, Q as QueuedUserMessage, C as ChatError, b as PiChatEvent, c as PromptPayload, d as PromptReceipt, F as FollowUpPayload, e as FollowUpReceipt, f as QueueClearPayload, g as QueueClearReceipt, I as InterruptPayload, h as CommandReceipt, i as StopPayload, j as StopReceipt, k as SessionSummary } from '../piChatEvent-nmOBSNU9.js';
5
5
  import { InputGroupAddon, InputGroupButton, InputGroupTextarea, Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from '@hachej/boring-ui-kit';
6
6
  import { Streamdown } from 'streamdown';
7
7
  import { StickToBottom } from 'use-stick-to-bottom';
@@ -593,6 +593,10 @@ interface ChatPanelEmptyState {
593
593
  /** Optional content rendered below the suggestion grid (e.g. a footer link). */
594
594
  footer?: ReactNode;
595
595
  }
596
+ interface AgentPluginReloadResult {
597
+ message: string;
598
+ reloaded: boolean;
599
+ }
596
600
  interface PiChatPanelProps<TComposerBlocker extends ComposerBlocker = ComposerBlocker> {
597
601
  /** Optional externally selected Pi session id. When provided, session navigation is owned by the host. */
598
602
  sessionId?: string;
@@ -639,7 +643,7 @@ interface PiChatPanelProps<TComposerBlocker extends ComposerBlocker = ComposerBl
639
643
  workspaceWarmupStatus?: ChatPanelWorkspaceWarmupStatus;
640
644
  onSessionReset?: () => void | Promise<void>;
641
645
  onBeforeSubmit?: (draft: string, context: ChatSubmitContext) => false | void | boolean | Promise<false | void | boolean>;
642
- onReloadAgentPlugins?: () => Promise<string>;
646
+ onReloadAgentPlugins?: () => Promise<AgentPluginReloadResult | string>;
643
647
  onCommandResult?: (message: string) => void;
644
648
  onComposerWarning?: (message: string) => void;
645
649
  onMentionedFilesConsumed?: () => void;
@@ -802,4 +806,4 @@ declare const CodeBlock: ({ code, language, showLineNumbers, className, children
802
806
 
803
807
  declare function cn(...inputs: ClassValue[]): string;
804
808
 
805
- export { type AgentCommandContribution, type AgentCommandOptions, ArtifactOpenProvider, type AvailableModel, ChatEmptyState, type ChatEmptyStateProps, PiChatPanel as ChatPanel, type PiChatPanelProps as ChatPanelProps, type ChatSuggestion, CodeBlock, type CommandRegistry, type ComposerBlocker, type ComposerBlockerAction, Conversation, ConversationContent, ConversationScrollButton, DebugDrawer, type GroupedToolEntry, Message, MessageAction, MessageActions, MessageContent, MessageResponse, ModelPickerMenu, ModelSelect, ModelSelectTrigger, type ModelSelection, type OpenArtifactHandler, type ParsedCommand, PiChatPanel, type PiChatPanelProps, SessionBrowser as PiSessionBrowser, type PiSessionCreateInit, SessionList as PiSessionList, type PiSessionSearchItem, type PiSessionSearchOptions, type PiSessionSearchSortMode, PromptInput, PromptInputFooter, PromptInputSubmit, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, type SessionListProps, type SlashCommand, type SlashCommandContext, ToolCallGroup, type ToolPart, type ToolRenderer, type ToolRendererOverrides, type UploadFileOptions, type UploadFileResult, type UsePiSessionsOptions, type UsePiSessionsResult, activeSessionStorageKey, builtinCommands, clearActiveSessionId, cn, createCommandRegistry, defaultChatSuggestions, defaultToolRenderers, getAgentCommands, matchPiSessionSearch, mergeShadcnToolRenderers, mergeToolRenderers, parsePiSessionSearchQuery, parseSlashCommand, readActiveSessionId, resolveToolRenderer, searchPiSessions, uploadFile, useOpenArtifact, usePiSessions, writeActiveSessionId };
809
+ export { type AgentCommandContribution, type AgentCommandOptions, type AgentPluginReloadResult, ArtifactOpenProvider, type AvailableModel, ChatEmptyState, type ChatEmptyStateProps, PiChatPanel as ChatPanel, type PiChatPanelProps as ChatPanelProps, type ChatSuggestion, CodeBlock, type CommandRegistry, type ComposerBlocker, type ComposerBlockerAction, Conversation, ConversationContent, ConversationScrollButton, DebugDrawer, type GroupedToolEntry, Message, MessageAction, MessageActions, MessageContent, MessageResponse, ModelPickerMenu, ModelSelect, ModelSelectTrigger, type ModelSelection, type OpenArtifactHandler, type ParsedCommand, PiChatPanel, type PiChatPanelProps, SessionBrowser as PiSessionBrowser, type PiSessionCreateInit, SessionList as PiSessionList, type PiSessionSearchItem, type PiSessionSearchOptions, type PiSessionSearchSortMode, PromptInput, PromptInputFooter, PromptInputSubmit, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, type SessionListProps, type SlashCommand, type SlashCommandContext, ToolCallGroup, type ToolPart, type ToolRenderer, type ToolRendererOverrides, type UploadFileOptions, type UploadFileResult, type UsePiSessionsOptions, type UsePiSessionsResult, activeSessionStorageKey, builtinCommands, clearActiveSessionId, cn, createCommandRegistry, defaultChatSuggestions, defaultToolRenderers, getAgentCommands, matchPiSessionSearch, mergeShadcnToolRenderers, mergeToolRenderers, parsePiSessionSearchQuery, parseSlashCommand, readActiveSessionId, resolveToolRenderer, searchPiSessions, uploadFile, useOpenArtifact, usePiSessions, writeActiveSessionId };
@@ -1,3 +1,8 @@
1
+ import {
2
+ DebugDrawer,
3
+ cn,
4
+ copyTextToClipboard
5
+ } from "../chunk-BOIV2I3N.js";
1
6
  import {
2
7
  WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
3
8
  WORKSPACE_COMMAND_NOTIFY_EVENT
@@ -12,15 +17,10 @@ import {
12
17
  StopReceiptSchema,
13
18
  extractToolUiMetadata,
14
19
  sanitizeToolUiMetadata
15
- } from "../chunk-6O5ADR57.js";
20
+ } from "../chunk-BDYXKHWY.js";
16
21
  import {
17
22
  ErrorCode
18
- } from "../chunk-HDIRWHJB.js";
19
- import {
20
- DebugDrawer,
21
- cn,
22
- copyTextToClipboard
23
- } from "../chunk-BOIV2I3N.js";
23
+ } from "../chunk-GOM3VJOJ.js";
24
24
 
25
25
  // src/front/upload/uploadFile.ts
26
26
  function readAsDataUrl(file) {
@@ -5714,7 +5714,7 @@ function sortByUpdatedDesc(a, b) {
5714
5714
  return a.id.localeCompare(b.id);
5715
5715
  }
5716
5716
 
5717
- // ../../node_modules/.pnpm/@earendil-works+pi-tui@0.80.3/node_modules/@earendil-works/pi-tui/dist/fuzzy.js
5717
+ // ../../node_modules/.pnpm/@earendil-works+pi-tui@0.80.7/node_modules/@earendil-works/pi-tui/dist/fuzzy.js
5718
5718
  function fuzzyMatch(query, text) {
5719
5719
  const queryLower = query.toLowerCase();
5720
5720
  const textLower = text.toLowerCase();
@@ -7094,11 +7094,15 @@ function PiTimelineMessage({ message, isLast, isStreaming, showThoughts, toolRen
7094
7094
  ),
7095
7095
  children: fileParts.map((file, index) => {
7096
7096
  const openPath = file.path ?? attachmentSummaryPaths[index];
7097
- const canOpen = Boolean(openArtifact && openPath);
7097
+ const openUrl = file.url && !openPath ? file.url : void 0;
7098
+ const canOpen = Boolean(openArtifact && openPath || openUrl);
7098
7099
  const openAttachment = () => {
7099
- if (!openPath) return;
7100
- if (file.filesystem) openArtifact?.(openPath, { filesystem: file.filesystem });
7101
- else openArtifact?.(openPath);
7100
+ if (openPath) {
7101
+ if (file.filesystem) openArtifact?.(openPath, { filesystem: file.filesystem });
7102
+ else openArtifact?.(openPath);
7103
+ return;
7104
+ }
7105
+ if (openUrl) window.open(openUrl, "_blank", "noopener,noreferrer");
7102
7106
  };
7103
7107
  const openAttachmentFromKeyboard = (event) => {
7104
7108
  if (event.key !== "Enter" && event.key !== " ") return;
@@ -7112,9 +7116,9 @@ function PiTimelineMessage({ message, isLast, isStreaming, showThoughts, toolRen
7112
7116
  ...canOpen ? {
7113
7117
  role: "button",
7114
7118
  tabIndex: 0,
7115
- title: `Open ${openPath} in workspace`,
7116
- "aria-label": `Open ${file.filename ?? openPath} in workspace`,
7117
- "data-workspace-path": openPath,
7119
+ title: openPath ? `Open ${openPath} in workspace` : `Open ${file.filename ?? "attachment"}`,
7120
+ "aria-label": openPath ? `Open ${file.filename ?? openPath} in workspace` : `Open ${file.filename ?? "attachment"}`,
7121
+ ...openPath ? { "data-workspace-path": openPath } : {},
7118
7122
  onClick: openAttachment,
7119
7123
  onKeyDown: openAttachmentFromKeyboard
7120
7124
  } : void 0,
@@ -9702,12 +9706,6 @@ function parseBrowserPluginReloadDetail(detail) {
9702
9706
  return null;
9703
9707
  }
9704
9708
  }
9705
- function pluginReloadFailureMessage(message) {
9706
- const firstLine = message.trim().split(/\r?\n/).find((line) => line.trim().length > 0)?.trim() ?? "";
9707
- if (/^agent plugins reloaded\.?$/i.test(firstLine)) return null;
9708
- if (/^agent plugins will reload on the next message\.?$/i.test(firstLine)) return null;
9709
- return message;
9710
- }
9711
9709
  function shouldRefreshSessionListAfterEvent(event) {
9712
9710
  return event.type === "agent-end";
9713
9711
  }
@@ -9722,6 +9720,13 @@ var EMPTY_COMMANDS = [];
9722
9720
  var EMPTY_COMMAND_NAMES = [];
9723
9721
  var EMPTY_BLOCKERS = [];
9724
9722
  var RUN_REJECTED_NOTICE_ID = "run-rejected";
9723
+ function normalizeAgentPluginReloadResult(result) {
9724
+ if (typeof result !== "string") return result;
9725
+ const firstLine = result.trim().split(/\r?\n/).find((line) => line.trim().length > 0)?.trim() ?? "";
9726
+ if (/^(?:agent plugins|extensions) reloaded\.?$/i.test(firstLine)) return { message: result, reloaded: true };
9727
+ if (/^(?:agent plugins|extensions) will reload on the next message\.?$/i.test(firstLine)) return { message: result, reloaded: false };
9728
+ throw new Error(result);
9729
+ }
9725
9730
  function PiChatPanel({
9726
9731
  sessionId,
9727
9732
  extraCommands,
@@ -10049,20 +10054,15 @@ function PiChatPanel({
10049
10054
  }, [activeSessionId, addLocalNotice, externalSessionId, onSessionReset, sessions.create, sessions.delete]);
10050
10055
  const reloadAgentPlugins = useCallback18(async () => {
10051
10056
  if (!onReloadAgentPlugins) throw new Error("Agent plugin reload is not configured.");
10052
- return await onReloadAgentPlugins();
10057
+ return normalizeAgentPluginReloadResult(await onReloadAgentPlugins());
10053
10058
  }, [onReloadAgentPlugins]);
10054
10059
  const runPluginUpdate = useCallback18(async () => {
10055
10060
  setPluginUpdateState({ kind: "running" });
10056
10061
  try {
10057
- const message = await reloadAgentPlugins();
10058
- const failureMessage = pluginReloadFailureMessage(message);
10059
- if (failureMessage) {
10060
- setPluginUpdateState({ kind: "error", message: failureMessage });
10061
- return `Extension update failed: ${failureMessage}`;
10062
- }
10063
- setPluginUpdateState({ kind: "success", reloaded: !/will reload on the next message/i.test(message) });
10062
+ const result = await reloadAgentPlugins();
10063
+ setPluginUpdateState({ kind: "success", reloaded: result.reloaded });
10064
10064
  setServerSkillsRefreshKey((key) => key + 1);
10065
- return message;
10065
+ return result.message;
10066
10066
  } catch (error) {
10067
10067
  const message = errorMessage2(error, "Extension reload failed.");
10068
10068
  setPluginUpdateState({ kind: "error", message });
@@ -10220,7 +10220,7 @@ function PiChatPanel({
10220
10220
  }),
10221
10221
  resetSession,
10222
10222
  listCommands: () => registry.list(),
10223
- reloadAgentPlugins,
10223
+ reloadAgentPlugins: async () => (await reloadAgentPlugins()).message,
10224
10224
  pluginUpdate: { run: runPluginUpdate },
10225
10225
  openModelPicker,
10226
10226
  selectComposerModel,