|
|
@@ -1,10 +1,13 @@
|
|
|
import json
|
|
|
+from collections.abc import Iterator
|
|
|
from datetime import datetime, timedelta
|
|
|
from typing import cast
|
|
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
from core_events import EventPublishContract, EventServiceClient, EventServiceClientError
|
|
|
+from uuid import uuid4
|
|
|
+
|
|
|
from core_domain import (
|
|
|
AgentSkillRefContract,
|
|
|
AgentToolRefContract,
|
|
|
@@ -19,23 +22,30 @@ from core_shared import JSONValue, try_build_redis_client
|
|
|
from core_shared.task_queue import TaskQueuePublisher
|
|
|
|
|
|
from app.bootstrap.settings import AgentServiceSettings
|
|
|
-from app.db.models import AgentDefinition, AgentRun, AgentToolInvocation, AgentVersion
|
|
|
+from app.db.models import AgentDefinition, AgentRun, AgentToolInvocation, AgentConfig
|
|
|
from app.domain.repositories import (
|
|
|
AgentDefinitionRepository,
|
|
|
AgentRunRepository,
|
|
|
AgentToolInvocationRepository,
|
|
|
- AgentVersionRepository)
|
|
|
+ AgentConfigRepository)
|
|
|
from app.infrastructure.model_gateway_client import ModelGatewayClient, ModelGatewayClientError
|
|
|
from app.infrastructure.memory_client import MemoryClient, MemoryClientError
|
|
|
from app.infrastructure.skill_client import SkillServiceClient, SkillServiceClientError
|
|
|
from app.infrastructure.tool_client import ToolServiceClient, ToolServiceClientError
|
|
|
from app.schemas.agent import (
|
|
|
AgentCreateRequest,
|
|
|
+ AgentConfigCreateRequest,
|
|
|
+ AgentConfigListRequest,
|
|
|
AgentRunCreateRequest,
|
|
|
+ AgentRunDetailRequest,
|
|
|
AgentRunExecuteRequest,
|
|
|
AgentRunStatusUpdateRequest,
|
|
|
AgentStatusUpdateRequest,
|
|
|
- AgentVersionCreateRequest)
|
|
|
+ AgentUpdateRequest)
|
|
|
+
|
|
|
+
|
|
|
+def generate_agent_code() -> str:
|
|
|
+ return f"agent_{uuid4().hex[:16]}"
|
|
|
|
|
|
|
|
|
class AgentApplicationService:
|
|
|
@@ -43,7 +53,7 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_repository: AgentDefinitionRepository,
|
|
|
- agent_version_repository: AgentVersionRepository,
|
|
|
+ agent_config_repository: AgentConfigRepository,
|
|
|
agent_run_repository: AgentRunRepository,
|
|
|
agent_tool_invocation_repository: AgentToolInvocationRepository,
|
|
|
model_gateway_client: ModelGatewayClient | None = None,
|
|
|
@@ -56,7 +66,7 @@ class AgentApplicationService:
|
|
|
react_max_tool_calls: int = 10,
|
|
|
react_tool_retry_count: int = 1) -> None:
|
|
|
self.agent_repository = agent_repository
|
|
|
- self.agent_version_repository = agent_version_repository
|
|
|
+ self.agent_config_repository = agent_config_repository
|
|
|
self.agent_run_repository = agent_run_repository
|
|
|
self.agent_tool_invocation_repository = agent_tool_invocation_repository
|
|
|
self.model_gateway_client = model_gateway_client
|
|
|
@@ -71,7 +81,7 @@ class AgentApplicationService:
|
|
|
|
|
|
def create_agent(self, payload: AgentCreateRequest) -> AgentDefinition:
|
|
|
return self.agent_repository.create(
|
|
|
- code=payload.code,
|
|
|
+ code=payload.code or generate_agent_code(),
|
|
|
name=payload.name,
|
|
|
description=payload.description,
|
|
|
agent_type=payload.agent_type,
|
|
|
@@ -81,6 +91,27 @@ class AgentApplicationService:
|
|
|
def list_agents(self) -> list[AgentDefinition]:
|
|
|
return self.agent_repository.list_all()
|
|
|
|
|
|
+ def get_agent(self, *, agent_id: str) -> AgentDefinition | None:
|
|
|
+ return self.agent_repository.get_by_id(agent_id=agent_id)
|
|
|
+
|
|
|
+ def update_agent(self, payload: AgentUpdateRequest) -> AgentDefinition | None:
|
|
|
+ return self.agent_repository.update(
|
|
|
+ agent_id=payload.agent_id,
|
|
|
+ name=payload.name,
|
|
|
+ description=payload.description,
|
|
|
+ metadata_json=payload.metadata_json)
|
|
|
+
|
|
|
+ def delete_agent(self, *, agent_id: str) -> bool:
|
|
|
+ agent = self.agent_repository.get_by_id(agent_id=agent_id)
|
|
|
+ if agent is None:
|
|
|
+ return False
|
|
|
+ runs = self.agent_run_repository.list_by_scope(agent_id=agent_id)
|
|
|
+ for run in runs:
|
|
|
+ self.agent_tool_invocation_repository.delete_by_run(agent_run_id=run.id)
|
|
|
+ self.agent_run_repository.delete_by_agent(agent_id=agent_id)
|
|
|
+ self.agent_config_repository.delete_by_agent(agent_id=agent_id)
|
|
|
+ return self.agent_repository.delete(agent_id=agent_id) is not None
|
|
|
+
|
|
|
def update_agent_status(
|
|
|
self,
|
|
|
*,
|
|
|
@@ -90,15 +121,14 @@ class AgentApplicationService:
|
|
|
agent_id=agent_id,
|
|
|
status=payload.status)
|
|
|
|
|
|
- def create_agent_version(self, payload: AgentVersionCreateRequest) -> AgentVersion:
|
|
|
+ def create_agent_config(self, payload: AgentConfigCreateRequest) -> AgentConfig:
|
|
|
agent = self.agent_repository.get_by_id(
|
|
|
agent_id=payload.agent_id)
|
|
|
if agent is None:
|
|
|
raise ValueError(f"agent not found: {payload.agent_id}")
|
|
|
|
|
|
- return self.agent_version_repository.create(
|
|
|
+ return self.agent_config_repository.create(
|
|
|
agent_id=payload.agent_id,
|
|
|
- status=payload.status,
|
|
|
role=payload.role,
|
|
|
goal=payload.goal,
|
|
|
system_prompt=payload.system_prompt,
|
|
|
@@ -107,19 +137,19 @@ class AgentApplicationService:
|
|
|
tool_refs_json=[item.model_dump(mode="json") for item in payload.tool_refs],
|
|
|
skill_refs_json=[item.model_dump(mode="json") for item in payload.skill_refs])
|
|
|
|
|
|
- def list_agent_versions(self, *, agent_id: str) -> list[AgentVersion]:
|
|
|
- return self.agent_version_repository.list_by_agent(agent_id=agent_id)
|
|
|
+ def list_agent_configs(self, *, agent_id: str) -> list[AgentConfig]:
|
|
|
+ return self.agent_config_repository.list_by_agent(agent_id=agent_id)
|
|
|
|
|
|
def create_agent_run(self, payload: AgentRunCreateRequest) -> AgentRun:
|
|
|
- agent_version = self._resolve_agent_version(
|
|
|
+ agent_config = self._resolve_agent_config(
|
|
|
agent_id=payload.agent_id,
|
|
|
- agent_version_id=payload.agent_version_id)
|
|
|
- if agent_version is None:
|
|
|
- raise ValueError("published agent version not found")
|
|
|
+ agent_config_id=payload.agent_config_id)
|
|
|
+ if agent_config is None:
|
|
|
+ raise ValueError("agent config not found")
|
|
|
|
|
|
agent_run = self.agent_run_repository.create(
|
|
|
agent_id=payload.agent_id,
|
|
|
- agent_version_id=agent_version.id,
|
|
|
+ agent_config_id=agent_config.id,
|
|
|
session_id=payload.session_id,
|
|
|
input_text=payload.input_text,
|
|
|
input_json=payload.input_json)
|
|
|
@@ -141,6 +171,10 @@ class AgentApplicationService:
|
|
|
agent_id=agent_id,
|
|
|
session_id=session_id)
|
|
|
|
|
|
+ def get_agent_run(self, payload: AgentRunDetailRequest) -> AgentRun | None:
|
|
|
+ return self.agent_run_repository.get_by_id(
|
|
|
+ agent_run_id=payload.agent_run_id)
|
|
|
+
|
|
|
def list_agent_tool_invocations(
|
|
|
self,
|
|
|
*,
|
|
|
@@ -176,15 +210,15 @@ class AgentApplicationService:
|
|
|
if agent_run is None:
|
|
|
return None
|
|
|
|
|
|
- agent_version = self.agent_version_repository.get_by_id(
|
|
|
- agent_version_id=agent_run.agent_version_id)
|
|
|
- if agent_version is None:
|
|
|
+ agent_config = self.agent_config_repository.get_by_id(
|
|
|
+ agent_config_id=agent_run.agent_config_id)
|
|
|
+ if agent_config is None:
|
|
|
return self.agent_run_repository.update_status(
|
|
|
agent_run_id=agent_run.id,
|
|
|
status="failed",
|
|
|
worker_key=payload.worker_key,
|
|
|
- error_code="agent_version_missing",
|
|
|
- error_message=f"agent version not found: {agent_run.agent_version_id}")
|
|
|
+ error_code="agent_config_missing",
|
|
|
+ error_message=f"agent config not found: {agent_run.agent_config_id}")
|
|
|
|
|
|
self.agent_run_repository.update_status(
|
|
|
agent_run_id=agent_run.id,
|
|
|
@@ -193,13 +227,13 @@ class AgentApplicationService:
|
|
|
|
|
|
memory_results, memory_metadata = self._read_relevant_memories(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version)
|
|
|
- selected_tools = self._select_tool_refs(agent_run=agent_run, agent_version=agent_version)
|
|
|
- selected_skills = self._select_skill_refs(agent_run=agent_run, agent_version=agent_version)
|
|
|
+ agent_config=agent_config)
|
|
|
+ selected_tools = self._select_tool_refs(agent_run=agent_run, agent_config=agent_config)
|
|
|
+ selected_skills = self._select_skill_refs(agent_run=agent_run, agent_config=agent_config)
|
|
|
if payload.dry_run:
|
|
|
messages = self._build_chat_messages(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
memory_results=memory_results,
|
|
|
capability_context=self._format_capability_plan(
|
|
|
selected_tools=selected_tools,
|
|
|
@@ -210,10 +244,10 @@ class AgentApplicationService:
|
|
|
worker_key=payload.worker_key,
|
|
|
output_text=self._build_dry_run_output(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version),
|
|
|
+ agent_config=agent_config),
|
|
|
output_json={
|
|
|
"dry_run": True,
|
|
|
- "agent_version_id": agent_version.id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
"message_count": len(messages),
|
|
|
"messages": [message.model_dump(mode="json") for message in messages],
|
|
|
"selected_tool_refs": [
|
|
|
@@ -235,10 +269,10 @@ class AgentApplicationService:
|
|
|
})
|
|
|
return completed_run
|
|
|
|
|
|
- if self._read_bool(agent_version.model_config_json, "react_enabled", default=False):
|
|
|
+ if self._read_bool(agent_config.model_config_json, "react_enabled", default=False):
|
|
|
return self._execute_react_agent_run(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
payload=payload,
|
|
|
memory_results=memory_results,
|
|
|
memory_metadata=memory_metadata,
|
|
|
@@ -247,7 +281,7 @@ class AgentApplicationService:
|
|
|
|
|
|
tool_invocations = self._invoke_selected_tools(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
selected_tools=selected_tools)
|
|
|
skill_invocations = self._invoke_selected_skills(
|
|
|
agent_run=agent_run,
|
|
|
@@ -255,7 +289,7 @@ class AgentApplicationService:
|
|
|
worker_key=payload.worker_key)
|
|
|
messages = self._build_chat_messages(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
memory_results=memory_results,
|
|
|
capability_context=self._format_capability_results(
|
|
|
tool_invocations=tool_invocations,
|
|
|
@@ -277,17 +311,17 @@ class AgentApplicationService:
|
|
|
try:
|
|
|
response = self.model_gateway_client.create_chat_completion(
|
|
|
ChatCompletionRequestContract(
|
|
|
- model=self._read_optional_string(agent_version.model_config_json, "model"),
|
|
|
+ model=self._read_optional_string(agent_config.model_config_json, "model"),
|
|
|
temperature=self._read_optional_float(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"temperature"),
|
|
|
max_tokens=self._read_optional_int(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"max_tokens"),
|
|
|
messages=messages,
|
|
|
metadata_json={
|
|
|
"agent_id": agent_run.agent_id,
|
|
|
- "agent_version_id": agent_version.id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
"agent_run_id": agent_run.id,
|
|
|
})
|
|
|
)
|
|
|
@@ -301,7 +335,7 @@ class AgentApplicationService:
|
|
|
|
|
|
memory_write_metadata = self._write_interaction_memory(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
output_text=response.content)
|
|
|
completed_run = self.agent_run_repository.update_status(
|
|
|
agent_run_id=agent_run.id,
|
|
|
@@ -310,7 +344,7 @@ class AgentApplicationService:
|
|
|
output_text=response.content,
|
|
|
output_json={
|
|
|
"dry_run": False,
|
|
|
- "agent_version_id": agent_version.id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
"model": response.model,
|
|
|
"finish_reason": response.finish_reason,
|
|
|
"usage_json": response.usage_json,
|
|
|
@@ -331,6 +365,135 @@ class AgentApplicationService:
|
|
|
})
|
|
|
return completed_run
|
|
|
|
|
|
+ def execute_agent_run_stream(
|
|
|
+ self,
|
|
|
+ *,
|
|
|
+ agent_run_id: str,
|
|
|
+ payload: AgentRunExecuteRequest) -> Iterator[dict[str, JSONValue]]:
|
|
|
+ agent_run = self.agent_run_repository.get_by_id(
|
|
|
+ agent_run_id=agent_run_id)
|
|
|
+ if agent_run is None:
|
|
|
+ return
|
|
|
+
|
|
|
+ agent_config = self.agent_config_repository.get_by_id(
|
|
|
+ agent_config_id=agent_run.agent_config_id)
|
|
|
+ if agent_config is None:
|
|
|
+ failed_run = self.agent_run_repository.update_status(
|
|
|
+ agent_run_id=agent_run.id,
|
|
|
+ status="failed",
|
|
|
+ worker_key=payload.worker_key,
|
|
|
+ error_code="agent_config_missing",
|
|
|
+ error_message=f"agent config not found: {agent_run.agent_config_id}")
|
|
|
+ yield {"event": "agent.run.failed", "run": self._agent_run_to_json(failed_run)}
|
|
|
+ return
|
|
|
+
|
|
|
+ running_run = self.agent_run_repository.update_status(
|
|
|
+ agent_run_id=agent_run.id,
|
|
|
+ status="running",
|
|
|
+ worker_key=payload.worker_key)
|
|
|
+ yield {"event": "agent.run.started", "run": self._agent_run_to_json(running_run)}
|
|
|
+
|
|
|
+ if payload.dry_run or self._read_bool(agent_config.model_config_json, "react_enabled", default=False):
|
|
|
+ completed_run = self.execute_agent_run(agent_run_id=agent_run.id, payload=payload)
|
|
|
+ yield {"event": "agent.run.completed", "run": self._agent_run_to_json(completed_run)}
|
|
|
+ return
|
|
|
+
|
|
|
+ memory_results, memory_metadata = self._read_relevant_memories(
|
|
|
+ agent_run=agent_run,
|
|
|
+ agent_config=agent_config)
|
|
|
+ selected_tools = self._select_tool_refs(agent_run=agent_run, agent_config=agent_config)
|
|
|
+ selected_skills = self._select_skill_refs(agent_run=agent_run, agent_config=agent_config)
|
|
|
+ tool_invocations = self._invoke_selected_tools(
|
|
|
+ agent_run=agent_run,
|
|
|
+ agent_config=agent_config,
|
|
|
+ selected_tools=selected_tools)
|
|
|
+ skill_invocations = self._invoke_selected_skills(
|
|
|
+ agent_run=agent_run,
|
|
|
+ selected_skills=selected_skills,
|
|
|
+ worker_key=payload.worker_key)
|
|
|
+ messages = self._build_chat_messages(
|
|
|
+ agent_run=agent_run,
|
|
|
+ agent_config=agent_config,
|
|
|
+ memory_results=memory_results,
|
|
|
+ capability_context=self._format_capability_results(
|
|
|
+ tool_invocations=tool_invocations,
|
|
|
+ skill_invocations=skill_invocations))
|
|
|
+
|
|
|
+ if self.model_gateway_client is None:
|
|
|
+ failed_run = self.agent_run_repository.update_status(
|
|
|
+ agent_run_id=agent_run.id,
|
|
|
+ status="failed",
|
|
|
+ worker_key=payload.worker_key,
|
|
|
+ error_code="model_gateway_missing",
|
|
|
+ error_message="model gateway client is not configured",
|
|
|
+ output_json={
|
|
|
+ "tool_invocations": tool_invocations,
|
|
|
+ "skill_invocations": skill_invocations,
|
|
|
+ **memory_metadata,
|
|
|
+ })
|
|
|
+ yield {"event": "agent.run.failed", "run": self._agent_run_to_json(failed_run)}
|
|
|
+ return
|
|
|
+
|
|
|
+ output_parts: list[str] = []
|
|
|
+ try:
|
|
|
+ for delta in self.model_gateway_client.stream_chat_completion(
|
|
|
+ ChatCompletionRequestContract(
|
|
|
+ model=self._read_optional_string(agent_config.model_config_json, "model"),
|
|
|
+ temperature=self._read_optional_float(
|
|
|
+ agent_config.model_config_json,
|
|
|
+ "temperature"),
|
|
|
+ max_tokens=self._read_optional_int(
|
|
|
+ agent_config.model_config_json,
|
|
|
+ "max_tokens"),
|
|
|
+ messages=messages,
|
|
|
+ metadata_json={
|
|
|
+ "agent_id": agent_run.agent_id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
+ "agent_run_id": agent_run.id,
|
|
|
+ })):
|
|
|
+ output_parts.append(delta)
|
|
|
+ yield {"event": "agent.run.delta", "agent_run_id": agent_run.id, "delta": delta}
|
|
|
+ except ModelGatewayClientError as exc:
|
|
|
+ failed_run = self.agent_run_repository.update_status(
|
|
|
+ agent_run_id=agent_run.id,
|
|
|
+ status="failed",
|
|
|
+ worker_key=payload.worker_key,
|
|
|
+ error_code="model_gateway_error",
|
|
|
+ error_message=str(exc))
|
|
|
+ yield {"event": "agent.run.failed", "run": self._agent_run_to_json(failed_run)}
|
|
|
+ return
|
|
|
+
|
|
|
+ output_text = "".join(output_parts)
|
|
|
+ memory_write_metadata = self._write_interaction_memory(
|
|
|
+ agent_run=agent_run,
|
|
|
+ agent_config=agent_config,
|
|
|
+ output_text=output_text)
|
|
|
+ completed_run = self.agent_run_repository.update_status(
|
|
|
+ agent_run_id=agent_run.id,
|
|
|
+ status="completed",
|
|
|
+ worker_key=payload.worker_key,
|
|
|
+ output_text=output_text,
|
|
|
+ output_json={
|
|
|
+ "dry_run": False,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
+ "streamed": True,
|
|
|
+ "tool_invocations": tool_invocations,
|
|
|
+ "skill_invocations": skill_invocations,
|
|
|
+ **memory_metadata,
|
|
|
+ **memory_write_metadata,
|
|
|
+ })
|
|
|
+ if completed_run is not None:
|
|
|
+ self._publish_event(
|
|
|
+ event_type="agent.run.completed",
|
|
|
+ agent_run=completed_run,
|
|
|
+ payload_json={
|
|
|
+ "agent_run_id": completed_run.id,
|
|
|
+ "dry_run": False,
|
|
|
+ "status": completed_run.status,
|
|
|
+ "streamed": True,
|
|
|
+ })
|
|
|
+ yield {"event": "agent.run.completed", "run": self._agent_run_to_json(completed_run)}
|
|
|
+
|
|
|
def _publish_event(
|
|
|
self,
|
|
|
*,
|
|
|
@@ -350,17 +513,40 @@ class AgentApplicationService:
|
|
|
payload_json={
|
|
|
**payload_json,
|
|
|
"agent_id": agent_run.agent_id,
|
|
|
- "agent_version_id": agent_run.agent_version_id,
|
|
|
+ "agent_config_id": agent_run.agent_config_id,
|
|
|
})
|
|
|
)
|
|
|
except EventServiceClientError:
|
|
|
return
|
|
|
|
|
|
+ def _agent_run_to_json(self, agent_run: AgentRun | None) -> dict[str, JSONValue]:
|
|
|
+ if agent_run is None:
|
|
|
+ return {}
|
|
|
+ return {
|
|
|
+ "id": agent_run.id,
|
|
|
+ "agent_id": agent_run.agent_id,
|
|
|
+ "agent_config_id": agent_run.agent_config_id,
|
|
|
+ "session_id": agent_run.session_id,
|
|
|
+ "input_text": agent_run.input_text,
|
|
|
+ "input_json": agent_run.input_json,
|
|
|
+ "output_text": agent_run.output_text,
|
|
|
+ "output_json": agent_run.output_json,
|
|
|
+ "status": agent_run.status,
|
|
|
+ "worker_key": agent_run.worker_key,
|
|
|
+ "queued_time": agent_run.queued_time,
|
|
|
+ "lease_expire_time": agent_run.lease_expire_time,
|
|
|
+ "started_time": agent_run.started_time,
|
|
|
+ "finished_time": agent_run.finished_time,
|
|
|
+ "error_code": agent_run.error_code,
|
|
|
+ "error_message": agent_run.error_message,
|
|
|
+ "created_time": agent_run.created_time,
|
|
|
+ }
|
|
|
+
|
|
|
def _execute_react_agent_run(
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion,
|
|
|
+ agent_config: AgentConfig,
|
|
|
payload: AgentRunExecuteRequest,
|
|
|
memory_results: list[MemorySearchResultContract],
|
|
|
memory_metadata: dict[str, JSONValue],
|
|
|
@@ -380,7 +566,7 @@ class AgentApplicationService:
|
|
|
worker_key=payload.worker_key)
|
|
|
messages = self._build_chat_messages(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
memory_results=memory_results,
|
|
|
capability_context=self._format_react_instruction(
|
|
|
agent_run=agent_run,
|
|
|
@@ -392,7 +578,7 @@ class AgentApplicationService:
|
|
|
tool_call_count = 0
|
|
|
|
|
|
max_steps = self._read_int(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"react_max_steps",
|
|
|
default=self.react_max_steps)
|
|
|
for step_index in range(max(max_steps, 1)):
|
|
|
@@ -400,7 +586,7 @@ class AgentApplicationService:
|
|
|
response = self.model_gateway_client.create_chat_completion(
|
|
|
self._build_chat_completion_request(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
messages=messages,
|
|
|
selected_tools=selected_tools)
|
|
|
)
|
|
|
@@ -435,7 +621,7 @@ class AgentApplicationService:
|
|
|
break
|
|
|
|
|
|
max_tool_calls = self._read_int(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"react_max_tool_calls",
|
|
|
default=self.react_max_tool_calls)
|
|
|
if tool_call_count >= max(max_tool_calls, 0):
|
|
|
@@ -462,7 +648,7 @@ class AgentApplicationService:
|
|
|
}
|
|
|
current_invocations = self._invoke_react_tool_with_retry(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
tool_ref=matching_tools[0])
|
|
|
tool_call_count += len(current_invocations)
|
|
|
agent_run.input_json = original_input_json
|
|
|
@@ -477,7 +663,7 @@ class AgentApplicationService:
|
|
|
|
|
|
memory_write_metadata = self._write_interaction_memory(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
output_text=final_answer)
|
|
|
completed_run = self.agent_run_repository.update_status(
|
|
|
agent_run_id=agent_run.id,
|
|
|
@@ -486,7 +672,7 @@ class AgentApplicationService:
|
|
|
output_text=final_answer,
|
|
|
output_json={
|
|
|
"dry_run": False,
|
|
|
- "agent_version_id": agent_version.id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
"react_enabled": True,
|
|
|
"react_steps": react_steps,
|
|
|
"react_tool_call_count": tool_call_count,
|
|
|
@@ -557,30 +743,30 @@ class AgentApplicationService:
|
|
|
return None
|
|
|
return result, released_lease_count
|
|
|
|
|
|
- def _resolve_agent_version(
|
|
|
+ def _resolve_agent_config(
|
|
|
self,
|
|
|
*,
|
|
|
agent_id: str,
|
|
|
- agent_version_id: str | None) -> AgentVersion | None:
|
|
|
- if agent_version_id is not None:
|
|
|
- return self.agent_version_repository.get_by_id(
|
|
|
- agent_version_id=agent_version_id)
|
|
|
- return self.agent_version_repository.get_latest_published(
|
|
|
+ agent_config_id: str | None) -> AgentConfig | None:
|
|
|
+ if agent_config_id is not None:
|
|
|
+ return self.agent_config_repository.get_by_id(
|
|
|
+ agent_config_id=agent_config_id)
|
|
|
+ return self.agent_config_repository.get_latest_by_agent(
|
|
|
agent_id=agent_id)
|
|
|
|
|
|
def _build_chat_messages(
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion,
|
|
|
+ agent_config: AgentConfig,
|
|
|
memory_results: list[MemorySearchResultContract] | None = None,
|
|
|
capability_context: str | None = None) -> list[ChatMessageContract]:
|
|
|
messages = [
|
|
|
- ChatMessageContract(role="system", content=agent_version.system_prompt),
|
|
|
+ ChatMessageContract(role="system", content=agent_config.system_prompt),
|
|
|
]
|
|
|
- if agent_version.goal:
|
|
|
+ if agent_config.goal:
|
|
|
messages.append(
|
|
|
- ChatMessageContract(role="system", content=f"Goal: {agent_version.goal}")
|
|
|
+ ChatMessageContract(role="system", content=f"Goal: {agent_config.goal}")
|
|
|
)
|
|
|
if memory_results:
|
|
|
messages.append(
|
|
|
@@ -604,10 +790,10 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion) -> list[AgentToolRefContract]:
|
|
|
+ agent_config: AgentConfig) -> list[AgentToolRefContract]:
|
|
|
input_preview = self._build_input_preview(agent_run)
|
|
|
selected: list[AgentToolRefContract] = []
|
|
|
- for item in agent_version.tool_refs_json:
|
|
|
+ for item in agent_config.tool_refs_json:
|
|
|
ref = AgentToolRefContract.model_validate(item)
|
|
|
if (
|
|
|
ref.required
|
|
|
@@ -621,10 +807,10 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion) -> list[AgentSkillRefContract]:
|
|
|
+ agent_config: AgentConfig) -> list[AgentSkillRefContract]:
|
|
|
input_preview = self._build_input_preview(agent_run)
|
|
|
selected: list[AgentSkillRefContract] = []
|
|
|
- for item in agent_version.skill_refs_json:
|
|
|
+ for item in agent_config.skill_refs_json:
|
|
|
ref = AgentSkillRefContract.model_validate(item)
|
|
|
auto_invoke = self._read_bool(ref.config_json, "auto_invoke", default=True)
|
|
|
if auto_invoke or self._matches_selection_keywords(ref.config_json, input_preview):
|
|
|
@@ -635,14 +821,14 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion,
|
|
|
+ agent_config: AgentConfig,
|
|
|
selected_tools: list[AgentToolRefContract]) -> list[dict[str, JSONValue]]:
|
|
|
invocations: list[dict[str, JSONValue]] = []
|
|
|
for ref in selected_tools:
|
|
|
invocation = self.agent_tool_invocation_repository.create(
|
|
|
agent_run_id=agent_run.id,
|
|
|
agent_id=agent_run.agent_id,
|
|
|
- agent_version_id=agent_version.id,
|
|
|
+ agent_config_id=agent_config.id,
|
|
|
tool_code=ref.tool_code,
|
|
|
tool_binding_id=ref.tool_binding_id,
|
|
|
status="selected",
|
|
|
@@ -778,9 +964,6 @@ class AgentApplicationService:
|
|
|
try:
|
|
|
created_run = self.skill_client.create_skill_run(
|
|
|
skill_id=skill_id,
|
|
|
- skill_version_id=self._read_optional_string(
|
|
|
- ref.config_json,
|
|
|
- "skill_version_id"),
|
|
|
installation_id=self._read_optional_string(
|
|
|
ref.config_json,
|
|
|
"installation_id"),
|
|
|
@@ -878,9 +1061,9 @@ class AgentApplicationService:
|
|
|
"name": detail.tool_definition.name,
|
|
|
"description": detail.tool_definition.description,
|
|
|
"tool_type": detail.tool_definition.tool_type,
|
|
|
- "input_schema_json": detail.tool_version.input_schema_json or {},
|
|
|
- "output_schema_json": detail.tool_version.output_schema_json or {},
|
|
|
- "timeout_ms": detail.tool_version.timeout_ms,
|
|
|
+ "input_schema_json": detail.connection.input_schema_json or {},
|
|
|
+ "output_schema_json": detail.connection.output_schema_json or {},
|
|
|
+ "timeout_ms": detail.connection.timeout_ms,
|
|
|
}
|
|
|
)
|
|
|
except ToolServiceClientError as exc:
|
|
|
@@ -892,17 +1075,17 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion,
|
|
|
+ agent_config: AgentConfig,
|
|
|
tool_ref: AgentToolRefContract) -> list[dict[str, JSONValue]]:
|
|
|
retry_count = self._read_int(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"react_tool_retry_count",
|
|
|
default=self.react_tool_retry_count)
|
|
|
attempts: list[dict[str, JSONValue]] = []
|
|
|
for attempt_index in range(max(retry_count, 0) + 1):
|
|
|
current = self._invoke_selected_tools(
|
|
|
agent_run=agent_run,
|
|
|
- agent_version=agent_version,
|
|
|
+ agent_config=agent_config,
|
|
|
selected_tools=[tool_ref])
|
|
|
for item in current:
|
|
|
item["attempt_index"] = attempt_index
|
|
|
@@ -974,23 +1157,23 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion,
|
|
|
+ agent_config: AgentConfig,
|
|
|
messages: list[ChatMessageContract],
|
|
|
selected_tools: list[AgentToolRefContract] | None = None) -> ChatCompletionRequestContract:
|
|
|
function_calling_enabled = self._read_bool(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"function_calling_enabled",
|
|
|
default=False) or self._read_bool(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"tool_calling_enabled",
|
|
|
default=False)
|
|
|
return ChatCompletionRequestContract(
|
|
|
- model=self._read_optional_string(agent_version.model_config_json, "model"),
|
|
|
+ model=self._read_optional_string(agent_config.model_config_json, "model"),
|
|
|
temperature=self._read_optional_float(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"temperature"),
|
|
|
max_tokens=self._read_optional_int(
|
|
|
- agent_version.model_config_json,
|
|
|
+ agent_config.model_config_json,
|
|
|
"max_tokens"),
|
|
|
messages=messages,
|
|
|
tools_json=(
|
|
|
@@ -1003,7 +1186,7 @@ class AgentApplicationService:
|
|
|
tool_choice="auto" if function_calling_enabled and selected_tools else None,
|
|
|
metadata_json={
|
|
|
"agent_id": agent_run.agent_id,
|
|
|
- "agent_version_id": agent_version.id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
"agent_run_id": agent_run.id,
|
|
|
})
|
|
|
|
|
|
@@ -1075,11 +1258,11 @@ class AgentApplicationService:
|
|
|
for keyword in keywords
|
|
|
)
|
|
|
|
|
|
- def _build_dry_run_output(self, *, agent_run: AgentRun, agent_version: AgentVersion) -> str:
|
|
|
+ def _build_dry_run_output(self, *, agent_run: AgentRun, agent_config: AgentConfig) -> str:
|
|
|
input_preview = agent_run.input_text or str(agent_run.input_json or {})
|
|
|
return (
|
|
|
- f"[dry-run] Agent role={agent_version.role} "
|
|
|
- f"version={agent_version.version_no} received: {input_preview}"
|
|
|
+ f"[dry-run] Agent role={agent_config.role} "
|
|
|
+ f"received: {input_preview}"
|
|
|
)
|
|
|
|
|
|
def _read_optional_string(self, payload: dict[str, JSONValue], key: str) -> str | None:
|
|
|
@@ -1104,17 +1287,17 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion) -> tuple[list[MemorySearchResultContract], dict[str, JSONValue]]:
|
|
|
+ agent_config: AgentConfig) -> tuple[list[MemorySearchResultContract], dict[str, JSONValue]]:
|
|
|
if self.memory_client is None:
|
|
|
return [], {"memory_read_enabled": False, "memory_read_reason": "client_missing"}
|
|
|
- if not self._read_bool(agent_version.memory_policy_json, "enabled", default=True):
|
|
|
+ if not self._read_bool(agent_config.memory_policy_json, "enabled", default=True):
|
|
|
return [], {"memory_read_enabled": False, "memory_read_reason": "policy_disabled"}
|
|
|
|
|
|
query = agent_run.input_text or str(agent_run.input_json or "")
|
|
|
if not query:
|
|
|
return [], {"memory_read_enabled": True, "memory_read_count": 0}
|
|
|
|
|
|
- scope = self._resolve_memory_scope(agent_run=agent_run, agent_version=agent_version)
|
|
|
+ scope = self._resolve_memory_scope(agent_run=agent_run, agent_config=agent_config)
|
|
|
if scope is None:
|
|
|
return [], {
|
|
|
"memory_read_enabled": True,
|
|
|
@@ -1132,7 +1315,7 @@ class AgentApplicationService:
|
|
|
owner_agent_id=agent_run.agent_id,
|
|
|
session_id=agent_run.session_id,
|
|
|
limit=self._read_int(
|
|
|
- agent_version.memory_policy_json,
|
|
|
+ agent_config.memory_policy_json,
|
|
|
"read_top_k",
|
|
|
default=8))
|
|
|
)
|
|
|
@@ -1154,14 +1337,14 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion,
|
|
|
+ agent_config: AgentConfig,
|
|
|
output_text: str) -> dict[str, JSONValue]:
|
|
|
if self.memory_client is None:
|
|
|
return {"memory_write_enabled": False, "memory_write_reason": "client_missing"}
|
|
|
- if not self._read_bool(agent_version.memory_policy_json, "write_enabled", default=True):
|
|
|
+ if not self._read_bool(agent_config.memory_policy_json, "write_enabled", default=True):
|
|
|
return {"memory_write_enabled": False, "memory_write_reason": "policy_disabled"}
|
|
|
|
|
|
- scope = self._resolve_memory_scope(agent_run=agent_run, agent_version=agent_version)
|
|
|
+ scope = self._resolve_memory_scope(agent_run=agent_run, agent_config=agent_config)
|
|
|
if scope is None:
|
|
|
return {"memory_write_enabled": True, "memory_write_reason": "scope_unavailable"}
|
|
|
|
|
|
@@ -1177,20 +1360,19 @@ class AgentApplicationService:
|
|
|
output_text=output_text),
|
|
|
content_json={
|
|
|
"agent_run_id": agent_run.id,
|
|
|
- "agent_version_id": agent_version.id,
|
|
|
+ "agent_config_id": agent_config.id,
|
|
|
"input_text": agent_run.input_text,
|
|
|
"output_text": output_text,
|
|
|
},
|
|
|
metadata_json={
|
|
|
"source": "agent-service",
|
|
|
- "role": agent_version.role,
|
|
|
- "version_no": agent_version.version_no,
|
|
|
+ "role": agent_config.role,
|
|
|
},
|
|
|
owner_agent_id=agent_run.agent_id,
|
|
|
session_id=agent_run.session_id,
|
|
|
source_ref=f"agent_run:{agent_run.id}",
|
|
|
importance_score=self._read_nested_int(
|
|
|
- agent_version.memory_policy_json,
|
|
|
+ agent_config.memory_policy_json,
|
|
|
"config_json",
|
|
|
"write_importance_score",
|
|
|
default=50))
|
|
|
@@ -1212,9 +1394,9 @@ class AgentApplicationService:
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
- agent_version: AgentVersion) -> tuple[MemoryScopeType, str] | None:
|
|
|
+ agent_config: AgentConfig) -> tuple[MemoryScopeType, str] | None:
|
|
|
scope_value = self._read_optional_string(
|
|
|
- agent_version.memory_policy_json,
|
|
|
+ agent_config.memory_policy_json,
|
|
|
"memory_scope") or "session"
|
|
|
if scope_value == "global":
|
|
|
return "global", "global"
|
|
|
@@ -1285,7 +1467,7 @@ def build_agent_application_service(
|
|
|
redis_client = try_build_redis_client(settings.redis_url)
|
|
|
return AgentApplicationService(
|
|
|
agent_repository=AgentDefinitionRepository(db),
|
|
|
- agent_version_repository=AgentVersionRepository(db),
|
|
|
+ agent_config_repository=AgentConfigRepository(db),
|
|
|
agent_run_repository=AgentRunRepository(db),
|
|
|
agent_tool_invocation_repository=AgentToolInvocationRepository(db),
|
|
|
model_gateway_client=ModelGatewayClient(
|