// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= import { selectActionableInterruptedRun, selectEventNativeActiveRunId, } from '@/components/ChatBox/runControlArbitration'; import { createProjectViewState, type ProjectedRun } from '@/lib/projector'; import { createChatProjectionState, type ChatProjectionNode, } from '@/lib/projector/chat'; import { createHumanControlProjectionState, type HumanControlInteraction, } from '@/lib/projector/control'; import type { ProjectEventStoreSnapshot } from '@/store/projectEventStore'; import { describe, expect, it } from 'vitest'; function run( runId: string, status: ProjectedRun['status'], overrides: Partial = {} ): ProjectedRun { return { runId, status, lastSequence: 2, runVersion: 2, updatedAt: '2026-08-12T10:00:00.000Z', origin: 'local', resumeBlockedReason: null, ...overrides, }; } function canonicalNode(runId: string, eventType = 'run.attempt_started') { return { id: `${runId}:${eventType}`, eventId: `${runId}:${eventType}`, projectId: 'project-1', runId, createdAt: '2026-08-12T10:00:00.000Z', runSequence: 1, cloudCursor: null, eventType, legacyStep: null, kind: 'run_status', status: 'running', } as ChatProjectionNode; } function request( interactionId: string, runId: string, requestEventType = 'interaction.requested' ) { return { interactionId, runId, status: 'requested', requestSource: 'canonical', requestEventId: `${runId}:${requestEventType}`, requestEventType, } as HumanControlInteraction; } function snapshot({ runs, nodes = [], controls = [], needsResync = false, eventsTruncated = false, overflowed = false, }: { runs: ProjectedRun[]; nodes?: ChatProjectionNode[]; controls?: HumanControlInteraction[]; needsResync?: boolean; eventsTruncated?: boolean; overflowed?: boolean; }): ProjectEventStoreSnapshot { const view = createProjectViewState('project-1', 'live'); const chat = createChatProjectionState('project-1'); const control = createHumanControlProjectionState('project-1'); return { view: { ...view, needsResync, eventsTruncated, runs: Object.fromEntries(runs.map((item) => [item.runId, item])), }, chat: { ...chat, nodes, nodeById: Object.fromEntries(nodes.map((node) => [node.eventId, node])), }, control: { ...control, orderedInteractionIds: controls.map((item) => item.interactionId), interactionById: Object.fromEntries( controls.map((item) => [item.interactionId, item]) ), }, revision: 1, hasHydratedSnapshot: true, overflowed, lastEffects: [], }; } describe('event-native Run-control arbitration', () => { it('lets a typed pending control outrank the legacy-owned live Run', () => { const state = snapshot({ runs: [run('legacy-live', 'running'), run('input', 'waiting_for_user')], nodes: [canonicalNode('legacy-live')], controls: [request('question-1', 'input')], }); expect(selectEventNativeActiveRunId(state, 'legacy-live')).toBe('input'); }); it('does not give aggregate-only or orphan historical Runs controls', () => { expect( selectEventNativeActiveRunId( snapshot({ runs: [run('past', 'running')] }), 'past' ) ).toBeNull(); expect( selectEventNativeActiveRunId( snapshot({ runs: [run('past', 'running')], nodes: [canonicalNode('past')], }), null ) ).toBeNull(); }); it('fails closed for truncated, resyncing, overflowed, and gapped state', () => { const pending = run('input', 'waiting_for_user'); const controls = [request('question-1', 'input')]; expect( selectEventNativeActiveRunId( snapshot({ runs: [pending], controls, eventsTruncated: true }), null ) ).toBeNull(); expect( selectEventNativeActiveRunId( snapshot({ runs: [pending], controls, needsResync: true }), null ) ).toBeNull(); expect( selectEventNativeActiveRunId( snapshot({ runs: [pending], controls, overflowed: true }), null ) ).toBeNull(); expect( selectEventNativeActiveRunId( snapshot({ runs: [run('input', 'waiting_for_user', { lastSequence: 1 })], controls, }), null ) ).toBeNull(); }); it('does not treat a canonical-envelope legacy ASK as typed authority', () => { const state = snapshot({ runs: [run('input', 'waiting_for_user')], controls: [request('question-1', 'input', 'legacy.step')], }); expect(selectEventNativeActiveRunId(state, null)).toBeNull(); }); it('allows only evidenced, actionable local interruptions', () => { const local = run('local', 'interrupted'); const blocked = run('blocked', 'interrupted', { resumeBlockedReason: 'local_workspace_missing', }); const state = snapshot({ runs: [local, blocked], nodes: [ canonicalNode(local.runId, 'run.interrupted'), canonicalNode(blocked.runId, 'run.interrupted'), ], }); expect(selectActionableInterruptedRun(state, local.runId)).toBe(local); expect(selectActionableInterruptedRun(state, blocked.runId)).toBeNull(); }); });