|
|
@@ -9,6 +9,7 @@ from core_domain import (
|
|
|
AgentSkillRefContract,
|
|
|
AgentToolRefContract,
|
|
|
ChatCompletionRequestContract,
|
|
|
+ ChatCompletionResponseContract,
|
|
|
ChatMessageContract,
|
|
|
MemoryCreateContract,
|
|
|
MemoryScopeType,
|
|
|
@@ -469,6 +470,7 @@ class AgentApplicationService:
|
|
|
agent_run=agent_run,
|
|
|
agent_version=agent_version,
|
|
|
messages=messages,
|
|
|
+ selected_tools=selected_tools,
|
|
|
)
|
|
|
)
|
|
|
except ModelGatewayClientError as exc:
|
|
|
@@ -486,7 +488,7 @@ class AgentApplicationService:
|
|
|
},
|
|
|
)
|
|
|
|
|
|
- action = self._parse_react_action(response.content)
|
|
|
+ action = self._parse_react_action_from_response(response)
|
|
|
react_step: dict[str, JSONValue] = {
|
|
|
"step_index": step_index,
|
|
|
"model_content": response.content,
|
|
|
@@ -1058,13 +1060,63 @@ class AgentApplicationService:
|
|
|
return {"action": "finish", "answer": content}
|
|
|
return {str(item_key): item_value for item_key, item_value in value.items()}
|
|
|
|
|
|
+ def _parse_react_action_from_response(
|
|
|
+ self,
|
|
|
+ response: ChatCompletionResponseContract,
|
|
|
+ ) -> dict[str, JSONValue]:
|
|
|
+ if response.tool_calls_json:
|
|
|
+ action = self._parse_openai_tool_call(response.tool_calls_json[0])
|
|
|
+ if action is not None:
|
|
|
+ return action
|
|
|
+ return self._parse_react_action(response.content)
|
|
|
+
|
|
|
+ def _parse_openai_tool_call(
|
|
|
+ self,
|
|
|
+ tool_call: dict[str, JSONValue],
|
|
|
+ ) -> dict[str, JSONValue] | None:
|
|
|
+ function_value = tool_call.get("function")
|
|
|
+ if not isinstance(function_value, dict):
|
|
|
+ return None
|
|
|
+ tool_code = function_value.get("name")
|
|
|
+ if not isinstance(tool_code, str) or not tool_code:
|
|
|
+ return None
|
|
|
+ raw_arguments = function_value.get("arguments")
|
|
|
+ input_json: dict[str, JSONValue] = {}
|
|
|
+ if isinstance(raw_arguments, str) and raw_arguments:
|
|
|
+ try:
|
|
|
+ decoded = json.loads(raw_arguments)
|
|
|
+ except json.JSONDecodeError:
|
|
|
+ decoded = {"raw_arguments": raw_arguments}
|
|
|
+ if isinstance(decoded, dict):
|
|
|
+ input_json = {str(item_key): item_value for item_key, item_value in decoded.items()}
|
|
|
+ elif isinstance(raw_arguments, dict):
|
|
|
+ input_json = {str(item_key): item_value for item_key, item_value in raw_arguments.items()}
|
|
|
+ tool_call_id = tool_call.get("id")
|
|
|
+ return {
|
|
|
+ "action": "tool",
|
|
|
+ "tool_code": tool_code,
|
|
|
+ "input_json": input_json,
|
|
|
+ "tool_call_id": tool_call_id if isinstance(tool_call_id, str) else None,
|
|
|
+ "tool_call_protocol": "openai",
|
|
|
+ }
|
|
|
+
|
|
|
def _build_chat_completion_request(
|
|
|
self,
|
|
|
*,
|
|
|
agent_run: AgentRun,
|
|
|
agent_version: AgentVersion,
|
|
|
messages: list[ChatMessageContract],
|
|
|
+ selected_tools: list[AgentToolRefContract] | None = None,
|
|
|
) -> ChatCompletionRequestContract:
|
|
|
+ function_calling_enabled = self._read_bool(
|
|
|
+ agent_version.model_config_json,
|
|
|
+ "function_calling_enabled",
|
|
|
+ default=False,
|
|
|
+ ) or self._read_bool(
|
|
|
+ agent_version.model_config_json,
|
|
|
+ "tool_calling_enabled",
|
|
|
+ default=False,
|
|
|
+ )
|
|
|
return ChatCompletionRequestContract(
|
|
|
model=self._read_optional_string(agent_version.model_config_json, "model"),
|
|
|
temperature=self._read_optional_float(
|
|
|
@@ -1076,6 +1128,15 @@ class AgentApplicationService:
|
|
|
"max_tokens",
|
|
|
),
|
|
|
messages=messages,
|
|
|
+ tools_json=(
|
|
|
+ self._build_openai_tool_schemas(
|
|
|
+ agent_run=agent_run,
|
|
|
+ selected_tools=selected_tools or [],
|
|
|
+ )
|
|
|
+ if function_calling_enabled
|
|
|
+ else []
|
|
|
+ ),
|
|
|
+ tool_choice="auto" if function_calling_enabled and selected_tools else None,
|
|
|
metadata_json={
|
|
|
"tenant_id": agent_run.tenant_id,
|
|
|
"agent_id": agent_run.agent_id,
|
|
|
@@ -1084,6 +1145,34 @@ class AgentApplicationService:
|
|
|
},
|
|
|
)
|
|
|
|
|
|
+ def _build_openai_tool_schemas(
|
|
|
+ self,
|
|
|
+ *,
|
|
|
+ agent_run: AgentRun,
|
|
|
+ selected_tools: list[AgentToolRefContract],
|
|
|
+ ) -> list[dict[str, JSONValue]]:
|
|
|
+ tool_schemas: list[dict[str, JSONValue]] = []
|
|
|
+ for schema in self._build_react_tool_schemas(
|
|
|
+ agent_run=agent_run,
|
|
|
+ selected_tools=selected_tools,
|
|
|
+ ):
|
|
|
+ tool_code = schema.get("tool_code")
|
|
|
+ if not isinstance(tool_code, str) or not tool_code:
|
|
|
+ continue
|
|
|
+ description = schema.get("description")
|
|
|
+ input_schema = schema.get("input_schema_json")
|
|
|
+ tool_schemas.append(
|
|
|
+ {
|
|
|
+ "type": "function",
|
|
|
+ "function": {
|
|
|
+ "name": tool_code,
|
|
|
+ "description": description if isinstance(description, str) else "",
|
|
|
+ "parameters": input_schema if isinstance(input_schema, dict) else {},
|
|
|
+ },
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return tool_schemas
|
|
|
+
|
|
|
def _build_skill_input_json(
|
|
|
self,
|
|
|
*,
|