agno 2.2.13__py3-none-any.whl → 2.4.3__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.
- agno/agent/__init__.py +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/workflow/types.py
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
import json
|
|
2
1
|
from dataclasses import dataclass
|
|
3
2
|
from enum import Enum
|
|
4
3
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
5
4
|
|
|
6
|
-
from fastapi import WebSocket
|
|
7
5
|
from pydantic import BaseModel
|
|
8
6
|
|
|
9
7
|
from agno.media import Audio, File, Image, Video
|
|
10
8
|
from agno.models.metrics import Metrics
|
|
11
9
|
from agno.session.workflow import WorkflowSession
|
|
12
|
-
from agno.utils.log import log_warning
|
|
13
10
|
from agno.utils.media import (
|
|
14
11
|
reconstruct_audio_list,
|
|
15
12
|
reconstruct_files,
|
|
16
13
|
reconstruct_images,
|
|
17
14
|
reconstruct_videos,
|
|
18
15
|
)
|
|
19
|
-
from agno.utils.serialize import json_serializer
|
|
20
16
|
from agno.utils.timer import Timer
|
|
21
17
|
|
|
22
18
|
|
|
@@ -107,10 +103,46 @@ class StepInput:
|
|
|
107
103
|
return str(self.input)
|
|
108
104
|
|
|
109
105
|
def get_step_output(self, step_name: str) -> Optional["StepOutput"]:
|
|
110
|
-
"""Get output from a specific previous step by name
|
|
106
|
+
"""Get output from a specific previous step by name
|
|
107
|
+
|
|
108
|
+
Searches recursively through nested steps (Parallel, Condition, Router, Loop, Steps)
|
|
109
|
+
to find step outputs at any depth.
|
|
110
|
+
"""
|
|
111
|
+
if not self.previous_step_outputs:
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
# First try direct lookup
|
|
115
|
+
direct = self.previous_step_outputs.get(step_name)
|
|
116
|
+
if direct:
|
|
117
|
+
return direct
|
|
118
|
+
|
|
119
|
+
# Search recursively in nested steps
|
|
120
|
+
return self._search_nested_steps(step_name)
|
|
121
|
+
|
|
122
|
+
def _search_nested_steps(self, step_name: str) -> Optional["StepOutput"]:
|
|
123
|
+
"""Recursively search for a step output in nested steps (Parallel, Condition, etc.)"""
|
|
111
124
|
if not self.previous_step_outputs:
|
|
112
125
|
return None
|
|
113
|
-
|
|
126
|
+
|
|
127
|
+
for step_output in self.previous_step_outputs.values():
|
|
128
|
+
result = self._search_in_step_output(step_output, step_name)
|
|
129
|
+
if result:
|
|
130
|
+
return result
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
def _search_in_step_output(self, step_output: "StepOutput", step_name: str) -> Optional["StepOutput"]:
|
|
134
|
+
"""Helper to recursively search within a single StepOutput"""
|
|
135
|
+
if not step_output.steps:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
for nested_step in step_output.steps:
|
|
139
|
+
if nested_step.step_name == step_name:
|
|
140
|
+
return nested_step
|
|
141
|
+
# Recursively search deeper
|
|
142
|
+
result = self._search_in_step_output(nested_step, step_name)
|
|
143
|
+
if result:
|
|
144
|
+
return result
|
|
145
|
+
return None
|
|
114
146
|
|
|
115
147
|
def get_step_content(self, step_name: str) -> Optional[Union[str, Dict[str, str]]]:
|
|
116
148
|
"""Get content from a specific previous step by name
|
|
@@ -209,7 +241,7 @@ class StepInput:
|
|
|
209
241
|
input_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
210
242
|
if self.input is not None:
|
|
211
243
|
if isinstance(self.input, BaseModel):
|
|
212
|
-
input_dict = self.input.model_dump(exclude_none=True)
|
|
244
|
+
input_dict = self.input.model_dump(exclude_none=True, mode="json")
|
|
213
245
|
elif isinstance(self.input, (dict, list)):
|
|
214
246
|
input_dict = self.input
|
|
215
247
|
else:
|
|
@@ -281,7 +313,7 @@ class StepOutput:
|
|
|
281
313
|
content_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
282
314
|
if self.content is not None:
|
|
283
315
|
if isinstance(self.content, BaseModel):
|
|
284
|
-
content_dict = self.content.model_dump(exclude_none=True)
|
|
316
|
+
content_dict = self.content.model_dump(exclude_none=True, mode="json")
|
|
285
317
|
elif isinstance(self.content, (dict, list)):
|
|
286
318
|
content_dict = self.content
|
|
287
319
|
else:
|
|
@@ -441,75 +473,6 @@ class WorkflowMetrics:
|
|
|
441
473
|
self.duration = self.timer.elapsed
|
|
442
474
|
|
|
443
475
|
|
|
444
|
-
@dataclass
|
|
445
|
-
class WebSocketHandler:
|
|
446
|
-
"""Generic WebSocket handler for real-time workflow events"""
|
|
447
|
-
|
|
448
|
-
websocket: Optional[WebSocket] = None
|
|
449
|
-
|
|
450
|
-
def format_sse_event(self, json_data: str) -> str:
|
|
451
|
-
"""Parse JSON data into SSE-compliant format.
|
|
452
|
-
|
|
453
|
-
Args:
|
|
454
|
-
json_data: JSON string containing the event data
|
|
455
|
-
|
|
456
|
-
Returns:
|
|
457
|
-
SSE-formatted response with event type and data
|
|
458
|
-
"""
|
|
459
|
-
import json
|
|
460
|
-
|
|
461
|
-
try:
|
|
462
|
-
# Parse the JSON to extract the event type
|
|
463
|
-
data = json.loads(json_data)
|
|
464
|
-
event_type = data.get("event", "message")
|
|
465
|
-
|
|
466
|
-
# Format as SSE: event: <event_type>\ndata: <json_data>\n\n
|
|
467
|
-
return f"event: {event_type}\ndata: {json_data}\n\n"
|
|
468
|
-
except (json.JSONDecodeError, KeyError):
|
|
469
|
-
# Fallback to generic message event if parsing fails
|
|
470
|
-
return f"event: message\ndata: {json_data}\n\n"
|
|
471
|
-
|
|
472
|
-
async def handle_event(self, event: Any) -> None:
|
|
473
|
-
"""Handle an event object - serializes and sends via WebSocket"""
|
|
474
|
-
if not self.websocket:
|
|
475
|
-
return
|
|
476
|
-
|
|
477
|
-
try:
|
|
478
|
-
if hasattr(event, "to_dict"):
|
|
479
|
-
data = event.to_dict()
|
|
480
|
-
elif hasattr(event, "__dict__"):
|
|
481
|
-
data = event.__dict__
|
|
482
|
-
elif isinstance(event, dict):
|
|
483
|
-
data = event
|
|
484
|
-
else:
|
|
485
|
-
data = {"type": "message", "content": str(event)}
|
|
486
|
-
|
|
487
|
-
await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
|
|
488
|
-
|
|
489
|
-
except Exception as e:
|
|
490
|
-
log_warning(f"Failed to handle WebSocket event: {e}")
|
|
491
|
-
|
|
492
|
-
async def handle_text(self, message: str) -> None:
|
|
493
|
-
"""Handle a plain text message"""
|
|
494
|
-
if not self.websocket:
|
|
495
|
-
return
|
|
496
|
-
|
|
497
|
-
try:
|
|
498
|
-
await self.websocket.send_text(self.format_sse_event(message))
|
|
499
|
-
except Exception as e:
|
|
500
|
-
log_warning(f"Failed to send WebSocket text: {e}")
|
|
501
|
-
|
|
502
|
-
async def handle_dict(self, data: Dict[str, Any]) -> None:
|
|
503
|
-
"""Handle a dictionary directly"""
|
|
504
|
-
if not self.websocket:
|
|
505
|
-
return
|
|
506
|
-
|
|
507
|
-
try:
|
|
508
|
-
await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
|
|
509
|
-
except Exception as e:
|
|
510
|
-
log_warning(f"Failed to send WebSocket dict: {e}")
|
|
511
|
-
|
|
512
|
-
|
|
513
476
|
class StepType(str, Enum):
|
|
514
477
|
FUNCTION = "Function"
|
|
515
478
|
STEP = "Step"
|