Harness-Model Protocol Analysis
Analyzes the interface layer between agent frameworks (harness) and language models. This skill examines the wire protocol, message encoding, and agentic primitives that enable tool-augmented conversation.
Distinction from tool-interface-analysis
| tool-interface-analysis | harness-model-protocol | |------------------------|------------------------| | How tools are registered and discovered | How tool calls are encoded on the wire | | Schema generation (Pydantic → JSON Schema) | Schema transmission to LLM API | | Error feedback patterns | Response parsing and error extraction | | Retry mechanisms at tool level | Streaming mechanics and partial responses | | Tool execution orchestration | Message format translation |
Process
- Map message protocol — Identify wire format (OpenAI, Anthropic, custom)
- Trace tool call encoding — How tool calls are requested and parsed
- Analyze streaming mechanics — SSE, WebSocket, chunk handling
- Catalog agentic primitives — System prompts, scratchpads, interrupts
- Evaluate provider abstraction — How multi-LLM support is achieved
Message Protocol Analysis
Wire Format Families
OpenAI-Compatible (Chat Completions)
{
"model": "gpt-4",
"messages": [
{"role": "system", "content": "..."},
{"role": "user", "content": "..."},
{"role": "assistant", "content": "...", "tool_calls": [...]},
{"role": "tool", "tool_call_id": "...", "content": "..."}
],
"tools": [...],
"tool_choice": "auto" | "required" | {"type": "function", "function": {"name": "..."}}
}
Anthropic Messages API
{
"model": "claude-sonnet-4-20250514",
"system": "...", # System prompt separate from messages
"messages": [
{"role": "user", "content": "..."},
{"role": "assistant", "content": [
{"type": "text", "text": "..."},
{"type": "tool_use", "id": "...", "name": "...", "input": {...}}
]},
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "...", "content": "..."}
]}
],
"tools": [...]
}
Google Gemini (Generative AI)
{
"contents": [
{"role": "user", "parts": [{"text": "..."}]},
{"role": "model", "parts": [
{"text": "..."},
{"functionCall": {"name": "...", "args": {...}}}
]},
{"role": "user", "parts": [
{"functionResponse": {"name": "...", "response": {...}}}
]}
],
"tools": [{"functionDeclarations": [...]}]
}
Key Dimensions
| Dimension | OpenAI | Anthropic | Gemini | |-----------|--------|-----------|--------| | System prompt | In messages | Separate field | In contents (optional) | | Tool calls | tool_calls array | Content blocks | functionCall in parts | | Tool results | Role tool | Role user + tool_result | functionResponse | | Multi-tool | Single message | Single message | Single message | | Streaming | SSE data: {...} | SSE event: ... | SSE chunks |
Translation Patterns
Universal Message Type
@dataclass
class UniversalMessage:
role: Literal["system", "user", "assistant", "tool"]
content: str | list[ContentBlock]
tool_calls: list[ToolCall] | None = None
tool_call_id: str | None = None # For tool results
@dataclass
class ToolCall:
id: str
name: str
arguments: dict
class ProviderAdapter(Protocol):
def to_native(self, messages: list[UniversalMessage]) -> dict: ...
def from_native(self, response: dict) -> UniversalMessage: ...
Adapter Registry
ADAPTERS = {
"openai": OpenAIAdapter(),
"anthropic": AnthropicAdapter(),
"gemini": GeminiAdapter(),
}
def invoke(messages: list[UniversalMessage], provider: str) -> UniversalMessage:
adapter = ADAPTERS[provider]
native_request = adapter.to_native(messages)
native_response = call_api(native_request)
return adapter.from_native(native_response)
Tool Call Encoding
Request Encoding (Framework → LLM)
Schema Transmission Strategies
| Strategy | How tools reach LLM | Example | |----------|---------------------|---------| | Function calling API | Native tools parameter | OpenAI, Anthropic | | System prompt injection | Tools described in system message | ReAct prompting | | XML format | Tools in structured XML | Claude XML, custom | | JSON mode + schema | Output constrained to schema | Structured outputs |
Function Calling (Native)
def prepare_request(self, messages, tools):
return {
"messages": messages,
"tools": [
{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.parameters_schema
}
}
for tool in tools
],
"tool_choice": self.tool_choice
}
System Prompt Injection (ReAct)
TOOL_PROMPT = """
You have access to the following tools:
{tools_description}
To use a tool, respond with:
Thought: [your reasoning]
Action: [tool name]
Action Input: [JSON arguments]
After receiving the observation, continue reasoning or provide final answer.
"""
def prepare_request(self, messages, tools):
tools_desc = "\n".join(f"- {t.name}: {t.description}" for t in tools)
system = TOOL_PROMPT.format(tools_description=tools_desc)
return {"messages": [{"role": "system", "content": system}] + messages}
Response Parsing (LLM → Framework)
Function Call Extraction
def parse_response(self, response) -> ParsedResponse:
message = response.choices[0].message
if message.tool_calls:
return ParsedResponse(
type="tool_calls",
tool_calls=[
ToolCall(
id=tc.id,
name=tc.function.name,
arguments=json.loads(tc.function.arguments)
)
for tc in message.tool_calls
]
)
else:
return ParsedResponse(type="text", content=message.content)
ReAct Parsing (Regex-Based)
REACT_PATTERN = r"Action:\s*(\w+)\s*Action Input:\s*(.+?)(?=Observation:|$)"
def parse_react_response(self, content: str) -> ParsedResponse:
match = re.search(REACT_PATTERN, content, re.DOTALL)
if match:
tool_name = match.group(1).strip()
arguments = json.loads(match.group(2).strip())
return ParsedResponse(
type="tool_calls",
tool_calls=[ToolCall(id=str(uuid4()), name=tool_name, arguments=arguments)]
)
return ParsedResponse(type="text", content=content)
XML Parsing
def parse_xml_response(self, content: str) -> ParsedResponse:
root = ET.fromstring(f"<root>{content}</root>")
tool_use = root.find(".//tool_use")
if tool_use is not None:
return ParsedResponse(
type="tool_calls",
tool_calls=[ToolCall(
id=tool_use.get("id", str(uuid4())),
name=tool_use.find("name").text,
arguments=json.loads(tool_use.find("arguments").text)
)]
)
return ParsedResponse(type="text", content=content)
Tool Choice Constraints
| Constraint | Effect | Use Case | |------------|--------|----------| | auto | Model decides whether to call tools | General usage | | required | Model must call at least one tool | Force tool use | | none | Model cannot call tools | Planning phase | | {"function": {"name": "X"}} | Model must call specific tool | Guided execution |
Streaming Protocol Analysis
SSE (Server-Sent Events)
OpenAI Streaming
data: {"id":"chatcmpl-...","choices":[{"delta":{"content":"Hello"}}]}
data: {"id":"chatcmpl-...","choices":[{"delta":{"tool_calls":[{"index":0,"function":{"argu