feat: add project fork async job service with cli prune/clear commands and shared container image build target
This commit is contained in:
@@ -10,7 +10,14 @@ from ..config import Settings
|
||||
from ..errors import ToolInputError
|
||||
from .lessons import LessonStore
|
||||
from .loop import TraceCallback, react_loop
|
||||
from .state import AgentState, get_state
|
||||
from .state import (
|
||||
MAX_EVAL_DEPTH,
|
||||
AgentState,
|
||||
get_eval_depth,
|
||||
get_state,
|
||||
reset_eval_depth,
|
||||
set_eval_depth,
|
||||
)
|
||||
|
||||
logger = logging.getLogger("devii.agentic.controller")
|
||||
|
||||
@@ -58,6 +65,7 @@ class AgenticController:
|
||||
"forget_lessons": self._forget,
|
||||
"verify": self._verify,
|
||||
"delegate": self._delegate,
|
||||
"eval": self._eval,
|
||||
}
|
||||
handler = handlers.get(name)
|
||||
if handler is None:
|
||||
@@ -147,12 +155,53 @@ class AgenticController:
|
||||
{"status": "success", "verified": bool(confirmed), "summary": summary}, ensure_ascii=False
|
||||
)
|
||||
|
||||
async def _spawn(
|
||||
self, prompt: str, tools: list[dict[str, Any]], system_prompt: str = SUB_AGENT_SYSTEM_PROMPT
|
||||
) -> tuple[str, AgentState]:
|
||||
if self._llm is None or self._dispatcher is None:
|
||||
raise ToolInputError("Sub-agent execution is not available in this context.")
|
||||
depth = get_eval_depth()
|
||||
if depth >= MAX_EVAL_DEPTH:
|
||||
raise ToolInputError(
|
||||
"Nested self-evaluation limit reached; a tool or eval cannot keep calling itself."
|
||||
)
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
sub_state = AgentState()
|
||||
token = set_eval_depth(depth + 1)
|
||||
try:
|
||||
result = await react_loop(
|
||||
llm=self._llm,
|
||||
dispatcher=self._dispatcher,
|
||||
messages=messages,
|
||||
tools=tools,
|
||||
state=sub_state,
|
||||
settings=self._settings,
|
||||
max_iterations=self._settings.delegate_max_iterations,
|
||||
plan_required=self._settings.plan_required,
|
||||
verify_required=self._settings.verify_required,
|
||||
on_trace=self._on_trace,
|
||||
cost_tracker=self._cost_tracker,
|
||||
chunk_store=self._chunk_store,
|
||||
)
|
||||
finally:
|
||||
reset_eval_depth(token)
|
||||
return result, sub_state
|
||||
|
||||
async def run_subagent(self, prompt: str) -> str:
|
||||
prompt = str(prompt or "").strip()
|
||||
if not prompt:
|
||||
raise ToolInputError("A non-empty prompt is required.")
|
||||
tools = [tool for tool in self._tools if tool["function"]["name"] != NO_DELEGATE]
|
||||
result, _ = await self._spawn(prompt, tools)
|
||||
return result
|
||||
|
||||
async def _delegate(self, arguments: dict[str, Any]) -> str:
|
||||
task = str(arguments.get("task", "")).strip()
|
||||
if not task:
|
||||
raise ToolInputError("delegate requires a task description.")
|
||||
if self._llm is None or self._dispatcher is None:
|
||||
raise ToolInputError("Delegation is not available in this context.")
|
||||
allowed = arguments.get("allowed_tools")
|
||||
if allowed:
|
||||
allowed_set = {str(name) for name in allowed}
|
||||
@@ -163,26 +212,7 @@ class AgenticController:
|
||||
]
|
||||
else:
|
||||
tools = [tool for tool in self._tools if tool["function"]["name"] != NO_DELEGATE]
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": SUB_AGENT_SYSTEM_PROMPT},
|
||||
{"role": "user", "content": task},
|
||||
]
|
||||
sub_state = AgentState()
|
||||
result = await react_loop(
|
||||
llm=self._llm,
|
||||
dispatcher=self._dispatcher,
|
||||
messages=messages,
|
||||
tools=tools,
|
||||
state=sub_state,
|
||||
settings=self._settings,
|
||||
max_iterations=self._settings.delegate_max_iterations,
|
||||
plan_required=self._settings.plan_required,
|
||||
verify_required=self._settings.verify_required,
|
||||
on_trace=self._on_trace,
|
||||
cost_tracker=self._cost_tracker,
|
||||
chunk_store=self._chunk_store,
|
||||
)
|
||||
result, sub_state = await self._spawn(task, tools)
|
||||
return json.dumps(
|
||||
{
|
||||
"status": "success",
|
||||
@@ -193,3 +223,10 @@ class AgenticController:
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
async def _eval(self, arguments: dict[str, Any]) -> str:
|
||||
prompt = str(arguments.get("prompt", "")).strip()
|
||||
if not prompt:
|
||||
raise ToolInputError("eval requires a non-empty prompt.")
|
||||
result = await self.run_subagent(prompt)
|
||||
return json.dumps({"status": "success", "result": result}, ensure_ascii=False)
|
||||
|
||||
Reference in New Issue
Block a user