Skip to content

Commit 3ef87e5

Browse files
committed
Add req id
1 parent 649ee9c commit 3ef87e5

File tree

6 files changed

+55
-2
lines changed

6 files changed

+55
-2
lines changed

apps/sim/app/workspace/[workspaceId]/components/message-actions/message-actions.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
ModalContent,
1111
ModalFooter,
1212
ModalHeader,
13+
TagIcon,
1314
Textarea,
1415
ThumbsDown,
1516
ThumbsUp,
@@ -46,20 +47,26 @@ interface MessageActionsProps {
4647
content: string
4748
chatId?: string
4849
userQuery?: string
50+
requestId?: string
4951
}
5052

51-
export function MessageActions({ content, chatId, userQuery }: MessageActionsProps) {
53+
export function MessageActions({ content, chatId, userQuery, requestId }: MessageActionsProps) {
5254
const [copied, setCopied] = useState(false)
55+
const [copiedRequestId, setCopiedRequestId] = useState(false)
5356
const [pendingFeedback, setPendingFeedback] = useState<'up' | 'down' | null>(null)
5457
const [feedbackText, setFeedbackText] = useState('')
5558
const resetTimeoutRef = useRef<number | null>(null)
59+
const requestIdTimeoutRef = useRef<number | null>(null)
5660
const submitFeedback = useSubmitCopilotFeedback()
5761

5862
useEffect(() => {
5963
return () => {
6064
if (resetTimeoutRef.current !== null) {
6165
window.clearTimeout(resetTimeoutRef.current)
6266
}
67+
if (requestIdTimeoutRef.current !== null) {
68+
window.clearTimeout(requestIdTimeoutRef.current)
69+
}
6370
}
6471
}, [])
6572

@@ -79,6 +86,20 @@ export function MessageActions({ content, chatId, userQuery }: MessageActionsPro
7986
}
8087
}, [content])
8188

89+
const copyRequestId = useCallback(async () => {
90+
if (!requestId) return
91+
try {
92+
await navigator.clipboard.writeText(requestId)
93+
setCopiedRequestId(true)
94+
if (requestIdTimeoutRef.current !== null) {
95+
window.clearTimeout(requestIdTimeoutRef.current)
96+
}
97+
requestIdTimeoutRef.current = window.setTimeout(() => setCopiedRequestId(false), 1500)
98+
} catch {
99+
/* clipboard unavailable */
100+
}
101+
}, [requestId])
102+
82103
const handleFeedbackClick = useCallback(
83104
(type: 'up' | 'down') => {
84105
if (chatId && userQuery) {
@@ -144,6 +165,21 @@ export function MessageActions({ content, chatId, userQuery }: MessageActionsPro
144165
>
145166
<ThumbsDown className={ICON_CLASS} />
146167
</button>
168+
{requestId && (
169+
<button
170+
type='button'
171+
aria-label='Copy request ID'
172+
onClick={copyRequestId}
173+
className={BUTTON_CLASS}
174+
title={copiedRequestId ? 'Copied!' : 'Copy request ID'}
175+
>
176+
{copiedRequestId ? (
177+
<Check className={ICON_CLASS} />
178+
) : (
179+
<TagIcon className={ICON_CLASS} />
180+
)}
181+
</button>
182+
)}
147183
</div>
148184

149185
<Modal open={pendingFeedback !== null} onOpenChange={handleModalClose}>

apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export function MothershipChat({
182182
content={msg.content}
183183
chatId={chatId}
184184
userQuery={precedingUserMsg?.content}
185+
requestId={msg.requestId}
185186
/>
186187
</div>
187188
)}

apps/sim/lib/copilot/request/go/stream.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ export interface StreamLoopOptions extends OrchestratorOptions {
158158
* Return true to skip the default handler for this event.
159159
*/
160160
onBeforeDispatch?: (event: StreamEvent, context: StreamingContext) => boolean | undefined
161+
/**
162+
* Called when the Go backend's trace ID (go_trace_id) is first received via SSE.
163+
*/
164+
onGoTraceId?: (goTraceId: string) => void
161165
}
162166

163167
/**
@@ -234,8 +238,12 @@ export async function runStreamLoop(
234238

235239
const streamEvent = eventToStreamEvent(raw)
236240
if (raw.trace?.requestId) {
241+
const prev = context.requestId
237242
context.requestId = raw.trace.requestId
238243
context.trace.setGoTraceId(raw.trace.requestId)
244+
if (raw.trace.requestId !== prev) {
245+
options.onGoTraceId?.(raw.trace.requestId)
246+
}
239247
}
240248

241249
if (shouldSkipToolCallEvent(streamEvent) || shouldSkipToolResultEvent(streamEvent)) {

apps/sim/lib/copilot/request/lifecycle/run.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export interface CopilotLifecycleOptions extends OrchestratorOptions {
4343
goRoute?: string
4444
trace?: TraceCollector
4545
simRequestId?: string
46+
onGoTraceId?: (goTraceId: string) => void
4647
}
4748

4849
export async function runCopilotLifecycle(

apps/sim/lib/copilot/request/lifecycle/start.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ export function createSSEStream(params: StreamingOrchestrationParams): ReadableS
143143
trace: collector,
144144
simRequestId: requestId,
145145
abortSignal: abortController.signal,
146+
onGoTraceId: (goTraceId) => {
147+
publisher.updateRequestId(goTraceId)
148+
},
146149
onEvent: async (event) => {
147150
await publisher.publish(event)
148151
},

apps/sim/lib/copilot/request/session/writer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface StreamWriterOptions {
2222
export class StreamWriter {
2323
private readonly streamId: string
2424
private readonly chatId: string | undefined
25-
private readonly requestId: string
25+
private requestId: string
2626
private readonly keepaliveMs: number
2727
private readonly flushIntervalMs: number
2828
private readonly flushMaxBatch: number
@@ -55,6 +55,10 @@ export class StreamWriter {
5555
return this._sawComplete
5656
}
5757

58+
updateRequestId(id: string): void {
59+
this.requestId = id
60+
}
61+
5862
attach(controller: ReadableStreamDefaultController): void {
5963
this.controller = controller
6064
}

0 commit comments

Comments
 (0)