@axhub/acp 0.1.0 → 0.1.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.
Files changed (203) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +4 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/next-minimal-server.js.nft.json +1 -1
  6. package/.next/next-server.js.nft.json +1 -1
  7. package/.next/routes-manifest.json +28 -0
  8. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/server/app/_global-error.html +1 -1
  10. package/.next/server/app/_global-error.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/_not-found.html +1 -1
  19. package/.next/server/app/_not-found.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  21. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  23. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  25. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  26. package/.next/server/app/api/acp/capabilities/route.js +5 -3
  27. package/.next/server/app/api/acp/capabilities/route.js.nft.json +1 -1
  28. package/.next/server/app/api/acp/commands/route.js +1 -1
  29. package/.next/server/app/api/acp/commands/route.js.nft.json +1 -1
  30. package/.next/server/app/api/acp/runtime/route.js.nft.json +1 -1
  31. package/.next/server/app/api/chat/cancel/route/app-paths-manifest.json +3 -0
  32. package/.next/server/app/api/chat/cancel/route/build-manifest.json +9 -0
  33. package/.next/server/app/api/chat/cancel/route/server-reference-manifest.json +4 -0
  34. package/.next/server/app/api/chat/cancel/route.js +11 -0
  35. package/.next/server/app/api/chat/cancel/route.js.nft.json +1 -0
  36. package/.next/server/app/api/chat/cancel/route_client-reference-manifest.js +3 -0
  37. package/.next/server/app/api/chat/resume/[streamId]/route/app-paths-manifest.json +3 -0
  38. package/.next/server/app/api/chat/resume/[streamId]/route/build-manifest.json +9 -0
  39. package/.next/server/app/api/chat/resume/[streamId]/route/server-reference-manifest.json +4 -0
  40. package/.next/server/app/api/chat/resume/[streamId]/route.js +11 -0
  41. package/.next/server/app/api/chat/resume/[streamId]/route.js.nft.json +1 -0
  42. package/.next/server/app/api/chat/resume/[streamId]/route_client-reference-manifest.js +3 -0
  43. package/.next/server/app/api/chat/route.js +5 -3
  44. package/.next/server/app/api/chat/route.js.nft.json +1 -1
  45. package/.next/server/app/api/conversations/[threadId]/messages/route.js +4 -2
  46. package/.next/server/app/api/conversations/[threadId]/messages/route.js.nft.json +1 -1
  47. package/.next/server/app/api/conversations/[threadId]/route.js +2 -2
  48. package/.next/server/app/api/conversations/[threadId]/route.js.nft.json +1 -1
  49. package/.next/server/app/api/conversations/[threadId]/runtime/route/app-paths-manifest.json +3 -0
  50. package/.next/server/app/api/conversations/[threadId]/runtime/route/build-manifest.json +9 -0
  51. package/.next/server/app/api/conversations/[threadId]/runtime/route/server-reference-manifest.json +4 -0
  52. package/.next/server/app/api/conversations/[threadId]/runtime/route.js +11 -0
  53. package/.next/server/app/api/conversations/[threadId]/runtime/route.js.nft.json +1 -0
  54. package/.next/server/app/api/conversations/[threadId]/runtime/route_client-reference-manifest.js +3 -0
  55. package/.next/server/app/api/conversations/route.js +2 -2
  56. package/.next/server/app/api/conversations/route.js.nft.json +1 -1
  57. package/.next/server/app/api/local-files/image/route.js.nft.json +1 -1
  58. package/.next/server/app/api/local-files/open/route.js.nft.json +1 -1
  59. package/.next/server/app/api/output-artifacts/thread/route/app-paths-manifest.json +3 -0
  60. package/.next/server/app/api/output-artifacts/thread/route/build-manifest.json +9 -0
  61. package/.next/server/app/api/output-artifacts/thread/route/server-reference-manifest.json +4 -0
  62. package/.next/server/app/api/output-artifacts/thread/route.js +8 -0
  63. package/.next/server/app/api/output-artifacts/thread/route.js.nft.json +1 -0
  64. package/.next/server/app/api/output-artifacts/thread/route_client-reference-manifest.js +3 -0
  65. package/.next/server/app/api/output-artifacts/workspace/route.js +1 -1
  66. package/.next/server/app/api/output-artifacts/workspace/route.js.nft.json +1 -1
  67. package/.next/server/app/api/tools/image-generation/files/[id]/route.js.nft.json +1 -1
  68. package/.next/server/app/api/tools/image-generation/records/route.js.nft.json +1 -1
  69. package/.next/server/app/api/tools/user-choice/route.js.nft.json +1 -1
  70. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  71. package/.next/server/app/page.js +2 -2
  72. package/.next/server/app/page.js.nft.json +1 -1
  73. package/.next/server/app/page_client-reference-manifest.js +1 -1
  74. package/.next/server/app/session/[provider]/[sessionId]/page.js +1 -1
  75. package/.next/server/app/session/[provider]/[sessionId]/page.js.nft.json +1 -1
  76. package/.next/server/app/session/[provider]/[sessionId]/page_client-reference-manifest.js +1 -1
  77. package/.next/server/app/thread/[threadId]/page.js +1 -1
  78. package/.next/server/app/thread/[threadId]/page.js.nft.json +1 -1
  79. package/.next/server/app/thread/[threadId]/page_client-reference-manifest.js +1 -1
  80. package/.next/server/app-paths-manifest.json +4 -0
  81. package/.next/server/chunks/0zjb_server_app_api_conversations_[threadId]_runtime_route_actions_08lhdqs.js +3 -0
  82. package/.next/server/chunks/[root-of-the-server]__04pn6ap._.js +3 -0
  83. package/.next/server/chunks/[root-of-the-server]__0aovkxs._.js +3 -0
  84. package/.next/server/chunks/[root-of-the-server]__0c.r6ru._.js +76 -0
  85. package/.next/server/chunks/[root-of-the-server]__0gmxr~m._.js +3 -0
  86. package/.next/server/chunks/[root-of-the-server]__0iokgmz._.js +1 -1
  87. package/.next/server/chunks/[root-of-the-server]__0j-lxr4._.js +1 -1
  88. package/.next/server/chunks/[root-of-the-server]__0lbwo2g._.js +3 -0
  89. package/.next/server/chunks/[root-of-the-server]__0ly6hop._.js +1 -1
  90. package/.next/server/chunks/[root-of-the-server]__0ml.1wa._.js +3 -0
  91. package/.next/server/chunks/[root-of-the-server]__0o2epta._.js +3 -0
  92. package/.next/server/chunks/[root-of-the-server]__0os92l7._.js +3 -0
  93. package/.next/server/chunks/[root-of-the-server]__0tmhg7j._.js +1 -1
  94. package/.next/server/chunks/[root-of-the-server]__0txmfnw._.js +2 -2
  95. package/.next/server/chunks/[root-of-the-server]__0wo0b8z._.js +1 -1
  96. package/.next/server/chunks/[root-of-the-server]__0xh8d4~._.js +3 -0
  97. package/.next/server/chunks/[root-of-the-server]__0zmyki-._.js +3 -0
  98. package/.next/server/chunks/[root-of-the-server]__0zn3~pq._.js +3 -0
  99. package/.next/server/chunks/[root-of-the-server]__13xepwb._.js +3 -0
  100. package/.next/server/chunks/_0_9_730._.js +107 -0
  101. package/.next/server/chunks/_0gx~6n6._.js +107 -0
  102. package/.next/server/chunks/_next-internal_server_app_api_chat_cancel_route_actions_0hdg4o_.js +3 -0
  103. package/.next/server/chunks/_next-internal_server_app_api_chat_resume_[streamId]_route_actions_12ynw6q.js +3 -0
  104. package/.next/server/chunks/_next-internal_server_app_api_output-artifacts_thread_route_actions_04~2mo7.js +3 -0
  105. package/.next/server/chunks/lib_conversations_store_ts_0gzcj38._.js +4 -4
  106. package/.next/server/chunks/node_modules_0nyqhq8._.js +3 -0
  107. package/.next/server/chunks/ssr/{[root-of-the-server]__0piffp7._.js → [root-of-the-server]__09wwymw._.js} +2 -2
  108. package/.next/server/chunks/ssr/{[root-of-the-server]__0488vn3._.js → [root-of-the-server]__0n6oe29._.js} +1 -1
  109. package/.next/server/chunks/ssr/{[root-of-the-server]__0icm-_h._.js → [root-of-the-server]__0niwg81._.js} +2 -2
  110. package/.next/server/chunks/ssr/_03.pm1z._.js +18 -16
  111. package/.next/server/chunks/ssr/_0txwi90._.js +1 -1
  112. package/.next/server/chunks/ssr/lib_conversations_store_ts_0-pd6d3._.js +2 -2
  113. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js +1 -1
  114. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_02suzhc.js +2 -2
  115. package/.next/server/functions-config-manifest.json +3 -0
  116. package/.next/server/instrumentation.js.nft.json +1 -1
  117. package/.next/server/middleware-build-manifest.js +3 -3
  118. package/.next/server/pages/404.html +1 -1
  119. package/.next/server/pages/500.html +1 -1
  120. package/.next/static/chunks/0btc2281yau9i.js +104 -0
  121. package/.next/static/chunks/0c~b2_-vk17t5.css +1 -0
  122. package/README.md +2 -2
  123. package/dist/components/assistant-ui/acp-command-menu.mjs +42 -9
  124. package/dist/components/assistant-ui/acp-elicitation-option-list.mjs +1 -1
  125. package/dist/components/assistant-ui/file.mjs +2 -2
  126. package/dist/components/assistant-ui/image-generation-settings-dialog.mjs +25 -6
  127. package/dist/components/assistant-ui/image.mjs +2 -2
  128. package/dist/components/assistant-ui/markdown-text.mjs +3 -3
  129. package/dist/components/assistant-ui/thread/composer.d.ts +1 -1
  130. package/dist/components/assistant-ui/thread/composer.mjs +37 -3
  131. package/dist/components/assistant-ui/thread/context-chips.mjs +3 -2
  132. package/dist/components/assistant-ui/thread/index.mjs +1 -1
  133. package/dist/components/assistant-ui/thread/message-list.mjs +1 -1
  134. package/dist/components/assistant-ui/thread/messages.mjs +2 -2
  135. package/dist/components/assistant-ui/thread-list.d.ts +8 -2
  136. package/dist/components/assistant-ui/thread-list.mjs +80 -7
  137. package/dist/components/assistant-ui/threadlist-sidebar.d.ts +4 -1
  138. package/dist/components/assistant-ui/threadlist-sidebar.mjs +2 -2
  139. package/dist/components/assistant-ui/tool-fallback.d.ts +1 -1
  140. package/dist/components/assistant-ui/tool-fallback.mjs +48 -11
  141. package/dist/components/tool-ui/option-list.d.ts +2 -1
  142. package/dist/components/tool-ui/option-list.mjs +4 -4
  143. package/dist/lib/acp2aisdk/client-context.d.ts +6 -0
  144. package/dist/lib/acp2aisdk/client-context.mjs +43 -7
  145. package/dist/lib/acp2aisdk/commands.mjs +5 -20
  146. package/dist/lib/acp2aisdk/context.d.ts +4 -0
  147. package/dist/lib/acp2aisdk/errors.d.ts +2 -0
  148. package/dist/lib/acp2aisdk/errors.mjs +37 -0
  149. package/dist/lib/acp2aisdk/index.d.ts +7 -0
  150. package/dist/lib/acp2aisdk/index.mjs +110 -34
  151. package/dist/lib/acp2aisdk/provider-compat.mjs +4 -2
  152. package/dist/lib/acp2aisdk/resumable-ui-stream.d.ts +11 -0
  153. package/dist/lib/acp2aisdk/resumable-ui-stream.mjs +323 -0
  154. package/dist/lib/acp2aisdk/runtime-message-filter.d.ts +6 -0
  155. package/dist/lib/acp2aisdk/runtime-message-filter.mjs +22 -0
  156. package/dist/lib/acp2aisdk/runtime-persistence.d.ts +21 -0
  157. package/dist/lib/acp2aisdk/runtime-persistence.mjs +135 -0
  158. package/dist/lib/acp2aisdk/session-store.mjs +7 -1
  159. package/dist/lib/acp2aisdk/skill-command-cache.mjs +1 -1
  160. package/dist/lib/api/client.d.ts +51 -4
  161. package/dist/lib/api/client.mjs +35 -4
  162. package/dist/lib/api/cors.mjs +7 -1
  163. package/dist/lib/api/http-response.d.ts +2 -0
  164. package/dist/lib/api/http-response.mjs +22 -0
  165. package/dist/lib/conversations/client-adapter.d.ts +1 -0
  166. package/dist/lib/conversations/client-adapter.mjs +158 -51
  167. package/dist/lib/conversations/provider-message-loader.d.ts +7 -0
  168. package/dist/lib/conversations/provider-message-loader.mjs +99 -0
  169. package/dist/lib/conversations/runtime-message-recovery.d.ts +9 -0
  170. package/dist/lib/conversations/runtime-message-recovery.mjs +95 -0
  171. package/dist/lib/conversations/store.d.ts +2 -2
  172. package/dist/lib/conversations/store.mjs +49 -149
  173. package/dist/lib/conversations/title-text.d.ts +3 -0
  174. package/dist/lib/conversations/title-text.mjs +81 -0
  175. package/dist/lib/conversations/types.d.ts +12 -1
  176. package/dist/lib/local-image-files.mjs +9 -1
  177. package/dist/lib/local-image-paths.mjs +31 -6
  178. package/dist/lib/output-artifacts/thread.d.ts +22 -0
  179. package/dist/lib/output-artifacts/thread.mjs +47 -0
  180. package/dist/lib/output-artifacts/workspace.mjs +6 -2
  181. package/dist/lib/provider-history/codex.mjs +5 -30
  182. package/dist/public-api/server.d.ts +1 -1
  183. package/dist/public-api/server.mjs +1 -1
  184. package/dist/tools/image-generation/client.mjs +6 -4
  185. package/dist/tools/image-generation/server.mjs +3 -1
  186. package/dist/tools/image-generation/shared.d.ts +1 -0
  187. package/dist/tools/image-generation/shared.mjs +4 -0
  188. package/dist/tools/image-generation/ui-detail.mjs +66 -2
  189. package/dist/tools/user-choice/ui.mjs +66 -30
  190. package/package.json +2 -1
  191. package/.next/server/chunks/[root-of-the-server]__04xq..~._.js +0 -3
  192. package/.next/server/chunks/[root-of-the-server]__07sxz4_._.js +0 -3
  193. package/.next/server/chunks/[root-of-the-server]__0dwg3fr._.js +0 -178
  194. package/.next/server/chunks/[root-of-the-server]__0eanzwb._.js +0 -3
  195. package/.next/server/chunks/[root-of-the-server]__0gqx~5k._.js +0 -3
  196. package/.next/server/chunks/[root-of-the-server]__0~mtsby._.js +0 -3
  197. package/.next/server/chunks/[root-of-the-server]__10-n4io._.js +0 -3
  198. package/.next/server/chunks/[root-of-the-server]__10g507v._.js +0 -3
  199. package/.next/static/chunks/0zftsky7gte_9.js +0 -102
  200. package/.next/static/chunks/1610ha42i.fl~.css +0 -1
  201. /package/.next/static/{mbk_N5Gs4ZJg3lciRL6ya → Kri5x_Y9TwyCw9FEY15ME}/_buildManifest.js +0 -0
  202. /package/.next/static/{mbk_N5Gs4ZJg3lciRL6ya → Kri5x_Y9TwyCw9FEY15ME}/_clientMiddlewareManifest.js +0 -0
  203. /package/.next/static/{mbk_N5Gs4ZJg3lciRL6ya → Kri5x_Y9TwyCw9FEY15ME}/_ssgManifest.js +0 -0
