fix(web): fence request telemetry lifecycles
This commit is contained in:
@@ -35,10 +35,6 @@ function sleep(ms: number, signal: AbortSignal): Promise<void> {
|
||||
})
|
||||
}
|
||||
|
||||
/** Coarse connection state for the UI (audit C1): 'connected' after each generation's handshake,
|
||||
* 'reconnecting' the moment the generation fails (covers the whole backoff+retry span). */
|
||||
export type ConnectionState = 'connected' | 'reconnecting'
|
||||
|
||||
/** Frame sink callbacks: the Controller owns the physical streams; business dispatch belongs to
|
||||
* SessionManager. */
|
||||
export interface ConnectionSinks {
|
||||
@@ -48,9 +44,6 @@ export interface ConnectionSinks {
|
||||
onConnected?: () => void
|
||||
/** After every failed generation closes and before retry starts. Not emitted when the controller is stopped. */
|
||||
onDisconnected?: () => void
|
||||
/** Coarse state transitions (deduplicated: fires only on change). The initial pre-connect
|
||||
* span reports nothing — the UI treats "no state yet" as connecting, not as an outage. */
|
||||
onStateChange?: (state: ConnectionState) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +58,6 @@ export class ConnectionController {
|
||||
private attempt = 0
|
||||
private current: AbortController | null = null
|
||||
private running = false
|
||||
private lastState: ConnectionState | null = null
|
||||
private readonly config: Required<ConnectionConfig>
|
||||
|
||||
constructor(
|
||||
@@ -140,7 +132,6 @@ export class ConnectionController {
|
||||
timeout.abort()
|
||||
if (ac.signal.aborted) throw new Error('generation aborted during readiness handshake')
|
||||
this.attempt = 0
|
||||
this.emitState('connected')
|
||||
this.callSink(this.sinks.onConnected)
|
||||
} catch {
|
||||
// Transport failure: treat as generation failure, fall through to the shared backoff.
|
||||
@@ -150,7 +141,6 @@ export class ConnectionController {
|
||||
await failed
|
||||
if (!this.isRunning()) return
|
||||
this.callSink(this.sinks.onDisconnected)
|
||||
this.emitState('reconnecting')
|
||||
this.attempt += 1
|
||||
console.warn(`[web-runtime] connection lost, retry #${this.attempt}`)
|
||||
const idle = new AbortController()
|
||||
@@ -158,13 +148,6 @@ export class ConnectionController {
|
||||
}
|
||||
}
|
||||
|
||||
/** Deduplicated state emission (sink isolation applies). */
|
||||
private emitState(state: ConnectionState): void {
|
||||
if (this.lastState === state) return
|
||||
this.lastState = state
|
||||
this.callSink(() => this.sinks.onStateChange?.(state))
|
||||
}
|
||||
|
||||
private async pumpStream<F extends { type: string }>(
|
||||
stream: AsyncIterable<RpcRequest<F>>,
|
||||
sink: ((envelope: RpcRequest<F>) => void) | undefined,
|
||||
|
||||
@@ -1143,7 +1143,7 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
|
||||
// The fixture's durable transcript is historically zero-based, while
|
||||
// the real Agent's request telemetry opens turns at one.
|
||||
turn: turn + 1,
|
||||
step: 0,
|
||||
step: 1,
|
||||
provider: target.provider,
|
||||
model: target.model,
|
||||
// No fixture token-meter is composed, so omit the request-pressure
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import type { Context } from 'cordis'
|
||||
import type { IApiClient } from './api.ts'
|
||||
import { ConnectionController, type ConnectionConfig, type ConnectionSinks, type ConnectionState } from './connection.ts'
|
||||
import { ConnectionController, type ConnectionConfig, type ConnectionSinks } from './connection.ts'
|
||||
import { FixtureApiClient } from './fixture.ts'
|
||||
import { WebApiClient } from './web-api-client.ts'
|
||||
|
||||
@@ -27,7 +27,7 @@ export { RpcId, AbstractApiClient, transportError } from './api.ts'
|
||||
|
||||
// Connection loop types are public through ConnectionHandle.start; the
|
||||
// controller remains package-internal.
|
||||
export type { ConnectionConfig, ConnectionSinks, ConnectionState }
|
||||
export type { ConnectionConfig, ConnectionSinks }
|
||||
|
||||
|
||||
/** Required services (none — this is the wire root). */
|
||||
|
||||
Reference in New Issue
Block a user