Reorder shared D&D extraction prompt messages
This commit is contained in:
@@ -98,6 +98,18 @@ D&D prompt content. `internal/framework/promptfs` provides the domain-neutral
|
||||
filesystem composition helper used to combine module-owned files with shared
|
||||
domain prompt fragments.
|
||||
|
||||
The D&D spell, NPC, and combat-turn extractors each declare an ordered prompt
|
||||
asset manifest. The manifest lists the package-owned YAML and Markdown files,
|
||||
then the exact shared fragments rendered by that prompt; the same ordered list
|
||||
drives both filesystem mounting and the prompt fingerprint. Shared extraction
|
||||
evidence and in-world identity messages precede the cacheable transcript and
|
||||
campaign-reference messages. Spell and combat prompts then render immediate
|
||||
resolution and the cacheable NPC registry before their lane-specific material;
|
||||
the NPC prompt renders its task and instructions instead. The identity,
|
||||
transcript, and campaign-reference messages are ephemeral in all three prompts,
|
||||
and the NPC registry is ephemeral where it is used by spell and combat prompts.
|
||||
Unused shared assets are neither mounted nor fingerprinted.
|
||||
|
||||
Schema helpers load embedded JSON Schema with identity and digest metadata,
|
||||
return defensive copies, and expose a diagnostics map that omits schema bytes.
|
||||
The small framework registry contains only generic test schemas; production
|
||||
@@ -113,8 +125,8 @@ input and an optional `application/json` `npcs` input. The extractor generates
|
||||
the catalog input from its prepared
|
||||
effective catalog as `{"spell_names":[...]}` using sorted canonical names only.
|
||||
The shared D&D prompt assets include a generic NPC grounding fragment directly
|
||||
after the campaign reference message for both extractors. When an NPC registry
|
||||
is bound, the
|
||||
after the campaign reference message for spell and combat prompts. When an NPC
|
||||
registry is bound, the
|
||||
domain registry boundary strictly decodes and identity-validates one durable
|
||||
artifact, re-encodes canonical JSON, and generates a semantic digest over
|
||||
those bytes. The unbound input is exactly `{"npcs":[]}`. Input digests cover
|
||||
|
||||
@@ -47,9 +47,16 @@ LLM-backed extensions own their prompt definitions and response schemas under
|
||||
package-local embedded assets. Shared filesystem composition belongs in
|
||||
`internal/framework/promptfs`; reusable D&D prompt fragments, reference
|
||||
declarations, prompt-input assembly, and source-unit helpers belong in
|
||||
`internal/modules/dnd/shared`, which also owns bounded D&D diagnostics. Stage
|
||||
contracts expose only Notarius structured-
|
||||
completion types, not Scriptorium public types.
|
||||
`internal/modules/dnd/shared`, which also owns bounded D&D diagnostics. The
|
||||
spell, NPC, and combat-turn extractors use ordered package-local prompt
|
||||
manifests for both rendering and prompt fingerprinting, so only the shared
|
||||
fragments each prompt actually renders participate in either operation. Their
|
||||
common prompt order is system, extraction evidence, in-world identity,
|
||||
transcript, and campaign references, with ephemeral cache control on identity,
|
||||
transcript, and references. Spell and combat prompts append immediate
|
||||
resolution and an ephemeral NPC registry before lane-specific material; the
|
||||
NPC prompt appends its task and instructions. Stage contracts expose only
|
||||
Notarius structured-completion types, not Scriptorium public types.
|
||||
|
||||
Reference material may inform a module or prompt but must not become source
|
||||
evidence. The resolver and materializer behavior is described in
|
||||
@@ -182,15 +189,14 @@ source evidence.
|
||||
|
||||
The prompt limits each cast to its declaration and immediate resolution; it
|
||||
does not follow summoned creatures, persistent effects, or other downstream
|
||||
consequences through the scene. Source references must collectively support all
|
||||
reported facts, using separate narrow ranges when immediate evidence is
|
||||
non-contiguous. The prompt grounds caster names in in-world identities, using
|
||||
the player and party references to disambiguate transcript speakers without
|
||||
treating those references as event evidence. Effects describe the session as
|
||||
played: model rules knowledge cannot supplement or correct the transcript, and
|
||||
nonstandard adjudication is attributed to the GM or table rather than stated as
|
||||
a universal rule. Structural source validation remains deterministic; semantic
|
||||
claim completeness is enforced through extraction policy and evaluation.
|
||||
consequences through the scene. Shared extraction-evidence and identity rules
|
||||
require transcript-supported factual claims and the most specific in-world
|
||||
caster identity, while campaign references only disambiguate source text.
|
||||
Effects describe the session as played: model rules knowledge cannot supplement
|
||||
or correct the transcript, and nonstandard adjudication is attributed to the GM
|
||||
or table rather than stated as a universal rule. Structural source validation
|
||||
remains deterministic; semantic claim completeness is enforced through
|
||||
extraction policy and evaluation.
|
||||
|
||||
Both the extractor and deterministic catalog validator expose
|
||||
the effective base-plus-overlay semantic digest as scoped prepared-component
|
||||
@@ -223,12 +229,16 @@ The NPC extractor maps private model output to the canonical `dnd.NPCList`,
|
||||
assigns source identity and deterministic NPC IDs, and preserves source
|
||||
references for deterministic validation. It uses the shared campaign
|
||||
references only for disambiguation and does not consume the optional NPC
|
||||
registry slot. Its prompt and private response schema are package-owned.
|
||||
registry slot. Its prompt and private response schema are package-owned. The
|
||||
prompt uses the common evidence, identity, transcript, and campaign-reference
|
||||
messages, then the NPC-specific task and instructions; only the identity,
|
||||
transcript, and campaign-reference messages carry ephemeral cache control.
|
||||
|
||||
### `internal/modules/dnd/extract/combatturns`
|
||||
|
||||
The combat extractor prepares one structured request per supplied chunk using
|
||||
the shared transcript, campaign-reference, and NPC-grounding prompt inputs. It
|
||||
the shared extraction-evidence, identity, transcript, campaign-reference,
|
||||
immediate-resolution, and NPC-grounding prompt inputs. It
|
||||
maps the private response to `dnd.CombatTurnList`, assigns the current source
|
||||
identity, removes exact duplicate source ranges, and orders turns by valid
|
||||
source-document position while preserving malformed candidate fields for
|
||||
@@ -236,8 +246,11 @@ deterministic validators. Its package-owned private response schema enforces
|
||||
only the structural JSON envelope; semantic artifact constraints remain with
|
||||
the validator chain. Its prepared metadata and checkpoint fingerprints contain
|
||||
only prompt/schema/mapping identities plus an optional NPC registry digest.
|
||||
The package exposes typed registration and is included in the production D&D
|
||||
registrar with the default combat extraction chain.
|
||||
The prompt renders immediate resolution and the NPC registry before the
|
||||
combat-specific task and instructions; identity, transcript, campaign
|
||||
references, and the NPC registry use ephemeral cache control. The package
|
||||
exposes typed registration and is included in the production D&D registrar with
|
||||
the default combat extraction chain.
|
||||
|
||||
The combat normalizer accepts only the optional structured NPC registry.
|
||||
Campaign references remain extractor-only LLM context and are not materialized
|
||||
|
||||
@@ -20,6 +20,12 @@ inputs:
|
||||
messages:
|
||||
- role: system
|
||||
content_file: ./sharedassets/common-dnd-system.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-extraction-evidence.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-identity.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-transcript.md
|
||||
cache_control:
|
||||
@@ -28,8 +34,12 @@ messages:
|
||||
content_file: ./sharedassets/common-dnd-references.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-immediate-resolution.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-npcs.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./task.md
|
||||
- role: user
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
Return exactly one JSON object and no explanatory text.
|
||||
|
||||
Return the combat_turns array even when no combat turn is established. Return
|
||||
one or more actions for every turn. Use one of the supported turn_kind and
|
||||
action category values. Set round to null when the transcript does not state
|
||||
an explicit or unambiguous positive round number. Set resolution to null when
|
||||
the transcript establishes the declaration but not an immediate resolution.
|
||||
|
||||
Every source reference must contain start_unit_id and end_unit_id from the
|
||||
provided transcript. Do not add source_id; the extraction mapper assigns the
|
||||
current source identity. Do not include fields not defined by the response
|
||||
schema.
|
||||
action category values. Set round to null when the transcript does not state an
|
||||
explicit or unambiguous positive round number. Set resolution to null when the
|
||||
transcript establishes the declaration but not an immediate resolution.
|
||||
|
||||
@@ -5,26 +5,15 @@ participant takes a combat turn or performs a discrete interrupting combat
|
||||
event. Reactions, legendary actions, lair actions, and other out-of-turn events
|
||||
belong at the point where they occur in transcript chronology.
|
||||
|
||||
Report only the declaration and its immediate observed resolution. Immediate
|
||||
resolution may include directly associated rolls, damage, healing, movement,
|
||||
conditions, target outcomes, or an interruption. Do not follow consequences
|
||||
that occur on later turns or elsewhere in the scene.
|
||||
|
||||
Exclude initiative setup without a turn or combat event, tactical planning,
|
||||
table talk, rules lookup, hypothetical actions, abandoned declarations, recap
|
||||
of combat outside the current passage, and downstream consequences.
|
||||
|
||||
Use only the supplied transcript as evidence. Do not infer a round, target,
|
||||
roll, amount, condition, outcome, or action classification from D&D rules
|
||||
knowledge. Preserve the session as played; attribute relevant nonstandard
|
||||
rulings to the GM or table.
|
||||
Do not infer a round, target, roll, amount, condition, outcome, or action
|
||||
classification from D&D rules knowledge. Preserve the session as played;
|
||||
attribute relevant nonstandard rulings to the GM or table.
|
||||
|
||||
The actor must be the in-world character or creature, not a player, transcript
|
||||
speaker, or GM. Use player, party, glossary, and NPC reference material only
|
||||
to disambiguate identities. Reference material is context, never combat
|
||||
evidence. Unmatched actors and targets remain permitted.
|
||||
Unmatched actors and targets remain permitted.
|
||||
|
||||
For every factual detail in a turn, cite all supporting transcript units in the
|
||||
turn-level source_refs collection. Use narrow ranges when evidence is
|
||||
non-contiguous. Numeric source-unit IDs identify transcript units; they do not
|
||||
establish chronology outside the supplied transcript.
|
||||
turn-level source_refs collection.
|
||||
|
||||
@@ -20,8 +20,11 @@ var promptAssetManifest = shared.PromptAssetManifest{
|
||||
},
|
||||
SharedFiles: []string{
|
||||
"common-dnd-system.md",
|
||||
"common-dnd-extraction-evidence.md",
|
||||
"common-dnd-identity.md",
|
||||
"common-dnd-transcript.md",
|
||||
"common-dnd-references.md",
|
||||
"common-dnd-immediate-resolution.md",
|
||||
"common-dnd-npcs.md",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ inputs:
|
||||
messages:
|
||||
- role: system
|
||||
content_file: ./sharedassets/common-dnd-system.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-extraction-evidence.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-identity.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-transcript.md
|
||||
cache_control:
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
Return exactly one JSON object and no explanatory text.
|
||||
|
||||
For every NPC record, cite one or more transcript source-unit ranges that
|
||||
collectively support the canonical name, every alias, the description, and
|
||||
every relationship. Use integer start_unit_id and end_unit_id values from the
|
||||
transcript. Do not provide source_id; the extractor assigns it automatically.
|
||||
Use narrow ranges when evidence is not contiguous and do not bridge unrelated
|
||||
conversation with a broad range.
|
||||
|
||||
A canonical name must be the most specific in-world identity supported by the
|
||||
transcript. Never use a human player, transcript speaker, or GM name when an
|
||||
associated in-world character or creature is identified. Player, party, and
|
||||
glossary references may disambiguate identities, but they are not transcript
|
||||
evidence and cannot establish that an NPC appeared, acted, or was discussed.
|
||||
Do not return a person or entity mentioned only in those references.
|
||||
For every NPC record, cite transcript units that support the canonical name,
|
||||
every alias, the description, and every relationship.
|
||||
|
||||
Descriptions must be short session records, not biographies, statistics,
|
||||
alignment, motivations, or lore inferred from general D&D knowledge. Do not
|
||||
|
||||
@@ -5,12 +5,11 @@ Include an in-world non-PC participant when the transcript establishes that it
|
||||
appears, acts, speaks, or is materially discussed and gives it a proper name,
|
||||
a stable alias or title, or an individually useful distinguishing description.
|
||||
|
||||
Exclude human players, transcript speakers, the GM as an out-of-world person,
|
||||
Exclude human players, transcript speakers, and the GM as out-of-world people,
|
||||
player characters identified by the player or party references, incidental or
|
||||
hypothetical name drops, corrected transcription mistakes, characters mentioned
|
||||
only by reference material, indistinguishable crowds or groups, and temporary
|
||||
summoned creatures or spell effects without a persistent individual identity.
|
||||
|
||||
Return canonical in-world names rather than player names or transcript speaker
|
||||
names. Keep each description concise and limited to facts established by the
|
||||
Keep each description concise and limited to facts established by the
|
||||
transcript. Include only explicitly supported aliases and relationships.
|
||||
|
||||
@@ -20,6 +20,8 @@ var promptAssetManifest = shared.PromptAssetManifest{
|
||||
},
|
||||
SharedFiles: []string{
|
||||
"common-dnd-system.md",
|
||||
"common-dnd-extraction-evidence.md",
|
||||
"common-dnd-identity.md",
|
||||
"common-dnd-transcript.md",
|
||||
"common-dnd-references.md",
|
||||
},
|
||||
|
||||
@@ -23,6 +23,12 @@ inputs:
|
||||
messages:
|
||||
- role: system
|
||||
content_file: ./sharedassets/common-dnd-system.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-extraction-evidence.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-identity.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-transcript.md
|
||||
cache_control:
|
||||
@@ -31,8 +37,12 @@ messages:
|
||||
content_file: ./sharedassets/common-dnd-references.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-immediate-resolution.md
|
||||
- role: user
|
||||
content_file: ./sharedassets/common-dnd-npcs.md
|
||||
cache_control:
|
||||
type: ephemeral
|
||||
- role: user
|
||||
content_file: ./catalog.md
|
||||
- role: user
|
||||
|
||||
@@ -1,40 +1,29 @@
|
||||
Source references must use integer source-unit IDs from the transcript. Provide
|
||||
start_unit_id and end_unit_id for each source reference; the extractor assigns
|
||||
source_id automatically.
|
||||
For each spell cast, source references must collectively support the caster,
|
||||
spell, effect, and narrative_description. If a detail is not supported by the
|
||||
cited transcript units, omit that detail or describe only the supported attempt
|
||||
or declaration.
|
||||
|
||||
Report only the casting declaration or action and its immediate resolution.
|
||||
This may include an immediately resolved target, saving throw, damage, healing,
|
||||
condition, interruption, or outcome. Do not follow summoned creatures,
|
||||
persistent effects, or other downstream consequences through the rest of the
|
||||
scene.
|
||||
For spells, do not follow summoned creatures, persistent effects, or other
|
||||
downstream consequences through the rest of the scene.
|
||||
|
||||
For every detail you report, cite all supporting transcript units. The source
|
||||
references for an artifact must collectively support every factual claim in
|
||||
caster, spell, effect, and narrative_description. When immediate supporting
|
||||
evidence is non-contiguous, provide multiple narrow source references. Do not
|
||||
use one broad range merely to bridge unrelated table conversation. If a detail
|
||||
is not supported by the cited transcript units, omit that detail or describe
|
||||
only the supported attempt or declaration.
|
||||
Return only D&D spell-cast artifacts. For each spell cast, identify the
|
||||
in-world caster, spell name, effect, narrative description, and source
|
||||
references.
|
||||
|
||||
Return only D&D spell-cast artifacts. For each spell cast, identify the in-world
|
||||
caster, spell name, effect, narrative description, and source references.
|
||||
|
||||
The caster must be the canonical in-world character or creature, not the human
|
||||
player, transcript speaker, or GM. Use the player and party references together
|
||||
with transcript context to map first-person player speech to the associated
|
||||
player character and use the canonical character name from the references.
|
||||
Likewise, attribute a spell narrated by the GM to the in-world creature that
|
||||
casts it. Never return a player or GM name when the associated in-world caster
|
||||
can be identified. If the caster cannot be resolved, use only the most specific
|
||||
in-world identity supported by the transcript; do not invent a name.
|
||||
Use the player and party references together with transcript context to map
|
||||
first-person player speech to the associated player character and use the
|
||||
canonical character name from the references. Likewise, attribute a spell
|
||||
narrated by the GM to the in-world creature that casts it. If the caster cannot
|
||||
be resolved, use only the most specific in-world identity supported by the
|
||||
transcript; do not invent a name.
|
||||
|
||||
Use the canonical spell-name catalog to select spell names. Do not return a
|
||||
spell name absent from that catalog, even when it is suggested by general D&D
|
||||
knowledge or reference material.
|
||||
|
||||
Use player, party, and glossary reference material only to clarify source text;
|
||||
references are not source evidence for a spell cast. Do not return spells,
|
||||
casters, or effects that are mentioned only in reference material.
|
||||
Use player, party, and glossary reference material only to clarify source text.
|
||||
Do not return spells, casters, or effects that are mentioned only in reference
|
||||
material.
|
||||
|
||||
Effects and narrative descriptions are session records, not rules summaries.
|
||||
Report only mechanics, explanations, and outcomes established by the cited
|
||||
@@ -42,5 +31,3 @@ transcript units. Preserve the table's observed resolution without silently
|
||||
correcting it from general D&D knowledge. If the transcript gives a possibly
|
||||
nonstandard rationale, use wording such as "the GM rules" or "the table
|
||||
resolves" rather than asserting that rationale as a universal rule.
|
||||
|
||||
Return exactly one JSON object and no explanatory text.
|
||||
|
||||
@@ -21,8 +21,11 @@ var promptAssetManifest = shared.PromptAssetManifest{
|
||||
},
|
||||
SharedFiles: []string{
|
||||
"common-dnd-system.md",
|
||||
"common-dnd-extraction-evidence.md",
|
||||
"common-dnd-identity.md",
|
||||
"common-dnd-transcript.md",
|
||||
"common-dnd-references.md",
|
||||
"common-dnd-immediate-resolution.md",
|
||||
"common-dnd-npcs.md",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -46,9 +46,12 @@ func TestScriptoriumPromptPreparesWithMissingOptionalReferences(t *testing.T) {
|
||||
transcript := []byte(`{"id":"session-1","segments":[]}`)
|
||||
prepared := prepareSpellsPrompt(t, transcript, " ", " ", " ")
|
||||
|
||||
if !strings.Contains(prepared.Messages[2].Content, " ") {
|
||||
t.Fatalf("reference message did not include empty optional reference placeholders")
|
||||
for _, message := range prepared.Messages {
|
||||
if strings.Contains(message.Content, "Player list reference:") && strings.Contains(message.Content, "Party roster reference:") && strings.Contains(message.Content, "Glossary reference:") {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("reference message did not render empty optional reference placeholders")
|
||||
}
|
||||
|
||||
func TestScriptoriumPromptDiagnosticsOmitRawMaterials(t *testing.T) {
|
||||
|
||||
@@ -23,10 +23,13 @@ type PromptAssetManifest struct {
|
||||
}
|
||||
|
||||
var sharedPromptPaths = map[string]string{
|
||||
"common-dnd-system.md": "assets/prompts/common-dnd-system.md",
|
||||
"common-dnd-transcript.md": "assets/prompts/common-dnd-transcript.md",
|
||||
"common-dnd-references.md": "assets/prompts/common-dnd-references.md",
|
||||
"common-dnd-npcs.md": "assets/prompts/common-dnd-npcs.md",
|
||||
"common-dnd-system.md": "assets/prompts/common-dnd-system.md",
|
||||
"common-dnd-extraction-evidence.md": "assets/prompts/common-dnd-extraction-evidence.md",
|
||||
"common-dnd-identity.md": "assets/prompts/common-dnd-identity.md",
|
||||
"common-dnd-transcript.md": "assets/prompts/common-dnd-transcript.md",
|
||||
"common-dnd-references.md": "assets/prompts/common-dnd-references.md",
|
||||
"common-dnd-immediate-resolution.md": "assets/prompts/common-dnd-immediate-resolution.md",
|
||||
"common-dnd-npcs.md": "assets/prompts/common-dnd-npcs.md",
|
||||
}
|
||||
|
||||
func (manifest PromptAssetManifest) PromptFS(moduleFS fs.FS) (fs.FS, error) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Transcript units are the only evidence for extracted events and factual claims.
|
||||
Campaign and registry references may disambiguate names, aliases, speakers, or
|
||||
other identities, but they do not establish events, participation, effects, or
|
||||
source evidence.
|
||||
|
||||
Every reported factual claim must be supported by cited transcript units. Use
|
||||
integer `start_unit_id` and `end_unit_id` values from the transcript. Omit
|
||||
`source_id`; Notarius assigns the current source identity.
|
||||
|
||||
When supporting evidence is non-contiguous, use multiple narrow ranges rather
|
||||
than a broad range that bridges unrelated conversation.
|
||||
|
||||
Return exactly one JSON object and no explanatory text. Output only the
|
||||
configured JSON object and fields defined by its response schema.
|
||||
@@ -0,0 +1,7 @@
|
||||
Use the most specific supported in-world character or creature identity for
|
||||
each actor or participant. Do not identify a human player, transcript speaker,
|
||||
or the GM as an out-of-world person when an in-world identity is supported.
|
||||
|
||||
Player, party, glossary, campaign, and NPC registry references may disambiguate
|
||||
an identity, but a reference alone cannot establish that the identity
|
||||
participated in the transcript.
|
||||
@@ -0,0 +1,7 @@
|
||||
Report only a declaration or action and its immediate observed resolution.
|
||||
Immediate resolution may include directly associated rolls, damage, healing,
|
||||
movement, conditions, target outcomes, interruptions, or other outcomes shown
|
||||
with that declaration or action.
|
||||
|
||||
Do not follow consequences that occur on later turns or elsewhere in the
|
||||
scene.
|
||||
Reference in New Issue
Block a user