feat(vibe): adapt sessions to context and exploration
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
import { DbService, VibeEvent, VibePlan, VibeSession } from './db.service.js';
|
||||
import { SessionDirector } from './session-director.service.js';
|
||||
import { Candidate } from './generators.service.js';
|
||||
import {
|
||||
initialVibeState,
|
||||
normalizeVibeContext,
|
||||
normalizeVibeEventPayload,
|
||||
VibeContext,
|
||||
} from './vibe-context.service.js';
|
||||
|
||||
/**
|
||||
* This is deliberately a narrow bridge between the durable Vibe ledger and
|
||||
@@ -21,7 +27,7 @@ export type VibeEventType = (typeof VIBE_EVENT_TYPES)[number];
|
||||
|
||||
export interface StartVibeSessionInput {
|
||||
seedTrackId?: string;
|
||||
context?: Record<string, unknown>;
|
||||
context?: VibeContext | Record<string, unknown>;
|
||||
intent?: string;
|
||||
policyVersion?: string;
|
||||
resumeSessionId?: string;
|
||||
@@ -73,13 +79,19 @@ export class VibeSessionCoordinator {
|
||||
|
||||
async start(userId: string, input: StartVibeSessionInput): Promise<VibeSessionResponse> {
|
||||
if (input.resumeSessionId) return this.resume(userId, input.resumeSessionId);
|
||||
const context = input.context ?? {};
|
||||
const context = normalizeVibeContext({ ...(input.context ?? {}) });
|
||||
const initialState = initialVibeState(context);
|
||||
const policyVersion = input.policyVersion ?? DEFAULT_VIBE_POLICY_VERSION;
|
||||
const session = await this.db.createVibeSession({
|
||||
userId,
|
||||
policyVersion,
|
||||
seedTrackId: input.seedTrackId ?? null,
|
||||
context,
|
||||
context: { ...context },
|
||||
profile: {
|
||||
goals: initialState.sessionGoal,
|
||||
explorationCoefficient: initialState.explorationCoefficient,
|
||||
discoveryRadius: initialState.discoveryRadius,
|
||||
},
|
||||
});
|
||||
|
||||
// session_state is a derived cache used by the current director. Give it
|
||||
@@ -87,8 +99,15 @@ export class VibeSessionCoordinator {
|
||||
// session while the durable tables remain the source of truth.
|
||||
await this.db.createSessionState(
|
||||
userId,
|
||||
typeof context.activity === 'string' ? context.activity : input.intent,
|
||||
{ energy: 0.5, noveltyHunger: 0.3 },
|
||||
initialState.contextLabel ?? input.intent,
|
||||
{
|
||||
energy: initialState.energy,
|
||||
noveltyHunger: initialState.noveltyHunger,
|
||||
explorationCoefficient: initialState.explorationCoefficient,
|
||||
discoveryRadius: initialState.discoveryRadius,
|
||||
sessionGoal: initialState.sessionGoal,
|
||||
context,
|
||||
},
|
||||
session.id,
|
||||
);
|
||||
await this.db.recordVibeEvent({
|
||||
@@ -180,6 +199,11 @@ export class VibeSessionCoordinator {
|
||||
input: AppendVibeEventInput,
|
||||
): Promise<VibeSessionResponse & { event: VibeEvent; idempotent: boolean }> {
|
||||
try {
|
||||
// Do this before the ledger write, rather than after it, because Vibe
|
||||
// events are immutable. The DB repeats this boundary for non-HTTP
|
||||
// callers; keeping it here also makes coordinator callers see exactly
|
||||
// what will be persisted.
|
||||
const payload = normalizeVibeEventPayload(input.type, input.payload);
|
||||
const result = await this.db.recordVibeEvent({
|
||||
sessionId,
|
||||
userId,
|
||||
@@ -189,8 +213,13 @@ export class VibeSessionCoordinator {
|
||||
occurredAt: input.occurredAt,
|
||||
positionMs: input.positionMs,
|
||||
durationMs: input.durationMs,
|
||||
payload: input.payload,
|
||||
payload,
|
||||
});
|
||||
// The ledger write is authoritative; this idempotent projection updates
|
||||
// exploration only after the exact event exists. Keep the compatibility
|
||||
// guard for old coordinator test doubles during the migration.
|
||||
const projectSessionFeedback = (this.db as Partial<DbService>).projectVibeSessionFeedback;
|
||||
if (projectSessionFeedback) await projectSessionFeedback.call(this.db, result.event);
|
||||
if (!isMaterialFeedback(input.type)) {
|
||||
const response = await this.getPlan(userId, sessionId);
|
||||
return { ...response, event: result.event, idempotent: !result.inserted };
|
||||
|
||||
Reference in New Issue
Block a user