feat(backend): generalized workbench endpoint + tool registry (#136) #218

Merged
claude-bot merged 1 commit from feat/136-workbench-endpoint-registry into feat/v3.10-gm-workbench 2026-07-19 15:24:23 +00:00
Contributor

Final foundation item of v3.10.0 GM Workbench. Targets the integration branch. Builds on #134 + #138.

Closes #136.

What

The single extension point for the Workbench — adding a tool = adding one ToolDef registry entry, never touching the endpoint.

  • generation_service.py: GENERATOR_TOOLS registry + ToolDef (input model, system prompt, context builders, prompt/parse callables, or a custom runner; sync_allowed/prefetchable/json_mode flags). run_tool generic executor (build declared context → prompt → llm_service.generate_structured_text → parse). Context builders campaign_context (folds in #137's system context), lore_context, threads_context, recent_sessions_context. Eager-loads game_system_ref + guards unloaded refs (sa_inspect().unloaded) against async lazy loads.
  • POST /api/campaigns/{campaign_id}/workbench/{tool_id}/generate (GM-only): 404 unknown tool → 422 bad params → 503 if LLM unconfigured; sync tools run inline (row written ready/failed), async tools enqueue run_workbench_generation and return pending (poll #138 history).
  • Names migrated as tool_id="names" — a custom runner delegating to audio_service.generate_name_options, so output (incl. #137 per-system hints) is byte-identical and existing name tests pass unmodified. Custom-prompt names no longer need an active session.
  • Old endpoints kept as thin wrappers into the registry (session name-options, planning names cache-miss).

Verification (Docker, py3.12)

  • 684 backend tests (+10 test_workbench_generation.py: sync/async dispatch, GM-only 403, 404/422, GenerationResult written + visible in history, session-less custom prompt); existing name-generation tests pass unmodified. ruff check/format clean. No migration; no bot API change.

Deferred (noted)

  • Full prefetch generalization is deferred: planning_tasks.prefetch_name_options stays names-specific (it precomputes context then closes its DB session before 13 slow LLM calls; a generic worker needs an open session), with prefetchable=True as the declarative hook. Folds naturally into #155 (improv NPC "with prefetch"), the second prefetchable consumer, where a generalized worker can be designed + tested against two tools.

🤖 Generated with Claude Code

Final foundation item of **v3.10.0 GM Workbench**. Targets the integration branch. Builds on #134 + #138. Closes #136. ## What The single extension point for the Workbench — **adding a tool = adding one `ToolDef` registry entry**, never touching the endpoint. - **`generation_service.py`**: `GENERATOR_TOOLS` registry + `ToolDef` (input model, system prompt, context builders, prompt/parse callables, or a custom `runner`; `sync_allowed`/`prefetchable`/`json_mode` flags). `run_tool` generic executor (build declared context → prompt → `llm_service.generate_structured_text` → parse). Context builders `campaign_context` (folds in #137's system context), `lore_context`, `threads_context`, `recent_sessions_context`. Eager-loads `game_system_ref` + guards unloaded refs (`sa_inspect().unloaded`) against async lazy loads. - **`POST /api/campaigns/{campaign_id}/workbench/{tool_id}/generate`** (GM-only): 404 unknown tool → 422 bad params → 503 if LLM unconfigured; sync tools run inline (row written `ready`/`failed`), async tools enqueue `run_workbench_generation` and return `pending` (poll #138 history). - **Names migrated** as `tool_id="names"` — a custom runner delegating to `audio_service.generate_name_options`, so output (incl. #137 per-system hints) is byte-identical and existing name tests pass **unmodified**. Custom-prompt names no longer need an active session. - **Old endpoints kept** as thin wrappers into the registry (session name-options, planning names cache-miss). ## Verification (Docker, py3.12) - **684 backend tests** (+10 `test_workbench_generation.py`: sync/async dispatch, GM-only 403, 404/422, GenerationResult written + visible in history, session-less custom prompt); existing name-generation tests pass unmodified. `ruff check`/`format` clean. No migration; no bot API change. ## Deferred (noted) - **Full prefetch generalization** is deferred: `planning_tasks.prefetch_name_options` stays names-specific (it precomputes context then closes its DB session before 13 slow LLM calls; a generic worker needs an open session), with `prefetchable=True` as the declarative hook. Folds naturally into **#155** (improv NPC "with prefetch"), the second prefetchable consumer, where a generalized worker can be designed + tested against two tools. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The single extension point for the GM Workbench: a GENERATOR_TOOLS registry
(ToolDef) + POST /api/campaigns/{campaign_id}/workbench/{tool_id}/generate
(GM-only) that dispatches sync (inline) or async (Celery, run_workbench_generation)
per the tool's sync_allowed flag, writing every run into the #138 GenerationResult
scratchpad. Adding a tool = adding one registry entry.

- generation_service.py: ToolDef registry, ToolResult, run_tool generic executor
  (build declared context -> prompt -> llm_service.generate_structured_text ->
  parse) + context builders campaign_context (folds in #137 system context) /
  lore_context / threads_context / recent_sessions_context. Eager-loads
  game_system_ref and guards unloaded refs (sa_inspect().unloaded) against async
  lazy loads.
- Names migrated as the first tool (tool_id="names"): a custom runner delegating
  to audio_service.generate_name_options so output — incl. #137 per-system hints —
  stays byte-identical and existing name tests pass unmodified. Custom-prompt
  names no longer require an active session (campaign-scoped).
- Old endpoints kept as thin wrappers into the registry (sessions name-options,
  planning names cache-miss); planning prefetch left delegating to the same name
  generator with prefetchable=True as the declarative hook (full generalization
  folds into #155, the second prefetchable consumer).

Foundation for the six generator tools. No migration (uses #138's GenerationResult);
no bot API change. Verified in Docker: 684 backend tests (+10), ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
claude-bot merged commit db06368f0c into feat/v3.10-gm-workbench 2026-07-19 15:24:23 +00:00
Sign in to join this conversation.
No description provided.