Skip to content

sync_filter: bypass the LLM for /sync_* commands (inject assistant message directly) #39

Description

@dvystrcil

Why

After PR #38 added the <filter-result> marker tag + emphatic wording, /sync_down behaviour improved dramatically:

Before #38 After #38
Wall time spinner for minutes 2.4s
Reasoning size 20,037 chars circular loop 44 output tokens, no looping
Visible response empty "Pulled latest changes — already up to date."

But qwen3.6:35b still double-checks the filter's work by calling run_command("cd ~/fiction/standing-patrol && git pull") + get_process_status after the filter has already injected the SUCCESS result. The model gets the same answer ("Already up to date") and reports the right thing — but the redundant shell calls defeat the point of the filter intercepting in the first place. Prompt-only fixes haven't been enough to fully eliminate this.

Two prompt iterations applied to fiction-writer today:

  1. "DO NOT call run_command for /sync_* commands"
  2. " tag = authoritative outcome, do not re-do the work"

Both helped; neither got us to zero tool calls.

Proposal: bypass the LLM entirely

For /sync_* commands, the LLM adds no value — the filter already knows the outcome. Instead of injecting a role: system message and routing through the model, the filter should:

  1. Inject a role: assistant message directly with the result text
  2. Short-circuit the request so OWUI doesn't call the model at all

Two outcomes:

  • Zero shell tool calls (impossible to misuse — the model never runs)
  • Sub-second response (no model latency; user sees the result the moment the filter finishes the git operation)

Implementation sketch

async def inlet(self, body: dict, user=None) -> dict:
    ...
    if self._is_sync_down(user_message):
        result = self._sync_down(project)
        log.info("[sync] SYNC DOWN result: " + result)
        # Append an assistant message directly + signal short-circuit
        messages.append({
            "role": "assistant",
            "content": self._format_user_visible(command="/sync_down", result=result),
        })
        body["messages"] = messages
        # OWUI honors a sentinel that tells it to skip the LLM call entirely
        # (need to look up the exact mechanism — possibly body["_skip_completion"]=True
        # or a return-shape signal)
        body["_short_circuit"] = True   # ← stand-in; verify the actual key
        return body

The user-visible content would be exactly what the model produces today:

Pulled latest changes — already up to date.

For FAILURE cases:

Sync down failed: <error from git output>. You may want to investigate or retry.

Open questions before implementing

  1. What's the actual OWUI mechanism to short-circuit? Need to inspect OWUI's filter dispatch source. Candidates:
    • Return body with a special key OWUI checks
    • Raise a specific exception type
    • Set a done: True flag on the appended assistant message
  2. Does the OWUI frontend handle a chat that gets a response without a model round-trip? It might not animate the same way; might need extra fields (id, model name, usage stats) to look "real".
  3. What about title generation and tagging? OWUI fires those as separate background tasks. They'll still hit ollama-small-cuda for the chat title. That's fine — they're independent of the main chat completion.
  4. Does this break the outlet filter? outlet() runs after the assistant message; if it expects a real model response shape, the synthesized assistant message needs to match.

Acceptance criteria

  • /sync_down in a fiction-writer chat produces the success/failure sentence in <500ms
  • kubectl logs deploy/ollama shows NO chat completion request for the /sync_* command
  • kubectl logs deploy/owui-pipelines still shows the filter chain running (sync_filter SUCCESS log line)
  • No JSON.parse error on the frontend
  • Title generation / tag generation still work (those hit the small lane independently)
  • Same behaviour for /sync_up and /sync_pr

Related

  • fix(sync_filter): wrap result in marker tag + emphatic wording #38 — the marker-tag + emphatic-wording approach (current state)
  • fiction-writer system prompt has the /sync_* filter-awareness section + <filter-result> recognition (DB UPDATE applied 2026-05-25, prompt 7672 → 10080 chars)
  • Trigger context: same chat where qwen3.6:35b wedged ollama-big for 30 min — diagnosis was a gfx1151 wedge, not the filter; pod-rolled to clear. The filter change is sound; this issue is the next level of polish.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions