Important Fixes, New mechanics, and many more
Some checks failed
CI / validate (push) Failing after 9m21s

This commit is contained in:
2026-08-15 17:37:57 +05:00
parent 1774496cf9
commit 438e5af0ad
56 changed files with 5090 additions and 119 deletions

View File

@@ -1,4 +1,4 @@
import { RoundPlanSchema, RoundResolutionSchema, WorldStarterSchema, moderate13Plus, type Character, type PlayerIntent, type RoundPlan, type RoundResolution, type WorldStarter } from '@dng/shared'
import { RoundPlanSchema, RoundResolutionSchema, StorySummarySchema, WorldStarterSchema, moderate13Plus, type RoundContext, type RoundPlan, type RoundResolution, type StorySummary, type WorldStarter } from '@dng/shared'
import type { DiceRoll } from '@dng/shared'
type JsonSchema = Record<string, unknown>
@@ -96,18 +96,27 @@ export async function generateWorld(messages: Array<{ role: 'user' | 'assistant'
return world
}
export async function planRound(input: { scene: string; intents: PlayerIntent[]; characters: Character[]; memories: string[] }): Promise<RoundPlan> {
export async function planRound(input: RoundContext): Promise<RoundPlan> {
return structuredRequest('round_plan', RoundPlanSchema.toJSONSchema(), [
{ role: 'system', content: 'You plan one asynchronous TTRPG round. You may request checks and propose story events. Never invent dice results and never directly mutate mechanical state. The server owns rules, HP, inventory, statuses and randomness.' },
{ role: 'system', content: 'You plan one asynchronous TTRPG round. Human intents are authoritative and happen first. Then provide at most one action for each supplied aiCharacter, in the supplied order; never create AI actions for human-controlled characters. You may request checks and propose story events. Never invent dice results and never directly mutate mechanical state. The server owns rules, HP, inventory, statuses and randomness.' },
{ role: 'user', content: JSON.stringify(input) },
], value => RoundPlanSchema.parse(value))
}
export async function narrateRound(input: { scene: string; intents: PlayerIntent[]; aiActions: RoundPlan['aiActions']; rolls: DiceRoll[]; permittedEvents: RoundPlan['proposedEvents'] }): Promise<RoundResolution> {
export async function narrateRound(input: { context: RoundContext; actionSequence: Array<{ phase: 'human' | 'ai'; characterId: string; action: string }>; rolls: DiceRoll[]; permittedEvents: RoundPlan['proposedEvents'] }): Promise<RoundResolution> {
const resolution = await structuredRequest('round_resolution', RoundResolutionSchema.toJSONSchema(), [
{ role: 'system', content: 'Narrate the resolved TTRPG round using the supplied, authoritative dice results. Do not change them. Keep player agency, maintain a 13+ rating, and end with a clear prompt for the next round.' },
{ role: 'system', content: 'Narrate the resolved TTRPG round in the exact supplied actionSequence order: all human actions first, then AI/delegated hero actions. Use the authoritative dice results without changing them. Keep player agency, maintain a 13+ rating, and end with a clear prompt for the next round.' },
{ role: 'user', content: JSON.stringify(input) },
], value => RoundResolutionSchema.parse(value))
assert13Plus(resolution.narration, resolution.nextPrompt, resolution.memory?.summary ?? '')
return resolution
}
export async function summarizeStory(input: { previousSummary: string | null; rounds: Array<{ number: number; narration: string }> }): Promise<StorySummary> {
const result = await structuredRequest('story_summary', StorySummarySchema.toJSONSchema(), [
{ role: 'system', content: 'Update a durable TTRPG campaign summary. Preserve established facts, goals, relationships and unresolved consequences. Use only the supplied previous summary and round narrations. Be concise and do not invent details.' },
{ role: 'user', content: JSON.stringify(input) },
], value => StorySummarySchema.parse(value))
assert13Plus(result.summary)
return result
}