Skip to content

feat(forwarder): system prompt for session chat (#418) - #430

Closed
jonathaneoliver wants to merge 1 commit into
feat/llm-budget-ledger-417from
feat/llm-prompt-418
Closed

feat(forwarder): system prompt for session chat (#418)#430
jonathaneoliver wants to merge 1 commit into
feat/llm-budget-ledger-417from
feat/llm-prompt-418

Conversation

@jonathaneoliver

Copy link
Copy Markdown
Owner

Summary

What's in the prompt

  • Role + how sessions are recorded (session_id ⨯ play_id, 1Hz snapshots, HAR-style network_requests).
  • Schema of session_snapshots + network_requests + llm_calls with the columns analyses actually reach for.
  • Response-style rules — anchor every claim to mm:ss.ms timestamps (the dashboard auto-links these to seek), structure forensic answers as Observation / Mechanism / Evidence, comparison answers as Similarities / Differences / Hypotheses, no padding, no SQL in answers unless asked.
  • Mode hints triggered by the focus-context preamble (Focus session_id / Focus range / Compare sessions).
  • Tool-use guidance — start narrow, aggregate before materializing, errors-first.
  • Failure-mode language so a confused or data-sparse model stops cleanly instead of hallucinating.

Loader behaviour

  • SessionChatPrompt() reads /config/prompts/session_chat.md (overridable via SESSION_CHAT_PROMPT_PATH).
  • PromptCache.Load re-reads only on mtime change — edit the file in production, next chat picks it up automatically.
  • Built-in stub fallback keeps /api/session_chat working when the file is missing or malformed.
  • Frontmatter parser handles standard --- delimiters; missing or unversioned frontmatter logs unversioned into the ledger.

Ledger correlation

llm_calls.prompt_version now carries the version from the loaded prompt's frontmatter, so A/B iterations on the prompt correlate with response quality (e.g. cost per turn, average iterations, error rate) over time.

Test plan

  • go test ./... 67/67 pass.
  • docker build clean; image contains /config/prompts/session_chat.md (8.5 KB).
  • TestSessionChat_InjectsSystemPrompt — uses a unique marker string to verify the on-disk prompt body actually reaches the LLM as the first message.
  • Frontmatter parsing covers: no frontmatter, with frontmatter, unterminated frontmatter, unversioned frontmatter.
  • PromptCache covers: re-read on mtime change, hit cache when unchanged, missing-file fallback to builtin.
  • Live-network smoke against a real LLM with the new prompt — manual / deploy-time.

🤖 Generated with Claude Code

Adds the system prompt that drives all three AI session-analysis
modes (overview, forensic, compare) and a small loader that mtime-
caches it so operators can iterate live.

  prompts/session_chat.md
    YAML frontmatter (prompt_version, default_max_tokens,
    default_temperature) + body covering:
      - role / objective
      - how a session is recorded (session_id ⨯ play_id, snapshot
        cadence, network_requests row shape)
      - schema of session_snapshots + network_requests + llm_calls
      - response style — anchor to mm:ss.ms timestamps, structure
        forensic answers as Observation / Mechanism / Evidence,
        comparison answers as Similarities / Differences /
        Hypotheses, no padding, no SQL in answers unless asked
      - mode hints driven by the focus-context preamble
        (Focus session_id / Focus range / Compare sessions)
      - tool-use guidance — start narrow, aggregate before
        materializing rows, errors-first, never SELECT *
      - failure-mode language for sparse-data and stuck loops

  llm_prompt.go
    PromptCache.Load(path) — re-read only on mtime change so
    edit-and-reload works without restart. Frontmatter parser
    accepts the standard '---' delimiter style. Built-in
    fallback prompt keeps /api/session_chat working when the
    file is missing.

  llm_session_chat.go
    handleSessionChat now loads the system prompt, prepends it
    as the first message (largest, prefix-cacheable), then the
    focus-context preamble (small, varies per call), then the
    user-supplied messages.

  llm_calls.prompt_version
    Now populated from the loaded prompt's frontmatter so
    A/B prompt iteration correlates with response quality
    over time.

  Dockerfile
    Copies prompts/ into /config/prompts/. Override path via
    SESSION_CHAT_PROMPT_PATH env or ConfigMap mount over /config.

10 new tests (67 total): frontmatter parsing, mtime cache, builtin
fallback, on-disk load, system-prompt-actually-injected end-to-end.

Verified: go test ./... 67/67 pass; docker build clean; image
contains /config/prompts/session_chat.md.

Part of epic #412.
Closes #418.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jonathaneoliver

Copy link
Copy Markdown
Owner Author

Closing — superseded by the v2.0.0 release.

This stale stacked-PR chain (epic #412) has no salvageable diff against current main. The feature lives on in the v3 dashboard + forwarder; further work should target those, not this stack.

@jonathaneoliver
jonathaneoliver deleted the feat/llm-prompt-418 branch May 27, 2026 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant