Spaces:
Sleeping
Sleeping
Adding a bi-agent system.
Browse files- agents/generator_and_critic.py +100 -0
- agents/json_tool_calling_agents.py +2 -9
- proxy.py +7 -8
agents/generator_and_critic.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import os
|
| 3 |
+
from typing import List, Optional
|
| 4 |
+
from smolagents import CodeAgent, ToolCallingAgent
|
| 5 |
+
import smolagents.models
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
# ---------------- Agent Prompts ----------------
|
| 9 |
+
GENERATOR_INSTRUCTIONS = """
|
| 10 |
+
You are the Generator/Refiner.
|
| 11 |
+
|
| 12 |
+
Goal
|
| 13 |
+
- Produce a concise draft that strictly satisfies the caller's constraints.
|
| 14 |
+
- Use the managed agent named "critic_agent" to validate your draft.
|
| 15 |
+
- Repeat: draft → call critic_agent → if ok, return draft; else revise and re-check.
|
| 16 |
+
- Output ONLY the final draft text (no JSON, no commentary).
|
| 17 |
+
|
| 18 |
+
Constraints to enforce in every revision:
|
| 19 |
+
- Respect the maximum word count.
|
| 20 |
+
- Use bullet points where appropriate (lines starting with '-' or '•').
|
| 21 |
+
- Include all required phrases verbatim.
|
| 22 |
+
- End with a line starting with 'Next steps:'.
|
| 23 |
+
|
| 24 |
+
Implementation guidance (you write/run the code):
|
| 25 |
+
- Use a small loop with a bounded number of rounds provided by the caller.
|
| 26 |
+
- Call critic_agent with a single string payload that contains:
|
| 27 |
+
- the DRAFT
|
| 28 |
+
- the list of required phrases
|
| 29 |
+
- the word limit
|
| 30 |
+
- any other constraints you need
|
| 31 |
+
- critic_agent returns a JSON object with keys: ok (bool), violations (list[str]), suggestions (str).
|
| 32 |
+
- If ok == true, immediately return the current draft (and stop).
|
| 33 |
+
- Otherwise, revise the draft to fix ALL violations, then re-check.
|
| 34 |
+
|
| 35 |
+
Important:
|
| 36 |
+
- Do NOT print anything except the final draft at the end.
|
| 37 |
+
- Avoid verbose interleaved logs; keep code minimal.
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
CRITIC_INSTRUCTIONS = """
|
| 41 |
+
You are the Critic.
|
| 42 |
+
|
| 43 |
+
Input
|
| 44 |
+
- A single string payload that includes:
|
| 45 |
+
- DRAFT text
|
| 46 |
+
- explicit constraints (e.g., max_words, must_include list, bullets rule, ending 'Next steps:')
|
| 47 |
+
|
| 48 |
+
Task
|
| 49 |
+
- Evaluate the DRAFT against the constraints and general quality (clarity, correctness, structure, tone).
|
| 50 |
+
- Return ONLY compact JSON (no text outside JSON) with shape:
|
| 51 |
+
{
|
| 52 |
+
"ok": true|false,
|
| 53 |
+
"violations": ["short, concrete issues..."],
|
| 54 |
+
"suggestions": "one short paragraph of actionable guidance"
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
Rules
|
| 58 |
+
- ok=true ONLY if all constraints are satisfied AND the draft reads clearly.
|
| 59 |
+
- Keep violations terse and actionable.
|
| 60 |
+
- Keep suggestions short and prescriptive.
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
# ---------------- Factory ----------------
|
| 65 |
+
def generate_generator_with_managed_critic(
|
| 66 |
+
*,
|
| 67 |
+
gen_max_steps: int = 12,
|
| 68 |
+
crt_max_steps: int = 2,
|
| 69 |
+
) -> CodeAgent:
|
| 70 |
+
"""
|
| 71 |
+
Returns a CodeAgent (generator) that manages a critic sub-agent.
|
| 72 |
+
The critic is exposed to the generator as a managed agent (callable like a tool).
|
| 73 |
+
"""
|
| 74 |
+
|
| 75 |
+
model = smolagents.models.OpenAIServerModel(
|
| 76 |
+
model_id=os.getenv("AGENT_MODEL", ""),
|
| 77 |
+
api_base=os.getenv("UPSTREAM_OPENAI_BASE", "").rstrip("/"),
|
| 78 |
+
api_key=os.getenv("OPENAI_API_KEY"),
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
critic_agent = ToolCallingAgent(
|
| 82 |
+
tools=[], # critic needs no tools; it just returns JSON text
|
| 83 |
+
model=model,
|
| 84 |
+
name="critic_agent",
|
| 85 |
+
description="Evaluates drafts against constraints and returns a compact JSON report.",
|
| 86 |
+
instructions=CRITIC_INSTRUCTIONS,
|
| 87 |
+
add_base_tools=False,
|
| 88 |
+
max_steps=crt_max_steps,
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
generator = CodeAgent(
|
| 92 |
+
tools=[], # keep toolbox minimal
|
| 93 |
+
model=model,
|
| 94 |
+
name="generator_with_managed_critic",
|
| 95 |
+
managed_agents=[critic_agent], # <-- critic attached here
|
| 96 |
+
instructions=GENERATOR_INSTRUCTIONS,
|
| 97 |
+
add_base_tools=False,
|
| 98 |
+
max_steps=gen_max_steps,
|
| 99 |
+
)
|
| 100 |
+
return generator
|
agents/json_tool_calling_agents.py
CHANGED
|
@@ -7,7 +7,7 @@ def generate_tool_calling_agent_with_tools(
|
|
| 7 |
tools=None, name: str = "tool_calling_agent_without_tools"
|
| 8 |
):
|
| 9 |
"""
|
| 10 |
-
Create a
|
| 11 |
"""
|
| 12 |
if tools is None:
|
| 13 |
tools = []
|
|
@@ -27,14 +27,7 @@ def generate_tool_calling_agent_with_tools(
|
|
| 27 |
)
|
| 28 |
|
| 29 |
|
| 30 |
-
def
|
| 31 |
-
"""
|
| 32 |
-
Create a code-writing agent without any extra tools.
|
| 33 |
-
"""
|
| 34 |
-
return generate_tool_calling_agent_with_tools(name="self_critiquing_agent")
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def generate_code_writing_agent_with_search_and_code():
|
| 38 |
"""
|
| 39 |
Create a code-writing agent without any extra tools.
|
| 40 |
"""
|
|
|
|
| 7 |
tools=None, name: str = "tool_calling_agent_without_tools"
|
| 8 |
):
|
| 9 |
"""
|
| 10 |
+
Create a JSON tool-calling agent with specified tools.
|
| 11 |
"""
|
| 12 |
if tools is None:
|
| 13 |
tools = []
|
|
|
|
| 27 |
)
|
| 28 |
|
| 29 |
|
| 30 |
+
def generate_tool_calling_agent_with_search_and_code():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
"""
|
| 32 |
Create a code-writing agent without any extra tools.
|
| 33 |
"""
|
proxy.py
CHANGED
|
@@ -25,10 +25,11 @@ from agents.code_writing_agents import (
|
|
| 25 |
)
|
| 26 |
|
| 27 |
from agents.json_tool_calling_agents import (
|
| 28 |
-
|
| 29 |
-
generate_self_critiquing_agent,
|
| 30 |
)
|
| 31 |
|
|
|
|
|
|
|
| 32 |
# Logging setup
|
| 33 |
logging.basicConfig(level=os.getenv("LOG_LEVEL", "INFO").upper())
|
| 34 |
log = logging.getLogger(__name__)
|
|
@@ -620,7 +621,7 @@ async def list_models():
|
|
| 620 |
"object": "list",
|
| 621 |
"data": [
|
| 622 |
{
|
| 623 |
-
"id": "
|
| 624 |
"object": "model",
|
| 625 |
"created": now,
|
| 626 |
"owned_by": "you",
|
|
@@ -717,11 +718,9 @@ async def chat_completions(req: fastapi.Request):
|
|
| 717 |
elif model_name == "code-writing-agent-with-search":
|
| 718 |
agent_for_request = generate_code_writing_agent_with_search()
|
| 719 |
elif model_name == "tool-calling-agent-with-search-and-code":
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
agent_for_request = generate_self_critiquing_agent()
|
| 725 |
else:
|
| 726 |
# Emit error for unknown model
|
| 727 |
return fastapi.responses.JSONResponse(
|
|
|
|
| 25 |
)
|
| 26 |
|
| 27 |
from agents.json_tool_calling_agents import (
|
| 28 |
+
generate_tool_calling_agent_with_search_and_code,
|
|
|
|
| 29 |
)
|
| 30 |
|
| 31 |
+
from agents.generator_and_critic import generate_generator_with_managed_critic
|
| 32 |
+
|
| 33 |
# Logging setup
|
| 34 |
logging.basicConfig(level=os.getenv("LOG_LEVEL", "INFO").upper())
|
| 35 |
log = logging.getLogger(__name__)
|
|
|
|
| 621 |
"object": "list",
|
| 622 |
"data": [
|
| 623 |
{
|
| 624 |
+
"id": "generator-with-managed-critic",
|
| 625 |
"object": "model",
|
| 626 |
"created": now,
|
| 627 |
"owned_by": "you",
|
|
|
|
| 718 |
elif model_name == "code-writing-agent-with-search":
|
| 719 |
agent_for_request = generate_code_writing_agent_with_search()
|
| 720 |
elif model_name == "tool-calling-agent-with-search-and-code":
|
| 721 |
+
agent_for_request = generate_tool_calling_agent_with_search_and_code()
|
| 722 |
+
elif model_name == "generator-with-managed-critic":
|
| 723 |
+
agent_for_request = generate_generator_with_managed_critic()
|
|
|
|
|
|
|
| 724 |
else:
|
| 725 |
# Emit error for unknown model
|
| 726 |
return fastapi.responses.JSONResponse(
|