Skip to content

Support annotation-driven terminal-on-success managed tools #30

Description

@mostlydev

Summary

A state-changing managed tool can return a successful authoritative result, then the model can contradict that result in the terminal assistant round. cllama currently streams and persists the contradictory terminal as a successful completion.

This was observed on cllama v0.7.8 through an OpenAI-compatible managed-tool turn:

  1. The model called a state-changing managed tool.
  2. The provider service returned HTTP 200 with the managed envelope ok: true and domain state DENIED.
  3. cllama fed that receipt back to the model.
  4. The model's terminal text claimed the action was Approved and instructed the next actor to proceed.
  5. Session history retained that terminal, and a follow-on invocation amplified the false state.

The service's durable state and notification were correct; no downstream action occurred. The defect is the proxy-authorized narration after the managed action.

Boundary

This is not runner-specific. cllama is the only component that sees both the successful managed-tool receipt and the later terminal response. A messaging runner receives only cllama's terminal output and cannot infer which managed tool ran or whether its result was authoritative.

Prompt wording is not a deterministic boundary: the downstream contract already said the API result was authoritative, prohibited mismatched state words, and instructed the model to stop after the action. The incident still reproduced.

A generic semantic validator over arbitrary JSON would also be unsafe. cllama should not guess that a field named status has workflow semantics, nor suppress final text after ordinary read tools.

Proposed contract

Support an optional, namespaced managed-tool annotation (exact name open for design, e.g. x-claw.terminalOnSuccess) declaring that a successful tool call completes the mediated turn.

For an annotated tool, after transport success and the normal managed envelope reports ok: true, cllama should:

  • record the complete tool trace and receipt;
  • end mediation without requesting another model-authored round;
  • return a protocol-valid empty terminal response (buffered or streamed);
  • log a distinct intervention/audit event;
  • avoid storing model-authored terminal text that could contradict the receipt.

For non-2xx responses or ok: false, retain the current recovery loop so the model can explain or correct the failure.

Ordering constraint

The first safe version should require a terminal action to be the sole or last managed call in the round. If multiple calls are present, define behavior explicitly and never execute calls ordered after a terminal action succeeds.

Acceptance criteria

  • OpenAI-compatible and Anthropic request formats have parity.
  • Buffered and synthetic-streaming responses produce protocol-valid empty terminals.
  • Successful annotated calls do not trigger another model round.
  • Failed annotated calls preserve current model recovery behavior.
  • Tool trace and session-history receipts remain complete.
  • Managed continuity cannot anchor a contradictory terminal after the successful terminal action.
  • Mixed/batched call ordering is deterministic and tested.
  • Unannotated tools remain behaviorally unchanged.

Integration note

Service descriptor generators will need a small follow-up to emit the annotation for domain actions whose durable service/outbox notification is already the canonical user-visible result. That compiler/adapter work should consume this proxy contract rather than add runner-specific suppression.

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