Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/fast-canonical-session-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@roomote/cloud-agents': patch
'@roomote/sdk': patch
'@roomote/types': patch
'@roomote/db': patch
'@roomote/web': patch
---

Sessions no longer announce an outdated status as current. Every model-relevant input, including events the transcript hides, is recorded in one ordered per-Session log with the time it was observed and the order it was admitted. Before each turn, a deterministic reducer decides which state facts are still current, which stay as history, and which are obsolete, using authoritative versions where a source provides them; a queued update that a newer version has already replaced no longer runs. Conversations also rebuild from that same log after a restart, so a resumed Session and a continuing one describe the same state.
6 changes: 6 additions & 0 deletions apps/web/src/trpc/commands/setup/setup-session.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 34 additions & 3 deletions apps/web/src/trpc/commands/setup/setup-session.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { createHash } from 'node:crypto';

import { buildFastAgentArtifactCreator } from '@roomote/sdk/server';
import {
buildFastAgentArtifactCreator,
enqueueFastAgentParentEvent,
} from '@roomote/sdk/server';
import { buildFastAgentSetupAdapter } from '@roomote/cloud-agents/server';
import {
and,
Expand Down Expand Up @@ -465,10 +468,38 @@ export async function scheduleSetupPlatformEvent(
): Promise<{ scheduled: boolean }> {
const turn = await buildSetupPlatformEventTurn(auth, input);
if (!turn) return { scheduled: false };
scheduleWebFastAgentTurn(turn);
await enqueueDurableWebPlatformEventTurn(turn);
return { scheduled: true };
}

async function enqueueDurableWebPlatformEventTurn(
turn: Parameters<typeof scheduleWebFastAgentTurn>[0],
): Promise<void> {
if (!turn.durableSessionId || !turn.setupContext || !turn.currentMessageId) {
throw new Error('A setup platform event requires durable turn context.');
}
await enqueueFastAgentParentEvent({
parent: {
sessionId: turn.durableSessionId,
conversation: turn.delivery.conversation,
},
event: {
type: 'human_follow_up',
eventId: turn.currentMessageId,
currentMessageId: turn.currentMessageId,
userId: turn.userId,
question: turn.question,
turnSource: 'platform_event',
platformEventKind: turn.platformEventKind ?? 'setup',
...(turn.platformEventVisibility
? { platformEventVisibility: turn.platformEventVisibility }
: {}),
setupSession: true,
setupContext: turn.setupContext,
},
});
}

async function buildSetupPlatformEventTurn(
auth: UserAuthSuccess,
input: {
Expand Down Expand Up @@ -784,7 +815,7 @@ export async function reconcileSetupPlatformEvents(
},
{ conversation, setupSnapshot },
);
if (turn) scheduleWebFastAgentTurn(turn);
if (turn) await enqueueDurableWebPlatformEventTurn(turn);
return setupCompleted;
}

Expand Down
Loading
Loading