@axhub/acp 0.1.0 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +4 -0
- package/.next/build-manifest.json +3 -3
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/routes-manifest.json +28 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/acp/capabilities/route.js +5 -3
- package/.next/server/app/api/acp/capabilities/route.js.nft.json +1 -1
- package/.next/server/app/api/acp/commands/route.js +1 -1
- package/.next/server/app/api/acp/commands/route.js.nft.json +1 -1
- package/.next/server/app/api/acp/runtime/route.js.nft.json +1 -1
- package/.next/server/app/api/chat/cancel/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/chat/cancel/route/build-manifest.json +9 -0
- package/.next/server/app/api/chat/cancel/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/chat/cancel/route.js +11 -0
- package/.next/server/app/api/chat/cancel/route.js.nft.json +1 -0
- package/.next/server/app/api/chat/cancel/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/chat/resume/[streamId]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/chat/resume/[streamId]/route/build-manifest.json +9 -0
- package/.next/server/app/api/chat/resume/[streamId]/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/chat/resume/[streamId]/route.js +11 -0
- package/.next/server/app/api/chat/resume/[streamId]/route.js.nft.json +1 -0
- package/.next/server/app/api/chat/resume/[streamId]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/chat/route.js +5 -3
- package/.next/server/app/api/chat/route.js.nft.json +1 -1
- package/.next/server/app/api/conversations/[threadId]/messages/route.js +4 -2
- package/.next/server/app/api/conversations/[threadId]/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/conversations/[threadId]/route.js +2 -2
- package/.next/server/app/api/conversations/[threadId]/route.js.nft.json +1 -1
- package/.next/server/app/api/conversations/[threadId]/runtime/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/conversations/[threadId]/runtime/route/build-manifest.json +9 -0
- package/.next/server/app/api/conversations/[threadId]/runtime/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/conversations/[threadId]/runtime/route.js +11 -0
- package/.next/server/app/api/conversations/[threadId]/runtime/route.js.nft.json +1 -0
- package/.next/server/app/api/conversations/[threadId]/runtime/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/conversations/route.js +2 -2
- package/.next/server/app/api/conversations/route.js.nft.json +1 -1
- package/.next/server/app/api/local-files/image/route.js.nft.json +1 -1
- package/.next/server/app/api/local-files/open/route.js.nft.json +1 -1
- package/.next/server/app/api/output-artifacts/thread/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/output-artifacts/thread/route/build-manifest.json +9 -0
- package/.next/server/app/api/output-artifacts/thread/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/output-artifacts/thread/route.js +8 -0
- package/.next/server/app/api/output-artifacts/thread/route.js.nft.json +1 -0
- package/.next/server/app/api/output-artifacts/thread/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/output-artifacts/workspace/route.js +1 -1
- package/.next/server/app/api/output-artifacts/workspace/route.js.nft.json +1 -1
- package/.next/server/app/api/tools/image-generation/files/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/tools/image-generation/records/route.js.nft.json +1 -1
- package/.next/server/app/api/tools/user-choice/route.js.nft.json +1 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/page.js +2 -2
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/session/[provider]/[sessionId]/page.js +1 -1
- package/.next/server/app/session/[provider]/[sessionId]/page.js.nft.json +1 -1
- package/.next/server/app/session/[provider]/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/thread/[threadId]/page.js +1 -1
- package/.next/server/app/thread/[threadId]/page.js.nft.json +1 -1
- package/.next/server/app/thread/[threadId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +4 -0
- package/.next/server/chunks/0zjb_server_app_api_conversations_[threadId]_runtime_route_actions_08lhdqs.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__04pn6ap._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0aovkxs._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0c.r6ru._.js +76 -0
- package/.next/server/chunks/[root-of-the-server]__0gmxr~m._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0iokgmz._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0j-lxr4._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0lbwo2g._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0ly6hop._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0ml.1wa._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0o2epta._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0os92l7._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0tmhg7j._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0txmfnw._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__0wo0b8z._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0xh8d4~._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0zmyki-._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0zn3~pq._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__13xepwb._.js +3 -0
- package/.next/server/chunks/_0_9_730._.js +107 -0
- package/.next/server/chunks/_0gx~6n6._.js +107 -0
- package/.next/server/chunks/_next-internal_server_app_api_chat_cancel_route_actions_0hdg4o_.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_chat_resume_[streamId]_route_actions_12ynw6q.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_output-artifacts_thread_route_actions_04~2mo7.js +3 -0
- package/.next/server/chunks/lib_conversations_store_ts_0gzcj38._.js +4 -4
- package/.next/server/chunks/node_modules_0nyqhq8._.js +3 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__0piffp7._.js → [root-of-the-server]__09wwymw._.js} +2 -2
- package/.next/server/chunks/ssr/{[root-of-the-server]__0488vn3._.js → [root-of-the-server]__0n6oe29._.js} +1 -1
- package/.next/server/chunks/ssr/{[root-of-the-server]__0icm-_h._.js → [root-of-the-server]__0niwg81._.js} +2 -2
- package/.next/server/chunks/ssr/_03.pm1z._.js +18 -16
- package/.next/server/chunks/ssr/_0txwi90._.js +1 -1
- package/.next/server/chunks/ssr/lib_conversations_store_ts_0-pd6d3._.js +2 -2
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js +1 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_02suzhc.js +2 -2
- package/.next/server/functions-config-manifest.json +3 -0
- package/.next/server/instrumentation.js.nft.json +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/0c~b2_-vk17t5.css +1 -0
- package/.next/static/chunks/0r125n-._y5ny.js +104 -0
- package/README.md +2 -2
- package/bin/acp.mjs +0 -48
- package/dist/components/assistant-ui/acp-command-menu.mjs +42 -9
- package/dist/components/assistant-ui/acp-elicitation-option-list.mjs +1 -1
- package/dist/components/assistant-ui/acp-selectors.mjs +1 -3
- package/dist/components/assistant-ui/file.mjs +2 -2
- package/dist/components/assistant-ui/image-generation-settings-dialog.mjs +25 -6
- package/dist/components/assistant-ui/image.mjs +2 -2
- package/dist/components/assistant-ui/markdown-text.mjs +3 -3
- package/dist/components/assistant-ui/thread/composer.d.ts +1 -1
- package/dist/components/assistant-ui/thread/composer.mjs +37 -3
- package/dist/components/assistant-ui/thread/context-chips.mjs +3 -2
- package/dist/components/assistant-ui/thread/index.mjs +1 -1
- package/dist/components/assistant-ui/thread/message-list.mjs +1 -1
- package/dist/components/assistant-ui/thread/messages.mjs +2 -2
- package/dist/components/assistant-ui/thread-list.d.ts +8 -2
- package/dist/components/assistant-ui/thread-list.mjs +80 -7
- package/dist/components/assistant-ui/threadlist-sidebar.d.ts +4 -1
- package/dist/components/assistant-ui/threadlist-sidebar.mjs +2 -2
- package/dist/components/assistant-ui/tool-fallback.d.ts +1 -1
- package/dist/components/assistant-ui/tool-fallback.mjs +48 -11
- package/dist/components/tool-ui/option-list.d.ts +2 -1
- package/dist/components/tool-ui/option-list.mjs +4 -4
- package/dist/lib/acp2aisdk/client-context.d.ts +6 -0
- package/dist/lib/acp2aisdk/client-context.mjs +43 -7
- package/dist/lib/acp2aisdk/commands.mjs +5 -20
- package/dist/lib/acp2aisdk/context.d.ts +4 -0
- package/dist/lib/acp2aisdk/errors.d.ts +2 -0
- package/dist/lib/acp2aisdk/errors.mjs +37 -0
- package/dist/lib/acp2aisdk/index.d.ts +7 -0
- package/dist/lib/acp2aisdk/index.mjs +110 -34
- package/dist/lib/acp2aisdk/provider-compat.mjs +4 -2
- package/dist/lib/acp2aisdk/provider-registry.mjs +2 -5
- package/dist/lib/acp2aisdk/resumable-ui-stream.d.ts +11 -0
- package/dist/lib/acp2aisdk/resumable-ui-stream.mjs +323 -0
- package/dist/lib/acp2aisdk/runtime-message-filter.d.ts +6 -0
- package/dist/lib/acp2aisdk/runtime-message-filter.mjs +22 -0
- package/dist/lib/acp2aisdk/runtime-persistence.d.ts +21 -0
- package/dist/lib/acp2aisdk/runtime-persistence.mjs +135 -0
- package/dist/lib/acp2aisdk/session-store.mjs +7 -1
- package/dist/lib/acp2aisdk/skill-command-cache.mjs +1 -1
- package/dist/lib/acp2aisdk/types.d.ts +0 -1
- package/dist/lib/api/client.d.ts +51 -4
- package/dist/lib/api/client.mjs +35 -4
- package/dist/lib/api/cors.mjs +7 -1
- package/dist/lib/api/http-response.d.ts +2 -0
- package/dist/lib/api/http-response.mjs +22 -0
- package/dist/lib/conversations/client-adapter.d.ts +1 -0
- package/dist/lib/conversations/client-adapter.mjs +158 -51
- package/dist/lib/conversations/provider-message-loader.d.ts +7 -0
- package/dist/lib/conversations/provider-message-loader.mjs +99 -0
- package/dist/lib/conversations/runtime-message-recovery.d.ts +9 -0
- package/dist/lib/conversations/runtime-message-recovery.mjs +95 -0
- package/dist/lib/conversations/store.d.ts +2 -2
- package/dist/lib/conversations/store.mjs +49 -149
- package/dist/lib/conversations/title-text.d.ts +3 -0
- package/dist/lib/conversations/title-text.mjs +81 -0
- package/dist/lib/conversations/types.d.ts +12 -1
- package/dist/lib/local-image-files.mjs +9 -1
- package/dist/lib/local-image-paths.mjs +31 -6
- package/dist/lib/output-artifacts/thread.d.ts +22 -0
- package/dist/lib/output-artifacts/thread.mjs +47 -0
- package/dist/lib/output-artifacts/workspace.mjs +6 -2
- package/dist/lib/provider-history/codex.mjs +5 -30
- package/dist/public-api/server.d.ts +1 -1
- package/dist/public-api/server.mjs +1 -1
- package/dist/tools/image-generation/client.mjs +6 -4
- package/dist/tools/image-generation/server.mjs +3 -1
- package/dist/tools/image-generation/shared.d.ts +1 -0
- package/dist/tools/image-generation/shared.mjs +4 -0
- package/dist/tools/image-generation/ui-detail.mjs +66 -2
- package/dist/tools/user-choice/ui.mjs +66 -30
- package/package.json +6 -6
- package/.next/server/chunks/[root-of-the-server]__04xq..~._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__07sxz4_._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0dwg3fr._.js +0 -178
- package/.next/server/chunks/[root-of-the-server]__0eanzwb._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0gqx~5k._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0~mtsby._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__10-n4io._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__10g507v._.js +0 -3
- package/.next/static/chunks/0zftsky7gte_9.js +0 -102
- package/.next/static/chunks/1610ha42i.fl~.css +0 -1
- /package/.next/static/{mbk_N5Gs4ZJg3lciRL6ya → 0241KNhzDEg6VFWZ_e_qK}/_buildManifest.js +0 -0
- /package/.next/static/{mbk_N5Gs4ZJg3lciRL6ya → 0241KNhzDEg6VFWZ_e_qK}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{mbk_N5Gs4ZJg3lciRL6ya → 0241KNhzDEg6VFWZ_e_qK}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -24,8 +24,8 @@ npx -y @axhub/acp --cors-origin https://client.example.com
|
|
|
24
24
|
### External Integration
|
|
25
25
|
|
|
26
26
|
- [HTTP Chat API](docs/http-chat-api.md) documents `POST /api/chat`, including request parameters, stream chunks, response headers, a one-shot command example, and a live message listener example.
|
|
27
|
-
- [Post Message API](docs/post-message-api.md) documents the browser `postMessage` bridge for iframe/opened-window context injection.
|
|
28
|
-
- [Host Integration](docs/host-integration.md) documents generic iframe/child-window embedding, runtime API base configuration, context injection, HTTP chat execution, image generation, and React component reuse.
|
|
27
|
+
- [Post Message API](docs/post-message-api.md) documents the browser `postMessage` bridge for iframe/opened-window context injection, host runtime configuration, UI-originated chat/attachments, thread snapshot queries, and lifecycle subscriptions.
|
|
28
|
+
- [Host Integration](docs/host-integration.md) documents generic iframe/child-window embedding, runtime API base configuration, context injection, runtime config injection, postMessage thread queries, HTTP chat execution, image generation, and React component reuse.
|
|
29
29
|
- [Component And Runtime API](docs/component-runtime-api.md) documents package-level `@axhub/acp/ui`, `@axhub/acp/runtime`, `@axhub/acp/server`, `@axhub/acp/react`, and `@axhub/acp/react/styles.css` entries for component/runtime reuse, including embedded runtime API base configuration and Composer host extension props.
|
|
30
30
|
|
|
31
31
|
### 1. Configure Codex
|
package/bin/acp.mjs
CHANGED
|
@@ -92,10 +92,6 @@ function parseArgs(args) {
|
|
|
92
92
|
return { help: false, options };
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
function quoteCommandArg(value) {
|
|
96
|
-
return /[\s"']/u.test(value) ? `"${value.replace(/"/gu, '\\"')}"` : value;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
95
|
function runtimeHostForUrl(hostname) {
|
|
100
96
|
const normalized = String(hostname || "")
|
|
101
97
|
.trim()
|
|
@@ -124,47 +120,6 @@ function buildServerRuntimeEnv(options) {
|
|
|
124
120
|
};
|
|
125
121
|
}
|
|
126
122
|
|
|
127
|
-
function codexAcpCommandLine() {
|
|
128
|
-
const codexAcpBin = require.resolve(
|
|
129
|
-
"@zed-industries/codex-acp/bin/codex-acp.js",
|
|
130
|
-
);
|
|
131
|
-
return [process.execPath, codexAcpBin].map(quoteCommandArg).join(" ");
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function isCodexProviderName(value) {
|
|
135
|
-
const normalized = String(value || "")
|
|
136
|
-
.trim()
|
|
137
|
-
.toLowerCase();
|
|
138
|
-
return normalized === "codex" || normalized === "openai";
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function hasCodexCommandOverride(env) {
|
|
142
|
-
if (env.ACP_CODEX_COMMAND?.trim()) return true;
|
|
143
|
-
|
|
144
|
-
const rawJson =
|
|
145
|
-
env.ACP_PROVIDER_COMMAND_OVERRIDES || env.AXHUB_ACP_COMMAND_OVERRIDES;
|
|
146
|
-
if (!rawJson) return false;
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
const parsed = JSON.parse(rawJson);
|
|
150
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
for (const [providerName, value] of Object.entries(parsed)) {
|
|
154
|
-
if (!isCodexProviderName(providerName)) continue;
|
|
155
|
-
if (typeof value === "string") return Boolean(value.trim());
|
|
156
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
return typeof value.command === "string" && Boolean(value.command.trim());
|
|
160
|
-
}
|
|
161
|
-
} catch {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
123
|
let parsed;
|
|
169
124
|
try {
|
|
170
125
|
parsed = parseArgs(process.argv.slice(2));
|
|
@@ -208,9 +163,6 @@ const child = spawn(process.execPath, [nextBin, ...nextArgs], {
|
|
|
208
163
|
ACP_UI_DEFAULT_WORKSPACE_PATH:
|
|
209
164
|
process.env.ACP_UI_DEFAULT_WORKSPACE_PATH || launchCwd,
|
|
210
165
|
...buildServerRuntimeEnv(parsed.options),
|
|
211
|
-
...(hasCodexCommandOverride(process.env)
|
|
212
|
-
? {}
|
|
213
|
-
: { ACP_CODEX_COMMAND: codexAcpCommandLine() }),
|
|
214
166
|
},
|
|
215
167
|
stdio: "inherit",
|
|
216
168
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { ComposerPrimitive, useAui, useAuiState, } from "@assistant-ui/react";
|
|
3
|
+
import { ComposerPrimitive, useAui, useAuiState, unstable_useTriggerPopoverScopeContext as useTriggerPopoverScopeContext, } from "@assistant-ui/react";
|
|
4
4
|
import { SlashIcon, SparklesIcon } from "lucide-react";
|
|
5
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
6
6
|
import { Button } from "../ui/button.mjs";
|
|
7
7
|
import { useAcpUiRuntimeContext } from "../../lib/acp2aisdk/client-context.mjs";
|
|
8
8
|
import { persistSkillCommandCache, readSkillCommandCache, shouldFetchSkillCommands, } from "../../lib/acp2aisdk/skill-command-cache.mjs";
|
|
@@ -107,7 +107,6 @@ export function AcpCommandTriggerButton() {
|
|
|
107
107
|
}, children: _jsx(SlashIcon, { className: "size-4" }) }));
|
|
108
108
|
}
|
|
109
109
|
export function AcpCommandMenu() {
|
|
110
|
-
const aui = useAui();
|
|
111
110
|
const { provider, workspacePath } = useAcpUiRuntimeContext();
|
|
112
111
|
const threadId = useAuiState((state) => state.threads.mainThreadId);
|
|
113
112
|
const messages = useAuiState((state) => state.thread.messages);
|
|
@@ -164,12 +163,46 @@ export function AcpCommandMenu() {
|
|
|
164
163
|
setCommands(nextCommands);
|
|
165
164
|
}, [provider, runtimeCommands, workspacePath]);
|
|
166
165
|
const adapter = useMemo(() => createCommandAdapter(commands), [commands]);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
const popoverRef = useRef(null);
|
|
167
|
+
return (_jsxs(ComposerPrimitive.Unstable_TriggerPopover, { ref: popoverRef, char: "/", adapter: adapter, className: "absolute bottom-full left-0 z-50 mb-3 w-[min(26rem,calc(100vw-2rem))] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md", children: [_jsx(AcpCommandPopoverDismiss, { popoverRef: popoverRef }), _jsx(AcpCommandAction, { commandsRef: commandsRef }), _jsx("div", { className: "max-h-80 overflow-y-auto p-1.5", children: _jsx(ComposerPrimitive.Unstable_TriggerPopoverItems, { children: (items) => items.length ? (items.map((item, index) => (_jsxs(ComposerPrimitive.Unstable_TriggerPopoverItem, { item: item, index: index, className: cn("flex min-h-10 w-full items-start gap-2 rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground data-[highlighted=true]:bg-accent"), children: [_jsx(SparklesIcon, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-mono", children: item.label }), item.description ? (_jsx("span", { className: "block truncate text-muted-foreground text-xs", children: item.description })) : null] })] }, `${item.type}-${item.id}`)))) : (_jsx(EmptyCommandState, {})) }) })] }));
|
|
168
|
+
}
|
|
169
|
+
function AcpCommandPopoverDismiss({ popoverRef, }) {
|
|
170
|
+
const { close, open } = useTriggerPopoverScopeContext();
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (!open)
|
|
173
|
+
return;
|
|
174
|
+
function isInside(target) {
|
|
175
|
+
var _a;
|
|
176
|
+
return target instanceof Node && ((_a = popoverRef.current) === null || _a === void 0 ? void 0 : _a.contains(target));
|
|
177
|
+
}
|
|
178
|
+
function handlePointerDown(event) {
|
|
179
|
+
if (!isInside(event.target))
|
|
180
|
+
close();
|
|
181
|
+
}
|
|
182
|
+
function handleFocusIn(event) {
|
|
183
|
+
if (!isInside(event.target))
|
|
184
|
+
close();
|
|
185
|
+
}
|
|
186
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
187
|
+
document.addEventListener("focusin", handleFocusIn);
|
|
188
|
+
return () => {
|
|
189
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
190
|
+
document.removeEventListener("focusin", handleFocusIn);
|
|
191
|
+
};
|
|
192
|
+
}, [close, open, popoverRef]);
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
function AcpCommandAction({ commandsRef, }) {
|
|
196
|
+
const aui = useAui();
|
|
197
|
+
const { close } = useTriggerPopoverScopeContext();
|
|
198
|
+
const handleExecute = useCallback((item) => {
|
|
199
|
+
var _a;
|
|
200
|
+
const command = commandsRef.current.find((candidate) => candidate.name === item.id);
|
|
201
|
+
const nextText = (_a = command === null || command === void 0 ? void 0 : command.name) !== null && _a !== void 0 ? _a : item.label;
|
|
202
|
+
aui.thread().composer().setText(`${nextText} `);
|
|
203
|
+
close();
|
|
204
|
+
}, [aui, close, commandsRef]);
|
|
205
|
+
return (_jsx(ComposerPrimitive.Unstable_TriggerPopover.Action, { removeOnExecute: true, onExecute: handleExecute }));
|
|
173
206
|
}
|
|
174
207
|
function EmptyCommandState() {
|
|
175
208
|
return (_jsx("div", { className: "px-3 py-4 text-center text-muted-foreground text-sm", children: "\u6682\u65E0\u53EF\u7528\u547D\u4EE4" }));
|
|
@@ -131,8 +131,8 @@ export function AcpElicitationOptionListCard(part) {
|
|
|
131
131
|
: "text-primary") }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "break-words font-medium text-base leading-snug", children: payload.message }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-muted-foreground text-xs", children: [_jsx("span", { children: payload.fieldTitle }), _jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsx("span", { children: statusLabel })] }), payload.fieldDescription && (_jsx("div", { className: "mt-2 break-words text-muted-foreground text-sm leading-snug", children: payload.fieldDescription }))] })] }), isReceipt ? (_jsxs("div", { className: cn("flex items-center gap-2 rounded-md border px-3 py-2 text-sm", isAcceptedReceipt
|
|
132
132
|
? "border-emerald-200 bg-emerald-50 text-emerald-900 dark:border-emerald-900/50 dark:bg-emerald-950/30 dark:text-emerald-200"
|
|
133
133
|
: "border-muted-foreground/20 bg-muted/40 text-muted-foreground"), children: [isAcceptedReceipt ? (_jsx(CheckIcon, { className: "size-4 shrink-0" })) : (_jsx(XCircleIcon, { className: "size-4 shrink-0" })), _jsx("span", { className: "min-w-0 break-words", children: getReceiptText(payload, receiptAction, displayedChoice) })] })) : (_jsx(OptionList, { id: payload.toolCallId || part.toolCallId, options: payload.options, selectionMode: payload.selectionMode, defaultValue: payload.defaultValue, minSelections: payload.minSelections, maxSelections: payload.maxSelections, className: "my-0 border-0 bg-transparent p-0 shadow-none", actions: [
|
|
134
|
-
{ id: "confirm", label: "确认" },
|
|
135
134
|
{ id: "cancel", label: "取消", variant: "outline" },
|
|
135
|
+
{ id: "confirm", label: "确认" },
|
|
136
136
|
], onAction: (actionId, selectedValue) => {
|
|
137
137
|
if (disabled)
|
|
138
138
|
return;
|
|
@@ -32,9 +32,7 @@ function getOptionLabel(options, value) {
|
|
|
32
32
|
const PROVIDER_OPTIONS = ACP_PROVIDER_KEYS.map((provider, index) => ({
|
|
33
33
|
value: provider,
|
|
34
34
|
label: ACP_PROVIDER_REGISTRY[provider].label,
|
|
35
|
-
description:
|
|
36
|
-
? "已验证"
|
|
37
|
-
: "需本地 CLI/登录",
|
|
35
|
+
description: "需先安装并登录",
|
|
38
36
|
order: index,
|
|
39
37
|
}));
|
|
40
38
|
function capabilityOptions(snapshot, key) {
|
|
@@ -15,7 +15,7 @@ import { cva } from "class-variance-authority";
|
|
|
15
15
|
import { BracesIcon, DownloadIcon, FileIcon, FileTextIcon, ImageIcon, MusicIcon, VideoIcon, } from "lucide-react";
|
|
16
16
|
import { memo } from "react";
|
|
17
17
|
import { cn } from "../../lib/utils.mjs";
|
|
18
|
-
const fileVariants = cva("aui-file-root inline-flex items-center gap-3 rounded-lg transition-colors", {
|
|
18
|
+
const fileVariants = cva("aui-file-root inline-flex max-w-full items-center gap-3 rounded-lg transition-colors", {
|
|
19
19
|
variants: {
|
|
20
20
|
variant: {
|
|
21
21
|
outline: "border-border border hover:bg-muted/50",
|
|
@@ -95,7 +95,7 @@ function FileDownload(_a) {
|
|
|
95
95
|
}
|
|
96
96
|
const FileImpl = ({ filename, data, mimeType }) => {
|
|
97
97
|
const bytes = getBase64Size(data);
|
|
98
|
-
return (_jsxs(FileRoot, { children: [_jsx(FileIconDisplay, { mimeType: mimeType }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx(FileName, { children: filename }), _jsx(FileSize, { bytes: bytes, className: "text-xs" })] }), _jsx(FileDownload, Object.assign({ data: data, mimeType: mimeType }, (filename !== undefined && { filename })))] }));
|
|
98
|
+
return (_jsxs(FileRoot, { className: "flex w-fit", children: [_jsx(FileIconDisplay, { mimeType: mimeType }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx(FileName, { children: filename }), _jsx(FileSize, { bytes: bytes, className: "text-xs" })] }), _jsx(FileDownload, Object.assign({ data: data, mimeType: mimeType }, (filename !== undefined && { filename })))] }));
|
|
99
99
|
};
|
|
100
100
|
const File = memo(FileImpl);
|
|
101
101
|
File.displayName = "File";
|
|
@@ -6,22 +6,41 @@ import { Label } from "../ui/label.mjs";
|
|
|
6
6
|
import { Switch } from "../ui/switch.mjs";
|
|
7
7
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs.mjs";
|
|
8
8
|
import { useAcpUiRuntimeContext } from "../../lib/acp2aisdk/client-context.mjs";
|
|
9
|
-
import { normalizeImageGenerationToolSettings } from "../../tools/image-generation/client.mjs";
|
|
10
|
-
import { IMAGE_GENERATION_TOOL_ID } from "../../tools/image-generation/shared.mjs";
|
|
9
|
+
import { normalizeImageGenerationToolSettings, } from "../../tools/image-generation/client.mjs";
|
|
10
|
+
import { hasCompleteImageGenerationRuntimeSettings, IMAGE_GENERATION_TOOL_ID, normalizeImageGenerationRuntimeSettings, } from "../../tools/image-generation/shared.mjs";
|
|
11
11
|
import { normalizeUserChoiceToolSettings } from "../../tools/user-choice/client.mjs";
|
|
12
12
|
import { USER_CHOICE_TOOL_ID } from "../../tools/user-choice/shared.mjs";
|
|
13
13
|
export function ImageGenerationSettingsDialog({ trigger, }) {
|
|
14
14
|
var _a, _b, _c;
|
|
15
|
-
const { builtinToolSettings, setBuiltinToolSettings } = useAcpUiRuntimeContext();
|
|
16
|
-
const
|
|
15
|
+
const { builtinToolSettings, hostImageGenerationSettings, runtimeBuiltinToolSettings, setBuiltinToolSettings, setHostImageGenerationSettings, } = useAcpUiRuntimeContext();
|
|
16
|
+
const hasHostImageGenerationSettings = Boolean(hostImageGenerationSettings);
|
|
17
|
+
const imageGenerationToolSettings = normalizeImageGenerationToolSettings(runtimeBuiltinToolSettings[IMAGE_GENERATION_TOOL_ID]);
|
|
18
|
+
const imageGenerationSettingsComplete = hasCompleteImageGenerationRuntimeSettings(imageGenerationToolSettings);
|
|
17
19
|
const userChoiceToolSettings = normalizeUserChoiceToolSettings(builtinToolSettings[USER_CHOICE_TOOL_ID]);
|
|
20
|
+
const updateImageGenerationSettings = (updater) => {
|
|
21
|
+
if (hasHostImageGenerationSettings) {
|
|
22
|
+
setHostImageGenerationSettings((current) => {
|
|
23
|
+
var _a;
|
|
24
|
+
return updater(normalizeImageGenerationToolSettings(Object.assign(Object.assign({}, imageGenerationToolSettings), ((_a = normalizeImageGenerationRuntimeSettings(current)) !== null && _a !== void 0 ? _a : {}))));
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
setBuiltinToolSettings(IMAGE_GENERATION_TOOL_ID, (current) => updater(normalizeImageGenerationToolSettings(current)));
|
|
29
|
+
};
|
|
18
30
|
const updateSetting = (key, value) => {
|
|
19
|
-
|
|
31
|
+
updateImageGenerationSettings((current) => (Object.assign(Object.assign({}, current), { [key]: value })));
|
|
32
|
+
};
|
|
33
|
+
const updateConnectionSetting = (key, value) => {
|
|
34
|
+
updateImageGenerationSettings((current) => {
|
|
35
|
+
const next = Object.assign(Object.assign({}, current), { [key]: value });
|
|
36
|
+
return Object.assign(Object.assign({}, next), { enabled: next.enabled && hasCompleteImageGenerationRuntimeSettings(next) });
|
|
37
|
+
});
|
|
20
38
|
};
|
|
21
39
|
const updateUserChoiceSetting = (key, value) => {
|
|
22
40
|
setBuiltinToolSettings(USER_CHOICE_TOOL_ID, (current) => (Object.assign(Object.assign({}, normalizeUserChoiceToolSettings(current)), { [key]: value })));
|
|
23
41
|
};
|
|
24
|
-
return (_jsxs(Dialog, { children: [_jsx(DialogTrigger, { asChild: true, children: trigger }), _jsxs(DialogContent, { className: "sm:max-w-xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "\u5DE5\u5177\u8BBE\u7F6E" }), _jsx(DialogDescription, { children: "\u914D\u7F6E\u5185\u7F6E\u5DE5\u5177\u7684\u8FDE\u63A5\u4FE1\u606F\u548C\u4EA4\u4E92\u884C\u4E3A\u3002" })] }), _jsxs(Tabs, { defaultValue: "image-generation", children: [_jsxs(TabsList, { className: "grid w-full grid-cols-2", children: [_jsx(TabsTrigger, { value: "image-generation", children: "\u56FE\u7247\u751F\u6210" }), _jsx(TabsTrigger, { value: "user-choice", children: "\u7528\u6237\u9009\u62E9" })] }), _jsxs(TabsContent, { value: "image-generation", className: "grid gap-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3 rounded-md border px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Label, { htmlFor: "image-generation-enabled", children: "\u56FE\u7247\u751F\u6210\u5DE5\u5177" }), _jsx("p", { className: "mt-1 text-muted-foreground text-xs", children: "\
|
|
42
|
+
return (_jsxs(Dialog, { children: [_jsx(DialogTrigger, { asChild: true, children: trigger }), _jsxs(DialogContent, { className: "sm:max-w-xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "\u5DE5\u5177\u8BBE\u7F6E" }), _jsx(DialogDescription, { children: "\u914D\u7F6E\u5185\u7F6E\u5DE5\u5177\u7684\u8FDE\u63A5\u4FE1\u606F\u548C\u4EA4\u4E92\u884C\u4E3A\u3002" })] }), _jsxs(Tabs, { defaultValue: "image-generation", children: [_jsxs(TabsList, { className: "grid w-full grid-cols-2", children: [_jsx(TabsTrigger, { value: "image-generation", children: "\u56FE\u7247\u751F\u6210" }), _jsx(TabsTrigger, { value: "user-choice", children: "\u7528\u6237\u9009\u62E9" })] }), _jsxs(TabsContent, { value: "image-generation", className: "grid gap-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3 rounded-md border px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Label, { htmlFor: "image-generation-enabled", children: "\u56FE\u7247\u751F\u6210\u5DE5\u5177" }), _jsx("p", { className: "mt-1 text-muted-foreground text-xs", children: "\u586B\u5199 API Base URL\u3001API Key \u548C\u6A21\u578B\u540E\u53EF\u5F00\u542F\u3002" })] }), _jsx(Switch, { id: "image-generation-enabled", checked: imageGenerationToolSettings.enabled &&
|
|
43
|
+
imageGenerationSettingsComplete, disabled: !imageGenerationSettingsComplete, onCheckedChange: (checked) => updateSetting("enabled", checked) })] }), _jsx(SettingsInput, { id: "image-generation-base-url", label: "API Base URL", placeholder: "https://api.openai.com/v1", value: (_a = imageGenerationToolSettings.baseUrl) !== null && _a !== void 0 ? _a : "", onValueChange: (value) => updateConnectionSetting("baseUrl", value) }), _jsx(SettingsInput, { id: "image-generation-api-key", label: "API Key", placeholder: "sk-...", type: "password", value: (_b = imageGenerationToolSettings.apiKey) !== null && _b !== void 0 ? _b : "", onValueChange: (value) => updateConnectionSetting("apiKey", value) }), _jsx(SettingsInput, { id: "image-generation-model", label: "\u6A21\u578B", placeholder: "gpt-image-1", value: (_c = imageGenerationToolSettings.model) !== null && _c !== void 0 ? _c : "", onValueChange: (value) => updateConnectionSetting("model", value) }), _jsxs("div", { className: "flex items-center justify-between gap-3 rounded-md border px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Label, { htmlFor: "image-generation-preserve-prompt", children: "\u4FDD\u7559\u539F\u59CB\u63D0\u793A\u8BCD" }), _jsx("p", { className: "mt-1 text-muted-foreground text-xs", children: "\u8BF7\u6C42\u56FE\u7247 API \u65F6\u5728 prompt \u524D\u52A0\u5165\u4E0D\u8981\u6539\u5199\u63D0\u793A\uFF0C\u8BB0\u5F55\u4ECD\u663E\u793A\u539F\u59CB\u63D0\u793A\u8BCD\u3002" })] }), _jsx(Switch, { id: "image-generation-preserve-prompt", checked: imageGenerationToolSettings.preservePrompt, onCheckedChange: (checked) => updateSetting("preservePrompt", checked) })] })] }), _jsxs(TabsContent, { value: "user-choice", className: "grid gap-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3 rounded-md border px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Label, { htmlFor: "user-choice-enabled", children: "\u7528\u6237\u9009\u62E9\u5DE5\u5177" }), _jsx("p", { className: "mt-1 text-muted-foreground text-xs", children: "\u5141\u8BB8\u6A21\u578B\u901A\u8FC7 MCP \u53D1\u8D77\u5355\u9009\u3001\u591A\u9009\u6216\u591A\u9898\u9009\u62E9\u3002" })] }), _jsx(Switch, { id: "user-choice-enabled", checked: userChoiceToolSettings.enabled, onCheckedChange: (checked) => updateUserChoiceSetting("enabled", checked) })] }), _jsx(SettingsInput, { id: "user-choice-timeout-ms", label: "\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09", type: "number", value: String(userChoiceToolSettings.waitTimeoutMs), onValueChange: (value) => updateUserChoiceSetting("waitTimeoutMs", Number.parseInt(value, 10)) }), _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Label, { htmlFor: "user-choice-custom-input", children: "\u5141\u8BB8\u81EA\u5B9A\u4E49\u8F93\u5165" }), _jsx(Switch, { id: "user-choice-custom-input", checked: userChoiceToolSettings.allowCustomInput, onCheckedChange: (checked) => updateUserChoiceSetting("allowCustomInput", checked) })] }), _jsx(SettingsInput, { id: "user-choice-custom-input-label", label: "\u81EA\u5B9A\u4E49\u9009\u9879\u6587\u6848", value: userChoiceToolSettings.customInputLabel, onValueChange: (value) => updateUserChoiceSetting("customInputLabel", value) })] })] }), _jsx(DialogFooter, { showCloseButton: true })] })] }));
|
|
25
44
|
}
|
|
26
45
|
function SettingsInput({ id, label, value, onValueChange, placeholder, type = "text", }) {
|
|
27
46
|
return (_jsxs("div", { className: "grid gap-2", children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(Input, { id: id, type: type, value: value, placeholder: placeholder, onChange: (event) => onValueChange(event.currentTarget.value) })] }));
|
|
@@ -81,7 +81,7 @@ const copyImagePart = async (part) => {
|
|
|
81
81
|
const mime = (_b = (_a = mimeFromImage(part.image)) !== null && _a !== void 0 ? _a : blob.type) !== null && _b !== void 0 ? _b : "image/png";
|
|
82
82
|
await navigator.clipboard.write([new ClipboardItem({ [mime]: blob })]);
|
|
83
83
|
};
|
|
84
|
-
const imageVariants = cva("aui-image-root relative overflow-hidden rounded-lg", {
|
|
84
|
+
const imageVariants = cva("aui-image-root relative w-fit max-w-full overflow-hidden rounded-lg", {
|
|
85
85
|
variants: {
|
|
86
86
|
variant: {
|
|
87
87
|
outline: "border-border border",
|
|
@@ -90,7 +90,7 @@ const imageVariants = cva("aui-image-root relative overflow-hidden rounded-lg",
|
|
|
90
90
|
},
|
|
91
91
|
size: {
|
|
92
92
|
sm: "max-w-64",
|
|
93
|
-
default: "
|
|
93
|
+
default: "max-w-[30vw] max-md:max-w-full",
|
|
94
94
|
lg: "max-w-[512px]",
|
|
95
95
|
full: "w-full",
|
|
96
96
|
},
|
|
@@ -97,7 +97,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
97
97
|
},
|
|
98
98
|
p: (_a) => {
|
|
99
99
|
var { className } = _a, props = __rest(_a, ["className"]);
|
|
100
|
-
return (_jsx("div", Object.assign({ className: cn("aui-md-p my-2
|
|
100
|
+
return (_jsx("div", Object.assign({ className: cn("aui-md-p my-2 leading-[1.6] first:mt-0 last:mb-0 md:my-2.5 md:leading-[1.7]", className) }, props)));
|
|
101
101
|
},
|
|
102
102
|
a: (_a) => {
|
|
103
103
|
var { className, href, children } = _a, props = __rest(_a, ["className", "href", "children"]);
|
|
@@ -159,7 +159,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
159
159
|
},
|
|
160
160
|
li: (_a) => {
|
|
161
161
|
var { className } = _a, props = __rest(_a, ["className"]);
|
|
162
|
-
return (_jsx("li", Object.assign({ className: cn("aui-md-li leading-[1.7]", className) }, props)));
|
|
162
|
+
return (_jsx("li", Object.assign({ className: cn("aui-md-li leading-[1.6] md:leading-[1.7]", className) }, props)));
|
|
163
163
|
},
|
|
164
164
|
sup: (_a) => {
|
|
165
165
|
var { className } = _a, props = __rest(_a, ["className"]);
|
|
@@ -199,7 +199,7 @@ function LocalFile({ path, className }) {
|
|
|
199
199
|
body: JSON.stringify({ path }),
|
|
200
200
|
}).catch(() => { });
|
|
201
201
|
};
|
|
202
|
-
return (_jsxs(File.Root, { role: "button", tabIndex: 0, className: cn("my-
|
|
202
|
+
return (_jsxs(File.Root, { role: "button", tabIndex: 0, className: cn("my-1.5 flex w-fit cursor-pointer", className), onClick: openFile, onKeyDown: (event) => {
|
|
203
203
|
if (event.key === "Enter" || event.key === " ") {
|
|
204
204
|
event.preventDefault();
|
|
205
205
|
openFile();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComposerPrimitive } from "@assistant-ui/react";
|
|
2
|
-
import type
|
|
2
|
+
import { type ComponentPropsWithoutRef, type FC, type ReactNode } from "react";
|
|
3
3
|
type ComposerInputProps = ComponentPropsWithoutRef<typeof ComposerPrimitive.Input>;
|
|
4
4
|
export type ComposerProps = {
|
|
5
5
|
placeholder?: string;
|
|
@@ -1,15 +1,49 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { AuiIf, ComposerPrimitive } from "@assistant-ui/react";
|
|
3
|
+
import { AuiIf, ComposerPrimitive, useAui, useAuiState, } from "@assistant-ui/react";
|
|
4
4
|
import { ArrowUpIcon, SquareIcon } from "lucide-react";
|
|
5
|
+
import { useCallback, } from "react";
|
|
5
6
|
import { AcpCommandMenu } from "../acp-command-menu.mjs";
|
|
6
7
|
import { AcpComposerSelectors } from "../acp-selectors.mjs";
|
|
7
8
|
import { ComposerAddAttachment, ComposerAttachments, } from "../attachment.mjs";
|
|
8
9
|
import { TooltipIconButton } from "../tooltip-icon-button.mjs";
|
|
9
10
|
import { Button } from "../../ui/button.mjs";
|
|
11
|
+
import { useAcpUiRuntimeContext } from "../../../lib/acp2aisdk/client-context.mjs";
|
|
12
|
+
import { acpApiClient } from "../../../lib/api/client.mjs";
|
|
10
13
|
export const Composer = ({ addAttachmentLabel, ariaLabel = "消息输入框", leadingActions, onPaste, placeholder = "输入 / 使用技能,或直接发送消息...", sendLabel, showAttachments = true, showCommandMenu = true, showSelectors = true, trailingActions, triggerPopovers, }) => {
|
|
11
|
-
|
|
14
|
+
const aui = useAui();
|
|
15
|
+
const cancelActiveChatRun = useCancelActiveChatRun();
|
|
16
|
+
const handleInputKeyDown = useCallback((event) => {
|
|
17
|
+
if (event.key !== "Escape")
|
|
18
|
+
return;
|
|
19
|
+
const composer = aui.composer();
|
|
20
|
+
queueMicrotask(() => {
|
|
21
|
+
if (event.defaultPrevented)
|
|
22
|
+
return;
|
|
23
|
+
if (!composer.getState().canCancel)
|
|
24
|
+
return;
|
|
25
|
+
cancelActiveChatRun();
|
|
26
|
+
composer.cancel();
|
|
27
|
+
});
|
|
28
|
+
}, [aui, cancelActiveChatRun]);
|
|
29
|
+
return (_jsx(ComposerPrimitive.Root, { className: "aui-composer-root relative flex w-full flex-col", children: _jsx(ComposerPrimitive.AttachmentDropzone, { asChild: true, children: _jsxs("div", { "data-slot": "aui_composer-shell", className: "flex w-full flex-col gap-2 rounded-(--composer-radius) border bg-background p-(--composer-padding) transition-shadow focus-within:border-ring/75 focus-within:ring-2 focus-within:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50", children: [_jsxs(ComposerPrimitive.Unstable_TriggerPopoverRoot, { children: [showAttachments ? _jsx(ComposerAttachments, {}) : null, _jsx(ComposerPrimitive.Input, { placeholder: placeholder, className: "aui-composer-input max-h-32 min-h-10 w-full resize-none bg-transparent px-1.75 py-1 text-[13px] outline-none placeholder:text-muted-foreground/80 md:text-sm", rows: 1, autoFocus: true, "aria-label": ariaLabel, cancelOnEscape: false, onKeyDown: handleInputKeyDown, onPaste: onPaste }), showCommandMenu ? _jsx(AcpCommandMenu, {}) : null, triggerPopovers] }), _jsx(ComposerAction, { addAttachmentLabel: addAttachmentLabel, leadingActions: leadingActions, sendLabel: sendLabel, showAddAttachment: showAttachments, showSelectors: showSelectors, trailingActions: trailingActions })] }) }) }));
|
|
12
30
|
};
|
|
13
31
|
export const ComposerAction = ({ addAttachmentLabel, leadingActions, sendLabel = "发送消息", showAddAttachment = true, showSelectors = true, trailingActions, }) => {
|
|
14
|
-
|
|
32
|
+
const cancelActiveChatRun = useCancelActiveChatRun();
|
|
33
|
+
return (_jsxs("div", { className: "aui-composer-action-wrapper relative flex items-center justify-between text-[13px] md:text-sm", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [showAddAttachment ? (_jsx(ComposerAddAttachment, { label: addAttachmentLabel })) : null, showSelectors ? _jsx(AcpComposerSelectors, {}) : null, leadingActions] }), _jsxs("div", { className: "flex items-center gap-1", children: [trailingActions, _jsx(AuiIf, { condition: (s) => !s.thread.isRunning, children: _jsx(ComposerPrimitive.Send, { asChild: true, children: _jsx(TooltipIconButton, { tooltip: sendLabel, side: "bottom", type: "button", variant: "default", size: "icon", className: "aui-composer-send size-8 rounded-full", "aria-label": sendLabel, children: _jsx(ArrowUpIcon, { className: "aui-composer-send-icon size-4" }) }) }) }), _jsx(AuiIf, { condition: (s) => s.thread.isRunning, children: _jsx(ComposerPrimitive.Cancel, { asChild: true, children: _jsx(Button, { type: "button", variant: "default", size: "icon", className: "aui-composer-cancel size-8 rounded-full", "aria-label": "\u505C\u6B62\u751F\u6210", onClick: () => {
|
|
34
|
+
cancelActiveChatRun();
|
|
35
|
+
}, children: _jsx(SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" }) }) }) })] })] }));
|
|
15
36
|
};
|
|
37
|
+
function useCancelActiveChatRun() {
|
|
38
|
+
const { provider, workspacePath } = useAcpUiRuntimeContext();
|
|
39
|
+
const remoteId = useAuiState((state) => state.threadListItem.remoteId);
|
|
40
|
+
const mainThreadId = useAuiState((state) => state.threads.mainThreadId);
|
|
41
|
+
const threadId = remoteId !== null && remoteId !== void 0 ? remoteId : mainThreadId;
|
|
42
|
+
return useCallback(() => {
|
|
43
|
+
void acpApiClient.cancelChat({
|
|
44
|
+
threadId,
|
|
45
|
+
provider,
|
|
46
|
+
workspacePath,
|
|
47
|
+
});
|
|
48
|
+
}, [provider, threadId, workspacePath]);
|
|
49
|
+
}
|
|
@@ -103,9 +103,10 @@ function getContextChipTooltip(item, workspacePath) {
|
|
|
103
103
|
}
|
|
104
104
|
export const ContextChips = () => {
|
|
105
105
|
const { contextBundle, removeContextItems, workspacePath } = useAcpUiRuntimeContext();
|
|
106
|
-
|
|
106
|
+
const visibleItems = contextBundle.items.filter((item) => item.hidden !== true);
|
|
107
|
+
if (visibleItems.length === 0)
|
|
107
108
|
return null;
|
|
108
|
-
return (_jsx("div", { className: "flex min-h-11 w-full items-center", children: _jsx("div", { className: "flex w-full flex-wrap items-center gap-1.5 px-1", children:
|
|
109
|
+
return (_jsx("div", { className: "flex min-h-11 w-full items-center", children: _jsx("div", { className: "flex w-full flex-wrap items-center gap-1.5 px-1", children: visibleItems.map((item) => {
|
|
109
110
|
const id = item.id;
|
|
110
111
|
if (!id)
|
|
111
112
|
return null;
|
|
@@ -21,7 +21,7 @@ export const Thread = ({ isHistoryRoute = false }) => {
|
|
|
21
21
|
["--thread-max-width"]: "44rem",
|
|
22
22
|
["--composer-radius"]: "24px",
|
|
23
23
|
["--composer-padding"]: "10px",
|
|
24
|
-
}, children: _jsx(ThreadPrimitive.Viewport, { turnAnchor: "top", "data-slot": "aui_thread-viewport", className: "relative flex flex-1 flex-col overflow-x-auto overflow-y-auto scroll-smooth", children: _jsxs("div", { className: "mx-auto flex w-full max-w-(--thread-max-width) flex-1 flex-col px-4 pt-4", children: [_jsx(AuiIf, { condition: () => showLoadingState, children: _jsx(ThreadHistoryLoading, {}) }), _jsx(AuiIf, { condition: () => messageCount === 0 && (!isHistoryRoute || showHistoryEmpty), children: _jsx(ThreadEmptyState, { isHistoryRoute: isHistoryRoute }) }), _jsx(MessageList, {}), _jsxs(ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mt-auto flex flex-col gap-0 overflow-visible rounded-t-(--composer-radius) bg-background pb-4 md:pb-6", children: [_jsx(ThreadScrollToBottom, {}), _jsx(ContextChips, {}), _jsx(Composer, {})] })] }) }) }));
|
|
24
|
+
}, children: _jsx(ThreadPrimitive.Viewport, { turnAnchor: "top", "data-slot": "aui_thread-viewport", className: "relative flex flex-1 flex-col overflow-x-auto overflow-y-auto scroll-smooth", children: _jsxs("div", { className: "mx-auto flex w-full max-w-(--thread-max-width) flex-1 flex-col px-3 pt-14 sm:px-4 lg:pt-4", children: [_jsx(AuiIf, { condition: () => showLoadingState, children: _jsx(ThreadHistoryLoading, {}) }), _jsx(AuiIf, { condition: () => messageCount === 0 && (!isHistoryRoute || showHistoryEmpty), children: _jsx(ThreadEmptyState, { isHistoryRoute: isHistoryRoute }) }), _jsx(MessageList, {}), _jsxs(ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mt-auto flex flex-col gap-0 overflow-visible rounded-t-(--composer-radius) bg-background pb-4 md:pb-6", children: [_jsx(ThreadScrollToBottom, {}), _jsx(ContextChips, {}), _jsx(Composer, {})] })] }) }) }));
|
|
25
25
|
};
|
|
26
26
|
function useDebouncedHistoryEmptyState({ isHistoryRoute, isLoading, messageCount, }) {
|
|
27
27
|
const [showEmpty, setShowEmpty] = useState(false);
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { ThreadPrimitive, useAuiState } from "@assistant-ui/react";
|
|
4
4
|
import { AssistantMessage, EditComposer, UserMessage } from "./messages.mjs";
|
|
5
5
|
export const MessageList = () => {
|
|
6
|
-
return (_jsx("div", { "data-slot": "aui_message-group", className: "mb-
|
|
6
|
+
return (_jsx("div", { "data-slot": "aui_message-group", className: "mb-8 flex flex-col gap-y-6 empty:hidden md:mb-10 md:gap-y-8", children: _jsx(ThreadPrimitive.Messages, { children: () => _jsx(ThreadMessage, {}) }) }));
|
|
7
7
|
};
|
|
8
8
|
export const ThreadMessage = () => {
|
|
9
9
|
const role = useAuiState((s) => s.message.role);
|
|
@@ -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-
|
|
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-
|
|
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
|
|
2
|
-
|
|
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
|
-
|
|
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: [
|
|
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;
|