1
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
import type {
|
||||
CustomWorldAssetCoverageSummary,
|
||||
CreatorIntentReadiness,
|
||||
CustomWorldAgentMessage,
|
||||
CustomWorldAgentOperationRecord,
|
||||
CustomWorldAgentSessionSnapshot,
|
||||
CustomWorldAgentStage,
|
||||
CustomWorldAssetCoverageSummary,
|
||||
CustomWorldDraftCardSummary,
|
||||
CustomWorldPendingClarification,
|
||||
CustomWorldSuggestedAction,
|
||||
EightAnchorContent,
|
||||
} from '../../../packages/shared/src/contracts/customWorldAgent.js';
|
||||
import type { CustomWorldSessionRecord as LegacyCustomWorldSessionRecord } from '../../../packages/shared/src/contracts/runtime.js';
|
||||
import type { RuntimeRepositoryPort } from '../repositories/runtimeRepository.js';
|
||||
@@ -19,15 +20,19 @@ import {
|
||||
resolveCreatorIntentStage,
|
||||
} from './customWorldAgentClarificationService.js';
|
||||
import {
|
||||
buildAnchorPackFromIntent,
|
||||
buildDraftSummaryFromIntent,
|
||||
buildDraftTitleFromIntent,
|
||||
createEmptyCreatorIntentRecord,
|
||||
extractCreatorIntentPatch,
|
||||
mergeCreatorIntentRecord,
|
||||
normalizeCreatorIntentRecord,
|
||||
} from './customWorldAgentIntentExtractionService.js';
|
||||
import { rebuildRoleAssetCoverage } from './customWorldAgentRoleAssetStateService.js';
|
||||
import {
|
||||
buildAnchorPackFromEightAnchorContent,
|
||||
buildCreatorIntentFromEightAnchorContent,
|
||||
buildDraftSummaryFromEightAnchorContent,
|
||||
buildDraftTitleFromEightAnchorContent,
|
||||
buildEightAnchorContentFromCreatorIntent,
|
||||
createEmptyEightAnchorContent,
|
||||
estimateProgressPercentFromAnchorContent,
|
||||
normalizeEightAnchorContent,
|
||||
} from './eightAnchorCompatibilityService.js';
|
||||
|
||||
export const CUSTOM_WORLD_AGENT_SESSION_ID_PREFIX =
|
||||
'custom-world-agent-session-';
|
||||
@@ -36,6 +41,10 @@ export type CustomWorldAgentSessionRecord = {
|
||||
sessionId: string;
|
||||
userId: string;
|
||||
seedText: string;
|
||||
currentTurn: number;
|
||||
anchorContent: EightAnchorContent;
|
||||
progressPercent: number;
|
||||
lastAssistantReply: string | null;
|
||||
stage: CustomWorldAgentStage;
|
||||
focusCardId: string | null;
|
||||
creatorIntent: Record<string, unknown> | null;
|
||||
@@ -69,6 +78,10 @@ export type CustomWorldAgentSessionRecord = {
|
||||
type CreateSessionInput = {
|
||||
seedText?: string;
|
||||
welcomeMessage: string;
|
||||
currentTurn?: number;
|
||||
anchorContent?: EightAnchorContent;
|
||||
progressPercent?: number;
|
||||
lastAssistantReply?: string | null;
|
||||
pendingClarifications: CustomWorldAgentSessionRecord['pendingClarifications'];
|
||||
creatorIntent?: CustomWorldAgentSessionRecord['creatorIntent'];
|
||||
creatorIntentReadiness?: CreatorIntentReadiness;
|
||||
@@ -169,20 +182,95 @@ function hasUserInput(record: CustomWorldAgentSessionRecord) {
|
||||
}
|
||||
|
||||
function buildCompatibleCreatorIntent(record: CustomWorldAgentSessionRecord) {
|
||||
const existingIntent =
|
||||
normalizeCreatorIntentRecord(record.creatorIntent) ??
|
||||
createEmptyCreatorIntentRecord('freeform');
|
||||
const compatibleAnchorIntent = buildCreatorIntentFromEightAnchorContent(
|
||||
normalizeEightAnchorContent(
|
||||
(record as Record<string, unknown>).anchorContent ?? null,
|
||||
),
|
||||
);
|
||||
|
||||
if (!record.seedText.trim()) {
|
||||
return existingIntent;
|
||||
if (
|
||||
compatibleAnchorIntent &&
|
||||
(compatibleAnchorIntent.worldHook ||
|
||||
compatibleAnchorIntent.rawSettingText ||
|
||||
compatibleAnchorIntent.playerPremise ||
|
||||
compatibleAnchorIntent.openingSituation ||
|
||||
compatibleAnchorIntent.coreConflicts.length > 0 ||
|
||||
compatibleAnchorIntent.keyCharacters.length > 0 ||
|
||||
compatibleAnchorIntent.iconicElements.length > 0)
|
||||
) {
|
||||
return compatibleAnchorIntent;
|
||||
}
|
||||
|
||||
const seedPatch = extractCreatorIntentPatch({
|
||||
currentIntent: existingIntent,
|
||||
latestUserMessage: record.seedText,
|
||||
});
|
||||
return normalizeCreatorIntentRecord(record.creatorIntent);
|
||||
}
|
||||
|
||||
return mergeCreatorIntentRecord(existingIntent, seedPatch);
|
||||
function buildCompatibleCurrentTurn(record: CustomWorldAgentSessionRecord) {
|
||||
if (typeof (record as Record<string, unknown>).currentTurn === 'number') {
|
||||
return Math.max(
|
||||
0,
|
||||
Math.round((record as Record<string, unknown>).currentTurn as number),
|
||||
);
|
||||
}
|
||||
|
||||
return record.messages.filter((message) => message.role === 'user').length;
|
||||
}
|
||||
|
||||
function buildCompatibleAnchorContent(record: CustomWorldAgentSessionRecord) {
|
||||
const normalized = normalizeEightAnchorContent(
|
||||
(record as Record<string, unknown>).anchorContent ?? null,
|
||||
);
|
||||
|
||||
if (
|
||||
normalized.worldPromise ||
|
||||
normalized.playerFantasy ||
|
||||
normalized.themeBoundary ||
|
||||
normalized.playerEntryPoint ||
|
||||
normalized.coreConflict ||
|
||||
normalized.keyRelationships.length > 0 ||
|
||||
normalized.hiddenLines ||
|
||||
normalized.iconicElements
|
||||
) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
return buildEightAnchorContentFromCreatorIntent(
|
||||
buildCompatibleCreatorIntent(record),
|
||||
);
|
||||
}
|
||||
|
||||
function buildCompatibleProgressPercent(record: CustomWorldAgentSessionRecord) {
|
||||
const rawProgress = (record as Record<string, unknown>).progressPercent;
|
||||
if (typeof rawProgress === 'number' && Number.isFinite(rawProgress)) {
|
||||
return Math.max(0, Math.min(100, Math.round(rawProgress)));
|
||||
}
|
||||
|
||||
if (
|
||||
record.stage === 'foundation_review' ||
|
||||
record.stage === 'object_refining' ||
|
||||
record.stage === 'visual_refining' ||
|
||||
record.stage === 'long_tail_review' ||
|
||||
record.stage === 'ready_to_publish' ||
|
||||
record.stage === 'published'
|
||||
) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
return estimateProgressPercentFromAnchorContent(
|
||||
buildCompatibleAnchorContent(record),
|
||||
);
|
||||
}
|
||||
|
||||
function buildCompatibleLastAssistantReply(record: CustomWorldAgentSessionRecord) {
|
||||
const existingReply = (record as Record<string, unknown>).lastAssistantReply;
|
||||
if (typeof existingReply === 'string') {
|
||||
return existingReply;
|
||||
}
|
||||
|
||||
const lastAssistantMessage = [...record.messages]
|
||||
.reverse()
|
||||
.find((message) => message.role === 'assistant' && message.text.trim());
|
||||
|
||||
return lastAssistantMessage?.text ?? null;
|
||||
}
|
||||
|
||||
function buildCompatibleReadiness(record: CustomWorldAgentSessionRecord) {
|
||||
@@ -239,8 +327,8 @@ function buildCompatiblePendingClarifications(
|
||||
|
||||
function buildCompatibleDraftProfile(
|
||||
record: CustomWorldAgentSessionRecord,
|
||||
creatorIntent: ReturnType<typeof buildCompatibleCreatorIntent>,
|
||||
) {
|
||||
const anchorContent = buildCompatibleAnchorContent(record);
|
||||
const existingDraftProfile = toRecord(record.draftProfile);
|
||||
const hasFoundationContent = Boolean(
|
||||
existingDraftProfile &&
|
||||
@@ -258,20 +346,21 @@ function buildCompatibleDraftProfile(
|
||||
name:
|
||||
toText(existingDraftProfile?.name) ||
|
||||
toText(existingDraftProfile?.title) ||
|
||||
buildDraftTitleFromIntent(creatorIntent),
|
||||
buildDraftTitleFromEightAnchorContent(anchorContent),
|
||||
summary:
|
||||
toText(existingDraftProfile?.summary) ||
|
||||
buildDraftSummaryFromIntent(creatorIntent),
|
||||
buildDraftSummaryFromEightAnchorContent(anchorContent),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...(existingDraftProfile ?? {}),
|
||||
title:
|
||||
toText(existingDraftProfile?.title) || buildDraftTitleFromIntent(creatorIntent),
|
||||
toText(existingDraftProfile?.title) ||
|
||||
buildDraftTitleFromEightAnchorContent(anchorContent),
|
||||
summary:
|
||||
toText(existingDraftProfile?.summary) ||
|
||||
buildDraftSummaryFromIntent(creatorIntent),
|
||||
buildDraftSummaryFromEightAnchorContent(anchorContent),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -381,35 +470,58 @@ function buildCompatibleAssetCoverage(
|
||||
|
||||
function applyCompatibility(record: CustomWorldAgentSessionRecord) {
|
||||
const creatorIntent = buildCompatibleCreatorIntent(record);
|
||||
const creatorIntentReadiness = evaluateCreatorIntentReadiness(creatorIntent);
|
||||
const currentTurn = buildCompatibleCurrentTurn(record);
|
||||
const anchorContent = buildCompatibleAnchorContent(record);
|
||||
const progressPercent = buildCompatibleProgressPercent(record);
|
||||
const lastAssistantReply = buildCompatibleLastAssistantReply(record);
|
||||
const creatorIntentReadiness =
|
||||
progressPercent >= 100
|
||||
? {
|
||||
isReady: true,
|
||||
completedKeys: [
|
||||
'world_hook',
|
||||
'player_premise',
|
||||
'theme_and_tone',
|
||||
'core_conflict',
|
||||
'relationship_seed',
|
||||
'iconic_element',
|
||||
],
|
||||
missingKeys: [],
|
||||
}
|
||||
: evaluateCreatorIntentReadiness(creatorIntent);
|
||||
const stage =
|
||||
record.stage === 'collecting_intent' ||
|
||||
record.stage === 'clarifying' ||
|
||||
record.stage === 'foundation_review'
|
||||
? resolveCreatorIntentStage({
|
||||
hasUserInput: hasUserInput(record),
|
||||
readiness: creatorIntentReadiness,
|
||||
})
|
||||
: record.stage;
|
||||
record.stage === 'object_refining' ||
|
||||
record.stage === 'visual_refining' ||
|
||||
record.stage === 'long_tail_review' ||
|
||||
record.stage === 'ready_to_publish' ||
|
||||
record.stage === 'published'
|
||||
? record.stage
|
||||
: progressPercent >= 100
|
||||
? ('foundation_review' as const)
|
||||
: resolveCreatorIntentStage({
|
||||
hasUserInput: hasUserInput(record),
|
||||
readiness: creatorIntentReadiness,
|
||||
});
|
||||
const pendingClarifications = buildCompatiblePendingClarifications({
|
||||
...record,
|
||||
creatorIntent,
|
||||
creatorIntentReadiness,
|
||||
});
|
||||
const draftProfile = buildCompatibleDraftProfile(record, creatorIntent);
|
||||
const draftProfile = buildCompatibleDraftProfile(record);
|
||||
|
||||
return {
|
||||
...record,
|
||||
currentTurn,
|
||||
anchorContent,
|
||||
progressPercent,
|
||||
lastAssistantReply,
|
||||
stage,
|
||||
creatorIntent,
|
||||
creatorIntentReadiness,
|
||||
anchorPack:
|
||||
record.anchorPack && Object.keys(record.anchorPack).length > 0
|
||||
? record.anchorPack
|
||||
: buildAnchorPackFromIntent(creatorIntent, {
|
||||
completedKeys: creatorIntentReadiness.completedKeys,
|
||||
missingKeys: creatorIntentReadiness.missingKeys,
|
||||
}),
|
||||
: buildAnchorPackFromEightAnchorContent(anchorContent, progressPercent),
|
||||
draftProfile,
|
||||
pendingClarifications,
|
||||
suggestedActions: buildCompatibleSuggestedActions({
|
||||
@@ -430,6 +542,10 @@ function toSnapshot(
|
||||
): CustomWorldAgentSessionSnapshot {
|
||||
return {
|
||||
sessionId: record.sessionId,
|
||||
currentTurn: record.currentTurn,
|
||||
anchorContent: cloneRecord(record.anchorContent),
|
||||
progressPercent: record.progressPercent,
|
||||
lastAssistantReply: record.lastAssistantReply,
|
||||
stage: record.stage,
|
||||
focusCardId: record.focusCardId,
|
||||
creatorIntent: cloneRecord(record.creatorIntent),
|
||||
@@ -491,6 +607,15 @@ export class CustomWorldAgentSessionStore {
|
||||
sessionId,
|
||||
userId,
|
||||
seedText: input.seedText?.trim() ?? '',
|
||||
currentTurn: Math.max(0, Math.round(input.currentTurn ?? 0)),
|
||||
anchorContent: normalizeEightAnchorContent(
|
||||
input.anchorContent ?? createEmptyEightAnchorContent(),
|
||||
),
|
||||
progressPercent: Math.max(
|
||||
0,
|
||||
Math.min(100, Math.round(input.progressPercent ?? 0)),
|
||||
),
|
||||
lastAssistantReply: input.lastAssistantReply ?? input.welcomeMessage,
|
||||
stage: input.stage ?? 'collecting_intent',
|
||||
focusCardId: null,
|
||||
creatorIntent: cloneRecord(input.creatorIntent ?? {}),
|
||||
@@ -567,6 +692,10 @@ export class CustomWorldAgentSessionStore {
|
||||
patch: Partial<
|
||||
Pick<
|
||||
CustomWorldAgentSessionRecord,
|
||||
| 'currentTurn'
|
||||
| 'anchorContent'
|
||||
| 'progressPercent'
|
||||
| 'lastAssistantReply'
|
||||
| 'stage'
|
||||
| 'creatorIntent'
|
||||
| 'creatorIntentReadiness'
|
||||
@@ -584,6 +713,21 @@ export class CustomWorldAgentSessionStore {
|
||||
>,
|
||||
) {
|
||||
return this.mutate(userId, sessionId, (record) => {
|
||||
if (typeof patch.currentTurn === 'number') {
|
||||
record.currentTurn = Math.max(0, Math.round(patch.currentTurn));
|
||||
}
|
||||
if (patch.anchorContent !== undefined) {
|
||||
record.anchorContent = normalizeEightAnchorContent(patch.anchorContent);
|
||||
}
|
||||
if (typeof patch.progressPercent === 'number') {
|
||||
record.progressPercent = Math.max(
|
||||
0,
|
||||
Math.min(100, Math.round(patch.progressPercent)),
|
||||
);
|
||||
}
|
||||
if (patch.lastAssistantReply !== undefined) {
|
||||
record.lastAssistantReply = patch.lastAssistantReply;
|
||||
}
|
||||
if (patch.stage) {
|
||||
record.stage = patch.stage;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user