mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 08:03:13 +00:00
fix(plugins): fan Pi session-only status out to plugin subscribers
The providerSessionOnly early-return in applyNormalizedStatus emitted to onAgentStatus (main-window fanout) but skipped enrichedStatusListeners, so plugins subscribed to agent.status.changed silently missed every Pi session_start event. Route both emit sites through one helper so a future early return cannot drop the plugin tap again. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -7083,6 +7083,38 @@ describe('AgentHookServer ingestRemote', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('fans a Pi session-only status out to plugins, not just the renderer', () => {
|
||||
const server = new AgentHookServer()
|
||||
const rendererListener = vi.fn()
|
||||
const pluginListener = vi.fn()
|
||||
server.setListener(rendererListener)
|
||||
server.subscribeEnrichedStatus(pluginListener)
|
||||
|
||||
server.ingestRemote(
|
||||
{
|
||||
paneKey: PANE,
|
||||
tabId: 'tab-1',
|
||||
worktreeId: 'wt-1',
|
||||
providerSession: {
|
||||
key: 'session_id',
|
||||
id: 'pi-session-1',
|
||||
transcriptPath: '/tmp/pi-session-1.jsonl'
|
||||
},
|
||||
providerSessionOnly: true,
|
||||
payload: { state: 'done', prompt: '', agentType: 'pi' }
|
||||
},
|
||||
'conn-1'
|
||||
)
|
||||
|
||||
// The session-only path returns early, so it must not skip the plugin tap.
|
||||
expect(rendererListener).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ paneKey: PANE, providerSessionOnly: true })
|
||||
)
|
||||
expect(pluginListener).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ paneKey: PANE, providerSessionOnly: true })
|
||||
)
|
||||
})
|
||||
|
||||
it('rejects invalid remote metadata-only session envelopes', () => {
|
||||
const server = new AgentHookServer()
|
||||
const listener = vi.fn()
|
||||
|
||||
@@ -903,7 +903,7 @@ export class AgentHookServer {
|
||||
this.state.lastStatusByPaneKey.set(enriched.paneKey, enriched)
|
||||
this.scheduleStatusPersist()
|
||||
this.notifyStatusChangeListeners()
|
||||
this.onAgentStatus?.(enriched)
|
||||
this.emitEnrichedStatus(enriched)
|
||||
return enriched
|
||||
}
|
||||
const stateReconciledPayload =
|
||||
@@ -1015,6 +1015,13 @@ export class AgentHookServer {
|
||||
this.state.lastStatusByPaneKey.set(enriched.paneKey, enriched)
|
||||
this.scheduleStatusPersist()
|
||||
this.notifyStatusChangeListeners()
|
||||
this.emitEnrichedStatus(enriched)
|
||||
return enriched
|
||||
}
|
||||
|
||||
// Why: every status emit must reach plugins too, so a new early-return path
|
||||
// upstream cannot silently leave the plugin tap behind the main-window fanout.
|
||||
private emitEnrichedStatus(enriched: EnrichedAgentHookEventPayload): void {
|
||||
this.onAgentStatus?.(enriched)
|
||||
for (const listener of this.enrichedStatusListeners) {
|
||||
try {
|
||||
@@ -1023,7 +1030,6 @@ export class AgentHookServer {
|
||||
console.error('[agent-hooks] enriched status listener threw', err)
|
||||
}
|
||||
}
|
||||
return enriched
|
||||
}
|
||||
|
||||
private clearAssistantMessageRetry(paneKey: string): void {
|
||||
|
||||
Reference in New Issue
Block a user