Orchestrata Ultimate / Specs / 103-tool-calling-refactor

103-tool-calling-refactor: Tool-Calling Code Refactoring

A capability that lets orchestrata refactor an existing codebase in place by driving an LLM (DeepSeek deepseek-v4-pro) through function/tool calls: the model reads, searches, and outlines real source with sandboxed tools, applies exact-match edits, and verifies them — guided by a refactoring system prompt.

At a glance

Item Value
Spec directory specs/103-tool-calling-refactor/
Status line in the spec Draft
Requirement IDs defined 25
With a @traces citation in src/ 21 (84.0%)
With a @traces citation in tests/ 1 (4.0%)
Tracked files 2
RTM page 103-tool-calling-refactor

Reading this spec

This spec adds the ability to refactor an existing codebase in place by driving an LLM (DeepSeek deepseek-v4-pro) through function calls. The model reads, searches and outlines real source with sandboxed tools, applies exact-match edits and verifies them, guided by a refactoring system prompt. The gap it fills: the volk pipeline from Concierge to CodeDirector is a greenfield builder that scaffolds every intent as a new project and emits whole files, so it cannot modify an existing repository. The REFACTOR intent type, its classifier keywords, AST context injection and routing to U:Cd already exist, but there was no tool-calling layer, no refactor execution driver and no refactor system prompt.

Four user stories set the scope: a developer requests a targeted refactor, the refactor is confined to a safe scope, an operator watches and audits it, and it reuses the existing code-intelligence tools. The 25 requirement IDs (REQ-103-NNN) fall into groups. Protocol fields: Message gains optional tool_calls, tool_call_id and name, all defaulting to empty so the change is backward compatible, and the adapter parses tool_calls from the response and passes them up through the provider manager. Tools: a machine-readable TOOL_SCHEMAS list in OpenAI function-calling format and a RefactorTools.dispatch method, including ast_outline, edit_file and a run_check tool limited to whitelisted read-only commands (ruff, py_compile, pytest, mypy). Agent loop: the full assistant and tool message history persists across turns, and the entry point is refactor(task, root, ...). The prompt tells the model to observe before mutating, make minimal edits, and verify before finishing. Routing a REFACTOR intent to this capability from the CodeDirector path is marked as deferred.

The code is in the refactor package: refactor tools (9 requirements), the refactor agent, the provider protocols and the DeepSeek adapter. The requirements traceability matrix lists each ID. The spec's own status line reads Draft and it tracks 2 files. Measured coverage is 21 of 25 requirements cited by at least one @traces in src/ (84.0%), spread over 5 modules; the module citing the most of them is orchestrata_ultimate/refactor/tools (9 requirements). In tests/, 1 requirement is cited by a test-side @traces. 4 requirements have no citing symbol: REQ-103-004 (backward-compatible defaults), the two prompt requirements REQ-103-020 and REQ-103-021, and REQ-103-024 (ordered logging of tool calls); the behaviour may still exist in code that was never annotated.

Requirements

Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.

ID Done Requirement Traced by
REQ-103-001 no Message (SPEC-011) gains optional tool_calls, tool_call_id, and name fields 1
REQ-103-002 no ProviderRequest gains optional tools and tool_choice fields 1
REQ-103-003 no RawProviderResponse and ProviderResponse gain a tool_calls field 2
REQ-103-004 no All new protocol fields default to empty/None, so the added tool-calling surface is fully backward compatible none
REQ-103-005 no The DeepSeek adapter forwards tools/tool_choice to the API via request parameters 1
REQ-103-006 no The adapter serialises assistant tool_calls and tool-role messages (with tool_call_id/name) into the API payload 1
REQ-103-007 no The adapter parses choices[].message.tool_calls into RawProviderResponse.tool_calls, and ProviderManager propagates them through to ProviderResponse 1
REQ-103-008 no All RefactorTools file tools resolve paths under a sandbox root; any path escaping root is rejected 2
REQ-103-009 no Every tool returns a string and never raises into the loop — failures are returned as ERROR: ... text 1
REQ-103-010 no A machine-readable TOOL_SCHEMAS list (OpenAI function-calling format) describes every tool, and RefactorTools.dispatch(name, arguments) -> str executes one tool by name 2
REQ-103-011 no read_file(path) returns raw file contents so exact snippets can be copied for edits 1
REQ-103-012 no list_dir(path) and grep(pattern, path) provide discovery over .py files 2
REQ-103-013 no ast_outline(path) surfaces classes/functions with signatures and line numbers 1
REQ-103-014 no edit_file(path, old_string, new_string) replaces ONE exact, unique occurrence, rejecting the edit if old_string is absent or non-unique 1
REQ-103-015 no write_file(path, content) creates or overwrites a file (for new helper modules) 1
REQ-103-016 no run_check(command) runs a whitelisted, read-only verification command (ruff, py_compile, pytest, mypy) from root 1
REQ-103-017 no The loop sends the system prompt + task + TOOL_SCHEMAS, and while the model returns tool_calls, executes each via dispatch, appends one tool message per call keyed by tool_call_id, and re-invokes the model 1
REQ-103-018 no The loop terminates when the model returns content with no tool calls (status="completed"), after max_iterations (status="max_iterations"), or on a fatal error (status="error") 1
REQ-103-019 no The full assistant/tool message history is preserved across turns so the model retains continuity 1
REQ-103-020 no The refactoring system prompt instructs the model to OBSERVE before MUTATING (read/outline/grep first), make MINIMAL surgical edits via edit_file, preserve behavior unless asked otherwise, and VERIFY with run_check before finishing none
REQ-103-021 no The prompt forbids fabricating file contents and instructs the model to copy exact snippets from read_file for edit_file none
REQ-103-022 no refactor(task: str, root: str | Path, model: str = "deepseek-v4-pro", max_iterations: int = 25) -> RefactorResult runs the tool-use loop and returns a RefactorResult 1
REQ-103-023 no RefactorResult records files_changed, iterations, the ordered tool_calls trace, verified, and status 2
REQ-103-024 no Every tool call (name, arguments, truncated result) and model turn is logged via the SPEC-100 structured logger, in order none
REQ-103-025 no When intent classification yields IntentType.REFACTOR, the CodeDirector path MAY dispatch to this refactor capability instead of greenfield scaffolding — a deferred/future MAY requirement (wiring tracked separately); the refactor capability remains independently invocable via the refactor() entry point and a CLI regardless of this wiring 1

Code that traces this spec

Module Symbols Requirements
orchestrata_ultimate/core/protocols/providers 4 3
orchestrata_ultimate/orchestrator/intent_broker 1 1
orchestrata_ultimate/providers/adapters/deepseek_adapter 1 3
orchestrata_ultimate/refactor/agent 3 5
orchestrata_ultimate/refactor/tools 10 9

Checklists

checklists/requirements.md

The requirement list above comes from this file; 0 of 25 checkbox items are ticked.

Full spec text

Verbatim from specs/103-tool-calling-refactor/spec.md; headings are pushed down two levels.

SPEC-103: Tool-Calling Code Refactoring

Metadata


Overview

What

A capability that lets orchestrata refactor an existing codebase in place by driving an LLM (DeepSeek deepseek-v4-pro) through function/tool calls: the model reads, searches, and outlines real source with sandboxed tools, applies exact-match edits, and verifies them — guided by a refactoring system prompt.

Why

The volk pipeline (Concierge→…→CodeDirector) is a greenfield builder: every intent is scaffolded as a new project, and the Coder emits whole FILE: blocks (deepseek_coder_driver). It cannot modify an existing repository in place. The REFACTOR intent type, classifier keywords, AST context injection, and routing to U:Cd already exist (orchestrator/impact/, knowledge_graph/volk_context_injector.py), but there is no tool-calling layer, no refactor execution driver, and no refactor system prompt. A refactor requires the model to observe existing code and make surgical changes — which is precisely what tool calls enable and whole-file regeneration does not.

How
  1. Extend the provider protocol + DeepSeek adapter with OpenAI-compatible tool-calling (tools/tool_choice in, tool_calls out).
  2. Provide a small sandboxed tool registry the model can call: read / list / grep / AST outline (observe), edit_file exact-match + write_file (mutate), run_check (verify).
  3. Run a tool-use loop that sends the tools + a refactoring system prompt, executes each requested tool call, feeds results back, and iterates until the model returns a final answer or a turn budget is reached.
  4. Expose a refactor(task, root, ...) entry point returning a structured result (files touched, tool-call trace, verification outcome).

User Scenarios

US-001: Developer requests a targeted refactor

As a developer I want to ask orchestrata to "add type hints and docstrings to module X" So that the existing file is improved in place without regenerating it Acceptance Criteria:

US-002: Refactor confined to a safe scope

As a maintainer I want the refactor to be unable to touch anything outside the target directory So that an autonomous run cannot corrupt the wider repo or read secrets Acceptance Criteria:

US-003: Operator watches and audits the refactor

As an operator I want to see the model's tool calls and edits as they happen So that I can trust the change and debug a bad run Acceptance Criteria:

US-004: Refactor reuses the existing code-intelligence tools

As a core developer I want the refactor agent to use the existing AST/analysis tooling So that the model reasons over verified structure, not hallucinated layout Acceptance Criteria:


Data Models

Tool schema (OpenAI/DeepSeek function-calling, sent to the model)
{
  "type": "function",
  "function": {
    "name": "edit_file",
    "description": "Replace ONE exact, unique occurrence of old_string with new_string.",
    "parameters": {
      "type": "object",
      "properties": {
        "path": {"type": "string"},
        "old_string": {"type": "string"},
        "new_string": {"type": "string"}
      },
      "required": ["path", "old_string", "new_string"]
    }
  }
}
Tool-call envelope (returned by the model / parsed by the adapter)
{ "id": "call_abc", "type": "function",
  "function": {"name": "read_file", "arguments": "{\"path\": \"x.py\"}"} }
Conversation message fields (added to Message, SPEC-011)
Field Type Role Meaning
tool_calls list[dict] | None assistant tool calls the model requested
tool_call_id str | None tool the call this result answers
name str | None tool the tool's name
RefactorResult
Field Type Required Meaning
task str ✓ the refactor instruction
root str ✓ sandbox root the refactor ran in
files_changed list[str] ✓ files written/edited
iterations int ✓ tool-use loop turns consumed
tool_calls list[dict] ✓ ordered trace: name, arguments, result summary
verified bool | None ✓ result of the final run_check, or None if not run
final_message str ✓ the model's closing summary
status "completed" | "max_iterations" | "error" ✓ terminal status

Functional Requirements

FR-001 — Tool-calling protocol fields

The provider protocol MUST carry tool-calling data end to end.

FR-002 — DeepSeek adapter tool support
FR-003 — Sandboxed tool registry
FR-004 — Tool catalog

The registry MUST provide at minimum:

FR-005 — Tool-use loop
FR-006 — Refactoring system prompt
FR-007 — Entry point & result
FR-008 — Observability
FR-009 — Pipeline integration (future)

Error Conditions

ID Trigger Severity Handling
ERR-103-001 edit_file old_string not found WARNING Return ERROR: not found; model retries with corrected snippet
ERR-103-002 edit_file old_string not unique WARNING Return ERROR: not unique (N matches); model adds context
ERR-103-003 Path escapes sandbox root ERROR Reject with ERROR: path escapes sandbox; never touch the path
ERR-103-004 run_check command not whitelisted ERROR Reject; list permitted prefixes
ERR-103-005 run_check times out (120s) WARNING Return ERROR: command timed out; loop continues
ERR-103-006 Model exceeds max_iterations WARNING Stop with status=max_iterations; return partial trace + files changed
ERR-103-007 LLM call fails after retries (e.g. 429) ERROR Surface as status=error with the cause; do not leave a half-edited file unreported
ERR-103-008 Tool raises unexpectedly ERROR Caught; returned as ERROR: <type>: <msg> so the loop survives

API Contracts

def refactor(
    task: str,
    root: str | Path,
    model: str = "deepseek-v4-pro",
    max_iterations: int = 25,
) -> RefactorResult: ...

class RefactorTools:
    def __init__(self, root: str | Path) -> None: ...
    def dispatch(self, name: str, arguments: dict) -> str: ...
# read_file, list_dir, grep, ast_outline, edit_file, write_file, run_check

TOOL_SCHEMAS: list[dict]   # OpenAI/DeepSeek function specs

Security Requirements


Dependencies

Component Spec Purpose
Provider Manager SPEC-011 Carries tools/tool_calls; routes to DeepSeek
LLM Client Facade SPEC-028 The tool-use loop builds on the client path
Logging & Exceptions SPEC-100 Structured tool-call/turn logging
CXP / impact routing SPEC-004 / orchestrator.impact IntentType.REFACTOR classification + routing (integration, FR-009)
DeepSeek API external deepseek-v4-pro with OpenAI-compatible function calling

Testing Requirements


Definition of Done


Revision History

Version Date Author Changes
0.1.0 2026-05-28 Mohamed Initial spec — tool-calling refactor capability