domyn 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of domyn might be problematic. Click here for more details.
- domyn/__init__.py +14 -0
- domyn/agents/__init__.py +108 -0
- domyn/agents/adapters/__init__.py +6 -0
- domyn/agents/adapters/_invocation.py +97 -0
- domyn/agents/adapters/domyn_agent.py +407 -0
- domyn/agents/adapters/langgraph.py +347 -0
- domyn/agents/agents/__init__.py +48 -0
- domyn/agents/agents/agent.py +780 -0
- domyn/agents/agents/base.py +77 -0
- domyn/agents/agents/delegate_agent.py +405 -0
- domyn/agents/agents/wrapped.py +118 -0
- domyn/agents/approvals/__init__.py +61 -0
- domyn/agents/approvals/models.py +205 -0
- domyn/agents/approvals/policy.py +185 -0
- domyn/agents/approvals/store.py +327 -0
- domyn/agents/approvals/subject.py +137 -0
- domyn/agents/audio/__init__.py +21 -0
- domyn/agents/audio/base.py +88 -0
- domyn/agents/audio/convert.py +78 -0
- domyn/agents/audio/local.py +214 -0
- domyn/agents/audio/models.py +34 -0
- domyn/agents/audio/openai_compatible.py +138 -0
- domyn/agents/channels/__init__.py +16 -0
- domyn/agents/channels/_parts.py +24 -0
- domyn/agents/channels/_voice.py +108 -0
- domyn/agents/channels/cursor_store.py +79 -0
- domyn/agents/channels/domyn_relay.py +339 -0
- domyn/agents/channels/slack.py +262 -0
- domyn/agents/channels/telegram.py +253 -0
- domyn/agents/channels/whatsapp.py +367 -0
- domyn/agents/cli/README.md +171 -0
- domyn/agents/cli/cli.py +102 -0
- domyn/agents/cli/cli_dependencies.py +78 -0
- domyn/agents/cli/commands/__init__.py +11 -0
- domyn/agents/cli/commands/export/__init__.py +3 -0
- domyn/agents/cli/commands/export/command.py +60 -0
- domyn/agents/cli/commands/init/__init__.py +5 -0
- domyn/agents/cli/commands/init/command.py +351 -0
- domyn/agents/cli/commands/run/__init__.py +5 -0
- domyn/agents/cli/commands/run/command.py +778 -0
- domyn/agents/cli/commands/serve/__init__.py +5 -0
- domyn/agents/cli/commands/serve/command.py +936 -0
- domyn/agents/cli/commands/serve/server.py +158 -0
- domyn/agents/cli/commands/setup/__init__.py +3 -0
- domyn/agents/cli/commands/setup/command.py +134 -0
- domyn/agents/cli/commands/skills/__init__.py +3 -0
- domyn/agents/cli/commands/skills/command.py +206 -0
- domyn/agents/cli/main.py +46 -0
- domyn/agents/cli/project.py +174 -0
- domyn/agents/cli/utils.py +31 -0
- domyn/agents/conversation_manager/__init__.py +17 -0
- domyn/agents/conversation_manager/base.py +341 -0
- domyn/agents/conversation_manager/in_memory.py +281 -0
- domyn/agents/conversation_manager/sqlite.py +479 -0
- domyn/agents/core/__init__.py +445 -0
- domyn/agents/core/context.py +91 -0
- domyn/agents/core/decorators.py +247 -0
- domyn/agents/core/documents.py +658 -0
- domyn/agents/core/exceptions.py +5 -0
- domyn/agents/core/interfaces.py +57 -0
- domyn/agents/core/utils.py +231 -0
- domyn/agents/core/visibility.py +43 -0
- domyn/agents/decisions/__init__.py +138 -0
- domyn/agents/decisions/approvals.py +147 -0
- domyn/agents/decisions/base.py +161 -0
- domyn/agents/decisions/config.py +148 -0
- domyn/agents/decisions/context.py +134 -0
- domyn/agents/decisions/events.py +73 -0
- domyn/agents/decisions/llm.py +322 -0
- domyn/agents/decisions/models.py +233 -0
- domyn/agents/decisions/none.py +35 -0
- domyn/agents/decisions/runtime.py +275 -0
- domyn/agents/decisions/sensitivity.py +180 -0
- domyn/agents/decisions/system_one.py +221 -0
- domyn/agents/decisions/tools.py +140 -0
- domyn/agents/decorators.py +10 -0
- domyn/agents/hooks/__init__.py +143 -0
- domyn/agents/hooks/base.py +134 -0
- domyn/agents/hooks/function_hook.py +516 -0
- domyn/agents/instructions/__init__.py +101 -0
- domyn/agents/instructions/conditional.py +203 -0
- domyn/agents/instructions/discovery.py +114 -0
- domyn/agents/instructions/models.py +147 -0
- domyn/agents/instructions/runtime.py +103 -0
- domyn/agents/instructions/sources.py +206 -0
- domyn/agents/integrations/__init__.py +0 -0
- domyn/agents/integrations/domyn/__init__.py +8 -0
- domyn/agents/integrations/domyn/domyn_platform.py +238 -0
- domyn/agents/integrations/domyn_platform_sdk.py +263 -0
- domyn/agents/integrations/hermes_platform_gateway/__init__.py +715 -0
- domyn/agents/integrations/hermes_platform_gateway/_context.py +43 -0
- domyn/agents/integrations/hermes_platform_gateway/adapter.py +1872 -0
- domyn/agents/integrations/hermes_platform_gateway/client.py +440 -0
- domyn/agents/integrations/hermes_platform_gateway/relay_client.py +189 -0
- domyn/agents/integrations/hermes_platform_gateway/schema.py +49 -0
- domyn/agents/integrations/langgraph/README.md +198 -0
- domyn/agents/integrations/langgraph/__init__.py +25 -0
- domyn/agents/integrations/langgraph/domyn_platform.py +230 -0
- domyn/agents/integrations/langgraph/handler.py +1020 -0
- domyn/agents/integrations/langgraph/run_state.py +157 -0
- domyn/agents/integrations/langgraph/utils.py +60 -0
- domyn/agents/integrations/utils.py +91 -0
- domyn/agents/interfaces/__init__.py +18 -0
- domyn/agents/interfaces/adapter.py +62 -0
- domyn/agents/interfaces/auth.py +19 -0
- domyn/agents/interfaces/channel.py +51 -0
- domyn/agents/interfaces/cli/__init__.py +10 -0
- domyn/agents/interfaces/cli/approval.py +403 -0
- domyn/agents/interfaces/cli/assets/logo_100.ans +11 -0
- domyn/agents/interfaces/cli/assets/logo_100.frames.gz +0 -0
- domyn/agents/interfaces/cli/assets/logo_120.ans +13 -0
- domyn/agents/interfaces/cli/assets/logo_120.frames.gz +0 -0
- domyn/agents/interfaces/cli/assets/logo_150.ans +17 -0
- domyn/agents/interfaces/cli/assets/logo_150.frames.gz +0 -0
- domyn/agents/interfaces/cli/banner.py +305 -0
- domyn/agents/interfaces/cli/calls.py +228 -0
- domyn/agents/interfaces/cli/commands.py +133 -0
- domyn/agents/interfaces/cli/config.py +1838 -0
- domyn/agents/interfaces/cli/context_view.py +186 -0
- domyn/agents/interfaces/cli/conversations.py +273 -0
- domyn/agents/interfaces/cli/export.py +1275 -0
- domyn/agents/interfaces/cli/grants.py +175 -0
- domyn/agents/interfaces/cli/inventory.py +63 -0
- domyn/agents/interfaces/cli/markdown.py +736 -0
- domyn/agents/interfaces/cli/processes_view.py +160 -0
- domyn/agents/interfaces/cli/project_import.py +243 -0
- domyn/agents/interfaces/cli/project_trust.py +68 -0
- domyn/agents/interfaces/cli/prompt.py +919 -0
- domyn/agents/interfaces/cli/renderer.py +859 -0
- domyn/agents/interfaces/cli/repl.py +1746 -0
- domyn/agents/interfaces/cli/select.py +619 -0
- domyn/agents/interfaces/cli/setup.py +1934 -0
- domyn/agents/interfaces/cli/skills_view.py +422 -0
- domyn/agents/interfaces/cli/spinner.py +268 -0
- domyn/agents/interfaces/cli/theme.py +274 -0
- domyn/agents/interfaces/cli/voice.py +339 -0
- domyn/agents/interfaces/cursor_store.py +28 -0
- domyn/agents/interfaces/normalizer.py +44 -0
- domyn/agents/llm/__init__.py +116 -0
- domyn/agents/llm/anthropic.py +492 -0
- domyn/agents/llm/base.py +395 -0
- domyn/agents/llm/cerebras.py +406 -0
- domyn/agents/llm/context_window.py +232 -0
- domyn/agents/llm/context_windows.json +78 -0
- domyn/agents/llm/custom.py +310 -0
- domyn/agents/llm/delegate.py +63 -0
- domyn/agents/llm/domyn.py +268 -0
- domyn/agents/llm/open_router.py +480 -0
- domyn/agents/llm/openai.py +471 -0
- domyn/agents/llm/vllm.py +423 -0
- domyn/agents/loader/__init__.py +120 -0
- domyn/agents/loader/config.py +1080 -0
- domyn/agents/logger/__init__.py +115 -0
- domyn/agents/memory/managers/__init__.py +17 -0
- domyn/agents/memory/managers/base.py +240 -0
- domyn/agents/memory/managers/local.py +164 -0
- domyn/agents/memory/managers/remote.py +60 -0
- domyn/agents/planner_strategy/__init__.py +308 -0
- domyn/agents/planner_strategy/base.py +66 -0
- domyn/agents/planner_strategy/context_injection.py +100 -0
- domyn/agents/planner_strategy/context_management/__init__.py +0 -0
- domyn/agents/planner_strategy/context_management/base.py +73 -0
- domyn/agents/planner_strategy/context_management/budget.py +231 -0
- domyn/agents/planner_strategy/context_management/compaction.py +1778 -0
- domyn/agents/planner_strategy/context_management/full_messages.py +80 -0
- domyn/agents/planner_strategy/context_management/summary.py +307 -0
- domyn/agents/planner_strategy/context_management/tool_use.py +747 -0
- domyn/agents/planner_strategy/prompting/__init__.py +1 -0
- domyn/agents/planner_strategy/prompting/base.py +372 -0
- domyn/agents/planner_strategy/prompting/data.py +46 -0
- domyn/agents/planner_strategy/prompting/json_prompting.py +380 -0
- domyn/agents/planner_strategy/prompting/messages_building.py +59 -0
- domyn/agents/planner_strategy/prompting/structural_tags_prompting.py +461 -0
- domyn/agents/planner_strategy/prompting/utils.py +152 -0
- domyn/agents/planner_strategy/react.py +665 -0
- domyn/agents/planner_strategy/tool_use.py +1021 -0
- domyn/agents/planner_strategy/tool_use_thought.py +658 -0
- domyn/agents/planner_strategy/utils.py +361 -0
- domyn/agents/plugins/__init__.py +5 -0
- domyn/agents/registry/__init__.py +23 -0
- domyn/agents/registry/agents.py +48 -0
- domyn/agents/registry/hooks.py +36 -0
- domyn/agents/registry/llm.py +55 -0
- domyn/agents/registry/planner_strategy.py +47 -0
- domyn/agents/registry/tools.py +40 -0
- domyn/agents/runner/__init__.py +4947 -0
- domyn/agents/runner/sse_transport.py +520 -0
- domyn/agents/runner/transport.py +303 -0
- domyn/agents/runner/websocket_transport.py +408 -0
- domyn/agents/scripts/__init__.py +7 -0
- domyn/agents/scripts/pdf_reader.py +184 -0
- domyn/agents/server.py +192 -0
- domyn/agents/skills/__init__.py +86 -0
- domyn/agents/skills/builtin/cli/domyn-cli/SKILL.md +346 -0
- domyn/agents/skills/builtin/cli/domyn-docs/SKILL.md +71 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/cli/configuration.md +191 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/cli/sessions.md +120 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/cli/tools-and-approvals.md +89 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/getting-started/installation.md +126 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/getting-started/quickstart-cli.md +89 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/getting-started/quickstart-library.md +97 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/approvals.md +347 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/configuration.md +293 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/context-compaction.md +150 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/conversations-and-memory.md +157 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/decision-models.md +211 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/events-and-streaming.md +163 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/hooks.md +234 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/llm-providers.md +225 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/orchestration.md +172 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/planner-strategies.md +139 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/remote-agents.md +279 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/skills.md +290 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/standing-instructions.md +129 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/tools.md +310 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/guides/transcription.md +122 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/index.md +41 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/reference/cli.md +160 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/reference/events.md +104 -0
- domyn/agents/skills/builtin/cli/domyn-docs/pages/reference/yaml-schema.md +172 -0
- domyn/agents/skills/builtin/data/data-analysis/SKILL.md +397 -0
- domyn/agents/skills/builtin/data/data-analysis/scripts/common.py +211 -0
- domyn/agents/skills/builtin/data/data-analysis/scripts/default_analysis.py +501 -0
- domyn/agents/skills/builtin/data/data-analysis/scripts/profile_data.py +290 -0
- domyn/agents/skills/builtin/data/data-analysis/scripts/timeseries_analysis.py +390 -0
- domyn/agents/skills/builtin/data/data_utils.py +479 -0
- domyn/agents/skills/builtin/data/prepare_series.py +425 -0
- domyn/agents/skills/builtin/data/prepare_table.py +360 -0
- domyn/agents/skills/builtin/data/series_format.py +304 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/SKILL.md +342 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/classification_baseline.py +135 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/classification_catboost.py +166 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/classification_compare.py +209 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/common.py +652 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/make_split.py +67 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/regression_baseline.py +108 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/regression_catboost.py +144 -0
- domyn/agents/skills/builtin/data/tabular-classification-regression/scripts/regression_compare.py +199 -0
- domyn/agents/skills/builtin/data/time-series-forecasting/SKILL.md +349 -0
- domyn/agents/skills/builtin/data/time-series-forecasting/scripts/common.py +474 -0
- domyn/agents/skills/builtin/data/time-series-forecasting/scripts/forecast_baseline.py +213 -0
- domyn/agents/skills/builtin/data/time-series-forecasting/scripts/forecast_catboost.py +287 -0
- domyn/agents/skills/builtin/data/time-series-forecasting/scripts/forecast_compare.py +398 -0
- domyn/agents/skills/builtin/data/time-series-forecasting/scripts/forecast_split.py +64 -0
- domyn/agents/skills/builtin/productivity/brainstorming/SKILL.md +184 -0
- domyn/agents/skills/builtin/productivity/communication/SKILL.md +126 -0
- domyn/agents/skills/builtin/productivity/documents/SKILL.md +218 -0
- domyn/agents/skills/builtin/productivity/documents/scripts/check_pdf.py +296 -0
- domyn/agents/skills/builtin/productivity/documents/scripts/pdf_layout.json +76 -0
- domyn/agents/skills/builtin/productivity/documents/scripts/pdf_layout.py +632 -0
- domyn/agents/skills/builtin/productivity/presentations/SKILL.md +463 -0
- domyn/agents/skills/builtin/productivity/presentations/scripts/check_pptx.py +886 -0
- domyn/agents/skills/builtin/productivity/presentations/scripts/slides.py +1102 -0
- domyn/agents/skills/builtin/productivity/presentations/template/layouts.pptx +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-Bold.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-BoldItalic.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-Italic.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-Light.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-LightItalic.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-Medium.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-MediumItalic.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-Regular.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-SemiBold.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/DMSans-SemiBoldItalic.ttf +0 -0
- domyn/agents/skills/builtin/resources/assets/fonts/OFL-LICENSE.txt +93 -0
- domyn/agents/skills/builtin/resources/palette.json +89 -0
- domyn/agents/skills/builtin/resources/plotly_style.py +170 -0
- domyn/agents/skills/builtin/resources/seaborn_style.py +310 -0
- domyn/agents/skills/builtin/resources/typography.json +41 -0
- domyn/agents/skills/builtin/visualization/charts/SKILL.md +173 -0
- domyn/agents/skills/builtin/visualization/interactive-charts/SKILL.md +135 -0
- domyn/agents/skills/catalog.py +279 -0
- domyn/agents/skills/external_files.py +82 -0
- domyn/agents/skills/integration.py +241 -0
- domyn/agents/skills/layout.py +111 -0
- domyn/agents/skills/local.py +110 -0
- domyn/agents/skills/models.py +228 -0
- domyn/agents/skills/parser.py +192 -0
- domyn/agents/skills/remote.py +19 -0
- domyn/agents/skills/runtime.py +392 -0
- domyn/agents/skills/search.py +278 -0
- domyn/agents/skills/selectors.py +409 -0
- domyn/agents/skills/sources.py +357 -0
- domyn/agents/skills/turn.py +100 -0
- domyn/agents/tools/__init__.py +38 -0
- domyn/agents/tools/base.py +669 -0
- domyn/agents/tools/builtin/__init__.py +259 -0
- domyn/agents/tools/builtin/backends.py +260 -0
- domyn/agents/tools/builtin/browser.py +331 -0
- domyn/agents/tools/builtin/browser_install.py +224 -0
- domyn/agents/tools/builtin/browser_sessions.py +922 -0
- domyn/agents/tools/builtin/files.py +708 -0
- domyn/agents/tools/builtin/processes.py +1084 -0
- domyn/agents/tools/builtin/session.py +258 -0
- domyn/agents/tools/builtin/shell.py +859 -0
- domyn/agents/tools/builtin/workspace.py +170 -0
- domyn/agents/tools/delegate_tool.py +165 -0
- domyn/agents/tools/function_tool.py +453 -0
- domyn/agents/tools/mcp/__init__.py +14 -0
- domyn/agents/tools/mcp/mcp_config.py +138 -0
- domyn/agents/tools/mcp/mcp_tool.py +845 -0
- domyn/agents/tools/mcp/oauth_providers.py +505 -0
- domyn/agents/tools/read_tool_result.py +271 -0
- domyn/agents/tools/rest_function_tool.py +167 -0
- domyn/agents/tools/schema.py +461 -0
- domyn/agents/tools/streamable_function_tool.py +68 -0
- domyn/agents/tracing/__init__.py +128 -0
- domyn-0.0.1.dist-info/METADATA +159 -0
- domyn-0.0.1.dist-info/RECORD +313 -0
- domyn-0.0.1.dist-info/WHEEL +4 -0
- domyn-0.0.1.dist-info/entry_points.txt +2 -0
- domyn-0.0.1.dist-info/licenses/LICENSE +202 -0
- domyn-0.0.1.dist-info/licenses/NOTICE +21 -0
domyn/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Domyn.
|
|
2
|
+
|
|
3
|
+
The top-level package of the Domyn distribution. Each product is a subpackage:
|
|
4
|
+
``domyn.agents`` is the agent framework. Importing ``domyn`` imports none of them.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
__version__ = version("domyn")
|
|
11
|
+
except PackageNotFoundError:
|
|
12
|
+
__version__ = "unknown"
|
|
13
|
+
|
|
14
|
+
__all__ = ["__version__"]
|
domyn/agents/__init__.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Domyn Agents.
|
|
2
|
+
|
|
3
|
+
Importing the package imports none of its subpackages, so a process that needs
|
|
4
|
+
one light module does not pay for the agent machinery. ``decorators`` and
|
|
5
|
+
``register_transport`` are imported on first use.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import warnings
|
|
9
|
+
from importlib import import_module
|
|
10
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
warnings.filterwarnings(
|
|
14
|
+
"ignore", category=UserWarning, message=r"Field name .* shadows an attribute in parent"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
__version__ = version("domyn")
|
|
19
|
+
except PackageNotFoundError:
|
|
20
|
+
__version__ = "unknown"
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Agent",
|
|
24
|
+
"AnthropicProvider",
|
|
25
|
+
"ApprovalType",
|
|
26
|
+
"BaseAgent",
|
|
27
|
+
"BaseEvent",
|
|
28
|
+
"ContextVisibility",
|
|
29
|
+
"DelegateAgent",
|
|
30
|
+
"ExecutionEventType",
|
|
31
|
+
"FunctionTool",
|
|
32
|
+
"HandoffScope",
|
|
33
|
+
"InteractionContext",
|
|
34
|
+
"MCPTool",
|
|
35
|
+
"OpenAIProvider",
|
|
36
|
+
"OpenRouterProvider",
|
|
37
|
+
"Part",
|
|
38
|
+
"Runner",
|
|
39
|
+
"StreamableFunctionTool",
|
|
40
|
+
"VLLMProvider",
|
|
41
|
+
"__version__",
|
|
42
|
+
"decorators",
|
|
43
|
+
"load_application_from_file",
|
|
44
|
+
"register_transport",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
# Public names, resolved on first use from the subpackage that owns them, so that
|
|
48
|
+
# ``from domyn.agents import Agent`` works while importing the package imports none
|
|
49
|
+
# of its subpackages.
|
|
50
|
+
_LAZY_EXPORTS = {
|
|
51
|
+
"Agent": "domyn.agents.agents",
|
|
52
|
+
"ContextVisibility": "domyn.agents.agents",
|
|
53
|
+
"HandoffScope": "domyn.agents.agents",
|
|
54
|
+
"ApprovalType": "domyn.agents.core",
|
|
55
|
+
"DelegateAgent": "domyn.agents.agents",
|
|
56
|
+
"BaseAgent": "domyn.agents.core",
|
|
57
|
+
"InteractionContext": "domyn.agents.core",
|
|
58
|
+
"BaseEvent": "domyn.agents.core",
|
|
59
|
+
"ExecutionEventType": "domyn.agents.core",
|
|
60
|
+
"Part": "domyn.agents.core",
|
|
61
|
+
"Runner": "domyn.agents.runner",
|
|
62
|
+
"FunctionTool": "domyn.agents.tools",
|
|
63
|
+
"StreamableFunctionTool": "domyn.agents.tools",
|
|
64
|
+
"MCPTool": "domyn.agents.tools",
|
|
65
|
+
"VLLMProvider": "domyn.agents.llm",
|
|
66
|
+
"OpenAIProvider": "domyn.agents.llm",
|
|
67
|
+
"OpenRouterProvider": "domyn.agents.llm",
|
|
68
|
+
"AnthropicProvider": "domyn.agents.llm",
|
|
69
|
+
"load_application_from_file": "domyn.agents.loader",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if TYPE_CHECKING:
|
|
73
|
+
from domyn.agents.agents import Agent as Agent
|
|
74
|
+
from domyn.agents.agents import ContextVisibility as ContextVisibility
|
|
75
|
+
from domyn.agents.agents import DelegateAgent as DelegateAgent
|
|
76
|
+
from domyn.agents.agents import HandoffScope as HandoffScope
|
|
77
|
+
from domyn.agents.core import ApprovalType as ApprovalType
|
|
78
|
+
from domyn.agents.core import BaseAgent as BaseAgent
|
|
79
|
+
from domyn.agents.core import BaseEvent as BaseEvent
|
|
80
|
+
from domyn.agents.core import ExecutionEventType as ExecutionEventType
|
|
81
|
+
from domyn.agents.core import InteractionContext as InteractionContext
|
|
82
|
+
from domyn.agents.core import Part as Part
|
|
83
|
+
from domyn.agents.core import decorators as decorators
|
|
84
|
+
from domyn.agents.llm import AnthropicProvider as AnthropicProvider
|
|
85
|
+
from domyn.agents.llm import OpenAIProvider as OpenAIProvider
|
|
86
|
+
from domyn.agents.llm import OpenRouterProvider as OpenRouterProvider
|
|
87
|
+
from domyn.agents.llm import VLLMProvider as VLLMProvider
|
|
88
|
+
from domyn.agents.loader import load_application_from_file as load_application_from_file
|
|
89
|
+
from domyn.agents.runner import Runner as Runner
|
|
90
|
+
from domyn.agents.runner.transport import register_transport as register_transport
|
|
91
|
+
from domyn.agents.tools import FunctionTool as FunctionTool
|
|
92
|
+
from domyn.agents.tools import MCPTool as MCPTool
|
|
93
|
+
from domyn.agents.tools import StreamableFunctionTool as StreamableFunctionTool
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def __getattr__(name: str) -> Any:
|
|
97
|
+
if name == "decorators":
|
|
98
|
+
return import_module("domyn.agents.decorators")
|
|
99
|
+
if name == "register_transport":
|
|
100
|
+
from domyn.agents.runner.transport import register_transport
|
|
101
|
+
|
|
102
|
+
globals()[name] = register_transport
|
|
103
|
+
return register_transport
|
|
104
|
+
if name in _LAZY_EXPORTS:
|
|
105
|
+
value = getattr(import_module(_LAZY_EXPORTS[name]), name)
|
|
106
|
+
globals()[name] = value
|
|
107
|
+
return value
|
|
108
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Shared per-invocation plumbing for FrameworkAdapter implementations.
|
|
2
|
+
|
|
3
|
+
LangGraphAdapter and DomynAgentAdapter each drive a fresh asyncio.Task for
|
|
4
|
+
their delegate/platform-tool callback (``call_platform_tool`` /
|
|
5
|
+
``_make_tool_call``) — LangGraph's ``ainvoke()`` and
|
|
6
|
+
``Runner._merge_with_injections`` both schedule every step of a turn via
|
|
7
|
+
``asyncio.ensure_future``/``asyncio.create_task``, so ``asyncio.current_task()``
|
|
8
|
+
inside that callback is never the task ``invoke()``'s ``_runner_task()``
|
|
9
|
+
registered anything under. A ``contextvars.ContextVar`` survives this where a
|
|
10
|
+
``dict[asyncio.Task, ...]`` would not: a ``contextvars.Context`` is copied into
|
|
11
|
+
every child task at the moment it is spawned from a task carrying it, so
|
|
12
|
+
``.get()`` finds the right value regardless of which disposable child task is
|
|
13
|
+
executing.
|
|
14
|
+
|
|
15
|
+
``InvocationCtx`` fields are *snapshots* taken at ``invoke()`` time, not a live
|
|
16
|
+
reference to the inbound ``BaseEvent``: the native Runner's
|
|
17
|
+
``_setup_conversation_turn`` rewrites that event's
|
|
18
|
+
``interaction_id``/``turn_id``/``conversation_id`` in place (it always mints
|
|
19
|
+
its own ``interaction_id``), so reading these fields later off a stored
|
|
20
|
+
reference yields the runner's regenerated ids instead of the platform's
|
|
21
|
+
originals — and the platform then can't correlate, or never answers, the tool
|
|
22
|
+
call. Both adapters hit the same failure mode, so both snapshot at
|
|
23
|
+
``invoke()`` time via ``spawn_invocation()`` below rather than re-reading the
|
|
24
|
+
event later.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import asyncio
|
|
28
|
+
import contextvars
|
|
29
|
+
from collections.abc import Awaitable, Callable
|
|
30
|
+
from dataclasses import dataclass
|
|
31
|
+
|
|
32
|
+
from domyn.agents.interfaces import EmitPriorityFn
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True, slots=True)
|
|
36
|
+
class InvocationCtx:
|
|
37
|
+
"""Per-invocation data needed by a platform/delegate tool round trip.
|
|
38
|
+
|
|
39
|
+
author/conversation_id/turn_id/interaction_id ride along with
|
|
40
|
+
emit_priority: the relay routes frames to the platform by
|
|
41
|
+
conversation_id and drops any frame whose value doesn't match, turn_id
|
|
42
|
+
is read by the transports' cross-turn replay filter, and
|
|
43
|
+
author/interaction_id are the correlation identity the platform matches
|
|
44
|
+
a TOOL_START against. Without them, TOOL_START events never reach the
|
|
45
|
+
platform-side runner and the tool call never completes.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
emit_priority: EmitPriorityFn
|
|
49
|
+
author: str
|
|
50
|
+
conversation_id: str | None
|
|
51
|
+
turn_id: str | None
|
|
52
|
+
interaction_id: str | None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# Shared by every FrameworkAdapter implementation. Safe across adapter types:
|
|
56
|
+
# each adapter's own _runner_task (built by spawn_invocation below) sets and
|
|
57
|
+
# resets its own value inside its own task's context, and InvocationCtx
|
|
58
|
+
# carries the invocation's own emit_priority closure rather than depending on
|
|
59
|
+
# which adapter subclass is running — nothing reads adapter identity off it.
|
|
60
|
+
invocation_ctx: contextvars.ContextVar[InvocationCtx | None] = contextvars.ContextVar(
|
|
61
|
+
"adapter_invocation_ctx", default=None
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def spawn_invocation(
|
|
66
|
+
*,
|
|
67
|
+
request_id: str,
|
|
68
|
+
conversation_id: str,
|
|
69
|
+
ctx: InvocationCtx,
|
|
70
|
+
semaphore: asyncio.Semaphore,
|
|
71
|
+
conversation_tasks: dict[str, asyncio.Task[None]],
|
|
72
|
+
in_flight: dict[str, asyncio.Task[None]],
|
|
73
|
+
run_body: Callable[[], Awaitable[None]],
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Schedule *run_body* under the invocation bookkeeping both adapters share.
|
|
76
|
+
|
|
77
|
+
Registers the task in *conversation_tasks* (read by on_cancel) and
|
|
78
|
+
*in_flight* (read by close() / the busy-buffer check), sets *ctx* on the
|
|
79
|
+
shared ``invocation_ctx`` ContextVar for the duration of the call, and
|
|
80
|
+
bounds concurrency with *semaphore* — all reset/popped in a ``finally``
|
|
81
|
+
so a cancelled or failing *run_body* still cleans up.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
async def _runner_task() -> None:
|
|
85
|
+
current = asyncio.current_task()
|
|
86
|
+
conversation_tasks[conversation_id] = current # type: ignore[assignment]
|
|
87
|
+
token = invocation_ctx.set(ctx)
|
|
88
|
+
try:
|
|
89
|
+
async with semaphore:
|
|
90
|
+
await run_body()
|
|
91
|
+
finally:
|
|
92
|
+
invocation_ctx.reset(token)
|
|
93
|
+
conversation_tasks.pop(conversation_id, None)
|
|
94
|
+
|
|
95
|
+
task = asyncio.create_task(_runner_task(), name=f"invoke:{request_id}")
|
|
96
|
+
in_flight[request_id] = task
|
|
97
|
+
task.add_done_callback(lambda _: in_flight.pop(request_id, None))
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"""DomynAgentAdapter — FrameworkAdapter that drives the native Domyn Runner.
|
|
2
|
+
|
|
3
|
+
WebSocket-specific code lives in the channel, not here. The adapter:
|
|
4
|
+
|
|
5
|
+
- Accepts ``(event, emit, emit_priority)`` per invocation.
|
|
6
|
+
- Drives ``Runner.run()`` and forwards emitted ``BaseEvent`` objects via *emit*
|
|
7
|
+
(best-effort) or *emit_priority* (guaranteed, used for TOOL_START and AGENT_END).
|
|
8
|
+
- Wires ``DelegateTool.relay`` so platform tool round-trips work:
|
|
9
|
+
DelegateTool.execute() → _make_tool_call() → emit_priority(TOOL_START)
|
|
10
|
+
→ suspend on Future → on_tool_response(TOOL_END) → Future resolved → return.
|
|
11
|
+
- Manages in-flight task concurrency with a semaphore and a busy-buffer.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import uuid
|
|
16
|
+
from datetime import UTC, datetime
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from domyn.agents.adapters._invocation import InvocationCtx, invocation_ctx, spawn_invocation
|
|
20
|
+
from domyn.agents.agents import Agent
|
|
21
|
+
from domyn.agents.core import BaseEvent, ExecutionEventType, ToolAction
|
|
22
|
+
from domyn.agents.interfaces import EmitFn, EmitPriorityFn
|
|
23
|
+
from domyn.agents.logger import get_logger
|
|
24
|
+
from domyn.agents.runner import Runner
|
|
25
|
+
from domyn.agents.tools import DelegateTool
|
|
26
|
+
|
|
27
|
+
logger = get_logger()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Helpers
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _collect_delegate_tools(agent: Agent) -> list[DelegateTool]:
|
|
36
|
+
"""Walk the agent tree and collect every DelegateTool without a wrapped callable."""
|
|
37
|
+
tools: list[DelegateTool] = []
|
|
38
|
+
visited: set[str] = set()
|
|
39
|
+
|
|
40
|
+
def _walk(a: Agent) -> None:
|
|
41
|
+
if a.name in visited:
|
|
42
|
+
return
|
|
43
|
+
visited.add(a.name)
|
|
44
|
+
for tool in getattr(a, "tools", []):
|
|
45
|
+
if isinstance(tool, DelegateTool) and tool.wrapped is None:
|
|
46
|
+
tools.append(tool)
|
|
47
|
+
for sub in getattr(a, "sub_agents", []):
|
|
48
|
+
if isinstance(sub, Agent):
|
|
49
|
+
_walk(sub)
|
|
50
|
+
|
|
51
|
+
_walk(agent)
|
|
52
|
+
return tools
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# DomynAgentAdapter
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DomynAgentAdapter:
|
|
61
|
+
"""FrameworkAdapter that drives a native Domyn Agent via ``Runner.run()``.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
root:
|
|
66
|
+
Root agent of the agent tree to execute.
|
|
67
|
+
application_name:
|
|
68
|
+
Identifies this application in traces and conversation history.
|
|
69
|
+
user_id:
|
|
70
|
+
User identity forwarded to the Runner.
|
|
71
|
+
max_concurrency:
|
|
72
|
+
Maximum number of simultaneously active invocations.
|
|
73
|
+
busy_buffer:
|
|
74
|
+
Additional invocations queued behind the semaphore before WorkerBusy
|
|
75
|
+
rejection kicks in. Defaults to *max_concurrency*.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
root: Agent,
|
|
81
|
+
application_name: str = "domyn-exposed",
|
|
82
|
+
user_id: str = "platform",
|
|
83
|
+
max_concurrency: int = 8,
|
|
84
|
+
busy_buffer: int | None = None,
|
|
85
|
+
) -> None:
|
|
86
|
+
self._root = root
|
|
87
|
+
self._application_name = application_name
|
|
88
|
+
self._user_id = user_id
|
|
89
|
+
self._max_concurrency = max_concurrency
|
|
90
|
+
self._busy_buffer = busy_buffer if busy_buffer is not None else max_concurrency
|
|
91
|
+
|
|
92
|
+
self._runner = Runner()
|
|
93
|
+
self._semaphore = asyncio.Semaphore(max_concurrency)
|
|
94
|
+
|
|
95
|
+
# In-flight task registry (keyed by request_id == event_id of AGENT_START)
|
|
96
|
+
self._in_flight: dict[str, asyncio.Task[None]] = {}
|
|
97
|
+
# Separate index by conversation_id for cancel routing
|
|
98
|
+
self._conversation_tasks: dict[str, asyncio.Task[None]] = {}
|
|
99
|
+
|
|
100
|
+
# Platform-tool round-trip state
|
|
101
|
+
self._platform_calls: dict[str, asyncio.Future[Any]] = {}
|
|
102
|
+
|
|
103
|
+
# Wire relay onto every DelegateTool in the agent tree
|
|
104
|
+
self._delegate_tools = _collect_delegate_tools(root)
|
|
105
|
+
self._delegate_tool_names = frozenset(t.tool_name for t in self._delegate_tools)
|
|
106
|
+
for tool in self._delegate_tools:
|
|
107
|
+
tool.relay = self._make_tool_call
|
|
108
|
+
if self._delegate_tools:
|
|
109
|
+
logger.info(
|
|
110
|
+
"DomynAgentAdapter: wired delegate tools: %s",
|
|
111
|
+
", ".join(t.tool_name for t in self._delegate_tools),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
self.events_dropped: int = 0
|
|
115
|
+
|
|
116
|
+
# ------------------------------------------------------------------
|
|
117
|
+
# Periodic platform-tool rediscovery
|
|
118
|
+
# ------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
async def refresh_delegate_tools(
|
|
121
|
+
self,
|
|
122
|
+
api_key: str | None,
|
|
123
|
+
space_id: str | None,
|
|
124
|
+
channel_id: str | None,
|
|
125
|
+
base_url: str | None,
|
|
126
|
+
configuration_id: str | None,
|
|
127
|
+
attach_new_tools: bool = True,
|
|
128
|
+
) -> None:
|
|
129
|
+
"""Re-run platform tool discovery against the live agent tree.
|
|
130
|
+
|
|
131
|
+
Unlike the one-time call at startup, a failed fetch here leaves the
|
|
132
|
+
existing tool set untouched (``drop_on_fetch_failure=False``) — a
|
|
133
|
+
transient network blip must not wipe out every platform tool from a
|
|
134
|
+
running worker. Newly attached DelegateTool instances are wired with
|
|
135
|
+
this adapter's relay exactly as ``__init__`` wires the initial set.
|
|
136
|
+
"""
|
|
137
|
+
from domyn.agents.integrations.domyn import populate_delegate_tool_schemas
|
|
138
|
+
|
|
139
|
+
await populate_delegate_tool_schemas(
|
|
140
|
+
root=self._root,
|
|
141
|
+
api_key=api_key,
|
|
142
|
+
space_id=space_id,
|
|
143
|
+
channel_id=channel_id,
|
|
144
|
+
base_url=base_url,
|
|
145
|
+
configuration_id=configuration_id,
|
|
146
|
+
attach_new_tools=attach_new_tools,
|
|
147
|
+
drop_on_fetch_failure=False,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
fresh = _collect_delegate_tools(self._root)
|
|
151
|
+
for tool in fresh:
|
|
152
|
+
if tool.relay is None:
|
|
153
|
+
tool.relay = self._make_tool_call
|
|
154
|
+
self._delegate_tools = fresh
|
|
155
|
+
self._delegate_tool_names = frozenset(t.tool_name for t in fresh)
|
|
156
|
+
if fresh:
|
|
157
|
+
logger.info(
|
|
158
|
+
f"DomynAgentAdapter: refreshed delegate tools: "
|
|
159
|
+
f"{', '.join(t.tool_name for t in fresh)}"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# ------------------------------------------------------------------
|
|
163
|
+
# FrameworkAdapter contract
|
|
164
|
+
# ------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
async def invoke(
|
|
167
|
+
self,
|
|
168
|
+
event: BaseEvent,
|
|
169
|
+
emit: EmitFn,
|
|
170
|
+
emit_priority: EmitPriorityFn,
|
|
171
|
+
) -> None:
|
|
172
|
+
"""Schedule execution of one AGENT_START event.
|
|
173
|
+
|
|
174
|
+
Returns immediately after creating the asyncio.Task.
|
|
175
|
+
"""
|
|
176
|
+
request_id = event.event_id or ""
|
|
177
|
+
if not request_id:
|
|
178
|
+
logger.warning("DomynAgentAdapter.invoke: AGENT_START has no event_id; skipping")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
if len(self._in_flight) >= self._max_concurrency + self._busy_buffer:
|
|
182
|
+
# event_id is per-frame unique; let BaseEvent auto-generate it. Stamping the
|
|
183
|
+
# inbound request's id here makes the delegating transport dedup this frame as
|
|
184
|
+
# a replay of the AGENT_START it already saw and drop it silently, so the turn
|
|
185
|
+
# dies on a read timeout instead. The correlation rides in metadata.
|
|
186
|
+
busy = BaseEvent(
|
|
187
|
+
event_type=ExecutionEventType.ERROR_OCCURRED,
|
|
188
|
+
author=event.author,
|
|
189
|
+
timestamp=datetime.now(UTC).replace(tzinfo=None),
|
|
190
|
+
interaction_id=event.interaction_id,
|
|
191
|
+
error_code="WorkerBusy",
|
|
192
|
+
error_message="max concurrency reached",
|
|
193
|
+
metadata={"request_id": request_id},
|
|
194
|
+
)
|
|
195
|
+
await emit_priority(busy)
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
conversation_id = event.conversation_id or request_id
|
|
199
|
+
|
|
200
|
+
async def _run_body() -> None:
|
|
201
|
+
await self._run_agent(event, request_id, conversation_id, emit, emit_priority)
|
|
202
|
+
|
|
203
|
+
spawn_invocation(
|
|
204
|
+
request_id=request_id,
|
|
205
|
+
conversation_id=conversation_id,
|
|
206
|
+
ctx=InvocationCtx(
|
|
207
|
+
emit_priority=emit_priority,
|
|
208
|
+
author=event.author,
|
|
209
|
+
conversation_id=conversation_id,
|
|
210
|
+
turn_id=event.turn_id,
|
|
211
|
+
interaction_id=event.interaction_id,
|
|
212
|
+
),
|
|
213
|
+
semaphore=self._semaphore,
|
|
214
|
+
conversation_tasks=self._conversation_tasks,
|
|
215
|
+
in_flight=self._in_flight,
|
|
216
|
+
run_body=_run_body,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def on_tool_response(self, event: BaseEvent) -> None:
|
|
220
|
+
"""Resolve (or reject) the Future suspended on a DelegateTool call."""
|
|
221
|
+
call_id = getattr(event.action, "call_id", None) if event.action else None
|
|
222
|
+
if call_id is None:
|
|
223
|
+
return
|
|
224
|
+
future = self._platform_calls.pop(call_id, None)
|
|
225
|
+
if future is None or future.done():
|
|
226
|
+
return
|
|
227
|
+
if event.event_type == ExecutionEventType.TOOL_ERROR:
|
|
228
|
+
future.set_exception(
|
|
229
|
+
RuntimeError(event.error_message or f"platform tool error ({event.error_code})")
|
|
230
|
+
)
|
|
231
|
+
else:
|
|
232
|
+
observation = getattr(event.action, "observation", None) if event.action else None
|
|
233
|
+
future.set_result(observation)
|
|
234
|
+
|
|
235
|
+
def on_cancel(self, event: BaseEvent) -> None:
|
|
236
|
+
"""Cancel the in-flight task for the given conversation_id."""
|
|
237
|
+
conv_id = event.conversation_id
|
|
238
|
+
if not conv_id:
|
|
239
|
+
logger.debug("DomynAgentAdapter.on_cancel: no conversation_id — cancelling all")
|
|
240
|
+
for t in list(self._in_flight.values()):
|
|
241
|
+
t.cancel()
|
|
242
|
+
return
|
|
243
|
+
task: asyncio.Task[None] | None = self._conversation_tasks.get(conv_id)
|
|
244
|
+
if task is None or task.done():
|
|
245
|
+
logger.debug("DomynAgentAdapter.on_cancel: no in-flight task for conv=%s", conv_id)
|
|
246
|
+
return
|
|
247
|
+
logger.info("DomynAgentAdapter.on_cancel: cancelling conv=%s", conv_id)
|
|
248
|
+
task.cancel()
|
|
249
|
+
|
|
250
|
+
async def close(self) -> None:
|
|
251
|
+
"""Cancel all in-flight tasks and reject pending DelegateTool Futures."""
|
|
252
|
+
for fut in self._platform_calls.values():
|
|
253
|
+
if not fut.done():
|
|
254
|
+
fut.set_exception(RuntimeError("DomynAgentAdapter shutting down"))
|
|
255
|
+
self._platform_calls.clear()
|
|
256
|
+
self._conversation_tasks.clear()
|
|
257
|
+
for task in list(self._in_flight.values()):
|
|
258
|
+
task.cancel()
|
|
259
|
+
if self._in_flight:
|
|
260
|
+
await asyncio.gather(*self._in_flight.values(), return_exceptions=True)
|
|
261
|
+
|
|
262
|
+
# ------------------------------------------------------------------
|
|
263
|
+
# Internal — invocation execution
|
|
264
|
+
# ------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
async def _run_agent(
|
|
267
|
+
self,
|
|
268
|
+
agent_start: BaseEvent,
|
|
269
|
+
request_id: str,
|
|
270
|
+
conversation_id: str,
|
|
271
|
+
emit: EmitFn,
|
|
272
|
+
emit_priority: EmitPriorityFn,
|
|
273
|
+
) -> None:
|
|
274
|
+
"""Run the Runner for one invocation and forward events to the channel."""
|
|
275
|
+
done: BaseEvent
|
|
276
|
+
try:
|
|
277
|
+
_saw_terminal = False
|
|
278
|
+
async for ev in self._runner.run(
|
|
279
|
+
application_name=self._application_name,
|
|
280
|
+
user_id=self._user_id,
|
|
281
|
+
user_input=agent_start,
|
|
282
|
+
root=self._root,
|
|
283
|
+
conversation_id=conversation_id,
|
|
284
|
+
):
|
|
285
|
+
# Track whether the runner itself emitted a terminal event so we
|
|
286
|
+
# skip the synthetic AGENT_END below.
|
|
287
|
+
if (
|
|
288
|
+
(ev.event_type == ExecutionEventType.AGENT_END and ev.author == self._root.name)
|
|
289
|
+
or (ev.event_type == ExecutionEventType.RESPONSE and not ev.is_partial)
|
|
290
|
+
or ev.event_type == ExecutionEventType.TOOL_NEEDS_FEEDBACK
|
|
291
|
+
):
|
|
292
|
+
_saw_terminal = True
|
|
293
|
+
|
|
294
|
+
# Suppress the runner's observability TOOL_START/TOOL_END for
|
|
295
|
+
# DelegateTool names. _make_tool_call() runs the whole round trip
|
|
296
|
+
# itself under a fresh call_id: it sends its own TOOL_START, and
|
|
297
|
+
# the platform answers with the TOOL_END that resolves it. The
|
|
298
|
+
# runner's pair carries the *LLM's* tool_call id instead — an id
|
|
299
|
+
# the platform never issued — so forwarding them shows the relay a
|
|
300
|
+
# duplicate TOOL_START and then a TOOL_END for a call it cannot
|
|
301
|
+
# match. TOOL_ERROR is deliberately still forwarded: that one
|
|
302
|
+
# reports a local failure (e.g. the relay round trip itself
|
|
303
|
+
# failing), which is information the platform does not already have.
|
|
304
|
+
if (
|
|
305
|
+
ev.event_type in (ExecutionEventType.TOOL_START, ExecutionEventType.TOOL_END)
|
|
306
|
+
and getattr(ev.action, "name", None) in self._delegate_tool_names
|
|
307
|
+
):
|
|
308
|
+
continue
|
|
309
|
+
|
|
310
|
+
# Must never be dropped: losing it strands the turn forever — the
|
|
311
|
+
# human never sees the approval request, and nothing else will
|
|
312
|
+
# ever re-prompt them. emit() is best-effort (drops when the
|
|
313
|
+
# channel's outbound queue is full); emit_priority() blocks
|
|
314
|
+
# instead, the same guarantee already given to TOOL_START/AGENT_END.
|
|
315
|
+
if ev.event_type == ExecutionEventType.TOOL_NEEDS_FEEDBACK:
|
|
316
|
+
await emit_priority(ev)
|
|
317
|
+
continue
|
|
318
|
+
|
|
319
|
+
await emit(ev)
|
|
320
|
+
|
|
321
|
+
if _saw_terminal:
|
|
322
|
+
return
|
|
323
|
+
|
|
324
|
+
done = BaseEvent(
|
|
325
|
+
event_type=ExecutionEventType.AGENT_END,
|
|
326
|
+
author=self._root.name,
|
|
327
|
+
timestamp=datetime.now(UTC).replace(tzinfo=None),
|
|
328
|
+
interaction_id=agent_start.interaction_id,
|
|
329
|
+
conversation_id=conversation_id,
|
|
330
|
+
turn_id=agent_start.turn_id,
|
|
331
|
+
metadata={"request_id": request_id},
|
|
332
|
+
)
|
|
333
|
+
except asyncio.CancelledError:
|
|
334
|
+
raise
|
|
335
|
+
except Exception as exc:
|
|
336
|
+
logger.error(
|
|
337
|
+
"DomynAgentAdapter: invocation failed request_id=%s: %s",
|
|
338
|
+
request_id,
|
|
339
|
+
exc,
|
|
340
|
+
exc_info=True,
|
|
341
|
+
)
|
|
342
|
+
done = BaseEvent(
|
|
343
|
+
event_type=ExecutionEventType.AGENT_END,
|
|
344
|
+
author=self._root.name,
|
|
345
|
+
timestamp=datetime.now(UTC).replace(tzinfo=None),
|
|
346
|
+
interaction_id=agent_start.interaction_id,
|
|
347
|
+
conversation_id=conversation_id,
|
|
348
|
+
turn_id=agent_start.turn_id,
|
|
349
|
+
error_code=type(exc).__name__,
|
|
350
|
+
error_message=str(exc),
|
|
351
|
+
metadata={"request_id": request_id},
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
done = done.model_copy(update={"timestamp": datetime.now(UTC).replace(tzinfo=None)})
|
|
355
|
+
await emit_priority(done)
|
|
356
|
+
|
|
357
|
+
# ------------------------------------------------------------------
|
|
358
|
+
# Internal — DelegateTool round-trip
|
|
359
|
+
# ------------------------------------------------------------------
|
|
360
|
+
|
|
361
|
+
async def _make_tool_call(self, name: str, kwargs: dict[str, Any]) -> Any:
|
|
362
|
+
"""Send TOOL_START to the relay and suspend until TOOL_END / TOOL_ERROR.
|
|
363
|
+
|
|
364
|
+
Called by ``DelegateTool.execute()`` via ``tool.relay``. Correlation IDs
|
|
365
|
+
are read from the shared ``invocation_ctx`` ContextVar set by
|
|
366
|
+
``invoke()`` via ``spawn_invocation()``, not from
|
|
367
|
+
``asyncio.current_task()``: ``Runner._merge_with_injections`` drives
|
|
368
|
+
every step of the turn (including the step that reaches this
|
|
369
|
+
DelegateTool) in a fresh ``asyncio.Task`` via ``asyncio.ensure_future``,
|
|
370
|
+
so the task executing here is never the one ``invoke()`` created. The
|
|
371
|
+
ContextVar is still found because a ``contextvars.Context`` is copied
|
|
372
|
+
into every child task spawned from a task carrying it, and concurrent
|
|
373
|
+
invocations each get their own copy — see ``InvocationCtx``.
|
|
374
|
+
"""
|
|
375
|
+
ctx = invocation_ctx.get()
|
|
376
|
+
|
|
377
|
+
if ctx is None:
|
|
378
|
+
raise RuntimeError(
|
|
379
|
+
"DomynAgentAdapter._make_tool_call: no invocation context for current task — "
|
|
380
|
+
"cannot send TOOL_START. Is the DelegateTool being called outside of invoke()?"
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
call_id = str(uuid.uuid4())
|
|
384
|
+
tool_start = BaseEvent(
|
|
385
|
+
event_type=ExecutionEventType.TOOL_START,
|
|
386
|
+
author=ctx.author,
|
|
387
|
+
timestamp=datetime.now(UTC).replace(tzinfo=None),
|
|
388
|
+
conversation_id=ctx.conversation_id,
|
|
389
|
+
interaction_id=ctx.interaction_id,
|
|
390
|
+
turn_id=ctx.turn_id,
|
|
391
|
+
action=ToolAction(name=name, parameters=kwargs, call_id=call_id),
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
loop = asyncio.get_running_loop()
|
|
395
|
+
future: asyncio.Future[Any] = loop.create_future()
|
|
396
|
+
self._platform_calls[call_id] = future
|
|
397
|
+
|
|
398
|
+
try:
|
|
399
|
+
await ctx.emit_priority(tool_start)
|
|
400
|
+
except Exception:
|
|
401
|
+
self._platform_calls.pop(call_id, None)
|
|
402
|
+
raise
|
|
403
|
+
|
|
404
|
+
try:
|
|
405
|
+
return await future
|
|
406
|
+
finally:
|
|
407
|
+
self._platform_calls.pop(call_id, None)
|