ccm commited on
Commit
1e30ae2
·
1 Parent(s): 994f33b

Adding a bi-agent system.

Browse files
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 code-writing agent without any extra tools.
11
  """
12
  if tools is None:
13
  tools = []
@@ -27,14 +27,7 @@ def generate_tool_calling_agent_with_tools(
27
  )
28
 
29
 
30
- def generate_self_critiquing_agent():
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
- generate_code_writing_agent_with_search_and_code,
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": "self-critiquing-agent",
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
- agent_for_request = generate_code_writing_agent_with_search_and_code()
722
- elif model_name == "self-critiquing-agent":
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(