@hachej/boring-agent 0.1.64 → 0.1.66

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.
@@ -0,0 +1,18 @@
1
+ // src/shared/events.ts
2
+ var AGENT_NOT_IMPLEMENTED_UNTIL_T1 = "ERR_NOT_IMPLEMENTED_UNTIL_T1";
3
+ function sessionStreamPath(sessionId) {
4
+ return `sessions/${sessionId}`;
5
+ }
6
+ var AgentNotImplementedError = class extends Error {
7
+ code = AGENT_NOT_IMPLEMENTED_UNTIL_T1;
8
+ constructor(message = "This agent capability is not implemented until T1.") {
9
+ super(message);
10
+ this.name = "AgentNotImplementedError";
11
+ }
12
+ };
13
+
14
+ export {
15
+ AGENT_NOT_IMPLEMENTED_UNTIL_T1,
16
+ sessionStreamPath,
17
+ AgentNotImplementedError
18
+ };
@@ -0,0 +1,96 @@
1
+ // src/shared/error-codes.ts
2
+ import { z } from "zod";
3
+ var ErrorCode = z.enum([
4
+ // Auth / config
5
+ "UNAUTHORIZED",
6
+ "MISSING_API_KEY",
7
+ "INVALID_API_KEY",
8
+ "OIDC_REFRESH_FAILED",
9
+ "VERCEL_AUTH_FAILED",
10
+ "CONFIG_INVALID",
11
+ // Workspace / path
12
+ "PATH_ESCAPE",
13
+ "PATH_ABSOLUTE",
14
+ "PATH_NULL_BYTE",
15
+ "PATH_SYMLINK_ESCAPE",
16
+ "PATH_NOT_FOUND",
17
+ "PATH_NOT_WRITABLE",
18
+ "WORKSPACE_UNINITIALIZED",
19
+ "WORKSPACE_NOT_READY",
20
+ // Agent runtime / provisioning
21
+ "AGENT_RUNTIME_NOT_READY",
22
+ "RUNTIME_PROVISIONING_FAILED",
23
+ "RUNTIME_PROVISIONING_LOCKED",
24
+ // Sandbox / exec
25
+ "BWRAP_UNAVAILABLE",
26
+ "BWRAP_TIMEOUT",
27
+ "OUTPUT_TRUNCATED",
28
+ "SANDBOX_NOT_READY",
29
+ "SANDBOX_EXPIRED",
30
+ "VERCEL_API_ERROR",
31
+ "REMOTE_WORKER_TIMEOUT",
32
+ "REMOTE_WORKER_STREAM_CLOSED",
33
+ "CIRCUIT_OPEN",
34
+ "ABORTED",
35
+ // Billing / metering
36
+ "PAYMENT_REQUIRED",
37
+ "MODEL_BUDGET_EXCEEDED",
38
+ "METERING_UNSUPPORTED_COMMAND",
39
+ // Session / bridge
40
+ "SESSION_NOT_FOUND",
41
+ "SESSION_LOCKED",
42
+ "STREAM_BUFFER_EVICTED",
43
+ "CURSOR_OUT_OF_RANGE",
44
+ "BRIDGE_COMMAND_INVALID",
45
+ // Tool
46
+ "TOOL_NOT_FOUND",
47
+ "TOOL_INVALID_INPUT",
48
+ "TOOL_EXECUTION_ERROR",
49
+ // Plugin
50
+ "PLUGIN_LOAD_FAILED",
51
+ "PLUGIN_NAME_COLLISION",
52
+ "PLUGIN_RUNTIME_REVISION_MISMATCH",
53
+ "PLUGIN_RUNTIME_PRIVATE_FILE",
54
+ "PLUGIN_RUNTIME_UNSAFE_IMPORT",
55
+ "PLUGIN_RUNTIME_TRANSFORM_FAILED",
56
+ "RUNTIME_PLUGIN_NOT_FOUND",
57
+ "RUNTIME_PLUGIN_ROUTE_NOT_FOUND",
58
+ "RUNTIME_PLUGIN_HANDLER_FAILED",
59
+ "RUNTIME_PLUGIN_LOAD_FAILED",
60
+ "RUNTIME_PLUGIN_RESPONSE_UNSUPPORTED",
61
+ // Runtime provisioning
62
+ "PROVISIONING_LAYOUT_FAILED",
63
+ "PROVISIONING_SKILLS_FAILED",
64
+ "PROVISIONING_TEMPLATES_FAILED",
65
+ "PROVISIONING_NODE_PREFLIGHT_FAILED",
66
+ "PROVISIONING_NPM_INSTALL_FAILED",
67
+ "PROVISIONING_UV_BOOTSTRAP_FAILED",
68
+ "PROVISIONING_UV_INSTALL_FAILED",
69
+ "PROVISIONING_ARTIFACT_FAILED",
70
+ // Internal
71
+ "ERR_NOT_IMPLEMENTED_UNTIL_T1",
72
+ "INTERNAL_ERROR"
73
+ ]);
74
+ var ERROR_CODES = ErrorCode.options;
75
+ var ApiErrorPayloadSchema = z.object({
76
+ code: ErrorCode,
77
+ message: z.string().min(1),
78
+ details: z.record(z.unknown()).optional()
79
+ });
80
+ var ApiErrorResponseSchema = z.object({
81
+ error: ApiErrorPayloadSchema
82
+ });
83
+ var ErrorLogFieldsSchema = z.object({
84
+ level: z.enum(["warn", "error"]),
85
+ code: ErrorCode,
86
+ prefix: z.string().min(1),
87
+ msg: z.string().min(1)
88
+ }).catchall(z.unknown());
89
+
90
+ export {
91
+ ErrorCode,
92
+ ERROR_CODES,
93
+ ApiErrorPayloadSchema,
94
+ ApiErrorResponseSchema,
95
+ ErrorLogFieldsSchema
96
+ };
@@ -1,16 +1,3 @@
1
- // src/shared/telemetry.ts
2
- var noopTelemetry = {
3
- capture() {
4
- }
5
- };
6
- function safeCapture(telemetry, event) {
7
- try {
8
- void Promise.resolve(telemetry.capture(event)).catch(() => {
9
- });
10
- } catch {
11
- }
12
- }
13
-
14
1
  // src/shared/validateTool.ts
