[Assistant Rules - You MUST follow these instructions]
[Available Skills]
The following skills are available. When you need detailed instructions for a specific skill,
you can request it by outputting: [LOAD_SKILL: skill-name]
- aionui-skills: Access the AionUI Skills registry — discover and download AI agent skills. Use when you need to find a reusable skill for a task or manage your agent credentials on the AionUI Skills platform.
- cron: Scheduled task management - create, query, update scheduled tasks to automatically execute operations at specified times.
- officecli: Create, analyze, proofread, and modify Office documents (.docx, .xlsx, .pptx) using the officecli CLI tool. Use when the user wants to create, inspect, check formatting, find issues, add charts, or modify Office documents.
- skill-creator: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
[Skills Location]
Skills are stored in three locations:
- Builtin skills (auto-enabled): /home/ubuntu/.config/AionUi/config/builtin-skills/_builtin/{skill-name}/SKILL.md
- Bundled skills: /home/ubuntu/.config/AionUi/config/builtin-skills/{skill-name}/SKILL.md
- User custom skills: /home/ubuntu/.config/AionUi/config/skills/{skill-name}/SKILL.md
Each skill has a SKILL.md file containing detailed instructions.
To use a skill, read its SKILL.md file when needed.
For example:
- Builtin "cron" skill: /home/ubuntu/.config/AionUi/config/builtin-skills/_builtin/cron/SKILL.md
- Bundled "pptx" skill: /home/ubuntu/.config/AionUi/config/builtin-skills/pptx/SKILL.md
[User Request]
Done. Now in AionUI Detect Custom Agent, enter:
Field Value
Display Name Ollama Cloud
Command /home/ubuntu/ollama-acp
Arguments (leave empty)
Environment Variables (leave empty — key is baked in)
Click Detect — AionUI will run the script, it will handshake via ACP protocol and register as an independent agent. Try it and let me know what happens.
some start - hi
4
🤖
Ollama Cloud
Session failed to start
process exited unexpectedly (code: unknown, signal: none)
Invalid params
Failed to send message. Please try again.
The agent started but session failed. Let me debug the ACP script. The error is "Invalid params" - likely an issue with the `NewSessionResponse` or `InitializeResponse` format. Let me check the exact schema required.
Good — it detected! Session start is failing. Let me debug:
View Steps
/home/ubuntu/.hermes/hermes-agent/venv/bin/python3 -c " from acp.schema import InitializeResponse, NewSessionResponse, SessionInfo, Implementation import inspect print('InitializeResponse fields:', list(InitializeResponse.model_fields.keys())) print('NewSessionResponse fields:', list(NewSessionResponse.model_fields.keys())) print('SessionInfo fields:', list(SessionInfo.model_fields.keys())) "
/home/ubuntu/.hermes/hermes-agent/venv/bin/python3 -c " from acp.schema import InitializeResponse, NewSessionResponse, SessionInfo, Implementation, AgentCapabilities print('AgentCapabilities fields:', list(AgentCapabilities.model_fields.keys())) # Check what protocol_version expects import inspect print(InitializeResponse.model_fields['protocol_version']) print(NewSessionResponse.model_fields['session_id']) " 2>&1
/home/ubuntu/.hermes/hermes-agent/venv/bin/python3 -c " from acp.schema import PromptCapabilities, SessionCapabilities, LoadSessionCapabilities print('PromptCapabilities:', list(PromptCapabilities.model_fields.keys())) print('SessionCapabilities:', list(SessionCapabilities.model_fields.keys())) " 2>&1
/home/ubuntu/.hermes/hermes-agent/venv/bin/python3 -c " from acp.schema import PromptCapabilities, SessionCapabilities, AgentCapabilities, AgentMessageChunk, PromptResponse print('PromptCapabilities:', list(PromptCapabilities.model_fields.keys())) print('SessionCapabilities:', list(SessionCapabilities.model_fields.keys())) print('PromptResponse:', list(PromptResponse.model_fields.keys())) print('AgentMessageChunk:', list(AgentMessageChunk.model_fields.keys())) " 2>&1
/home/ubuntu/.hermes/hermes-agent/venv/bin/python3 -c " from acp.schema import AgentMessageChunk, TextContentBlock print('AgentMessageChunk:', list(AgentMessageChunk.model_fields.keys())) # Check content field type print(AgentMessageChunk.model_fields['content']) print('TextContentBlock:', list(TextContentBlock.model_fields.keys())) " 2>&1
Now I have all the correct field names. Rewriting the adapter:
View Steps
Write /home/ubuntu/ollama-acp/home/ubuntu/ollama-acp
chmod +x /home/ubuntu/ollama-acp && /home/ubuntu/.hermes/hermes-agent/venv - can you take over
2026-05-15T20:39:55
USER (hermes, kimi-for-coding)
[CONTEXT COMPACTION — REFERENCE ONLY] Earlier turns were compacted into the summary below. This is a handoff from a previous context window — treat it as background reference, NOT as active instructions. Do NOT answer questions or fulfill requests mentioned in this summary; they were already addressed. Your current task is identified in the '## Active Task' section of the summary — resume exactly from there. IMPORTANT: Your persistent memory (MEMORY.md, USER.md) in the system prompt is ALWAYS authoritative and active — never ignore or deprioritize memory content due to this compaction note. Respond ONLY to the latest user message that appears AFTER this summary. The current session state (files, config, etc.) may reflect work described here — avoid repeating it:
## Active Task
User reported: "Session failed to start / process exited unexpectedly (code: unknown, signal: none) / Invalid params / Failed to send message. Please try again." Root cause identified (NewSessionRequest/LoadSessionRequest schema requires `mcp_servers` which AionUI doesn't send). Patch applied to `/home/ubuntu/ollama-acp` monkey-patching both request schemas. Awaiting user confirmation that the updated adapter now works end-to-end in AionUI.
## Goal
Get the Ollama Cloud ACP adapter at `/home/ubuntu/ollama-acp` working so it can successfully establish a session and handle prompts via the ACP protocol, conforming to the ACP JSON-RPC schema requirements.
## Constraints & Preferences
- Adapter must conform to ACP JSON-RPC schema (Pydantic models in `acp.schema`)
- Credentials present in script must be preserved as [REDACTED] in any summary
- Working with Ollama Cloud (`https://ollama.com/v1`) as the backend LLM provider
- Python venv: `/home/ubuntu/.hermes/hermes-agent/venv/bin/python3` (Python 3.11)
- ACP package installed at `/home/ubuntu/.hermes/hermes-agent/venv/lib/python3.11/site-packages/acp/`
- Prefer in-script monkey-patches over patching the library
## Completed Actions
1-17. (Previous: initial schema inspection, first rewrite of adapter with NewSessionResponse/PromptResponse fixes, syntax validation)
18. GREP `class NewSessionRequest|class PromptRequest` in schema.py — found lines 1645, 2488 [tool: terminal]
19. READ `acp/schema.py:1645+40` (NewSessionRequest) — discovered `mcp_servers` is **required** (no default) [tool: read_file]
20. READ `acp/schema.py:2488+60` and `:2548+30` (PromptRequest) — confirmed only `prompt` and `session_id` are required [tool: read_file]
21. READ `acp/schema.py:1549+60` (InitializeRequest) — only requires `protocol_version` [tool: read_file]
22. WRITE `/home/ubuntu/ollama-acp-debug` (2,395 bytes) — debug wrapper logging JSON-RPC to `/tmp/...` [tool: write_file]
23. CHMOD +x `/home/ubuntu/ollama-acp-debug` [tool: terminal]
24. GREP `mcp_servers` in acp package — found `Agent` protocol has `mcp_servers: ... | None = None` but schema requires it [tool: terminal]
25. READ `acp/interfaces.py` (9,387 chars) — confirmed mismatch between Agent protocol and request schema [tool: read_file]
26. READ `acp/router.py` (8,041 chars) — confirmed line 101 `model.model_validate(params)` validates BEFORE handler is called [tool: read_file]
27. TEST validation against `{"cwd":"/home"}` — FAILED with "mcp_servers field required" [tool: terminal]
28. WRITE `/home/ubuntu/ollama-acp` (7,329 bytes) — added monkey-patch for `NewSessionRequest.model_validate` [tool: write_file]
29. COMPILE — Syntax OK [tool: terminal]
30. TEST initial patch attempt — FAILED (used `@classmethod` decorator incorrectly) [tool: terminal]
31. DEBUG with `__pydantic_validator__` inspection [tool: terminal]
32. TEST corrected patch approach (plain function assigned to class) — WORKED, injected `mcp_servers=[]` [tool: terminal]
33. PATCH `/home/ubuntu/ollama-acp` — fixed monkey-patch implementation to use proper function-on-class assignment [tool: patch]
34. COMPILE — Syntax OK [tool: terminal]
35. TEST patch in isolation — "OK (no mcpServers): mcp_servers=[] / OK (empty mcpServers): mcp_servers=[] / Patch working correctly!" [tool: terminal]
36. READ `/home/ubuntu/ollama-acp` (9,213 chars) — verified full script content [tool: read_file]
37. GREP `class LoadSessionRequest` — found line 2362 [tool: terminal]
38. READ `acp/schema.py:2362+40` — confirmed `LoadSessionRequest` ALSO has `mcp_servers` as required [tool: read_file]
39. PATCH `/home/ubuntu/ollama-acp` — extended monkey-patch to ALSO cover `LoadSessionRequest` (2,039-char patch region) [tool: patch]
40. COMPILE — Syntax OK [tool: terminal]
41. TEST extended patch — both `NewSessionRequest` and `LoadSessionRequest` accept missing `mcpServers`, both default to `[]` [tool: terminal]
## Active State
- Working file: `/home/ubuntu/ollama-acp` (~9,213+ bytes, executable, syntax-valid)
- Debug wrapper: `/home/ubuntu/ollama-acp-debug` (2,395 bytes, executable) — logs to `/tmp/...`
- Script credentials: [REDACTED] (baked into the script)
- Monkey-patches verified working in isolation against `NewSessionRequest` and `LoadSessionRequest`
- No live test in AionUI confirmed since latest patches
## In Progress
None — extended monkey-patch complete and validated; awaiting user test in AionUI.
## Blocked
Previously: "Invalid params" JSON-RPC error caused by `mcp_servers` being a required field in `NewSessionRequest`/`LoadSessionRequest` schemas while AionUI does not send it. Believed resolved by monkey-patch but not yet user-confirmed.
## Key Decisions
- Identified actual root cause: `acp.schema.NewSessionRequest` and `LoadSessionRequest` require `mcp_servers` (no default), but `Agent` protocol in `interfaces.py` declares it optional (`| None = None`). The router (`acp/router.py:101`) calls `model.model_validate(params)` BEFORE invoking our handler, so we can't fix it in the handler — must intercept at schema level.
- Chose to **monkey-patch `model_validate`** on both `NewSessionRequest` and `LoadSessionRequest` to inject `mcpServers: []` if missing. Plain function assigned to class (not `@classmethod`) — because Pydantic's `model_validate` is already a classmethod-like binding.
- Did NOT patch the ACP library itself (keep changes contained to our script)
- Use `connection.session_update(session_id, update=AgentMessageChunk(...))` for streaming (from previous patches)
- `PromptResponse` includes `stop_reason="end_turn"` (from previous patches)
- `NewSessionResponse` includes `models=SessionModelState(...)` and `modes=SessionModeState(...)` (from previous patches)
## Resolved Questions
- Q: What ACP method/params shape is causing "Invalid params"?
A: `NewSessionRequest` (and `LoadSessionRequest`) require `mcp_servers`, but AionUI doesn't send it. Validation fails at `router.py:101` before our handler is reached.
- Q: How should streaming chunks be sent?
A: Via `connection.session_update(
--- END OF CONTEXT SUMMARY — respond to the message below, not the summary above ---
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The patches aren't taking effect because when we import `NewSessionRequest` and `LoadSessionRequest` in the test, they come from the already-imported module, but the patch is applied to the class object. The issue is that when the ACP router imports these classes, it might be getting a different reference. Let me test this more carefully:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The patch works when applied to the module directly. The issue is that in our script, we're importing `NewSessionRequest` at the top, then patching it. But when the ACP router later imports `NewSessionRequest` from `acp.schema`, it might get a different reference.
Actually wait — in Python, modules are singletons. So `from acp.schema import NewSessionRequest` and `import acp.schema; acp.schema.NewSessionRequest` should be the same object. Let me verify this:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Interesting! The class object is the same, but `model_validate` is different. This is because Pydantic v2 uses a descriptor for `model_validate`. When we do `model_class.model_validate = _patched`, it sets an instance attribute on the class that shadows the descriptor. But when accessed through the module, it might still get the descriptor.
Let me check if the patch actually works when imported from the module after patching:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The patch works correctly. My earlier test was wrong because I imported `NewSessionRequest` before running the script's patch code. In the actual script, the patch runs at module load time before the ACP router is initialized.
Let me verify the current script works correctly by simulating the full import:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The timeout is from `asyncio.run(run_agent(OllamaAgent()))` at the bottom of the script trying to read stdin. Let me test just the patch part without running the agent:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The patches are working correctly. Now let me also verify the final script content is correct:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The script looks good. Now let me also check if there might be other issues. Let me look at the AionUI logs to see what exact error is happening. But first, let me also consider another possibility: maybe the issue is not with `mcp_servers` but with something else in the response format.
Let me create a simple test to verify the entire flow works by simulating JSON-RPC requests:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The schema patches are working. Now, the "Invalid params" error might be coming from somewhere else. Let me check if there are any other required fields in responses that could cause issues. Let me also check the AionUI logs:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
These logs are from the Hermes agent, not from the Ollama ACP adapter. Let me look for logs specifically about the Ollama agent:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
These logs show the error message being sent TO the Hermes agent, not from the Ollama adapter. The "Invalid params" is coming from AionUI itself when it tries to communicate with the Ollama ACP adapter.
Let me look for more specific logs about the Ollama adapter process:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see! The logs show that the Hermes agent (which is the "Ollama Cloud" agent in AionUI's perspective) successfully returned a `newSession` response with models. The issue is that this is the **Hermes agent** that's already configured as "Ollama Cloud" in AionUI — not our custom ACP adapter.
Wait, looking more carefully at the logs: the `<-` arrow shows messages FROM the agent TO AionUI. I can see the `newSession` response was successful with `sessionId` and `models`. But then the session failed with "Invalid params".
The key insight: the logs show `[ACP hermes STDERR]` — this is the Hermes agent's stderr. The "Invalid params" error is happening when AionUI tries to start a session with our custom Ollama ACP adapter.
Let me look for logs specifically about the custom agent detection/startup:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Now I can see the issue more clearly! Looking at the logs:
1. `20:07:15` and `20:08:25`: The adapter responds to `initialize` with `{"agentInfo":{"name":"ollama-acp","version":"1.0.0"},"protocolVersion":1}` — but this is **missing `agentCapabilities`**!
2. At `20:08:25`: `AcpError: Invalid params` — this happens right after the initialize response.
The `initialize` response is missing the required `agentCapabilities` field! Let me check the `InitializeResponse` schema again:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see! `agent_capabilities` has a default of `AgentCapabilities()`, so it's not required. But wait — looking at the logs again:
```
<- {"agentInfo":{"name":"ollama-acp","version":"1.0.0"},"protocolVersion":1}
```
This is the OLD response from before my fix! The logs are from 20:07 and 20:08, which was before I updated the script. Let me check if there are more recent attempts:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
No recent attempts with the new script. The user needs to try detecting the agent again with the updated script. But wait — let me also check if there's a problem with how the script is being executed. The logs from earlier showed the initialize response missing `agentCapabilities`. Let me verify my current script returns the correct response:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Found another bug! `SessionCapabilities(close=True)` is wrong — `close` expects a `SessionCloseCapabilities` object, not a boolean. Let me check what `SessionCloseCapabilities` looks like:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Now I understand — `SessionCapabilities(close=True)` is wrong. `close` expects a `SessionCloseCapabilities` object (or None), not a boolean. Let me fix this:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Both responses now validate correctly. Let me also verify the `PromptResponse`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
All responses validate correctly. Now let me also check if there might be an issue with `AgentCapabilities` defaults. Looking at the JSON output, I see `load_session: false` — let me check if this is correct:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Good, the defaults look fine. Now let me verify the final script is correct:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The script looks good. Now let me also add some debugging to help diagnose any remaining issues. Let me create a version that logs to stderr so we can see what's happening:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The script is now updated with:
1. **Schema patch** for `NewSessionRequest` and `LoadSessionRequest` — injects empty `mcpServers` if missing, fixing the "Invalid params" from AionUI not sending that field
2. **Fixed `SessionCapabilities`** — `close=SessionCloseCapabilities()` instead of `close=True`
3. **Added debug logging** to stderr so we can see what's happening in AionUI logs
**Please try again in AionUI:**
1. Settings → AI Agents
2. Click **Detect Custom Agent**
3. Display Name: `Ollama Cloud`
4. Command: `/home/ubuntu/ollama-acp`
5. Click **Detect**
If it still fails, check the AionUI logs with:
```bash
sudo journalctl -u aionui -f | grep -i "ollama-acp"
```
The debug logs will show us exactly which method is being called and where it fails.
2026-05-15T20:39:55
USER (hermes, kimi-for-coding)
i am not getting any response
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The user says they're not getting any response. This could mean:
1. The AionUI detection is hanging
2. The script is crashing silently
3. There's a different issue
Let me check if the script can run standalone and also check AionUI logs to see what's happening. I should also consider that maybe the script is hanging because `run_agent` is waiting for stdin but AionUI isn't sending anything, or there's a process startup issue.
Let me check the logs and also test the script directly.
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Wait — the logs show it's **working**! Let me look more carefully:
- `20:31:12` — `initialize` called, responded correctly
- `20:31:12` — `new_session` called with `cwd` and `mcp_servers=[]` — **working!**
- `20:31:12` — `prompt` called — **working!**
- `20:31:39` — another `prompt` called — **still working!**
The adapter is successfully handling requests! The issue might be that:
1. The response from Ollama Cloud is slow/empty
2. The streaming isn't reaching AionUI
3. AionUI isn't displaying the response
Let me check if there are any errors after the prompt calls:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The `20:28:01` error was from the OLD script (before my fix). The `20:31:12` logs show the NEW script is working correctly!
But the user says they're "not getting any response" — this means the session started but the prompt response might be empty or slow. The issue is likely that the Ollama Cloud API call is either:
1. Taking too long
2. Returning empty content
3. The streaming chunks aren't being sent correctly
Let me check if there are any errors after the prompt call and also test the Ollama API directly:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I can see the issue now! Looking at the logs:
```
20:31:39.919 › [ACP custom STDERR]: [ollama-acp] prompt called: session_id=..., prompt_blocks=1
20:31:42.126 › [AcpClient:custom:prompt]
20:31:42.126 › <- {"stopReason":"end_turn","usage":{"inputTokens":224,"outputTokens":42,"totalTokens":266},"userMessageId":"a2eca573-fda4-4eb4-94a5-dbd672b15378"}
```
The `prompt` response is returning **only** the final `PromptResponse` with `stopReason="end_turn"`, but there's **no streaming content** being sent before it! The response has `outputTokens:42` which means the Ollama API DID generate text, but the streaming chunks aren't reaching AionUI.
The problem is that the `AgentMessageChunk` streaming is not working correctly. Looking at the code, I'm using `connection.session_update()` to send chunks, but there might be an issue with how the chunks are structured or how `session_update` works.
Let me check the `AgentMessageChunk` schema more carefully and also check if `session_update` is the right method:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see — `ContentChunk` has `content` as a required field with a discriminator `type`. My `TextContentBlock(type="text", text=delta)` should work. But the issue might be that `session_update` on the connection is not the right way to send streaming chunks.
Let me check the `AgentSideConnection.session_update` method:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The `session_update` method looks correct. It sends a `SessionNotification` with the update. Let me check if there's an issue with how the notification is being sent. Let me also check the `notify_model` function:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see — `serialize_params` uses `exclude_none=True, exclude_defaults=True`. This means if `message_id` is None (which is the default), it will be excluded from the serialized output. But `message_id` is required for `AgentMessageChunk` to work properly — it's how AionUI knows which message the chunk belongs to.
Wait, actually `message_id` has `Optional[str]` with default `None`, so it might be excluded. But looking at the schema, `message_id` is described as required for chunks. Let me check if this is causing the issue.
Actually, looking more carefully at the logs, the issue might be simpler — the Ollama API is returning content but the streaming isn't working because `connection` is None or the chunks aren't being sent properly.
Let me test the Ollama API directly to see if it returns content:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The Ollama API is working and returning content. The issue is that the chunks ARE being generated but the user isn't seeing them in AionUI. Let me check if the streaming is actually working. Looking at the logs again:
```
20:31:39.919 › [ACP custom STDERR]: [ollama-acp] prompt called
20:31:42.126 › [AcpClient:custom:prompt]
20:31:42.126 › <- {"stopReason":"end_turn",...}
```
There's a ~3 second gap between `prompt called` and the response. During this time, the streaming chunks should be sent. But I don't see any log entries for the chunks being sent. This suggests the chunks might not be reaching AionUI.
Wait — I don't log when chunks are sent. Let me add more logging to see if chunks are being sent. But actually, looking at the AionUI response, it shows the final `PromptResponse` but no intermediate chunks. This means either:
1. The chunks aren't being sent
2. The chunks are being sent but AionUI isn't displaying them
Let me check if `connection.session_update` is actually sending anything by adding a log:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Now let me check if the issue is that AionUI expects the response content to be in the `PromptResponse` itself, not just via streaming. Looking at the `PromptResponse` schema:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see — `PromptResponse` doesn't have a `content` field! The content is supposed to be sent via streaming chunks (`AgentMessageChunk`), and the `PromptResponse` just signals the end of the turn with `stop_reason`.
So the architecture is:
1. Agent receives `prompt` request
2. Agent sends streaming `AgentMessageChunk` notifications via `connection.session_update()`
3. Agent returns `PromptResponse` with `stop_reason="end_turn"` to signal completion
This should work. But the user isn't seeing any response. Let me check if maybe the issue is that AionUI expects the agent to NOT stream but instead return the content in some other way.
Actually, wait — let me look at how the Hermes agent handles this. Looking at the logs, Hermes sends responses back to AionUI. Let me check if Hermes uses streaming or returns content directly:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Let me check how the Hermes agent (which works) sends responses. Let me look at the acp_adapter in Hermes:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I notice the helper `update_agent_message_text` doesn't include `message_id`. Let me check if `message_id` is actually required or if it's optional:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
`message_id` is optional (default `None`). The helper doesn't include it. So that's not the issue.
Let me think about this differently. The logs show:
1. `prompt called` at 20:31:39
2. Response returned at 20:31:42 with `stopReason="end_turn"`
But there's no log of chunks being sent (because I just added that log). The issue might be that the chunks ARE being sent but AionUI isn't showing them because there's something wrong with how they're serialized.
Wait — let me re-read the `serialize_params` function:
```python
def serialize_params(params: BaseModel) -> dict[str, Any]:
return params.model_dump(by_alias=True, exclude_none=True, exclude_defaults=True)
```
It uses `exclude_defaults=True`. Let me check what happens when we serialize an `AgentMessageChunk`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The serialization looks correct. Let me check if maybe the issue is that AionUI expects the agent message chunks to be sent BEFORE the PromptResponse, and maybe there's a race condition or the connection isn't working.
Actually, let me look at this from a different angle. Let me check the AionUI client side to see how it handles `session/update` notifications:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Let me check what the client does with `session_update`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Let me check how the AionUI client handles the `session_update` notification. Let me look at the Hermes agent code to see how it sends responses:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Let me take a step back and think about this. The user says "i am not getting any response". Looking at the logs:
1. The adapter IS working — `initialize`, `new_session`, and `prompt` are all being called successfully
2. The `PromptResponse` is being returned with `stopReason="end_turn"`
3. But the user doesn't see any text in AionUI
The issue is that AionUI expects to receive the response text via streaming chunks, but something is preventing the chunks from being displayed. Let me check if maybe the chunks need to be sent with a specific format or if there's an issue with the notification.
Actually, wait — let me look at the `SessionNotification` schema:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see — `SessionNotification` has a `discriminator="session_update"` on the `update` field. This means the `sessionUpdate` field in the JSON must match one of the literal values. My `AgentMessageChunk(session_update="agent_message_chunk")` should serialize to `{"sessionUpdate": "agent_message_chunk", ...}` which should match.
Let me test the full serialization of a `SessionNotification`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
The serialization looks correct. Let me now check if maybe the issue is that the AionUI client expects the `session/update` notification to have a specific format. Let me look at how the client processes these notifications:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Let me think about this differently. Maybe the issue is not with the ACP protocol but with how AionUI handles custom agents. Let me check if there's something specific about how AionUI expects responses.
Actually, I just realized something. Looking at the logs again:
```
20:31:39.919 › [ACP custom STDERR]: [ollama-acp] prompt called: session_id=..., prompt_blocks=1
20:31:42.126 › [AcpClient:custom:prompt]
20:31:42.126 › <- {"stopReason":"end_turn","usage":{"inputTokens":224,"outputTokens":42,"totalTokens":266},"userMessageId":"a2eca573-fda4-4eb4-94a5-dbd672b15378"}
```
The `AcpClient:custom:prompt` log and the `<-` response appear at the SAME timestamp (20:31:42.126). This means the response was returned immediately. But the Ollama API call took ~3 seconds (from 20:31:39 to 20:31:42). During those 3 seconds, streaming chunks should have been sent.
But wait — I don't see any logs about chunks being sent in the AionUI logs. This is because my debug log (`self._log`) goes to stderr, which AionUI captures as `[ACP custom STDERR]`. If chunks were being sent, I should see the "Sending chunk" log.
Actually, I just added that log in the latest patch. Let me check if the user is running the latest version of the script. But more importantly, let me check if maybe the issue is that `connection` is None when `prompt` is called.
Looking at the router code, the `connection` parameter is passed to the handler if it's in the signature. Let me verify:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see — the router uses `_resolve_handler` which checks if the method signature has a `params` parameter (legacy API). For the `prompt` method, it extracts parameters from the Pydantic model. But `connection` is NOT part of the `PromptRequest` model — it's injected separately.
Let me check how `run_agent` passes the connection to the handler:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see! The `AgentSideConnection` passes `self` (the connection) to the agent via `to_agent(self)` if `to_agent` is callable. But in my script, I'm passing `OllamaAgent()` directly, not a callable.
Wait, looking at line 45:
```python
agent = to_agent(self) if callable(to_agent) else to_agent
```
If `to_agent` is an `Agent` instance (not callable), it just uses it directly. But then how does the agent get access to the connection?
Let me check `build_agent_router`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I see! The router just routes requests to the agent's methods. The `connection` is NOT automatically passed. Looking at the `Agent` protocol in `interfaces.py`, the `prompt` method signature is:
```python
async def prompt(
self,
prompt_blocks: list[ContentBlock],
session_id: str,
connection: AgentSideConnection,
**kwargs: Any,
) -> PromptResponse: ...
```
So `connection` IS in the signature. But the router extracts parameters from the `PromptRequest` model, and `connection` is NOT part of that model. So how does it get passed?
Let me check `model_to_kwargs`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
So `model_to_kwargs` only extracts fields that are in the Pydantic model. `connection` is NOT in the `PromptRequest` model, so it won't be passed.
But wait — looking at the router code in `router.py`:
```python
async def wrapper(params: Any) -> Any:
if legacy_api:
_warn_legacy_handler(obj, attr)
model_obj = model.model_validate(params)
if legacy_api:
return await func(model_obj)
params = {k: getattr(model_obj, k) for k in model.model_fields if k != "field_meta"}
if meta := getattr(model_obj, "field_meta", None):
params.update(meta)
return await func(**params)
```
The router only passes fields from the Pydantic model. So `connection` is NOT being passed to `prompt`!
This means `connection` is `None` in my handler, and the streaming chunks are NOT being sent. The final `PromptResponse` is returned, but without any streaming content.
But wait — how does the Hermes agent send responses then? Let me check how Hermes does it:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Now I see it! The Hermes ACP adapter uses `self._conn` which is stored on the agent instance. It does NOT rely on `connection` being passed to the `prompt` method. Let me check how `_conn` is set:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Now I understand! The Hermes ACP adapter uses `on_connect(conn)` to store the connection, then uses `self._conn` later. This is the pattern I need to follow.
Looking back at `AgentSideConnection.__init__`:
```python
if on_connect := getattr(agent, "on_connect", None):
on_connect(self)
```
So if my agent has an `on_connect` method, it will be called with the connection. Then I can store it and use it later.
Let me update my script to use this pattern instead of relying on `connection` being passed to `prompt`:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
Now I understand the issue. The `connection` parameter is NOT being passed by the ACP router because it's not part of the `PromptRequest` schema. I need to use the `on_connect` pattern like Hermes does.
Let me update the script to store the connection in `on_connect` and use `self._conn` instead:
2026-05-15T20:39:55
ASSISTANT (hermes, kimi-for-coding)
I've fixed the root cause. The issue was that `connection` was not being passed to the `prompt` method because the ACP router only passes fields from the `PromptRequest` Pydantic model. I changed the script to use the `on_connect` pattern (like Hermes does) to store the connection and then use `self._conn` for streaming.
**Please try again in AionUI:**
1. Settings → AI Agents
2. Click **Detect Custom Agent**
3. Display Name: `Ollama Cloud`
4. Command: `/home/ubuntu/ollama-acp`
5. Click **Detect**
Then start a chat and send a message. You should now see the response streaming in.
If it still doesn't work, check the logs with:
```bash
sudo journalctl -u aionui -f | grep -i "ollama-acp"
```