@shepai/cli 1.164.0-pr514.db33061 → 1.164.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/dist/packages/core/src/application/ports/output/agents/interactive-agent-executor.interface.d.ts +1 -3
- package/dist/packages/core/src/application/ports/output/agents/interactive-agent-executor.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/repositories/interactive-session-repository.interface.d.ts +0 -19
- package/dist/packages/core/src/application/ports/output/repositories/interactive-session-repository.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/interactive-session-service.interface.d.ts +1 -7
- package/dist/packages/core/src/application/ports/output/services/interactive-session-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/interactive/send-interactive-message.use-case.d.ts +0 -2
- package/dist/packages/core/src/application/use-cases/interactive/send-interactive-message.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/interactive/send-interactive-message.use-case.js +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-interactive-session.repository.d.ts +0 -12
- package/dist/packages/core/src/infrastructure/repositories/sqlite-interactive-session.repository.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-interactive-session.repository.js +0 -31
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.d.ts +7 -38
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.js +45 -152
- package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.d.ts +1 -17
- package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.js +47 -131
- package/dist/src/presentation/web/app/api/interactive/chat/[featureId]/messages/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/interactive/chat/[featureId]/messages/route.js +1 -3
- package/dist/src/presentation/web/components/assistant-ui/thread.js +1 -8
- package/dist/src/presentation/web/components/features/chat/ChatTab.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/chat/ChatTab.js +7 -13
- package/dist/src/presentation/web/components/features/chat/useChatRuntime.d.ts +0 -16
- package/dist/src/presentation/web/components/features/chat/useChatRuntime.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/chat/useChatRuntime.js +7 -98
- package/dist/src/presentation/web/components/features/settings/AgentModelPicker/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/AgentModelPicker/index.js +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__2b71641f._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__2b71641f._.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js +2 -2
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1abe77bb._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1abe77bb._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__563e4faf._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__563e4faf._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7562afc6._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7562afc6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__821a11c1._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__821a11c1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__86ff0bc5._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__86ff0bc5._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8b0aac03._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__98740ee4._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__98740ee4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ba9f9e11._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ba9f9e11._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e0be67c7._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e0be67c7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_02e01240._.js +1 -1
- package/web/.next/server/chunks/ssr/_02e01240._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0727935d._.js +1 -1
- package/web/.next/server/chunks/ssr/_0727935d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_18886033._.js +1 -1
- package/web/.next/server/chunks/ssr/_18886033._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_22e00a14._.js +1 -1
- package/web/.next/server/chunks/ssr/_22e00a14._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_2f8f89fb._.js +3 -0
- package/web/.next/server/chunks/ssr/{_7a6f6a76._.js.map → _2f8f89fb._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_8276397a._.js → _52403a07._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_8276397a._.js.map → _52403a07._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_0020fddd._.js → _8b57edb8._.js} +2 -2
- package/web/.next/server/chunks/ssr/_8b57edb8._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_9215e9ec._.js +1 -1
- package/web/.next/server/chunks/ssr/_9215e9ec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_a5a5901d._.js +1 -1
- package/web/.next/server/chunks/ssr/_a5a5901d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_ad09f271._.js +1 -1
- package/web/.next/server/chunks/ssr/_ad09f271._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_c3f595c6._.js +1 -1
- package/web/.next/server/chunks/ssr/_c3f595c6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_fdc356bf._.js → _c9f903f2._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_fdc356bf._.js.map → _c9f903f2._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_ea9e1556._.js +1 -1
- package/web/.next/server/chunks/ssr/_ea9e1556._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_f1ba9be6._.js +2 -2
- package/web/.next/server/chunks/ssr/_f1ba9be6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_f33cd07e._.js +2 -2
- package/web/.next/server/chunks/ssr/_f33cd07e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_f8b45233._.js +1 -1
- package/web/.next/server/chunks/ssr/_f8b45233._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +47 -47
- package/web/.next/static/chunks/{d6a1a06ee3c12489.js → 25e894a1de46b5fb.js} +1 -1
- package/web/.next/static/chunks/{1ad664f7081cf4c0.js → 2609c8fc6f14cb26.js} +1 -1
- package/web/.next/static/chunks/{16eea21868510afd.js → 29f0d874b1fde3d6.js} +2 -2
- package/web/.next/static/chunks/400e93efac983a76.css +1 -0
- package/web/.next/static/chunks/{5d8c83c576ec1a7b.js → 498e45f8e05a5491.js} +1 -1
- package/web/.next/static/chunks/{ee9fe376b60c3cab.js → 56955fa252a9f3ed.js} +2 -2
- package/web/.next/static/chunks/7f491899a2fe2fd7.js +1 -0
- package/web/.next/static/chunks/{dedf6ca63c5468fa.js → a8243f8d06bdcef0.js} +2 -2
- package/web/.next/static/chunks/{4788a37d8c608e30.js → ce0316338f7e01e6.js} +1 -1
- package/web/.next/static/chunks/{e77d053610055e0c.js → ce87ded6cc38b4de.js} +1 -1
- package/web/.next/static/chunks/{9162bb869b3543e2.js → cf000ba1a3f11439.js} +1 -1
- package/web/.next/static/chunks/{940bca62e44f3e90.js → cf75fade434602c6.js} +2 -2
- package/web/.next/static/chunks/{8094762f5cda4934.js → d9e4d90ef254da84.js} +1 -1
- package/web/.next/static/chunks/{7d40e79e524c8d18.js → dc21cf85bfa262a7.js} +2 -2
- package/web/.next/static/chunks/e6398f94cffe9bc2.js +1 -0
- package/web/.next/static/chunks/{4f7d9c08a205bc4e.js → ecfd93d61bf4d933.js} +1 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/051-add-session-usage-tracking.d.ts +0 -18
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/051-add-session-usage-tracking.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/051-add-session-usage-tracking.js +0 -32
- package/web/.next/server/chunks/ssr/_0020fddd._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_7a6f6a76._.js +0 -3
- package/web/.next/static/chunks/7cec51e9bd7d1f4f.js +0 -1
- package/web/.next/static/chunks/a760d5829014058d.js +0 -1
- package/web/.next/static/chunks/eeadf13c0ea6cbe0.css +0 -1
- /package/web/.next/static/{lQkUWQQS5aR4vq6WUZ2yr → rav6zzO3q2NtCKwg9XZXP}/_buildManifest.js +0 -0
- /package/web/.next/static/{lQkUWQQS5aR4vq6WUZ2yr → rav6zzO3q2NtCKwg9XZXP}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{lQkUWQQS5aR4vq6WUZ2yr → rav6zzO3q2NtCKwg9XZXP}/_ssgManifest.js +0 -0
package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.js
CHANGED
|
@@ -44,14 +44,6 @@ export class InteractiveSessionService {
|
|
|
44
44
|
sessions = new Map();
|
|
45
45
|
/** Cached agentSessionIds from stopped sessions, keyed by featureId. */
|
|
46
46
|
stoppedAgentSessionIds = new Map();
|
|
47
|
-
/**
|
|
48
|
-
* Feature-level subscribers that survive session restarts.
|
|
49
|
-
*
|
|
50
|
-
* Unlike session-level subscribers (in SessionState.subscribers), these
|
|
51
|
-
* persist when a session dies and a new one boots. SSE connections
|
|
52
|
-
* subscribe here so they continue receiving events from new sessions.
|
|
53
|
-
*/
|
|
54
|
-
featureSubscribers = new Map();
|
|
55
47
|
constructor(sessionRepo, messageRepo, executorFactory, featureRepo, contextBuilder) {
|
|
56
48
|
this.sessionRepo = sessionRepo;
|
|
57
49
|
this.messageRepo = messageRepo;
|
|
@@ -189,10 +181,9 @@ export class InteractiveSessionService {
|
|
|
189
181
|
// Create the interactive executor and session
|
|
190
182
|
const executor = this.executorFactory.createInteractiveExecutor(resolvedAgentType, authConfig);
|
|
191
183
|
let handle;
|
|
192
|
-
|
|
193
|
-
if (previousAgentSessionId) {
|
|
184
|
+
if (state.agentSessionId) {
|
|
194
185
|
// Resume existing SDK session
|
|
195
|
-
handle = await executor.resumeSession(
|
|
186
|
+
handle = await executor.resumeSession(state.agentSessionId, {
|
|
196
187
|
cwd: worktreePath,
|
|
197
188
|
model: state.model,
|
|
198
189
|
systemPrompt: context,
|
|
@@ -227,7 +218,7 @@ export class InteractiveSessionService {
|
|
|
227
218
|
if (event.content) {
|
|
228
219
|
greetingText += event.content;
|
|
229
220
|
state.currentAssistantBuffer += event.content;
|
|
230
|
-
|
|
221
|
+
state.subscribers.forEach((sub) => sub({ delta: event.content, done: false }));
|
|
231
222
|
}
|
|
232
223
|
break;
|
|
233
224
|
case 'tool_use':
|
|
@@ -235,12 +226,12 @@ export class InteractiveSessionService {
|
|
|
235
226
|
const toolLabel = event.label;
|
|
236
227
|
const toolDetail = event.detail;
|
|
237
228
|
void this.persistToolEvent(state, toolLabel, toolDetail);
|
|
238
|
-
|
|
229
|
+
state.subscribers.forEach((sub) => sub({
|
|
239
230
|
delta: '',
|
|
240
231
|
done: false,
|
|
241
232
|
log: `Using tool: ${toolLabel}`,
|
|
242
233
|
activity: { kind: 'tool_use', label: toolLabel, detail: toolDetail },
|
|
243
|
-
});
|
|
234
|
+
}));
|
|
244
235
|
}
|
|
245
236
|
break;
|
|
246
237
|
case 'tool_result':
|
|
@@ -248,18 +239,18 @@ export class InteractiveSessionService {
|
|
|
248
239
|
const resultLabel = event.label;
|
|
249
240
|
const resultDetail = event.detail;
|
|
250
241
|
void this.persistToolEvent(state, resultLabel, resultDetail);
|
|
251
|
-
|
|
242
|
+
state.subscribers.forEach((sub) => sub({
|
|
252
243
|
delta: '',
|
|
253
244
|
done: false,
|
|
254
245
|
log: `Completed: ${resultLabel}`,
|
|
255
246
|
activity: { kind: 'tool_result', label: resultLabel, detail: resultDetail },
|
|
256
|
-
});
|
|
247
|
+
}));
|
|
257
248
|
}
|
|
258
249
|
break;
|
|
259
250
|
case 'status':
|
|
260
251
|
if (event.content) {
|
|
261
252
|
const statusContent = event.content;
|
|
262
|
-
|
|
253
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: false, log: statusContent }));
|
|
263
254
|
}
|
|
264
255
|
break;
|
|
265
256
|
case 'done': {
|
|
@@ -268,15 +259,6 @@ export class InteractiveSessionService {
|
|
|
268
259
|
// Capture the SDK session ID (available after first message exchange)
|
|
269
260
|
const sdkSessionId = handle.sessionId;
|
|
270
261
|
if (sdkSessionId) {
|
|
271
|
-
// Detect CWD mismatch: if we tried to resume but got a different
|
|
272
|
-
// session ID, the SDK silently created a fresh session (typically
|
|
273
|
-
// because the cwd changed or session JSONL was lost).
|
|
274
|
-
if (previousAgentSessionId && sdkSessionId !== previousAgentSessionId) {
|
|
275
|
-
// eslint-disable-next-line no-console
|
|
276
|
-
console.warn(`[InteractiveSession] Session resume mismatch for feature ${featureId}: ` +
|
|
277
|
-
`expected ${previousAgentSessionId}, got ${sdkSessionId}. ` +
|
|
278
|
-
`SDK created a fresh session (likely cwd changed or session expired).`);
|
|
279
|
-
}
|
|
280
262
|
state.agentSessionId = sdkSessionId;
|
|
281
263
|
// Persist to DB so it survives service restarts
|
|
282
264
|
void this.sessionRepo.updateAgentSessionId(state.sessionId, sdkSessionId);
|
|
@@ -301,7 +283,7 @@ export class InteractiveSessionService {
|
|
|
301
283
|
state.currentAssistantBuffer = '';
|
|
302
284
|
state.toolEventsLog = [];
|
|
303
285
|
// Notify subscribers of end-of-turn
|
|
304
|
-
|
|
286
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: true }));
|
|
305
287
|
// Start idle timer now that the session is live
|
|
306
288
|
this.resetTimer(state);
|
|
307
289
|
return; // Boot complete
|
|
@@ -452,7 +434,7 @@ export class InteractiveSessionService {
|
|
|
452
434
|
if (event.content) {
|
|
453
435
|
responseText += event.content;
|
|
454
436
|
state.currentAssistantBuffer += event.content;
|
|
455
|
-
|
|
437
|
+
state.subscribers.forEach((sub) => sub({ delta: event.content, done: false }));
|
|
456
438
|
}
|
|
457
439
|
break;
|
|
458
440
|
case 'tool_use':
|
|
@@ -460,12 +442,12 @@ export class InteractiveSessionService {
|
|
|
460
442
|
const toolLabel = event.label;
|
|
461
443
|
const toolDetail = event.detail;
|
|
462
444
|
void this.persistToolEvent(state, toolLabel, toolDetail);
|
|
463
|
-
|
|
445
|
+
state.subscribers.forEach((sub) => sub({
|
|
464
446
|
delta: '',
|
|
465
447
|
done: false,
|
|
466
448
|
log: `Using tool: ${toolLabel}`,
|
|
467
449
|
activity: { kind: 'tool_use', label: toolLabel, detail: toolDetail },
|
|
468
|
-
});
|
|
450
|
+
}));
|
|
469
451
|
}
|
|
470
452
|
break;
|
|
471
453
|
case 'tool_result':
|
|
@@ -473,18 +455,18 @@ export class InteractiveSessionService {
|
|
|
473
455
|
const resultLabel = event.label;
|
|
474
456
|
const resultDetail = event.detail;
|
|
475
457
|
void this.persistToolEvent(state, resultLabel, resultDetail);
|
|
476
|
-
|
|
458
|
+
state.subscribers.forEach((sub) => sub({
|
|
477
459
|
delta: '',
|
|
478
460
|
done: false,
|
|
479
461
|
log: `Completed: ${resultLabel}`,
|
|
480
462
|
activity: { kind: 'tool_result', label: resultLabel, detail: resultDetail },
|
|
481
|
-
});
|
|
463
|
+
}));
|
|
482
464
|
}
|
|
483
465
|
break;
|
|
484
466
|
case 'status':
|
|
485
467
|
if (event.content) {
|
|
486
468
|
const statusContent = event.content;
|
|
487
|
-
|
|
469
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: false, log: statusContent }));
|
|
488
470
|
}
|
|
489
471
|
break;
|
|
490
472
|
case 'done': {
|
|
@@ -504,39 +486,17 @@ export class InteractiveSessionService {
|
|
|
504
486
|
await this.messageRepo.create(msg);
|
|
505
487
|
state.currentAssistantBuffer = '';
|
|
506
488
|
state.toolEventsLog = [];
|
|
507
|
-
// Accumulate usage from this turn
|
|
508
|
-
if (event.usage) {
|
|
509
|
-
void this.sessionRepo.accumulateUsage(state.sessionId, {
|
|
510
|
-
costUsd: event.usage.costUsd ?? 0,
|
|
511
|
-
inputTokens: event.usage.inputTokens ?? 0,
|
|
512
|
-
outputTokens: event.usage.outputTokens ?? 0,
|
|
513
|
-
turns: event.usage.numTurns ?? 1,
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
489
|
// Mark as unread — if user has the chat open, the frontend
|
|
517
490
|
// will immediately call markRead to clear it
|
|
518
491
|
void this.sessionRepo.updateTurnStatus(state.sessionId, 'unread');
|
|
519
492
|
// Notify subscribers of end-of-turn
|
|
520
|
-
|
|
493
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: true }));
|
|
521
494
|
return; // Turn complete
|
|
522
495
|
}
|
|
523
496
|
case 'error':
|
|
524
497
|
// eslint-disable-next-line no-console
|
|
525
498
|
console.error(`[InteractiveSession] agent error during turn for session ${state.sessionId}:`, event.content);
|
|
526
|
-
|
|
527
|
-
if (event.usage) {
|
|
528
|
-
void this.sessionRepo.accumulateUsage(state.sessionId, {
|
|
529
|
-
costUsd: event.usage.costUsd ?? 0,
|
|
530
|
-
inputTokens: event.usage.inputTokens ?? 0,
|
|
531
|
-
outputTokens: event.usage.outputTokens ?? 0,
|
|
532
|
-
turns: event.usage.numTurns ?? 1,
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
this.notify(state, {
|
|
536
|
-
delta: '',
|
|
537
|
-
done: true,
|
|
538
|
-
log: `Error: ${event.content ?? 'unknown'}`,
|
|
539
|
-
});
|
|
499
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: true, log: `Error: ${event.content ?? 'unknown'}` }));
|
|
540
500
|
break;
|
|
541
501
|
case 'init':
|
|
542
502
|
// The SDK emits init on every turn, but we only show "Session started"
|
|
@@ -544,36 +504,32 @@ export class InteractiveSessionService {
|
|
|
544
504
|
// spamming the chat with repeated session-started messages.
|
|
545
505
|
break;
|
|
546
506
|
case 'api_retry':
|
|
547
|
-
|
|
548
|
-
delta: '',
|
|
549
|
-
done: false,
|
|
550
|
-
log: event.content ?? 'Retrying API call...',
|
|
551
|
-
});
|
|
507
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: false, log: event.content ?? 'Retrying API call...' }));
|
|
552
508
|
break;
|
|
553
509
|
case 'rate_limit':
|
|
554
|
-
|
|
510
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: false, log: event.content ?? 'Rate limited' }));
|
|
555
511
|
break;
|
|
556
512
|
case 'task_started':
|
|
557
513
|
if (event.content) {
|
|
558
514
|
void this.persistToolEvent(state, 'Subtask started', event.content);
|
|
559
|
-
|
|
515
|
+
state.subscribers.forEach((sub) => sub({
|
|
560
516
|
delta: '',
|
|
561
517
|
done: false,
|
|
562
518
|
log: `Subtask: ${event.content}`,
|
|
563
519
|
activity: { kind: 'system', label: 'Subtask started', detail: event.content },
|
|
564
|
-
});
|
|
520
|
+
}));
|
|
565
521
|
}
|
|
566
522
|
break;
|
|
567
523
|
case 'task_progress':
|
|
568
524
|
if (event.content) {
|
|
569
|
-
|
|
525
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: false, log: `Subtask: ${event.content}` }));
|
|
570
526
|
}
|
|
571
527
|
break;
|
|
572
528
|
case 'task_done':
|
|
573
529
|
if (event.content) {
|
|
574
530
|
const taskStatus = event.detail ?? 'completed';
|
|
575
531
|
void this.persistToolEvent(state, `Subtask ${taskStatus}`, event.content);
|
|
576
|
-
|
|
532
|
+
state.subscribers.forEach((sub) => sub({
|
|
577
533
|
delta: '',
|
|
578
534
|
done: false,
|
|
579
535
|
log: `Subtask ${taskStatus}: ${event.content}`,
|
|
@@ -582,7 +538,7 @@ export class InteractiveSessionService {
|
|
|
582
538
|
label: `Subtask ${taskStatus}`,
|
|
583
539
|
detail: event.content,
|
|
584
540
|
},
|
|
585
|
-
});
|
|
541
|
+
}));
|
|
586
542
|
}
|
|
587
543
|
break;
|
|
588
544
|
}
|
|
@@ -607,18 +563,14 @@ export class InteractiveSessionService {
|
|
|
607
563
|
await this.messageRepo.create(msg);
|
|
608
564
|
state.currentAssistantBuffer = '';
|
|
609
565
|
state.toolEventsLog = [];
|
|
610
|
-
|
|
566
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: true }));
|
|
611
567
|
}
|
|
612
568
|
else if (!responseText) {
|
|
613
569
|
// Stream ended without any response — SDK session likely died.
|
|
614
570
|
// Mark as error so the next message triggers a fresh session.
|
|
615
571
|
// eslint-disable-next-line no-console
|
|
616
572
|
console.error(`[InteractiveSession] stream ended without response for session ${state.sessionId} — session may have died`);
|
|
617
|
-
|
|
618
|
-
delta: '',
|
|
619
|
-
done: true,
|
|
620
|
-
log: 'Session disconnected — will restart on next message',
|
|
621
|
-
});
|
|
573
|
+
state.subscribers.forEach((sub) => sub({ delta: '', done: true, log: 'Session disconnected — will restart on next message' }));
|
|
622
574
|
if (state.agentSessionId) {
|
|
623
575
|
this.stoppedAgentSessionIds.set(state.featureId, state.agentSessionId);
|
|
624
576
|
}
|
|
@@ -677,7 +629,7 @@ export class InteractiveSessionService {
|
|
|
677
629
|
// ---------------------------------------------------------------------------
|
|
678
630
|
// Feature-scoped API (frontend doesn't manage sessions)
|
|
679
631
|
// ---------------------------------------------------------------------------
|
|
680
|
-
async sendUserMessage(featureId, content, worktreePath
|
|
632
|
+
async sendUserMessage(featureId, content, worktreePath) {
|
|
681
633
|
// 1. Persist user message to DB immediately — this is the source of truth
|
|
682
634
|
const now = new Date();
|
|
683
635
|
const userMsg = {
|
|
@@ -690,21 +642,7 @@ export class InteractiveSessionService {
|
|
|
690
642
|
};
|
|
691
643
|
await this.messageRepo.create(userMsg);
|
|
692
644
|
// 2. Find active session for this feature
|
|
693
|
-
|
|
694
|
-
// If the caller requested a different model/agent than the running session,
|
|
695
|
-
// silently stop the current session so a new one boots with the new config.
|
|
696
|
-
// Also clear the cached agentSessionId so we create a fresh SDK session
|
|
697
|
-
// instead of resuming the old one (which would keep the old model).
|
|
698
|
-
if (state && model && state.model !== model) {
|
|
699
|
-
await this.stopSession(state.sessionId);
|
|
700
|
-
this.stoppedAgentSessionIds.delete(featureId);
|
|
701
|
-
state = undefined;
|
|
702
|
-
}
|
|
703
|
-
else if (state && agentType && state.agentType !== agentType) {
|
|
704
|
-
await this.stopSession(state.sessionId);
|
|
705
|
-
this.stoppedAgentSessionIds.delete(featureId);
|
|
706
|
-
state = undefined;
|
|
707
|
-
}
|
|
645
|
+
const state = this.findActiveStateForFeature(featureId);
|
|
708
646
|
if (state) {
|
|
709
647
|
const dbSession = await this.sessionRepo.findById(state.sessionId);
|
|
710
648
|
if (dbSession?.status === InteractiveSessionStatus.ready) {
|
|
@@ -736,7 +674,7 @@ export class InteractiveSessionService {
|
|
|
736
674
|
await this.sessionRepo.updateStatus(dbSession.id, InteractiveSessionStatus.stopped, new Date());
|
|
737
675
|
}
|
|
738
676
|
// Boot a new session — startSession will find the agentSessionId from DB
|
|
739
|
-
const session = await this.startSession(featureId, worktreePath
|
|
677
|
+
const session = await this.startSession(featureId, worktreePath);
|
|
740
678
|
const newState = this.sessions.get(session.id);
|
|
741
679
|
if (newState) {
|
|
742
680
|
newState.pendingUserContent = content;
|
|
@@ -760,7 +698,6 @@ export class InteractiveSessionService {
|
|
|
760
698
|
}
|
|
761
699
|
// Resolve model display: explicit override > default
|
|
762
700
|
const displayModel = state.model ?? 'claude-sonnet-4-6';
|
|
763
|
-
const usage = await this.sessionRepo.getUsage(state.sessionId);
|
|
764
701
|
sessionInfo = {
|
|
765
702
|
pid: null, // SDK manages process internally
|
|
766
703
|
sessionId: state.agentSessionId ?? state.sessionId,
|
|
@@ -772,9 +709,6 @@ export class InteractiveSessionService {
|
|
|
772
709
|
lastActivityAt: dbSession?.lastActivityAt
|
|
773
710
|
? new Date(dbSession.lastActivityAt).toISOString()
|
|
774
711
|
: new Date().toISOString(),
|
|
775
|
-
totalCostUsd: usage?.totalCostUsd ?? null,
|
|
776
|
-
totalInputTokens: usage?.totalInputTokens ?? null,
|
|
777
|
-
totalOutputTokens: usage?.totalOutputTokens ?? null,
|
|
778
712
|
};
|
|
779
713
|
}
|
|
780
714
|
else {
|
|
@@ -785,7 +719,6 @@ export class InteractiveSessionService {
|
|
|
785
719
|
// Show DB info even without live process (process was lost on restart)
|
|
786
720
|
if (latest.status !== InteractiveSessionStatus.stopped &&
|
|
787
721
|
latest.status !== InteractiveSessionStatus.error) {
|
|
788
|
-
const latestUsage = await this.sessionRepo.getUsage(latest.id);
|
|
789
722
|
sessionInfo = {
|
|
790
723
|
pid: null,
|
|
791
724
|
sessionId: latest.id,
|
|
@@ -797,9 +730,6 @@ export class InteractiveSessionService {
|
|
|
797
730
|
lastActivityAt: latest.lastActivityAt
|
|
798
731
|
? new Date(latest.lastActivityAt).toISOString()
|
|
799
732
|
: new Date().toISOString(),
|
|
800
|
-
totalCostUsd: latestUsage?.totalCostUsd ?? null,
|
|
801
|
-
totalInputTokens: latestUsage?.totalInputTokens ?? null,
|
|
802
|
-
totalOutputTokens: latestUsage?.totalOutputTokens ?? null,
|
|
803
733
|
};
|
|
804
734
|
}
|
|
805
735
|
}
|
|
@@ -822,26 +752,29 @@ export class InteractiveSessionService {
|
|
|
822
752
|
return { messages, sessionStatus, streamingText, sessionInfo, turnStatus };
|
|
823
753
|
}
|
|
824
754
|
subscribeByFeature(featureId, onChunk) {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
}
|
|
833
|
-
subs.add(onChunk);
|
|
834
|
-
return () => {
|
|
835
|
-
subs.delete(onChunk);
|
|
836
|
-
if (subs.size === 0) {
|
|
837
|
-
this.featureSubscribers.delete(featureId);
|
|
838
|
-
}
|
|
839
|
-
};
|
|
755
|
+
const state = this.findActiveStateForFeature(featureId);
|
|
756
|
+
if (!state) {
|
|
757
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
758
|
+
return () => { };
|
|
759
|
+
}
|
|
760
|
+
state.subscribers.add(onChunk);
|
|
761
|
+
return () => state.subscribers.delete(onChunk);
|
|
840
762
|
}
|
|
841
763
|
async stopByFeature(featureId) {
|
|
842
764
|
const state = this.findActiveStateForFeature(featureId);
|
|
843
765
|
if (!state)
|
|
844
766
|
return;
|
|
767
|
+
// Persist a system message before killing
|
|
768
|
+
const msg = {
|
|
769
|
+
id: crypto.randomUUID(),
|
|
770
|
+
featureId,
|
|
771
|
+
sessionId: state.sessionId,
|
|
772
|
+
role: InteractiveMessageRole.assistant,
|
|
773
|
+
content: '**Session stopped by user**',
|
|
774
|
+
createdAt: new Date(),
|
|
775
|
+
updatedAt: new Date(),
|
|
776
|
+
};
|
|
777
|
+
await this.messageRepo.create(msg);
|
|
845
778
|
await this.stopSession(state.sessionId);
|
|
846
779
|
}
|
|
847
780
|
async markRead(featureId) {
|
|
@@ -921,23 +854,6 @@ export class InteractiveSessionService {
|
|
|
921
854
|
}
|
|
922
855
|
}
|
|
923
856
|
// ---------------------------------------------------------------------------
|
|
924
|
-
// Event dispatch
|
|
925
|
-
// ---------------------------------------------------------------------------
|
|
926
|
-
/**
|
|
927
|
-
* Dispatch a StreamChunk to all subscribers for a session.
|
|
928
|
-
*
|
|
929
|
-
* Sends to both session-level subscribers (legacy, for sessionId-based
|
|
930
|
-
* subscribe()) and feature-level subscribers (for SSE connections that
|
|
931
|
-
* must survive session restarts).
|
|
932
|
-
*/
|
|
933
|
-
notify(state, chunk) {
|
|
934
|
-
state.subscribers.forEach((sub) => sub(chunk));
|
|
935
|
-
const featureSubs = this.featureSubscribers.get(state.featureId);
|
|
936
|
-
if (featureSubs) {
|
|
937
|
-
featureSubs.forEach((sub) => sub(chunk));
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
// ---------------------------------------------------------------------------
|
|
941
857
|
// Timer helpers
|
|
942
858
|
// ---------------------------------------------------------------------------
|
|
943
859
|
/** Start or restart the idle timeout timer for a session. */
|
package/dist/src/presentation/web/app/api/interactive/chat/[featureId]/messages/route.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/presentation/web/app/api/interactive/chat/[featureId]/messages/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAIvC,UAAU,WAAW;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxC;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/presentation/web/app/api/interactive/chat/[featureId]/messages/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAIvC,UAAU,WAAW;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxC;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuC/F;AAED,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,WAAW,EACrB,EAAE,MAAM,EAAE,EAAE,WAAW,GACtB,OAAO,CAAC,YAAY,CAAC,CAgBvB;AAED,wBAAsB,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAe/F"}
|
|
@@ -18,7 +18,7 @@ export async function POST(request, { params }) {
|
|
|
18
18
|
try {
|
|
19
19
|
const { featureId } = await params;
|
|
20
20
|
const body = (await request.json());
|
|
21
|
-
const { content, worktreePath
|
|
21
|
+
const { content, worktreePath } = body;
|
|
22
22
|
if (!content || typeof content !== 'string' || content.trim().length === 0) {
|
|
23
23
|
return NextResponse.json({ error: 'content must be a non-empty string' }, { status: 400 });
|
|
24
24
|
}
|
|
@@ -35,8 +35,6 @@ export async function POST(request, { params }) {
|
|
|
35
35
|
featureId,
|
|
36
36
|
content,
|
|
37
37
|
worktreePath: resolvedWorktreePath,
|
|
38
|
-
model: typeof model === 'string' ? model : undefined,
|
|
39
|
-
agentType: typeof agentType === 'string' ? agentType : undefined,
|
|
40
38
|
});
|
|
41
39
|
return NextResponse.json({ message }, { status: 201 });
|
|
42
40
|
}
|
|
@@ -152,12 +152,6 @@ function ThinkingIndicator({ booting }) {
|
|
|
152
152
|
// ── Message metadata (timestamp + relative time) ────────────────────────────
|
|
153
153
|
function MessageMeta() {
|
|
154
154
|
const message = useMessage();
|
|
155
|
-
// Tick every 30s so relative timestamps stay fresh
|
|
156
|
-
const [tick, setTick] = useState(0);
|
|
157
|
-
useEffect(() => {
|
|
158
|
-
const id = setInterval(() => setTick((t) => t + 1), 30_000);
|
|
159
|
-
return () => clearInterval(id);
|
|
160
|
-
}, []);
|
|
161
155
|
const meta = useMemo(() => {
|
|
162
156
|
if (!message?.createdAt)
|
|
163
157
|
return null;
|
|
@@ -168,8 +162,7 @@ function MessageMeta() {
|
|
|
168
162
|
time: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
|
169
163
|
relative: formatRelativeTime(date),
|
|
170
164
|
};
|
|
171
|
-
|
|
172
|
-
}, [message?.createdAt, tick]);
|
|
165
|
+
}, [message?.createdAt]);
|
|
173
166
|
if (!meta)
|
|
174
167
|
return null;
|
|
175
168
|
return (_jsx("span", { className: "text-muted-foreground/60 text-[10px]", title: meta.time, children: meta.relative }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatTab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/chat/ChatTab.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"ChatTab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/chat/ChatTab.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,OAAO,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,YAAY,2CAgGhE"}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useCallback, useState } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { AssistantRuntimeProvider } from '@assistant-ui/react';
|
|
6
|
-
import { Trash2, Cpu } from 'lucide-react';
|
|
6
|
+
import { Trash2, Square, Cpu } from 'lucide-react';
|
|
7
7
|
import { cn } from '../../../lib/utils.js';
|
|
8
8
|
import { Thread } from '../../assistant-ui/thread.js';
|
|
9
9
|
import { useAttachments } from '../../../hooks/use-attachments.js';
|
|
@@ -11,20 +11,12 @@ import { composeUserInput } from '../../../app/actions/compose-user-input.js';
|
|
|
11
11
|
import { AgentModelPicker } from '../../features/settings/AgentModelPicker/index.js';
|
|
12
12
|
import { useChatRuntime } from './useChatRuntime.js';
|
|
13
13
|
import { ChatComposer } from './ChatComposer.js';
|
|
14
|
-
const IS_DEV = process.env.NODE_ENV === 'development';
|
|
15
14
|
export function ChatTab({ featureId, worktreePath }) {
|
|
16
15
|
const [overrideAgent, setOverrideAgent] = useState(undefined);
|
|
17
16
|
const [overrideModel, setOverrideModel] = useState(undefined);
|
|
18
|
-
const [debugMode, setDebugMode] = useState(false);
|
|
19
17
|
const att = useAttachments();
|
|
20
18
|
const contentTransform = useCallback((content) => composeUserInput(content, att.completedAttachments.map((a) => ({ path: a.path, name: a.name, notes: a.notes }))), [att.completedAttachments]);
|
|
21
|
-
const { runtime, status, clearChat, sessionInfo, isChatLoading } = useChatRuntime(featureId, worktreePath, {
|
|
22
|
-
contentTransform,
|
|
23
|
-
onMessageSent: att.clearAttachments,
|
|
24
|
-
model: overrideModel,
|
|
25
|
-
agentType: overrideAgent,
|
|
26
|
-
debugMode,
|
|
27
|
-
});
|
|
19
|
+
const { runtime, status, clearChat, stopAgent, sessionInfo, isChatLoading } = useChatRuntime(featureId, worktreePath, { contentTransform, onMessageSent: att.clearAttachments });
|
|
28
20
|
const handlePickFiles = useCallback(async () => {
|
|
29
21
|
try {
|
|
30
22
|
const res = await fetch('/api/dialog/pick-files');
|
|
@@ -54,16 +46,18 @@ export function ChatTab({ featureId, worktreePath }) {
|
|
|
54
46
|
setOverrideAgent(agent);
|
|
55
47
|
setOverrideModel(model);
|
|
56
48
|
}, className: "w-55" }) }));
|
|
57
|
-
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsx(ChatHeader, { sessionInfo: sessionInfo, isAgentActive: status.isRunning, onClear: clearChat,
|
|
49
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsx(ChatHeader, { sessionInfo: sessionInfo, isAgentActive: status.isRunning, onClear: clearChat, onStop: stopAgent }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: isChatLoading ? (_jsx(ChatSkeleton, {})) : (_jsx(AssistantRuntimeProvider, { runtime: runtime, children: _jsx(Thread, { composer: composer }) })) })] }));
|
|
58
50
|
}
|
|
59
51
|
// ── Loading skeleton ────────────────────────────────────────────────────────
|
|
60
52
|
function ChatSkeleton() {
|
|
61
53
|
return (_jsxs("div", { className: "flex flex-1 flex-col gap-3 p-4 pt-6", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("div", { className: "bg-muted h-6 w-6 animate-pulse rounded-full" }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("div", { className: "bg-muted h-4 w-48 animate-pulse rounded-lg" }), _jsx("div", { className: "bg-muted h-4 w-72 animate-pulse rounded-lg" }), _jsx("div", { className: "bg-muted h-4 w-36 animate-pulse rounded-lg" })] })] }), _jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("div", { className: "bg-muted h-6 w-6 animate-pulse rounded-full" }), _jsx("div", { className: "bg-muted h-4 w-32 animate-pulse rounded-lg" })] }), _jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("div", { className: "bg-muted h-6 w-6 animate-pulse rounded-full" }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("div", { className: "bg-muted h-4 w-56 animate-pulse rounded-lg" }), _jsx("div", { className: "bg-muted h-4 w-64 animate-pulse rounded-lg" })] })] })] }));
|
|
62
54
|
}
|
|
63
55
|
// ── Chat header — compact session info + actions ─────────────────────────────
|
|
64
|
-
function ChatHeader({ sessionInfo, isAgentActive, onClear,
|
|
56
|
+
function ChatHeader({ sessionInfo, isAgentActive, onClear, onStop, }) {
|
|
65
57
|
const { t } = useTranslation('web');
|
|
66
|
-
return (_jsxs("div", { className: "flex h-8 shrink-0 items-center border-b px-3", children: [_jsx("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: sessionInfo ? (_jsxs(_Fragment, { children: [isAgentActive ? (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-emerald-500" })) : (_jsx(Cpu, { className: "text-muted-foreground/40 h-3 w-3 shrink-0" })), _jsxs("span", { className: "text-muted-foreground font-mono text-[10px]", children: [sessionInfo.model ?? 'agent', sessionInfo.sessionId ? ` · ${sessionInfo.sessionId.slice(0, 8)}` : ''] })] })) : (_jsx("span", { className: "text-muted-foreground/40 text-[11px]", children: t('chat.noSession') })) }), _jsxs("div", { className: "flex items-center gap-1 ps-2", children: [
|
|
58
|
+
return (_jsxs("div", { className: "flex h-8 shrink-0 items-center border-b px-3", children: [_jsx("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: sessionInfo ? (_jsxs(_Fragment, { children: [isAgentActive ? (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-emerald-500" })) : (_jsx(Cpu, { className: "text-muted-foreground/40 h-3 w-3 shrink-0" })), _jsxs("span", { className: "text-muted-foreground font-mono text-[10px]", children: [sessionInfo.model ?? 'agent', sessionInfo.sessionId ? ` · ${sessionInfo.sessionId.slice(0, 8)}` : ''] })] })) : (_jsx("span", { className: "text-muted-foreground/40 text-[11px]", children: t('chat.noSession') })) }), _jsxs("div", { className: "flex items-center gap-1 ps-2", children: [sessionInfo ? (_jsxs(_Fragment, { children: [_jsxs(ToolbarButton, { onClick: () => {
|
|
59
|
+
void onStop();
|
|
60
|
+
}, title: t('chat.forceStopAgent'), variant: "danger", children: [_jsx(Square, { className: "h-2.5 w-2.5 fill-current" }), _jsx("span", { children: t('chat.stop') })] }), _jsx("span", { className: "text-border mx-0.5", children: "|" })] })) : null, _jsxs(ToolbarButton, { onClick: () => {
|
|
67
61
|
void onClear();
|
|
68
62
|
}, title: t('chat.clearChatHistory'), children: [_jsx(Trash2, { className: "h-2.5 w-2.5" }), _jsx("span", { children: t('chat.clear') })] })] })] }));
|
|
69
63
|
}
|
|
@@ -5,9 +5,6 @@ interface SessionInfo {
|
|
|
5
5
|
startedAt: string;
|
|
6
6
|
idleTimeoutMinutes: number;
|
|
7
7
|
lastActivityAt: string;
|
|
8
|
-
totalCostUsd: number | null;
|
|
9
|
-
totalInputTokens: number | null;
|
|
10
|
-
totalOutputTokens: number | null;
|
|
11
8
|
}
|
|
12
9
|
export interface ChatStatus {
|
|
13
10
|
/** Whether the agent is actively working (booting, thinking, streaming). */
|
|
@@ -20,19 +17,6 @@ export interface ChatRuntimeOptions {
|
|
|
20
17
|
contentTransform?: (content: string) => string;
|
|
21
18
|
/** Called after a message is successfully sent (e.g. clear attachments). */
|
|
22
19
|
onMessageSent?: () => void;
|
|
23
|
-
/** Override model for new sessions (e.g. 'claude-sonnet-4-6'). */
|
|
24
|
-
model?: string;
|
|
25
|
-
/** Override agent type for new sessions (e.g. 'claude-code'). */
|
|
26
|
-
agentType?: string;
|
|
27
|
-
/** When true, inject debug bubbles showing SSE events, session info, etc. */
|
|
28
|
-
debugMode?: boolean;
|
|
29
|
-
}
|
|
30
|
-
/** A debug event captured from SSE for display in debug mode. */
|
|
31
|
-
export interface DebugEvent {
|
|
32
|
-
id: string;
|
|
33
|
-
timestamp: Date;
|
|
34
|
-
label: string;
|
|
35
|
-
detail?: string;
|
|
36
20
|
}
|
|
37
21
|
/**
|
|
38
22
|
* `featureId` is a polymorphic scope key: a feature UUID, "repo-<id>", or "global".
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatRuntime.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/chat/useChatRuntime.ts"],"names":[],"mappings":"AAkBA,UAAU,WAAW;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"useChatRuntime.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/chat/useChatRuntime.ts"],"names":[],"mappings":"AAkBA,UAAU,WAAW;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAgDD,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAID,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,kBAAkB;;;;;;;EAiQ7B"}
|