talkops-opscloud 0.3.0b1__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.
- opscloud/__init__.py +5 -0
- opscloud/__main__.py +6 -0
- opscloud/_constants.py +53 -0
- opscloud/_debug.py +145 -0
- opscloud/_debug_buffer.py +250 -0
- opscloud/_textual_patches.py +367 -0
- opscloud/_version.py +15 -0
- opscloud/agent/__init__.py +27 -0
- opscloud/agent/config.py +168 -0
- opscloud/agent/factory.py +1103 -0
- opscloud/approval_mode.py +44 -0
- opscloud/backend/__init__.py +49 -0
- opscloud/backend/composite.py +89 -0
- opscloud/backend/local.py +183 -0
- opscloud/backend/registry.py +79 -0
- opscloud/backend/sandbox_config.py +107 -0
- opscloud/backend/sandbox_factory.py +432 -0
- opscloud/built_in_skills/remember/SKILL.md +124 -0
- opscloud/built_in_skills/skill-creator/SKILL.md +348 -0
- opscloud/built_in_skills/skill-creator/scripts/init_skill.py +371 -0
- opscloud/built_in_skills/skill-creator/scripts/quick_validate.py +165 -0
- opscloud/cli/__init__.py +1 -0
- opscloud/cli/commands/__init__.py +15 -0
- opscloud/cli/commands/auth.py +45 -0
- opscloud/cli/commands/doctor.py +100 -0
- opscloud/cli/commands/mcp.py +137 -0
- opscloud/cli/commands/threads.py +51 -0
- opscloud/cli/interactive.py +154 -0
- opscloud/cli/main.py +903 -0
- opscloud/cli/non_interactive.py +425 -0
- opscloud/cli/server_manager.py +58 -0
- opscloud/commands/__init__.py +19 -0
- opscloud/commands/_base.py +110 -0
- opscloud/commands/_guards.py +52 -0
- opscloud/commands/_router.py +146 -0
- opscloud/commands/_types.py +36 -0
- opscloud/commands/core/__init__.py +47 -0
- opscloud/commands/core/auth.py +94 -0
- opscloud/commands/core/bug.py +46 -0
- opscloud/commands/core/clear.py +106 -0
- opscloud/commands/core/cloud.py +185 -0
- opscloud/commands/core/compact.py +128 -0
- opscloud/commands/core/config_cmd.py +120 -0
- opscloud/commands/core/context.py +220 -0
- opscloud/commands/core/cost.py +44 -0
- opscloud/commands/core/doctor.py +535 -0
- opscloud/commands/core/effort.py +108 -0
- opscloud/commands/core/exit_cmd.py +41 -0
- opscloud/commands/core/fast.py +148 -0
- opscloud/commands/core/help_cmd.py +94 -0
- opscloud/commands/core/mcp.py +134 -0
- opscloud/commands/core/model.py +109 -0
- opscloud/commands/core/permissions.py +196 -0
- opscloud/commands/core/plugins.py +92 -0
- opscloud/commands/core/pool.py +108 -0
- opscloud/commands/core/resume.py +97 -0
- opscloud/commands/core/skills.py +178 -0
- opscloud/commands/power/__init__.py +51 -0
- opscloud/commands/power/agents.py +98 -0
- opscloud/commands/power/btw.py +85 -0
- opscloud/commands/power/copy.py +97 -0
- opscloud/commands/power/goal.py +548 -0
- opscloud/commands/power/loop.py +295 -0
- opscloud/commands/power/memory.py +287 -0
- opscloud/commands/power/review.py +152 -0
- opscloud/commands/power/rubric.py +287 -0
- opscloud/commands/power/runtime.py +321 -0
- opscloud/commands/power/skill_creator.py +70 -0
- opscloud/commands/power/skill_invoke.py +165 -0
- opscloud/commands/power/tasks.py +209 -0
- opscloud/commands/power/trace.py +117 -0
- opscloud/commands/power/ui_toggles.py +135 -0
- opscloud/commands/power/version.py +52 -0
- opscloud/commands/registry.py +176 -0
- opscloud/config/__init__.py +114 -0
- opscloud/config/adapters/__init__.py +5 -0
- opscloud/config/adapters/postgres.py +776 -0
- opscloud/config/adapters/sqlite.py +769 -0
- opscloud/config/aws.py +248 -0
- opscloud/config/cloud_profiles.py +437 -0
- opscloud/config/env_vars.py +81 -0
- opscloud/config/langsmith.py +319 -0
- opscloud/config/manifest.py +817 -0
- opscloud/config/metadata.py +205 -0
- opscloud/config/paths.py +604 -0
- opscloud/config/plugins.py +130 -0
- opscloud/config/settings.py +834 -0
- opscloud/config/store.py +453 -0
- opscloud/config/store_factory.py +97 -0
- opscloud/config/toml_config.py +562 -0
- opscloud/editor.py +173 -0
- opscloud/exceptions.py +65 -0
- opscloud/file_ops.py +217 -0
- opscloud/hooks/__init__.py +139 -0
- opscloud/hooks/env.py +44 -0
- opscloud/hooks/interrupt.py +121 -0
- opscloud/hooks/models/__init__.py +109 -0
- opscloud/hooks/models/adapters.py +19 -0
- opscloud/hooks/models/config.py +79 -0
- opscloud/hooks/models/domain.py +434 -0
- opscloud/hooks/models/transport.py +37 -0
- opscloud/hooks/tools.py +231 -0
- opscloud/input.py +48 -0
- opscloud/integrations/__init__.py +80 -0
- opscloud/integrations/base.py +153 -0
- opscloud/integrations/content_filter.py +119 -0
- opscloud/integrations/event_bus.py +480 -0
- opscloud/integrations/hooks.py +238 -0
- opscloud/integrations/identity.py +181 -0
- opscloud/integrations/notifications.py +134 -0
- opscloud/integrations/stream_bridge.py +397 -0
- opscloud/integrations/thread_store.py +81 -0
- opscloud/json_types.py +20 -0
- opscloud/mcp/__init__.py +57 -0
- opscloud/mcp/config.py +203 -0
- opscloud/mcp/discovery.py +229 -0
- opscloud/mcp/mcp_info.py +109 -0
- opscloud/mcp/middleware.py +102 -0
- opscloud/mcp/preload.py +505 -0
- opscloud/mcp/raw_config.py +149 -0
- opscloud/mcp/semantic_profiler.py +305 -0
- opscloud/mcp/session_manager.py +727 -0
- opscloud/mcp/trust.py +105 -0
- opscloud/memory/__init__.py +27 -0
- opscloud/memory/branch.py +61 -0
- opscloud/memory/guard.py +19 -0
- opscloud/memory/onboarding.py +120 -0
- opscloud/memory/registry.py +134 -0
- opscloud/memory/store.py +223 -0
- opscloud/middleware/__init__.py +106 -0
- opscloud/middleware/_repository_bounds.py +459 -0
- opscloud/middleware/ask_user.py +152 -0
- opscloud/middleware/auto_mode.py +60 -0
- opscloud/middleware/auto_mode_hitl.py +2434 -0
- opscloud/middleware/compaction.py +566 -0
- opscloud/middleware/configurable_model.py +233 -0
- opscloud/middleware/cost_tracking.py +1021 -0
- opscloud/middleware/glm_stall_recovery.py +109 -0
- opscloud/middleware/goal_criteria.py +1234 -0
- opscloud/middleware/goal_state_notice.py +712 -0
- opscloud/middleware/goal_tools.py +407 -0
- opscloud/middleware/headless_mcp_guard.py +88 -0
- opscloud/middleware/jev_model_router.py +1018 -0
- opscloud/middleware/local_context.py +460 -0
- opscloud/middleware/mcp_context.py +151 -0
- opscloud/middleware/mcp_middleware.py +146 -0
- opscloud/middleware/memory_guard.py +393 -0
- opscloud/middleware/model_retry.py +205 -0
- opscloud/middleware/registry.py +137 -0
- opscloud/middleware/reliable_rubric.py +709 -0
- opscloud/middleware/resume_state.py +91 -0
- opscloud/middleware/server_hooks.py +1189 -0
- opscloud/middleware/shell_allow_list.py +90 -0
- opscloud/middleware/skills.py +382 -0
- opscloud/middleware/subagent_artifacts.py +84 -0
- opscloud/middleware/subagent_telemetry.py +261 -0
- opscloud/middleware/subagents.py +243 -0
- opscloud/middleware/tool_filter.py +384 -0
- opscloud/middleware/unified_system_message.py +62 -0
- opscloud/model/__init__.py +37 -0
- opscloud/model/config.py +2992 -0
- opscloud/model/factory.py +477 -0
- opscloud/model/pool.py +459 -0
- opscloud/model/reasoning.py +282 -0
- opscloud/offload.py +173 -0
- opscloud/output.py +64 -0
- opscloud/plugins/__init__.py +189 -0
- opscloud/plugins/_json.py +22 -0
- opscloud/plugins/adapters/__init__.py +13 -0
- opscloud/plugins/adapters/agents.py +112 -0
- opscloud/plugins/adapters/commands.py +190 -0
- opscloud/plugins/adapters/mcp.py +363 -0
- opscloud/plugins/adapters/skills.py +132 -0
- opscloud/plugins/commands_cli.py +541 -0
- opscloud/plugins/discovery.py +512 -0
- opscloud/plugins/manifest.py +335 -0
- opscloud/plugins/marketplace.py +893 -0
- opscloud/plugins/models.py +334 -0
- opscloud/plugins/project_plugins.py +317 -0
- opscloud/plugins/protocol.py +31 -0
- opscloud/plugins/store.py +905 -0
- opscloud/plugins/substitution.py +122 -0
- opscloud/project_utils.py +145 -0
- opscloud/prompts/__init__.py +37 -0
- opscloud/prompts/system.py +483 -0
- opscloud/prompts/templates/system_prompt.md +166 -0
- opscloud/prompts/types.py +54 -0
- opscloud/rubrics/__init__.py +42 -0
- opscloud/rubrics/evaluator.py +404 -0
- opscloud/rubrics/evidence_extractor.py +229 -0
- opscloud/rubrics/generator.py +239 -0
- opscloud/rubrics/jev_compiler.py +175 -0
- opscloud/rubrics/jev_grader.py +297 -0
- opscloud/rubrics/middleware.py +8 -0
- opscloud/schema/__init__.py +107 -0
- opscloud/schema/interrupts.py +981 -0
- opscloud/security/__init__.py +91 -0
- opscloud/security/approval_mode.py +528 -0
- opscloud/security/approval_mode_source.py +230 -0
- opscloud/security/cli_ast_evaluator.py +552 -0
- opscloud/security/jev_classifier.py +651 -0
- opscloud/security/shell_safety.py +340 -0
- opscloud/security/unicode_security.py +439 -0
- opscloud/security/url_validation.py +160 -0
- opscloud/server/__init__.py +13 -0
- opscloud/server/_server_config.py +158 -0
- opscloud/server/server.py +242 -0
- opscloud/server/server_graph.py +93 -0
- opscloud/skills/__init__.py +91 -0
- opscloud/skills/commands.py +1099 -0
- opscloud/skills/invocation.py +200 -0
- opscloud/skills/load.py +388 -0
- opscloud/skills/loader.py +23 -0
- opscloud/skills/merge.py +65 -0
- opscloud/skills/registry.py +263 -0
- opscloud/skills/sources.py +174 -0
- opscloud/skills/trust.py +417 -0
- opscloud/state/__init__.py +142 -0
- opscloud/state/base.py +154 -0
- opscloud/state/cloud_context.py +262 -0
- opscloud/state/goal_channels.py +124 -0
- opscloud/state/goal_state_limits.py +175 -0
- opscloud/state/resume_state.py +58 -0
- opscloud/state/service_context.py +281 -0
- opscloud/state/session.py +957 -0
- opscloud/state/state_migration.py +86 -0
- opscloud/subagents/__init__.py +30 -0
- opscloud/subagents/loader.py +331 -0
- opscloud/subagents/subagents_parser.py +117 -0
- opscloud/subagents/types.py +25 -0
- opscloud/tools/__init__.py +36 -0
- opscloud/tools/catalog.py +37 -0
- opscloud/tools/display.py +24 -0
- opscloud/tools/fetch_url.py +176 -0
- opscloud/tools/goal_tools.py +423 -0
- opscloud/tools/registry.py +105 -0
- opscloud/tools/thread.py +32 -0
- opscloud/tools/web_search.py +215 -0
- opscloud/ui/__init__.py +119 -0
- opscloud/ui/app.py +5400 -0
- opscloud/ui/app.tcss +479 -0
- opscloud/ui/clipboard.py +147 -0
- opscloud/ui/command_registry.py +482 -0
- opscloud/ui/message_store.py +152 -0
- opscloud/ui/permission_store.py +360 -0
- opscloud/ui/preferences.py +113 -0
- opscloud/ui/prompt_manager.py +96 -0
- opscloud/ui/remote_client.py +505 -0
- opscloud/ui/textual_adapter.py +1269 -0
- opscloud/ui/theme.py +728 -0
- opscloud/ui/ui_help.py +415 -0
- opscloud/ui/widgets/__init__.py +383 -0
- opscloud/ui/widgets/_ask_user_types.py +81 -0
- opscloud/ui/widgets/_copy_spans.py +52 -0
- opscloud/ui/widgets/_inline_prompt.py +290 -0
- opscloud/ui/widgets/_js_eval_display.py +139 -0
- opscloud/ui/widgets/_links.py +175 -0
- opscloud/ui/widgets/_tool_stream.py +308 -0
- opscloud/ui/widgets/agent_selector.py +297 -0
- opscloud/ui/widgets/approval.py +741 -0
- opscloud/ui/widgets/ask_user.py +539 -0
- opscloud/ui/widgets/auth.py +695 -0
- opscloud/ui/widgets/auth_manager.py +214 -0
- opscloud/ui/widgets/auto_mode_notice.py +146 -0
- opscloud/ui/widgets/autocomplete.py +709 -0
- opscloud/ui/widgets/chat_input.py +805 -0
- opscloud/ui/widgets/cloud_selector.py +528 -0
- opscloud/ui/widgets/config_manager.py +652 -0
- opscloud/ui/widgets/debug_console.py +1269 -0
- opscloud/ui/widgets/devops_renderers.py +184 -0
- opscloud/ui/widgets/diff.py +237 -0
- opscloud/ui/widgets/effort_selector.py +166 -0
- opscloud/ui/widgets/goal_review.py +612 -0
- opscloud/ui/widgets/goal_status.py +57 -0
- opscloud/ui/widgets/infra_panel.py +141 -0
- opscloud/ui/widgets/install_confirm.py +114 -0
- opscloud/ui/widgets/loading.py +170 -0
- opscloud/ui/widgets/mcp_viewer.py +1204 -0
- opscloud/ui/widgets/messages.py +4461 -0
- opscloud/ui/widgets/model_selector.py +863 -0
- opscloud/ui/widgets/notification_center.py +108 -0
- opscloud/ui/widgets/notification_settings.py +119 -0
- opscloud/ui/widgets/operation_card.py +106 -0
- opscloud/ui/widgets/permissions_manager.py +667 -0
- opscloud/ui/widgets/plugin_manager.py +1212 -0
- opscloud/ui/widgets/pool_selector.py +376 -0
- opscloud/ui/widgets/preamble.py +53 -0
- opscloud/ui/widgets/skills_viewer.py +432 -0
- opscloud/ui/widgets/status.py +1037 -0
- opscloud/ui/widgets/subagent_panel.py +927 -0
- opscloud/ui/widgets/theme_selector.py +232 -0
- opscloud/ui/widgets/thread_selector.py +358 -0
- opscloud/ui/widgets/toast.py +31 -0
- opscloud/ui/widgets/tool_display.py +325 -0
- opscloud/ui/widgets/tool_renderers.py +234 -0
- opscloud/ui/widgets/tool_widgets.py +278 -0
- opscloud/ui/widgets/welcome.py +421 -0
- opscloud/ui/widgets/welcome_popup.py +102 -0
- opscloud/utils/__init__.py +24 -0
- opscloud/utils/cost_estimation.py +169 -0
- opscloud/utils/git.py +390 -0
- opscloud/utils/logger.py +571 -0
- opscloud/utils/session_stats.py +115 -0
- opscloud/utils/startup_error.py +37 -0
- talkops_opscloud-0.3.0b1.dist-info/METADATA +449 -0
- talkops_opscloud-0.3.0b1.dist-info/RECORD +309 -0
- talkops_opscloud-0.3.0b1.dist-info/WHEEL +4 -0
- talkops_opscloud-0.3.0b1.dist-info/entry_points.txt +2 -0
- talkops_opscloud-0.3.0b1.dist-info/licenses/LICENSE +175 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Client↔server interrupt transport for Hooks v2 server-owned events."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, TypeAdapter
|
|
8
|
+
|
|
9
|
+
from opscloud.hooks.models.adapters import HOOK_INVOCATION_RESPONSE_ADAPTER
|
|
10
|
+
from opscloud.hooks.models.transport import (
|
|
11
|
+
HookInvocationRequest,
|
|
12
|
+
HookInvocationResponse,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from uuid import UUID
|
|
17
|
+
|
|
18
|
+
HOOK_INVOCATION_INTERRUPT_TYPE: Literal["hook_invocation"] = "hook_invocation"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class HookInvocationInterrupt(BaseModel):
|
|
22
|
+
"""LangGraph interrupt envelope for a server-owned hook invocation."""
|
|
23
|
+
|
|
24
|
+
model_config = ConfigDict(extra="forbid")
|
|
25
|
+
|
|
26
|
+
type: Literal["hook_invocation"] = HOOK_INVOCATION_INTERRUPT_TYPE
|
|
27
|
+
request: HookInvocationRequest
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
HOOK_INVOCATION_INTERRUPT_ADAPTER: TypeAdapter[HookInvocationInterrupt] = TypeAdapter(HookInvocationInterrupt)
|
|
31
|
+
|
|
32
|
+
type HookResumeValue = dict[str, Any]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_hook_interrupt_payload(request: HookInvocationRequest) -> dict[str, Any]:
|
|
36
|
+
"""Serialize a hook invocation request for `interrupt()`.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
request: Versioned server-owned invocation request.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
JSON-compatible interrupt payload with a stable `type` discriminator.
|
|
43
|
+
"""
|
|
44
|
+
return HOOK_INVOCATION_INTERRUPT_ADAPTER.dump_python(
|
|
45
|
+
HookInvocationInterrupt(request=request),
|
|
46
|
+
mode="json",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def parse_hook_interrupt_payload(value: object) -> HookInvocationRequest | None:
|
|
51
|
+
"""Parse a hook invocation interrupt payload when present.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
value: Raw interrupt value from LangGraph.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The embedded request, or None when value is not a hook interrupt.
|
|
58
|
+
"""
|
|
59
|
+
if not isinstance(value, dict) or value.get("type") != HOOK_INVOCATION_INTERRUPT_TYPE:
|
|
60
|
+
return None
|
|
61
|
+
interrupt_data = HOOK_INVOCATION_INTERRUPT_ADAPTER.validate_python(value)
|
|
62
|
+
return interrupt_data.request
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def build_hook_resume_value(response: HookInvocationResponse) -> HookResumeValue:
|
|
66
|
+
"""Serialize a hook invocation response for `Command(resume=...)`.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
response: Decision returned by the client runtime.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
JSON-compatible resume value for the matching interrupt id.
|
|
73
|
+
"""
|
|
74
|
+
return HOOK_INVOCATION_RESPONSE_ADAPTER.dump_python(response, mode="json")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def parse_hook_resume_value(
|
|
78
|
+
value: object,
|
|
79
|
+
*,
|
|
80
|
+
invocation_id: UUID,
|
|
81
|
+
snapshot_id: str,
|
|
82
|
+
) -> HookInvocationResponse:
|
|
83
|
+
"""Validate a resumed hook response against the outstanding request.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
value: Resume payload returned by the client.
|
|
87
|
+
invocation_id: Expected invocation id from the request.
|
|
88
|
+
snapshot_id: Expected configuration snapshot id.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Validated hook invocation response.
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
ValueError: If the resume payload is not a JSON object or if the
|
|
95
|
+
invocation_id or snapshot_id does not match expectations.
|
|
96
|
+
"""
|
|
97
|
+
if not isinstance(value, dict):
|
|
98
|
+
msg = "Hook resume payload must be a JSON object"
|
|
99
|
+
raise ValueError(msg)
|
|
100
|
+
response = HOOK_INVOCATION_RESPONSE_ADAPTER.validate_python(value)
|
|
101
|
+
if response.invocation_id != invocation_id:
|
|
102
|
+
msg = f"Resume invocation id {response.invocation_id} does not match {invocation_id}"
|
|
103
|
+
raise ValueError(msg)
|
|
104
|
+
if response.snapshot_id != snapshot_id:
|
|
105
|
+
msg = f"Resume snapshot id {response.snapshot_id} does not match {snapshot_id}"
|
|
106
|
+
raise ValueError(msg)
|
|
107
|
+
return response
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def is_hook_interrupt_payload(value: object) -> bool:
|
|
111
|
+
"""Return whether value looks like a Hooks v2 invocation interrupt.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
value: Any interrupt payload value to check.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
True if the value is a dict with type 'hook_invocation', False otherwise.
|
|
118
|
+
"""
|
|
119
|
+
return (
|
|
120
|
+
isinstance(value, dict) and value.get("type") == HOOK_INVOCATION_INTERRUPT_TYPE
|
|
121
|
+
)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Hook domain and transport models."""
|
|
2
|
+
|
|
3
|
+
from opscloud.hooks.models.domain import (
|
|
4
|
+
AgentIdentity,
|
|
5
|
+
BackgroundTaskSnapshot,
|
|
6
|
+
BaseHookDecision,
|
|
7
|
+
CompactTrigger,
|
|
8
|
+
EffortLevel,
|
|
9
|
+
HookContext,
|
|
10
|
+
HookDecision,
|
|
11
|
+
HookDiagnostic,
|
|
12
|
+
HookDomainEvent,
|
|
13
|
+
HookEffect,
|
|
14
|
+
HookEvent,
|
|
15
|
+
HookInvocation,
|
|
16
|
+
HookOwner,
|
|
17
|
+
NotificationDecision,
|
|
18
|
+
NotificationEvent,
|
|
19
|
+
OpscloudNotification,
|
|
20
|
+
OpscloudNotificationKind,
|
|
21
|
+
PermissionEffect,
|
|
22
|
+
PermissionRequestDecision,
|
|
23
|
+
PermissionRequestEvent,
|
|
24
|
+
PostToolUseDecision,
|
|
25
|
+
PostToolUseEvent,
|
|
26
|
+
PostToolUseFailureDecision,
|
|
27
|
+
PostToolUseFailureEvent,
|
|
28
|
+
PreCompactDecision,
|
|
29
|
+
PreCompactEvent,
|
|
30
|
+
PreToolUseDecision,
|
|
31
|
+
PreToolUseEvent,
|
|
32
|
+
SessionCronSnapshot,
|
|
33
|
+
SessionEndCause,
|
|
34
|
+
SessionEndDecision,
|
|
35
|
+
SessionEndEvent,
|
|
36
|
+
SessionStartCause,
|
|
37
|
+
SessionStartDecision,
|
|
38
|
+
SessionStartEvent,
|
|
39
|
+
StopDecision,
|
|
40
|
+
StopEvent,
|
|
41
|
+
SubagentStartDecision,
|
|
42
|
+
SubagentStartEvent,
|
|
43
|
+
SubagentStopDecision,
|
|
44
|
+
SubagentStopEvent,
|
|
45
|
+
ToolCallData,
|
|
46
|
+
UserPromptSubmitDecision,
|
|
47
|
+
UserPromptSubmitEvent,
|
|
48
|
+
)
|
|
49
|
+
from opscloud.hooks.models.config import (
|
|
50
|
+
CommandHandlerSpec,
|
|
51
|
+
HooksConfig,
|
|
52
|
+
MatcherGroup,
|
|
53
|
+
)
|
|
54
|
+
from opscloud.hooks.models.transport import (
|
|
55
|
+
HookInvocationRequest,
|
|
56
|
+
HookInvocationResponse,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"AgentIdentity",
|
|
61
|
+
"BackgroundTaskSnapshot",
|
|
62
|
+
"BaseHookDecision",
|
|
63
|
+
"CommandHandlerSpec",
|
|
64
|
+
"CompactTrigger",
|
|
65
|
+
"EffortLevel",
|
|
66
|
+
"HookContext",
|
|
67
|
+
"HookDecision",
|
|
68
|
+
"HookDiagnostic",
|
|
69
|
+
"HookDomainEvent",
|
|
70
|
+
"HookEffect",
|
|
71
|
+
"HookEvent",
|
|
72
|
+
"HookInvocation",
|
|
73
|
+
"HookInvocationRequest",
|
|
74
|
+
"HookInvocationResponse",
|
|
75
|
+
"HookOwner",
|
|
76
|
+
"HooksConfig",
|
|
77
|
+
"MatcherGroup",
|
|
78
|
+
"NotificationDecision",
|
|
79
|
+
"NotificationEvent",
|
|
80
|
+
"OpscloudNotification",
|
|
81
|
+
"OpscloudNotificationKind",
|
|
82
|
+
"PermissionEffect",
|
|
83
|
+
"PermissionRequestDecision",
|
|
84
|
+
"PermissionRequestEvent",
|
|
85
|
+
"PostToolUseDecision",
|
|
86
|
+
"PostToolUseEvent",
|
|
87
|
+
"PostToolUseFailureDecision",
|
|
88
|
+
"PostToolUseFailureEvent",
|
|
89
|
+
"PreCompactDecision",
|
|
90
|
+
"PreCompactEvent",
|
|
91
|
+
"PreToolUseDecision",
|
|
92
|
+
"PreToolUseEvent",
|
|
93
|
+
"SessionCronSnapshot",
|
|
94
|
+
"SessionEndCause",
|
|
95
|
+
"SessionEndDecision",
|
|
96
|
+
"SessionEndEvent",
|
|
97
|
+
"SessionStartCause",
|
|
98
|
+
"SessionStartDecision",
|
|
99
|
+
"SessionStartEvent",
|
|
100
|
+
"StopDecision",
|
|
101
|
+
"StopEvent",
|
|
102
|
+
"SubagentStartDecision",
|
|
103
|
+
"SubagentStartEvent",
|
|
104
|
+
"SubagentStopDecision",
|
|
105
|
+
"SubagentStopEvent",
|
|
106
|
+
"ToolCallData",
|
|
107
|
+
"UserPromptSubmitDecision",
|
|
108
|
+
"UserPromptSubmitEvent",
|
|
109
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Cached runtime validators for hook model boundaries."""
|
|
2
|
+
|
|
3
|
+
from pydantic import TypeAdapter
|
|
4
|
+
|
|
5
|
+
from opscloud.hooks.models.domain import (
|
|
6
|
+
HookDecision,
|
|
7
|
+
HookDomainEvent,
|
|
8
|
+
HookInvocation,
|
|
9
|
+
)
|
|
10
|
+
from opscloud.hooks.models.transport import (
|
|
11
|
+
HookInvocationRequest,
|
|
12
|
+
HookInvocationResponse,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
HOOK_DOMAIN_EVENT_ADAPTER: TypeAdapter[HookDomainEvent] = TypeAdapter(HookDomainEvent)
|
|
16
|
+
HOOK_INVOCATION_ADAPTER: TypeAdapter[HookInvocation] = TypeAdapter(HookInvocation)
|
|
17
|
+
HOOK_DECISION_ADAPTER: TypeAdapter[HookDecision] = TypeAdapter(HookDecision)
|
|
18
|
+
HOOK_INVOCATION_REQUEST_ADAPTER: TypeAdapter[HookInvocationRequest] = TypeAdapter(HookInvocationRequest)
|
|
19
|
+
HOOK_INVOCATION_RESPONSE_ADAPTER: TypeAdapter[HookInvocationResponse] = TypeAdapter(HookInvocationResponse)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Validated hook configuration models for declarative Hooks v2 specifications."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
8
|
+
|
|
9
|
+
from opscloud.hooks.models.domain import HookEvent
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _ConfigModel(BaseModel):
|
|
13
|
+
"""Base model for hook configuration objects."""
|
|
14
|
+
|
|
15
|
+
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CommandHandlerSpec(_ConfigModel):
|
|
19
|
+
"""Configuration for a command hook handler.
|
|
20
|
+
|
|
21
|
+
Currently supports `type: "command"`. Commands can run shell expressions
|
|
22
|
+
or direct executable arguments via `argv`.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
type: Literal["command"]
|
|
26
|
+
command: str
|
|
27
|
+
argv: list[str] | None = None
|
|
28
|
+
timeout: float | None = Field(default=None, gt=0, allow_inf_nan=False)
|
|
29
|
+
status_message: str | None = Field(default=None, alias="statusMessage")
|
|
30
|
+
async_: bool | None = Field(default=None, alias="async")
|
|
31
|
+
|
|
32
|
+
@field_validator("argv", mode="after")
|
|
33
|
+
@classmethod
|
|
34
|
+
def _normalize_argv(cls, value: list[str] | None) -> list[str] | None:
|
|
35
|
+
"""Validate that argv is a non-empty list of strings if provided.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
value: Provided argv list or None.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Validated list of string arguments.
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
ValueError: If argv is empty, contains non-strings, or has an empty executable.
|
|
45
|
+
"""
|
|
46
|
+
if value is None:
|
|
47
|
+
return None
|
|
48
|
+
if not value or not all(isinstance(part, str) for part in value):
|
|
49
|
+
msg = "argv must be a non-empty list of strings when provided."
|
|
50
|
+
raise ValueError(msg)
|
|
51
|
+
if not value[0].strip():
|
|
52
|
+
msg = "argv[0] must be a non-empty executable path."
|
|
53
|
+
raise ValueError(msg)
|
|
54
|
+
return value
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
HandlerSpec = CommandHandlerSpec
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class MatcherGroup(_ConfigModel):
|
|
61
|
+
"""A matcher pattern and its ordered hook handlers.
|
|
62
|
+
|
|
63
|
+
Attributes:
|
|
64
|
+
matcher: Tool name pattern (e.g. 'Bash', 'aws_*', 'Write') or regex.
|
|
65
|
+
hooks: List of handler specifications to execute on match.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
matcher: str | None = None
|
|
69
|
+
hooks: list[HandlerSpec]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class HooksConfig(_ConfigModel):
|
|
73
|
+
"""Top-level configuration grouped by hook lifecycle event.
|
|
74
|
+
|
|
75
|
+
Attributes:
|
|
76
|
+
hooks: Mapping from lifecycle HookEvent to list of MatcherGroups.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
hooks: dict[HookEvent, list[MatcherGroup]]
|