Skip to content

fix(langfuse): include system prompt in generation input (Anthropic system + Codex instructions) - #64292

Closed
FnExpress wants to merge 1 commit into
NousResearch:mainfrom
FnExpress:fix/langfuse-system-prompt-codex
Closed

fix(langfuse): include system prompt in generation input (Anthropic system + Codex instructions)#64292
FnExpress wants to merge 1 commit into
NousResearch:mainfrom
FnExpress:fix/langfuse-system-prompt-codex

Conversation

@FnExpress

Copy link
Copy Markdown

Summary

Langfuse LLM call generation observations show conversations without the agent's system prompt (skills, memory, SOUL, tool guidance) for every provider that moves the system prompt out of messages:

The pre_api_request hook only forwarded request_messages, so traces for both paths looked like conversations with no instructions at all — e.g. a Codex-backed Hermes turn whose LLM call 1 shows 18k prompt tokens but only a one-line user message as input.

This PR salvages #32175 by @db-aeon onto current main (cherry-picked so authorship survives, per the AGENTS.md salvage etiquette), then fixes the whole bug class:

  • agent/conversation_loop.py derives the system prompt the provider actually receives — api_kwargs["system"]api_kwargs["instructions"]messages[0] fallback, extracted into a _system_prompt_for_hooks() helper — and passes it to pre_api_request as system_prompt
  • plugins/observability/langfuse prepends a serialized role: system entry to the generation input (after the last-12 window, so long conversations never drop it), flattens Anthropic content-block lists, skips the prepend when messages[0] already carries the system role (chat_completions), and records system_prompt_chars metadata

