feat: refine UI, improve UX, optimize the analysis pipeline, and add character standing positions

This commit is contained in:
saturn
2026-04-02 17:39:16 +08:00
parent c3e74c228a
commit 9703714b69
153 changed files with 4472 additions and 1088 deletions

View File

@@ -0,0 +1,49 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
recoveryProbeTestUtils,
startRecoveryProbe,
} from '@/lib/query/hooks/run-stream/recovery-probe'
describe('recovery probe', () => {
afterEach(() => {
vi.useRealTimers()
recoveryProbeTestUtils.clearSuccessfulProbeScopes()
})
it('retries active run recovery when the first probe misses and a later probe finds a run', async () => {
vi.useFakeTimers()
const resolveActiveRunId = vi
.fn<({ projectId, storageScopeKey }: { projectId: string; storageScopeKey?: string }) => Promise<string | null>>()
.mockResolvedValueOnce(null)
.mockResolvedValueOnce('run-2')
const onRecovered = vi.fn()
const cleanup = startRecoveryProbe({
projectId: 'project-1',
storageKey: 'scope:story-to-script:episode-1',
storageScopeKey: 'episode-1',
hasRunState: () => false,
resolveActiveRunId,
onRecovered,
})
await vi.advanceTimersByTimeAsync(0)
expect(resolveActiveRunId).toHaveBeenCalledTimes(1)
expect(resolveActiveRunId).toHaveBeenLastCalledWith({
projectId: 'project-1',
storageScopeKey: 'episode-1',
})
expect(onRecovered).not.toHaveBeenCalled()
await vi.advanceTimersByTimeAsync(
recoveryProbeTestUtils.PROBE_RETRY_INTERVAL_MS,
)
expect(resolveActiveRunId).toHaveBeenCalledTimes(2)
expect(onRecovered).toHaveBeenCalledTimes(1)
expect(onRecovered).toHaveBeenCalledWith('run-2')
cleanup()
})
})

View File

@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'
import { TASK_TYPE } from '@/lib/task/types'
import { getTaskFlowMeta } from '@/lib/llm-observe/stage-pipeline'
import { normalizeTaskPayload } from '@/lib/task/submitter'
import { isActiveTaskStatus, normalizeTaskPayload, shouldAttachNewTaskToReusableRun } from '@/lib/task/submitter'
describe('task submitter helpers', () => {
it('fills default flow metadata when payload misses flow fields', () => {
@@ -56,4 +56,14 @@ describe('task submitter helpers', () => {
expect(meta.flowStageTotal).toBe(7)
expect(meta.flowStageTitle).toBe('Meta')
})
it('reuses linked runs only while the existing task is still active', () => {
expect(isActiveTaskStatus('queued')).toBe(true)
expect(isActiveTaskStatus('processing')).toBe(true)
expect(isActiveTaskStatus('completed')).toBe(false)
expect(shouldAttachNewTaskToReusableRun('queued')).toBe(false)
expect(shouldAttachNewTaskToReusableRun('processing')).toBe(false)
expect(shouldAttachNewTaskToReusableRun('failed')).toBe(true)
expect(shouldAttachNewTaskToReusableRun(null)).toBe(true)
})
})