refactor: replace welcome message with server_info status payload
Unify the initial connection handshake and capability update paths. The server now sends a server_info status message on connect and whenever capabilities change, enabling the onboarding flow where voice becomes available after models are configured.
This commit is contained in:
@@ -29,7 +29,7 @@ function createMockTransport() {
|
||||
let onOpen: () => void = () => {}
|
||||
let onClose: (_event?: unknown) => void = () => {}
|
||||
let onError: (_event?: unknown) => void = () => {}
|
||||
let welcomeOrdinal = 1
|
||||
let serverInfoOrdinal = 1
|
||||
|
||||
const transport: DaemonTransport = {
|
||||
send: (data) => sent.push(data),
|
||||
@@ -61,11 +61,16 @@ function createMockTransport() {
|
||||
sent.length = 0
|
||||
onMessage(
|
||||
JSON.stringify({
|
||||
type: 'welcome',
|
||||
serverId: `srv_test_${welcomeOrdinal++}`,
|
||||
hostname: null,
|
||||
version: null,
|
||||
resumed: false,
|
||||
type: 'session',
|
||||
message: {
|
||||
type: 'status',
|
||||
payload: {
|
||||
status: 'server_info',
|
||||
serverId: `srv_test_${serverInfoOrdinal++}`,
|
||||
hostname: null,
|
||||
version: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
},
|
||||
|
||||
@@ -4,10 +4,11 @@ import {
|
||||
AgentCreatedStatusPayloadSchema,
|
||||
AgentRefreshedStatusPayloadSchema,
|
||||
AgentResumedStatusPayloadSchema,
|
||||
parseServerInfoStatusPayload,
|
||||
RestartRequestedStatusPayloadSchema,
|
||||
ShutdownRequestedStatusPayloadSchema,
|
||||
SessionInboundMessageSchema,
|
||||
type WSWelcomeMessage,
|
||||
type ServerInfoStatusPayload,
|
||||
WSOutboundMessageSchema,
|
||||
} from '../shared/messages.js'
|
||||
import type {
|
||||
@@ -450,7 +451,7 @@ export class DaemonClient {
|
||||
private readonly logServerId: string | null
|
||||
private readonly logClientIdHash: string
|
||||
private readonly logGeneration: number | null
|
||||
private lastWelcomeMessage: WSWelcomeMessage | null = null
|
||||
private lastServerInfoMessage: ServerInfoStatusPayload | null = null
|
||||
|
||||
constructor(private config: DaemonClientConfig) {
|
||||
this.logger = config.logger ?? consoleLogger
|
||||
@@ -565,7 +566,7 @@ export class DaemonClient {
|
||||
const transportUrl = this.resolveTransportUrlForAttempt()
|
||||
const transport = transportFactory({ url: transportUrl, headers })
|
||||
this.transport = transport
|
||||
this.lastWelcomeMessage = null
|
||||
this.lastServerInfoMessage = null
|
||||
|
||||
this.updateConnectionState({
|
||||
status: 'connecting',
|
||||
@@ -700,7 +701,7 @@ export class DaemonClient {
|
||||
this.clearWaiters(new Error('Daemon client closed'))
|
||||
this.rejectPendingSendQueue(new Error('Daemon client closed'))
|
||||
this.terminalStreams.clearAll()
|
||||
this.lastWelcomeMessage = null
|
||||
this.lastServerInfoMessage = null
|
||||
this.updateConnectionState(
|
||||
{ status: 'disposed' },
|
||||
{ event: 'DISPOSE', reason: 'Client closed', reasonCode: 'disposed' }
|
||||
@@ -2796,8 +2797,8 @@ export class DaemonClient {
|
||||
return requestId ?? crypto.randomUUID()
|
||||
}
|
||||
|
||||
getLastWelcomeMessage(): WSWelcomeMessage | null {
|
||||
return this.lastWelcomeMessage
|
||||
getLastServerInfoMessage(): ServerInfoStatusPayload | null {
|
||||
return this.lastServerInfoMessage
|
||||
}
|
||||
|
||||
private resolveTransportUrlForAttempt(): string {
|
||||
@@ -2962,18 +2963,6 @@ export class DaemonClient {
|
||||
return
|
||||
}
|
||||
|
||||
if (parsed.data.type === 'welcome') {
|
||||
this.lastWelcomeMessage = parsed.data
|
||||
this.resetConnectTimeout()
|
||||
this.reconnectAttempt = 0
|
||||
this.updateConnectionState({ status: 'connected' }, { event: 'HELLO_WELCOME' })
|
||||
this.resubscribeCheckoutDiffSubscriptions()
|
||||
this.resubscribeTerminalDirectorySubscriptions()
|
||||
this.flushPendingSendQueue()
|
||||
this.resolveConnect()
|
||||
return
|
||||
}
|
||||
|
||||
this.handleSessionMessage(parsed.data.message)
|
||||
}
|
||||
|
||||
@@ -3050,7 +3039,7 @@ export class DaemonClient {
|
||||
this.clearWaiters(new Error(reason ?? 'Connection lost'))
|
||||
this.rejectPendingSendQueue(new Error(reason ?? 'Connection lost'))
|
||||
this.terminalStreams.clearAll()
|
||||
this.lastWelcomeMessage = null
|
||||
this.lastServerInfoMessage = null
|
||||
|
||||
if (wasDisposed) {
|
||||
this.rejectConnect(new Error(reason ?? 'Daemon client is disposed'))
|
||||
@@ -3084,6 +3073,22 @@ export class DaemonClient {
|
||||
}
|
||||
|
||||
private handleSessionMessage(msg: SessionOutboundMessage): void {
|
||||
if (msg.type === 'status') {
|
||||
const serverInfo = parseServerInfoStatusPayload(msg.payload)
|
||||
if (serverInfo) {
|
||||
this.lastServerInfoMessage = serverInfo
|
||||
if (this.connectionState.status === 'connecting') {
|
||||
this.resetConnectTimeout()
|
||||
this.reconnectAttempt = 0
|
||||
this.updateConnectionState({ status: 'connected' }, { event: 'HELLO_SERVER_INFO' })
|
||||
this.resubscribeCheckoutDiffSubscriptions()
|
||||
this.resubscribeTerminalDirectorySubscriptions()
|
||||
this.flushPendingSendQueue()
|
||||
this.resolveConnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.type === 'terminal_stream_exit') {
|
||||
this.terminalStreams.clearStream({ streamId: msg.payload.streamId })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user