Commits

  • test(langfuse): system prompt must reach generation input across providers — RED-first coverage: plugin contract (prepend, block-list flatten, no duplication, window-safe, metadata) plus the cross-hook-boundary regression the fix(langfuse): include Anthropic system prompt in generation input #32175 review asked for — real ResponsesApiTransport().build_kwargs() / AnthropicTransport().build_kwargs() output flows through the loop's derivation into the plugin hook with no Hermes internals mocked (only the Langfuse client is faked)
  • fix(langfuse): include Anthropic system prompt in generation input (@db-aeon, cherry-picked from fix(langfuse): include Anthropic system prompt in generation input #32175; conflicts with the current middleware/hook block resolved)
  • fix(langfuse): carry Codex/Responses instructions into hook system_prompt — the Codex sibling path + _system_prompt_for_hooks() extraction

Test plan

  • tests/plugins/test_langfuse_plugin.py — 59 passed (48 pre-existing + 9 new + 2 from fix(langfuse): include Anthropic system prompt in generation input #32175)
  • Affected surface: tests/plugins/, tests/hermes_cli/test_plugins.py, tests/run_agent/test_run_agent_codex_responses.py — no regressions vs clean main
  • scripts/run_tests.sh full suite — remaining failures reproduce identically on clean main (environment-specific, macOS), zero delta from this change
  • E2E against a self-hosted Langfuse: enabled observability/langfuse, ran hermes chat on an openai-codex model — generation input now starts with role: system (102,659 chars, system_prompt_chars metadata matches); chat_completions sessions unchanged (single system entry, no duplication)

Closes #32175 (supersedes it while preserving its commit; happy to rebase if @db-aeon prefers to land his PR first — this one then shrinks to the Codex path + tests).

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have labels Jul 14, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

This PR includes the system prompt in generation input for Langfuse.

Looks Good

  • Targeted fix for Langfuse integration.
  • Well-scoped: 4 files.

No Issues Found


Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for extending the Langfuse fix to the Codex/Responses request shape; the current Anthropic and Codex premise is verified.

Problems

  • agent/bedrock_adapter.py:580-583 also removes the system prompt from messages, encoding it as Bedrock blocks shaped {"text": content} and sending it through a separate system kwarg at agent/bedrock_adapter.py:951-962. The new check at plugins/observability/langfuse/__init__.py:497 only accepts dict blocks where type == "text", so the proposed helper returns no system entry for Bedrock and leaves the same trace gap on that provider.

Suggested changes

  • Accept Bedrock text blocks in _serialize_system_prompt() and add a BedrockTransport().build_kwargs() regression through the hook-boundary helper, alongside the Anthropic and Codex cases.

Automated hermes-sweeper review.

if isinstance(system_prompt, list):
parts: list[str] = []
for block in system_prompt:
if isinstance(block, dict) and block.get("type") == "text":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bedrock Converse sends separate system blocks as {"text": ...} (agent/bedrock_adapter.py:580-583,951-962), not {"type": "text", ...}. This condition drops every Bedrock system prompt, leaving the same Langfuse gap there; please accept that block shape and cover it with a transport-boundary regression.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 16, 2026
Include Anthropic, Codex/Responses, and Bedrock system prompts in Langfuse generation input, with regression coverage across provider call paths.

Co-authored-by: Dan Benyamin <db@project-aeon.com>

Co-authored-by: Cursor <cursoragent@cursor.com>
@FnExpress
FnExpress force-pushed the fix/langfuse-system-prompt-codex branch from dd55a07 to 009d803 Compare July 22, 2026 13:45
erosika added a commit to erosika/hermes-agent that referenced this pull request Aug 10, 2026
Providers that move the system prompt out of messages made it vanish
from traces: Anthropic Messages carries it as a separate system kwarg
(str or content-block list) and the Responses/Codex API as top-level
instructions, so generation inputs showed conversations without the
agent's instructions, skills, or memory. conversation_loop now derives
the system prompt as actually sent to the provider and forwards it to
hooks; the plugin prepends a role: system entry when messages don't
already carry one. Serialization routes through _capture_content so
capture modes apply to system prompts too.

Adopted from NousResearch#64292, which extends NousResearch#32175's Anthropic fix to the
Codex/Responses path — thanks @FnExpress and @db-aeon.

Co-authored-by: FnExpress <37214785+FnExpress@users.noreply.github.com>
Co-authored-by: Dan Benyamin <db@project-aeon.com>
@erosika

erosika commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

adopted into #83437 with co-author credit — thanks for extending the fix across Anthropic, Codex, and Bedrock shapes. integration changes: system-prompt serialization routes through the branch's capture modes, and the Bedrock premise test tolerates the transport's cachePoint block on current main.

kshitijk4poor added a commit that referenced this pull request Aug 13, 2026
… fan-out

Salvaged from PR #83437 by @erosika, with adopted fixes from @bgodlin (#81054),
@aldoeliacim (#82332), @nftpoetrist (#42326), @rodboev (#39653), @FnExpress
(#64292, supersedes #32175 by @db-aeon), @Per0-1 (#61166), @NaMinhyeok (#64797),
and @liuhao1024 (#43130).

Widens the bundled Langfuse plugin from 6 to 11 hooks and fixes two
attribution bugs. Also adopts shutdown/atexit lifecycle fixes and composes
8 prior community PRs with interaction-fix follow-ups.

Model attribution: on_pre_llm_request and on_post_llm_call now prefer the
wire value (request body model, response model) over the agent attribute,
which goes stale after /model switch or provider fallback.

Cost total: both cost paths now send a summed total alongside the per-type
breakdown, since Langfuse does not derive calculatedTotalCost from
cost_details keys. Subscription-included routes send no cost keys at all.

New coverage: api_request_error closes failed generations with ERROR level;
on_session_finalize/on_session_end close dangling traces for tool-only and
interrupted turns; subagent_start/subagent_stop trace delegated children as
spans; MoA advisor fan-out emits one generation per advisor priced at the
advisor's own model.

Capture modes: HERMES_LANGFUSE_CAPTURE=metadata|sanitized|full (default
sanitized). Sanitized mode redacts secret patterns before truncation.

Adopted lifecycle fixes: shutdown client at session finalize when
reason=shutdown (not on session rotation); atexit finalizer ends open root
spans for short-lived processes; root context manager exited to prevent
interpreter-teardown TypeError; TOCTOU on _get_langfuse() fixed with lock;
reasoning_content surfaced in traces; system prompt included in generation
input for Anthropic/Codex/Bedrock; SDK v3 update_trace replaces set_trace_io.

Closes #29482, #43129, #72661.
Supersedes #81054, #82332, #42326, #39653, #64292, #32175, #61166, #64797, #43130.
Partially addresses #67544 (capture modes + secret redaction; user_id remains open).
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Merged via #85439 — your fix was adopted and composed into the wider Langfuse tracing PR by @erosika. Your contribution is credited in the commit body. Thanks @FnExpress!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants