Skip to content

Commit 67585de

Browse files
author
Javier Canizalez
committed
docs: refresh README and architecture
1 parent f10f418 commit 67585de

2 files changed

Lines changed: 291 additions & 355 deletions

File tree

ARCHITECTURE.md

Lines changed: 165 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,206 +1,214 @@
1-
# Architecture: fourmis-agents
1+
# Architecture: fourmis-agents-sdk
22

33
## Overview
44

5-
fourmis-agents is structured in 5 layers, from bottom (provider APIs) to top (public API).
5+
`fourmis-agents-sdk` is organized in layered components from provider SDKs up to the public `query()` API.
66

77
```
8-
┌─────────────────────────────────────────────────┐
9-
│ Layer 5: Public API │
10-
│ query() → AsyncGenerator<AgentMessage> │
11-
│ createMcpServer(), mcpTool() │
12-
├─────────────────────────────────────────────────┤
13-
│ Layer 4: Agent Loop │
14-
│ prompt → LLM → tool calls → execute → repeat │
15-
│ Permission checks, hooks, subagent spawn │
16-
├─────────────────────────────────────────────────┤
17-
│ Layer 3: Tool System │
18-
│ Built-in tools (Bash, Read, Write, Edit, │
19-
│ Glob, Grep) + MCP tools + subagent tools │
20-
├─────────────────────────────────────────────────┤
21-
│ Layer 2: Provider Adapters │
22-
│ Anthropic, OpenAI, Gemini adapters │
23-
│ Normalize: messages, tool calls, streaming │
24-
├─────────────────────────────────────────────────┤
25-
│ Layer 1: Provider APIs │
26-
│ @anthropic-ai/sdk, openai, @google/genai │
27-
└─────────────────────────────────────────────────┘
8+
┌──────────────────────────────────────────────────────────┐
9+
│ Layer 5: Public API │
10+
│ query(), Query controls, provider/tool/MCP exports │
11+
├──────────────────────────────────────────────────────────┤
12+
│ Layer 4: Agent Loop │
13+
│ prompt -> provider -> tool calls -> execution -> repeat │
14+
│ hooks, permissions, subagents, memory, budgets │
15+
├──────────────────────────────────────────────────────────┤
16+
│ Layer 3: Tool and Runtime Integration │
17+
│ built-in tools, MCP tools/resources, Task tools │
18+
├──────────────────────────────────────────────────────────┤
19+
│ Layer 2: Provider Adapters │
20+
│ Anthropic/OpenAI/Gemini normalization │
21+
├──────────────────────────────────────────────────────────┤
22+
│ Layer 1: Provider SDKs / HTTP APIs │
23+
│ @anthropic-ai/sdk, openai, @google/genai, OAuth endpoints│
24+
└──────────────────────────────────────────────────────────┘
2825
```
2926

30-
## Layer 1: Provider APIs
27+
## Layer 1: Provider SDKs / APIs
3128

32-
Official SDKs for each provider:
29+
- Anthropic: `@anthropic-ai/sdk`
30+
- OpenAI: `openai`
31+
- Gemini: `@google/genai` plus OAuth HTTP mode
3332

34-
```ts
35-
import Anthropic from "@anthropic-ai/sdk"; // Anthropic direct API
36-
import OpenAI from "openai"; // OpenAI
37-
import { GoogleGenAI } from "@google/genai"; // Gemini (API key mode)
38-
```
39-
40-
No subprocess spawning — we call APIs directly.
33+
Fourmis executes these directly (no mandatory subprocess model for host query execution).
4134

4235
## Layer 2: Provider Adapters
4336

44-
Each adapter implements `ProviderAdapter`, normalizing a provider's API into a common streaming interface:
45-
46-
```ts
47-
interface ProviderAdapter {
48-
name: string;
49-
chat(request: ChatRequest): AsyncGenerator<ChatChunk>;
50-
calculateCost(model: string, usage: TokenUsage): number;
51-
getContextWindow(model: string): number;
52-
supportsFeature(feature: ProviderFeature): boolean;
53-
}
54-
```
37+
Adapters implement a common interface (`ProviderAdapter`) to normalize:
5538

