ouro-agent 0.2.0__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.
- ouro/__init__.py +5 -0
- ouro/application/__init__.py +155 -0
- ouro/application/agent_definitions.py +356 -0
- ouro/application/agent_execution.py +179 -0
- ouro/application/agent_models.py +211 -0
- ouro/application/agent_recovery.py +492 -0
- ouro/application/agent_tree.py +520 -0
- ouro/application/agents.py +2464 -0
- ouro/application/compaction.py +1706 -0
- ouro/application/configuration.py +1275 -0
- ouro/application/configuration_models.py +449 -0
- ouro/application/configuration_transfer.py +119 -0
- ouro/application/configuration_views.py +261 -0
- ouro/application/data_transfer.py +161 -0
- ouro/application/dto.py +38 -0
- ouro/application/event_models.py +199 -0
- ouro/application/events.py +562 -0
- ouro/application/file_inputs.py +434 -0
- ouro/application/harness.py +47 -0
- ouro/application/model_generation.py +127 -0
- ouro/application/model_requests.py +303 -0
- ouro/application/models.py +329 -0
- ouro/application/observers.py +343 -0
- ouro/application/plugin_commands.py +329 -0
- ouro/application/plugin_models.py +148 -0
- ouro/application/plugins.py +1169 -0
- ouro/application/prompt_context.py +31 -0
- ouro/application/provider_auth.py +368 -0
- ouro/application/provider_auth_bindings.py +73 -0
- ouro/application/provider_auth_models.py +42 -0
- ouro/application/queued_inputs.py +695 -0
- ouro/application/recovery.py +241 -0
- ouro/application/resource_models.py +46 -0
- ouro/application/resources.py +345 -0
- ouro/application/run_continuations.py +696 -0
- ouro/application/run_drivers.py +422 -0
- ouro/application/run_ownership.py +237 -0
- ouro/application/run_resources.py +49 -0
- ouro/application/run_turns.py +45 -0
- ouro/application/runs.py +1291 -0
- ouro/application/runtime.py +4528 -0
- ouro/application/runtime_activity.py +897 -0
- ouro/application/runtime_configuration.py +139 -0
- ouro/application/runtime_environment.py +42 -0
- ouro/application/session_controls.py +613 -0
- ouro/application/session_editing.py +204 -0
- ouro/application/session_event_stream.py +98 -0
- ouro/application/session_history.py +328 -0
- ouro/application/session_models.py +321 -0
- ouro/application/session_recovery.py +395 -0
- ouro/application/session_transfer.py +364 -0
- ouro/application/sessions.py +1088 -0
- ouro/application/skill_activations.py +104 -0
- ouro/application/supervisor.py +1421 -0
- ouro/application/supervisor_models.py +162 -0
- ouro/application/task_execution.py +470 -0
- ouro/application/task_scheduler.py +118 -0
- ouro/application/tasks.py +348 -0
- ouro/application/tool_calls.py +1895 -0
- ouro/application/usage.py +265 -0
- ouro/auth/__init__.py +1 -0
- ouro/auth/authorization.py +106 -0
- ouro/auth/commit.py +43 -0
- ouro/auth/contracts.py +163 -0
- ouro/auth/credentials.py +288 -0
- ouro/auth/driver_contracts.py +115 -0
- ouro/auth/drivers/__init__.py +1 -0
- ouro/auth/drivers/openai_callback.py +96 -0
- ouro/auth/drivers/openai_codex.py +121 -0
- ouro/auth/drivers/openai_errors.py +31 -0
- ouro/auth/drivers/openai_tokens.py +213 -0
- ouro/auth/file_permissions.py +93 -0
- ouro/auth/managed_requests.py +148 -0
- ouro/auth/request_auth.py +46 -0
- ouro/auth/store.py +121 -0
- ouro/automation/__init__.py +1 -0
- ouro/automation/file_records.py +66 -0
- ouro/automation/local_files.py +383 -0
- ouro/automation/plugin_tasks.py +32 -0
- ouro/automation/repository.py +37 -0
- ouro/automation/schedule.py +130 -0
- ouro/automation/sqlite.py +279 -0
- ouro/billing/__init__.py +6 -0
- ouro/billing/base.py +49 -0
- ouro/billing/local.py +353 -0
- ouro/billing/queries.py +123 -0
- ouro/builtin_plugins/__init__.py +14 -0
- ouro/builtin_plugins/agent_context/README.md +101 -0
- ouro/builtin_plugins/agent_context/__init__.py +3 -0
- ouro/builtin_plugins/agent_context/agent_context_plugin.py +161 -0
- ouro/builtin_plugins/agent_context/definition.py +53 -0
- ouro/builtin_plugins/agent_context/instructions.py +20 -0
- ouro/builtin_plugins/goal/README.md +131 -0
- ouro/builtin_plugins/goal/__init__.py +3 -0
- ouro/builtin_plugins/goal/commands.py +346 -0
- ouro/builtin_plugins/goal/definition.py +151 -0
- ouro/builtin_plugins/goal/goal_plugin.py +527 -0
- ouro/builtin_plugins/goal/prompts.py +104 -0
- ouro/builtin_plugins/goal/state.py +150 -0
- ouro/builtin_plugins/plan/README.md +119 -0
- ouro/builtin_plugins/plan/__init__.py +3 -0
- ouro/builtin_plugins/plan/definition.py +116 -0
- ouro/builtin_plugins/plan/plan_plugin.py +558 -0
- ouro/builtin_plugins/plan/state.py +62 -0
- ouro/cli/__init__.py +1 -0
- ouro/cli/agent_commands.py +274 -0
- ouro/cli/approval_commands.py +131 -0
- ouro/cli/config_commands.py +489 -0
- ouro/cli/context_output.py +65 -0
- ouro/cli/data_commands.py +20 -0
- ouro/cli/errors.py +13 -0
- ouro/cli/main.py +854 -0
- ouro/cli/mcp_commands.py +190 -0
- ouro/cli/parser.py +1931 -0
- ouro/cli/plugin_commands.py +375 -0
- ouro/cli/prompt_commands.py +86 -0
- ouro/cli/provider_auth_commands.py +159 -0
- ouro/cli/provider_commands.py +820 -0
- ouro/cli/resource_commands.py +194 -0
- ouro/cli/run.py +232 -0
- ouro/cli/session_commands.py +672 -0
- ouro/cli/skills.py +331 -0
- ouro/cli/usage_commands.py +293 -0
- ouro/config/__init__.py +146 -0
- ouro/config/agents.py +183 -0
- ouro/config/compaction.py +228 -0
- ouro/config/credentials.py +62 -0
- ouro/config/endpoints.py +196 -0
- ouro/config/file.py +106 -0
- ouro/config/permissions.py +148 -0
- ouro/config/prompts.py +199 -0
- ouro/config/provider_codec.py +230 -0
- ouro/config/provider_headers.py +134 -0
- ouro/config/provider_models.py +657 -0
- ouro/config/provider_runtime.py +166 -0
- ouro/config/provider_template_store.py +504 -0
- ouro/config/provider_templates.py +1044 -0
- ouro/config/providers.py +1324 -0
- ouro/config/queued_inputs.py +67 -0
- ouro/config/reasoning.py +301 -0
- ouro/config/run_budget.py +81 -0
- ouro/config/skills.py +233 -0
- ouro/config/tool_execution.py +77 -0
- ouro/core/__init__.py +54 -0
- ouro/core/adapter.py +264 -0
- ouro/core/agents.py +462 -0
- ouro/core/approvals.py +110 -0
- ouro/core/attachment_input.py +60 -0
- ouro/core/attachment_projection.py +89 -0
- ouro/core/base.py +45 -0
- ouro/core/billing.py +209 -0
- ouro/core/callbacks.py +113 -0
- ouro/core/cancellation.py +52 -0
- ouro/core/compaction.py +462 -0
- ouro/core/content.py +97 -0
- ouro/core/context.py +360 -0
- ouro/core/context_providers.py +242 -0
- ouro/core/context_snapshots.py +79 -0
- ouro/core/continuations.py +258 -0
- ouro/core/errors.py +126 -0
- ouro/core/events.py +91 -0
- ouro/core/extensions.py +5 -0
- ouro/core/harness.py +53 -0
- ouro/core/harness_calls.py +217 -0
- ouro/core/inner_loop.py +49 -0
- ouro/core/input_content.py +106 -0
- ouro/core/interactions.py +56 -0
- ouro/core/message_frames.py +70 -0
- ouro/core/message_roles.py +5 -0
- ouro/core/message_semantics.py +71 -0
- ouro/core/messages.py +339 -0
- ouro/core/model_completion.py +50 -0
- ouro/core/model_execution.py +226 -0
- ouro/core/model_generation.py +55 -0
- ouro/core/model_requests.py +46 -0
- ouro/core/model_selection.py +3 -0
- ouro/core/observers.py +357 -0
- ouro/core/persistence.py +40 -0
- ouro/core/plugin_contracts.py +19 -0
- ouro/core/plugin_tasks.py +38 -0
- ouro/core/prompt_policies.py +263 -0
- ouro/core/provider.py +255 -0
- ouro/core/reasoning.py +141 -0
- ouro/core/redaction.py +79 -0
- ouro/core/request_context.py +34 -0
- ouro/core/resources.py +75 -0
- ouro/core/results.py +16 -0
- ouro/core/run_budget.py +74 -0
- ouro/core/run_drivers.py +140 -0
- ouro/core/run_transitions.py +102 -0
- ouro/core/session_commits.py +223 -0
- ouro/core/session_controls.py +353 -0
- ouro/core/session_extensions.py +63 -0
- ouro/core/session_titles.py +61 -0
- ouro/core/state.py +267 -0
- ouro/core/task_ports.py +35 -0
- ouro/core/tasks.py +176 -0
- ouro/core/tool_batch_transitions.py +146 -0
- ouro/core/tool_batches.py +95 -0
- ouro/core/tool_policies.py +243 -0
- ouro/core/tool_requests.py +61 -0
- ouro/core/tool_result_projection.py +97 -0
- ouro/core/tools.py +198 -0
- ouro/core/turn_policies.py +225 -0
- ouro/core/usage_queries.py +87 -0
- ouro/data_commands.py +65 -0
- ouro/deployment.py +39 -0
- ouro/local_application.py +908 -0
- ouro/local_io.py +81 -0
- ouro/local_locks/__init__.py +341 -0
- ouro/local_locks/windows.py +57 -0
- ouro/local_processes/__init__.py +96 -0
- ouro/local_processes/commands.py +222 -0
- ouro/local_processes/windows.py +123 -0
- ouro/local_providers.py +48 -0
- ouro/mcp/__init__.py +78 -0
- ouro/mcp/client.py +48 -0
- ouro/mcp/configuration.py +231 -0
- ouro/mcp/connection_check.py +62 -0
- ouro/mcp/errors.py +33 -0
- ouro/mcp/manager.py +612 -0
- ouro/mcp/models.py +199 -0
- ouro/mcp/runtime.py +97 -0
- ouro/mcp/sdk.py +337 -0
- ouro/mcp/sse_transport.py +156 -0
- ouro/mcp/tool_adapter.py +92 -0
- ouro/plugins/__init__.py +22 -0
- ouro/plugins/adapters.py +188 -0
- ouro/plugins/api.py +1150 -0
- ouro/plugins/builtin.py +191 -0
- ouro/plugins/candidates.py +50 -0
- ouro/plugins/catalog.py +1052 -0
- ouro/plugins/compatibility.py +227 -0
- ouro/plugins/contracts.py +301 -0
- ouro/plugins/contribution_types.py +279 -0
- ouro/plugins/contributions.py +1378 -0
- ouro/plugins/dependencies.py +256 -0
- ouro/plugins/driver_contracts.py +54 -0
- ouro/plugins/environment.py +24 -0
- ouro/plugins/execution_contracts.py +113 -0
- ouro/plugins/generation.py +237 -0
- ouro/plugins/generation_resources.py +193 -0
- ouro/plugins/harness_calls.py +181 -0
- ouro/plugins/implementation_contracts.py +16 -0
- ouro/plugins/installer.py +226 -0
- ouro/plugins/instructions.py +170 -0
- ouro/plugins/invocation.py +66 -0
- ouro/plugins/manifest.py +596 -0
- ouro/plugins/mcp.py +214 -0
- ouro/plugins/models.py +291 -0
- ouro/plugins/native_ports.py +109 -0
- ouro/plugins/package.py +256 -0
- ouro/plugins/paths.py +35 -0
- ouro/plugins/processes.py +72 -0
- ouro/plugins/providers.py +254 -0
- ouro/plugins/readiness.py +87 -0
- ouro/plugins/registry.py +301 -0
- ouro/plugins/resources.py +125 -0
- ouro/plugins/run_drivers.py +208 -0
- ouro/plugins/runtime.py +2102 -0
- ouro/plugins/scaffold.py +147 -0
- ouro/plugins/scheduling.py +155 -0
- ouro/plugins/semver.py +134 -0
- ouro/plugins/services.py +243 -0
- ouro/plugins/session_controllers.py +260 -0
- ouro/plugins/sources.py +322 -0
- ouro/plugins/store.py +358 -0
- ouro/plugins/tasks.py +68 -0
- ouro/plugins/tool_content.py +51 -0
- ouro/plugins/tool_groups.py +232 -0
- ouro/plugins/worker.py +1833 -0
- ouro/plugins/worker_drivers.py +95 -0
- ouro/plugins/worker_models.py +36 -0
- ouro/plugins/worker_processes.py +32 -0
- ouro/plugins/worker_providers.py +52 -0
- ouro/plugins/worker_scheduling.py +40 -0
- ouro/plugins/worker_services.py +142 -0
- ouro/plugins/worker_tool_groups.py +130 -0
- ouro/prompts/__init__.py +180 -0
- ouro/providers/__init__.py +15 -0
- ouro/providers/anthropic_messages.py +475 -0
- ouro/providers/anthropic_messages_codec.py +231 -0
- ouro/providers/authentication.py +177 -0
- ouro/providers/connection_check.py +60 -0
- ouro/providers/factory.py +299 -0
- ouro/providers/faux.py +74 -0
- ouro/providers/headers.py +51 -0
- ouro/providers/http_transport.py +382 -0
- ouro/providers/openai_chat_completions.py +446 -0
- ouro/providers/openai_chat_completions_codec.py +346 -0
- ouro/providers/openai_responses.py +232 -0
- ouro/providers/openai_responses_codec.py +281 -0
- ouro/providers/openai_responses_errors.py +32 -0
- ouro/providers/openai_responses_items.py +73 -0
- ouro/providers/openai_responses_stream.py +316 -0
- ouro/providers/reasoning.py +27 -0
- ouro/providers/request_context.py +26 -0
- ouro/providers/retrying.py +84 -0
- ouro/providers/tool_content.py +48 -0
- ouro/py.typed +1 -0
- ouro/resources/__init__.py +4 -0
- ouro/resources/base.py +53 -0
- ouro/resources/files.py +86 -0
- ouro/resources/local.py +219 -0
- ouro/sdk/__init__.py +1 -0
- ouro/sdk/plugins/__init__.py +1 -0
- ouro/sdk/plugins/content.py +36 -0
- ouro/sdk/plugins/environment.py +17 -0
- ouro/sdk/plugins/interactions.py +155 -0
- ouro/sdk/plugins/models.py +65 -0
- ouro/sdk/plugins/processes.py +39 -0
- ouro/sdk/plugins/providers.py +183 -0
- ouro/sdk/plugins/run_drivers.py +205 -0
- ouro/sdk/plugins/scheduled.py +13 -0
- ouro/sdk/plugins/scheduling.py +99 -0
- ouro/sdk/plugins/services.py +49 -0
- ouro/sdk/plugins/state.py +61 -0
- ouro/sdk/plugins/v3.py +955 -0
- ouro/sdk/plugins/worker.py +229 -0
- ouro/sdk/plugins/worker_drivers.py +170 -0
- ouro/sdk/plugins/worker_environment.py +15 -0
- ouro/sdk/plugins/worker_models.py +54 -0
- ouro/sdk/plugins/worker_processes.py +40 -0
- ouro/sdk/plugins/worker_providers.py +113 -0
- ouro/sdk/plugins/worker_scheduling.py +164 -0
- ouro/sdk/plugins/worker_services.py +101 -0
- ouro/sdk/plugins/worker_tool_groups.py +96 -0
- ouro/sdk/plugins/worker_tools.py +154 -0
- ouro/sessions/__init__.py +37 -0
- ouro/sessions/base.py +280 -0
- ouro/sessions/catalog.py +152 -0
- ouro/sessions/file_commits.py +255 -0
- ouro/sessions/index.py +154 -0
- ouro/sessions/layout.py +15 -0
- ouro/sessions/local_files.py +1710 -0
- ouro/sessions/local_index.py +291 -0
- ouro/sessions/locks.py +29 -0
- ouro/sessions/message_index.py +107 -0
- ouro/sessions/message_journal.py +35 -0
- ouro/sessions/portable.py +175 -0
- ouro/sessions/sqlite.py +1589 -0
- ouro/sessions/sqlite_commits.py +196 -0
- ouro/sessions/transfer.py +149 -0
- ouro/skills/__init__.py +48 -0
- ouro/skills/context.py +222 -0
- ouro/skills/loader.py +188 -0
- ouro/skills/manager.py +425 -0
- ouro/skills/models.py +60 -0
- ouro/skills/parser.py +253 -0
- ouro/tools/__init__.py +45 -0
- ouro/tools/base.py +266 -0
- ouro/tools/batch_executor.py +94 -0
- ouro/tools/builtin.py +23 -0
- ouro/tools/builtin_agents.py +253 -0
- ouro/tools/builtin_ask_user.py +168 -0
- ouro/tools/builtin_common.py +45 -0
- ouro/tools/builtin_files.py +390 -0
- ouro/tools/builtin_glob.py +157 -0
- ouro/tools/builtin_grep.py +651 -0
- ouro/tools/builtin_ignore.py +94 -0
- ouro/tools/builtin_search.py +79 -0
- ouro/tools/builtin_shell.py +361 -0
- ouro/tools/builtin_todolist.py +178 -0
- ouro/tools/builtin_view_image.py +165 -0
- ouro/tools/executor.py +501 -0
- ouro/tools/registry.py +197 -0
- ouro/tools/result_content.py +52 -0
- ouro/tools/schema.py +51 -0
- ouro/transfer/__init__.py +1 -0
- ouro/transfer/archive.py +206 -0
- ouro/transfer/skills.py +160 -0
- ouro/tui/__init__.py +5 -0
- ouro/tui/app.py +5548 -0
- ouro/tui/archive_paths.py +120 -0
- ouro/tui/attachment_editor.py +215 -0
- ouro/tui/attachment_paths.py +47 -0
- ouro/tui/attachment_picker.py +120 -0
- ouro/tui/clipboard.py +31 -0
- ouro/tui/commands.py +299 -0
- ouro/tui/configuration_screens.py +1773 -0
- ouro/tui/configuration_workflows.py +1658 -0
- ouro/tui/controller.py +2632 -0
- ouro/tui/conversation_history.py +1887 -0
- ouro/tui/data_transfer.py +423 -0
- ouro/tui/entry.py +42 -0
- ouro/tui/inline_editor.py +170 -0
- ouro/tui/input_drafts.py +146 -0
- ouro/tui/keyboard.py +29 -0
- ouro/tui/markdown.py +85 -0
- ouro/tui/menu_labels.py +34 -0
- ouro/tui/menu_sorting.py +63 -0
- ouro/tui/model_menus.py +101 -0
- ouro/tui/plan_confirmation.py +25 -0
- ouro/tui/plugin_workflows.py +509 -0
- ouro/tui/preferences.py +126 -0
- ouro/tui/prompt_screens.py +126 -0
- ouro/tui/prompt_workflows.py +147 -0
- ouro/tui/provider_auth_screens.py +346 -0
- ouro/tui/provider_screens.py +819 -0
- ouro/tui/provider_workflows.py +1059 -0
- ouro/tui/question_forms.py +163 -0
- ouro/tui/screens.py +1821 -0
- ouro/tui/selection.py +8 -0
- ouro/tui/state.py +538 -0
- ouro/tui/subagent_navigation.py +303 -0
- ouro/tui/task_screens.py +443 -0
- ouro/tui/task_workflows.py +284 -0
- ouro/tui/terminal.py +167 -0
- ouro/tui/text_inputs.py +80 -0
- ouro/tui/text_wrapping.py +103 -0
- ouro/tui/theme.py +582 -0
- ouro/tui/tool_presentations.py +263 -0
- ouro/tui/welcome/__init__.py +50 -0
- ouro/tui/welcome/centered.py +84 -0
- ouro/tui/welcome/components.py +454 -0
- ouro/tui/welcome/dot_matrix/__init__.py +1 -0
- ouro/tui/welcome/dot_matrix/field.py +102 -0
- ouro/tui/welcome/dot_matrix/raster.py +151 -0
- ouro/tui/welcome/dot_matrix/widget.py +200 -0
- ouro/tui/welcome/host.py +139 -0
- ouro/tui/welcome/model.py +68 -0
- ouro/tui/welcome/styles/__init__.py +1 -0
- ouro/tui/welcome/styles/basic.py +36 -0
- ouro/tui/welcome/styles/clifford.py +95 -0
- ouro/tui/welcome/styles/crystal.py +71 -0
- ouro/tui/welcome/styles/electron_bloom.py +64 -0
- ouro/tui/welcome/styles/event_horizon.py +93 -0
- ouro/tui/welcome/styles/interference.py +60 -0
- ouro/tui/welcome/styles/julia_reliquary.py +161 -0
- ouro/tui/widgets.py +3512 -0
- ouro/tui/windows_console.py +60 -0
- ouro/tui/windows_driver.py +97 -0
- ouro/tui/wrapped_document.py +141 -0
- ouro_agent-0.2.0.dist-info/METADATA +198 -0
- ouro_agent-0.2.0.dist-info/RECORD +438 -0
- ouro_agent-0.2.0.dist-info/WHEEL +4 -0
- ouro_agent-0.2.0.dist-info/entry_points.txt +2 -0
- ouro_agent-0.2.0.dist-info/licenses/LICENSE +21 -0
ouro/__init__.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Application services that orchestrate OURO core runtime boundaries."""
|
|
2
|
+
|
|
3
|
+
from ouro.application.agent_definitions import AgentDefinitionService
|
|
4
|
+
from ouro.application.agent_models import (
|
|
5
|
+
AgentDefinitionCatalogView,
|
|
6
|
+
AgentDefinitionDetail,
|
|
7
|
+
AgentDefinitionView,
|
|
8
|
+
AgentHandleView,
|
|
9
|
+
AgentInteractionSummary,
|
|
10
|
+
AgentInteractionView,
|
|
11
|
+
AgentReadView,
|
|
12
|
+
AgentTreeEdge,
|
|
13
|
+
AgentTreeNode,
|
|
14
|
+
AgentTreeNotification,
|
|
15
|
+
AgentTreeSnapshot,
|
|
16
|
+
AgentWaitResultView,
|
|
17
|
+
SpawnAgentRequest,
|
|
18
|
+
)
|
|
19
|
+
from ouro.application.agent_tree import AgentTreeSubscription
|
|
20
|
+
from ouro.application.agents import AgentService
|
|
21
|
+
from ouro.application.configuration import ConfigurationFacade
|
|
22
|
+
from ouro.application.configuration_models import (
|
|
23
|
+
ConfigurationOverview,
|
|
24
|
+
MCPConfigCatalogView,
|
|
25
|
+
MCPConnectionCheckView,
|
|
26
|
+
MCPServerConfigView,
|
|
27
|
+
)
|
|
28
|
+
from ouro.application.dto import ApplicationStartupReport
|
|
29
|
+
from ouro.application.event_models import RuntimeEventCategory, RuntimeEventView
|
|
30
|
+
from ouro.application.events import RuntimeEventRecorder, RuntimeEventSinkRegistration
|
|
31
|
+
from ouro.application.models import ModelReasoningState
|
|
32
|
+
from ouro.application.queued_inputs import QueuedUserInputView
|
|
33
|
+
from ouro.application.resources import ResourceService
|
|
34
|
+
from ouro.application.runtime import RuntimeService
|
|
35
|
+
from ouro.application.runtime_configuration import (
|
|
36
|
+
RuntimeConfigurationResolver,
|
|
37
|
+
RuntimeConfigurationSnapshot,
|
|
38
|
+
RuntimeProviderOptions,
|
|
39
|
+
)
|
|
40
|
+
from ouro.application.session_models import (
|
|
41
|
+
ReplayFrame,
|
|
42
|
+
SessionBranchResult,
|
|
43
|
+
SessionCatalogEntry,
|
|
44
|
+
SessionCatalogQuery,
|
|
45
|
+
SessionCatalogResult,
|
|
46
|
+
SessionContextSnapshot,
|
|
47
|
+
SessionContextStatus,
|
|
48
|
+
SessionDetail,
|
|
49
|
+
SessionEventPage,
|
|
50
|
+
SessionExport,
|
|
51
|
+
SessionMessagePage,
|
|
52
|
+
SessionMutationResult,
|
|
53
|
+
SessionObservationSnapshot,
|
|
54
|
+
SessionReplay,
|
|
55
|
+
SessionSummary,
|
|
56
|
+
SessionTrashResult,
|
|
57
|
+
SessionView,
|
|
58
|
+
)
|
|
59
|
+
from ouro.application.sessions import SessionService, SessionTitleGenerator
|
|
60
|
+
from ouro.application.supervisor import RuntimeSubscription, RuntimeSupervisor
|
|
61
|
+
from ouro.application.supervisor_models import (
|
|
62
|
+
RUNTIME_TOOL_ARGUMENT_TAIL_MAX_CHARS,
|
|
63
|
+
HostInputReceipt,
|
|
64
|
+
RunHandle,
|
|
65
|
+
RuntimeActivity,
|
|
66
|
+
RuntimeActivitySnapshot,
|
|
67
|
+
RuntimeNotification,
|
|
68
|
+
RuntimeStatusSnapshot,
|
|
69
|
+
RuntimeToolCallActivity,
|
|
70
|
+
ShutdownPolicy,
|
|
71
|
+
SupervisorStartResult,
|
|
72
|
+
)
|
|
73
|
+
from ouro.application.usage import UsageService
|
|
74
|
+
from ouro.core.results import RunResult
|
|
75
|
+
from ouro.core.usage_queries import (
|
|
76
|
+
UsageAuditLog,
|
|
77
|
+
UsageEntryList,
|
|
78
|
+
UsageMutationResult,
|
|
79
|
+
UsageSummary,
|
|
80
|
+
UsageTotals,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
__all__ = [
|
|
84
|
+
"AgentDefinitionCatalogView",
|
|
85
|
+
"AgentDefinitionDetail",
|
|
86
|
+
"AgentDefinitionService",
|
|
87
|
+
"AgentDefinitionView",
|
|
88
|
+
"AgentHandleView",
|
|
89
|
+
"AgentInteractionSummary",
|
|
90
|
+
"AgentInteractionView",
|
|
91
|
+
"AgentReadView",
|
|
92
|
+
"AgentService",
|
|
93
|
+
"AgentTreeEdge",
|
|
94
|
+
"AgentTreeNotification",
|
|
95
|
+
"AgentTreeNode",
|
|
96
|
+
"AgentTreeSnapshot",
|
|
97
|
+
"AgentTreeSubscription",
|
|
98
|
+
"AgentWaitResultView",
|
|
99
|
+
"ApplicationStartupReport",
|
|
100
|
+
"ConfigurationFacade",
|
|
101
|
+
"ConfigurationOverview",
|
|
102
|
+
"HostInputReceipt",
|
|
103
|
+
"MCPConfigCatalogView",
|
|
104
|
+
"MCPConnectionCheckView",
|
|
105
|
+
"MCPServerConfigView",
|
|
106
|
+
"ModelReasoningState",
|
|
107
|
+
"QueuedUserInputView",
|
|
108
|
+
"RUNTIME_TOOL_ARGUMENT_TAIL_MAX_CHARS",
|
|
109
|
+
"RunResult",
|
|
110
|
+
"RuntimeEventRecorder",
|
|
111
|
+
"RuntimeEventSinkRegistration",
|
|
112
|
+
"RuntimeEventCategory",
|
|
113
|
+
"RuntimeEventView",
|
|
114
|
+
"RuntimeService",
|
|
115
|
+
"RuntimeConfigurationResolver",
|
|
116
|
+
"RuntimeConfigurationSnapshot",
|
|
117
|
+
"RuntimeProviderOptions",
|
|
118
|
+
"RuntimeSupervisor",
|
|
119
|
+
"RuntimeSubscription",
|
|
120
|
+
"ResourceService",
|
|
121
|
+
"RunHandle",
|
|
122
|
+
"RuntimeNotification",
|
|
123
|
+
"RuntimeActivity",
|
|
124
|
+
"RuntimeActivitySnapshot",
|
|
125
|
+
"RuntimeStatusSnapshot",
|
|
126
|
+
"RuntimeToolCallActivity",
|
|
127
|
+
"ShutdownPolicy",
|
|
128
|
+
"SupervisorStartResult",
|
|
129
|
+
"UsageAuditLog",
|
|
130
|
+
"UsageEntryList",
|
|
131
|
+
"UsageMutationResult",
|
|
132
|
+
"UsageService",
|
|
133
|
+
"UsageSummary",
|
|
134
|
+
"UsageTotals",
|
|
135
|
+
"ReplayFrame",
|
|
136
|
+
"SessionBranchResult",
|
|
137
|
+
"SessionCatalogEntry",
|
|
138
|
+
"SessionService",
|
|
139
|
+
"SessionTitleGenerator",
|
|
140
|
+
"SessionCatalogQuery",
|
|
141
|
+
"SessionCatalogResult",
|
|
142
|
+
"SessionContextSnapshot",
|
|
143
|
+
"SessionContextStatus",
|
|
144
|
+
"SessionDetail",
|
|
145
|
+
"SessionEventPage",
|
|
146
|
+
"SessionExport",
|
|
147
|
+
"SessionMessagePage",
|
|
148
|
+
"SessionMutationResult",
|
|
149
|
+
"SessionObservationSnapshot",
|
|
150
|
+
"SessionReplay",
|
|
151
|
+
"SessionSummary",
|
|
152
|
+
"SessionTrashResult",
|
|
153
|
+
"SessionView",
|
|
154
|
+
"SpawnAgentRequest",
|
|
155
|
+
]
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
|
|
5
|
+
from ouro.application.agent_models import (
|
|
6
|
+
AgentDefinitionCatalogView,
|
|
7
|
+
AgentDefinitionDetail,
|
|
8
|
+
AgentDefinitionView,
|
|
9
|
+
AgentToolOptionView,
|
|
10
|
+
)
|
|
11
|
+
from ouro.config.agents import AgentDefinitionsConfigManager
|
|
12
|
+
from ouro.config.providers import ProviderConfigManager
|
|
13
|
+
from ouro.core.agents import (
|
|
14
|
+
AGENT_CONTROL_TOOL_NAMES,
|
|
15
|
+
AgentCatalogEntry,
|
|
16
|
+
AgentCatalogSnapshot,
|
|
17
|
+
AgentDefinition,
|
|
18
|
+
EffectiveToolRef,
|
|
19
|
+
ToolSelection,
|
|
20
|
+
)
|
|
21
|
+
from ouro.core.approvals import (
|
|
22
|
+
PermissionMode,
|
|
23
|
+
SessionApprovalMode,
|
|
24
|
+
configured_tool_permission,
|
|
25
|
+
resolve_tool_permission,
|
|
26
|
+
)
|
|
27
|
+
from ouro.core.errors import ConfigError
|
|
28
|
+
from ouro.core.tools import tool_definition_contract_hash
|
|
29
|
+
from ouro.tools import ToolDefinition, ToolRegistry
|
|
30
|
+
|
|
31
|
+
GENERAL_AGENT_DEFINITION = AgentDefinition(
|
|
32
|
+
agent_id="general",
|
|
33
|
+
name="General",
|
|
34
|
+
description="A general-purpose subagent for a bounded delegated task.",
|
|
35
|
+
system_prompt=(
|
|
36
|
+
"Work independently on the delegated task. Use only the available tools and return "
|
|
37
|
+
"a concise result with evidence, verification, and unresolved questions."
|
|
38
|
+
),
|
|
39
|
+
tool_selection=ToolSelection(mode="all"),
|
|
40
|
+
can_spawn=False,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class AgentDefinitionService:
|
|
45
|
+
"""Resolve definitions and current tool capabilities for one decision."""
|
|
46
|
+
|
|
47
|
+
def __init__(self, config: AgentDefinitionsConfigManager) -> None:
|
|
48
|
+
self.config = config
|
|
49
|
+
self.providers = ProviderConfigManager(config.file.root)
|
|
50
|
+
|
|
51
|
+
def default_model_route(self) -> str:
|
|
52
|
+
return self.providers.require_default_route()
|
|
53
|
+
|
|
54
|
+
def list(self, *, tools: ToolRegistry) -> AgentDefinitionCatalogView:
|
|
55
|
+
config = self.config.snapshot()
|
|
56
|
+
entries = self._entries(tools)
|
|
57
|
+
return AgentDefinitionCatalogView(
|
|
58
|
+
revision=config.revision,
|
|
59
|
+
definitions=tuple(
|
|
60
|
+
self._view(
|
|
61
|
+
entry,
|
|
62
|
+
source=(
|
|
63
|
+
"builtin"
|
|
64
|
+
if entry.definition.agent_id == GENERAL_AGENT_DEFINITION.agent_id
|
|
65
|
+
else "user"
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
for entry in entries
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def get(self, agent_id: str, *, tools: ToolRegistry) -> AgentDefinitionDetail:
|
|
73
|
+
entry = next(
|
|
74
|
+
(item for item in self._entries(tools) if item.definition.agent_id == agent_id),
|
|
75
|
+
None,
|
|
76
|
+
)
|
|
77
|
+
if entry is None:
|
|
78
|
+
raise ConfigError(f"agent definition not found: {agent_id}")
|
|
79
|
+
source = "builtin" if agent_id == GENERAL_AGENT_DEFINITION.agent_id else "user"
|
|
80
|
+
view = self._view(entry, source=source)
|
|
81
|
+
return AgentDefinitionDetail(
|
|
82
|
+
**view.model_dump(), system_prompt=entry.definition.system_prompt
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def create(
|
|
86
|
+
self,
|
|
87
|
+
*,
|
|
88
|
+
agent_id: str,
|
|
89
|
+
name: str,
|
|
90
|
+
description: str,
|
|
91
|
+
system_prompt: str,
|
|
92
|
+
tool_selection: ToolSelection,
|
|
93
|
+
model: str | None = None,
|
|
94
|
+
tools: ToolRegistry,
|
|
95
|
+
expected_revision: int,
|
|
96
|
+
) -> AgentDefinitionCatalogView:
|
|
97
|
+
self._require_known_selected_tools(tool_selection, tools)
|
|
98
|
+
definition = AgentDefinition(
|
|
99
|
+
agent_id=agent_id,
|
|
100
|
+
name=name,
|
|
101
|
+
description=description,
|
|
102
|
+
system_prompt=system_prompt,
|
|
103
|
+
tool_selection=tool_selection,
|
|
104
|
+
model=model,
|
|
105
|
+
)
|
|
106
|
+
self.config.create(definition, expected_revision=expected_revision)
|
|
107
|
+
return self.list(tools=tools)
|
|
108
|
+
|
|
109
|
+
def update(
|
|
110
|
+
self,
|
|
111
|
+
*,
|
|
112
|
+
agent_id: str,
|
|
113
|
+
name: str,
|
|
114
|
+
description: str,
|
|
115
|
+
system_prompt: str,
|
|
116
|
+
tool_selection: ToolSelection,
|
|
117
|
+
model: str | None,
|
|
118
|
+
tools: ToolRegistry,
|
|
119
|
+
expected_revision: int,
|
|
120
|
+
) -> AgentDefinitionCatalogView:
|
|
121
|
+
if agent_id == GENERAL_AGENT_DEFINITION.agent_id:
|
|
122
|
+
raise ConfigError(f"builtin agent definition is immutable: {agent_id}")
|
|
123
|
+
self._require_known_selected_tools(tool_selection, tools)
|
|
124
|
+
current = next(
|
|
125
|
+
(item for item in self.config.snapshot().definitions if item.agent_id == agent_id),
|
|
126
|
+
None,
|
|
127
|
+
)
|
|
128
|
+
if current is None:
|
|
129
|
+
raise ConfigError(f"agent definition not found: {agent_id}")
|
|
130
|
+
updated = AgentDefinition(
|
|
131
|
+
agent_id=agent_id,
|
|
132
|
+
name=name,
|
|
133
|
+
description=description,
|
|
134
|
+
system_prompt=system_prompt,
|
|
135
|
+
tool_selection=tool_selection,
|
|
136
|
+
model=model,
|
|
137
|
+
can_spawn=current.can_spawn,
|
|
138
|
+
default_budget=current.default_budget,
|
|
139
|
+
)
|
|
140
|
+
self.config.update(updated, expected_revision=expected_revision)
|
|
141
|
+
return self.list(tools=tools)
|
|
142
|
+
|
|
143
|
+
def delete(
|
|
144
|
+
self,
|
|
145
|
+
agent_id: str,
|
|
146
|
+
*,
|
|
147
|
+
expected_revision: int,
|
|
148
|
+
tools: ToolRegistry | None = None,
|
|
149
|
+
) -> AgentDefinitionCatalogView:
|
|
150
|
+
if agent_id == GENERAL_AGENT_DEFINITION.agent_id:
|
|
151
|
+
raise ConfigError(f"builtin agent definition is immutable: {agent_id}")
|
|
152
|
+
self.config.delete(agent_id, expected_revision=expected_revision)
|
|
153
|
+
return self.list(tools=tools or ToolRegistry())
|
|
154
|
+
|
|
155
|
+
def copy_builtin(
|
|
156
|
+
self,
|
|
157
|
+
agent_id: str,
|
|
158
|
+
*,
|
|
159
|
+
new_agent_id: str,
|
|
160
|
+
name: str,
|
|
161
|
+
tools: ToolRegistry,
|
|
162
|
+
expected_revision: int,
|
|
163
|
+
) -> AgentDefinitionCatalogView:
|
|
164
|
+
if agent_id != GENERAL_AGENT_DEFINITION.agent_id:
|
|
165
|
+
raise ConfigError(f"builtin agent definition not found: {agent_id}")
|
|
166
|
+
copied = AgentDefinition(
|
|
167
|
+
**{
|
|
168
|
+
**GENERAL_AGENT_DEFINITION.model_dump(exclude={"contract_hash"}),
|
|
169
|
+
"agent_id": new_agent_id,
|
|
170
|
+
"name": name,
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
self.config.create(copied, expected_revision=expected_revision)
|
|
174
|
+
return self.list(tools=tools)
|
|
175
|
+
|
|
176
|
+
def tool_options(self, tools: ToolRegistry) -> tuple[AgentToolOptionView, ...]:
|
|
177
|
+
return tuple(
|
|
178
|
+
AgentToolOptionView(
|
|
179
|
+
name=definition.name,
|
|
180
|
+
description=definition.description,
|
|
181
|
+
effect=definition.effect,
|
|
182
|
+
owner_id=self._owner_id(tools, definition.name),
|
|
183
|
+
execution_contract_hash=self.tool_reference(
|
|
184
|
+
tools, definition
|
|
185
|
+
).execution_contract_hash,
|
|
186
|
+
)
|
|
187
|
+
for definition in self._candidate_definitions(tools)
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
def catalog_snapshot(
|
|
191
|
+
self,
|
|
192
|
+
tools: ToolRegistry,
|
|
193
|
+
*,
|
|
194
|
+
permission_overrides: Mapping[str, PermissionMode] | None = None,
|
|
195
|
+
plugin_permission_overrides: Mapping[str, PermissionMode] | None = None,
|
|
196
|
+
approval_mode: SessionApprovalMode = "inherit",
|
|
197
|
+
) -> AgentCatalogSnapshot:
|
|
198
|
+
config = self.config.snapshot()
|
|
199
|
+
return AgentCatalogSnapshot(
|
|
200
|
+
revision=config.revision,
|
|
201
|
+
entries=self._entries(
|
|
202
|
+
tools,
|
|
203
|
+
permission_overrides=permission_overrides,
|
|
204
|
+
plugin_permission_overrides=plugin_permission_overrides,
|
|
205
|
+
approval_mode=approval_mode,
|
|
206
|
+
),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def _entries(
|
|
210
|
+
self,
|
|
211
|
+
tools: ToolRegistry,
|
|
212
|
+
*,
|
|
213
|
+
permission_overrides: Mapping[str, PermissionMode] | None = None,
|
|
214
|
+
plugin_permission_overrides: Mapping[str, PermissionMode] | None = None,
|
|
215
|
+
approval_mode: SessionApprovalMode = "inherit",
|
|
216
|
+
) -> tuple[AgentCatalogEntry, ...]:
|
|
217
|
+
config = self.config.snapshot()
|
|
218
|
+
overrides = permission_overrides or {}
|
|
219
|
+
plugin_overrides = plugin_permission_overrides or {}
|
|
220
|
+
definitions = (GENERAL_AGENT_DEFINITION, *config.definitions)
|
|
221
|
+
candidates = {
|
|
222
|
+
definition.name: definition for definition in self._candidate_definitions(tools)
|
|
223
|
+
}
|
|
224
|
+
entries: list[AgentCatalogEntry] = []
|
|
225
|
+
for definition in definitions:
|
|
226
|
+
selected_names = (
|
|
227
|
+
tuple(candidates)
|
|
228
|
+
if definition.tool_selection.mode == "all"
|
|
229
|
+
else definition.tool_selection.names
|
|
230
|
+
)
|
|
231
|
+
missing = tuple(name for name in selected_names if name not in candidates)
|
|
232
|
+
effective: list[EffectiveToolRef] = []
|
|
233
|
+
for name in selected_names:
|
|
234
|
+
if name not in candidates:
|
|
235
|
+
continue
|
|
236
|
+
tool = candidates[name]
|
|
237
|
+
raw_plugin_id = tool.metadata.get("plugin_id")
|
|
238
|
+
plugin_id = (
|
|
239
|
+
raw_plugin_id if isinstance(raw_plugin_id, str) and raw_plugin_id else None
|
|
240
|
+
)
|
|
241
|
+
permission = resolve_tool_permission(
|
|
242
|
+
tool.permission_mode,
|
|
243
|
+
approval_mode,
|
|
244
|
+
permission_control=tool.permission_control,
|
|
245
|
+
override=configured_tool_permission(
|
|
246
|
+
name,
|
|
247
|
+
plugin_id,
|
|
248
|
+
tool_overrides=overrides,
|
|
249
|
+
plugin_overrides=plugin_overrides,
|
|
250
|
+
),
|
|
251
|
+
)
|
|
252
|
+
if permission == "deny":
|
|
253
|
+
continue
|
|
254
|
+
effective.append(
|
|
255
|
+
self.tool_reference(
|
|
256
|
+
tools,
|
|
257
|
+
tool,
|
|
258
|
+
minimum_permission_mode=permission,
|
|
259
|
+
)
|
|
260
|
+
)
|
|
261
|
+
entries.append(
|
|
262
|
+
AgentCatalogEntry(
|
|
263
|
+
definition=definition,
|
|
264
|
+
effective_tools=tuple(effective),
|
|
265
|
+
missing_tool_names=missing,
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
return tuple(entries)
|
|
269
|
+
|
|
270
|
+
@staticmethod
|
|
271
|
+
def _candidate_definitions(tools: ToolRegistry) -> tuple[ToolDefinition, ...]:
|
|
272
|
+
return tuple(
|
|
273
|
+
definition
|
|
274
|
+
for definition in tools.definitions()
|
|
275
|
+
if definition.name not in AGENT_CONTROL_TOOL_NAMES
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
@classmethod
|
|
279
|
+
def tool_reference(
|
|
280
|
+
cls,
|
|
281
|
+
tools: ToolRegistry,
|
|
282
|
+
definition: ToolDefinition,
|
|
283
|
+
*,
|
|
284
|
+
minimum_permission_mode: PermissionMode = "auto",
|
|
285
|
+
) -> EffectiveToolRef:
|
|
286
|
+
metadata = definition.metadata
|
|
287
|
+
plugin_id = metadata.get("plugin_id")
|
|
288
|
+
contribution_id = metadata.get("contribution_id")
|
|
289
|
+
canonical_id = (
|
|
290
|
+
f"{plugin_id}/tools/{contribution_id}"
|
|
291
|
+
if isinstance(plugin_id, str) and isinstance(contribution_id, str)
|
|
292
|
+
else f"ouro.host/tools/{definition.name}"
|
|
293
|
+
)
|
|
294
|
+
execution_hash = metadata.get("execution_contract_hash")
|
|
295
|
+
raw_plugin_permissions = metadata.get("plugin_permissions", ())
|
|
296
|
+
plugin_permissions = (
|
|
297
|
+
frozenset(item for item in raw_plugin_permissions if isinstance(item, str))
|
|
298
|
+
if isinstance(raw_plugin_permissions, (list, tuple))
|
|
299
|
+
else frozenset()
|
|
300
|
+
)
|
|
301
|
+
is_shell = isinstance(metadata.get("shell_kind"), str)
|
|
302
|
+
is_mcp = definition.source == "mcp"
|
|
303
|
+
return EffectiveToolRef(
|
|
304
|
+
public_name=definition.name,
|
|
305
|
+
canonical_tool_id=canonical_id,
|
|
306
|
+
owner_id=cls._owner_id(tools, definition.name),
|
|
307
|
+
execution_contract_hash=(
|
|
308
|
+
execution_hash
|
|
309
|
+
if isinstance(execution_hash, str) and execution_hash
|
|
310
|
+
else tool_definition_contract_hash(definition)
|
|
311
|
+
),
|
|
312
|
+
source=definition.source,
|
|
313
|
+
effect=definition.effect,
|
|
314
|
+
minimum_permission_mode=minimum_permission_mode,
|
|
315
|
+
requires_network=(is_shell or is_mcp or "network.outbound" in plugin_permissions),
|
|
316
|
+
requires_mcp=is_mcp,
|
|
317
|
+
requires_external_paths=(is_shell or is_mcp or "process.spawn" in plugin_permissions),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
@staticmethod
|
|
321
|
+
def _owner_id(tools: ToolRegistry, name: str) -> str:
|
|
322
|
+
return tools.owner_of(name) or "ouro.host"
|
|
323
|
+
|
|
324
|
+
@staticmethod
|
|
325
|
+
def _require_known_selected_tools(
|
|
326
|
+
selection: ToolSelection,
|
|
327
|
+
tools: ToolRegistry,
|
|
328
|
+
) -> None:
|
|
329
|
+
if selection.mode != "selected":
|
|
330
|
+
return
|
|
331
|
+
known = set(tools.names()) - AGENT_CONTROL_TOOL_NAMES
|
|
332
|
+
missing = sorted(set(selection.names) - known)
|
|
333
|
+
if missing:
|
|
334
|
+
raise ConfigError("unknown selected tools: " + ", ".join(missing))
|
|
335
|
+
|
|
336
|
+
@staticmethod
|
|
337
|
+
def _view(
|
|
338
|
+
entry: AgentCatalogEntry,
|
|
339
|
+
*,
|
|
340
|
+
source: str,
|
|
341
|
+
) -> AgentDefinitionView:
|
|
342
|
+
return AgentDefinitionView(
|
|
343
|
+
agent_id=entry.definition.agent_id,
|
|
344
|
+
name=entry.definition.name,
|
|
345
|
+
description=entry.definition.description,
|
|
346
|
+
tool_selection=entry.definition.tool_selection,
|
|
347
|
+
model=entry.definition.model,
|
|
348
|
+
source="builtin" if source == "builtin" else "user",
|
|
349
|
+
editable=source == "user",
|
|
350
|
+
compatibility="available" if entry.available else "unavailable",
|
|
351
|
+
missing_tool_names=entry.missing_tool_names,
|
|
352
|
+
contract_hash=entry.definition.contract_hash,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
__all__ = ["AgentDefinitionService", "GENERAL_AGENT_DEFINITION"]
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from collections.abc import Awaitable, Callable
|
|
6
|
+
from typing import Protocol
|
|
7
|
+
|
|
8
|
+
from ouro.application.events import ApplicationEventPublisher
|
|
9
|
+
from ouro.application.supervisor_models import RunHandle, RuntimeStatusSnapshot
|
|
10
|
+
from ouro.core.agents import DelegationRecord
|
|
11
|
+
from ouro.core.callbacks import run_blocking
|
|
12
|
+
from ouro.core.errors import DelegationRevisionConflictError, PersistenceError, SessionBusyError
|
|
13
|
+
from ouro.core.redaction import redact_text
|
|
14
|
+
from ouro.core.state import RunRecord
|
|
15
|
+
from ouro.sessions import SessionStore
|
|
16
|
+
|
|
17
|
+
_LOGGER = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RunObserver(Protocol):
|
|
21
|
+
async def wait_run(self, session_id: str, run_id: str) -> RunRecord: ...
|
|
22
|
+
|
|
23
|
+
async def wait(self, handle: RunHandle) -> RuntimeStatusSnapshot: ...
|
|
24
|
+
|
|
25
|
+
def release_handle(self, handle: RunHandle) -> None: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AgentExecutionTasks:
|
|
29
|
+
"""Own result settlement tasks by durable child Run identity.
|
|
30
|
+
|
|
31
|
+
Retries are bounded and scoped to observed delegations. Pending delivery
|
|
32
|
+
remains durable after exhaustion and can be retried by targeted recovery.
|
|
33
|
+
No Session enumeration, per-token checkpoint reads, or extra polling loop.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
store: SessionStore,
|
|
39
|
+
observer: RunObserver,
|
|
40
|
+
events: ApplicationEventPublisher,
|
|
41
|
+
settle: Callable[[DelegationRecord], Awaitable[object]],
|
|
42
|
+
) -> None:
|
|
43
|
+
self.store = store
|
|
44
|
+
self.observer = observer
|
|
45
|
+
self.events = events
|
|
46
|
+
self.settle = settle
|
|
47
|
+
self._tasks: dict[tuple[str, str], asyncio.Task[None]] = {}
|
|
48
|
+
self._receipts: set[asyncio.Task[None]] = set()
|
|
49
|
+
self._closed = False
|
|
50
|
+
|
|
51
|
+
def watch(self, relation: DelegationRecord) -> None:
|
|
52
|
+
if (
|
|
53
|
+
self._closed
|
|
54
|
+
or relation.child_session_id is None
|
|
55
|
+
or relation.current_child_run_id is None
|
|
56
|
+
or (relation.result is not None and relation.result.delivery.status != "pending")
|
|
57
|
+
):
|
|
58
|
+
return
|
|
59
|
+
key = relation.delegation_id, relation.current_child_run_id
|
|
60
|
+
current = self._tasks.get(key)
|
|
61
|
+
if current is not None and not current.done():
|
|
62
|
+
return
|
|
63
|
+
task = asyncio.create_task(self._observe(relation), name=f"ouro-agent-result-{key[1]}")
|
|
64
|
+
self._tasks[key] = task
|
|
65
|
+
task.add_done_callback(lambda done: self._finished(key, done))
|
|
66
|
+
|
|
67
|
+
def own_receipt(self, handle: RunHandle) -> None:
|
|
68
|
+
"""Release private process receipts; result waits use durable identity."""
|
|
69
|
+
if self._closed:
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
async def release() -> None:
|
|
73
|
+
await self.observer.wait(handle)
|
|
74
|
+
self.observer.release_handle(handle)
|
|
75
|
+
|
|
76
|
+
task = asyncio.create_task(release(), name=f"ouro-agent-receipt-{handle.handle_id}")
|
|
77
|
+
self._receipts.add(task)
|
|
78
|
+
task.add_done_callback(self._receipt_finished)
|
|
79
|
+
|
|
80
|
+
def _receipt_finished(self, task: asyncio.Task[None]) -> None:
|
|
81
|
+
self._receipts.discard(task)
|
|
82
|
+
if not task.cancelled() and task.exception() is not None:
|
|
83
|
+
_LOGGER.error("Agent receipt cleanup failed: %s", type(task.exception()).__name__)
|
|
84
|
+
|
|
85
|
+
async def close(self) -> None:
|
|
86
|
+
self._closed = True
|
|
87
|
+
tasks = (*self._tasks.values(), *self._receipts)
|
|
88
|
+
for task in tasks:
|
|
89
|
+
task.cancel()
|
|
90
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
91
|
+
self._tasks.clear()
|
|
92
|
+
self._receipts.clear()
|
|
93
|
+
|
|
94
|
+
def _finished(self, key: tuple[str, str], task: asyncio.Task[None]) -> None:
|
|
95
|
+
if self._tasks.get(key) is task:
|
|
96
|
+
self._tasks.pop(key)
|
|
97
|
+
if not task.cancelled() and task.exception() is not None:
|
|
98
|
+
# Reporting itself can fail if storage is unavailable. Keep this
|
|
99
|
+
# visible without logging prompts, tool payloads, or raw exceptions.
|
|
100
|
+
_LOGGER.error(
|
|
101
|
+
"Agent settlement reporting failed: %s (%s)", key, type(task.exception()).__name__
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
async def _observe(self, relation: DelegationRecord) -> None:
|
|
105
|
+
async def settle() -> object:
|
|
106
|
+
assert (
|
|
107
|
+
relation.child_session_id is not None and relation.current_child_run_id is not None
|
|
108
|
+
)
|
|
109
|
+
await self.observer.wait_run(relation.child_session_id, relation.current_child_run_id)
|
|
110
|
+
return await self.settle(relation)
|
|
111
|
+
|
|
112
|
+
await self.retry(relation, settle)
|
|
113
|
+
|
|
114
|
+
async def retry(
|
|
115
|
+
self, relation: DelegationRecord, operation: Callable[[], Awaitable[object]]
|
|
116
|
+
) -> None:
|
|
117
|
+
for attempt, delay in enumerate((0, 0.1, 0.5, 2.0)):
|
|
118
|
+
if delay:
|
|
119
|
+
await asyncio.sleep(delay)
|
|
120
|
+
try:
|
|
121
|
+
await operation()
|
|
122
|
+
return
|
|
123
|
+
except Exception as exc:
|
|
124
|
+
retryable = isinstance(exc, (OSError, PersistenceError, SessionBusyError))
|
|
125
|
+
error = f"{type(exc).__name__}: {redact_text(str(exc))}"[:4_000]
|
|
126
|
+
try:
|
|
127
|
+
await run_blocking(self._retain_error, relation, error)
|
|
128
|
+
except OSError, PersistenceError:
|
|
129
|
+
# The failed dependency may be the same store used for
|
|
130
|
+
# diagnostics. Still spend only the bounded retry budget.
|
|
131
|
+
if retryable and attempt < 3:
|
|
132
|
+
continue
|
|
133
|
+
raise
|
|
134
|
+
if retryable and attempt < 3:
|
|
135
|
+
continue
|
|
136
|
+
await self.events.publish(
|
|
137
|
+
session_id=relation.root_session_id,
|
|
138
|
+
run_id=relation.parent_run_id,
|
|
139
|
+
event_type="diagnostic",
|
|
140
|
+
payload={
|
|
141
|
+
"code": "agent_result_delivery_incomplete",
|
|
142
|
+
"severity": "error",
|
|
143
|
+
"component": "application.agents",
|
|
144
|
+
"delegation_id": relation.delegation_id,
|
|
145
|
+
"child_run_id": relation.current_child_run_id,
|
|
146
|
+
"error": error,
|
|
147
|
+
"recoverable": True,
|
|
148
|
+
"suggested_action": "Reconcile this root Session to retry settlement.",
|
|
149
|
+
},
|
|
150
|
+
)
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
def _retain_error(self, relation: DelegationRecord, error: str) -> None:
|
|
154
|
+
for _ in range(3):
|
|
155
|
+
current = self.store.load_delegation(relation.root_session_id, relation.delegation_id)
|
|
156
|
+
result = current.result
|
|
157
|
+
if (
|
|
158
|
+
result is None
|
|
159
|
+
or result.child_run_id != relation.current_child_run_id
|
|
160
|
+
or result.delivery.status != "pending"
|
|
161
|
+
):
|
|
162
|
+
return
|
|
163
|
+
try:
|
|
164
|
+
self.store.save_delegation(
|
|
165
|
+
current.model_copy(
|
|
166
|
+
update={
|
|
167
|
+
"result": result.model_copy(
|
|
168
|
+
update={
|
|
169
|
+
"delivery": result.delivery.model_copy(update={"error": error})
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
),
|
|
174
|
+
expected_revision=current.revision,
|
|
175
|
+
)
|
|
176
|
+
return
|
|
177
|
+
except DelegationRevisionConflictError:
|
|
178
|
+
continue
|
|
179
|
+
raise DelegationRevisionConflictError("Could not retain pending result delivery error")
|