mirror of
https://github.com/BillyOutlast/mangaharness.git
synced 2026-10-12 02:26:25 +00:00
Tone registry closure + v0.1.0 docs: shared mood vocabulary, V3 architecture doc
Daylight/bright/warm/cold/nostalgic/oppressive now resolve through the single tone registry (domain/tones + tones/mood) shared by the Tones shelf and the Agent; unknown tone words stay nonfatal. ARCHITECTURE.md updated to the Agent V3 pipeline. Co-Authored-By: BotTony329 <[email protected]>
This commit is contained in:
+54
-8
@@ -3,23 +3,69 @@
|
||||
Layered, with static boundary tests (`manga-studio/src/services/architecture.test.ts`)
|
||||
that fail the suite if a layer is bypassed.
|
||||
|
||||
- `src/domain/` — document model, commands, validation. Pure, no IO.
|
||||
## Editor Core (agent-independent)
|
||||
|
||||
- `src/domain/` — document model, commands, validation, camera math, tones.
|
||||
Pure, no IO.
|
||||
- `src/editor/` — zustand store and command dispatch; the only mutation path.
|
||||
- `src/services/` — application services (generation, characters, scenery,
|
||||
language, interaction, localEdit). UI and the agent BOTH call these; neither
|
||||
touches provider adapters, `/api/*` internals, or storage directly.
|
||||
- `src/agent/` — planning side: grounding, subject, scene intent, sequence
|
||||
plan, tool schemas, plan validation, step policy.
|
||||
- `src/agent-v2/` — execution engine: `pipeline.ts` (UNDERSTAND → PLAN →
|
||||
RESOLVE → CALL → VALIDATE), `orchestrator.ts` (transaction + policy +
|
||||
summary), `process/*` (per-domain step execution), `validation/`.
|
||||
- `src/characters/`, `src/tones/`, `src/language/` — domain helpers shared by
|
||||
UI and services.
|
||||
|
||||
**Editor Core does not depend on the Agent.** The dependency only ever points
|
||||
inward: agent → services → domain.
|
||||
|
||||
## Manga Agent V3
|
||||
|
||||
Natural language in, a finished page region out — with the LLM as Creative
|
||||
Director and code as the only owner of state, identity and execution.
|
||||
|
||||
```
|
||||
User prompt
|
||||
→ Literal Lock (agent-v3/contract/literalLock — immutable evidence)
|
||||
→ Creative Director LLM (ONE call, server-side /api/agent/direct)
|
||||
→ Creative Task Map (zod contract; names only, never runtime IDs)
|
||||
→ Structural validation (normalize → single canonical schema; field-path errors)
|
||||
→ Semantic capability resolution
|
||||
routing/cameraSemantics creative camera words → editor camera enums
|
||||
routing/interactionSemantics creative interaction words → InteractionType
|
||||
routing/dialogueSemantics delivery words → BubbleType
|
||||
(unknown wording = fallback + warning, raw intent preserved; never fatal)
|
||||
→ Project resolution (agent-v3/resolution — names bound to real IDs or
|
||||
marked create; "existing but missing" = blocked)
|
||||
→ Executable plan (routing/capabilityRouter — agent-v2 tool steps,
|
||||
REUSE/TRANSFORM/GENERATE decided here)
|
||||
→ agent-v2 orchestrator (transaction, rollback, step policy, preserved assets)
|
||||
→ Services → Domain commands
|
||||
→ Deterministic verifier (agent-v3/verification — participants exist, actors
|
||||
placed, dialogue byte-exact, scope untouched)
|
||||
→ Commit
|
||||
```
|
||||
|
||||
- `src/agent-v3/` — contract / director / context / resolution / routing /
|
||||
verification / run (client orchestration).
|
||||
- `src/agent-v2/` — execution engine: `orchestrator.ts` (transaction + policy
|
||||
+ summary), `process/*` (per-domain step execution), `validation/`.
|
||||
- `src/agent/` — shared planning-side vocabulary (literal evidence, resolver,
|
||||
tool schemas, step policy) plus provider plumbing.
|
||||
|
||||
## Providers & storage
|
||||
|
||||
- `src/ai/` + `src/server/` — provider registry and credential/session
|
||||
handling, server-side only.
|
||||
handling, server-side only. BYOK: keys never leave the user's own setup.
|
||||
- `src/app/api/` — HTTP routes: generate, assets/edit, remove-background,
|
||||
agent, provider status.
|
||||
agent, agent/direct, provider status.
|
||||
- `src/storage/` — projects in IndexedDB; generated/edited images via
|
||||
objectStore (Vercel Blob when a token exists, local `.data/` otherwise).
|
||||
Nothing requires Vercel.
|
||||
|
||||
Invariants worth knowing:
|
||||
|
||||
- The agent's run either lands whole or rolls back; generated library assets
|
||||
survive by design (they were paid for) and are named in the run summary.
|
||||
- Local edits always create a NEW asset with provenance; originals never mutate.
|
||||
- One canonical Creative Director system prompt; one camera normalization
|
||||
boundary; one tone registry (`domain/tones.ts` + `tones/mood.ts`) shared by
|
||||
the Tones shelf and the Agent.
|
||||
|
||||
@@ -183,3 +183,36 @@ describe("every tool the runtime accepts is documented to the planner", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("creative tone vocabulary (V3 semantics)", () => {
|
||||
it("resolves the words a Creative Director actually emits", () => {
|
||||
expect(toneForMood("daylight")).toBeDefined();
|
||||
expect(toneForMood("bright")).toBeDefined();
|
||||
expect(toneForMood("gloomy")).toBeDefined();
|
||||
expect(toneForMood("romantic")).toBeDefined();
|
||||
expect(toneForMood("cold")).toBeDefined();
|
||||
expect(toneForMood("nostalgic")).toBeDefined();
|
||||
});
|
||||
|
||||
it("'daylight' maps to a light tone — the live failure is closed", () => {
|
||||
expect(toneForMood("daylight")?.id).toBe("gradient-light");
|
||||
});
|
||||
|
||||
it("manual UI and the Agent share one registry", async () => {
|
||||
const { tonePreset } = await import("@/domain/tones");
|
||||
// Every MOOD_MAP target must be a real preset on the Tones shelf.
|
||||
for (const mood of ["daylight", "bright", "gloomy", "romantic", "cold", "nostalgic", "warm", "oppressive"]) {
|
||||
const resolved = toneForMood(mood);
|
||||
expect(resolved, mood).toBeDefined();
|
||||
expect(tonePreset(resolved!.id), mood).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("an unknown creative tone word is nonfatal — skipped, run continues", async () => {
|
||||
studio();
|
||||
const summary = await run([{ tool: "apply_tone", args: { panel: 1, mood: "chartreuse melancholy" } }]);
|
||||
expect(summary.status).not.toBe("failed");
|
||||
expect(summary.rolledBack).toBe(false);
|
||||
expect(summary.skippedSteps.length + summary.failed).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,11 @@ const MOOD_MAP: { pattern: RegExp; presetId: string }[] = [
|
||||
{ pattern: /\b(dark|darkness|night|shadow|shadowy|black out|unconscious)\b/i, presetId: "darkness" },
|
||||
{ pattern: /\b(anxious|anxiety|panick\w*|panic|dread|fear\w*|afraid|scared|tense|unease\w*|nervous)\b/i, presetId: "anxiety-hatch" },
|
||||
{ pattern: /\b(romance|romantic|love|loving|shoujo|tender|dreamy|flowers?)\b/i, presetId: "gradient-light" },
|
||||
{ pattern: /\b(daylight|day\s?light|bright\w*|sunny|sunlight|sunshine|cheerful|morning|hopeful|happy)\b/i, presetId: "gradient-light" },
|
||||
{ pattern: /\b(warm|gentle|cozy|calm|peaceful)\b/i, presetId: "dot-20" },
|
||||
{ pattern: /\b(cold|lonely|solitary|isolated|empty|quiet|still)\b/i, presetId: "lines-vertical" },
|
||||
{ pattern: /\b(nostalg\w*|memory|memories|flashback|wistful|longing)\b/i, presetId: "dot-fine" },
|
||||
{ pattern: /\b(oppress\w*|claustrophobic|ominous|suffocat\w*|dramatic)\b/i, presetId: "gradient-dark" },
|
||||
{ pattern: /\b(speed|fast|rush\w*|motion|moving|dash\w*)\b/i, presetId: "speed-diagonal" },
|
||||
{ pattern: /\b(impact|hit|hitting|punch\w*|crash\w*|slam\w*|smash\w*|collid\w*)\b/i, presetId: "impact-dense" },
|
||||
{ pattern: /\b(grain|grainy|noise|noisy|rough|dirty|gritty|texture[d]?)\b/i, presetId: "noise-light" },
|
||||
|
||||
Reference in New Issue
Block a user