@prateek_ai/agents-maker 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROMPT_TEMPLATE.md +143 -0
- package/README.md +92 -25
- package/agents/brain.md +90 -0
- package/agents/orchestrator.md +24 -3
- package/agents/planpro.md +91 -0
- package/bin/cli.js +40 -4
- package/claude/agents/architect.md +182 -0
- package/claude/agents/brain.md +97 -0
- package/claude/agents/code.md +185 -0
- package/claude/agents/compress.md +233 -0
- package/claude/agents/execute.md +164 -0
- package/claude/agents/orchestrate.md +434 -0
- package/claude/agents/planpro.md +98 -0
- package/claude/agents/review.md +141 -0
- package/claude/agents/ui.md +154 -0
- package/claude/agents/ux.md +151 -0
- package/claude/commands/architect.md +15 -0
- package/claude/commands/brain.md +15 -0
- package/claude/commands/code.md +15 -0
- package/claude/commands/compress.md +15 -0
- package/claude/commands/execute.md +15 -0
- package/claude/commands/orchestrate.md +15 -0
- package/claude/commands/planpro.md +15 -0
- package/claude/commands/review.md +15 -0
- package/claude/commands/ui.md +15 -0
- package/claude/commands/ux.md +15 -0
- package/config/agents.yaml +56 -0
- package/context_loaders/project_summary.py +5 -0
- package/docs/architecture.md +318 -0
- package/docs/domains.md +154 -0
- package/docs/workflows.md +548 -0
- package/examples/generic_project_lifecycle.md +518 -0
- package/examples/proof/README.md +138 -0
- package/examples/proof/implement-a-python-function-that-parses-an-iso-8/grade.md +14 -0
- package/examples/proof/implement-a-python-function-that-parses-an-iso-8/naive_output.md +211 -0
- package/examples/proof/implement-a-python-function-that-parses-an-iso-8/naive_prompt.txt +1 -0
- package/examples/proof/implement-a-python-function-that-parses-an-iso-8/structured_output.md +210 -0
- package/examples/proof/implement-a-python-function-that-parses-an-iso-8/structured_user.txt +35 -0
- package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/grade.md +14 -0
- package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/naive_output.md +274 -0
- package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/naive_prompt.txt +1 -0
- package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/structured_output.md +127 -0
- package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/structured_user.txt +35 -0
- package/package.json +10 -2
- package/platforms/antigravity.md +195 -0
- package/platforms/claude.md +305 -0
- package/platforms/openai.md +333 -0
- package/skills/analyze_repo.md +86 -86
- package/token_optimization/compressor.py +4 -7
- package/tools/_core.py +102 -0
- package/tools/compare_prompts.py +196 -0
- package/tools/generate_claude_agents.py +162 -0
- package/tools/generate_claude_md.py +14 -80
- package/tools/generate_platform_configs.py +26 -36
- package/tools/generate_prompt.py +79 -79
- package/tools/grade_proof.py +118 -0
- package/tools/init_project.py +11 -58
- package/tools/routing.py +103 -0
- package/tools/test_kit.py +392 -363
- package/tools/validate_kit.py +15 -43
- package/context_loaders/__pycache__/__init__.cpython-314.pyc +0 -0
- package/context_loaders/__pycache__/file_chunker.cpython-314.pyc +0 -0
- package/context_loaders/__pycache__/project_summary.cpython-314.pyc +0 -0
- package/context_loaders/__pycache__/repo_tree.cpython-314.pyc +0 -0
- package/token_optimization/__pycache__/compressor.cpython-314.pyc +0 -0
- package/tools/__pycache__/domain_utils.cpython-314.pyc +0 -0
- package/tools/__pycache__/generate_claude_md.cpython-314.pyc +0 -0
- package/tools/__pycache__/validate_kit.cpython-314.pyc +0 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Claude Integration Guide
|
|
2
|
+
|
|
3
|
+
How to use this kit with Anthropic Claude: Projects, Claude.ai, and the Anthropic API.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Companion Mode (Recommended)
|
|
8
|
+
|
|
9
|
+
The fastest way to use this kit with Claude. Run two commands once, then one command before every session.
|
|
10
|
+
|
|
11
|
+
### One-time setup (per project)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 1. Bootstrap the project
|
|
15
|
+
python agents-maker/tools/init_project.py
|
|
16
|
+
|
|
17
|
+
# 2. Paste system_prompt.md into Claude as the system prompt or Project Instructions
|
|
18
|
+
# (do this once — it contains all agents + skills pre-assembled)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Before every session
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python agents-maker/tools/generate_prompt.py "what you want to work on"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Copy the printed block and paste it as your next message to Claude. That's it.
|
|
28
|
+
|
|
29
|
+
**What you get back from Claude in Companion Mode:**
|
|
30
|
+
|
|
31
|
+
Every response ends with a structured block:
|
|
32
|
+
```
|
|
33
|
+
---
|
|
34
|
+
[Companion] Phase: implementation | Domain: software | Est. token budget: ~42%
|
|
35
|
+
|
|
36
|
+
What to do next (pick one):
|
|
37
|
+
[Recommended] A: Write unit tests for the new middleware
|
|
38
|
+
Command: python agents-maker/tools/generate_prompt.py "write tests for rate-limiting middleware"
|
|
39
|
+
|
|
40
|
+
B: Open Phase 4 review on the full auth service
|
|
41
|
+
C: Document rate-limit config in the runbook
|
|
42
|
+
---
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
You always know what to do next. Paste the `Command:` from option A to continue.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Option A — Claude Projects (claude.ai)
|
|
50
|
+
|
|
51
|
+
Claude Projects lets you set a persistent system prompt. This is the recommended zero-code integration — one paste, no file uploads needed.
|
|
52
|
+
|
|
53
|
+
### Setup steps
|
|
54
|
+
|
|
55
|
+
**1. Create a project**
|
|
56
|
+
|
|
57
|
+
In Claude.ai, create a new Project. Name it something like "Dev Assistant" or after your project.
|
|
58
|
+
|
|
59
|
+
**2. Set the Project Instructions**
|
|
60
|
+
|
|
61
|
+
Open Project Settings → Instructions. Paste the entire contents of `system_prompt.md` as the Project Instructions.
|
|
62
|
+
|
|
63
|
+
That's it — `system_prompt.md` contains all 8 agents and 12 skills pre-assembled (~28K tokens). No individual file uploads needed.
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
# Copy the full contents of system_prompt.md and paste here:
|
|
67
|
+
cat agents-maker/system_prompt.md | pbcopy # macOS
|
|
68
|
+
type agents-maker\system_prompt.md | clip # Windows
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**3. Start a session**
|
|
72
|
+
|
|
73
|
+
Fill in `PROMPT_TEMPLATE.md` and paste it as your first message. Or use the CLI:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python agents-maker/tools/generate_prompt.py "your task here"
|
|
77
|
+
# Copy the printed block → paste as your message
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### Keeping your system prompt current
|
|
83
|
+
|
|
84
|
+
When you add new agents or skills to the kit, regenerate `system_prompt.md` and repaste it into Project Instructions:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
python agents-maker/tools/init_project.py --update
|
|
88
|
+
# Then copy the updated system_prompt.md into Project Instructions
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Run `python tools/validate_kit.py` first to confirm all 8 integrity checks pass before regenerating.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Option B — Claude API (programmatic)
|
|
96
|
+
|
|
97
|
+
### Minimal example
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import anthropic
|
|
101
|
+
from pathlib import Path
|
|
102
|
+
|
|
103
|
+
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from env
|
|
104
|
+
|
|
105
|
+
def load_agent_kit() -> str:
|
|
106
|
+
"""Load orchestrator + all agent specs + skills as system context."""
|
|
107
|
+
parts = []
|
|
108
|
+
for path in [
|
|
109
|
+
"agents/orchestrator.md",
|
|
110
|
+
"agents/code_agent.md",
|
|
111
|
+
"agents/ui_agent.md",
|
|
112
|
+
"agents/ux_agent.md",
|
|
113
|
+
"agents/architect_agent.md",
|
|
114
|
+
"agents/compression_agent.md",
|
|
115
|
+
]:
|
|
116
|
+
parts.append(f"# {path}\n\n{Path(path).read_text()}")
|
|
117
|
+
for skill_file in Path("skills").glob("*.md"):
|
|
118
|
+
parts.append(f"# {skill_file}\n\n{skill_file.read_text()}")
|
|
119
|
+
return "\n\n---\n\n".join(parts)
|
|
120
|
+
|
|
121
|
+
system_prompt = load_agent_kit()
|
|
122
|
+
|
|
123
|
+
response = client.messages.create(
|
|
124
|
+
model="claude-sonnet-4-6",
|
|
125
|
+
max_tokens=4096,
|
|
126
|
+
system=system_prompt,
|
|
127
|
+
messages=[
|
|
128
|
+
{
|
|
129
|
+
"role": "user",
|
|
130
|
+
"content": (
|
|
131
|
+
"## Project State\n<paste project_summary.py output here>\n\n"
|
|
132
|
+
"Task: Add soft-delete to UserService."
|
|
133
|
+
),
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
)
|
|
137
|
+
print(response.content[0].text)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### With token optimization (using compressor.py)
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from token_optimization.compressor import Compressor, ContextBlock, FileEntry, PolicyLoader
|
|
144
|
+
from context_loaders.repo_tree import list_files
|
|
145
|
+
from context_loaders.file_chunker import chunk_files
|
|
146
|
+
|
|
147
|
+
# Load policy
|
|
148
|
+
loader = PolicyLoader()
|
|
149
|
+
loader.load()
|
|
150
|
+
policy = loader.get_workflow_policy("feature_implementation")
|
|
151
|
+
|
|
152
|
+
# Build context block
|
|
153
|
+
files = chunk_files(list_files("/your/repo", filter_paths=["src/"]))
|
|
154
|
+
block = ContextBlock(
|
|
155
|
+
project_state=project_summary,
|
|
156
|
+
files=[FileEntry(path=f["path"], content=f["content"]) for f in files],
|
|
157
|
+
conversation_state=conversation_state,
|
|
158
|
+
active_query="Add soft-delete to UserService",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
compressor = Compressor(policy)
|
|
162
|
+
compressed_context, report = compressor.compress(block)
|
|
163
|
+
|
|
164
|
+
# Send to Claude
|
|
165
|
+
response = client.messages.create(
|
|
166
|
+
model="claude-sonnet-4-6",
|
|
167
|
+
max_tokens=4096,
|
|
168
|
+
system=system_prompt,
|
|
169
|
+
messages=[{"role": "user", "content": compressed_context}],
|
|
170
|
+
)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Token-optimized defaults for Claude
|
|
176
|
+
|
|
177
|
+
### Concise mode system prompt suffix
|
|
178
|
+
|
|
179
|
+
Append to the orchestrator system prompt to enable concise mode by default:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
Output style: concise_bullets
|
|
183
|
+
Max response length: 600 tokens
|
|
184
|
+
Omit introductory sentences. Start all responses with the first finding or action.
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Context window guidance
|
|
188
|
+
|
|
189
|
+
| Claude model | Max input tokens | Recommended max_input_tokens policy |
|
|
190
|
+
|---|---|---|
|
|
191
|
+
| claude-haiku-4-5 | 200K | 60,000 |
|
|
192
|
+
| claude-sonnet-4-6 | 200K | 100,000 |
|
|
193
|
+
| claude-opus-4-7 | 200K | 150,000 |
|
|
194
|
+
|
|
195
|
+
Set `max_input_tokens` in `token_policies.yaml` well below the model limit to leave room for the system prompt and output.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Using extended thinking (Claude Sonnet / Opus)
|
|
200
|
+
|
|
201
|
+
For complex architecture tasks, enable extended thinking:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
response = client.messages.create(
|
|
205
|
+
model="claude-sonnet-4-6",
|
|
206
|
+
max_tokens=16000,
|
|
207
|
+
thinking={"type": "enabled", "budget_tokens": 10000},
|
|
208
|
+
system=system_prompt,
|
|
209
|
+
messages=[...],
|
|
210
|
+
)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Route only to `architect_agent` when thinking is enabled — it is expensive and most specialist tasks do not benefit.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Option C — Claude.ai Free Tier (no Projects access)
|
|
218
|
+
|
|
219
|
+
If you are on the Claude.ai free plan and do not have access to Projects, use this approach each session:
|
|
220
|
+
|
|
221
|
+
**1. Open a new Claude.ai conversation.**
|
|
222
|
+
|
|
223
|
+
**2. Paste `system_prompt.md` as your very first message** (before describing your task):
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
# Paste the full contents of agents-maker/system_prompt.md here as your first message.
|
|
227
|
+
# On macOS:
|
|
228
|
+
cat agents-maker/system_prompt.md | pbcopy
|
|
229
|
+
|
|
230
|
+
# On Windows:
|
|
231
|
+
type agents-maker\system_prompt.md | clip
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Send this message first. Claude will acknowledge the agent kit and wait for your task.
|
|
235
|
+
|
|
236
|
+
**3. Send your task using `PROMPT_TEMPLATE.md`:**
|
|
237
|
+
|
|
238
|
+
Open `PROMPT_TEMPLATE.md`, fill in the blanks, and send it as your second message. Or use the CLI:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
python agents-maker/tools/generate_prompt.py "your task here"
|
|
242
|
+
# Copy the printed block → paste as your second message
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Limitations vs. Option A (Projects):** The system prompt uses ~6K–24K tokens of your context window each session. On free-tier models, this leaves less room for file content and conversation history. Use `context_loaders/file_chunker.py` with `--max-lines 100` to keep file snippets small.
|
|
246
|
+
|
|
247
|
+
**Tip:** Save a `project_state.md` at the end of each session by copying the Orchestrator's final state block. Paste it at the start of the next session (after `system_prompt.md`) to resume without replaying history.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Routing without a project (API-only)
|
|
252
|
+
|
|
253
|
+
If you cannot use Projects, prepend the relevant agent spec inline:
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
specialist_prompt = Path("agents/code_agent.md").read_text()
|
|
257
|
+
user_message = f"{specialist_prompt}\n\n---\n\n{context}\n\n{user_query}"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
This is less elegant but fully functional.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Minimal Lifecycle Invocation
|
|
265
|
+
|
|
266
|
+
You do not need to specify a domain or configure anything beyond a task description. The Orchestrator detects the domain automatically from your message.
|
|
267
|
+
|
|
268
|
+
### Example — auto-detected domain
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
User: "Help me write a product requirements document for a mobile checkout flow."
|
|
272
|
+
|
|
273
|
+
Orchestrator behavior:
|
|
274
|
+
1. Scores signals: "product" (strong), "requirements" (strong), "mobile" (weak) → domain = product_design, confidence = high
|
|
275
|
+
2. Produces task_profile and asks 3–5 scoping questions (Phase 0, qa_brief style)
|
|
276
|
+
3. Awaits user approval before advancing to Phase 1
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
No domain hint required. Just describe the task.
|
|
280
|
+
|
|
281
|
+
### Example — domain hint prefix
|
|
282
|
+
|
|
283
|
+
If auto-detection might be ambiguous, prefix your message with `[domain: <key>]`:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
[domain: ops_process] Write an SOP for our employee offboarding process.
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Valid domain keys: `software`, `content`, `research`, `data_analytics`, `product_design`, `marketing`, `ops_process`. To add a custom domain, see [`docs/domains.md`](../docs/domains.md).
|
|
290
|
+
|
|
291
|
+
### Example — resuming a prior session
|
|
292
|
+
|
|
293
|
+
Paste the contents of a saved `project_state.md` file as your opening message:
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
[Paste contents of project_state.md here]
|
|
297
|
+
|
|
298
|
+
Continue from where we left off.
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The Orchestrator detects the `project_state.md` format, loads the state, and resumes at the recorded `current_phase` without replaying history.
|
|
302
|
+
|
|
303
|
+
### Adding `domain_profiles.yaml` to project knowledge (Claude Projects)
|
|
304
|
+
|
|
305
|
+
For the Orchestrator to load domain profiles at runtime, add `config/domain_profiles.yaml` to your Project knowledge documents alongside the other config files. Without it, the Orchestrator falls back to its built-in inline defaults (same 7 domains, same confidence thresholds).
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# OpenAI Integration Guide
|
|
2
|
+
|
|
3
|
+
How to use this kit with OpenAI: Chat Completions API, Assistants API, and Responses API (Agents SDK).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Using Companion Mode on OpenAI
|
|
8
|
+
|
|
9
|
+
Companion Mode works the same on OpenAI as on any other platform. Every response ends with a structured `[Companion]` block offering three ranked next steps. Here is the minimal setup using the Chat Completions API:
|
|
10
|
+
|
|
11
|
+
### One-time setup
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python agents-maker/tools/init_project.py
|
|
15
|
+
# Generates system_prompt.md — load this as the system role every session
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Before every session
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
python agents-maker/tools/generate_prompt.py "your task here"
|
|
22
|
+
# Copy the printed block → send as the user message
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Minimal Chat Completions example
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from openai import OpenAI
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
client = OpenAI() # reads OPENAI_API_KEY from env
|
|
32
|
+
|
|
33
|
+
system_prompt = Path("agents-maker/system_prompt.md").read_text(encoding="utf-8")
|
|
34
|
+
|
|
35
|
+
# Generate a routed prompt with the CLI, then send it:
|
|
36
|
+
user_message = Path("my_prompt.txt").read_text(encoding="utf-8")
|
|
37
|
+
|
|
38
|
+
response = client.chat.completions.create(
|
|
39
|
+
model="gpt-4o",
|
|
40
|
+
messages=[
|
|
41
|
+
{"role": "system", "content": system_prompt},
|
|
42
|
+
{"role": "user", "content": user_message},
|
|
43
|
+
],
|
|
44
|
+
max_tokens=4096,
|
|
45
|
+
)
|
|
46
|
+
print(response.choices[0].message.content)
|
|
47
|
+
# → Response ends with [Companion] block: three ranked next steps
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The `system_prompt.md` contains all 8 agents + 12 skills pre-assembled. Pass it once as the `system` role. Use `generate_prompt.py` output as the `user` role each turn. For multi-turn sessions, append prior `assistant` + `user` messages to the `messages` list normally.
|
|
51
|
+
|
|
52
|
+
See [platforms/claude.md](claude.md) for the full Companion Mode walkthrough and lifecycle example.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Option A — Chat Completions API (simplest)
|
|
57
|
+
|
|
58
|
+
No assistant setup required. Load agent specs as the system message.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from openai import OpenAI
|
|
62
|
+
from pathlib import Path
|
|
63
|
+
|
|
64
|
+
client = OpenAI() # reads OPENAI_API_KEY from env
|
|
65
|
+
|
|
66
|
+
def load_orchestrator_system() -> str:
|
|
67
|
+
parts = [Path("agents/orchestrator.md").read_text()]
|
|
68
|
+
for path in Path("agents").glob("*.md"):
|
|
69
|
+
if path.name != "orchestrator.md":
|
|
70
|
+
parts.append(f"# {path.name}\n\n{path.read_text()}")
|
|
71
|
+
for path in Path("skills").glob("*.md"):
|
|
72
|
+
parts.append(f"# {path.name}\n\n{path.read_text()}")
|
|
73
|
+
return "\n\n---\n\n".join(parts)
|
|
74
|
+
|
|
75
|
+
response = client.chat.completions.create(
|
|
76
|
+
model="gpt-4o",
|
|
77
|
+
messages=[
|
|
78
|
+
{"role": "system", "content": load_orchestrator_system()},
|
|
79
|
+
{"role": "user", "content": f"{project_summary}\n\nTask: {user_task}"},
|
|
80
|
+
],
|
|
81
|
+
max_tokens=4096,
|
|
82
|
+
)
|
|
83
|
+
print(response.choices[0].message.content)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Option B — Assistants API
|
|
89
|
+
|
|
90
|
+
Create one Assistant per agent. The Orchestrator assistant calls specialist assistants via tool calls or by spawning threads.
|
|
91
|
+
|
|
92
|
+
### Step 1 — Create assistants
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from openai import OpenAI
|
|
96
|
+
from pathlib import Path
|
|
97
|
+
|
|
98
|
+
client = OpenAI()
|
|
99
|
+
|
|
100
|
+
AGENT_FILES = {
|
|
101
|
+
"orchestrator": "agents/orchestrator.md",
|
|
102
|
+
"code_agent": "agents/code_agent.md",
|
|
103
|
+
"ui_agent": "agents/ui_agent.md",
|
|
104
|
+
"ux_agent": "agents/ux_agent.md",
|
|
105
|
+
"architect_agent": "agents/architect_agent.md",
|
|
106
|
+
"compression_agent": "agents/compression_agent.md",
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
assistants = {}
|
|
110
|
+
for name, path in AGENT_FILES.items():
|
|
111
|
+
instructions = Path(path).read_text()
|
|
112
|
+
# Append skill cards to each agent's instructions
|
|
113
|
+
# (Only skills listed in config/agents.yaml for that agent)
|
|
114
|
+
asst = client.beta.assistants.create(
|
|
115
|
+
name=name,
|
|
116
|
+
instructions=instructions,
|
|
117
|
+
model="gpt-4o",
|
|
118
|
+
tools=[], # add file_search or code_interpreter if needed
|
|
119
|
+
)
|
|
120
|
+
assistants[name] = asst.id
|
|
121
|
+
print(f"Created {name}: {asst.id}")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Save the returned IDs to a local file (e.g., `.assistant_ids.json`) for reuse.
|
|
125
|
+
|
|
126
|
+
### Step 2 — Run a thread
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import json, time
|
|
130
|
+
|
|
131
|
+
ids = json.loads(Path(".assistant_ids.json").read_text())
|
|
132
|
+
|
|
133
|
+
thread = client.beta.threads.create()
|
|
134
|
+
client.beta.threads.messages.create(
|
|
135
|
+
thread_id=thread.id,
|
|
136
|
+
role="user",
|
|
137
|
+
content=f"{project_summary}\n\nTask: {user_task}",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
run = client.beta.threads.runs.create(
|
|
141
|
+
thread_id=thread.id,
|
|
142
|
+
assistant_id=ids["orchestrator"],
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Poll for completion
|
|
146
|
+
while run.status in ("queued", "in_progress"):
|
|
147
|
+
time.sleep(1)
|
|
148
|
+
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
|
|
149
|
+
|
|
150
|
+
messages = client.beta.threads.messages.list(thread_id=thread.id)
|
|
151
|
+
print(messages.data[0].content[0].text.value)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Step 3 — Register routing as a tool (optional)
|
|
155
|
+
|
|
156
|
+
To enable the Orchestrator to explicitly call specialists, define a tool:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
route_tool = {
|
|
160
|
+
"type": "function",
|
|
161
|
+
"function": {
|
|
162
|
+
"name": "route_to_specialist",
|
|
163
|
+
"description": "Invoke a specialist agent with a structured context block.",
|
|
164
|
+
"parameters": {
|
|
165
|
+
"type": "object",
|
|
166
|
+
"properties": {
|
|
167
|
+
"agent": {
|
|
168
|
+
"type": "string",
|
|
169
|
+
"enum": ["code_agent", "ui_agent", "ux_agent", "architect_agent", "compression_agent"],
|
|
170
|
+
"description": "Which specialist to invoke."
|
|
171
|
+
},
|
|
172
|
+
"context_block": {
|
|
173
|
+
"type": "string",
|
|
174
|
+
"description": "Full context block to send to the specialist."
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
"required": ["agent", "context_block"],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Add to orchestrator assistant:
|
|
183
|
+
client.beta.assistants.update(
|
|
184
|
+
assistant_id=ids["orchestrator"],
|
|
185
|
+
tools=[route_tool],
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Handle the tool call in your run loop and spawn a new thread to the appropriate specialist assistant.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Option C — Responses API / Agents SDK
|
|
194
|
+
|
|
195
|
+
The OpenAI Agents SDK (beta) supports multi-agent handoffs natively.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from agents import Agent, Runner
|
|
199
|
+
|
|
200
|
+
orchestrator = Agent(
|
|
201
|
+
name="Orchestrator",
|
|
202
|
+
instructions=Path("agents/orchestrator.md").read_text(),
|
|
203
|
+
model="gpt-4o",
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
code_agent = Agent(
|
|
207
|
+
name="CodeAgent",
|
|
208
|
+
instructions=Path("agents/code_agent.md").read_text(),
|
|
209
|
+
model="gpt-4o",
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Register specialists as handoff targets
|
|
213
|
+
orchestrator.handoffs = [code_agent]
|
|
214
|
+
|
|
215
|
+
result = Runner.run_sync(orchestrator, f"{project_summary}\n\nTask: {user_task}")
|
|
216
|
+
print(result.final_output)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Token policy integration
|
|
222
|
+
|
|
223
|
+
Apply `token_policies.yaml` via `compressor.py` before constructing messages:
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from token_optimization.compressor import Compressor, ContextBlock, PolicyLoader
|
|
227
|
+
|
|
228
|
+
loader = PolicyLoader()
|
|
229
|
+
loader.load()
|
|
230
|
+
policy = loader.get_workflow_policy("feature_implementation")
|
|
231
|
+
compressor = Compressor(policy)
|
|
232
|
+
compressed, report = compressor.compress(context_block)
|
|
233
|
+
|
|
234
|
+
messages = [
|
|
235
|
+
{"role": "system", "content": system_prompt},
|
|
236
|
+
{"role": "user", "content": compressed},
|
|
237
|
+
]
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Token and cost guidance
|
|
243
|
+
|
|
244
|
+
| Model | Context window | Recommended max_input_tokens |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| gpt-4o | 128K | 50,000 |
|
|
247
|
+
| gpt-4o-mini | 128K | 60,000 |
|
|
248
|
+
| o3 / o4-mini | 200K | 100,000 |
|
|
249
|
+
|
|
250
|
+
Set `max_input_tokens` in `token_policies.yaml` to leave at least 4K tokens for the output.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Mapping agents.yaml to OpenAI primitives
|
|
255
|
+
|
|
256
|
+
| `agents.yaml` field | OpenAI equivalent |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `name` | `Assistant.name` |
|
|
259
|
+
| `description` | `Assistant.description` |
|
|
260
|
+
| `skills` | Included inline in `Assistant.instructions` |
|
|
261
|
+
| `routing_tags` | Used in Orchestrator's `route_to_specialist` tool logic |
|
|
262
|
+
| `cost_tier: high` | Consider `o3` or `gpt-4o`; `cost_tier: low` → `gpt-4o-mini` |
|
|
263
|
+
| `default_output_style` | Append style instructions to `Assistant.instructions` |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Minimal Lifecycle Invocation
|
|
268
|
+
|
|
269
|
+
You do not need to specify a domain. The Orchestrator scores the user's message against `config/domain_profiles.yaml` automatically.
|
|
270
|
+
|
|
271
|
+
### Example — auto-detected domain
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
# No domain configuration needed — just describe the task
|
|
275
|
+
user_task = "Write a go-to-market strategy brief for our new developer tool."
|
|
276
|
+
|
|
277
|
+
response = client.chat.completions.create(
|
|
278
|
+
model="gpt-4o",
|
|
279
|
+
messages=[
|
|
280
|
+
{"role": "system", "content": load_orchestrator_system()},
|
|
281
|
+
{"role": "user", "content": user_task},
|
|
282
|
+
],
|
|
283
|
+
)
|
|
284
|
+
# Orchestrator detects domain = marketing (signals: "strategy", "brief" → medium confidence)
|
|
285
|
+
# then asks 3–5 scoping questions before producing task_profile
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Example — domain hint prefix
|
|
289
|
+
|
|
290
|
+
For unambiguous routing, prefix the user message:
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
user_task = "[domain: ops_process] Write a runbook for our database failover procedure."
|
|
294
|
+
# Orchestrator skips scoring, uses ops_process directly with domain_confidence = high
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Storing project_state across threads (Assistants API)
|
|
298
|
+
|
|
299
|
+
The Orchestrator emits a `project_state.md` snapshot after each approved phase. To persist it across Assistants API sessions, attach it as a file on the thread:
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
# Save project_state.md emitted by the Orchestrator
|
|
303
|
+
project_state_content = extract_project_state_from_response(last_response)
|
|
304
|
+
Path("project_state.md").write_text(project_state_content)
|
|
305
|
+
|
|
306
|
+
# Resume in a new thread by attaching it
|
|
307
|
+
new_thread = client.beta.threads.create()
|
|
308
|
+
with open("project_state.md", "rb") as f:
|
|
309
|
+
file = client.files.create(file=f, purpose="assistants")
|
|
310
|
+
|
|
311
|
+
client.beta.threads.messages.create(
|
|
312
|
+
thread_id=new_thread.id,
|
|
313
|
+
role="user",
|
|
314
|
+
content="Continue from where we left off.",
|
|
315
|
+
attachments=[{"file_id": file.id, "tools": [{"type": "file_search"}]}],
|
|
316
|
+
)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### domain_profiles.yaml via file_search
|
|
320
|
+
|
|
321
|
+
To give the Orchestrator access to domain profiles at runtime, upload `config/domain_profiles.yaml` as a vector store file and enable `file_search` on the orchestrator assistant. The Orchestrator will retrieve it when scoring domain signals.
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
vector_store = client.beta.vector_stores.create(name="agent-kit-config")
|
|
325
|
+
client.beta.vector_stores.file_batches.upload_and_poll(
|
|
326
|
+
vector_store_id=vector_store.id,
|
|
327
|
+
files=[open("config/domain_profiles.yaml", "rb"),
|
|
328
|
+
open("config/token_policies.yaml", "rb")],
|
|
329
|
+
)
|
|
330
|
+
client.beta.assistants.update(
|
|
331
|
+
assistant_id=ids["orchestrator"],
|
|
332
|
+
tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
|
|
333
|
+
)
|