Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tailcallhq/forgecode
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: LLM360/forgecode
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 7 commits
  • 17 files changed
  • 2 contributors

Commits on May 1, 2026

  1. Configuration menu
    Copy the full SHA
    3387b1a View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    c62cac3 View commit details
    Browse the repository at this point in the history

Commits on May 2, 2026

  1. feat(prompt): FORGE_SYSTEM_PROMPT_FILE override env var

    Extract the SystemContext build + Handlebars rendering portion of
    add_system_message into a new public async method `render_blocks`,
    returning the (block1, block2) pair without touching conversation
    state. add_system_message becomes a thin orchestrator: env-var check
    first, then render_blocks, then set_system_messages.
    
    When FORGE_SYSTEM_PROMPT_FILE is set to a non-empty path, the file's
    UTF-8 contents become the sole system message, byte-for-byte. The
    override path skips Handlebars entirely so arbitrary content
    (including {{ and }}) passes through unmodified. Empty string is
    treated as unset.
    
    The unset-env-var path is byte-identical to the previous
    implementation — proven empirically against an OPENAI_COMPATIBLE
    provider: trace.jsonl messages[0].content matches BEFORE-binary trace
    to the byte (sha256 5f21ac07…, 11519 bytes).
    
    Composes with FORGE_TRACE_FILE: when the override is active,
    MergeSystemMessages is a no-op on the single system message (per
    ensure_system_first.rs:154-170), so the trace records the file
    contents byte-for-byte. This closes the integrity loop between
    prompt-writer intent and what the LLM actually sees on the wire.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    aldopareja and claude committed May 2, 2026
    Configuration menu
    Copy the full SHA
    234409b View commit details
    Browse the repository at this point in the history
  2. feat(prompt): add forge prompt render subcommand

    Adds `forge prompt render [-C <path>] [--agent <id>]` which prints the
    merged Block 1 + "\n\n" + Block 2 system prompt to stdout without
    contacting any LLM. Pairs with FORGE_SYSTEM_PROMPT_FILE: the typical
    SFT workflow is render → edit → run-with-override, with the trace
    recorder closing the integrity loop.
    
    Implementation:
    - forge_app::ForgeApp gains a private `build_system_prompt` helper
      that centralizes the SystemPrompt construction (cwd, files, agent,
      models, tool definitions, custom instructions, template config).
      Both `chat` and the new `render_system_prompt` go through this
      helper, guaranteeing they feed the templates from identical inputs.
    - forge_app::ForgeApp::render_system_prompt — calls render_blocks on
      the configured SystemPrompt; returns Option<(block1, block2)>.
    - API trait + ForgeAPI impl expose render_system_prompt.
    - forge_main: new TopLevelCommand::Prompt(PromptCommandGroup) with
      PromptCommand::Render { directory, agent }. Handler in
      render_prompt.rs creates a fresh ForgeAPI rooted at the resolved
      cwd (subcommand --cwd if provided, else the global cwd) so
      Environment::cwd, list_current_directory, and git ls-files all
      reflect the right tree.
    
    main.rs: skip the piped-stdin read when a subcommand is invoked.
    The chat path needs stdin (`cat prompt.txt | forge`); subcommands
    do not, and reading stdin blocks until EOF — under non-interactive
    automation (e.g. background processes whose stdin is a non-EOFing
    pipe), the read would hang forever and the subcommand would never
    run. The check `cli.subcommands.is_none() &&` preserves the existing
    chat-with-pipe behavior unchanged.
    
    Verified end-to-end against an OPENAI_COMPATIBLE Kimi-K2.6 endpoint:
      forge prompt render stdout sha256 = 5f21ac07… (11519 bytes)
      AFTER chat trace messages[0].content sha256 = 5f21ac07… (11519)
      AFTER chat with FORGE_SYSTEM_PROMPT_FILE trace = 5f21ac07… (11519)
    All identical to the BEFORE binary's chat trace, confirming render
    fidelity, refactor non-regression, and override fidelity together.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    aldopareja and claude committed May 2, 2026
    Configuration menu
    Copy the full SHA
    981e7ac View commit details
    Browse the repository at this point in the history

Commits on May 16, 2026

  1. fix(trace): emit per-turn request event for SFT integrity

    Move the trace recorder's outbound capture out of the on_request hook
    chain and into Orchestrator::execute_chat_turn, after the per-turn
    transformer chain and ProviderPipeline have run. Replaces the old single
    `context` event (turn 1 only) with a `request` event emitted once per
    logical turn, recording the full post-pipeline Request body the LLM
    receives.
    
    Every silent context mutator (compaction, doom-loop reminders, pending
    todos, tool-error retry annotations, per-turn transformer chain) is now
    automatically visible turn-by-turn, restoring ground truth for SFT data
    generation. The new event schema is {event, ts, turn, body} where body
    is the entire serialized Request post-ProviderPipeline; serde
    skip_serializing_if ensures only fields actually sent on the wire appear.
    
    write_request_event takes Context + provider_id + model_id + turn (no
    tools arg): tools come from Context.tools via Request::from(Context),
    which is the same source the wire path uses, so the trace is byte-equal
    to what hits the LLM.
    aldopareja committed May 16, 2026
    Configuration menu
    Copy the full SHA
    b0a20ba View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    60ef2c1 View commit details
    Browse the repository at this point in the history

Commits on May 17, 2026

  1. fix(trace): truncate FORGE_TRACE_FILE at handler init so reruns overw…

    …rite
    
    Re-running forge with the same FORGE_TRACE_FILE previously appended to
    the existing file, concatenating runs and breaking single-session JSONL
    parsers. Truncate the path once when TraceLoggingHandler is constructed
    so each execution starts with a clean trace.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    aldopareja and claude committed May 17, 2026
    Configuration menu
    Copy the full SHA
    2c09b0c View commit details
    Browse the repository at this point in the history
Loading