@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
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import fs from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { normalizeAcpProvider } from "../acp2aisdk/provider-registry.mjs";
|
|
4
5
|
import { DEFAULT_PERMISSION_MODE, normalizeWorkspacePath, } from "../acp2aisdk/session-store.mjs";
|
|
5
|
-
import {
|
|
6
|
+
import { findProviderSession, scanProviderSessions, } from "../provider-history/index.mjs";
|
|
6
7
|
import { mergePersistedBuiltinToolSettings, normalizePersistedBuiltinToolSettings, } from "../../tools/registry.mjs";
|
|
7
8
|
import { deleteRuntimeMessages, getRuntimeMessageRepository, isRuntimeMessageConversationExpired, pruneExpiredRuntimeMessages, upsertRuntimeMessage, } from "./message-repository.mjs";
|
|
9
|
+
import { loadProviderMessageRepository } from "./provider-message-loader.mjs";
|
|
10
|
+
import { getUserFacingMessageText } from "./title-text.mjs";
|
|
8
11
|
const STORE_VERSION = 1;
|
|
9
12
|
const DEFAULT_CONVERSATION_LIST_LIMIT = 50;
|
|
10
13
|
const MAX_CONVERSATION_LIST_LIMIT = 200;
|
|
@@ -141,7 +144,7 @@ async function readStore(workspacePath) {
|
|
|
141
144
|
}
|
|
142
145
|
async function writeStore(data, workspacePath) {
|
|
143
146
|
const storePath = getStorePath(workspacePath);
|
|
144
|
-
const tempStorePath = `${storePath}.${process.pid}.${Date.now()}.tmp`;
|
|
147
|
+
const tempStorePath = `${storePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
|
|
145
148
|
await fs.mkdir(/* turbopackIgnore: true */ path.dirname(storePath), {
|
|
146
149
|
recursive: true,
|
|
147
150
|
});
|
|
@@ -169,7 +172,9 @@ function isRecord(value) {
|
|
|
169
172
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
170
173
|
}
|
|
171
174
|
function normalizeConversationTitle(value, maxLength) {
|
|
172
|
-
let title = typeof value === "string"
|
|
175
|
+
let title = typeof value === "string"
|
|
176
|
+
? getUserFacingMessageText(value).replace(/\s+/g, " ").trim()
|
|
177
|
+
: "";
|
|
173
178
|
if (maxLength)
|
|
174
179
|
title = title.slice(0, maxLength).trim();
|
|
175
180
|
return title && title !== PLACEHOLDER_TITLE ? title : undefined;
|
|
@@ -203,7 +208,7 @@ function titleFromStoredMessage(message) {
|
|
|
203
208
|
if (!isRecord(content) || content.role !== "user")
|
|
204
209
|
return undefined;
|
|
205
210
|
const body = Array.isArray(content.parts) ? content.parts : content.content;
|
|
206
|
-
return normalizeConversationTitle(extractStoredText(body), GENERATED_TITLE_MAX_LENGTH);
|
|
211
|
+
return normalizeConversationTitle(getUserFacingMessageText(extractStoredText(body)), GENERATED_TITLE_MAX_LENGTH);
|
|
207
212
|
}
|
|
208
213
|
function titleFromRuntimeMessages(data, threadId) {
|
|
209
214
|
var _a, _b, _c;
|
|
@@ -215,33 +220,6 @@ function titleFromRuntimeMessages(data, threadId) {
|
|
|
215
220
|
}
|
|
216
221
|
return undefined;
|
|
217
222
|
}
|
|
218
|
-
function backfillMissingConversationTitles(data) {
|
|
219
|
-
var _a;
|
|
220
|
-
for (const conversation of data.conversations) {
|
|
221
|
-
const title = normalizeConversationTitle(conversation.title);
|
|
222
|
-
if (title) {
|
|
223
|
-
conversation.title = title;
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
conversation.title =
|
|
227
|
-
(_a = titleFromRuntimeMessages(data, conversation.threadId)) !== null && _a !== void 0 ? _a : null;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
function shouldScanProviderSessionsForTitleBackfill(data, workspacePath) {
|
|
231
|
-
const activeSessionThreadIds = new Set(data.sessions
|
|
232
|
-
.filter((session) => session.provider === "codex" &&
|
|
233
|
-
session.workspacePath === workspacePath &&
|
|
234
|
-
!!session.acpSessionId &&
|
|
235
|
-
!session.closedAt)
|
|
236
|
-
.map((session) => session.threadId));
|
|
237
|
-
return data.conversations.some((thread) => isActiveConversation(thread) &&
|
|
238
|
-
thread.provider === "codex" &&
|
|
239
|
-
thread.workspacePath === workspacePath &&
|
|
240
|
-
!normalizeConversationTitle(thread.title) &&
|
|
241
|
-
!!(thread.providerSessionId ||
|
|
242
|
-
thread.sourcePath ||
|
|
243
|
-
activeSessionThreadIds.has(thread.threadId)));
|
|
244
|
-
}
|
|
245
223
|
function normalizeBuiltinToolSettings(value) {
|
|
246
224
|
return normalizePersistedBuiltinToolSettings(value);
|
|
247
225
|
}
|
|
@@ -291,32 +269,17 @@ function updateConversationRecord(record, request) {
|
|
|
291
269
|
? request.lastActiveAt
|
|
292
270
|
: record.lastActiveAt, updatedAt: nowIso(), status: record.status === "deleted" ? "active" : record.status, deletedAt: record.status === "deleted" ? null : record.deletedAt });
|
|
293
271
|
}
|
|
294
|
-
function filterMessagesByFormat(repo, format) {
|
|
295
|
-
return format
|
|
296
|
-
? repo.messages.filter((message) => message.format === format)
|
|
297
|
-
: repo.messages;
|
|
298
|
-
}
|
|
299
|
-
function errorMessage(error) {
|
|
300
|
-
return error instanceof Error ? error.message : String(error);
|
|
301
|
-
}
|
|
302
272
|
export async function listConversations(workspacePath, options = {}) {
|
|
303
273
|
const normalizedWorkspacePath = normalizeWorkspacePath(workspacePath);
|
|
304
274
|
const shouldRefreshProvider = options.refreshProvider === true;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
? shouldScanProviderSessionsForTitleBackfill(snapshot, normalizedWorkspacePath)
|
|
311
|
-
: false);
|
|
312
|
-
const providerSessions = shouldScanProvider
|
|
313
|
-
? await scanProviderSessionsCached(normalizedWorkspacePath, options.refreshProvider)
|
|
314
|
-
: [];
|
|
275
|
+
if (!shouldRefreshProvider) {
|
|
276
|
+
const data = await readStore(normalizedWorkspacePath);
|
|
277
|
+
return paginateConversations(data.conversations, options);
|
|
278
|
+
}
|
|
279
|
+
const providerSessions = await scanProviderSessionsCached(normalizedWorkspacePath, options.refreshProvider);
|
|
315
280
|
return updateStore(normalizedWorkspacePath, (data) => {
|
|
316
|
-
var _a, _b, _c, _d, _e
|
|
281
|
+
var _a, _b, _c, _d, _e;
|
|
317
282
|
const now = nowIso();
|
|
318
|
-
const importProviderSessions = shouldRefreshProvider;
|
|
319
|
-
backfillMissingConversationTitles(data);
|
|
320
283
|
for (const session of providerSessions) {
|
|
321
284
|
const existingSession = data.sessions.find((record) => {
|
|
322
285
|
var _a;
|
|
@@ -334,8 +297,6 @@ export async function listConversations(workspacePath, options = {}) {
|
|
|
334
297
|
thread.providerSessionId === session.sessionId));
|
|
335
298
|
}
|
|
336
299
|
const existing = existingIndex >= 0 ? data.conversations[existingIndex] : null;
|
|
337
|
-
if (!existing && !importProviderSessions)
|
|
338
|
-
continue;
|
|
339
300
|
const existingTitle = normalizeConversationTitle(existing === null || existing === void 0 ? void 0 : existing.title);
|
|
340
301
|
const providerTitle = normalizeConversationTitle(session.title);
|
|
341
302
|
const record = Object.assign(Object.assign({}, (existing !== null && existing !== void 0 ? existing : {
|
|
@@ -349,9 +310,7 @@ export async function listConversations(workspacePath, options = {}) {
|
|
|
349
310
|
thoughtLevel: null,
|
|
350
311
|
permissionMode: DEFAULT_PERMISSION_MODE,
|
|
351
312
|
status: "active",
|
|
352
|
-
})), { updatedAt: (_c = (_b = session.lastActiveAt) !== null && _b !== void 0 ? _b : session.createdAt) !== null && _c !== void 0 ? _c : now, workspacePath: normalizeWorkspacePath((_d = session.workspacePath) !== null && _d !== void 0 ? _d : normalizedWorkspacePath), provider: session.provider, title: (
|
|
353
|
-
? titleFromRuntimeMessages(data, existing.threadId)
|
|
354
|
-
: null)) !== null && _f !== void 0 ? _f : null, providerSessionId: session.sessionId, sourcePath: session.sourcePath, sourceKind: session.sourceKind, lastSeenMtime: session.lastSeenMtime, lastActiveAt: session.lastActiveAt });
|
|
313
|
+
})), { updatedAt: (_c = (_b = session.lastActiveAt) !== null && _b !== void 0 ? _b : session.createdAt) !== null && _c !== void 0 ? _c : now, workspacePath: normalizeWorkspacePath((_d = session.workspacePath) !== null && _d !== void 0 ? _d : normalizedWorkspacePath), provider: session.provider, title: (_e = existingTitle !== null && existingTitle !== void 0 ? existingTitle : providerTitle) !== null && _e !== void 0 ? _e : null, providerSessionId: session.sessionId, sourcePath: session.sourcePath, sourceKind: session.sourceKind, lastSeenMtime: session.lastSeenMtime, lastActiveAt: session.lastActiveAt });
|
|
355
314
|
if (existingIndex >= 0) {
|
|
356
315
|
data.conversations[existingIndex] = record;
|
|
357
316
|
}
|
|
@@ -463,101 +422,27 @@ async function deleteExpiredRuntimeMessagesForThread(workspacePath, threadId) {
|
|
|
463
422
|
}
|
|
464
423
|
});
|
|
465
424
|
}
|
|
466
|
-
async function
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
if (conversation === null || conversation === void 0 ? void 0 : conversation.sourcePath) {
|
|
481
|
-
try {
|
|
482
|
-
const transcript = await loadProviderTranscript({
|
|
483
|
-
provider: conversation.provider,
|
|
484
|
-
sessionId: conversation.providerSessionId,
|
|
485
|
-
sourcePath: conversation.sourcePath,
|
|
486
|
-
});
|
|
487
|
-
const repo = convertTranscriptToMessageRepository(transcript, format !== null && format !== void 0 ? format : "ai-sdk/v6");
|
|
488
|
-
const messages = filterMessagesByFormat(repo, format);
|
|
489
|
-
if (messages.length === 0) {
|
|
490
|
-
return {
|
|
491
|
-
messages: [],
|
|
492
|
-
diagnostic: {
|
|
493
|
-
source: "provider-history",
|
|
494
|
-
error: "Provider transcript had no messages",
|
|
495
|
-
},
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
return {
|
|
499
|
-
headId: repo.headId,
|
|
500
|
-
messages,
|
|
501
|
-
diagnostic: { source: "provider-history" },
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
catch (error) {
|
|
505
|
-
return {
|
|
506
|
-
messages: [],
|
|
507
|
-
diagnostic: {
|
|
508
|
-
source: "provider-history",
|
|
509
|
-
error: errorMessage(error),
|
|
510
|
-
},
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
if (providerSession === null || providerSession === void 0 ? void 0 : providerSession.sourcePath) {
|
|
515
|
-
try {
|
|
516
|
-
const transcript = await loadProviderTranscript({
|
|
517
|
-
provider: providerSession.provider,
|
|
518
|
-
sessionId: providerSession.sessionId,
|
|
519
|
-
sourcePath: providerSession.sourcePath,
|
|
520
|
-
});
|
|
521
|
-
const repo = convertTranscriptToMessageRepository(transcript, format !== null && format !== void 0 ? format : "ai-sdk/v6");
|
|
522
|
-
const messages = filterMessagesByFormat(repo, format);
|
|
523
|
-
if (messages.length === 0) {
|
|
524
|
-
return {
|
|
525
|
-
messages: [],
|
|
526
|
-
diagnostic: {
|
|
527
|
-
source: "provider-history",
|
|
528
|
-
error: "Provider transcript had no messages",
|
|
529
|
-
},
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
return {
|
|
533
|
-
headId: repo.headId,
|
|
534
|
-
messages,
|
|
535
|
-
diagnostic: { source: "provider-history" },
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
catch (error) {
|
|
539
|
-
return {
|
|
540
|
-
messages: [],
|
|
541
|
-
diagnostic: {
|
|
542
|
-
source: "provider-history",
|
|
543
|
-
error: errorMessage(error),
|
|
544
|
-
},
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
return {
|
|
549
|
-
messages: [],
|
|
550
|
-
diagnostic: {
|
|
551
|
-
source: "provider-history",
|
|
552
|
-
error: providerSessionError !== null && providerSessionError !== void 0 ? providerSessionError : "Provider transcript not found",
|
|
553
|
-
},
|
|
554
|
-
};
|
|
425
|
+
async function syncMissingConversationTitleFromMessages({ workspacePath, threadId, messages, }) {
|
|
426
|
+
const title = messages
|
|
427
|
+
.map((message) => titleFromStoredMessage(message))
|
|
428
|
+
.find((candidate) => Boolean(candidate));
|
|
429
|
+
if (!title)
|
|
430
|
+
return;
|
|
431
|
+
await updateStore(workspacePath, (data) => {
|
|
432
|
+
const record = findActiveConversation(data, threadId);
|
|
433
|
+
if (!record || normalizeConversationTitle(record.title))
|
|
434
|
+
return;
|
|
435
|
+
record.title = title;
|
|
436
|
+
});
|
|
555
437
|
}
|
|
556
|
-
export async function loadConversationMessages(threadId, format, workspacePath) {
|
|
438
|
+
export async function loadConversationMessages(threadId, format, workspacePath, source = "auto") {
|
|
557
439
|
var _a;
|
|
558
440
|
const data = await readStore(workspacePath);
|
|
559
441
|
const conversation = data.conversations.find((thread) => thread.threadId === threadId && thread.status !== "deleted");
|
|
560
|
-
if (
|
|
442
|
+
if (source === "runtime") {
|
|
443
|
+
return getRuntimeMessageRepository(data, threadId, format);
|
|
444
|
+
}
|
|
445
|
+
if (conversation && source !== "provider") {
|
|
561
446
|
if (isRuntimeMessageConversationExpired(conversation)) {
|
|
562
447
|
if ((_a = data.messages) === null || _a === void 0 ? void 0 : _a[threadId]) {
|
|
563
448
|
await deleteExpiredRuntimeMessagesForThread(workspacePath, threadId);
|
|
@@ -566,8 +451,16 @@ export async function loadConversationMessages(threadId, format, workspacePath)
|
|
|
566
451
|
}
|
|
567
452
|
else {
|
|
568
453
|
const runtimeRepo = readRuntimeMessagesIfAvailable(data, threadId, format);
|
|
569
|
-
if (runtimeRepo)
|
|
454
|
+
if (runtimeRepo) {
|
|
455
|
+
if (!normalizeConversationTitle(conversation.title)) {
|
|
456
|
+
await syncMissingConversationTitleFromMessages({
|
|
457
|
+
workspacePath,
|
|
458
|
+
threadId,
|
|
459
|
+
messages: runtimeRepo.messages,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
570
462
|
return runtimeRepo;
|
|
463
|
+
}
|
|
571
464
|
}
|
|
572
465
|
}
|
|
573
466
|
const providerRepo = await loadProviderMessageRepository({
|
|
@@ -576,6 +469,13 @@ export async function loadConversationMessages(threadId, format, workspacePath)
|
|
|
576
469
|
workspacePath,
|
|
577
470
|
conversation: conversation !== null && conversation !== void 0 ? conversation : null,
|
|
578
471
|
});
|
|
472
|
+
if (conversation && !normalizeConversationTitle(conversation.title)) {
|
|
473
|
+
await syncMissingConversationTitleFromMessages({
|
|
474
|
+
workspacePath,
|
|
475
|
+
threadId,
|
|
476
|
+
messages: providerRepo.messages,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
579
479
|
return providerRepo;
|
|
580
480
|
}
|
|
581
481
|
export async function saveConversationMessage(threadId, request, workspacePath) {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const DISPLAY_ONLY_TAG_ROOTS = new Set([
|
|
2
|
+
"app-context",
|
|
3
|
+
"collaboration_mode",
|
|
4
|
+
"developer",
|
|
5
|
+
"dynamic_context",
|
|
6
|
+
"environment_context",
|
|
7
|
+
"permissions instructions",
|
|
8
|
+
"plugins_instructions",
|
|
9
|
+
"skills_instructions",
|
|
10
|
+
"system",
|
|
11
|
+
]);
|
|
12
|
+
function normalizeTagRoot(value) {
|
|
13
|
+
return value.trim().toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
function isDisplayOnlyTagRoot(root) {
|
|
16
|
+
const normalizedRoot = normalizeTagRoot(root);
|
|
17
|
+
if (DISPLAY_ONLY_TAG_ROOTS.has(normalizedRoot))
|
|
18
|
+
return true;
|
|
19
|
+
return (normalizedRoot.includes("_") ||
|
|
20
|
+
normalizedRoot.includes("-") ||
|
|
21
|
+
normalizedRoot.includes(" "));
|
|
22
|
+
}
|
|
23
|
+
function getOpeningTagRoot(text) {
|
|
24
|
+
var _a, _b;
|
|
25
|
+
const match = text.trim().match(/^<([A-Za-z][\w:-]*)(?:\s[^>]*)?>/u);
|
|
26
|
+
return (_b = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
|
|
27
|
+
}
|
|
28
|
+
function escapeRegExp(value) {
|
|
29
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
30
|
+
}
|
|
31
|
+
function getWrappedTagRoot(text) {
|
|
32
|
+
var _a, _b;
|
|
33
|
+
const trimmed = text.trim();
|
|
34
|
+
const match = trimmed.match(/^<([A-Za-z][\w:-]*)(?:\s[^>]*)?>[\s\S]*<\/\1>$/u);
|
|
35
|
+
return (_b = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
|
|
36
|
+
}
|
|
37
|
+
function extractTaggedText(text, tagName) {
|
|
38
|
+
var _a, _b, _c;
|
|
39
|
+
const pattern = new RegExp(`<${tagName}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${tagName}>`, "iu");
|
|
40
|
+
return (_c = (_b = (_a = pattern.exec(text)) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : "";
|
|
41
|
+
}
|
|
42
|
+
function stripLeadingDisplayOnlyTagBlocks(text) {
|
|
43
|
+
var _a;
|
|
44
|
+
let remaining = text.trim();
|
|
45
|
+
for (let index = 0; index < 10; index += 1) {
|
|
46
|
+
const openingMatch = remaining.match(/^<([A-Za-z][\w:-]*)(?:\s[^>]*)?>/u);
|
|
47
|
+
const root = (_a = openingMatch === null || openingMatch === void 0 ? void 0 : openingMatch[1]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
48
|
+
if (!openingMatch || !root || !isDisplayOnlyTagRoot(root)) {
|
|
49
|
+
return remaining;
|
|
50
|
+
}
|
|
51
|
+
const closingPattern = new RegExp(`</${escapeRegExp(root)}>`, "iu");
|
|
52
|
+
const contentStart = openingMatch[0].length;
|
|
53
|
+
const closingMatch = closingPattern.exec(remaining.slice(contentStart));
|
|
54
|
+
if (!closingMatch)
|
|
55
|
+
return "";
|
|
56
|
+
remaining = remaining
|
|
57
|
+
.slice(contentStart + closingMatch.index + closingMatch[0].length)
|
|
58
|
+
.trim();
|
|
59
|
+
}
|
|
60
|
+
return remaining;
|
|
61
|
+
}
|
|
62
|
+
export function isDisplayOnlyTagBlock(text) {
|
|
63
|
+
const root = getWrappedTagRoot(text);
|
|
64
|
+
return root ? isDisplayOnlyTagRoot(root) : false;
|
|
65
|
+
}
|
|
66
|
+
export function isDisplayOnlyTagStart(text) {
|
|
67
|
+
const root = getOpeningTagRoot(text);
|
|
68
|
+
return root ? isDisplayOnlyTagRoot(root) : false;
|
|
69
|
+
}
|
|
70
|
+
export function getUserFacingMessageText(text) {
|
|
71
|
+
const trimmed = text.trim();
|
|
72
|
+
if (!trimmed)
|
|
73
|
+
return "";
|
|
74
|
+
const userMessageText = extractTaggedText(trimmed, "user_message");
|
|
75
|
+
if (userMessageText)
|
|
76
|
+
return userMessageText;
|
|
77
|
+
const stripped = stripLeadingDisplayOnlyTagBlocks(trimmed);
|
|
78
|
+
return isDisplayOnlyTagBlock(stripped) || isDisplayOnlyTagStart(stripped)
|
|
79
|
+
? ""
|
|
80
|
+
: stripped;
|
|
81
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AcpBuiltinToolSettings, AcpPermissionMode, AcpProviderKey } from "../acp2aisdk";
|
|
1
|
+
import type { AcpBuiltinToolSettings, AcpPermissionMode, AcpProviderKey, AcpRunState } from "../acp2aisdk";
|
|
2
2
|
export type ConversationStatus = "active" | "archived" | "deleted";
|
|
3
3
|
export type ConversationSourceKind = "codex-jsonl";
|
|
4
4
|
export type ConversationBuiltinToolSettings = AcpBuiltinToolSettings;
|
|
@@ -52,6 +52,17 @@ export type ConversationMessageRepository<TContent = Record<string, unknown>> =
|
|
|
52
52
|
error?: string;
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
|
+
export type ConversationMessageSource = "auto" | "provider" | "runtime";
|
|
56
|
+
export type ConversationRuntimeResponse = {
|
|
57
|
+
threadId: string;
|
|
58
|
+
provider: AcpProviderKey;
|
|
59
|
+
workspacePath: string;
|
|
60
|
+
metadata: {
|
|
61
|
+
runState: AcpRunState;
|
|
62
|
+
} | null;
|
|
63
|
+
acpSessionId: string | null;
|
|
64
|
+
lastUsedAt: number | null;
|
|
65
|
+
};
|
|
55
66
|
export type ConversationStoreData = {
|
|
56
67
|
version: 1;
|
|
57
68
|
conversations: ConversationRecord[];
|
|
@@ -11,6 +11,14 @@ export const LOCAL_IMAGE_FILE_EXTENSIONS = new Set([
|
|
|
11
11
|
".webp",
|
|
12
12
|
]);
|
|
13
13
|
const LOCAL_FILE_EXTENSION_RE = /^\.[A-Za-z0-9][A-Za-z0-9_-]{0,15}$/;
|
|
14
|
+
function decodePathComponent(value) {
|
|
15
|
+
try {
|
|
16
|
+
return decodeURIComponent(value);
|
|
17
|
+
}
|
|
18
|
+
catch (_a) {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
14
22
|
export function normalizeLocalFilePath(value) {
|
|
15
23
|
const raw = value.trim();
|
|
16
24
|
if (!raw)
|
|
@@ -35,7 +43,7 @@ export function normalizeLocalFilePath(value) {
|
|
|
35
43
|
return null;
|
|
36
44
|
}
|
|
37
45
|
}
|
|
38
|
-
const withoutQuery = raw.split(/[?#]/, 1)[0];
|
|
46
|
+
const withoutQuery = decodePathComponent(raw.split(/[?#]/, 1)[0]);
|
|
39
47
|
const windowsPath = withoutQuery.replace(/^\/([A-Za-z]:[\\/])/, "$1");
|
|
40
48
|
if (path.win32.isAbsolute(windowsPath)) {
|
|
41
49
|
return windowsPath;
|
|
@@ -11,11 +11,36 @@ function trimPathValue(value) {
|
|
|
11
11
|
}
|
|
12
12
|
return trimmed;
|
|
13
13
|
}
|
|
14
|
+
function decodePathComponent(value) {
|
|
15
|
+
try {
|
|
16
|
+
return decodeURIComponent(value);
|
|
17
|
+
}
|
|
18
|
+
catch (_a) {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function normalizeLocalPathValue(value) {
|
|
23
|
+
const raw = trimPathValue(value);
|
|
24
|
+
if (/^https?:\/\//i.test(raw)) {
|
|
25
|
+
try {
|
|
26
|
+
const url = new URL(raw);
|
|
27
|
+
if (LOCAL_HOSTS.has(url.hostname)) {
|
|
28
|
+
return decodePathComponent(url.pathname);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (_a) {
|
|
32
|
+
return raw;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (raw.startsWith("file://"))
|
|
36
|
+
return raw;
|
|
37
|
+
return decodePathComponent(raw);
|
|
38
|
+
}
|
|
14
39
|
function hasImageExtension(value) {
|
|
15
|
-
return IMAGE_EXTENSION_RE.test(value
|
|
40
|
+
return IMAGE_EXTENSION_RE.test(value);
|
|
16
41
|
}
|
|
17
42
|
function hasFileExtension(value) {
|
|
18
|
-
return FILE_EXTENSION_RE.test(value
|
|
43
|
+
return FILE_EXTENSION_RE.test(value);
|
|
19
44
|
}
|
|
20
45
|
function isLocalHostUrl(value) {
|
|
21
46
|
try {
|
|
@@ -32,7 +57,7 @@ function isLocalAbsolutePath(value) {
|
|
|
32
57
|
UNC_LOCAL_PATH_RE.test(value));
|
|
33
58
|
}
|
|
34
59
|
export function isLocalFilePath(value) {
|
|
35
|
-
const raw =
|
|
60
|
+
const raw = normalizeLocalPathValue(value);
|
|
36
61
|
if (!hasFileExtension(raw))
|
|
37
62
|
return false;
|
|
38
63
|
if (raw.startsWith("file://"))
|
|
@@ -51,7 +76,7 @@ export function isLocalFilePath(value) {
|
|
|
51
76
|
return isLocalAbsolutePath(raw);
|
|
52
77
|
}
|
|
53
78
|
export function isLocalImagePath(value) {
|
|
54
|
-
const raw =
|
|
79
|
+
const raw = normalizeLocalPathValue(value);
|
|
55
80
|
if (!hasImageExtension(raw))
|
|
56
81
|
return false;
|
|
57
82
|
if (raw.startsWith("file://"))
|
|
@@ -82,10 +107,10 @@ export function isRenderableImageUrl(value) {
|
|
|
82
107
|
return false;
|
|
83
108
|
}
|
|
84
109
|
export function getLocalImagePreviewUrl(value) {
|
|
85
|
-
return `/api/local-files/image?path=${encodeURIComponent(
|
|
110
|
+
return `/api/local-files/image?path=${encodeURIComponent(normalizeLocalPathValue(value))}`;
|
|
86
111
|
}
|
|
87
112
|
export function getLocalFileName(value) {
|
|
88
|
-
const raw =
|
|
113
|
+
const raw = normalizeLocalPathValue(value);
|
|
89
114
|
let pathValue = raw;
|
|
90
115
|
if (raw.startsWith("file://") || isLocalHostUrl(raw)) {
|
|
91
116
|
try {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type AcpOutputArtifact } from "../../components/assistant-ui/addons/output-artifacts";
|
|
2
|
+
import type { ConversationMessageSource, StoredMessageEntry } from "../conversations/types";
|
|
3
|
+
import type { ImageGenerationRecord } from "../../tools/image-generation/shared";
|
|
4
|
+
export type ThreadOutputArtifactCollection = {
|
|
5
|
+
messages: StoredMessageEntry<Record<string, unknown>>[];
|
|
6
|
+
artifacts: AcpOutputArtifact[];
|
|
7
|
+
imageGenerationRecords: ImageGenerationRecord[];
|
|
8
|
+
workspaceArtifacts: AcpOutputArtifact[];
|
|
9
|
+
diagnostic?: {
|
|
10
|
+
source?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
type CollectThreadOutputArtifactsOptions = {
|
|
15
|
+
threadId: string;
|
|
16
|
+
workspacePath?: string | null;
|
|
17
|
+
format?: string | null;
|
|
18
|
+
source?: ConversationMessageSource;
|
|
19
|
+
sinceMs?: number | null;
|
|
20
|
+
};
|
|
21
|
+
export declare function collectThreadOutputArtifacts({ threadId, workspacePath, format, source, sinceMs, }: CollectThreadOutputArtifactsOptions): Promise<ThreadOutputArtifactCollection>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { normalizeAcpOutputArtifacts, } from "../../components/assistant-ui/addons/output-artifacts.mjs";
|
|
2
|
+
import { loadConversationMessages } from "../conversations/store.mjs";
|
|
3
|
+
import { listImageGenerationRecords } from "../../tools/image-generation/service.mjs";
|
|
4
|
+
import { scanWorkspaceOutputArtifacts } from "./workspace.mjs";
|
|
5
|
+
function getArtifactMergeKey(artifact) {
|
|
6
|
+
return `${artifact.kind}:${artifact.path || artifact.title}`;
|
|
7
|
+
}
|
|
8
|
+
function mergeAcpOutputArtifacts(...collections) {
|
|
9
|
+
const byKey = new Map();
|
|
10
|
+
for (const artifact of collections.flat()) {
|
|
11
|
+
const key = getArtifactMergeKey(artifact);
|
|
12
|
+
const previous = byKey.get(key);
|
|
13
|
+
if (!previous ||
|
|
14
|
+
(!previous.newText && artifact.newText) ||
|
|
15
|
+
artifact.updatedAt >= previous.updatedAt) {
|
|
16
|
+
byKey.set(key, artifact);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return [...byKey.values()];
|
|
20
|
+
}
|
|
21
|
+
function normalizeSinceMs(value) {
|
|
22
|
+
return Number.isFinite(value) ? Math.max(0, Number(value)) : 0;
|
|
23
|
+
}
|
|
24
|
+
export async function collectThreadOutputArtifacts({ threadId, workspacePath, format = "ai-sdk/v6", source = "auto", sinceMs, }) {
|
|
25
|
+
const repo = await loadConversationMessages(threadId, format, workspacePath, source);
|
|
26
|
+
const messages = repo.messages;
|
|
27
|
+
const messageArtifacts = normalizeAcpOutputArtifacts(messages.map((message) => message.content));
|
|
28
|
+
const [imageGenerationRecords, workspaceArtifacts] = await Promise.all([
|
|
29
|
+
listImageGenerationRecords({
|
|
30
|
+
workspacePath,
|
|
31
|
+
threadId,
|
|
32
|
+
limit: 100,
|
|
33
|
+
}).catch(() => []),
|
|
34
|
+
scanWorkspaceOutputArtifacts({
|
|
35
|
+
workspacePath,
|
|
36
|
+
threadId,
|
|
37
|
+
sinceMs: normalizeSinceMs(sinceMs),
|
|
38
|
+
}).catch(() => []),
|
|
39
|
+
]);
|
|
40
|
+
return {
|
|
41
|
+
messages,
|
|
42
|
+
artifacts: mergeAcpOutputArtifacts(messageArtifacts, workspaceArtifacts),
|
|
43
|
+
imageGenerationRecords,
|
|
44
|
+
workspaceArtifacts,
|
|
45
|
+
diagnostic: repo.diagnostic,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -54,7 +54,9 @@ function normalizeRelativePath(value) {
|
|
|
54
54
|
}
|
|
55
55
|
function isWithinWorkspace(root, filePath) {
|
|
56
56
|
const relativePath = path.relative(root, filePath);
|
|
57
|
-
return Boolean(relativePath &&
|
|
57
|
+
return Boolean(relativePath &&
|
|
58
|
+
!relativePath.startsWith("..") &&
|
|
59
|
+
!path.isAbsolute(relativePath));
|
|
58
60
|
}
|
|
59
61
|
function isExcludedRelativePath(relativePath) {
|
|
60
62
|
const parts = normalizeRelativePath(relativePath).split("/");
|
|
@@ -121,7 +123,9 @@ async function collectCandidateFiles(root) {
|
|
|
121
123
|
const visit = async (directory) => {
|
|
122
124
|
if (files.length >= MAX_SCAN_FILES)
|
|
123
125
|
return;
|
|
124
|
-
const entries = await fs
|
|
126
|
+
const entries = await fs
|
|
127
|
+
.readdir(directory, { withFileTypes: true })
|
|
128
|
+
.catch(() => []);
|
|
125
129
|
for (const entry of entries) {
|
|
126
130
|
if (files.length >= MAX_SCAN_FILES)
|
|
127
131
|
return;
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { getUserFacingMessageText, isDisplayOnlyTagBlock, } from "../conversations/title-text.mjs";
|
|
4
5
|
const PROVIDER = "codex";
|
|
5
6
|
const SOURCE_KIND = "codex-jsonl";
|
|
6
7
|
const UUID_RE = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/;
|
|
7
|
-
const DISPLAY_ONLY_TAG_ROOTS = new Set([
|
|
8
|
-
"app-context",
|
|
9
|
-
"collaboration_mode",
|
|
10
|
-
"developer",
|
|
11
|
-
"environment_context",
|
|
12
|
-
"permissions instructions",
|
|
13
|
-
"plugins_instructions",
|
|
14
|
-
"skills_instructions",
|
|
15
|
-
"system",
|
|
16
|
-
]);
|
|
17
8
|
const FINAL_ASSISTANT_PHASE = "final_answer";
|
|
18
9
|
function getCodexSessionsRoot() {
|
|
19
10
|
if (process.env.ACP_UI_CODEX_SESSIONS_ROOT) {
|
|
@@ -77,20 +68,6 @@ function truncate(text, maxLength) {
|
|
|
77
68
|
return trimmed;
|
|
78
69
|
return `${trimmed.slice(0, maxLength).trim()}...`;
|
|
79
70
|
}
|
|
80
|
-
function getWrappedTagRoot(text) {
|
|
81
|
-
var _a, _b;
|
|
82
|
-
const trimmed = text.trim();
|
|
83
|
-
const match = trimmed.match(/^<([^>\n]+)>[\s\S]*<\/\1>$/);
|
|
84
|
-
return (_b = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
|
|
85
|
-
}
|
|
86
|
-
function isDisplayOnlyTagBlock(text) {
|
|
87
|
-
const root = getWrappedTagRoot(text);
|
|
88
|
-
if (!root)
|
|
89
|
-
return false;
|
|
90
|
-
if (DISPLAY_ONLY_TAG_ROOTS.has(root))
|
|
91
|
-
return true;
|
|
92
|
-
return root.includes("_") || root.includes("-") || root.includes(" ");
|
|
93
|
-
}
|
|
94
71
|
async function collectJsonlFiles(root) {
|
|
95
72
|
const files = [];
|
|
96
73
|
async function visit(dir) {
|
|
@@ -154,10 +131,8 @@ async function parseSessionMeta(filePath, lines) {
|
|
|
154
131
|
isRecord(value.payload) &&
|
|
155
132
|
value.payload.type === "message" &&
|
|
156
133
|
value.payload.role === "user") {
|
|
157
|
-
const text = extractText(value.payload.content).trim();
|
|
158
|
-
if (text &&
|
|
159
|
-
!text.startsWith("# AGENTS.md") &&
|
|
160
|
-
!isDisplayOnlyTagBlock(text)) {
|
|
134
|
+
const text = getUserFacingMessageText(extractText(value.payload.content)).trim();
|
|
135
|
+
if (text && !text.startsWith("# AGENTS.md")) {
|
|
161
136
|
firstUserMessage = text;
|
|
162
137
|
}
|
|
163
138
|
}
|
|
@@ -171,7 +146,7 @@ async function parseSessionMeta(filePath, lines) {
|
|
|
171
146
|
value.type === "response_item" &&
|
|
172
147
|
isRecord(value.payload) &&
|
|
173
148
|
value.payload.type === "message") {
|
|
174
|
-
const text = extractText(value.payload.content).trim();
|
|
149
|
+
const text = getUserFacingMessageText(extractText(value.payload.content)).trim();
|
|
175
150
|
if (text && !isDisplayOnlyTagBlock(text))
|
|
176
151
|
summary = text;
|
|
177
152
|
}
|
|
@@ -210,7 +185,7 @@ function parseTranscriptMessage(value, index) {
|
|
|
210
185
|
payload.phase !== FINAL_ASSISTANT_PHASE) {
|
|
211
186
|
return null;
|
|
212
187
|
}
|
|
213
|
-
const text = extractText(payload.content).trim();
|
|
188
|
+
const text = getUserFacingMessageText(extractText(payload.content)).trim();
|
|
214
189
|
if (!text || isDisplayOnlyTagBlock(text))
|
|
215
190
|
return null;
|
|
216
191
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { cleanupAcpSession, getAcpSessionMetadata, listAcpSessionMetadata, streamAcpChat, } from "../lib/acp2aisdk";
|
|
1
|
+
export { cancelAcpSession, cleanupAcpSession, getAcpSessionMetadata, listAcpSessionMetadata, streamAcpChat, } from "../lib/acp2aisdk";
|
|
2
2
|
export { buildAcpCapabilitySnapshot } from "../lib/acp2aisdk/capabilities";
|
|
3
3
|
export { ACP_PROVIDER_ALIASES, ACP_PROVIDER_DEFAULT_MODE_IDS, ACP_PROVIDER_KEYS, ACP_PROVIDER_REGISTRY, getAcpProviderDefaultModeId, isAcpProviderKey, normalizeAcpProvider, readProviderOverridesFromEnv, resolveAcpProviderConfig, } from "../lib/acp2aisdk/provider-registry";
|
|
4
4
|
export { createAcpSessionKey, createInitialMetadata, DEFAULT_PERMISSION_MODE, DEFAULT_THREAD_ID, getDefaultWorkspacePath, getGlobalAcpSessionStore, normalizeThreadId, normalizeWorkspacePath, SESSION_IDLE_TTL_MS, } from "../lib/acp2aisdk/session-store";
|