56-
The adapters handle translation of tool call formats (Anthropic's `content[].type = "tool_use"` vs OpenAI's `tool_calls[].function` vs Gemini's `functionCall`/`functionResponse` parts) and tool result formats transparently.
39+
- message exchange
40+
- tool-call shape
41+
- streaming chunks
42+
- usage/cost accounting
43+
- feature capability checks
5744

58-
The Gemini adapter operates in two modes:
59-
- **API key mode** — uses `@google/genai` SDK with `generateContentStream()`
60-
- **OAuth mode** — direct HTTP to Google's Code Assist endpoint (`cloudcode-pa.googleapis.com`) with SSE streaming, using tokens from `gemini login` CLI
45+
Key files:
46+
- `src/providers/types.ts`
47+
- `src/providers/anthropic.ts`
48+
- `src/providers/openai.ts`
49+
- `src/providers/gemini.ts`
50+
- `src/providers/registry.ts`
6151

62-
New providers can be added via `registerProvider()`.
52+
Provider registry is lazy and extensible via `registerProvider()`.
6353

64-
## Layer 3: Tool System
54+
## Layer 3: Tool and Runtime Integration
6555

6656
### Tool Registry
6757

68-
```ts
69-
class ToolRegistry {
70-
register(tool: ToolImplementation): void;
71-
getDefinitions(): ToolDefinition[];
72-
execute(name: string, input: unknown, context: ToolContext): Promise<ToolResult>;
73-
list(): string[];
74-
}
75-
```
58+
`ToolRegistry` provides registration, definition export, and execution dispatch.
7659

77-
6 built-in tools are available in 3 presets (`coding`, `readonly`, `minimal`). MCP tools and subagent tools (Task, TaskOutput, TaskStop) are registered dynamically at runtime.
60+
Key file:
61+
- `src/tools/registry.ts`
7862

79-
### Tool Context
63+
### Built-in Tools
8064

81-
```ts
82-
type ToolContext = {
83-
cwd: string;
84-
signal: AbortSignal;
85-
sessionId: string;
86-
env?: Record<string, string>;
87-
};
88-
```
65+
Current built-ins:
66+
67+
- `Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`
68+
- `NotebookEdit`, `WebFetch`, `WebSearch`
69+
- `TodoWrite`, `Config`, `AskUserQuestion`, `ExitPlanMode`
70+
71+
Preset resolution defaults to `claude_code` and can also accept explicit arrays.
72+
73+
Key files:
74+
- `src/tools/index.ts`
75+
- `src/tools/presets.ts`
76+
- `src/tools/*.ts`
77+
78+
### MCP Integration
79+
80+
`McpClientManager` connects configured servers and projects tools as namespaced tool IDs (`mcp__<server>__<tool>`), plus resource tools:
81+
82+
- `mcp__list_resources`
83+
- `mcp__read_resource`
84+
85+
Key files:
86+
- `src/mcp/client.ts`
87+
- `src/mcp/server.ts`
88+
- `src/mcp/types.ts`
89+
- `src/tools/mcp-resources.ts`
90+
91+
### Subagents
92+
93+
Subagent definitions are injected into runtime and surfaced through `Task`, `TaskOutput`, `TaskStop` tools.
94+
95+
Key files:
96+
- `src/agents/types.ts`
97+
- `src/agents/task-manager.ts`
98+
- `src/agents/tools.ts`
8999

90100
## Layer 4: Agent Loop
91101

92-
The core execution engine (`agent-loop.ts`). An `AsyncGenerator<AgentMessage>` that:
102+
`agent-loop.ts` is the core execution engine and emits Claude-compatible envelopes.
103+
104+
Main flow:
93105

94-
1. Sends messages to the LLM via the provider adapter
95-
2. Streams text deltas as events
96-
3. Collects tool calls from the response
97-
4. Fires `PreToolUse` hooks (can deny or modify input)
98-
5. Checks permissions via `PermissionManager`
99-
6. Executes tools via the registry
100-
7. Fires `PostToolUse` / `PostToolUseFailure` hooks
101-
8. Feeds results back to the LLM
102-
9. Repeats until no tool calls remain or limits are hit
106+
1. Initialize session/system state.
107+
2. Send conversation to selected provider adapter.
108+
3. Collect `assistant` text/tool-use blocks.
109+
4. Apply hooks (`PreToolUse` etc.) and permission decisions.
110+
5. Execute tool calls through registry.
111+
6. Append tool results as `user` content.
112+
7. Repeat until completion or a terminal condition.
113+
8. Emit terminal `result` (`success` or error subtype).
103114

104-
Limits: `maxTurns`, `maxBudgetUsd`, `AbortSignal`.
115+
Terminal controls/limits:
116+
117+
- `maxTurns`
118+
- `maxBudgetUsd`
119+
- abort signal
120+
- structured output retry bounds
121+
122+
Related files:
123+
- `src/agent-loop.ts`
124+
- `src/permissions.ts`
125+
- `src/hooks.ts`
126+
- `src/settings.ts`
127+
- `src/utils/session-store.ts`
128+
- `src/memory/*`
129+
- `src/skills/*`
105130

106131
## Layer 5: Public API
107132

108133
### `query()`
109134

110-
Single entry point — creates a provider, builds a tool registry, sets up permissions/hooks/MCP/subagents, and returns a `Query` (AsyncGenerator with `interrupt()` and `close()` control methods).
135+
`query()` builds runtime state and returns a `Query` (async iterable + controls).
136+
137+
Controls include:
138+
139+
- `interrupt()`, `close()`
140+
- `setPermissionMode()`, `setModel()`, `setMaxThinkingTokens()`
141+
- `supportedModels()`, `supportedCommands()`, `initializationResult()`
142+
- MCP runtime controls (`mcpServerStatus`, `toggleMcpServer`, `setMcpServers`, ...)
143+
144+
Key files:
145+
- `src/api.ts`
146+
- `src/query.ts`
147+
- `src/index.ts`
111148

112-
### `createMcpServer()` / `mcpTool()`
149+
## Message Contract
113150

114-
Create in-process MCP servers with Zod-typed tool definitions.
151+
Fourmis emits Claude-style `SDKMessage` unions (`AgentMessage`) with core envelopes:
115152

116-
### `registerProvider()` / `getProvider()`
153+
- `system` (`init`, `status`, hook/task metadata)
154+
- `assistant` (text/tool_use blocks)
155+
- `user` (tool_result blocks)
156+
- `stream_event`
157+
- `tool_progress`, `tool_use_summary`
158+
- `result` (`success` or error subtype)
117159

118-
Manage the provider registry. Built-in providers (`anthropic`, `openai`) are lazy-created on first use.
160+
Key file:
161+
- `src/types.ts`
119162

120-
## File Structure
163+
## Compatibility Harness Architecture
164+
165+
`tests/compat` provides strict side-by-side regression checks against `@anthropic-ai/claude-agent-sdk`.
166+
167+
Components:
168+
169+
- scenario definitions: `tests/compat/scenarios.ts`
170+
- pair runner + trace normalization: `tests/compat/harness.ts`
171+
- assertion engine (sdk + parity): `tests/compat/assertions.ts`
172+
- report/artifact writer: `tests/compat/report.ts`
173+
- orchestrator entrypoint: `tests/compat/run-compat.ts`
174+
175+
Artifacts:
176+
177+
- per-run `summary.json`
178+
- human-readable `report.md`
179+
- per-scenario normalized traces for both SDKs
180+
181+
## Updated Repository Map
121182

122183
```
123-
fourmis-agents/
184+
fourmis-agent-sdk/
124185
├── src/
125-
│ ├── index.ts # Public API exports
126-
│ ├── api.ts # query() implementation
127-
│ ├── query.ts # Query wrapper (AsyncGenerator + control methods)
128-
│ ├── types.ts # All core types (messages, permissions, options)
129-
│ ├── agent-loop.ts # Core agent execution loop
130-
│ ├── permissions.ts # Permission manager (6 modes + rules + callback)
131-
│ ├── hooks.ts # Hook system (12 event types)
132-
│ ├── settings.ts # Settings file loader (.claude/settings*.json)
133-
│ │
134-
│ ├── providers/
135-
│ │ ├── types.ts # ProviderAdapter interface, ChatRequest, ChatChunk
136-
│ │ ├── registry.ts # Provider registry (register/get)
137-
│ │ ├── anthropic.ts # Anthropic API adapter
138-
│ │ ├── openai.ts # OpenAI API adapter (API key + Codex OAuth)
139-
│ │ └── gemini.ts # Gemini API adapter (API key + CLI OAuth)
140-
│ │
141-
│ ├── tools/
142-
│ │ ├── registry.ts # ToolRegistry class
143-
│ │ ├── presets.ts # Tool presets (coding, readonly, minimal)
144-
│ │ ├── bash.ts # Shell execution via Bun.spawn()
145-
│ │ ├── read.ts # File reading with line numbers
146-
│ │ ├── write.ts # File creation/overwriting
147-
│ │ ├── edit.ts # String replacement editing
148-
│ │ ├── glob.ts # File pattern matching
149-
│ │ ├── grep.ts # Regex content search
150-
│ │ └── mcp-resources.ts # MCP resource listing/reading tools
151-
│ │
152-
│ ├── mcp/
153-
│ │ ├── index.ts # Re-exports
154-
│ │ ├── client.ts # MCP client (connect to external servers)
155-
│ │ ├── server.ts # In-process MCP server + tool() helper
156-
│ │ └── types.ts # MCP config types (stdio, SSE, HTTP, SDK)
157-
│ │
186+
│ ├── api.ts
187+
│ ├── agent-loop.ts
188+
│ ├── hooks.ts
189+
│ ├── index.ts
190+
│ ├── permissions.ts
191+
│ ├── query.ts
192+
│ ├── settings.ts
193+
│ ├── types.ts
158194
│ ├── agents/
159-
│ │ ├── index.ts # Re-exports
160-
│ │ ├── types.ts # AgentDefinition, BackgroundTask
161-
│ │ ├── task-manager.ts # Background task lifecycle
162-
│ │ └── tools.ts # Task, TaskOutput, TaskStop tool implementations
163-
│ │
164195
│ ├── auth/
165-
│ │ ├── login-openai.ts # OpenAI Codex login flow
166-
│ │ ├── openai-oauth.ts # OpenAI OAuth token management
167-
│ │ └── gemini-oauth.ts # Gemini CLI OAuth token management
168-
│ │
169-
│ └── utils/
170-
│ ├── cost.ts # Per-model cost tables
171-
│ └── system-prompt.ts # Default system prompt builder
172-
173-
├── tests/
174-
│ ├── agent-loop.test.ts
175-
│ ├── hooks.test.ts
176-
│ ├── integration.test.ts
196+
│ ├── mcp/
197+
│ ├── memory/
177198
│ ├── providers/
178-
│ │ ├── anthropic.test.ts
179-
│ │ ├── openai.test.ts
180-
│ │ └── openai-integration.test.ts
199+
│ ├── skills/
181200
│ ├── tools/
182-
│ │ ├── bash.test.ts
183-
│ │ ├── edit.test.ts
184-
│ │ ├── glob.test.ts
185-
│ │ ├── grep.test.ts
186-
│ │ ├── read.test.ts
187-
│ │ └── write.test.ts
188-
│ ├── mcp/
189-
│ │ ├── client.test.ts
190-
│ │ ├── sdk-server.test.ts
191-
│ │ └── integration.test.ts
201+
│ └── utils/
202+
├── tests/
192203
│ ├── agents/
193-
│ │ ├── task-manager.test.ts
194-
│ │ ├── tools.test.ts
195-
│ │ └── integration.test.ts
196204
│ ├── auth/
197-
├── openai-oauth.test.ts
198-
│ └── openai-codex-integration.test.ts
199-
── compare/ # SDK comparison scenarios
200-
── scenarios/
201-
202-
├── package.json
203-
── tsconfig.json
205+
│ ├── compat/
206+
── mcp/
207+
── providers/
208+
── tools/
209+
├── agent-loop.test.ts
210+
├── hooks.test.ts
211+
│ └── integration.test.ts
204212
├── README.md
205213
└── ARCHITECTURE.md
206214
```

0 commit comments

Comments
 (0)