10xscale-agentflow-cli 0.1.8__tar.gz → 0.2.0__tar.gz
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.
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/PKG-INFO +2 -2
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/requires.txt +1 -1
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/PKG-INFO +2 -2
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/auth/jwt_auth.py +6 -1
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/exceptions/handle_errors.py +1 -15
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/loader.py +8 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/checkpointer/services/checkpointer_service.py +2 -1
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/graph/services/graph_service.py +62 -56
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/parse_output.py +4 -4
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/graph/react.py +0 -74
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/pyproject.toml +2 -2
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/tests/test_utils_parse_and_callable.py +2 -5
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/SOURCES.txt +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/dependency_links.txt +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/entry_points.txt +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/not-zip-safe +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/10xscale_agentflow_cli.egg-info/top_level.txt +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/MANIFEST.in +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/README.md +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/Task.md +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow.json +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/api.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/build.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/init.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/version.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/constants.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/config.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/output.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/validation.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/exceptions.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/logger.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/main.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/templates/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/templates/defaults.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/auth/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/auth/auth_backend.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/auth/base_auth.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/graph_config.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/sentry_config.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/settings.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/setup_logs.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/setup_middleware.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/config/worker_middleware.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/exceptions/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/exceptions/general_exception.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/exceptions/resources_exceptions.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/exceptions/user_exception.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/main.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/checkpointer/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/checkpointer/router.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/checkpointer/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/checkpointer/schemas/checkpointer_schemas.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/checkpointer/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/graph/router.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/graph/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/graph/schemas/graph_schemas.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/graph/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/ping/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/ping/router.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/setup_router.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/store/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/store/router.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/store/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/store/schemas/store_schemas.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/store/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/routers/store/services/store_service.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/tasks/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/tasks/user_tasks.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/callable_helper.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/response_helper.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/schemas/output_schemas.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/schemas/user_schemas.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/snowflake_id_generator.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/swagger_helper.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/utils/thread_name_generator.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/worker.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/graph/thread_name_generator.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/scripts/generate_docs.py +0 -0
- {10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: 10xscale-agentflow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: CLI and API for 10xscale AgentFlow
|
|
5
5
|
Author-email: 10xscale <contact@10xscale.ai>
|
|
6
6
|
Maintainer-email: Shudipto Trafder <shudiptotrafder@gmail.com>
|
|
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
21
21
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
22
22
|
Requires-Python: >=3.12
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
|
-
Requires-Dist: 10xscale-agentflow>=0.
|
|
24
|
+
Requires-Dist: 10xscale-agentflow>=0.5.0
|
|
25
25
|
Requires-Dist: fastapi
|
|
26
26
|
Requires-Dist: gunicorn
|
|
27
27
|
Requires-Dist: orjson
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: 10xscale-agentflow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: CLI and API for 10xscale AgentFlow
|
|
5
5
|
Author-email: 10xscale <contact@10xscale.ai>
|
|
6
6
|
Maintainer-email: Shudipto Trafder <shudiptotrafder@gmail.com>
|
|
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
21
21
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
22
22
|
Requires-Python: >=3.12
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
|
-
Requires-Dist: 10xscale-agentflow>=0.
|
|
24
|
+
Requires-Dist: 10xscale-agentflow>=0.5.0
|
|
25
25
|
Requires-Dist: fastapi
|
|
26
26
|
Requires-Dist: gunicorn
|
|
27
27
|
Requires-Dist: orjson
|
|
@@ -44,6 +44,11 @@ class JwtAuth(BaseAuth):
|
|
|
44
44
|
jwt_secret_key = os.environ.get("JWT_SECRET_KEY", None)
|
|
45
45
|
jwt_algorithm = os.environ.get("JWT_ALGORITHM", None)
|
|
46
46
|
|
|
47
|
+
# check bearer token then remove barer prefix
|
|
48
|
+
token = credential.credentials
|
|
49
|
+
if token.lower().startswith("bearer "):
|
|
50
|
+
token = token[7:]
|
|
51
|
+
|
|
47
52
|
if jwt_secret_key is None or jwt_algorithm is None:
|
|
48
53
|
raise UserAccountError(
|
|
49
54
|
message="JWT settings are not configured",
|
|
@@ -52,7 +57,7 @@ class JwtAuth(BaseAuth):
|
|
|
52
57
|
|
|
53
58
|
try:
|
|
54
59
|
decoded_token = jwt.decode(
|
|
55
|
-
|
|
60
|
+
token,
|
|
56
61
|
jwt_secret_key, # type: ignore
|
|
57
62
|
algorithms=[jwt_algorithm], # type: ignore
|
|
58
63
|
)
|
|
@@ -4,7 +4,6 @@ from agentflow.exceptions import (
|
|
|
4
4
|
GraphRecursionError,
|
|
5
5
|
MetricsError,
|
|
6
6
|
NodeError,
|
|
7
|
-
ResourceNotFoundError,
|
|
8
7
|
SchemaVersionError,
|
|
9
8
|
SerializationError,
|
|
10
9
|
StorageError,
|
|
@@ -40,7 +39,7 @@ def init_errors_handler(app: FastAPI):
|
|
|
40
39
|
ValueError: Handles value errors.
|
|
41
40
|
UserAccountError: Handles custom user account errors.
|
|
42
41
|
UserPermissionError: Handles custom user permission errors.
|
|
43
|
-
|
|
42
|
+
APIResourceNotFoundError: Handles custom API resource not found errors.
|
|
44
43
|
"""
|
|
45
44
|
|
|
46
45
|
@app.exception_handler(HTTPException)
|
|
@@ -208,16 +207,3 @@ def init_errors_handler(app: FastAPI):
|
|
|
208
207
|
details=getattr(exc, "context", None),
|
|
209
208
|
status_code=503,
|
|
210
209
|
)
|
|
211
|
-
|
|
212
|
-
@app.exception_handler(ResourceNotFoundError)
|
|
213
|
-
async def resource_not_found_storage_exception_handler(
|
|
214
|
-
request: Request, exc: ResourceNotFoundError
|
|
215
|
-
):
|
|
216
|
-
logger.error(f"ResourceNotFoundError: url: {request.base_url}", exc_info=exc)
|
|
217
|
-
return error_response(
|
|
218
|
-
request,
|
|
219
|
-
error_code=getattr(exc, "error_code", "RESOURCE_NOT_FOUND_000"),
|
|
220
|
-
message=getattr(exc, "message", str(exc)),
|
|
221
|
-
details=getattr(exc, "context", None),
|
|
222
|
-
status_code=404,
|
|
223
|
-
)
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/loader.py
RENAMED
|
@@ -202,6 +202,14 @@ async def attach_all_modules(
|
|
|
202
202
|
path,
|
|
203
203
|
)
|
|
204
204
|
container.bind_instance(BaseAuth, auth_backend)
|
|
205
|
+
elif method == "jwt":
|
|
206
|
+
from agentflow_cli.src.app.core.auth.jwt_auth import JwtAuth
|
|
207
|
+
|
|
208
|
+
jwt_auth = JwtAuth()
|
|
209
|
+
container.bind_instance(BaseAuth, jwt_auth)
|
|
210
|
+
|
|
211
|
+
elif method == "none":
|
|
212
|
+
container.bind_instance(BaseAuth, None, allow_none=True)
|
|
205
213
|
else:
|
|
206
214
|
# bind None
|
|
207
215
|
container.bind_instance(BaseAuth, None, allow_none=True)
|
|
@@ -174,7 +174,8 @@ class CheckpointerService:
|
|
|
174
174
|
base: dict[str, Any] = {}
|
|
175
175
|
if old_state is not None:
|
|
176
176
|
# Keep full dump so we can preserve existing fields
|
|
177
|
-
|
|
177
|
+
# Use serialize_as_any=True to include subclass fields
|
|
178
|
+
base = old_state.model_dump(serialize_as_any=True)
|
|
178
179
|
|
|
179
180
|
merged: dict[str, Any] = {**base}
|
|
180
181
|
|
|
@@ -247,7 +247,7 @@ class GraphService:
|
|
|
247
247
|
|
|
248
248
|
return GraphInvokeOutputSchema(
|
|
249
249
|
messages=messages,
|
|
250
|
-
state=raw_state.model_dump() if raw_state else None,
|
|
250
|
+
state=raw_state.model_dump(serialize_as_any=True) if raw_state else None,
|
|
251
251
|
context=context,
|
|
252
252
|
summary=context_summary,
|
|
253
253
|
meta=meta,
|
|
@@ -295,7 +295,7 @@ class GraphService:
|
|
|
295
295
|
mt = chunk.metadata or {}
|
|
296
296
|
mt.update(meta)
|
|
297
297
|
chunk.metadata = mt
|
|
298
|
-
yield chunk.model_dump_json()
|
|
298
|
+
yield chunk.model_dump_json(serialize_as_any=True)
|
|
299
299
|
if (
|
|
300
300
|
self.config.thread_name_generator_path
|
|
301
301
|
and meta["is_new_thread"]
|
|
@@ -308,7 +308,6 @@ class GraphService:
|
|
|
308
308
|
logger.info("Graph streaming completed successfully")
|
|
309
309
|
|
|
310
310
|
if meta["is_new_thread"] and self.config.thread_name_generator_path:
|
|
311
|
-
messages_str = [msg.text() for msg in messages_str]
|
|
312
311
|
thread_name = await self._save_thread_name(
|
|
313
312
|
config, config["thread_id"], messages_str
|
|
314
313
|
)
|
|
@@ -318,7 +317,7 @@ class GraphService:
|
|
|
318
317
|
event=StreamEvent.UPDATES,
|
|
319
318
|
data={"status": "completed"},
|
|
320
319
|
metadata=meta,
|
|
321
|
-
).model_dump_json()
|
|
320
|
+
).model_dump_json(serialize_as_any=True)
|
|
322
321
|
|
|
323
322
|
except Exception as e:
|
|
324
323
|
logger.error(f"Graph streaming failed: {e}")
|
|
@@ -344,6 +343,25 @@ class GraphService:
|
|
|
344
343
|
logger.error(f"Failed to get state schema: {e}")
|
|
345
344
|
raise HTTPException(status_code=500, detail=f"Failed to get state schema: {e!s}")
|
|
346
345
|
|
|
346
|
+
def _has_empty_tool_call(self, msg: Message) -> bool:
|
|
347
|
+
"""Return True if any tool call on the message has empty content.
|
|
348
|
+
|
|
349
|
+
A tool call is considered empty if its ``content`` attribute/key is ``None`` or
|
|
350
|
+
an empty string. Tool calls may be dict-like or objects with a ``content`` attribute.
|
|
351
|
+
"""
|
|
352
|
+
tool_calls = getattr(msg, "tools_calls", None)
|
|
353
|
+
if not tool_calls:
|
|
354
|
+
return False
|
|
355
|
+
for tool_call in tool_calls:
|
|
356
|
+
content = (
|
|
357
|
+
tool_call.get("content")
|
|
358
|
+
if isinstance(tool_call, dict)
|
|
359
|
+
else getattr(tool_call, "content", None)
|
|
360
|
+
)
|
|
361
|
+
if content in (None, ""):
|
|
362
|
+
return True
|
|
363
|
+
return False
|
|
364
|
+
|
|
347
365
|
async def fix_graph(
|
|
348
366
|
self,
|
|
349
367
|
thread_id: str,
|
|
@@ -372,66 +390,54 @@ class GraphService:
|
|
|
372
390
|
Raises:
|
|
373
391
|
HTTPException: If the operation fails
|
|
374
392
|
"""
|
|
393
|
+
try:
|
|
394
|
+
logger.info(f"Starting fix graph operation for thread: {thread_id}")
|
|
395
|
+
logger.debug(f"User info: {user}")
|
|
375
396
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
"
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
397
|
+
fix_config = {"thread_id": thread_id, "user": user}
|
|
398
|
+
if config:
|
|
399
|
+
fix_config.update(config)
|
|
400
|
+
|
|
401
|
+
logger.debug("Fetching current state from checkpointer")
|
|
402
|
+
state: AgentState | None = await self.checkpointer.aget_state(fix_config)
|
|
403
|
+
if not state:
|
|
404
|
+
logger.warning(f"No state found for thread: {thread_id}")
|
|
405
|
+
return {
|
|
406
|
+
"success": False,
|
|
407
|
+
"message": f"No state found for thread: {thread_id}",
|
|
408
|
+
"removed_count": 0,
|
|
409
|
+
"state": None,
|
|
410
|
+
}
|
|
390
411
|
|
|
391
|
-
|
|
392
|
-
logger.
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
412
|
+
messages: list[Message] = list(state.context or [])
|
|
413
|
+
logger.debug(f"Found {len(messages)} messages in state")
|
|
414
|
+
if not messages:
|
|
415
|
+
return {
|
|
416
|
+
"success": True,
|
|
417
|
+
"message": "No messages found in state",
|
|
418
|
+
"removed_count": 0,
|
|
419
|
+
"state": state.model_dump_json(serialize_as_any=True),
|
|
420
|
+
}
|
|
399
421
|
|
|
400
|
-
|
|
401
|
-
|
|
422
|
+
filtered = [m for m in messages if not self._has_empty_tool_call(m)]
|
|
423
|
+
removed_count = len(messages) - len(filtered)
|
|
402
424
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
"
|
|
407
|
-
|
|
408
|
-
"
|
|
409
|
-
"state": state.model_dump_json(),
|
|
410
|
-
}
|
|
425
|
+
if removed_count:
|
|
426
|
+
state.context = filtered
|
|
427
|
+
await self.checkpointer.aput_state(fix_config, state)
|
|
428
|
+
message = f"Successfully removed {removed_count} message(s)"
|
|
429
|
+
else:
|
|
430
|
+
message = "No messages with empty tool calls found"
|
|
411
431
|
|
|
412
|
-
last_message = messages[-1]
|
|
413
|
-
updated_context = []
|
|
414
|
-
if last_message.role == "assistant" and last_message.tools_calls:
|
|
415
|
-
updated_context = messages[:-1]
|
|
416
|
-
state.context = updated_context
|
|
417
|
-
await self.checkpointer.aput_state(fix_config, state)
|
|
418
432
|
return {
|
|
419
433
|
"success": True,
|
|
420
|
-
"message":
|
|
421
|
-
"removed_count":
|
|
422
|
-
"state": state.model_dump_json(),
|
|
434
|
+
"message": message,
|
|
435
|
+
"removed_count": removed_count,
|
|
436
|
+
"state": state.model_dump_json(serialize_as_any=True),
|
|
423
437
|
}
|
|
424
|
-
|
|
425
|
-
logger.
|
|
426
|
-
|
|
427
|
-
)
|
|
428
|
-
|
|
429
|
-
return {
|
|
430
|
-
"success": True,
|
|
431
|
-
"message": "No messages with empty tool calls found",
|
|
432
|
-
"removed_count": 0,
|
|
433
|
-
"state": state.model_dump_json(),
|
|
434
|
-
}
|
|
438
|
+
except Exception as e:
|
|
439
|
+
logger.error(f"Fix graph operation failed: {e}")
|
|
440
|
+
raise HTTPException(status_code=500, detail=f"Fix graph operation failed: {e!s}")
|
|
435
441
|
|
|
436
442
|
async def setup(self, data: GraphSetupSchema) -> dict:
|
|
437
443
|
# lets create tools
|
|
@@ -7,11 +7,11 @@ from agentflow_cli.src.app.core.config.settings import Settings
|
|
|
7
7
|
|
|
8
8
|
def parse_state_output(settings: Settings, response: BaseModel) -> dict[str, Any]:
|
|
9
9
|
# if settings.IS_DEBUG:
|
|
10
|
-
# return response.model_dump(exclude={"execution_meta"})
|
|
11
|
-
return response.model_dump()
|
|
10
|
+
# return response.model_dump(exclude={"execution_meta"}, serialize_as_any=True)
|
|
11
|
+
return response.model_dump(serialize_as_any=True)
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def parse_message_output(settings: Settings, response: BaseModel) -> dict[str, Any]:
|
|
15
15
|
# if settings.IS_DEBUG:
|
|
16
|
-
# return response.model_dump(exclude={"raw"})
|
|
17
|
-
return response.model_dump()
|
|
16
|
+
# return response.model_dump(exclude={"raw"}, serialize_as_any=True)
|
|
17
|
+
return response.model_dump(serialize_as_any=True)
|
|
@@ -1,37 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Graph-based React Agent Implementation
|
|
3
|
-
|
|
4
|
-
This module implements a reactive agent system using PyAgenity's StateGraph.
|
|
5
|
-
The agent can interact with tools (like weather checking) and maintain conversation
|
|
6
|
-
state through a checkpointer. The graph orchestrates the flow between the main
|
|
7
|
-
agent logic and tool execution.
|
|
8
|
-
|
|
9
|
-
Key Components:
|
|
10
|
-
- Weather tool: Demonstrates tool calling with dependency injection
|
|
11
|
-
- Main agent: AI-powered assistant that can use tools
|
|
12
|
-
- Graph flow: Conditional routing based on tool usage
|
|
13
|
-
- Checkpointer: Maintains conversation state across interactions
|
|
14
|
-
|
|
15
|
-
Architecture:
|
|
16
|
-
The system uses a state graph with two main nodes:
|
|
17
|
-
1. MAIN: Processes user input and generates AI responses
|
|
18
|
-
2. TOOL: Executes tool calls when requested by the AI
|
|
19
|
-
|
|
20
|
-
The graph conditionally routes between these nodes based on whether
|
|
21
|
-
the AI response contains tool calls. Conversation history is maintained
|
|
22
|
-
through the checkpointer, allowing for multi-turn conversations.
|
|
23
|
-
|
|
24
|
-
Tools are defined as functions with JSON schema docstrings that describe
|
|
25
|
-
their interface for the AI model. The ToolNode automatically extracts
|
|
26
|
-
these schemas for tool selection.
|
|
27
|
-
|
|
28
|
-
Dependencies:
|
|
29
|
-
- PyAgenity: For graph and state management
|
|
30
|
-
- LiteLLM: For AI model interactions
|
|
31
|
-
- InjectQ: For dependency injection
|
|
32
|
-
- Python logging: For debug and info messages
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
1
|
import logging
|
|
36
2
|
from typing import Any
|
|
37
3
|
|
|
@@ -70,46 +36,6 @@ class MyAgentState(AgentState):
|
|
|
70
36
|
checkpointer = InMemoryCheckpointer[MyAgentState]()
|
|
71
37
|
|
|
72
38
|
|
|
73
|
-
"""
|
|
74
|
-
Note: The docstring below will be used as the tool description and it will be
|
|
75
|
-
passed to the AI model for tool selection, so keep it relevant and concise.
|
|
76
|
-
This function will be converted to a tool with the following schema:
|
|
77
|
-
[
|
|
78
|
-
{
|
|
79
|
-
'type': 'function',
|
|
80
|
-
'function': {
|
|
81
|
-
'name': 'get_weather',
|
|
82
|
-
'description': 'Retrieve current weather information for a specified location.',
|
|
83
|
-
'parameters': {
|
|
84
|
-
'type': 'object',
|
|
85
|
-
'properties': {
|
|
86
|
-
'location': {'type': 'string'}
|
|
87
|
-
},
|
|
88
|
-
'required': ['location']
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
|
|
94
|
-
Parameters like tool_call_id, state, and checkpointer are injected automatically
|
|
95
|
-
by InjectQ when the tool is called by the agent.
|
|
96
|
-
Available injected parameters:
|
|
97
|
-
The following parameters are automatically injected by InjectQ when the tool is called,
|
|
98
|
-
but need to keep them as same name and type for proper injection:
|
|
99
|
-
- tool_call_id: Unique ID for the tool call
|
|
100
|
-
- state: Current AgentState containing conversation context
|
|
101
|
-
- config: Configuration dictionary passed during graph invocation
|
|
102
|
-
|
|
103
|
-
Below fields need to be used with Inject[] to get the instances:
|
|
104
|
-
- context_manager: ContextManager instance for managing context, like trimming
|
|
105
|
-
- publisher: Publisher instance for publishing events and logs
|
|
106
|
-
- checkpointer: InMemoryCheckpointer instance for state management
|
|
107
|
-
- store: InMemoryStore instance for temporary data storage
|
|
108
|
-
- callback: CallbackManager instance for handling callbacks
|
|
109
|
-
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
|
|
113
39
|
def get_weather(
|
|
114
40
|
location: str,
|
|
115
41
|
tool_call_id: str,
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "10xscale-agentflow-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "CLI and API for 10xscale AgentFlow"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -34,7 +34,7 @@ classifiers = [
|
|
|
34
34
|
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
35
35
|
]
|
|
36
36
|
dependencies = [
|
|
37
|
-
"10xscale-agentflow>=0.
|
|
37
|
+
"10xscale-agentflow>=0.5.0",
|
|
38
38
|
"fastapi",
|
|
39
39
|
"gunicorn",
|
|
40
40
|
"orjson",
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/tests/test_utils_parse_and_callable.py
RENAMED
|
@@ -28,9 +28,7 @@ def test_parse_state_output(is_debug: bool):
|
|
|
28
28
|
settings = Settings(IS_DEBUG=is_debug)
|
|
29
29
|
model = _StateModel(a=1, b="x", execution_meta={"duration": 123})
|
|
30
30
|
out = parse_state_output(settings, model)
|
|
31
|
-
#
|
|
32
|
-
# Since parse_state_output doesn't filter execution_meta (commented out),
|
|
33
|
-
# it should always be present regardless of debug mode
|
|
31
|
+
# Current implementation always includes execution_meta regardless of debug
|
|
34
32
|
assert out["execution_meta"] == {"duration": 123}
|
|
35
33
|
assert out["a"] == 1 and out["b"] == "x"
|
|
36
34
|
|
|
@@ -40,8 +38,7 @@ def test_parse_message_output(is_debug: bool):
|
|
|
40
38
|
settings = Settings(IS_DEBUG=is_debug)
|
|
41
39
|
model = _MessageModel(content="hello", raw={"tokens": 5})
|
|
42
40
|
out = parse_message_output(settings, model)
|
|
43
|
-
#
|
|
44
|
-
# it should always be present regardless of debug mode
|
|
41
|
+
# Current implementation always includes raw regardless of debug
|
|
45
42
|
assert out["raw"] == {"tokens": 5}
|
|
46
43
|
assert out["content"] == "hello"
|
|
47
44
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/__init__.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/api.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/build.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/init.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/commands/version.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/constants.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/__init__.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/config.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/output.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/core/validation.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/cli/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/__init__.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/agentflow_cli/src/app/worker.py
RENAMED
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.1.8 → 10xscale_agentflow_cli-0.2.0}/graph/thread_name_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|