Skip to content

feat: AD4M AI-assistant runtime — /v1 tool-calling + server-side subsystem (verified e2e) - #875

Draft
HexaField wants to merge 6 commits into
feat/openai-compat-endpointfrom
feat/ai-assistant-runtime
Draft

feat: AD4M AI-assistant runtime — /v1 tool-calling + server-side subsystem (verified e2e)#875
HexaField wants to merge 6 commits into
feat/openai-compat-endpointfrom
feat/ai-assistant-runtime

Conversation

@HexaField

@HexaField HexaField commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

AD4M AI-assistant runtime (stacked on #854)

Turns AD4M into a local AI-assistant host — verified end-to-end on Apple Silicon with Qwen2.5-7B. /v1 gains real tool calling; a server-side subsystem runs assistant turns inside the executor (persistent, concurrent, surviving client disconnect). The WE front end is coasys/we#95.

The AI is an assistant; AD4M agent stays the human (DID). Local models only (kalosm); no cloud dependency.

Commits

  1. /v1 tool/function calling (local, constrained decoding) — request tools/tool_choice/parallel_tool_calls; response tool_calls[] + finish_reason:"tool_calls" (oneshot + streaming). openai_compat/tool_grammar.rs compiles each tool's JSON-Schema at runtime into a kalosm ArcParser that masks the sampler, so a local model's output is always a schema-valid <tool_call> (Hermes/Qwen). auto/none recovered from text. No-tools path byte-identical; Cargo.toml unchanged.
  2. Assistant-run subsystem (rust-executor/src/assistant_runtime/) — watches perspectives for WE Message turns; the loop resolves Thread→Assistant→model→personalities/skills/MCP, assembles context, calls prompt_messages_stream (reusing the grammar), executes tools, folds results back, repeats; streams by rewriting Message.content (auto-publishes to WE); resumes from a durable RunState. we:// predicates match WE exactly. Boots beside MCP/REST, gated on --enable-assistants (default on).
  3. rmcp MCP clientMcpToolProvider connects an assistant's McpServers (stdio → child process; http/streamable/sse → streamable-HTTP; websocket unsupported), list_toolsToolDef, dispatches call_tool; failed servers logged + skipped.
  4. cli: --enable-assistants flag — thread the new Ad4mConfig field through the executor cli crate.
  5. fix: resolve model name/id before AIService — the loop passed Assistant.model_id straight through, but the LLM channel is keyed by the model uuid, so a name like "qwen2.5" never matched. Resolve via the /v1 model_selector first. Caught by the live end-to-end test.

Verified end-to-end (live — Apple Silicon, metal, Qwen2.5-7B-Instruct-Q4_K_M)

  • Tool calling: /v1/chat/completions + tool_choice:"required" → the real model returned a schema-valid get_weather(location, unit) tool call with content:null and finish_reason:"tool_calls".
  • Assistant loop: created an Assistant + Thread + completed user Message as we:// links → the runtime resolved everything, called the model, and wrote a real assistant reply (status:complete, RunState:done) back into the perspective — the whole watcher→loop→model→persist path, live.
  • Static: cargo check clean (pinned Rust 1.92); 34 unit tests pass (13 grammar + 21 runtime).
  • Not yet live-tested: MCP against a real external server (code compile-verified only); the WE UI visual render (needs the WE app).

cc @lucksus @data-bot-coasys

🤖 Generated with Claude Code

… decoding

Makes /v1/chat/completions a real OpenAI tool-calling endpoint for local models: request tools/tool_choice/parallel_tool_calls, response tool_calls + finish_reason "tool_calls" (oneshot + streaming). Local output is held to a schema-valid <tool_call> by compiling each tool's JSON-Schema into a kalosm ArcParser (openai_compat/tool_grammar.rs). Multi-turn tool results fold into prompt text; the no-tools path is unchanged; Cargo.toml unchanged (kalosm-sample via re-export).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 307b40f9-decf-4476-9c05-50c9c1e4313c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ai-assistant-runtime

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

A Rust subsystem in rust-executor that runs AI-assistant turns server-side — persistent, concurrent, surviving client disconnect. Watches perspectives for new WE Message turns, runs the context->model->tools->persist loop reusing the /v1 tool-calling machinery in-process, streams by rewriting Message.content (auto-publishes to WE), and resumes interrupted runs from a durable RunState.

- assistant_runtime/{entities,store,sdna,context,tools,run,registry,mod}
- Subject classes match the WE contract (coasys/we#95): Assistant/Personality/Skill/McpServer in we-root, Thread/Message in the neighbourhood perspective, we:// predicates.
- Built-in perspective/neighbourhood tools in-process; MCP client behind a trait seam (explicit error until rmcp client is wired — no silent stub).
- Boots beside the MCP/REST subsystems, gated on config.enable_assistants (default on).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HexaField HexaField changed the title feat(api/openai): tool/function calling on /v1 (local constrained decoding) feat: AD4M AI-assistant runtime — /v1 tool-calling + server-side run subsystem Jul 28, 2026
HexaField and others added 3 commits July 28, 2026 20:26
McpToolProvider now connects an assistant's configured McpServers via rmcp (stdio -> child process; http/streamable/sse -> streamable-HTTP; websocket unsupported by the pinned rmcp), discovers tools via list_tools -> ToolDef, and dispatches call_tool. Servers that fail to connect are logged and skipped (one bad server never fails the set). Enables rmcp client + transport-*-client features (server features retained). cargo check clean; 4 tools unit tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The assistant-runtime subsystem added Ad4mConfig.enable_assistants (rust-executor); the cli crate constructs Ad4mConfig and must supply it. Adds a --enable-assistants flag on the ad4m-executor bin (mirroring --enable-mcp; default on) and None in the dev/ad4m constructions. Fixes the E0063 that only surfaced building the downstream cli crate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The run loop passed Assistant.model_id straight to AIService, whose LLM channel is keyed by the registered model uuid — so a friendly name like 'qwen2.5' never matched (Model not found in LLM channel). Resolve via the /v1 model_selector (id | name | 'default') first, the same as the /v1 endpoint. Caught by the live loop end-to-end test on real hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HexaField HexaField changed the title feat: AD4M AI-assistant runtime — /v1 tool-calling + server-side run subsystem feat: AD4M AI-assistant runtime — /v1 tool-calling + server-side subsystem (verified e2e) Jul 28, 2026
…captured Qwen2.5 responses

Adds a ModelBackend seam (AiServiceBackend prod pass-through + FixtureModelBackend test) so the run loop can be driven by recorded responses. Two e2e tests run the FULL subsystem — real in-process PerspectiveInstance, real subject-class read/write, the real loop, real built-in tool execution, real persistence — against raw model text derived from Qwen2.5-7B /v1 responses captured live on Apple Silicon (tests/fixtures/):
- plain turn -> assistant message with the captured content, status complete, RunState done
- tool loop -> real perspective_add_link executed (sky_color_blue--hasColor-->blue added), post-tool final answer, toolCalls recorded, role:tool message persisted, RunState done
24 assistant_runtime tests pass (22 unit + 2 e2e). Production path unchanged (real backend is a faithful pass-through).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jhweir jhweir mentioned this pull request Aug 3, 2026
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant