Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b3b7ed6
.
MkDev11 Jan 22, 2026
e1ee5c1
fix: disable streaming for worker agents to prevent camel library error
MkDev11 Jan 22, 2026
abae378
feat: add streaming tool activity messages during task execution
MkDev11 Jan 22, 2026
d1e0e99
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 22, 2026
70b2357
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 22, 2026
15d5d7e
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 22, 2026
12a1a5c
Merge branch 'main' into feature/streaming-agent-output
fengju0213 Jan 23, 2026
309883d
fix: correct comment about streaming error cause
MkDev11 Jan 23, 2026
e7b2269
Merge remote-tracking branch 'origin/main' into feature/streaming-age…
a7m-1st Jan 23, 2026
f8bad62
choe: revert env
a7m-1st Jan 23, 2026
52df15b
enhance: use _schedule_async_task to avoid async race conditions in g…
a7m-1st Jan 23, 2026
9edb548
enhance: use _schedule_async_task to avoid async race conditions in g…
a7m-1st Jan 23, 2026
8a44f38
fix: address PR review comments from a7m-1st
MkDev11 Jan 23, 2026
df77971
refactor: remove tool streaming events, keep infra for model output s…
MkDev11 Jan 23, 2026
8902bdb
Merge upstream/main into feature/streaming-agent-output
MkDev11 Jan 25, 2026
8c54244
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 25, 2026
9a3c256
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 25, 2026
460eda5
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 26, 2026
ceddf47
style: change leading-tight to leading-normal for better readability
MkDev11 Jan 26, 2026
6ff3915
Merge branch 'main' into feature/streaming-agent-output
MkDev11 Jan 26, 2026
81b5f6e
refactor: remove AsyncChatCompletionStreamManager workaround
MkDev11 Jan 26, 2026
f4574ac
refactor: remove AsyncChatCompletionStreamManager workaround from sin…
MkDev11 Jan 26, 2026
6759353
chore: update camel-ai to 0.2.85
MkDev11 Jan 26, 2026
32316d2
refactor: update clone preservation comment
MkDev11 Jan 26, 2026
523ba97
Merge upstream/main - port streaming output feature to refactored age…
MkDev11 Jan 30, 2026
78d7962
Merge upstream/main - resolve frontend conflicts and add streaming ag…
MkDev11 Feb 1, 2026
5c65669
fix: PEP8 line too long in task.py
MkDev11 Feb 1, 2026
927244f
style: yapf format task.py
MkDev11 Feb 1, 2026
1087a17
fix: resolve conflict in node.tsx, preserve streaming agent output fe…
MkDev11 Feb 2, 2026
7fdfadf
fix: resolve merge conflicts with upstream/main, update to use AgentS…
MkDev11 Feb 2, 2026
4dfef33
chore: isolate set_main_event_loop & _schedule_async_task
a7m-1st Feb 3, 2026
9949d35
refactor: remove streaming_agent_output feature, keep event_loop_util…
MkDev11 Feb 3, 2026
66c3df6
fix: add mock for _schedule_async_task in agent model test
MkDev11 Feb 3, 2026
c5ddcb4
style: fix lint issues with ruff
MkDev11 Feb 3, 2026
257597f
style: fix import order with isort
MkDev11 Feb 3, 2026
f7ab0f8
update based on review comment
Wendong-Fan Feb 3, 2026
eba1277
Merge branch 'main' into feature/streaming-agent-output
Wendong-Fan Feb 3, 2026
77f96d9
using _schedule_async_task
Wendong-Fan Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions backend/app/agent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# limitations under the License.
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========

from app.agent.agent_model import agent_model, set_main_event_loop
from app.agent.agent_model import agent_model
from app.agent.factory import (
browser_agent,
developer_agent,
Expand All @@ -31,7 +31,6 @@
"agent_model",
"get_mcp_tools",
"get_toolkits",
"set_main_event_loop",
"browser_agent",
"developer_agent",
"document_agent",
Expand Down
62 changes: 1 addition & 61 deletions backend/app/agent/agent_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,80 +12,20 @@
# limitations under the License.
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========

import asyncio
import contextvars
import logging
import uuid
from threading import Lock
from typing import Any, Callable

from camel.messages import BaseMessage
from camel.models import ModelFactory
from camel.toolkits import FunctionTool, RegisteredAgentToolkit
from camel.types import ModelPlatformType

from app.utils.event_loop_utils import _schedule_async_task
from app.agent.listen_chat_agent import ListenChatAgent, logger
from app.model.chat import AgentModelConfig, Chat
from app.service.task import ActionCreateAgentData, Agents, get_task_lock

# Thread-safe reference to main event loop using contextvars
# This ensures each request has its own event loop reference,
# avoiding race conditions
_main_event_loop_var: contextvars.ContextVar[asyncio.AbstractEventLoop
| None] = contextvars.ContextVar(
"_main_event_loop",
default=None
)

# Global fallback for main event loop reference
# Used when contextvars don't propagate to worker threads
# (e.g., asyncio.to_thread)
_GLOBAL_MAIN_LOOP: asyncio.AbstractEventLoop | None = None
_GLOBAL_MAIN_LOOP_LOCK = Lock()


def set_main_event_loop(loop: asyncio.AbstractEventLoop | None):
"""Set the main event loop reference for thread-safe task scheduling.

This should be called from the main async context before spawning threads
that need to schedule async tasks. Uses both contextvars (for request
isolation) and a global fallback (for thread pool workers where
contextvars may not propagate).
"""
global _GLOBAL_MAIN_LOOP
_main_event_loop_var.set(loop)
with _GLOBAL_MAIN_LOOP_LOCK:
_GLOBAL_MAIN_LOOP = loop


def _schedule_async_task(coro):
"""Schedule an async coroutine as a task, thread-safe.

This function handles scheduling from both the main event loop thread
and from worker threads (e.g., when using asyncio.to_thread).
"""
try:
# Try to get the running loop (works in main event loop thread)
loop = asyncio.get_running_loop()
loop.create_task(coro)
except RuntimeError:
# No running loop in this thread (we're in a worker thread)
# First try contextvars, then fallback to global reference
main_loop = _main_event_loop_var.get()
if main_loop is None:
with _GLOBAL_MAIN_LOOP_LOCK:
main_loop = _GLOBAL_MAIN_LOOP
if main_loop is not None and main_loop.is_running():
asyncio.run_coroutine_threadsafe(coro, main_loop)
else:
# This should not happen in normal operation - log error and skip
logging.error(
"No event loop available for async task "
"scheduling, task skipped. Ensure "
"set_main_event_loop() is called "
"before parallel agent creation."
)


def agent_model(
agent_name: str,
Expand Down
Loading
Loading