fix(transcript): populate the prompts entity from prompt.accepted/queued engine events

This commit is contained in:
qer 2026-08-20 13:53:21 +08:00
parent 609d849596
commit 4733e9e593
2 changed files with 44 additions and 1 deletions

View file

@ -26,6 +26,8 @@ import type {
PromptCompleted,
PromptSteered,
} from '@moonshot-ai/agent-core-v2/agent/prompt/promptService';
import type { PromptAccepted } from '@moonshot-ai/agent-core-v2/agent/prompt/promptOps';
import type { PromptQueued } from '@moonshot-ai/agent-core-v2/agent/prompt/promptService';
import type {
ShellCompleted,
ShellOutput,
@ -89,6 +91,8 @@ export interface ProjectorInteraction {
type PlanRevisionEvent = { readonly type: 'plan.revision' } & PlanRevision;
type AgentActivityUpdatedEvent = { readonly type: 'agent.activity.updated' } & AgentActivityUpdated;
type PromptAcceptedEvent = { readonly type: 'prompt.accepted' } & PromptAccepted;
type PromptQueuedEvent = { readonly type: 'prompt.queued' } & PromptQueued;
type PromptCompletedEvent = { readonly type: 'prompt.completed' } & PromptCompleted;
type PromptAbortedEvent = { readonly type: 'prompt.aborted' } & PromptAborted;
type PromptSteeredEvent = { readonly type: 'prompt.steered' } & PromptSteered;
@ -121,6 +125,8 @@ export type ProjectorBusEvent =
| ({ readonly type: 'goal.updated' } & GoalUpdated)
| ({ readonly type: 'agent.status.updated' } & AgentStatusUpdated)
| AgentActivityUpdatedEvent
| PromptAcceptedEvent
| PromptQueuedEvent
| PromptCompletedEvent
| PromptAbortedEvent
| PromptSteeredEvent
@ -313,6 +319,10 @@ export class AgentTranscriptProjector {
return this.onAgentStatusUpdated(event);
case 'agent.activity.updated':
return this.onAgentActivityUpdated(event);
case 'prompt.accepted':
return this.onPromptAccepted(event);
case 'prompt.queued':
return this.onPromptQueued(event);
case 'prompt.submitted':
return this.onPromptSubmitted(event);
case 'prompt.completed':
@ -1297,6 +1307,25 @@ export class AgentTranscriptProjector {
return this.markerOp('notice', { level, message, event: eventPayload });
}
private onPromptAccepted(event: PromptAcceptedEvent): TranscriptOperation[] {
const prompt = this.upsertPrompt(event.promptId, () => ({
promptId: event.promptId,
status: 'running',
createdAt: nowIso(),
}));
return [{ op: 'prompt.upsert', prompt }];
}
private onPromptQueued(event: PromptQueuedEvent): TranscriptOperation[] {
const prompt = this.upsertPrompt(event.promptId, () => ({
promptId: event.promptId,
status: 'queued',
content: event.content,
createdAt: nowIso(),
}));
return [{ op: 'prompt.upsert', prompt }];
}
private onPromptSubmitted(event: ProjectorPromptSubmittedEvent): TranscriptOperation[] {
const prompt = this.upsertPrompt(event.promptId, () => ({
promptId: event.promptId,

View file

@ -1984,11 +1984,25 @@ describe('AgentTranscriptProjector', () => {
expect(turnOps('t0', tx.getItems()).state).toBe('failed');
});
it('mirrors turn liveness into meta.activity', () => {
it('tracks the prompt queue from accepted/queued through terminal', () => {
const projector = new AgentTranscriptProjector('main');
const tx = new AgentTranscript('main');
const feed = (event: ProjectorBusEvent): void => void tx.apply(projector.map(event));
feed(ev({ type: 'prompt.accepted', promptId: 'p1' }));
expect(tx.getPrompt('p1')).toMatchObject({ status: 'running' });
feed(ev({ type: 'prompt.queued', promptId: 'p2', content: [{ type: 'text', text: 'later' }], queueLength: 1 }));
expect(tx.getPrompt('p2')).toMatchObject({ status: 'queued' });
feed(ev({ type: 'prompt.completed', promptId: 'p2', finishedAt: '2026-08-20T00:00:01.000Z', reason: 'completed' }));
expect(tx.getPrompt('p2')).toMatchObject({ status: 'completed' });
feed(ev({ type: 'prompt.aborted', promptId: 'p1', abortedAt: '2026-08-20T00:00:02.000Z' }));
expect(tx.getPrompt('p1')).toMatchObject({ status: 'aborted' });
});
it('mirrors turn liveness into meta.activity', () => { const projector = new AgentTranscriptProjector('main');
const tx = new AgentTranscript('main');
const feed = (event: ProjectorBusEvent): void => void tx.apply(projector.map(event));
expect(tx.getMeta().activity).toBeUndefined();
feed(ev({ type: 'turn.started', turnId: 1, origin: { kind: 'user' } }));
expect(tx.getMeta().activity).toBe('turn');