feat(agent): implement tool-use orchestration loop - #103
Merged
Merged
Conversation
Svagtlys
marked this pull request as ready for review
September 26, 2026 08:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #79
Description
Implements the reason → act → observe tool-use orchestration loop: detect model tool calls, execute them against MCP servers, feed results back as provider-native tool messages, and re-invoke for final synthesis. Library-only primitive — no routes/lifespan wiring (Integration & Testing #1 composes it).
Implementation
octave.inferencetypes:ToolCall(id, name, arguments: str);Messagegainstool_calls/tool_call_id/nameand"tool"role;CompletionResult.tool_calls(additive, OpenAI-dialect)OpenAIAdapter: parseschoice.message.tool_callsfrom completion responses; serializes tool-carrying messages to provider payloads withexclude_none(strict local engines reject null tool keys) and the function-call envelopeoctave.tools.errors:ToolErrorbase introduced;ToolTranslationErrorre-based under it (backward-compatible)octave.agent(new package): composition layer and future Agent Manager homeToolLoop— round mechanics, provider-invariant transcript ordering,max_tool_roundslimit raisingToolLoopLimitErrorwith partial transcript; two-tier error split (Tier-1 model-correctable →Error:-prefixed tool messages; Tier-2 fatal → raise)ToolExecutorProtocol — execution seam; implementations never raise for tool-level failuresMcpToolExecutor— wrapsToolRegistry; joins text blocks,(no output)sentinel,McpError → ToolOutcome(is_error=True)conversiontests/agent/test_package.py) proves noopenai/mcpimports; onlymcp_executor.pytouchesoctave.mcpdocs/ARCHITECTURE.md:octave.agentsection + MCP Connector schema-translation status updatedReferences
.agents/specs/2026-09-25-tool-use-orchestration-loop-design.md.agents/specs/2026-09-25-tool-use-orchestration-loop.mdChecklist
ruff check src tests)mypy src, 54 files)Notes for reviewer
tool_callsmessage, N+1 completions). The test was corrected to match the spec, which the implementation satisfies.style:commit swept inplans/2026-09-25-issue-concurrent-tool-execution.md(deferred concurrent-execution issue draft referenced by the design doc).