Skip to content

Commit d2d08ff

Browse files
iyernaveenr4pmtong
andauthored
Make the agent step timeout configurable and record spend of failed runs (#1746)
Signed-off-by: Naveen R. Iyer <iyernaveenr@gmail.com> Co-authored-by: Tong Chen <web_chentong@163.com>
1 parent 7f50917 commit d2d08ff

3 files changed

Lines changed: 36 additions & 2 deletions

File tree

backend/app/agent/listen_chat_agent.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from camel.types.agents import ToolCallingRecord
3737
from pydantic import BaseModel
3838

39+
from app.component.environment import env
3940
from app.service.task import (
4041
Action,
4142
ActionActivateAgentData,
@@ -52,6 +53,21 @@
5253
logger = logging.getLogger("agent")
5354

5455

56+
# Default 30 minutes; long agent turns (e.g. writing many chapters in one
57+
# run) can legitimately exceed it, so allow tuning without a rebuild.
58+
# A non-positive value disables the per-step timeout entirely.
59+
def default_step_timeout() -> float | None:
60+
raw = env("AGENT_STEP_TIMEOUT_SECONDS", "1800")
61+
try:
62+
value = float(raw)
63+
except (TypeError, ValueError):
64+
logger.warning(
65+
"Invalid AGENT_STEP_TIMEOUT_SECONDS value %r; using 1800", raw
66+
)
67+
return 1800.0
68+
return value if value > 0 else None
69+
70+
5571
class ListenChatAgent(ChatAgent):
5672
_cdp_clone_lock = (
5773
threading.Lock()
@@ -95,12 +111,14 @@ def __init__(
95111
pause_event: asyncio.Event | None = None,
96112
prune_tool_calls_from_memory: bool = False,
97113
enable_snapshot_clean: bool = False,
98-
step_timeout: float | None = 1800, # 30 minutes
114+
step_timeout: float | None = None,
99115
model_reload_callback: (
100116
Callable[[], BaseModelBackend | ModelManager] | None
101117
) = None,
102118
**kwargs: Any,
103119
) -> None:
120+
if step_timeout is None:
121+
step_timeout = default_step_timeout()
104122
super().__init__(
105123
system_message=system_message,
106124
model=model,

backend/app/agent/toolkit/screenshot_toolkit.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from camel.toolkits import ScreenshotToolkit as BaseScreenshotToolkit
2121
from PIL import Image
2222

23+
from app.agent.listen_chat_agent import default_step_timeout
2324
from app.agent.toolkit.abstract_toolkit import AbstractToolkit
2425
from app.component.environment import env
2526
from app.utils.listen.toolkit_listen import auto_listen_toolkit
@@ -86,7 +87,9 @@ def read_image(
8687
tools=[],
8788
toolkits_to_register_agent=None,
8889
external_tools=None,
89-
step_timeout=getattr(self.agent, "step_timeout", 1800),
90+
step_timeout=getattr(
91+
self.agent, "step_timeout", default_step_timeout()
92+
),
9093
)
9194
response = vision_agent.step(message)
9295
if getattr(response, "msg", None) is not None:

src/store/chatStore.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3350,6 +3350,19 @@ const chatStore = (initial?: Partial<ChatStore>) =>
33503350
role: 'agent',
33513351
content: `❌ **Error**: ${errorMessage}`,
33523352
});
3353+
// Record the tokens consumed before the failure so the run's
3354+
// spend is not lost from the history row (a failed run
3355+
// otherwise stays at zero tokens forever).
3356+
if (!type && historyId && !isProjectBusyError) {
3357+
const tokensSoFar = getTokens(currentTaskId);
3358+
if (tokensSoFar > 0) {
3359+
proxyFetchPut(`/api/v1/chat/history/${historyId}`, {
3360+
tokens: tokensSoFar,
3361+
}).catch((err) => {
3362+
console.warn('History token update failed on error:', err);
3363+
});
3364+
}
3365+
}
33533366
uploadLog(currentTaskId, type);
33543367
// Update trigger execution status to Failed on error
33553368
updateTriggerExecutionStatus(

0 commit comments

Comments
 (0)