1909
1910
private async _sendMessage(chat: URI, prompt: string, workingDirectory: URI | undefined, attachments?: readonly MessageAttachment[], turnId?: string, _senderClientId?: string): Promise<void> {
1911
>
// `IAgent.sendMessage` declares `turnId?` but every production caller in
claudeAgent.ts
1912
>
// `AgentSideEffects` supplies one. Generate a fallback so the
1913
>
// session-side `QueuedRequest.turnId: string` invariant holds even if a
1914
>
// hypothetical caller forgets it.
1915
>
const effectiveTurnId = turnId ?? generateUuid();
1916
>
const context = this._getChatContext(chat);
1917
>
1918
>
// Additional peer chat: route to its own chat. Its SDK
1919
>
// `session_id` is the chat's chat id, NOT the parent session's.
1920
>
// Hold the per-chat lock across BOTH materialize and send (mirroring the
1921
>
// default-chat path below) so concurrent sends to the same peer chat
1922
>
// serialize and a racing disposeChat/disposeSession (which queue on the
1923
>
// same chat key) waits for the in-flight turn instead of disposing the
1924
>
// session under it.
1925
>
if (context.isPeerChat) {
1926
return this._sessionSequencer.queue(context.chatKey, async () => {
1927
const chatSession = await this._materializeChatLocked(context.session, chat);