Skip to content

ACP custom agent becomes unrecoverable after idle restart: model state is not restored and slash commands fall through to model invocation #4188

Description

@lanslot4n93r

Summary

A custom ACP agent works normally when a conversation is first created, but after AionUi reclaims the idle ACP process and later restores it with session/load, the conversation can become permanently unusable.

There appear to be multiple ACP host integration issues:

  1. The selected model is not reliably restored after ACP process restart.
  2. session/set_model is sent and acknowledged, but the conversation remains unusable.
  3. ACP available_commands_update is not reflected in AionUi's slash-command registry.
  4. /model, /help, and other local ACP commands fall through to the normal model invocation path.
  5. A credential/configuration failure is classified as retryable UNKNOWN_UPSTREAM_ERROR, causing ineffective process restarts and message replays.

This issue is not necessarily caused by AionUi alone. The ACP agent also has provider-restoration and error-reporting problems. However, AionUi currently has no recovery path once this state occurs.

Environment

  • OS: Windows x86_64
  • AionUi/aioncore version: 0.1.72
  • Agent type: Custom ACP agent
  • ACP agent: Hermes Agent
  • Provider type: Named custom OpenAI-compatible provider
  • Model: gpt-5.6-sol

No API keys, private endpoint credentials, local filesystem paths, user IDs, or conversation/session IDs are included in this report.

Reproduction steps

  1. Configure a custom ACP agent that advertises a named model ID similar to:

    custom:<named-provider>:gpt-5.6-sol
    
  2. Create a new AionUi conversation using that ACP agent.

  3. Send several messages and confirm that model calls work.

  4. Leave the conversation idle long enough for AionUi to reclaim the ACP subprocess.

  5. Send another message so that AionUi restarts the agent and calls session/load.

  6. Observe a provider credential error.

  7. Select the same valid model again from AionUi's model selector.

  8. Try local slash commands such as:

    /model
    /help
    /model custom:<named-provider>:gpt-5.6-sol
    

Actual behavior

The newly created conversation initially works and completes multiple model requests successfully.

After the idle ACP subprocess is reclaimed, AionUi restarts the process and loads the same ACP session. Subsequent requests fail with:

UNKNOWN_UPSTREAM_ERROR
custom/main requested but no endpoint credentials found

AionUi sends a model change using session/set_model with the complete model ID:

custom:<named-provider>:gpt-5.6-sol

The agent acknowledges the same resolved value, but the next prompt still fails immediately with the credential error.

The AionUi slash-command endpoint for the affected conversation returns an empty list:

[]

Commands such as /model and /help are stored as exact user messages, but they are not handled as local ACP commands. They fall through to the broken model invocation path and produce the same provider error.

Once this occurs, the user cannot recover the conversation in-band because the /model command that should repair the model selection itself requires the already-broken model invocation path.

Expected behavior

  1. AionUi should persist the full selected ACP model ID per conversation.
  2. After session/load, AionUi should reconcile or reapply the selected model.
  3. ACP available_commands_update events should populate the conversation's slash-command registry.
  4. Recognized local slash commands should be sent as a plain text-only ACP prompt without extra context/resource blocks.
  5. Control commands such as /model, /help, and /reset should remain usable even if the current model provider is broken.
  6. Credential/configuration failures should not be classified as retryable unknown upstream failures.
  7. Automatic retry should not repeatedly kill the process, reload the same broken session, and replay the same command.
  8. The UI should provide a way to discard/reinitialize a broken ACP session without deleting the entire AionUi conversation.

Diagnostic evidence

The observed sequence is:

New ACP conversation
→ multiple successful model calls
→ idle ACP process reclaimed
→ ACP process restarted
→ session/load succeeds
→ next prompt fails with missing endpoint credentials
→ AionUi sends session/set_model with complete named model ID
→ ACP agent acknowledges the same resolved model ID
→ next prompt still fails immediately
→ slash-command registry remains empty
→ /model and /help fall through to model invocation
→ AionUi marks the error retryable and repeats the failing lifecycle

The failure occurs locally in tens of milliseconds, before a real request is sent to the model endpoint.

Suggested AionUi-side improvements

  • Persist current_model_id in the conversation's ACP state.
  • Reconcile the selected model after every session/load or process restart.
  • Correctly consume and cache available_commands_update.
  • Route advertised slash commands through a text-only control path.
  • Do not attach skills, resources, files, or other content blocks to local ACP control commands.
  • Distinguish ACP control-command failures from ordinary prompt failures.
  • Classify missing-provider-credentials errors as non-retryable configuration errors.
  • Avoid automatic replay loops for deterministic configuration failures.
  • Provide a “reset/reinitialize ACP session” recovery action.
  • If possible, verify model state after session/set_model instead of treating an acknowledgement as proof that the provider is usable.

Cross-component note

The ACP agent also appears to have implementation issues:

  • A named custom provider may be restored as a generic custom provider.
  • Provider-resolution exceptions may be swallowed.
  • session/set_model may acknowledge success before credential availability is validated.
  • The custom/main error message may be hard-coded and misleading.

However, AionUi should still preserve its own selected model state, retain ACP command metadata, and provide a recovery path instead of leaving the conversation permanently locked.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions