Skip to content

tri-cli Phase 2: Direct Anthropic API (kill claude CLI dependency) #60

@gHashTag

Description

@gHashTag

Overview

Replace claude -p subprocess dependency with direct Anthropic Messages API calls from pure Zig. This is the critical unlock — after this, Claude CLI is no longer needed.

What exists (no new code needed — 2,147 LOC)

File LOC Status
src/vibeec/anthropic_client.zig 384 Messages API client, 8 tests
src/vibeec/streaming_sse.zig 413 SSE parser/formatter, 5 tests
src/vibeec/json_parser.zig 468 Recursive descent JSON, tested
src/vibeec/igla_tool_use_engine.zig 882 Tool execution engine, sandboxed

New code (~300 LOC)

tool_protocol.zig

Parse tool_use content blocks from Anthropic API response, format tool_result for next request.

// Parse from API response:
// {"type":"tool_use","id":"toolu_xxx","name":"Read","input":{"file_path":"src/main.zig"}}

// Format for next request:
// {"type":"tool_result","tool_use_id":"toolu_xxx","content":"file contents..."}

pub const ToolUseBlock = struct {
    id: []const u8,
    name: []const u8,
    input_json: []const u8,
};

pub fn parseToolUse(response_json: []const u8) ?ToolUseBlock { ... }
pub fn formatToolResult(tool_use_id: []const u8, content: []const u8) []const u8 { ... }

Wiring tasks

  1. Add tri-cli executable target to build.zig (link orphaned vibeec files)
  2. Wire: anthropic_client → SSE streaming → tool_protocoligla_tool_use_engine → loop
  3. Replace claude -p subprocess in agent_loop.zig with direct API call
  4. Read ANTHROPIC_API_KEY from environment

Agentic loop (core ~50 LOC)

while (true) {
    const response = try api.sendMessages(messages, tool_definitions);
    switch (response.stop_reason) {
        .end_turn => break,
        .tool_use => {
            const tool = parseToolUse(response);
            const result = try igla.execute(tool);
            messages.append(.{ .role = "tool", .content = formatToolResult(tool.id, result) });
        },
    }
}

Acceptance criteria

  • tri-cli binary compiles (new target in build.zig)
  • Sends prompt to api.anthropic.com/v1/messages directly (no claude binary)
  • Streaming response visible in terminal (SSE → text output)
  • Tool calls (Read, Bash, Write) executed via igla engine
  • Tool results fed back to API for multi-turn conversation
  • Agentic loop runs until end_turn or max turns
  • Works from Telegram bot (tri-bot can use direct API instead of CLI)

Architecture after Phase 2

BEFORE: tri-bot → claude CLI (TypeScript/Node.js) → Anthropic API
AFTER:  tri-bot → anthropic_client.zig (Pure Zig) → Anthropic API

~300 LOC new code connects ~2,500 LOC of existing tested code.

Depends on: #56 (merged)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions