kubiya-control-plane-api 0.1.0__py3-none-any.whl → 0.3.4__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 kubiya-control-plane-api might be problematic. Click here for more details.
- control_plane_api/README.md +266 -0
- control_plane_api/__init__.py +0 -0
- control_plane_api/__version__.py +1 -0
- control_plane_api/alembic/README +1 -0
- control_plane_api/alembic/env.py +98 -0
- control_plane_api/alembic/script.py.mako +28 -0
- control_plane_api/alembic/versions/1382bec74309_initial_migration_with_all_models.py +251 -0
- control_plane_api/alembic/versions/1f54bc2a37e3_add_analytics_tables.py +162 -0
- control_plane_api/alembic/versions/2e4cb136dc10_rename_toolset_ids_to_skill_ids_in_teams.py +30 -0
- control_plane_api/alembic/versions/31cd69a644ce_add_skill_templates_table.py +28 -0
- control_plane_api/alembic/versions/89e127caa47d_add_jobs_and_job_executions_tables.py +161 -0
- control_plane_api/alembic/versions/add_llm_models_table.py +51 -0
- control_plane_api/alembic/versions/b0e10697f212_add_runtime_column_to_teams_simple.py +42 -0
- control_plane_api/alembic/versions/ce43b24b63bf_add_execution_trigger_source_and_fix_.py +155 -0
- control_plane_api/alembic/versions/d4eaf16e3f8d_rename_toolsets_to_skills.py +84 -0
- control_plane_api/alembic/versions/efa2dc427da1_rename_metadata_to_custom_metadata.py +32 -0
- control_plane_api/alembic/versions/f973b431d1ce_add_workflow_executor_to_skill_types.py +44 -0
- control_plane_api/alembic.ini +148 -0
- control_plane_api/api/index.py +12 -0
- control_plane_api/app/__init__.py +11 -0
- control_plane_api/app/activities/__init__.py +20 -0
- control_plane_api/app/activities/agent_activities.py +379 -0
- control_plane_api/app/activities/team_activities.py +410 -0
- control_plane_api/app/activities/temporal_cloud_activities.py +577 -0
- control_plane_api/app/config/__init__.py +35 -0
- control_plane_api/app/config/api_config.py +354 -0
- control_plane_api/app/config/model_pricing.py +318 -0
- control_plane_api/app/config.py +95 -0
- control_plane_api/app/database.py +135 -0
- control_plane_api/app/exceptions.py +408 -0
- control_plane_api/app/lib/__init__.py +11 -0
- control_plane_api/app/lib/job_executor.py +312 -0
- control_plane_api/app/lib/kubiya_client.py +235 -0
- control_plane_api/app/lib/litellm_pricing.py +166 -0
- control_plane_api/app/lib/planning_tools/__init__.py +22 -0
- control_plane_api/app/lib/planning_tools/agents.py +155 -0
- control_plane_api/app/lib/planning_tools/base.py +189 -0
- control_plane_api/app/lib/planning_tools/environments.py +214 -0
- control_plane_api/app/lib/planning_tools/resources.py +240 -0
- control_plane_api/app/lib/planning_tools/teams.py +198 -0
- control_plane_api/app/lib/policy_enforcer_client.py +939 -0
- control_plane_api/app/lib/redis_client.py +436 -0
- control_plane_api/app/lib/supabase.py +71 -0
- control_plane_api/app/lib/temporal_client.py +138 -0
- control_plane_api/app/lib/validation/__init__.py +20 -0
- control_plane_api/app/lib/validation/runtime_validation.py +287 -0
- control_plane_api/app/main.py +128 -0
- control_plane_api/app/middleware/__init__.py +8 -0
- control_plane_api/app/middleware/auth.py +513 -0
- control_plane_api/app/middleware/exception_handler.py +267 -0
- control_plane_api/app/middleware/rate_limiting.py +384 -0
- control_plane_api/app/middleware/request_id.py +202 -0
- control_plane_api/app/models/__init__.py +27 -0
- control_plane_api/app/models/agent.py +79 -0
- control_plane_api/app/models/analytics.py +206 -0
- control_plane_api/app/models/associations.py +81 -0
- control_plane_api/app/models/environment.py +63 -0
- control_plane_api/app/models/execution.py +93 -0
- control_plane_api/app/models/job.py +179 -0
- control_plane_api/app/models/llm_model.py +75 -0
- control_plane_api/app/models/presence.py +49 -0
- control_plane_api/app/models/project.py +47 -0
- control_plane_api/app/models/session.py +38 -0
- control_plane_api/app/models/team.py +66 -0
- control_plane_api/app/models/workflow.py +55 -0
- control_plane_api/app/policies/README.md +121 -0
- control_plane_api/app/policies/approved_users.rego +62 -0
- control_plane_api/app/policies/business_hours.rego +51 -0
- control_plane_api/app/policies/rate_limiting.rego +100 -0
- control_plane_api/app/policies/tool_restrictions.rego +86 -0
- control_plane_api/app/routers/__init__.py +4 -0
- control_plane_api/app/routers/agents.py +364 -0
- control_plane_api/app/routers/agents_v2.py +1260 -0
- control_plane_api/app/routers/analytics.py +1014 -0
- control_plane_api/app/routers/context_manager.py +562 -0
- control_plane_api/app/routers/environment_context.py +270 -0
- control_plane_api/app/routers/environments.py +715 -0
- control_plane_api/app/routers/execution_environment.py +517 -0
- control_plane_api/app/routers/executions.py +1911 -0
- control_plane_api/app/routers/health.py +92 -0
- control_plane_api/app/routers/health_v2.py +326 -0
- control_plane_api/app/routers/integrations.py +274 -0
- control_plane_api/app/routers/jobs.py +1344 -0
- control_plane_api/app/routers/models.py +82 -0
- control_plane_api/app/routers/models_v2.py +361 -0
- control_plane_api/app/routers/policies.py +639 -0
- control_plane_api/app/routers/presence.py +234 -0
- control_plane_api/app/routers/projects.py +902 -0
- control_plane_api/app/routers/runners.py +379 -0
- control_plane_api/app/routers/runtimes.py +172 -0
- control_plane_api/app/routers/secrets.py +155 -0
- control_plane_api/app/routers/skills.py +1001 -0
- control_plane_api/app/routers/skills_definitions.py +140 -0
- control_plane_api/app/routers/task_planning.py +1256 -0
- control_plane_api/app/routers/task_queues.py +654 -0
- control_plane_api/app/routers/team_context.py +270 -0
- control_plane_api/app/routers/teams.py +1400 -0
- control_plane_api/app/routers/worker_queues.py +1545 -0
- control_plane_api/app/routers/workers.py +935 -0
- control_plane_api/app/routers/workflows.py +204 -0
- control_plane_api/app/runtimes/__init__.py +6 -0
- control_plane_api/app/runtimes/validation.py +344 -0
- control_plane_api/app/schemas/job_schemas.py +295 -0
- control_plane_api/app/services/__init__.py +1 -0
- control_plane_api/app/services/agno_service.py +619 -0
- control_plane_api/app/services/litellm_service.py +190 -0
- control_plane_api/app/services/policy_service.py +525 -0
- control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
- control_plane_api/app/skills/__init__.py +44 -0
- control_plane_api/app/skills/base.py +229 -0
- control_plane_api/app/skills/business_intelligence.py +189 -0
- control_plane_api/app/skills/data_visualization.py +154 -0
- control_plane_api/app/skills/docker.py +104 -0
- control_plane_api/app/skills/file_generation.py +94 -0
- control_plane_api/app/skills/file_system.py +110 -0
- control_plane_api/app/skills/python.py +92 -0
- control_plane_api/app/skills/registry.py +65 -0
- control_plane_api/app/skills/shell.py +102 -0
- control_plane_api/app/skills/workflow_executor.py +469 -0
- control_plane_api/app/utils/workflow_executor.py +354 -0
- control_plane_api/app/workflows/__init__.py +11 -0
- control_plane_api/app/workflows/agent_execution.py +507 -0
- control_plane_api/app/workflows/agent_execution_with_skills.py +222 -0
- control_plane_api/app/workflows/namespace_provisioning.py +326 -0
- control_plane_api/app/workflows/team_execution.py +399 -0
- control_plane_api/scripts/seed_models.py +239 -0
- control_plane_api/worker/__init__.py +0 -0
- control_plane_api/worker/activities/__init__.py +0 -0
- control_plane_api/worker/activities/agent_activities.py +1241 -0
- control_plane_api/worker/activities/approval_activities.py +234 -0
- control_plane_api/worker/activities/runtime_activities.py +388 -0
- control_plane_api/worker/activities/skill_activities.py +267 -0
- control_plane_api/worker/activities/team_activities.py +1217 -0
- control_plane_api/worker/config/__init__.py +31 -0
- control_plane_api/worker/config/worker_config.py +275 -0
- control_plane_api/worker/control_plane_client.py +529 -0
- control_plane_api/worker/examples/analytics_integration_example.py +362 -0
- control_plane_api/worker/models/__init__.py +1 -0
- control_plane_api/worker/models/inputs.py +89 -0
- control_plane_api/worker/runtimes/__init__.py +31 -0
- control_plane_api/worker/runtimes/base.py +789 -0
- control_plane_api/worker/runtimes/claude_code_runtime.py +1443 -0
- control_plane_api/worker/runtimes/default_runtime.py +617 -0
- control_plane_api/worker/runtimes/factory.py +173 -0
- control_plane_api/worker/runtimes/validation.py +93 -0
- control_plane_api/worker/services/__init__.py +1 -0
- control_plane_api/worker/services/agent_executor.py +422 -0
- control_plane_api/worker/services/agent_executor_v2.py +383 -0
- control_plane_api/worker/services/analytics_collector.py +457 -0
- control_plane_api/worker/services/analytics_service.py +464 -0
- control_plane_api/worker/services/approval_tools.py +310 -0
- control_plane_api/worker/services/approval_tools_agno.py +207 -0
- control_plane_api/worker/services/cancellation_manager.py +177 -0
- control_plane_api/worker/services/data_visualization.py +827 -0
- control_plane_api/worker/services/jira_tools.py +257 -0
- control_plane_api/worker/services/runtime_analytics.py +328 -0
- control_plane_api/worker/services/session_service.py +194 -0
- control_plane_api/worker/services/skill_factory.py +175 -0
- control_plane_api/worker/services/team_executor.py +574 -0
- control_plane_api/worker/services/team_executor_v2.py +465 -0
- control_plane_api/worker/services/workflow_executor_tools.py +1418 -0
- control_plane_api/worker/tests/__init__.py +1 -0
- control_plane_api/worker/tests/e2e/__init__.py +0 -0
- control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
- control_plane_api/worker/tests/integration/__init__.py +0 -0
- control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
- control_plane_api/worker/tests/unit/__init__.py +0 -0
- control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
- control_plane_api/worker/utils/__init__.py +1 -0
- control_plane_api/worker/utils/chunk_batcher.py +305 -0
- control_plane_api/worker/utils/retry_utils.py +60 -0
- control_plane_api/worker/utils/streaming_utils.py +373 -0
- control_plane_api/worker/worker.py +753 -0
- control_plane_api/worker/workflows/__init__.py +0 -0
- control_plane_api/worker/workflows/agent_execution.py +589 -0
- control_plane_api/worker/workflows/team_execution.py +429 -0
- kubiya_control_plane_api-0.3.4.dist-info/METADATA +229 -0
- kubiya_control_plane_api-0.3.4.dist-info/RECORD +182 -0
- kubiya_control_plane_api-0.3.4.dist-info/entry_points.txt +2 -0
- kubiya_control_plane_api-0.3.4.dist-info/top_level.txt +1 -0
- kubiya_control_plane_api-0.1.0.dist-info/METADATA +0 -66
- kubiya_control_plane_api-0.1.0.dist-info/RECORD +0 -5
- kubiya_control_plane_api-0.1.0.dist-info/top_level.txt +0 -1
- {kubiya_control_plane_api-0.1.0.dist-info/licenses → control_plane_api}/LICENSE +0 -0
- {kubiya_control_plane_api-0.1.0.dist-info → kubiya_control_plane_api-0.3.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Refactored Agent executor service using runtime abstraction.
|
|
3
|
+
|
|
4
|
+
This version delegates execution to pluggable runtime implementations,
|
|
5
|
+
making the code more maintainable and extensible.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Any, Optional
|
|
9
|
+
import structlog
|
|
10
|
+
|
|
11
|
+
from control_plane_api.worker.control_plane_client import ControlPlaneClient
|
|
12
|
+
from control_plane_api.worker.services.session_service import SessionService
|
|
13
|
+
from control_plane_api.worker.services.cancellation_manager import CancellationManager
|
|
14
|
+
from runtimes import (
|
|
15
|
+
RuntimeFactory,
|
|
16
|
+
RuntimeType,
|
|
17
|
+
RuntimeExecutionContext,
|
|
18
|
+
)
|
|
19
|
+
from control_plane_api.worker.utils.streaming_utils import StreamingHelper
|
|
20
|
+
|
|
21
|
+
logger = structlog.get_logger()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AgentExecutorServiceV2:
|
|
25
|
+
"""
|
|
26
|
+
Service for executing agents using runtime abstraction.
|
|
27
|
+
|
|
28
|
+
This service orchestrates agent execution by:
|
|
29
|
+
1. Loading session history
|
|
30
|
+
2. Selecting appropriate runtime based on agent config
|
|
31
|
+
3. Delegating execution to the runtime
|
|
32
|
+
4. Persisting session after execution
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
control_plane: ControlPlaneClient,
|
|
38
|
+
session_service: SessionService,
|
|
39
|
+
cancellation_manager: CancellationManager,
|
|
40
|
+
):
|
|
41
|
+
"""
|
|
42
|
+
Initialize the agent executor service.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
control_plane: Control Plane API client
|
|
46
|
+
session_service: Session management service
|
|
47
|
+
cancellation_manager: Execution cancellation manager
|
|
48
|
+
"""
|
|
49
|
+
self.control_plane = control_plane
|
|
50
|
+
self.session_service = session_service
|
|
51
|
+
self.cancellation_manager = cancellation_manager
|
|
52
|
+
self.runtime_factory = RuntimeFactory()
|
|
53
|
+
|
|
54
|
+
async def execute(self, input: Any) -> Dict[str, Any]:
|
|
55
|
+
"""
|
|
56
|
+
Execute an agent using the configured runtime.
|
|
57
|
+
|
|
58
|
+
This method:
|
|
59
|
+
1. Loads session history
|
|
60
|
+
2. Determines runtime type from agent config
|
|
61
|
+
3. Creates runtime instance
|
|
62
|
+
4. Executes agent via runtime
|
|
63
|
+
5. Persists session
|
|
64
|
+
6. Returns standardized result
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
input: AgentExecutionInput with execution details
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Dict with response, usage, success flag, runtime_type, etc.
|
|
71
|
+
"""
|
|
72
|
+
execution_id = input.execution_id
|
|
73
|
+
|
|
74
|
+
print("\n" + "=" * 80)
|
|
75
|
+
print("🤖 AGENT EXECUTION START (Runtime-Abstracted)")
|
|
76
|
+
print("=" * 80)
|
|
77
|
+
print(f"Execution ID: {execution_id}")
|
|
78
|
+
print(f"Agent ID: {input.agent_id}")
|
|
79
|
+
print(f"Organization: {input.organization_id}")
|
|
80
|
+
print(f"Model: {input.model_id or 'default'}")
|
|
81
|
+
print(f"Session ID: {input.session_id}")
|
|
82
|
+
print(
|
|
83
|
+
f"Prompt: {input.prompt[:100]}..."
|
|
84
|
+
if len(input.prompt) > 100
|
|
85
|
+
else f"Prompt: {input.prompt}"
|
|
86
|
+
)
|
|
87
|
+
print("=" * 80 + "\n")
|
|
88
|
+
|
|
89
|
+
logger.info(
|
|
90
|
+
"agent_execution_start",
|
|
91
|
+
execution_id=execution_id[:8],
|
|
92
|
+
agent_id=input.agent_id,
|
|
93
|
+
session_id=input.session_id,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
# STEP 1: Load session history
|
|
98
|
+
print("📚 Loading session history...")
|
|
99
|
+
session_history = self.session_service.load_session(
|
|
100
|
+
execution_id=execution_id, session_id=input.session_id
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if session_history:
|
|
104
|
+
print(
|
|
105
|
+
f"✅ Loaded {len(session_history)} messages from previous session\n"
|
|
106
|
+
)
|
|
107
|
+
else:
|
|
108
|
+
print("ℹ️ Starting new conversation\n")
|
|
109
|
+
|
|
110
|
+
# STEP 2: Determine runtime type
|
|
111
|
+
agent_config = input.agent_config or {}
|
|
112
|
+
runtime_type_str = agent_config.get("runtime", "default")
|
|
113
|
+
runtime_type = self.runtime_factory.parse_runtime_type(runtime_type_str)
|
|
114
|
+
|
|
115
|
+
print(f"🔌 Runtime Type: {runtime_type.value}")
|
|
116
|
+
print(f" Framework: {self._get_framework_name(runtime_type)}\n")
|
|
117
|
+
|
|
118
|
+
logger.info(
|
|
119
|
+
"runtime_selected",
|
|
120
|
+
execution_id=execution_id[:8],
|
|
121
|
+
runtime=runtime_type.value,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# STEP 3: Create runtime instance
|
|
125
|
+
print(f"⚙️ Creating runtime instance...")
|
|
126
|
+
runtime = self.runtime_factory.create_runtime(
|
|
127
|
+
runtime_type=runtime_type,
|
|
128
|
+
control_plane_client=self.control_plane,
|
|
129
|
+
cancellation_manager=self.cancellation_manager,
|
|
130
|
+
)
|
|
131
|
+
print(f"✅ Runtime created: {runtime.get_runtime_info()}\n")
|
|
132
|
+
|
|
133
|
+
# STEP 4: Get skills (if runtime supports tools)
|
|
134
|
+
skills = []
|
|
135
|
+
if runtime.supports_tools():
|
|
136
|
+
print(f"🔧 Fetching skills from Control Plane...")
|
|
137
|
+
try:
|
|
138
|
+
skill_configs = self.control_plane.get_skills(input.agent_id)
|
|
139
|
+
if skill_configs:
|
|
140
|
+
print(f"✅ Resolved {len(skill_configs)} skills")
|
|
141
|
+
print(f" Types: {[t.get('type') for t in skill_configs]}")
|
|
142
|
+
print(f" Names: {[t.get('name') for t in skill_configs]}")
|
|
143
|
+
print(f" Enabled: {[t.get('enabled', True) for t in skill_configs]}\n")
|
|
144
|
+
|
|
145
|
+
# DEBUG: Show full config for workflow_executor skills
|
|
146
|
+
for cfg in skill_configs:
|
|
147
|
+
if cfg.get('type') in ['workflow_executor', 'workflow']:
|
|
148
|
+
print(f"🔍 Workflow Executor Skill Config:")
|
|
149
|
+
print(f" Name: {cfg.get('name')}")
|
|
150
|
+
print(f" Type: {cfg.get('type')}")
|
|
151
|
+
print(f" Enabled: {cfg.get('enabled', True)}")
|
|
152
|
+
print(f" Config Keys: {list(cfg.get('configuration', {}).keys())}\n")
|
|
153
|
+
|
|
154
|
+
# Import here to avoid circular dependency
|
|
155
|
+
from services.skill_factory import SkillFactory
|
|
156
|
+
|
|
157
|
+
skills = SkillFactory.create_skills_from_list(
|
|
158
|
+
skill_configs
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if skills:
|
|
162
|
+
print(f"✅ Instantiated {len(skills)} skill(s)")
|
|
163
|
+
# Show types of instantiated skills
|
|
164
|
+
skill_types = [type(s).__name__ for s in skills]
|
|
165
|
+
print(f" Skill classes: {skill_types}\n")
|
|
166
|
+
else:
|
|
167
|
+
print(f"⚠️ No skills were instantiated (all disabled or failed)\n")
|
|
168
|
+
else:
|
|
169
|
+
print(f"⚠️ No skills found for agent\n")
|
|
170
|
+
except Exception as e:
|
|
171
|
+
print(f"❌ Error fetching skills: {str(e)}\n")
|
|
172
|
+
logger.error("skill_fetch_error", error=str(e), exc_info=True)
|
|
173
|
+
|
|
174
|
+
# STEP 5: Build execution context
|
|
175
|
+
print("📦 Building execution context...")
|
|
176
|
+
context = RuntimeExecutionContext(
|
|
177
|
+
execution_id=execution_id,
|
|
178
|
+
agent_id=input.agent_id,
|
|
179
|
+
organization_id=input.organization_id,
|
|
180
|
+
prompt=input.prompt,
|
|
181
|
+
system_prompt=input.system_prompt,
|
|
182
|
+
conversation_history=session_history,
|
|
183
|
+
model_id=input.model_id,
|
|
184
|
+
model_config=input.model_config,
|
|
185
|
+
agent_config=agent_config,
|
|
186
|
+
skills=skills,
|
|
187
|
+
mcp_servers=input.mcp_servers,
|
|
188
|
+
user_metadata=input.user_metadata,
|
|
189
|
+
runtime_config=agent_config.get("runtime_config"),
|
|
190
|
+
)
|
|
191
|
+
print("✅ Context ready\n")
|
|
192
|
+
|
|
193
|
+
# STEP 6: Execute via runtime (with streaming if supported)
|
|
194
|
+
print("⚡ Executing via runtime...\n")
|
|
195
|
+
|
|
196
|
+
if runtime.supports_streaming():
|
|
197
|
+
result = await self._execute_streaming(runtime, context, input)
|
|
198
|
+
else:
|
|
199
|
+
result = await runtime.execute(context)
|
|
200
|
+
|
|
201
|
+
print("\n✅ Runtime execution completed!")
|
|
202
|
+
print(f" Response Length: {len(result.response)} chars")
|
|
203
|
+
print(f" Success: {result.success}\n")
|
|
204
|
+
|
|
205
|
+
logger.info(
|
|
206
|
+
"agent_execution_completed",
|
|
207
|
+
execution_id=execution_id[:8],
|
|
208
|
+
success=result.success,
|
|
209
|
+
response_length=len(result.response),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# STEP 7: Persist session
|
|
213
|
+
if result.success and result.response:
|
|
214
|
+
print("💾 Persisting session history...")
|
|
215
|
+
|
|
216
|
+
# Build new messages
|
|
217
|
+
new_messages = [
|
|
218
|
+
{"role": "user", "content": input.prompt},
|
|
219
|
+
{"role": "assistant", "content": result.response},
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
# Combine with previous history
|
|
223
|
+
complete_session = session_history + new_messages
|
|
224
|
+
|
|
225
|
+
success = self.session_service.persist_session(
|
|
226
|
+
execution_id=execution_id,
|
|
227
|
+
session_id=input.session_id or execution_id,
|
|
228
|
+
user_id=input.user_id,
|
|
229
|
+
messages=complete_session,
|
|
230
|
+
metadata={
|
|
231
|
+
"agent_id": input.agent_id,
|
|
232
|
+
"organization_id": input.organization_id,
|
|
233
|
+
"runtime_type": runtime_type.value,
|
|
234
|
+
"turn_count": len(complete_session),
|
|
235
|
+
},
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if success:
|
|
239
|
+
print(
|
|
240
|
+
f"✅ Session persisted ({len(complete_session)} total messages)\n"
|
|
241
|
+
)
|
|
242
|
+
else:
|
|
243
|
+
print(f"⚠️ Session persistence failed\n")
|
|
244
|
+
|
|
245
|
+
# STEP 8: Print usage metrics
|
|
246
|
+
if result.usage:
|
|
247
|
+
print(f"📊 Token Usage:")
|
|
248
|
+
print(f" Input: {result.usage.get('prompt_tokens', 0)}")
|
|
249
|
+
print(f" Output: {result.usage.get('completion_tokens', 0)}")
|
|
250
|
+
print(f" Total: {result.usage.get('total_tokens', 0)}\n")
|
|
251
|
+
|
|
252
|
+
print("=" * 80)
|
|
253
|
+
print("🏁 AGENT EXECUTION END")
|
|
254
|
+
print("=" * 80 + "\n")
|
|
255
|
+
|
|
256
|
+
# Return standardized result
|
|
257
|
+
return {
|
|
258
|
+
"success": result.success,
|
|
259
|
+
"response": result.response,
|
|
260
|
+
"usage": result.usage,
|
|
261
|
+
"model": result.model or input.model_id,
|
|
262
|
+
"finish_reason": result.finish_reason or "stop",
|
|
263
|
+
"run_id": result.run_id,
|
|
264
|
+
"tool_messages": result.tool_messages or [],
|
|
265
|
+
"runtime_type": runtime_type.value,
|
|
266
|
+
"error": result.error,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
except Exception as e:
|
|
270
|
+
print("\n" + "=" * 80)
|
|
271
|
+
print("❌ AGENT EXECUTION FAILED")
|
|
272
|
+
print("=" * 80)
|
|
273
|
+
print(f"Error: {str(e)}")
|
|
274
|
+
print("=" * 80 + "\n")
|
|
275
|
+
|
|
276
|
+
logger.error(
|
|
277
|
+
"agent_execution_failed", execution_id=execution_id[:8], error=str(e)
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
"success": False,
|
|
282
|
+
"error": str(e),
|
|
283
|
+
"model": input.model_id,
|
|
284
|
+
"usage": {},
|
|
285
|
+
"finish_reason": "error",
|
|
286
|
+
"runtime_type": runtime_type_str if "runtime_type_str" in locals() else "unknown",
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async def _execute_streaming(
|
|
290
|
+
self, runtime, context: RuntimeExecutionContext, input: Any
|
|
291
|
+
) -> Any:
|
|
292
|
+
"""
|
|
293
|
+
Execute with streaming and publish events to Control Plane.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
runtime: Runtime instance
|
|
297
|
+
context: Execution context
|
|
298
|
+
input: Original input for additional metadata
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
Final RuntimeExecutionResult
|
|
302
|
+
"""
|
|
303
|
+
# Create streaming helper for publishing events
|
|
304
|
+
streaming_helper = StreamingHelper(
|
|
305
|
+
control_plane_client=self.control_plane, execution_id=context.execution_id
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
accumulated_response = ""
|
|
309
|
+
final_result = None
|
|
310
|
+
|
|
311
|
+
# Define event callback for publishing to Control Plane
|
|
312
|
+
def event_callback(event: Dict):
|
|
313
|
+
"""Callback to publish events to Control Plane SSE"""
|
|
314
|
+
event_type = event.get("type")
|
|
315
|
+
|
|
316
|
+
if event_type == "content_chunk":
|
|
317
|
+
# Publish content chunk
|
|
318
|
+
streaming_helper.publish_content_chunk(
|
|
319
|
+
content=event.get("content", ""),
|
|
320
|
+
message_id=event.get("message_id", context.execution_id),
|
|
321
|
+
)
|
|
322
|
+
elif event_type == "tool_start":
|
|
323
|
+
# Publish tool start
|
|
324
|
+
streaming_helper.publish_tool_start(
|
|
325
|
+
tool_name=event.get("tool_name"),
|
|
326
|
+
tool_execution_id=event.get("tool_execution_id"),
|
|
327
|
+
tool_args=event.get("tool_args", {}),
|
|
328
|
+
source="agent",
|
|
329
|
+
)
|
|
330
|
+
elif event_type == "tool_complete":
|
|
331
|
+
# Publish tool completion
|
|
332
|
+
streaming_helper.publish_tool_complete(
|
|
333
|
+
tool_name=event.get("tool_name"),
|
|
334
|
+
tool_execution_id=event.get("tool_execution_id"),
|
|
335
|
+
status=event.get("status", "success"),
|
|
336
|
+
output=event.get("output"),
|
|
337
|
+
error=event.get("error"),
|
|
338
|
+
source="agent",
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
# Stream execution
|
|
342
|
+
async for chunk in runtime.stream_execute(context, event_callback):
|
|
343
|
+
if chunk.response:
|
|
344
|
+
accumulated_response += chunk.response
|
|
345
|
+
print(chunk.response, end="", flush=True)
|
|
346
|
+
|
|
347
|
+
# Keep final result for metadata
|
|
348
|
+
if chunk.usage or chunk.finish_reason:
|
|
349
|
+
final_result = chunk
|
|
350
|
+
|
|
351
|
+
print() # New line after streaming
|
|
352
|
+
|
|
353
|
+
# Return final result with accumulated response
|
|
354
|
+
if final_result:
|
|
355
|
+
# Update response with accumulated content
|
|
356
|
+
final_result.response = accumulated_response
|
|
357
|
+
return final_result
|
|
358
|
+
else:
|
|
359
|
+
# Create final result if not provided
|
|
360
|
+
from runtimes.base import RuntimeExecutionResult
|
|
361
|
+
|
|
362
|
+
return RuntimeExecutionResult(
|
|
363
|
+
response=accumulated_response,
|
|
364
|
+
usage={},
|
|
365
|
+
success=True,
|
|
366
|
+
finish_reason="stop",
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
def _get_framework_name(self, runtime_type: RuntimeType) -> str:
|
|
370
|
+
"""
|
|
371
|
+
Get friendly framework name for runtime type.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
runtime_type: Runtime type enum
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
Framework name string
|
|
378
|
+
"""
|
|
379
|
+
mapping = {
|
|
380
|
+
RuntimeType.DEFAULT: "Agno",
|
|
381
|
+
RuntimeType.CLAUDE_CODE: "Claude Code SDK",
|
|
382
|
+
}
|
|
383
|
+
return mapping.get(runtime_type, "Unknown")
|