@@ -30,7 +30,7 @@ export const MessageError = () => {
30
30
  export const AssistantMessage = () => {
31
31
  const ACTION_BAR_PT = "pt-1.5";
32
32
  const ACTION_BAR_HEIGHT = `-mb-7.5 min-h-7.5 ${ACTION_BAR_PT}`;
33
- return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_assistant-message-root", "data-role": "assistant", className: "fade-in slide-in-from-bottom-1 relative animate-in duration-150 [contain-intrinsic-size:auto_300px] [content-visibility:auto]", children: [_jsxs("div", { "data-slot": "aui_assistant-message-content", className: "wrap-break-word px-2 text-[15px] text-foreground leading-relaxed md:text-base", children: [_jsx(MessagePrimitive.Parts, { children: ({ part }) => {
33
+ return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_assistant-message-root", "data-role": "assistant", className: "fade-in slide-in-from-bottom-1 relative animate-in duration-150 [contain-intrinsic-size:auto_300px] [content-visibility:auto]", children: [_jsxs("div", { "data-slot": "aui_assistant-message-content", className: "wrap-break-word px-1.5 text-sm text-foreground leading-[1.6] md:px-2 md:text-base md:leading-relaxed [&>[data-slot=image-root]]:my-2", children: [_jsx(MessagePrimitive.Parts, { children: ({ part }) => {
34
34
  var _a;
35
35
  if (part.type === "text")
36
36
  return _jsx(MarkdownText, {});
@@ -57,7 +57,7 @@ export const UserMessage = () => {
57
57
  const isInternalUserChoiceResult = useAuiState((state) => state.message.content.some((part) => part.type === "text" && isUserChoiceResultMessageText(part.text)));
58
58
  if (isInternalUserChoiceResult)
59
59
  return null;
60
- return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_user-message-root", className: "fade-in slide-in-from-bottom-1 grid animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 duration-150 [contain-intrinsic-size:auto_60px] [content-visibility:auto] [&:where(>*)]:col-start-2", "data-role": "user", children: [_jsx(UserMessageAttachments, {}), _jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [_jsx("div", { className: "aui-user-message-content wrap-break-word peer rounded-2xl bg-muted px-4 py-2.5 text-[15px] text-foreground md:text-base empty:hidden", children: _jsx(MessagePrimitive.Parts, { components: { Image: ImageMessage, File } }) }), _jsx("div", { className: "aui-user-action-bar-wrapper absolute start-0 top-1/2 -translate-x-full -translate-y-1/2 pe-2 peer-empty:hidden rtl:translate-x-full", children: _jsx(UserActionBar, {}) })] }), _jsx(BranchPicker, { "data-slot": "aui_user-branch-picker", className: "col-span-full col-start-1 row-start-3 -me-1 justify-end" })] }));
60
+ return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_user-message-root", className: "fade-in slide-in-from-bottom-1 grid animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 duration-150 [contain-intrinsic-size:auto_60px] [content-visibility:auto] [&:where(>*)]:col-start-2", "data-role": "user", children: [_jsx(UserMessageAttachments, {}), _jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [_jsx("div", { className: "aui-user-message-content wrap-break-word peer rounded-2xl bg-muted px-3.5 py-2 text-sm text-foreground leading-[1.55] md:px-4 md:py-2.5 md:text-base md:leading-normal empty:hidden [&>[data-slot=image-root]]:my-2", children: _jsx(MessagePrimitive.Parts, { components: { Image: ImageMessage, File } }) }), _jsx("div", { className: "aui-user-action-bar-wrapper absolute start-0 top-1/2 -translate-x-full -translate-y-1/2 pe-2 peer-empty:hidden rtl:translate-x-full", children: _jsx(UserActionBar, {}) })] }), _jsx(BranchPicker, { "data-slot": "aui_user-branch-picker", className: "col-span-full col-start-1 row-start-3 -me-1 justify-end" })] }));
61
61
  };
62
62
  export const UserActionBar = () => {
63
63
  return (_jsx(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-user-action-bar-root flex flex-col items-end", children: _jsx(ActionBarPrimitive.Edit, { asChild: true, children: _jsx(TooltipIconButton, { tooltip: "\u7F16\u8F91", className: "aui-user-action-edit p-4", children: _jsx(PencilIcon, {}) }) }) }));
@@ -1,2 +1,8 @@
1
- import type { FC } from "react";
2
- export declare const ThreadList: FC;
1
+ import { type FC, type MouseEventHandler } from "react";
2
+ type ThreadListProps = {
3
+ openInNewWindowHref?: string | null;
4
+ localNewThreadHref?: string | null;
5
+ onNewThreadClick?: MouseEventHandler<HTMLButtonElement>;
6
+ };
7
+ export declare const ThreadList: FC<ThreadListProps>;
8
+ export {};
@@ -1,9 +1,12 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { AuiIf, ThreadListItemMorePrimitive, ThreadListItemPrimitive, ThreadListPrimitive, } from "@assistant-ui/react";
3
- import { ArchiveIcon, MoreHorizontalIcon, PlusIcon, SettingsIcon, TrashIcon, } from "lucide-react";
3
+ import { AuiIf, ThreadListItemMorePrimitive, ThreadListItemPrimitive, ThreadListPrimitive, useAui, useAuiState, } from "@assistant-ui/react";
4
+ import { ArchiveIcon, ExternalLinkIcon, MoreHorizontalIcon, PlusIcon, SettingsIcon, TrashIcon, } from "lucide-react";
5
+ import { useEffect, useMemo, useRef, useState, } from "react";
4
6
  import { ImageGenerationSettingsDialog } from "./image-generation-settings-dialog.mjs";
5
7
  import { Button } from "../ui/button.mjs";
6
8
  import { Skeleton } from "../ui/skeleton.mjs";
9
+ import { acpApiClient } from "../../lib/api/client.mjs";
7
10
  const THREAD_LIST_SKELETON_ITEMS = [
8
11
  "thread-list-skeleton-1",
9
12
  "thread-list-skeleton-2",
@@ -11,11 +14,12 @@ const THREAD_LIST_SKELETON_ITEMS = [
11
14
  "thread-list-skeleton-4",
12
15
  "thread-list-skeleton-5",
13
16
  ];
14
- export const ThreadList = () => {
15
- return (_jsxs(ThreadListPrimitive.Root, { className: "aui-root aui-thread-list-root flex w-full min-w-0 flex-col gap-1", children: [_jsx(ThreadListNew, {}), _jsx(AuiIf, { condition: (s) => s.threads.isLoading && s.threads.threadIds.length === 0, children: _jsx(ThreadListSkeleton, {}) }), _jsxs(AuiIf, { condition: (s) => !s.threads.isLoading || s.threads.threadIds.length > 0, children: [_jsx(ThreadListPrimitive.Items, { children: () => _jsx(ThreadListItem, {}) }), _jsx(AuiIf, { condition: (s) => s.threads.hasMore, children: _jsx(ThreadListLoadMore, {}) })] })] }));
17
+ export const ThreadList = ({ openInNewWindowHref, localNewThreadHref, onNewThreadClick, }) => {
18
+ return (_jsxs(ThreadListPrimitive.Root, { className: "aui-root aui-thread-list-root flex w-full min-w-0 flex-col gap-1", children: [_jsx(ThreadListRuntimeRefresh, {}), _jsx(ThreadListNew, { openInNewWindowHref: openInNewWindowHref, localNewThreadHref: localNewThreadHref, onNewThreadClick: onNewThreadClick }), _jsx(AuiIf, { condition: (s) => s.threads.isLoading && s.threads.threadIds.length === 0, children: _jsx(ThreadListSkeleton, {}) }), _jsxs(AuiIf, { condition: (s) => !s.threads.isLoading || s.threads.threadIds.length > 0, children: [_jsx(ThreadListPrimitive.Items, { children: () => _jsx(ThreadListItem, {}) }), _jsx(AuiIf, { condition: (s) => s.threads.hasMore, children: _jsx(ThreadListLoadMore, {}) })] })] }));
16
19
  };
17
- const ThreadListNew = () => {
18
- return (_jsxs("div", { className: "aui-thread-list-top-actions mb-2 flex flex-col gap-1", children: [_jsx(ImageGenerationSettingsDialog, { trigger: _jsxs(Button, { type: "button", variant: "ghost", className: "aui-thread-list-settings h-9 w-full min-w-0 justify-start gap-2 rounded-lg px-3 text-sm hover:bg-muted data-[state=open]:bg-muted", children: [_jsx(SettingsIcon, { className: "size-4" }), _jsx("span", { className: "truncate", children: "\u8BBE\u7F6E" })] }) }), _jsx(ThreadListPrimitive.New, { asChild: true, children: _jsxs(Button, { variant: "ghost", className: "aui-thread-list-new h-9 w-full min-w-0 justify-start gap-2 rounded-lg px-3 text-sm hover:bg-muted", children: [_jsx(PlusIcon, { className: "size-4" }), _jsx("span", { className: "truncate", children: "\u65B0\u5EFA\u5BF9\u8BDD" })] }) })] }));
20
+ const ThreadListNew = ({ openInNewWindowHref, localNewThreadHref, onNewThreadClick, }) => {
21
+ const newThreadButton = (_jsxs(Button, { variant: "ghost", className: "aui-thread-list-new h-9 w-full min-w-0 justify-start gap-2 rounded-lg px-3 text-sm hover:bg-muted", onClick: onNewThreadClick, children: [_jsx(PlusIcon, { className: "size-4" }), _jsx("span", { className: "truncate", children: "\u65B0\u5EFA\u5BF9\u8BDD" })] }));
22
+ return (_jsxs("div", { className: "aui-thread-list-top-actions mb-2 flex flex-col gap-1", children: [_jsx(ImageGenerationSettingsDialog, { trigger: _jsxs(Button, { type: "button", variant: "ghost", className: "aui-thread-list-settings h-9 w-full min-w-0 justify-start gap-2 rounded-lg px-3 text-sm hover:bg-muted data-[state=open]:bg-muted", children: [_jsx(SettingsIcon, { className: "size-4" }), _jsx("span", { className: "truncate", children: "\u8BBE\u7F6E" })] }) }), localNewThreadHref ? (newThreadButton) : (_jsx(ThreadListPrimitive.New, { asChild: true, children: newThreadButton })), openInNewWindowHref ? (_jsx(Button, { asChild: true, variant: "ghost", className: "aui-thread-list-open-window h-9 w-full min-w-0 justify-start gap-2 rounded-lg px-3 text-sm hover:bg-muted", children: _jsxs("a", { href: openInNewWindowHref, target: "_blank", rel: "noopener noreferrer", children: [_jsx(ExternalLinkIcon, { className: "size-4" }), _jsx("span", { className: "truncate", children: "\u65B0\u7A97\u53E3\u6253\u5F00" })] }) })) : null] }));
19
23
  };
20
24
  const ThreadListSkeleton = () => {
21
25
  return (_jsx("div", { className: "flex flex-col gap-1", children: THREAD_LIST_SKELETON_ITEMS.map((item) => (_jsx("div", { role: "status", "aria-label": "\u6B63\u5728\u52A0\u8F7D\u5BF9\u8BDD", className: "aui-thread-list-skeleton-wrapper flex h-9 items-center px-3", children: _jsx(Skeleton, { className: "aui-thread-list-skeleton h-4 w-full" }) }, item))) }));
@@ -24,7 +28,76 @@ const ThreadListLoadMore = () => {
24
28
  return (_jsx(ThreadListPrimitive.LoadMore, { asChild: true, children: _jsxs(Button, { variant: "ghost", className: "aui-thread-list-load-more h-9 justify-center rounded-lg px-3 text-muted-foreground text-sm hover:bg-muted hover:text-foreground", children: [_jsx(AuiIf, { condition: (s) => !s.threads.isLoadingMore, children: "\u52A0\u8F7D\u66F4\u591A" }), _jsx(AuiIf, { condition: (s) => s.threads.isLoadingMore, children: "\u6B63\u5728\u52A0\u8F7D..." })] }) }));
25
29
  };
26
30
  const ThreadListItem = () => {
27
- return (_jsxs(ThreadListItemPrimitive.Root, { className: "aui-thread-list-item group/thread-list-item flex h-9 w-full min-w-0 items-center rounded-lg transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none data-active:bg-muted", children: [_jsx(ThreadListItemPrimitive.Trigger, { className: "aui-thread-list-item-trigger flex h-full min-w-0 flex-1 items-center px-3 text-start text-sm", children: _jsx("span", { className: "aui-thread-list-item-title min-w-0 flex-1 truncate", children: _jsx(ThreadListItemPrimitive.Title, { fallback: "\u65B0\u5BF9\u8BDD" }) }) }), _jsx(ThreadListItemMore, {})] }));
31
+ return (_jsxs(ThreadListItemPrimitive.Root, { className: "aui-thread-list-item group/thread-list-item flex h-9 w-full min-w-0 items-center rounded-lg transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none data-active:bg-muted", children: [_jsxs(ThreadListItemPrimitive.Trigger, { className: "aui-thread-list-item-trigger flex h-full min-w-0 flex-1 items-center px-3 text-start text-sm", children: [_jsx("span", { className: "aui-thread-list-item-title min-w-0 flex-1 truncate", children: _jsx(ThreadListItemPrimitive.Title, { fallback: "\u65B0\u5BF9\u8BDD" }) }), _jsx(ThreadListItemRunStatus, {})] }), _jsx(ThreadListItemMore, {})] }));
32
+ };
33
+ function getCustomString(custom, key) {
34
+ const value = custom === null || custom === void 0 ? void 0 : custom[key];
35
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
36
+ }
37
+ function getRunDisplayState(runState) {
38
+ return runState === "queued" || runState === "running" ? "running" : null;
39
+ }
40
+ const ThreadListRuntimeRefresh = () => {
41
+ const aui = useAui();
42
+ const isRunning = useAuiState((state) => state.thread.isRunning);
43
+ const previousIsRunningRef = useRef(isRunning);
44
+ useEffect(() => {
45
+ const wasRunning = previousIsRunningRef.current;
46
+ previousIsRunningRef.current = isRunning;
47
+ if (!wasRunning || isRunning)
48
+ return;
49
+ void aui
50
+ .threads()
51
+ .reload()
52
+ .catch(() => { });
53
+ }, [aui, isRunning]);
54
+ return null;
55
+ };
56
+ const ThreadListItemRunStatus = () => {
57
+ const remoteId = useAuiState((state) => state.threadListItem.remoteId);
58
+ const custom = useAuiState((state) => state.threadListItem.custom);
59
+ const isCurrentThread = useAuiState((state) => state.threads.mainThreadId === state.threadListItem.id);
60
+ const currentThreadIsRunning = useAuiState((state) => state.thread.isRunning);
61
+ const workspacePath = getCustomString(custom, "workspacePath");
62
+ const currentRunSignal = isCurrentThread ? currentThreadIsRunning : null;
63
+ const [displayState, setDisplayState] = useState(null);
64
+ const [refreshToken, setRefreshToken] = useState(0);
65
+ const previousRuntimeRefreshRef = useRef(`${isCurrentThread}:${currentRunSignal}`);
66
+ const runtimeRequest = useMemo(() => ({ refreshToken, remoteId, workspacePath }), [refreshToken, remoteId, workspacePath]);
67
+ useEffect(() => {
68
+ const signature = `${isCurrentThread}:${currentRunSignal}`;
69
+ if (previousRuntimeRefreshRef.current === signature)
70
+ return;
71
+ previousRuntimeRefreshRef.current = signature;
72
+ if (isCurrentThread)
73
+ setRefreshToken((value) => value + 1);
74
+ }, [isCurrentThread, currentRunSignal]);
75
+ useEffect(() => {
76
+ let cancelled = false;
77
+ if (!runtimeRequest.remoteId) {
78
+ setDisplayState(null);
79
+ return;
80
+ }
81
+ void acpApiClient
82
+ .getConversationRuntime(runtimeRequest.remoteId, runtimeRequest.workspacePath)
83
+ .then((runtime) => {
84
+ var _a;
85
+ if (cancelled)
86
+ return;
87
+ setDisplayState(getRunDisplayState((_a = runtime.metadata) === null || _a === void 0 ? void 0 : _a.runState));
88
+ })
89
+ .catch(() => {
90
+ if (!cancelled)
91
+ setDisplayState(null);
92
+ });
93
+ return () => {
94
+ cancelled = true;
95
+ };
96
+ }, [runtimeRequest]);
97
+ const isRunning = displayState === "running";
98
+ if (!isRunning)
99
+ return null;
100
+ return (_jsx("span", { className: "aui-thread-list-item-run-status ms-2 inline-flex size-3 shrink-0 items-center justify-center", role: "img", "aria-label": "\u5BF9\u8BDD\u8FD0\u884C\u4E2D", title: "\u5BF9\u8BDD\u8FD0\u884C\u4E2D", children: _jsx("span", { className: "block size-3 animate-spin rounded-full border border-foreground/70 border-t-transparent motion-reduce:animate-none" }) }));
28
101
  };
29
102
  const ThreadListItemMore = () => {
30
103
  return (_jsxs(ThreadListItemMorePrimitive.Root, { children: [_jsx(ThreadListItemMorePrimitive.Trigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "icon", className: "aui-thread-list-item-more me-0 h-7 w-0 overflow-hidden p-0 opacity-0 transition-[width,margin,opacity,background-color,color] group-hover/thread-list-item:me-2 group-hover/thread-list-item:w-7 group-hover/thread-list-item:opacity-100 group-focus-within/thread-list-item:me-2 group-focus-within/thread-list-item:w-7 group-focus-within/thread-list-item:opacity-100 data-[state=open]:me-2 data-[state=open]:w-7 data-[state=open]:bg-accent data-[state=open]:opacity-100", children: [_jsx(MoreHorizontalIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "\u66F4\u591A\u9009\u9879" })] }) }), _jsxs(ThreadListItemMorePrimitive.Content, { side: "bottom", align: "start", className: "aui-thread-list-item-more-content z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", children: [_jsx(ThreadListItemPrimitive.Archive, { asChild: true, children: _jsxs(ThreadListItemMorePrimitive.Item, { className: "aui-thread-list-item-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", children: [_jsx(ArchiveIcon, { className: "size-4" }), "\u5F52\u6863"] }) }), _jsx(ThreadListItemPrimitive.Delete, { asChild: true, children: _jsxs(ThreadListItemMorePrimitive.Item, { className: "aui-thread-list-item-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-destructive text-sm outline-none hover:bg-destructive/10 hover:text-destructive focus:bg-destructive/10 focus:text-destructive", children: [_jsx(TrashIcon, { className: "size-4" }), "\u5220\u9664"] }) })] })] }));
@@ -1,6 +1,9 @@
1
1
  import type * as React from "react";
2
2
  import { Sidebar } from "../ui/sidebar";
3
- export declare function ThreadListSidebar({ workspacePath, workspaceTitle, ...props }: React.ComponentProps<typeof Sidebar> & {
3
+ export declare function ThreadListSidebar({ workspacePath, workspaceTitle, openInNewWindowHref, localNewThreadHref, onNewThreadClick, ...props }: React.ComponentProps<typeof Sidebar> & {
4
4
  workspacePath?: string | null;
5
5
  workspaceTitle?: string | null;
6
+ openInNewWindowHref?: string | null;
7
+ localNewThreadHref?: string | null;
8
+ onNewThreadClick?: React.MouseEventHandler<HTMLButtonElement>;
6
9
  }): import("react/jsx-runtime").JSX.Element;
@@ -25,8 +25,8 @@ function getPathBasename(path) {
25
25
  return (_a = parts[parts.length - 1]) !== null && _a !== void 0 ? _a : normalizedPath;
26
26
  }
27
27
  export function ThreadListSidebar(_a) {
28
- var { workspacePath, workspaceTitle } = _a, props = __rest(_a, ["workspacePath", "workspaceTitle"]);
28
+ var { workspacePath, workspaceTitle, openInNewWindowHref, localNewThreadHref, onNewThreadClick } = _a, props = __rest(_a, ["workspacePath", "workspaceTitle", "openInNewWindowHref", "localNewThreadHref", "onNewThreadClick"]);
29
29
  const projectPath = (workspacePath === null || workspacePath === void 0 ? void 0 : workspacePath.trim()) || "当前项目";
30
30
  const projectTitle = (workspaceTitle === null || workspaceTitle === void 0 ? void 0 : workspaceTitle.trim()) || getPathBasename(projectPath);
31
- return (_jsxs(Sidebar, Object.assign({}, props, { children: [_jsx(SidebarHeader, { className: "aui-sidebar-header mb-2 border-b", children: _jsxs("div", { className: "aui-sidebar-header-content flex items-center justify-between", children: [_jsx(SidebarMenu, { className: "min-w-0 flex-1", children: _jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { size: "lg", asChild: true, children: _jsxs("div", { children: [_jsx(FolderIcon, { className: "aui-sidebar-header-icon size-4" }), _jsxs("div", { className: "aui-sidebar-header-heading me-2 min-w-0 space-y-1 leading-none", children: [_jsx("span", { className: "aui-sidebar-header-title block min-w-0 truncate font-semibold", title: projectTitle, children: projectTitle }), _jsx("span", { className: "aui-sidebar-header-description block min-w-0 truncate text-sidebar-foreground/60 text-xs", title: projectPath, children: projectPath })] })] }) }) }) }), _jsx(ThemeToggle, {})] }) }), _jsx(SidebarContent, { className: "aui-sidebar-content overflow-hidden px-0", children: _jsx(ScrollArea, { className: "aui-thread-list-scroll-area min-h-0 flex-1", children: _jsx("div", { className: "aui-thread-list-scroll-content w-full min-w-0 px-2", children: _jsx(ThreadList, {}) }) }) }), _jsx(SidebarRail, {})] })));
31
+ return (_jsxs(Sidebar, Object.assign({}, props, { children: [_jsx(SidebarHeader, { className: "aui-sidebar-header mb-2 border-b", children: _jsxs("div", { className: "aui-sidebar-header-content flex items-center justify-between", children: [_jsx(SidebarMenu, { className: "min-w-0 flex-1", children: _jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { size: "lg", asChild: true, children: _jsxs("div", { children: [_jsx(FolderIcon, { className: "aui-sidebar-header-icon size-4" }), _jsxs("div", { className: "aui-sidebar-header-heading me-2 min-w-0 space-y-1 leading-none", children: [_jsx("span", { className: "aui-sidebar-header-title block min-w-0 truncate font-semibold", title: projectTitle, children: projectTitle }), _jsx("span", { className: "aui-sidebar-header-description block min-w-0 truncate text-sidebar-foreground/60 text-xs", title: projectPath, children: projectPath })] })] }) }) }) }), _jsx(ThemeToggle, {})] }) }), _jsx(SidebarContent, { className: "aui-sidebar-content overflow-hidden px-0", children: _jsx(ScrollArea, { className: "aui-thread-list-scroll-area min-h-0 flex-1", children: _jsx("div", { className: "aui-thread-list-scroll-content w-full min-w-0 px-2", children: _jsx(ThreadList, { openInNewWindowHref: openInNewWindowHref, localNewThreadHref: localNewThreadHref, onNewThreadClick: onNewThreadClick }) }) }) }), _jsx(SidebarRail, {})] })));
32
32
  }
@@ -1,4 +1,4 @@
1
- import { type ToolCallMessagePartComponent, type ToolCallMessagePartStatus } from "@assistant-ui/react";
1
+ import type { ToolCallMessagePartComponent, ToolCallMessagePartStatus } from "@assistant-ui/react";
2
2
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../ui/collapsible";
3
3
  export type ToolFallbackRootProps = Omit<React.ComponentProps<typeof Collapsible>, "open" | "onOpenChange"> & {
4
4
  open?: boolean;
@@ -11,30 +11,67 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- import { useScrollLock, } from "@assistant-ui/react";
15
14
  import { AlertCircleIcon, CheckIcon, ChevronDownIcon, LoaderIcon, XCircleIcon, } from "lucide-react";
16
- import { memo, useCallback, useRef, useState } from "react";
15
+ import { memo, useCallback, useEffect, useRef, useState, } from "react";
17
16
  import { AcpToolContentBlocks } from "./acp-tool-content.mjs";
18
17
  import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "../ui/collapsible.mjs";
19
18
  import { cn } from "../../lib/utils.mjs";
20
19
  const ANIMATION_DURATION = 200;
20
+ function useScrollPositionLock(animatedElementRef, animationDuration) {
21
+ const scrollContainerRef = useRef(null);
22
+ const cleanupRef = useRef(null);
23
+ useEffect(() => {
24
+ return () => { var _a; return (_a = cleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(cleanupRef); };
25
+ }, []);
26
+ return useCallback(() => {
27
+ var _a;
28
+ (_a = cleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(cleanupRef);
29
+ if (!scrollContainerRef.current) {
30
+ let element = animatedElementRef.current;
31
+ while (element) {
32
+ const { overflowY } = getComputedStyle(element);
33
+ if (overflowY === "auto" || overflowY === "scroll") {
34
+ scrollContainerRef.current = element;
35
+ break;
36
+ }
37
+ element = element.parentElement;
38
+ }
39
+ }
40
+ const scrollContainer = scrollContainerRef.current;
41
+ if (!scrollContainer)
42
+ return;
43
+ const scrollPosition = scrollContainer.scrollTop;
44
+ const resetPosition = () => {
45
+ scrollContainer.scrollTop = scrollPosition;
46
+ };
47
+ scrollContainer.addEventListener("scroll", resetPosition);
48
+ const timeoutId = window.setTimeout(() => {
49
+ scrollContainer.removeEventListener("scroll", resetPosition);
50
+ cleanupRef.current = null;
51
+ }, animationDuration);
52
+ cleanupRef.current = () => {
53
+ window.clearTimeout(timeoutId);
54
+ scrollContainer.removeEventListener("scroll", resetPosition);
55
+ };
56
+ }, [animatedElementRef, animationDuration]);
57
+ }
21
58
  function ToolFallbackRoot(_a) {
22
59
  var { className, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, children } = _a, props = __rest(_a, ["className", "open", "onOpenChange", "defaultOpen", "children"]);
23
60
  const collapsibleRef = useRef(null);
24
61
  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
25
- const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
62
+ const lockScrollPosition = useScrollPositionLock(collapsibleRef, ANIMATION_DURATION);
26
63
  const isControlled = controlledOpen !== undefined;
27
64
  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
28
65
  const handleOpenChange = useCallback((open) => {
29
66
  if (!open) {
30
- lockScroll();
67
+ lockScrollPosition();
31
68
  }
32
69
  if (!isControlled) {
33
70
  setUncontrolledOpen(open);
34
71
  }
35
72
  controlledOnOpenChange === null || controlledOnOpenChange === void 0 ? void 0 : controlledOnOpenChange(open);
36
- }, [lockScroll, isControlled, controlledOnOpenChange]);
37
- return (_jsx(Collapsible, Object.assign({ ref: collapsibleRef, "data-slot": "tool-fallback-root", open: isOpen, onOpenChange: handleOpenChange, className: cn("aui-tool-fallback-root group/tool-fallback-root my-2.5 w-full rounded-lg border py-3 first:mt-0 last:mb-0", className), style: {
73
+ }, [lockScrollPosition, isControlled, controlledOnOpenChange]);
74
+ return (_jsx(Collapsible, Object.assign({ ref: collapsibleRef, "data-slot": "tool-fallback-root", open: isOpen, onOpenChange: handleOpenChange, className: cn("aui-tool-fallback-root group/tool-fallback-root my-2 w-full rounded-lg border py-2.5 first:mt-0 last:mb-0 md:my-2.5 md:py-3", className), style: {
38
75
  "--animation-duration": `${ANIMATION_DURATION}ms`,
39
76
  } }, props, { children: children })));
40
77
  }
@@ -59,23 +96,23 @@ function ToolFallbackTrigger(_a) {
59
96
  const Icon = statusIconMap[statusType];
60
97
  const label = isCancelled ? "已取消工具" : "已使用工具";
61
98
  const toolLabel = _jsx("b", { children: toolName });
62
- return (_jsxs(CollapsibleTrigger, Object.assign({ "data-slot": "tool-fallback-trigger", "aria-label": `${label}: ${toolName}`, className: cn("aui-tool-fallback-trigger group/trigger flex w-full items-center gap-2 px-4 text-sm transition-colors", className) }, props, { children: [_jsx(Icon, { "data-slot": "tool-fallback-trigger-icon", className: cn("aui-tool-fallback-trigger-icon size-4 shrink-0", isCancelled && "text-muted-foreground", isRunning && "animate-spin") }), _jsxs("span", { "data-slot": "tool-fallback-trigger-label", className: cn("aui-tool-fallback-trigger-label-wrapper relative min-w-0 flex-1 text-start leading-snug", isCancelled && "text-muted-foreground line-through"), title: toolName, children: [_jsx("span", { className: "aui-tool-fallback-trigger-label line-clamp-2 break-words", children: toolLabel }), isRunning && (_jsx("span", { "aria-hidden": true, "data-slot": "tool-fallback-trigger-shimmer", className: "aui-tool-fallback-trigger-shimmer shimmer pointer-events-none absolute inset-0 line-clamp-2 break-words motion-reduce:animate-none", children: toolLabel }))] }), _jsx(ChevronDownIcon, { "data-slot": "tool-fallback-trigger-chevron", className: cn("aui-tool-fallback-trigger-chevron size-4 shrink-0", "transition-transform duration-(--animation-duration) ease-out", "group-data-[state=closed]/trigger:-rotate-90", "group-data-[state=open]/trigger:rotate-0") })] })));
99
+ return (_jsxs(CollapsibleTrigger, Object.assign({ "data-slot": "tool-fallback-trigger", "aria-label": `${label}: ${toolName}`, className: cn("aui-tool-fallback-trigger group/trigger flex w-full items-center gap-2 px-3 text-[13px] transition-colors md:px-4 md:text-sm", className) }, props, { children: [_jsx(Icon, { "data-slot": "tool-fallback-trigger-icon", className: cn("aui-tool-fallback-trigger-icon size-3.5 shrink-0 md:size-4", isCancelled && "text-muted-foreground", isRunning && "animate-spin") }), _jsxs("span", { "data-slot": "tool-fallback-trigger-label", className: cn("aui-tool-fallback-trigger-label-wrapper relative min-w-0 flex-1 text-start leading-snug", isCancelled && "text-muted-foreground line-through"), title: toolName, children: [_jsx("span", { className: "aui-tool-fallback-trigger-label line-clamp-2 break-words", children: toolLabel }), isRunning && (_jsx("span", { "aria-hidden": true, "data-slot": "tool-fallback-trigger-shimmer", className: "aui-tool-fallback-trigger-shimmer shimmer pointer-events-none absolute inset-0 line-clamp-2 break-words motion-reduce:animate-none", children: toolLabel }))] }), _jsx(ChevronDownIcon, { "data-slot": "tool-fallback-trigger-chevron", className: cn("aui-tool-fallback-trigger-chevron size-3.5 shrink-0 md:size-4", "transition-transform duration-(--animation-duration) ease-out", "group-data-[state=closed]/trigger:-rotate-90", "group-data-[state=open]/trigger:rotate-0") })] })));
63
100
  }
64
101
  function ToolFallbackContent(_a) {
65
102
  var { className, children } = _a, props = __rest(_a, ["className", "children"]);
66
- return (_jsx(CollapsibleContent, Object.assign({ "data-slot": "tool-fallback-content", className: cn("aui-tool-fallback-content relative overflow-hidden text-sm outline-none", "group/collapsible-content ease-out", "data-[state=closed]:animate-collapsible-up", "data-[state=open]:animate-collapsible-down", "data-[state=closed]:fill-mode-forwards", "data-[state=closed]:pointer-events-none", "data-[state=open]:duration-(--animation-duration)", "data-[state=closed]:duration-(--animation-duration)", className) }, props, { children: _jsx("div", { className: "mt-3 flex flex-col gap-2 border-t pt-2", children: children }) })));
103
+ return (_jsx(CollapsibleContent, Object.assign({ "data-slot": "tool-fallback-content", className: cn("aui-tool-fallback-content relative overflow-hidden text-[13px] outline-none md:text-sm", "group/collapsible-content ease-out", "data-[state=closed]:animate-collapsible-up", "data-[state=open]:animate-collapsible-down", "data-[state=closed]:fill-mode-forwards", "data-[state=closed]:pointer-events-none", "data-[state=open]:duration-(--animation-duration)", "data-[state=closed]:duration-(--animation-duration)", className) }, props, { children: _jsx("div", { className: "mt-2.5 flex flex-col gap-2 border-t pt-2 md:mt-3", children: children }) })));
67
104
  }
68
105
  function ToolFallbackArgs(_a) {
69
106
  var { argsText, className } = _a, props = __rest(_a, ["argsText", "className"]);
70
107
  if (!argsText)
71
108
  return null;
72
- return (_jsx("div", Object.assign({ "data-slot": "tool-fallback-args", className: cn("aui-tool-fallback-args px-4", className) }, props, { children: _jsx("pre", { className: "aui-tool-fallback-args-value max-h-40 overflow-auto rounded-md bg-muted/30 px-3 py-2 font-mono text-xs leading-relaxed whitespace-pre-wrap break-words", children: argsText }) })));
109
+ return (_jsx("div", Object.assign({ "data-slot": "tool-fallback-args", className: cn("aui-tool-fallback-args px-3 md:px-4", className) }, props, { children: _jsx("pre", { className: "aui-tool-fallback-args-value max-h-40 overflow-auto rounded-md bg-muted/30 px-3 py-2 font-mono text-xs leading-relaxed whitespace-pre-wrap break-words", children: argsText }) })));
73
110
  }
74
111
  function ToolFallbackResult(_a) {
75
112
  var { result, className } = _a, props = __rest(_a, ["result", "className"]);
76
113
  if (result === undefined)
77
114
  return null;
78
- return (_jsxs("div", Object.assign({ "data-slot": "tool-fallback-result", className: cn("aui-tool-fallback-result border-t border-dashed px-4 pt-2", className) }, props, { children: [_jsx("p", { className: "aui-tool-fallback-result-header font-semibold", children: "\u7ED3\u679C\uFF1A" }), _jsx("pre", { className: "aui-tool-fallback-result-content max-h-56 overflow-auto rounded-md bg-muted/30 px-3 py-2 font-mono text-xs leading-relaxed whitespace-pre-wrap break-words", children: result === null
115
+ return (_jsxs("div", Object.assign({ "data-slot": "tool-fallback-result", className: cn("aui-tool-fallback-result border-t border-dashed px-3 pt-2 md:px-4", className) }, props, { children: [_jsx("p", { className: "aui-tool-fallback-result-header font-semibold", children: "\u7ED3\u679C\uFF1A" }), _jsx("pre", { className: "aui-tool-fallback-result-content max-h-56 overflow-auto rounded-md bg-muted/30 px-3 py-2 font-mono text-xs leading-relaxed whitespace-pre-wrap break-words", children: result === null
79
116
  ? "无结构化结果"
80
117
  : typeof result === "string"
81
118
  ? result
@@ -95,7 +132,7 @@ function ToolFallbackError(_a) {
95
132
  return null;
96
133
  const isCancelled = status.reason === "cancelled";
97
134
  const headerText = isCancelled ? "取消原因:" : "错误:";
98
- return (_jsxs("div", Object.assign({ "data-slot": "tool-fallback-error", className: cn("aui-tool-fallback-error px-4", className) }, props, { children: [_jsx("p", { className: "aui-tool-fallback-error-header font-semibold text-muted-foreground", children: headerText }), _jsx("p", { className: "aui-tool-fallback-error-reason text-muted-foreground", children: errorText })] })));
135
+ return (_jsxs("div", Object.assign({ "data-slot": "tool-fallback-error", className: cn("aui-tool-fallback-error px-3 md:px-4", className) }, props, { children: [_jsx("p", { className: "aui-tool-fallback-error-header font-semibold text-muted-foreground", children: headerText }), _jsx("p", { className: "aui-tool-fallback-error-reason text-muted-foreground", children: errorText })] })));
99
136
  }
100
137
  const ToolFallbackImpl = ({ toolName, argsText, result, status, toolCallId, }) => {
101
138
  const effectiveStatus = getEffectiveToolStatus(status, result);
@@ -29,6 +29,7 @@ export type OptionListProps = {
29
29
  isActionDisabled?: (actionId: string, value: string | string[] | null) => boolean;
30
30
  allowCustomInput?: boolean;
31
31
  customInputLabel?: string;
32
+ showRecommendedBadge?: boolean;
32
33
  className?: string;
33
34
  };
34
- export declare function OptionList({ id, options, selectionMode, value, defaultValue, choice, minSelections, maxSelections, actions, onChange, onAction, onBeforeAction, isActionDisabled, allowCustomInput, customInputLabel, className, }: OptionListProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function OptionList({ id, options, selectionMode, value, defaultValue, choice, minSelections, maxSelections, actions, onChange, onAction, onBeforeAction, isActionDisabled, allowCustomInput, customInputLabel, showRecommendedBadge, className, }: OptionListProps): import("react/jsx-runtime").JSX.Element;
@@ -18,9 +18,9 @@ function arrayToValue(value, selectionMode) {
18
18
  return (_a = value[0]) !== null && _a !== void 0 ? _a : null;
19
19
  }
20
20
  export function OptionList({ id, options, selectionMode = "multi", value, defaultValue, choice, minSelections = 1, maxSelections, actions = [
21
- { id: "confirm", label: "确认" },
22
21
  { id: "cancel", label: "取消", variant: "outline" },
23
- ], onChange, onAction, onBeforeAction, isActionDisabled, allowCustomInput = false, customInputLabel = "自定义", className, }) {
22
+ { id: "confirm", label: "确认" },
23
+ ], onChange, onAction, onBeforeAction, isActionDisabled, allowCustomInput = false, customInputLabel = "自定义", showRecommendedBadge = true, className, }) {
24
24
  const isControlled = value !== undefined;
25
25
  const isReceipt = choice !== undefined;
26
26
  const [internalValue, setInternalValue] = useState(valueToArray(defaultValue));
@@ -152,10 +152,10 @@ export function OptionList({ id, options, selectionMode = "multi", value, defaul
152
152
  : "border-border bg-card hover:bg-muted/60", (option.disabled || isReceipt) &&
153
153
  "cursor-default opacity-80 hover:bg-card", hasDescription ? "items-start" : "items-center"), children: [_jsx("span", { className: cn("flex size-4 shrink-0 items-center justify-center rounded-full border", selected
154
154
  ? "border-primary bg-primary text-primary-foreground"
155
- : "border-muted-foreground/30 text-transparent", hasDescription && "mt-0.5"), children: _jsx(CheckIcon, { className: "size-3" }) }), option.icon && (_jsx("span", { className: cn("shrink-0 text-muted-foreground", hasDescription && "mt-0.5"), children: option.icon })), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block break-words font-medium leading-5", children: option.label }), option.description && (_jsx("span", { className: "mt-0.5 block break-words text-muted-foreground text-xs leading-5", children: option.description })), option.recommended && (_jsx("span", { className: "mt-1 inline-flex rounded-sm bg-primary/10 px-1.5 py-0.5 font-medium text-primary text-xs", children: "\u63A8\u8350" }))] })] }, option.id));
155
+ : "border-muted-foreground/30 text-transparent", hasDescription && "mt-0.5"), children: _jsx(CheckIcon, { className: "size-3" }) }), option.icon && (_jsx("span", { className: cn("shrink-0 text-muted-foreground", hasDescription && "mt-0.5"), children: option.icon })), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block break-words font-medium leading-5", children: option.label }), option.description && (_jsx("span", { className: "mt-0.5 block break-words text-muted-foreground text-xs leading-5", children: option.description })), showRecommendedBadge && option.recommended && (_jsx("span", { className: "mt-1 inline-flex rounded-sm bg-primary/10 px-1.5 py-0.5 font-medium text-primary text-xs", children: "\u63A8\u8350" }))] })] }, option.id));
156
156
  }) }), allowCustomInput && selectedSet.has(CUSTOM_OPTION_ID) && !isReceipt && (_jsx(Input, { className: "mt-2", placeholder: customInputLabel, value: customText, onChange: handleCustomTextChange })), !isReceipt && actions.length > 0 && (_jsx("div", { className: "mt-3 flex flex-wrap justify-end gap-2", children: actions.map((action) => {
157
157
  var _a;
158
- const selectedValue = arrayToValue(selectedIds, selectionMode);
158
+ const selectedValue = actionValue;
159
159
  return (_jsx(Button, { type: "button", size: "sm", variant: (_a = action.variant) !== null && _a !== void 0 ? _a : "default", disabled: action.disabled ||
160
160
  (action.id === "confirm" && !isValidSelection) ||
161
161
  (isActionDisabled === null || isActionDisabled === void 0 ? void 0 : isActionDisabled(action.id, selectedValue)), onClick: () => void handleAction(action), children: action.label }, action.id));
@@ -1,7 +1,9 @@
1
1
  import { type PropsWithChildren } from "react";
2
2
  import type { AcpBuiltinToolSettings, AcpProviderKey } from "./";
3
3
  import { type ContextBundleV2, type ContextItem, type ContextItemKind, type ContextOperationResult } from "./context";
4
+ import { type ImageGenerationRuntimeSettings } from "../../tools/image-generation/shared";
4
5
  type BuiltinToolSettingsUpdater = unknown | ((current: unknown) => unknown);
6
+ type ImageGenerationSettingsUpdater = ImageGenerationRuntimeSettings | null | ((current: ImageGenerationRuntimeSettings | null) => ImageGenerationRuntimeSettings | null);
5
7
  export type AcpUiRuntimeContext = {
6
8
  provider: AcpProviderKey;
7
9
  model: string | null;
@@ -13,12 +15,16 @@ export type AcpUiRuntimeContext = {
13
15
  permissionMode: string;
14
16
  workspacePath: string | null;
15
17
  builtinToolSettings: AcpBuiltinToolSettings;
18
+ runtimeBuiltinToolSettings: AcpBuiltinToolSettings;
19
+ hostImageGenerationSettings: ImageGenerationRuntimeSettings | null;
16
20
  contextBundle: ContextBundleV2;
17
21
  setProvider: (value: string | null) => void;
18
22
  setModel: (value: string | null) => void;
19
23
  setModeId: (value: string | null) => void;
20
24
  setThoughtLevel: (value: string | null) => void;
21
25
  setBuiltinToolSettings: (toolId: string, value: BuiltinToolSettingsUpdater) => void;
26
+ setHostImageGenerationSettings: (value: ImageGenerationSettingsUpdater) => ImageGenerationRuntimeSettings | null;
27
+ clearHostImageGenerationSettings: () => ImageGenerationRuntimeSettings | null;
22
28
  syncModel: (value: string | null) => void;
23
29
  syncModeId: (value: string | null) => void;
24
30
  syncThoughtLevel: (value: string | null) => void;
@@ -4,6 +4,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, use
4
4
  import { createContextBundle, filterContextBundle, } from "./context.mjs";
5
5
  import { normalizeAcpProvider } from "./provider-registry.mjs";
6
6
  import { readStoredBuiltinToolSettings, storeBuiltinToolSettings, updateClientBuiltinToolSettings, } from "../../tools/client-registry.mjs";
7
+ import { IMAGE_GENERATION_TOOL_ID, mergeImageGenerationRuntimeSettings, normalizeImageGenerationRuntimeSettings, } from "../../tools/image-generation/shared.mjs";
7
8
  const DEFAULT_PROVIDER = "codex";
8
9
  const DEFAULT_PERMISSION_MODE = "bypassPermissions";
9
10
  const AcpUiContext = createContext(null);
@@ -51,6 +52,14 @@ function emitContextChanged(context, change) {
51
52
  detail: { context, change },
52
53
  }));
53
54
  }
55
+ function mergeHostBuiltinToolSettings(storedSettings, hostImageGenerationSettings) {
56
+ if (!hostImageGenerationSettings)
57
+ return storedSettings;
58
+ return updateClientBuiltinToolSettings(storedSettings, IMAGE_GENERATION_TOOL_ID, (current) => {
59
+ var _a;
60
+ return (_a = mergeImageGenerationRuntimeSettings(current, hostImageGenerationSettings)) !== null && _a !== void 0 ? _a : current;
61
+ });
62
+ }
54
63
  export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
55
64
  const [provider, setProviderState] = useState(() => normalizeAcpProvider(defaultProvider !== null && defaultProvider !== void 0 ? defaultProvider : DEFAULT_PROVIDER));
56
65
  const [model, setModelState] = useState(null);
@@ -60,14 +69,19 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
60
69
  const [explicitModeId, setExplicitModeIdState] = useState(null);
61
70
  const [explicitThoughtLevel, setExplicitThoughtLevelState] = useState(null);
62
71
  const [builtinToolSettings, setBuiltinToolSettingsState] = useState({});
72
+ const [hostImageGenerationSettings, setHostImageGenerationSettingsState] = useState(null);
63
73
  const [contextBundle, setContextBundleState] = useState(() => createContextBundle());
64
74
  const contextBundleRef = useRef(contextBundle);
75
+ const builtinToolSettingsRef = useRef(builtinToolSettings);
76
+ const hostImageGenerationSettingsRef = useRef(hostImageGenerationSettings);
65
77
  const setContextBundle = useCallback((next) => {
66
78
  contextBundleRef.current = next;
67
79
  setContextBundleState(next);
68
80
  }, []);
69
81
  useEffect(() => {
70
- setBuiltinToolSettingsState(readStoredBuiltinToolSettings());
82
+ const stored = readStoredBuiltinToolSettings();
83
+ builtinToolSettingsRef.current = stored;
84
+ setBuiltinToolSettingsState(stored);
71
85
  }, []);
72
86
  const normalize = useCallback((value) => {
73
87
  const normalized = String(value !== null && value !== void 0 ? value : "").trim();
@@ -103,11 +117,24 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
103
117
  setExplicitThoughtLevelState(normalized);
104
118
  }, [normalize]);
105
119
  const setBuiltinToolSettings = useCallback((toolId, next) => {
106
- setBuiltinToolSettingsState((current) => {
107
- const updated = updateClientBuiltinToolSettings(current, toolId, next);
108
- storeBuiltinToolSettings(updated);
109
- return updated;
110
- });
120
+ const updated = updateClientBuiltinToolSettings(builtinToolSettingsRef.current, toolId, next);
121
+ builtinToolSettingsRef.current = updated;
122
+ storeBuiltinToolSettings(updated);
123
+ setBuiltinToolSettingsState(updated);
124
+ }, []);
125
+ const setHostImageGenerationSettings = useCallback((next) => {
126
+ const rawNext = typeof next === "function"
127
+ ? next(hostImageGenerationSettingsRef.current)
128
+ : next;
129
+ const normalized = normalizeImageGenerationRuntimeSettings(rawNext);
130
+ hostImageGenerationSettingsRef.current = normalized;
131
+ setHostImageGenerationSettingsState(normalized);
132
+ return normalized;
133
+ }, []);
134
+ const clearHostImageGenerationSettings = useCallback(() => {
135
+ hostImageGenerationSettingsRef.current = null;
136
+ setHostImageGenerationSettingsState(null);
137
+ return null;
111
138
  }, []);
112
139
  const syncModel = useCallback((next) => setModelState(normalize(next)), [normalize]);
113
140
  const syncModeId = useCallback((next) => setModeIdState(normalize(next)), [normalize]);
@@ -174,7 +201,7 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
174
201
  if (current.items.length === 0)
175
202
  return null;
176
203
  const consumed = current;
177
- const next = createChangedBundle([]);
204
+ const next = createChangedBundle(consumed.items.filter((item) => item.pinned === true));
178
205
  setContextBundle(next);
179
206
  emitContextChanged(next, {
180
207
  operation: "consume",
@@ -183,6 +210,7 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
183
210
  });
184
211
  return consumed;
185
212
  }, [setContextBundle]);
213
+ const mergedBuiltinToolSettings = useMemo(() => mergeHostBuiltinToolSettings(builtinToolSettings, hostImageGenerationSettings), [builtinToolSettings, hostImageGenerationSettings]);
186
214
  const value = useMemo(() => ({
187
215
  provider,
188
216
  model,
@@ -194,12 +222,16 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
194
222
  permissionMode: DEFAULT_PERMISSION_MODE,
195
223
  workspacePath: normalize(workspacePath !== null && workspacePath !== void 0 ? workspacePath : null),
196
224
  builtinToolSettings,
225
+ runtimeBuiltinToolSettings: mergedBuiltinToolSettings,
226
+ hostImageGenerationSettings,
197
227
  contextBundle,
198
228
  setProvider,
199
229
  setModel,
200
230
  setModeId,
201
231
  setThoughtLevel,
202
232
  setBuiltinToolSettings,
233
+ setHostImageGenerationSettings,
234
+ clearHostImageGenerationSettings,
203
235
  syncModel,
204
236
  syncModeId,
205
237
  syncThoughtLevel,
@@ -215,10 +247,13 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
215
247
  consumeContextBundle,
216
248
  contextBundle,
217
249
  builtinToolSettings,
250
+ clearHostImageGenerationSettings,
218
251
  explicitModeId,
219
252
  explicitModel,
220
253
  explicitThoughtLevel,
221
254
  getContextBundle,
255
+ hostImageGenerationSettings,
256
+ mergedBuiltinToolSettings,
222
257
  model,
223
258
  modeId,
224
259
  normalize,
@@ -229,6 +264,7 @@ export function AcpUiProvider({ children, workspacePath, defaultProvider, }) {
229
264
  setModel,
230
265
  setProvider,
231
266
  setBuiltinToolSettings,
267
+ setHostImageGenerationSettings,
232
268
  syncModeId,
233
269
  syncModel,
234
270
  syncThoughtLevel,
@@ -1,10 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
- import os from "node:os";
3
2
  import path from "node:path";
4
- const SKILL_ROOTS = [
5
- { scope: "user", relativePath: [".codex", "skills"] },
6
- { scope: "system", relativePath: [".codex", "skills", ".system"] },
7
- ];
8
3
  function normalizeText(value) {
9
4
  return typeof value === "string" ? value.trim() : "";
10
5
  }
@@ -102,20 +97,10 @@ async function listSkillsFromRoot(rootPath, scope) {
102
97
  }
103
98
  export async function listAcpUiCommands({ workspacePath, } = {}) {
104
99
  const normalizedWorkspacePath = normalizeText(workspacePath);
105
- const roots = [
106
- ...(normalizedWorkspacePath
107
- ? [
108
- {
109
- rootPath: path.join(normalizedWorkspacePath, ".codex", "skills"),
110
- scope: "project",
111
- },
112
- ]
113
- : []),
114
- ...SKILL_ROOTS.map((root) => ({
115
- rootPath: path.join(os.homedir(), ...root.relativePath),
116
- scope: root.scope,
117
- })),
118
- ];
119
- const commandGroups = await Promise.all(roots.map((root) => listSkillsFromRoot(root.rootPath, root.scope)));
100
+ if (!normalizedWorkspacePath)
101
+ return [];
102
+ const commandGroups = await Promise.all([
103
+ listSkillsFromRoot(path.join(normalizedWorkspacePath, ".agents", "skills"), "project"),
104
+ ]);
120
105
  return uniqueCommands(commandGroups.flat()).sort((left, right) => left.name.localeCompare(right.name));
121
106
  }
@@ -20,6 +20,8 @@ export type TextRange = {
20
20
  export type ContextFileItem = {
21
21
  kind: "file";
22
22
  id?: string;
23
+ hidden?: boolean;
24
+ pinned?: boolean;
23
25
  path: string;
24
26
  name?: string;
25
27
  mimeType?: string;
@@ -58,6 +60,8 @@ export type ContextAnnotationTarget = {
58
60
  export type ContextAnnotationItem = {
59
61
  kind: "annotation";
60
62
  id?: string;
63
+ hidden?: boolean;
64
+ pinned?: boolean;
61
65
  body: string;
62
66
  target: ContextAnnotationTarget;
63
67
  title?: string;
@@ -0,0 +1,2 @@
1
+ export declare function sanitizeAcpErrorMessage(message: string): string;
2
+ export declare function acpErrorToMessage(error: unknown): string;
@@ -0,0 +1,37 @@
1
+ const AGENT_STDERR_MARKER = "\n[agent stderr]\n";
2
+ const LEADING_AGENT_STDERR_MARKER = "[agent stderr]\n";
3
+ const CODEX_MCP_STARTUP_UNKNOWN_SUBMISSION_RE = /\bWARN\s+codex_acp::thread:\s+Received event for unknown submission ID:\s*(?:[0-9a-f-]+)?\s*McpStartup(?:Update|Complete)\(/;
4
+ function isIgnoredAgentStderrLine(line) {
5
+ return CODEX_MCP_STARTUP_UNKNOWN_SUBMISSION_RE.test(line);
6
+ }
7
+ function filterAgentStderr(stderrText) {
8
+ return stderrText
9
+ .split("\n")
10
+ .filter((line) => !isIgnoredAgentStderrLine(line))
11
+ .join("\n")
12
+ .trim();
13
+ }
14
+ export function sanitizeAcpErrorMessage(message) {
15
+ const normalized = message.replace(/\r\n/g, "\n");
16
+ let prefix = normalized;
17
+ let stderrText = null;
18
+ const markerIndex = normalized.indexOf(AGENT_STDERR_MARKER);
19
+ if (markerIndex >= 0) {
20
+ prefix = normalized.slice(0, markerIndex);
21
+ stderrText = normalized.slice(markerIndex + AGENT_STDERR_MARKER.length);
22
+ }
23
+ else if (normalized.startsWith(LEADING_AGENT_STDERR_MARKER)) {
24
+ prefix = "";
25
+ stderrText = normalized.slice(LEADING_AGENT_STDERR_MARKER.length);
26
+ }
27
+ if (stderrText === null)
28
+ return normalized;
29
+ const filteredStderr = filterAgentStderr(stderrText);
30
+ const trimmedPrefix = prefix.trim();
31
+ if (!filteredStderr)
32
+ return trimmedPrefix || "Internal error";
33
+ return `${trimmedPrefix}\n[agent stderr]\n${filteredStderr}`.trim();
34
+ }
35
+ export function acpErrorToMessage(error) {
36
+ return sanitizeAcpErrorMessage(error instanceof Error ? error.message : String(error));
37
+ }