Compare commits
1 Commits
fix/syntax
...
feat/20260
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7181944220 |
@@ -15,6 +15,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import inspect
|
||||||
|
|
||||||
# fcntl is Unix-only; on Windows use msvcrt for file locking
|
# fcntl is Unix-only; on Windows use msvcrt for file locking
|
||||||
try:
|
try:
|
||||||
@@ -593,29 +594,51 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
agent = AIAgent(
|
agent_kwargs = {
|
||||||
model=turn_route["model"],
|
"model": turn_route["model"],
|
||||||
api_key=turn_route["runtime"].get("api_key"),
|
"api_key": turn_route["runtime"].get("api_key"),
|
||||||
base_url=turn_route["runtime"].get("base_url"),
|
"base_url": turn_route["runtime"].get("base_url"),
|
||||||
provider=turn_route["runtime"].get("provider"),
|
"provider": turn_route["runtime"].get("provider"),
|
||||||
api_mode=turn_route["runtime"].get("api_mode"),
|
"api_mode": turn_route["runtime"].get("api_mode"),
|
||||||
acp_command=turn_route["runtime"].get("command"),
|
"acp_command": turn_route["runtime"].get("command"),
|
||||||
acp_args=turn_route["runtime"].get("args"),
|
"acp_args": turn_route["runtime"].get("args"),
|
||||||
max_iterations=max_iterations,
|
"max_iterations": max_iterations,
|
||||||
reasoning_config=reasoning_config,
|
"reasoning_config": reasoning_config,
|
||||||
prefill_messages=prefill_messages,
|
"prefill_messages": prefill_messages,
|
||||||
providers_allowed=pr.get("only"),
|
"providers_allowed": pr.get("only"),
|
||||||
providers_ignored=pr.get("ignore"),
|
"providers_ignored": pr.get("ignore"),
|
||||||
providers_order=pr.get("order"),
|
"providers_order": pr.get("order"),
|
||||||
provider_sort=pr.get("sort"),
|
"provider_sort": pr.get("sort"),
|
||||||
disabled_toolsets=["cronjob", "messaging", "clarify"],
|
"disabled_toolsets": ["cronjob", "messaging", "clarify"],
|
||||||
tool_choice="required",
|
"tool_choice": "required",
|
||||||
quiet_mode=True,
|
"quiet_mode": True,
|
||||||
skip_memory=True, # Cron system prompts would corrupt user representations
|
"skip_memory": True, # Cron system prompts would corrupt user representations
|
||||||
platform="cron",
|
"platform": "cron",
|
||||||
session_id=_cron_session_id,
|
"session_id": _cron_session_id,
|
||||||
session_db=_session_db,
|
"session_db": _session_db,
|
||||||
)
|
}
|
||||||
|
try:
|
||||||
|
_agent_sig = inspect.signature(AIAgent.__init__)
|
||||||
|
_agent_params = _agent_sig.parameters
|
||||||
|
_accepts_var_kw = any(
|
||||||
|
p.kind == inspect.Parameter.VAR_KEYWORD
|
||||||
|
for p in _agent_params.values()
|
||||||
|
)
|
||||||
|
if not _accepts_var_kw:
|
||||||
|
_supported = {name for name in _agent_params if name != "self"}
|
||||||
|
_dropped = [key for key in list(agent_kwargs) if key not in _supported]
|
||||||
|
if _dropped:
|
||||||
|
logger.warning(
|
||||||
|
"Job '%s': dropping unsupported AIAgent kwargs for compatibility: %s",
|
||||||
|
job_id,
|
||||||
|
", ".join(sorted(_dropped)),
|
||||||
|
)
|
||||||
|
for key in _dropped:
|
||||||
|
agent_kwargs.pop(key, None)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
agent = AIAgent(**agent_kwargs)
|
||||||
|
|
||||||
# Run the agent with an *inactivity*-based timeout: the job can run
|
# Run the agent with an *inactivity*-based timeout: the job can run
|
||||||
# for hours if it's actively calling tools / receiving stream tokens,
|
# for hours if it's actively calling tools / receiving stream tokens,
|
||||||
|
|||||||
@@ -371,6 +371,76 @@ class TestRunJobSessionPersistence:
|
|||||||
assert call_args[0][1] == "cron_complete"
|
assert call_args[0][1] == "cron_complete"
|
||||||
fake_db.close.assert_called_once()
|
fake_db.close.assert_called_once()
|
||||||
|
|
||||||
|
def test_run_job_drops_unsupported_agent_kwargs_for_legacy_agent_signature(self, tmp_path):
|
||||||
|
job = {
|
||||||
|
"id": "legacy-agent-job",
|
||||||
|
"name": "legacy",
|
||||||
|
"prompt": "hello",
|
||||||
|
}
|
||||||
|
fake_db = MagicMock()
|
||||||
|
seen = {}
|
||||||
|
|
||||||
|
class LegacyAgent:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
model=None,
|
||||||
|
api_key=None,
|
||||||
|
base_url=None,
|
||||||
|
provider=None,
|
||||||
|
api_mode=None,
|
||||||
|
acp_command=None,
|
||||||
|
acp_args=None,
|
||||||
|
max_iterations=None,
|
||||||
|
reasoning_config=None,
|
||||||
|
prefill_messages=None,
|
||||||
|
providers_allowed=None,
|
||||||
|
providers_ignored=None,
|
||||||
|
providers_order=None,
|
||||||
|
provider_sort=None,
|
||||||
|
disabled_toolsets=None,
|
||||||
|
quiet_mode=None,
|
||||||
|
skip_memory=None,
|
||||||
|
platform=None,
|
||||||
|
session_id=None,
|
||||||
|
session_db=None,
|
||||||
|
):
|
||||||
|
seen.update({
|
||||||
|
"model": model,
|
||||||
|
"platform": platform,
|
||||||
|
"session_id": session_id,
|
||||||
|
"session_db": session_db,
|
||||||
|
})
|
||||||
|
|
||||||
|
def run_conversation(self, *_args, **_kwargs):
|
||||||
|
return {"final_response": "ok"}
|
||||||
|
|
||||||
|
with patch("cron.scheduler._hermes_home", tmp_path), \
|
||||||
|
patch("cron.scheduler._resolve_origin", return_value=None), \
|
||||||
|
patch("dotenv.load_dotenv"), \
|
||||||
|
patch("hermes_state.SessionDB", return_value=fake_db), \
|
||||||
|
patch(
|
||||||
|
"hermes_cli.runtime_provider.resolve_runtime_provider",
|
||||||
|
return_value={
|
||||||
|
"api_key": "***",
|
||||||
|
"base_url": "https://example.invalid/v1",
|
||||||
|
"provider": "openrouter",
|
||||||
|
"api_mode": "chat_completions",
|
||||||
|
},
|
||||||
|
), \
|
||||||
|
patch("run_agent.AIAgent", LegacyAgent):
|
||||||
|
success, output, final_response, error = run_job(job)
|
||||||
|
|
||||||
|
assert success is True
|
||||||
|
assert error is None
|
||||||
|
assert final_response == "ok"
|
||||||
|
assert "ok" in output
|
||||||
|
assert seen["model"] is not None
|
||||||
|
assert seen["platform"] == "cron"
|
||||||
|
assert seen["session_id"].startswith("cron_legacy-agent-job_")
|
||||||
|
assert seen["session_db"] is fake_db
|
||||||
|
fake_db.close.assert_called_once()
|
||||||
|
|
||||||
def test_run_job_empty_response_returns_empty_not_placeholder(self, tmp_path):
|
def test_run_job_empty_response_returns_empty_not_placeholder(self, tmp_path):
|
||||||
"""Empty final_response should stay empty for delivery logic (issue #2234).
|
"""Empty final_response should stay empty for delivery logic (issue #2234).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user