15
2
  function validateTool(tool) {
16
3
  if (typeof tool !== "object" || tool === null) return null;
@@ -23,7 +10,5 @@ function validateTool(tool) {
23
10
  }
24
11
 
25
12
  export {
26
- noopTelemetry,
27
- safeCapture,
28
13
  validateTool
29
14
  };
@@ -0,0 +1,9 @@
1
+ import { u as AgentConfig, b as Agent } from '../harness-DN9KdrT7.js';
2
+ export { a as AGENT_NOT_IMPLEMENTED_UNTIL_T1, c as AgentActor, d as AgentCoreHarness, e as AgentCoreHarnessFactory, f as AgentCorePromptInput, g as AgentCoreSessionAdapter, h as AgentCoreSessionSnapshot, i as AgentEvent, k as AgentMessageContent, l as AgentMessagePart, m as AgentNotImplementedError, n as AgentReadiness, o as AgentReadinessStatus, p as AgentResolveInputResponse, q as AgentRuntimeAdapter, r as AgentSendInput, s as AgentStartReceipt, t as AgentStreamOptions } from '../harness-DN9KdrT7.js';
3
+ import '../piChatEvent-B6Lg9ft-.js';
4
+ import 'zod';
5
+ import '@mariozechner/pi-coding-agent';
6
+
7
+ declare function createAgent(config: AgentConfig): Agent;
8
+
9
+ export { Agent, AgentConfig, createAgent };
@@ -0,0 +1,15 @@
1
+ import {
2
+ createAgent
3
+ } from "../chunk-NKP5AR4C.js";
4
+ import {
5
+ AGENT_NOT_IMPLEMENTED_UNTIL_T1,
6
+ AgentNotImplementedError
7
+ } from "../chunk-WSQ5QNIY.js";
8
+ import "../chunk-4LXA7OOV.js";
9
+ import "../chunk-AJZHR626.js";
10
+ import "../chunk-XZKU7FBV.js";
11
+ export {
12
+ AGENT_NOT_IMPLEMENTED_UNTIL_T1,
13
+ AgentNotImplementedError,
14
+ createAgent
15
+ };
@@ -0,0 +1,17 @@
1
+ import {
2
+ createPiCodingAgentHarness,
3
+ createResourceSettingsManager,
4
+ deriveSourcePlugin,
5
+ mergePiPackageSources,
6
+ withPiHarnessDefaults
7
+ } from "./chunk-HHW2UNBK.js";
8
+ import "./chunk-AQBXNPMD.js";
9
+ import "./chunk-AJZHR626.js";
10
+ import "./chunk-XZKU7FBV.js";
11
+ export {
12
+ createPiCodingAgentHarness,
13
+ createResourceSettingsManager,
14
+ deriveSourcePlugin,
15
+ mergePiPackageSources,
16
+ withPiHarnessDefaults
17
+ };
@@ -1,14 +1,14 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import * as react from 'react';
3
2
  import { ComponentProps, HTMLAttributes, FormEvent, ReactNode, ComponentType } from 'react';
4
3
  import { FileUIPart, ChatStatus, UIMessage } from 'ai';
5
- import { T as ToolUiMetadata, B as BoringChatPart, d as BoringChatMessage, m as PiChatStatus, r as QueuedUserMessage, C as ChatError, P as PiChatEvent, o as PromptPayload, p as PromptReceipt, F as FollowUpPayload, i as FollowUpReceipt, Q as QueueClearPayload, q as QueueClearReceipt, I as InterruptPayload, e as CommandReceipt, S as StopPayload, s as StopReceipt } from '../piChatEvent-JbwYVBZj.js';
6
- import { e as SessionSummary } from '../chatSubmitPayload-DHqQL2wD.js';
4
+ import { T as ToolUiMetadata, B as BoringChatPart, e as BoringChatMessage, k as PiChatStatus, Q as QueuedUserMessage, C as ChatError, P as PiChatEvent, n as SessionSummary } from '../piChatEvent-B6Lg9ft-.js';
5
+ import { P as PromptPayload, c as PromptReceipt, F as FollowUpPayload, a as FollowUpReceipt, Q as QueueClearPayload, d as QueueClearReceipt, I as InterruptPayload, C as CommandReceipt, S as StopPayload, e as StopReceipt } from '../piChatCommand-C5ZM-AMG.js';
7
6
  import { InputGroupAddon, InputGroupButton, InputGroupTextarea, Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from '@hachej/boring-ui-kit';
8
7
  import { Streamdown } from 'streamdown';
9
8
  import { StickToBottom } from 'use-stick-to-bottom';
10
9
  import { ClassValue } from 'clsx';
11
10
  import 'zod';
11
+ import '../chatSubmitPayload-DwOHyiqR.js';
12
12
 
13
13
  interface UploadFileOptions {
14
14
  apiBaseUrl?: string;
@@ -29,7 +29,7 @@ type PromptInputFilePart = FileUIPart & {
29
29
  };
30
30
 
31
31
  type PromptInputFooterProps = ComponentProps<typeof InputGroupAddon>;
32
- declare const PromptInputFooter: ({ align, className, ...props }: PromptInputFooterProps) => react_jsx_runtime.JSX.Element;
32
+ declare const PromptInputFooter: ({ align, className, ...props }: PromptInputFooterProps) => react.JSX.Element;
33
33
 
34
34
  interface PromptInputMessage {
35
35
  text: string;
@@ -54,14 +54,14 @@ type PromptInputProps = Omit<HTMLAttributes<HTMLFormElement>, "onSubmit" | "onEr
54
54
  path?: string;
55
55
  }>;
56
56
  };
57
- declare const PromptInput: ({ className, accept, multiple, globalDrop, syncHiddenInput, maxFiles, maxFileSize, onError, onSubmit, onUploadFile, children, ...props }: PromptInputProps) => react_jsx_runtime.JSX.Element;
57
+ declare const PromptInput: ({ className, accept, multiple, globalDrop, syncHiddenInput, maxFiles, maxFileSize, onError, onSubmit, onUploadFile, children, ...props }: PromptInputProps) => react.JSX.Element;
58
58
  type PromptInputTextareaProps = ComponentProps<typeof InputGroupTextarea>;
59
- declare const PromptInputTextarea: ({ onChange, onKeyDown, className, placeholder, ...props }: PromptInputTextareaProps) => react_jsx_runtime.JSX.Element;
59
+ declare const PromptInputTextarea: ({ onChange, onKeyDown, className, placeholder, ...props }: PromptInputTextareaProps) => react.JSX.Element;
60
60
  type PromptInputSubmitProps = ComponentProps<typeof InputGroupButton> & {
61
61
  status?: ChatStatus;
62
62
  onStop?: () => void;
63
63
  };
64
- declare const PromptInputSubmit: ({ className, variant, size, status, onStop, onClick, children, ...props }: PromptInputSubmitProps) => react_jsx_runtime.JSX.Element;
64
+ declare const PromptInputSubmit: ({ className, variant, size, status, onStop, onClick, children, ...props }: PromptInputSubmitProps) => react.JSX.Element;
65
65
 
66
66
  /**
67
67
  * Extended-thinking budget. Sent through the agent runtime to providers that
@@ -143,7 +143,7 @@ interface ChatEmptyStateProps {
143
143
  footer?: ReactNode;
144
144
  className?: string;
145
145
  }
146
- declare function ChatEmptyState({ eyebrow, title, description, suggestions, onSelect, footer, className, }: ChatEmptyStateProps): react_jsx_runtime.JSX.Element;
146
+ declare function ChatEmptyState({ eyebrow, title, description, suggestions, onSelect, footer, className, }: ChatEmptyStateProps): react.JSX.Element;
147
147
 
148
148
  interface ParsedCommand {
149
149
  name: string;
@@ -520,7 +520,7 @@ interface SessionListProps {
520
520
  onClose?: () => void;
521
521
  className?: string;
522
522
  }
523
- declare function SessionList({ sessions, activeId, loading, onSwitch, onCreate, onDelete, onLoadMore, hasMore, loadingMore, onClose, className, }: SessionListProps): react_jsx_runtime.JSX.Element;
523
+ declare function SessionList({ sessions, activeId, loading, onSwitch, onCreate, onDelete, onLoadMore, hasMore, loadingMore, onClose, className, }: SessionListProps): react.JSX.Element;
524
524
  declare const SessionBrowser: typeof SessionList;
525
525
 
526
526
  interface PiSessionSearchItem {
@@ -665,7 +665,7 @@ interface PiChatPanelProps<TComposerBlocker extends ComposerBlocker = ComposerBl
665
665
  * knowing what the code means or what the action does. */
666
666
  renderNoticeAction?: (notice: PiChatRuntimeNotice) => ReactNode;
667
667
  }
668
- declare function PiChatPanel<TComposerBlocker extends ComposerBlocker = ComposerBlocker>({ sessionId, extraCommands, apiBaseUrl, workspaceId, storageScope, requestHeaders, storage, fetch, className, chrome, debug, showSessions, hotReloadEnabled, suggestions, emptyState, emptyPlacement, composerPlaceholder, initialDraft, autoSubmitInitialDraft, onDraftRestored, onAutoSubmitInitialDraftAccepted, onAutoSubmitInitialDraftSettled, model, defaultModel, availableModels, hideDefaultModelOption, hideComposerSettings, suppressPreSubmitCancelledWarning, thinkingLevel, thinkingControl, serverResourcesEnabled, mentionedFiles, commands, excludeBuiltinCommands, toolRenderers, createRemoteSession, remoteSessionOptions, hydrateMessages, allowPromptDuringInitialHydration, workspaceWarmupStatus, onSessionReset, onBeforeSubmit, onReloadAgentPlugins, onCommandResult, onComposerWarning, onMentionedFilesConsumed, onPromptSubmitStarted, onData, onOpenArtifact, composerBlockers, onComposerStop, onComposerBlockerAction, onTurnComplete, renderNoticeAction, }: PiChatPanelProps<TComposerBlocker>): react_jsx_runtime.JSX.Element;
668
+ declare function PiChatPanel<TComposerBlocker extends ComposerBlocker = ComposerBlocker>({ sessionId, extraCommands, apiBaseUrl, workspaceId, storageScope, requestHeaders, storage, fetch, className, chrome, debug, showSessions, hotReloadEnabled, suggestions, emptyState, emptyPlacement, composerPlaceholder, initialDraft, autoSubmitInitialDraft, onDraftRestored, onAutoSubmitInitialDraftAccepted, onAutoSubmitInitialDraftSettled, model, defaultModel, availableModels, hideDefaultModelOption, hideComposerSettings, suppressPreSubmitCancelledWarning, thinkingLevel, thinkingControl, serverResourcesEnabled, mentionedFiles, commands, excludeBuiltinCommands, toolRenderers, createRemoteSession, remoteSessionOptions, hydrateMessages, allowPromptDuringInitialHydration, workspaceWarmupStatus, onSessionReset, onBeforeSubmit, onReloadAgentPlugins, onCommandResult, onComposerWarning, onMentionedFilesConsumed, onPromptSubmitStarted, onData, onOpenArtifact, composerBlockers, onComposerStop, onComposerBlockerAction, onTurnComplete, renderNoticeAction, }: PiChatPanelProps<TComposerBlocker>): react.JSX.Element;
669
669
 
670
670
  interface DebugDrawerProps {
671
671
  apiBaseUrl?: string;
@@ -677,7 +677,7 @@ interface DebugDrawerProps {
677
677
  width: number;
678
678
  onWidthChange: (w: number) => void;
679
679
  }
680
- declare function DebugDrawer({ apiBaseUrl, fetch, sessionId, messages, requestHeaders, storageScope, width, onWidthChange }: DebugDrawerProps): react_jsx_runtime.JSX.Element;
680
+ declare function DebugDrawer({ apiBaseUrl, fetch, sessionId, messages, requestHeaders, storageScope, width, onWidthChange }: DebugDrawerProps): react.JSX.Element;
681
681
 
682
682
  interface OpenArtifactOptions {
683
683
  filesystem?: string;
@@ -687,7 +687,7 @@ interface ArtifactOpenProviderProps {
687
687
  onOpenArtifact?: OpenArtifactHandler;
688
688
  children: ReactNode;
689
689
  }
690
- declare function ArtifactOpenProvider({ onOpenArtifact, children }: ArtifactOpenProviderProps): react_jsx_runtime.JSX.Element;
690
+ declare function ArtifactOpenProvider({ onOpenArtifact, children }: ArtifactOpenProviderProps): react.JSX.Element;
691
691
  declare function useOpenArtifact(): OpenArtifactHandler | null;
692
692
 
693
693
  interface AgentCommandContribution {
@@ -717,32 +717,32 @@ interface ToolCallGroupProps {
717
717
  tools: GroupedToolEntry[];
718
718
  mergedToolRenderers: ToolRendererOverrides;
719
719
  }
720
- declare const ToolCallGroup: react.MemoExoticComponent<({ tools, mergedToolRenderers }: ToolCallGroupProps) => react_jsx_runtime.JSX.Element | null>;
720
+ declare const ToolCallGroup: react.MemoExoticComponent<({ tools, mergedToolRenderers }: ToolCallGroupProps) => react.JSX.Element | null>;
721
721
 
722
722
  type MessageProps = HTMLAttributes<HTMLDivElement> & {
723
723
  from: UIMessage["role"];
724
724
  };
725
- declare const Message: ({ className, from, ...props }: MessageProps) => react_jsx_runtime.JSX.Element;
725
+ declare const Message: ({ className, from, ...props }: MessageProps) => react.JSX.Element;
726
726
  type MessageContentProps = HTMLAttributes<HTMLDivElement>;
727
- declare const MessageContent: ({ children, className, ...props }: MessageContentProps) => react_jsx_runtime.JSX.Element;
727
+ declare const MessageContent: ({ children, className, ...props }: MessageContentProps) => react.JSX.Element;
728
728
  type MessageActionsProps = ComponentProps<"div">;
729
- declare const MessageActions: ({ className, children, ...props }: MessageActionsProps) => react_jsx_runtime.JSX.Element;
729
+ declare const MessageActions: ({ className, children, ...props }: MessageActionsProps) => react.JSX.Element;
730
730
  type MessageActionProps = ComponentProps<typeof Button> & {
731
731
  tooltip?: string;
732
732
  label?: string;
733
733
  };
734
- declare const MessageAction: ({ tooltip, children, label, variant, size, ...props }: MessageActionProps) => react_jsx_runtime.JSX.Element;
734
+ declare const MessageAction: ({ tooltip, children, label, variant, size, ...props }: MessageActionProps) => react.JSX.Element;
735
735
  type MessageResponseProps = ComponentProps<typeof Streamdown>;
736
- declare const MessageResponse: react.MemoExoticComponent<({ className, shikiTheme, components, ...props }: MessageResponseProps) => react_jsx_runtime.JSX.Element>;
736
+ declare const MessageResponse: react.MemoExoticComponent<({ className, shikiTheme, components, ...props }: MessageResponseProps) => react.JSX.Element>;
737
737
 
738
738
  type ConversationProps = ComponentProps<typeof StickToBottom> & {
739
739
  onScrollToBottomReady?: (scrollToBottom: () => void) => void;
740
740
  };
741
- declare const Conversation: ({ className, children, onScrollToBottomReady, ...props }: ConversationProps) => react_jsx_runtime.JSX.Element;
741
+ declare const Conversation: ({ className, children, onScrollToBottomReady, ...props }: ConversationProps) => react.JSX.Element;
742
742
  type ConversationContentProps = ComponentProps<typeof StickToBottom.Content>;
743
- declare const ConversationContent: ({ className, ...props }: ConversationContentProps) => react_jsx_runtime.JSX.Element;
743
+ declare const ConversationContent: ({ className, ...props }: ConversationContentProps) => react.JSX.Element;
744
744
  type ConversationScrollButtonProps = ComponentProps<typeof Button>;
745
- declare const ConversationScrollButton: ({ className, ...props }: ConversationScrollButtonProps) => false | react_jsx_runtime.JSX.Element;
745
+ declare const ConversationScrollButton: ({ className, ...props }: ConversationScrollButtonProps) => false | react.JSX.Element;
746
746
 
747
747
  type ReasoningProps = ComponentProps<typeof Collapsible> & {
748
748
  isStreaming?: boolean;
@@ -752,22 +752,22 @@ type ReasoningProps = ComponentProps<typeof Collapsible> & {
752
752
  duration?: number;
753
753
  autoClose?: boolean;
754
754
  };
755
- declare const Reasoning: react.MemoExoticComponent<({ className, isStreaming, open, defaultOpen, onOpenChange, duration: durationProp, autoClose, children, ...props }: ReasoningProps) => react_jsx_runtime.JSX.Element>;
755
+ declare const Reasoning: react.MemoExoticComponent<({ className, isStreaming, open, defaultOpen, onOpenChange, duration: durationProp, autoClose, children, ...props }: ReasoningProps) => react.JSX.Element>;
756
756
  type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {
757
757
  getThinkingMessage?: (isStreaming: boolean, duration?: number) => ReactNode;
758
758
  };
759
- declare const ReasoningTrigger: react.MemoExoticComponent<({ className, children, getThinkingMessage, ...props }: ReasoningTriggerProps) => react_jsx_runtime.JSX.Element>;
759
+ declare const ReasoningTrigger: react.MemoExoticComponent<({ className, children, getThinkingMessage, ...props }: ReasoningTriggerProps) => react.JSX.Element>;
760
760
  type ReasoningContentProps = ComponentProps<typeof CollapsibleContent> & {
761
761
  children: string;
762
762
  };
763
- declare const ReasoningContent: react.MemoExoticComponent<({ className, children, ...props }: ReasoningContentProps) => react_jsx_runtime.JSX.Element>;
763
+ declare const ReasoningContent: react.MemoExoticComponent<({ className, children, ...props }: ReasoningContentProps) => react.JSX.Element>;
764
764
 
765
765
  type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
766
766
  code: string;
767
767
  language: string;
768
768
  showLineNumbers?: boolean;
769
769
  };
770
- declare const CodeBlock: ({ code, language, showLineNumbers, className, children, ...props }: CodeBlockProps) => react_jsx_runtime.JSX.Element;
770
+ declare const CodeBlock: ({ code, language, showLineNumbers, className, children, ...props }: CodeBlockProps) => react.JSX.Element;
771
771
 
772
772
  declare function cn(...inputs: ClassValue[]): string;
773
773
 
@@ -4,7 +4,6 @@ import {
4
4
  } from "../chunk-DGRKMMXO.js";
5
5
  import {
6
6
  CommandReceiptSchema,
7
- ErrorCode,
8
7
  FollowUpReceiptSchema,
9
8
  PiChatSnapshotSchema,
10
9
  PiChatStreamFrameSchema,
@@ -13,7 +12,10 @@ import {
13
12
  StopReceiptSchema,
14
13
  extractToolUiMetadata,
15
14
  sanitizeToolUiMetadata
16
- } from "../chunk-UPRDF2PB.js";
15
+ } from "../chunk-4LXA7OOV.js";
16
+ import {
17
+ ErrorCode
18
+ } from "../chunk-XZKU7FBV.js";
17
19
  import {
18
20
  DebugDrawer,
19
21
  cn,
@@ -2662,7 +2664,17 @@ function useChatModelSelection({
2662
2664
  setModelState(next);
2663
2665
  writePiComposerModelSelection(next, { storageScope, storage });
2664
2666
  }, [storage, storageScope]);
2667
+ const discoveryKey = useMemo2(
2668
+ () => JSON.stringify({
2669
+ apiBaseUrl: apiBaseUrl ?? "",
2670
+ headers: Object.entries(requestHeaders ?? {}).sort(([a], [b]) => a.localeCompare(b)),
2671
+ storageScope: storageScope ?? ""
2672
+ }),
2673
+ [apiBaseUrl, requestHeaders, storageScope]
2674
+ );
2665
2675
  const [availableModels, setAvailableModels] = useState7([]);
2676
+ const [loaded, setLoaded] = useState7(!enabled);
2677
+ const [loadedDiscoveryKey, setLoadedDiscoveryKey] = useState7(enabled ? null : discoveryKey);
2666
2678
  useEffect5(() => {
2667
2679
  if (loadedSettingsSourceRef.current.storage !== storage || loadedSettingsSourceRef.current.storageScope !== storageScope) return;
2668
2680
  if (!userSelectedModel || !model) return;
@@ -2680,14 +2692,31 @@ function useChatModelSelection({
2680
2692
  setModelState(defaultModel);
2681
2693
  }, [defaultModel]);
2682
2694
  useEffect5(() => {
2683
- if (!enabled) return;
2695
+ if (!enabled) {
2696
+ setLoaded(true);
2697
+ setLoadedDiscoveryKey(discoveryKey);
2698
+ return;
2699
+ }
2684
2700
  let aborted = false;
2701
+ setLoaded(false);
2685
2702
  const nextFetch = fetchImpl ?? globalThis.fetch.bind(globalThis);
2686
2703
  nextFetch(agentResourceUrl(apiBaseUrl, "/api/v1/agent/models"), {
2687
2704
  headers: scopedHeaders2(requestHeaders, storageScope)
2688
2705
  }).then((res) => res.ok ? res.json() : null).then((payload) => {
2689
- if (aborted || !payload?.models) return;
2706
+ if (aborted) return;
2707
+ if (!payload?.models) {
2708
+ userSelectedModelRef.current = false;
2709
+ setUserSelectedModel(false);
2710
+ setAvailableModels([]);
2711
+ setModelState(null);
2712
+ writePiComposerModelSelection(null, { storageScope, storage });
2713
+ setLoadedDiscoveryKey(discoveryKey);
2714
+ setLoaded(true);
2715
+ return;
2716
+ }
2690
2717
  setAvailableModels(payload.models);
2718
+ setLoadedDiscoveryKey(discoveryKey);
2719
+ setLoaded(true);
2691
2720
  const available = payload.models.filter((m) => m.available);
2692
2721
  setModelState((current) => {
2693
2722
  const currentAvailable = current ? available.some((m) => m.provider === current.provider && m.id === current.id) : false;
@@ -2695,14 +2724,24 @@ function useChatModelSelection({
2695
2724
  userSelectedModelRef.current = false;
2696
2725
  setUserSelectedModel(false);
2697
2726
  writePiComposerModelSelection(null, { storageScope, storage });
2698
- return payload.defaultModel ? { provider: payload.defaultModel.provider, id: payload.defaultModel.id } : null;
2727
+ if (payload.defaultModel) return { provider: payload.defaultModel.provider, id: payload.defaultModel.id };
2728
+ const firstAvailable = available[0];
2729
+ return firstAvailable ? { provider: firstAvailable.provider, id: firstAvailable.id } : null;
2699
2730
  });
2700
2731
  }).catch(() => {
2732
+ if (aborted) return;
2733
+ userSelectedModelRef.current = false;
2734
+ setUserSelectedModel(false);
2735
+ setAvailableModels([]);
2736
+ setModelState(null);
2737
+ writePiComposerModelSelection(null, { storageScope, storage });
2738
+ setLoadedDiscoveryKey(discoveryKey);
2739
+ setLoaded(true);
2701
2740
  });
2702
2741
  return () => {
2703
2742
  aborted = true;
2704
2743
  };
2705
- }, [apiBaseUrl, enabled, fetchImpl, requestHeaders, storage, storageScope]);
2744
+ }, [apiBaseUrl, discoveryKey, enabled, fetchImpl, requestHeaders, storage, storageScope]);
2706
2745
  useEffect5(() => {
2707
2746
  const onChange = (event) => {
2708
2747
  const next = parseModelSelection(event.detail);
@@ -2711,7 +2750,10 @@ function useChatModelSelection({
2711
2750
  globalThis.addEventListener?.("boring:model-change", onChange);
2712
2751
  return () => globalThis.removeEventListener?.("boring:model-change", onChange);
2713
2752
  }, [setModel]);
2714
- return { availableModels, model, setModel };
2753
+ const currentDiscoveryLoaded = !enabled || loaded && loadedDiscoveryKey === discoveryKey;
2754
+ const currentAvailableModels = currentDiscoveryLoaded ? availableModels : [];
2755
+ const currentModel = currentDiscoveryLoaded ? model : null;
2756
+ return { availableModels: currentAvailableModels, loaded: currentDiscoveryLoaded, model: currentModel, setModel };
2715
2757
  }
2716
2758
  function agentResourceUrl(apiBaseUrl, path) {
2717
2759
  const base = apiBaseUrl?.replace(/\/$/, "") ?? "";
@@ -2727,6 +2769,11 @@ function scopedHeaders2(headers, storageScope) {
2727
2769
 
2728
2770
  // src/front/hooks/useServerCommands.ts
2729
2771
  import { useEffect as useEffect6, useRef as useRef7, useState as useState8 } from "react";
2772
+ function serverCommandErrorMessage(body, fallback) {
2773
+ if (typeof body.error === "string") return body.error;
2774
+ if (body.error && typeof body.error === "object" && typeof body.error.message === "string") return body.error.message;
2775
+ return fallback;
2776
+ }
2730
2777
  function toSlashCommand(command, getSessionId, apiBaseUrl, requestHeaders, fetchImpl) {
2731
2778
  return {
2732
2779
  name: command.name,
@@ -2747,7 +2794,7 @@ function toSlashCommand(command, getSessionId, apiBaseUrl, requestHeaders, fetch
2747
2794
  const body = await res.json().catch(() => ({}));
2748
2795
  if (typeof globalThis.dispatchEvent === "function") {
2749
2796
  globalThis.dispatchEvent(new CustomEvent(WORKSPACE_COMMAND_NOTIFY_EVENT, {
2750
- detail: { message: body.error ?? `/${command.name} failed`, tone: "error", command: command.name }
2797
+ detail: { message: serverCommandErrorMessage(body, `/${command.name} failed`), tone: "error", command: command.name }
2751
2798
  }));
2752
2799
  }
2753
2800
  }
@@ -5667,7 +5714,7 @@ function sortByUpdatedDesc(a, b) {
5667
5714
  return a.id.localeCompare(b.id);
5668
5715
  }
5669
5716
 
5670
- // ../../node_modules/.pnpm/@earendil-works+pi-tui@0.75.5/node_modules/@earendil-works/pi-tui/dist/fuzzy.js
5717
+ // ../../node_modules/.pnpm/@earendil-works+pi-tui@0.80.3/node_modules/@earendil-works/pi-tui/dist/fuzzy.js
5671
5718
  function fuzzyMatch(query, text) {
5672
5719
  const queryLower = query.toLowerCase();
5673
5720
  const textLower = text.toLowerCase();
@@ -6086,7 +6133,7 @@ function ComposerBlockerNotice({
6086
6133
  {
6087
6134
  role: "status",
6088
6135
  "aria-live": "polite",
6089
- className: noticeSurfaceClass("info", "mx-auto mb-2 w-full max-w-3xl text-xs"),
6136
+ className: noticeSurfaceClass("info", "relative z-20 mx-auto mb-2 w-full max-w-3xl text-xs"),
6090
6137
  children: [
6091
6138
  /* @__PURE__ */ jsx16("span", { children: label }),
6092
6139
  blocker?.actions?.map((action) => {
@@ -9154,7 +9201,7 @@ function PiChatComposerSurface({
9154
9201
  useLayoutEffect2(() => {
9155
9202
  resizeTextarea(textareaRef.current);
9156
9203
  }, [draft, resizeTextarea, textareaRef]);
9157
- return /* @__PURE__ */ jsxs30("div", { className: cn(chrome ? "px-4 pb-4 pt-2 sm:px-6 sm:pb-5" : "px-3 pb-2 pt-1"), children: [
9204
+ return /* @__PURE__ */ jsxs30("div", { className: cn("relative z-20", chrome ? "px-4 pb-4 pt-2 sm:px-6 sm:pb-5" : "px-3 pb-2 pt-1"), children: [
9158
9205
  /* @__PURE__ */ jsx32(
9159
9206
  "div",
9160
9207
  {
@@ -9738,6 +9785,7 @@ function PiChatPanel({
9738
9785
  const selectedPiSession = selectedChatState ? activePiSession : void 0;
9739
9786
  const chatStatePending = Boolean(activeSessionId && chatState && chatState.sessionId !== activeSessionId);
9740
9787
  const selectedSessionPending = Boolean(activeSessionId && !selectedChatState);
9788
+ const modelDiscoveryEnabled = serverResourcesEnabled && availableModels === void 0;
9741
9789
  const modelDiscovery = useChatModelSelection({
9742
9790
  apiBaseUrl,
9743
9791
  defaultModel,
@@ -9745,13 +9793,19 @@ function PiChatPanel({
9745
9793
  requestHeaders: normalizedRequestHeaders,
9746
9794
  storage,
9747
9795
  storageScope,
9748
- enabled: serverResourcesEnabled && availableModels === void 0
9796
+ enabled: modelDiscoveryEnabled
9749
9797
  });
9750
9798
  const selectedModel = model === void 0 ? modelDiscovery.model : model;
9751
9799
  const modelOptions = useMemo13(
9752
9800
  () => modelOptionsForSelection(availableModels ?? modelDiscovery.availableModels, selectedModel),
9753
9801
  [availableModels, modelDiscovery.availableModels, selectedModel]
9754
9802
  );
9803
+ const selectedModelAuthorizedByDiscovery = !modelDiscoveryEnabled || Boolean(selectedModel && modelDiscovery.availableModels.some(
9804
+ (modelOption) => modelOption.available && modelOption.provider === selectedModel.provider && modelOption.id === selectedModel.id
9805
+ ));
9806
+ const serverModelSelectionPending = modelDiscoveryEnabled && !modelDiscovery.loaded;
9807
+ const serverModelSelectionUnavailable = modelDiscoveryEnabled && modelDiscovery.loaded && !selectedModelAuthorizedByDiscovery;
9808
+ const serverModelSelectionReady = !serverModelSelectionPending && !serverModelSelectionUnavailable;
9755
9809
  const [storedThinkingLevel, setStoredThinkingLevel] = useState20(
9756
9810
  () => thinkingControl ? readPiComposerSettings({ storageScope, storage }).thinkingLevel : DEFAULT_THINKING
9757
9811
  );
@@ -10082,7 +10136,7 @@ function PiChatPanel({
10082
10136
  insertSlashCommand(name);
10083
10137
  }, [dismissSlash, insertSlashCommand, openModelPicker, openThinkingPicker, setComposerDraft]);
10084
10138
  const policy = useMemo13(() => {
10085
- if (!selectedPiSession || !activeChatSessionId) return void 0;
10139
+ if (!selectedPiSession || !activeChatSessionId || !serverModelSelectionReady) return void 0;
10086
10140
  const policySession = {
10087
10141
  getState: () => {
10088
10142
  const state = selectedPiSession.getState();
@@ -10147,7 +10201,7 @@ function PiChatPanel({
10147
10201
  onMentionedFilesConsumed?.();
10148
10202
  }
10149
10203
  });
10150
- }, [activeChatSessionId, addLocalNotice, allowPromptDuringInitialHydration, clearMentionedFiles, composerBlocked, composerBlockerLabel, effectiveMentionedFiles, markLocalSubmitted, onBeforeSubmit, onCommandResult, onComposerWarning, onMentionedFilesConsumed, onPromptSubmitStarted, openModelPicker, openThinkingPicker, registry, reloadAgentPlugins, resetSession, runPluginUpdate, selectComposerModel, selectComposerThinking, selectedModel, selectedPiSession, selectedThinking, setComposerDraft, submitThinkingControl, suppressPreSubmitCancelledWarning]);
10204
+ }, [activeChatSessionId, addLocalNotice, allowPromptDuringInitialHydration, clearMentionedFiles, composerBlocked, composerBlockerLabel, effectiveMentionedFiles, markLocalSubmitted, onBeforeSubmit, onCommandResult, onComposerWarning, onMentionedFilesConsumed, onPromptSubmitStarted, openModelPicker, openThinkingPicker, registry, reloadAgentPlugins, resetSession, runPluginUpdate, selectComposerModel, selectComposerThinking, selectedModel, selectedPiSession, selectedThinking, serverModelSelectionReady, setComposerDraft, submitThinkingControl, suppressPreSubmitCancelledWarning]);
10151
10205
  const surfaceRunRejected = useCallback18((error) => {
10152
10206
  const errorCode = piChatErrorCode(error);
10153
10207
  dropLocalNotice(RUN_REJECTED_NOTICE_ID);
@@ -10292,10 +10346,12 @@ function PiChatPanel({
10292
10346
  const initialHydrationPromptAllowed = Boolean(
10293
10347
  allowPromptDuringInitialHydration && selectedChatState && selectedChatState.status === "hydrating" && !selectedChatState.hydrated && selectedChatState.history.messageCount === 0 && selectedChatState.committedMessages.length === 0 && selectedChatState.queue.followUps.length === 0 && Object.keys(selectedChatState.optimisticOutbox).length === 0 && !selectedChatState.streamingMessage
10294
10348
  );
10349
+ const noDiscoveredModelAvailable = modelDiscoveryEnabled && modelDiscovery.loaded && modelDiscovery.availableModels.every((modelOption) => !modelOption.available);
10350
+ const modelSelectionBlocked = serverModelSelectionPending || serverModelSelectionUnavailable || noDiscoveredModelAvailable;
10295
10351
  const disabled = !policy || sessionsLoading || composerBlocked;
10296
10352
  const isStreaming = isPiBusyStatus(status);
10297
10353
  const submitStatus = initialHydrationPromptAllowed ? "ready" : toPromptSubmitStatus(status);
10298
- const submitDisabled = !policy || sessionsLoading || composerBlocked && !isStreaming;
10354
+ const submitDisabled = !policy || sessionsLoading || modelSelectionBlocked || composerBlocked && !isStreaming;
10299
10355
  const mergedToolRenderers = useMemo13(() => mergeShadcnToolRenderers(toolRenderers), [toolRenderers]);
10300
10356
  const debugMessages = useMemo13(() => messages.map(toDebugUiMessage), [messages]);
10301
10357
  const onTextareaChange = useCallback18((event) => {
@@ -10314,13 +10370,6 @@ function PiChatPanel({
10314
10370
  window.dispatchEvent(new CustomEvent("boring:chat-session-status", {
10315
10371
  detail: { sessionId: activeChatSessionId, working: isStreaming }
10316
10372
  }));
10317
- if (!isStreaming) return;
10318
- const sessionId2 = activeChatSessionId;
10319
- return () => {
10320
- window.dispatchEvent(new CustomEvent("boring:chat-session-status", {
10321
- detail: { sessionId: sessionId2, working: false }
10322
- }));
10323
- };
10324
10373
  }, [activeChatSessionId, isStreaming]);
10325
10374
  const onTextareaKeyDown = useCallback18((event) => {
10326
10375
  if (event.key === "Escape" && isStreaming) {