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