Prompt registry

Every LLM system prompt the SDK ships (webagent narrator, planner, InlineAgent, markdown-edit, translator, STT cleanup, Dwell classifier) is registered on a process-wide registry under stable IDs. Hosts override per-locale, append site-wide reminders, or list what's registered — one API for the whole prompt surface.

Why

Before v0.2.2, prompts lived inline in each subsystem module. A host that wanted "Japanese planner prompt" or "the InlineAgent should never touch tone" had to fork the module. The registry is the "one place" for all of it.

Access

Every DotDotDuck instance exposes dddk.prompts. It's the same singleton as the module-level promptRegistry export — either works, whichever fits your import style.

import { autoInstall, promptRegistry, PROMPT_IDS } from '@perhapxin/dddk';

const dddk = autoInstall();

// Idiomatic path — via the instance
dddk.prompts.list();

// Also available as the shared singleton
promptRegistry.list();

Registered IDs

Every ID in the shipped PROMPT_IDS enum has a default. Full list:

ID constant String value Owner subsystem
INLINE_EDIT 'inline-edit.system' InlineAgent — replaces a text fragment inside a longer body
MARKDOWN_EDIT 'markdown-edit.system' Markdown-doc edit tool (used by Plan runner)
VOICE_CLEANUP 'voice-cleanup.system' Voice STT cleanup — turns raw transcript into polished prose
TRANSLATE 'translate.system' Immersive-translate — inline machine translation of visible copy
DWELL_CLASSIFY 'dwell-classify.system' Dwell classifier — labels the long-pressed element + suggests actions
PLANNER 'planner.system' Planner — writes the CoT / task plan for the WebAgent
WEBAGENT_NARRATOR 'webagent-narrator.system' WebAgent narrator — the everything-prompt for the agentic loop
WEBAGENT_COT 'webagent-cot.system' WebAgent CoT variant — thinking-mode narrator
TASK 'task.system' Task runner — free-form task execution prompt

Enumerate at runtime with dddk.prompts.list().

Override a single locale

dddk.prompts.override('inline-edit.system', 'ja', () => `
あなたはインライン編集アシスタントです。ユーザーが長いテキストの中の断片を選択し、指示を出しました…
`);

Fallback order when the SDK resolves a prompt: override(id, currentLocale)override(id, 'en') → the SDK-registered default. So you can localise Japanese while leaving English and every other locale on the shipped default.

For prompts that consume runtime context (planner, webagent narrator, Dwell classifier), the override function receives the full context object:

dddk.prompts.override('webagent-narrator.system', 'ja', (ctx, locale) => {
  // ctx is the AssemblePromptInput — brand, persona, sitemap, session, etc.
  return japaneseNarratorRenderer(ctx);
});

Append site-wide reminders

append() stitches extra content on the end of the resolved prompt. It runs for every locale — useful for one-line rules that shouldn't require re-writing the whole prompt:

dddk.prompts.append('webagent-narrator.system', () => `
- Never mention pricing.
- Always cite sources.
- Refuse anything not related to Acme products.
`);

Multiple append() calls stack in registration order. Reset with dddk.prompts.reset(id) (drops overrides + appenders, keeps the SDK default).

Full API

class PromptRegistry {
  registerDefault<Ctx>(id: string, render: (ctx: Ctx, locale: string) => string): void;
  override<Ctx>(id: string, locale: string, render: (ctx: Ctx, locale: string) => string): void;
  append<Ctx>(id: string, extra: (ctx: Ctx, locale: string) => string): void;
  render<Ctx>(id: string, ctx?: Ctx, locale?: string): string;
  reset(id: string): void;
  has(id: string): boolean;
  list(): string[];
}
  • registerDefault — normally you don't call this; subsystems do it at module init. Hosts wanting to ship an entirely new prompt id (e.g. a domain-specific tool) can use it.
  • override(id, locale, render) — most common host operation. Later calls with the same (id, locale) win.
  • append(id, extra) — join extra content to whatever renderer wins. Stacks.
  • render(id, ctx?, locale?) — resolve to a final string. locale defaults to 'en'.
  • reset(id) — drop overrides + appenders for this id. SDK default stays.
  • has(id) — is anything registered for this id (default or override)?
  • list() — every registered id, sorted alphabetically.

Common patterns

Multi-locale rollout

const NARRATOR_JA = (ctx: AssemblePromptInput) => `...`;
const NARRATOR_ES = (ctx: AssemblePromptInput) => `...`;
const NARRATOR_FR = (ctx: AssemblePromptInput) => `...`;

dddk.prompts.override('webagent-narrator.system', 'ja', NARRATOR_JA);
dddk.prompts.override('webagent-narrator.system', 'es', NARRATOR_ES);
dddk.prompts.override('webagent-narrator.system', 'fr', NARRATOR_FR);
// EN + zh-TW stay on SDK defaults.

Compliance layer without touching the base prompt

const compliance = () => `
Compliance requirements:
- Never disclose user PII.
- Refuse requests to draft legal or medical opinions.
- If asked about pricing, respond: "Please contact sales@acme.com."
`;

// Apply the compliance rules to every LLM-facing prompt the SDK ships.
for (const id of dddk.prompts.list()) {
  dddk.prompts.append(id, compliance);
}

Live locale switch

The registry is read at message-assembly time, not at subsystem construction. Change the site language and the next agent turn / next InlineAgent action / next translation uses the new locale's prompt automatically — no re-mount, no reload.

document.querySelector('#lang-picker')?.addEventListener('change', (e) => {
  const locale = (e.target as HTMLSelectElement).value;
  dddk.setLocale(locale);
  // Next agent turn uses the ja / es / fr / zh-TW variant of every registered prompt.
});

Non-goals

The registry does not:

  • Parse or execute the prompt. Runtime message plumbing (system role, temperature, tool schemas) still lives in the subsystem callsites.
  • Cache resolved strings. Each render(id, ctx, locale) call runs the renderer fresh — cheap enough to re-run per turn.
  • Store credentials or LLM provider config. That's DotDotDuckConfig.llm / config.llm.provider.
  • auto-install.md — the one-line install that registers defaults for you.
  • migrating.md — how to adopt the registry from v0.2.1.
  • agent/ — where the WebAgent narrator + planner prompts live at the callsite.