|
8 | 8 | reportManualRunToolStop, |
9 | 9 | } from '@/lib/copilot/client-sse/run-tool-execution' |
10 | 10 | import { MOTHERSHIP_CHAT_API_PATH } from '@/lib/copilot/constants' |
| 11 | +import { VFS_DIR_TO_RESOURCE } from '@/lib/copilot/resource-types' |
11 | 12 | import { isWorkflowToolName } from '@/lib/copilot/workflow-tools' |
12 | 13 | import { getNextWorkflowColor } from '@/lib/workflows/colors' |
13 | 14 | import { invalidateResourceQueries } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry' |
@@ -197,6 +198,36 @@ function ensureWorkflowInRegistry(resourceId: string, title: string, workspaceId |
197 | 198 | return true |
198 | 199 | } |
199 | 200 |
|
| 201 | +function extractResourceFromReadResult( |
| 202 | + path: string | undefined, |
| 203 | + output: unknown |
| 204 | +): MothershipResource | null { |
| 205 | + if (!path) return null |
| 206 | + |
| 207 | + const segments = path.split('/') |
| 208 | + const resourceType = VFS_DIR_TO_RESOURCE[segments[0]] |
| 209 | + if (!resourceType || !segments[1]) return null |
| 210 | + |
| 211 | + const obj = output && typeof output === 'object' ? (output as Record<string, unknown>) : undefined |
| 212 | + if (!obj) return null |
| 213 | + |
| 214 | + let id = obj.id as string | undefined |
| 215 | + let name = obj.name as string | undefined |
| 216 | + |
| 217 | + if (!id && typeof obj.content === 'string') { |
| 218 | + try { |
| 219 | + const parsed = JSON.parse(obj.content) |
| 220 | + id = parsed?.id as string | undefined |
| 221 | + name = parsed?.name as string | undefined |
| 222 | + } catch { |
| 223 | + // content is not JSON |
| 224 | + } |
| 225 | + } |
| 226 | + |
| 227 | + if (!id) return null |
| 228 | + return { type: resourceType, id, title: name || segments[1] } |
| 229 | +} |
| 230 | + |
200 | 231 | export interface UseChatOptions { |
201 | 232 | onResourceEvent?: () => void |
202 | 233 | } |
@@ -352,14 +383,6 @@ export function useChat( |
352 | 383 | return b |
353 | 384 | } |
354 | 385 |
|
355 | | - const ensureSubagentTextBlock = (): ContentBlock => { |
356 | | - const last = blocks[blocks.length - 1] |
357 | | - if (last?.type === 'subagent_text') return last |
358 | | - const b: ContentBlock = { type: 'subagent_text', content: '' } |
359 | | - blocks.push(b) |
360 | | - return b |
361 | | - } |
362 | | - |
363 | 386 | const flush = () => { |
364 | 387 | streamingBlocksRef.current = [...blocks] |
365 | 388 | setMessages((prev) => |
@@ -427,9 +450,10 @@ export function useChat( |
427 | 450 | lastContentSource !== contentSource && |
428 | 451 | runningText.length > 0 && |
429 | 452 | !runningText.endsWith('\n') |
430 | | - const tb = activeSubagent ? ensureSubagentTextBlock() : ensureTextBlock() |
431 | | - tb.content = (tb.content ?? '') + chunk |
432 | | - runningText += needsBoundaryNewline ? `\n${chunk}` : chunk |
| 453 | + const tb = ensureTextBlock() |
| 454 | + const normalizedChunk = needsBoundaryNewline ? `\n${chunk}` : chunk |
| 455 | + tb.content = (tb.content ?? '') + normalizedChunk |
| 456 | + runningText += normalizedChunk |
433 | 457 | lastContentSource = contentSource |
434 | 458 | streamingContentRef.current = runningText |
435 | 459 | flush() |
@@ -523,6 +547,18 @@ export function useChat( |
523 | 547 | error: (parsed.error ?? getPayloadData(parsed)?.error) as string | undefined, |
524 | 548 | } |
525 | 549 | flush() |
| 550 | + |
| 551 | + if (tc.name === 'read' && tc.status === 'success') { |
| 552 | + const readArgs = toolArgsMap.get(id) |
| 553 | + const resource = extractResourceFromReadResult( |
| 554 | + readArgs?.path as string | undefined, |
| 555 | + tc.result.output |
| 556 | + ) |
| 557 | + if (resource) { |
| 558 | + addResource(resource) |
| 559 | + onResourceEventRef.current?.() |
| 560 | + } |
| 561 | + } |
526 | 562 | } |
527 | 563 |
|
528 | 564 | break |
|
0 commit comments