Commit Graph
7 Commits
Author SHA1 Message Date
Shubham ChakrawarandClaude Opus 5 cbe23ea287 fix(engine): stop replaying an abandoned partial turn on retry
A turn that dies mid-stream (provider 503, user interrupt) appends its partial
assistant message to history so the transcript still shows what streamed, then
an error notice. `_outbound_messages()` drops notices, so the partial becomes
the FINAL message sent to the provider, and `retry()` replays it verbatim.

Several providers reject that outright:

  - Gemini: "Requests ending with a model turn are not supported"
  - Claude 4.6+ / Fable 5: "does not support assistant message prefill"
  - Claude 4.5 and older: "final assistant content cannot end with trailing
    whitespace" -- streamed deltas routinely end in a space

So every retry replays the same bad tail and the session is wedged until the
user sends a new message or gives up on it. Reproduced end-to-end against live
APIs on Gemini 3.6 Flash and Claude Sonnet 4.6; three of the four Claude models
in the curated picker reject the payload unconditionally.

Drop the abandoned partial in `_outbound_messages()`, alongside the notices it
already treats as display-only. The trailing error/interrupted notice is what
identifies it: a COMPLETED turn's assistant message is structurally identical
(trailing, no tool_calls) and must be kept, since its `extras` sidecar is
replayed back to the owning provider. Trailing tool_calls mean a turn suspended
awaiting durable resume, never an abandoned one.

Because the notices persist, this also unwedges sessions already broken on disk.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-25 15:13:33 -07:00
Yi-111-a 2e588ac0da fix(audit): stamp every lifecycle row with the tool call's ID
The shared `TurnEngine._audit()` boundary built its payload from the tool
name and arguments only, so the ordinary lifecycle stages (proposed /
started / finished) never carried `call_id`. Later-added paths like
reviewer_shadow and approval_resolved pass it explicitly at the call
site; the common boundary did not, and nothing left an audit sink able to
join a `started` to its `finished` when the same tool and arguments run
more than once in a turn (retries, repeated identical calls, concurrent
calls) — a failed attempt followed by a retry produced rows that could
not be told apart.

Stamp it once at that boundary instead of at each of the ~10 call sites,
so a new call site added later cannot forget it. `**event` still spreads
last, so a call site that means something else by `call_id` wins.

Closes #670
2026-10-01 08:18:22 +08:00
Rohit C Prasad 7db596dd80 Engine and server: worker grants, lead decisions, parked gates, reviewer, usage
The human's ticks on the staffing card are the worker's grant; approvals follow the lead's mode.
A lead answers a worker's parked call; team and work-item gates keep their payload in the Inbox.
2026-09-17 16:18:03 -07:00
Buddhika GodakandaandClaude d9fbb0790b Recover truncated tool calls, and never pass a leaked one off as an answer
Small local models drift off the tool-call format, especially with a large
tool schema in play. Two failures followed from that, both of which ended
the turn looking like the model had simply stopped mid-sentence.

Salvage handled well-formed Qwen/Hermes XML but gave up entirely on a call
cut off partway through. It now takes the function name plus every
parameter that actually closed. A trailing unterminated `<parameter=…>` is
dropped rather than guessed, so a half-written path or file body can never
reach a tool; if that leaves a required argument missing, the call fails
validation and the model gets a corrective tool error, which is the agent
loop working.

Worse, a call that never parsed at all was reported as `status: completed`
— indistinguishable from the model deciding it was done, leaving the user
with narration trailing off into stray closing tags. It now ends on the
error path, so the GUI offers Retry. That is the right affordance here: the
drift is probabilistic, not deterministic, so the same model usually
succeeds on a second attempt.

Detection ignores fenced and inline code, so a model *explaining* tool-call
syntax is still a real answer, and requires that tools were offered at all.

Reported against qwen3.5-9b on LM Studio, 2026-07-26.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-27 05:50:54 +05:30
Rohit C Prasad f1eb652d61 Allow mid-session model switching with a persisted transcript marker
Picker stays live for the session; switches persist a model_switch notice (§17 revised).
Rebinds refused mid-turn; images become placeholders for non-vision targets at send time.
2026-07-22 15:43:54 -07:00
Rohit C Prasad a63710ecfe Add Gemini 3 models with thought-signature support
Signatures ride the assistant message as a _gemini sidecar and are reattached in tool loops.
Thought-flagged parts are filtered from answer text; foreign sidecars stripped on the OpenAI wire.
Live-verified both Gemini 3 models end-to-end; without the echo they 400 on every tool loop.
2026-07-22 14:05:23 -07:00
Rohit C PrasadandDevika 2b45018ffa OpenWorker: initial import
Imported from andrewyng/aisuite@1b4bbf303e
(contents of its platform/ directory, hoisted to the repo root).
Development history prior to this commit lives in that repository.

Co-authored-by: Devika <devikaverma11@gmail.com>
2026-07-21 11:09:41 -07:00