10xscale-agentflow-cli 0.3.2__tar.gz → 0.3.2.2__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.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/PKG-INFO +2 -1
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/SOURCES.txt +30 -2
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/requires.txt +1 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/PKG-INFO +2 -1
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow.json +1 -1
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/commands/init.py +392 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/main.py +3 -11
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/dev/agentflow.json +6 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/dev/graph/agent.py +132 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/.pre-commot-config.yaml +50 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/agentflow.json +19 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/auth/agent_auth.py +19 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/evals/weather_agents.py +119 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/agent.py +45 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/nodes/__init__.py +5 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/nodes/main_node.py +27 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/nodes/tool_node.py +10 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/state.py +5 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod}/graph/thread_name_generator.py +1 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/tools/weather_tool.py +43 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/utils/__init__.py +0 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/utils/tool_decision.py +30 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/validators/__init__.py +0 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/validators/lifecyle.py +107 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/validators/manager.py +9 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/validators/validators.py +21 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/tests/__init__.py +0 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/tests/conftest.py +6 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/tests/test_agent_eval.py +88 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/tests/test_catalog_tools.py +47 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/tests/test_graph_nodes.py +57 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/SKILL.md +2 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/skills/agent-skills/references/stream-emitter.md +144 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/src/__init__.py +0 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/src/app/core/auth/__init__.py +0 -0
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/src/app/core/config/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/settings.py +1 -1
- 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/src/app/tasks/__init__.py +0 -0
- 10xscale_agentflow_cli-0.3.2.2/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/pyproject.toml +9 -2
- 10xscale_agentflow_cli-0.3.2/agentflow_cli/cli/commands/init.py +0 -129
- 10xscale_agentflow_cli-0.3.2/scripts/generate_docs.py +0 -21
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/dependency_links.txt +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/entry_points.txt +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/not-zip-safe +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/10xscale_agentflow_cli.egg-info/top_level.txt +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/MANIFEST.in +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/README.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/commands/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/commands/api.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/commands/build.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/commands/skills.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/commands/version.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/constants.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/core/config.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/core/output.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/core/validation.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/exceptions.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/logger.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/defaults.py +0 -0
- {10xscale_agentflow_cli-0.3.2/agentflow_cli/src → 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/dev/graph}/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2/agentflow_cli/src/app/core → 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod}/auth/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2/agentflow_cli/src/app/core/config → 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/evals}/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2/agentflow_cli/src/app/tasks → 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph}/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2/graph → 10xscale_agentflow_cli-0.3.2.2/agentflow_cli/cli/templates/prod/graph/tools}/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/agents-and-tools.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/api-client.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/api-configuration.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/api-settings-and-middleware.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/architecture.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/auth-and-authorization.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/callbacks-and-command.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/checkpointing-and-threads.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/cli-commands.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/client-auth-and-errors.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/client-messages-invoke-stream.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/client-threads-memory-files.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/context-id-background.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/dependency-injection.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/id-and-thread-name-generators.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/media-and-files.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/memory-and-store.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/prebuilt-agents-and-tools.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/production-runtime.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/providers-and-adapters.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/publishers-and-runtime-protocols.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/rate-limiting.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/remote-tools.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/rest-api-and-errors.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/security-and-validators.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/state-and-messages.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/state-graph.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/streaming.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/agent-skills/references/testing-and-evaluation.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/cli/templates/skills/copilot/agentflow.instructions.md +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/auth/auth_backend.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/auth/authorization.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/auth/base_auth.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/auth/jwt_auth.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/auth/permissions.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/graph_config.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/media_settings.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/sentry_config.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/setup_logs.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/setup_middleware.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/config/worker_middleware.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/exceptions/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/exceptions/general_exception.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/exceptions/handle_errors.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/exceptions/resources_exceptions.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/exceptions/user_exception.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/rate_limit/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/rate_limit/base.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/rate_limit/factory.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/rate_limit/memory.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/rate_limit/middleware.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/rate_limit/redis.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/request_limits.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/middleware/security_headers.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/utils/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/core/utils/log_sanitizer.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/loader.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/main.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/a2a.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/a2ui.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/checkpointer/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/checkpointer/router.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/checkpointer/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/checkpointer/schemas/checkpointer_schemas.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/checkpointer/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/checkpointer/services/checkpointer_service.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/router.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/schemas/graph_schemas.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/services/graph_service.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/graph/services/multimodal_preprocessor.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/media/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/media/router.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/media/schemas.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/ping/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/ping/router.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/setup_router.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/store/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/store/router.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/store/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/store/schemas/store_schemas.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/store/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/routers/store/services/store_service.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/tasks/user_tasks.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/callable_helper.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/media/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/media/extractor.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/media/pipeline.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/parse_output.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/response_helper.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/schemas/output_schemas.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/schemas/user_schemas.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/snowflake_id_generator.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/swagger_helper.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/utils/thread_name_generator.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/agentflow_cli/src/app/worker.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/graph/react.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/requirements.txt +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/setup.cfg +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/tests/test_multimodal_sprint2_extraction.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/tests/test_sprint4_media_api.py +0 -0
- {10xscale_agentflow_cli-0.3.2 → 10xscale_agentflow_cli-0.3.2.2}/tests/test_utils_parse_and_callable.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: 10xscale-agentflow-cli
|
|
3
|
-
Version: 0.3.2
|
|
3
|
+
Version: 0.3.2.2
|
|
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>
|
|
@@ -31,6 +31,7 @@ Requires-Dist: pydantic-settings
|
|
|
31
31
|
Requires-Dist: uvicorn
|
|
32
32
|
Requires-Dist: typer
|
|
33
33
|
Requires-Dist: python-dotenv
|
|
34
|
+
Requires-Dist: questionary
|
|
34
35
|
Provides-Extra: sentry
|
|
35
36
|
Requires-Dist: sentry-sdk>=2.10.0; extra == "sentry"
|
|
36
37
|
Provides-Extra: firebase
|
|
@@ -28,6 +28,35 @@ agentflow_cli/cli/core/output.py
|
|
|
28
28
|
agentflow_cli/cli/core/validation.py
|
|
29
29
|
agentflow_cli/cli/templates/__init__.py
|
|
30
30
|
agentflow_cli/cli/templates/defaults.py
|
|
31
|
+
agentflow_cli/cli/templates/dev/agentflow.json
|
|
32
|
+
agentflow_cli/cli/templates/dev/graph/__init__.py
|
|
33
|
+
agentflow_cli/cli/templates/dev/graph/agent.py
|
|
34
|
+
agentflow_cli/cli/templates/prod/.pre-commot-config.yaml
|
|
35
|
+
agentflow_cli/cli/templates/prod/agentflow.json
|
|
36
|
+
agentflow_cli/cli/templates/prod/auth/__init__.py
|
|
37
|
+
agentflow_cli/cli/templates/prod/auth/agent_auth.py
|
|
38
|
+
agentflow_cli/cli/templates/prod/evals/__init__.py
|
|
39
|
+
agentflow_cli/cli/templates/prod/evals/weather_agents.py
|
|
40
|
+
agentflow_cli/cli/templates/prod/graph/__init__.py
|
|
41
|
+
agentflow_cli/cli/templates/prod/graph/agent.py
|
|
42
|
+
agentflow_cli/cli/templates/prod/graph/state.py
|
|
43
|
+
agentflow_cli/cli/templates/prod/graph/thread_name_generator.py
|
|
44
|
+
agentflow_cli/cli/templates/prod/graph/nodes/__init__.py
|
|
45
|
+
agentflow_cli/cli/templates/prod/graph/nodes/main_node.py
|
|
46
|
+
agentflow_cli/cli/templates/prod/graph/nodes/tool_node.py
|
|
47
|
+
agentflow_cli/cli/templates/prod/graph/tools/__init__.py
|
|
48
|
+
agentflow_cli/cli/templates/prod/graph/tools/weather_tool.py
|
|
49
|
+
agentflow_cli/cli/templates/prod/graph/utils/__init__.py
|
|
50
|
+
agentflow_cli/cli/templates/prod/graph/utils/tool_decision.py
|
|
51
|
+
agentflow_cli/cli/templates/prod/graph/validators/__init__.py
|
|
52
|
+
agentflow_cli/cli/templates/prod/graph/validators/lifecyle.py
|
|
53
|
+
agentflow_cli/cli/templates/prod/graph/validators/manager.py
|
|
54
|
+
agentflow_cli/cli/templates/prod/graph/validators/validators.py
|
|
55
|
+
agentflow_cli/cli/templates/prod/tests/__init__.py
|
|
56
|
+
agentflow_cli/cli/templates/prod/tests/conftest.py
|
|
57
|
+
agentflow_cli/cli/templates/prod/tests/test_agent_eval.py
|
|
58
|
+
agentflow_cli/cli/templates/prod/tests/test_catalog_tools.py
|
|
59
|
+
agentflow_cli/cli/templates/prod/tests/test_graph_nodes.py
|
|
31
60
|
agentflow_cli/cli/templates/skills/agent-skills/SKILL.md
|
|
32
61
|
agentflow_cli/cli/templates/skills/agent-skills/references/agents-and-tools.md
|
|
33
62
|
agentflow_cli/cli/templates/skills/agent-skills/references/api-client.md
|
|
@@ -56,6 +85,7 @@ agentflow_cli/cli/templates/skills/agent-skills/references/rest-api-and-errors.m
|
|
|
56
85
|
agentflow_cli/cli/templates/skills/agent-skills/references/security-and-validators.md
|
|
57
86
|
agentflow_cli/cli/templates/skills/agent-skills/references/state-and-messages.md
|
|
58
87
|
agentflow_cli/cli/templates/skills/agent-skills/references/state-graph.md
|
|
88
|
+
agentflow_cli/cli/templates/skills/agent-skills/references/stream-emitter.md
|
|
59
89
|
agentflow_cli/cli/templates/skills/agent-skills/references/streaming.md
|
|
60
90
|
agentflow_cli/cli/templates/skills/agent-skills/references/testing-and-evaluation.md
|
|
61
91
|
agentflow_cli/cli/templates/skills/copilot/agentflow.instructions.md
|
|
@@ -140,8 +170,6 @@ agentflow_cli/src/app/utils/schemas/output_schemas.py
|
|
|
140
170
|
agentflow_cli/src/app/utils/schemas/user_schemas.py
|
|
141
171
|
graph/__init__.py
|
|
142
172
|
graph/react.py
|
|
143
|
-
graph/thread_name_generator.py
|
|
144
|
-
scripts/generate_docs.py
|
|
145
173
|
tests/test_multimodal_sprint2_extraction.py
|
|
146
174
|
tests/test_sprint4_media_api.py
|
|
147
175
|
tests/test_utils_parse_and_callable.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: 10xscale-agentflow-cli
|
|
3
|
-
Version: 0.3.2
|
|
3
|
+
Version: 0.3.2.2
|
|
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>
|
|
@@ -31,6 +31,7 @@ Requires-Dist: pydantic-settings
|
|
|
31
31
|
Requires-Dist: uvicorn
|
|
32
32
|
Requires-Dist: typer
|
|
33
33
|
Requires-Dist: python-dotenv
|
|
34
|
+
Requires-Dist: questionary
|
|
34
35
|
Provides-Extra: sentry
|
|
35
36
|
Requires-Dist: sentry-sdk>=2.10.0; extra == "sentry"
|
|
36
37
|
Provides-Extra: firebase
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"""Init command implementation."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import json
|
|
5
|
+
import re
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from string import Template
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import questionary
|
|
11
|
+
import typer
|
|
12
|
+
|
|
13
|
+
from agentflow_cli.cli.commands import BaseCommand
|
|
14
|
+
from agentflow_cli.cli.constants import Colors
|
|
15
|
+
from agentflow_cli.cli.exceptions import FileOperationError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_TEMPLATES_DIR = Path(__file__).parent.parent / "templates"
|
|
19
|
+
_SKIP_DIRS = {"__pycache__"}
|
|
20
|
+
_DIVIDER = Colors.colorize(" " + "─" * 46, "cyan")
|
|
21
|
+
|
|
22
|
+
# Directories inside prod/ that are only included based on user choices
|
|
23
|
+
_AUTH_DIR = "auth"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _dim(text: str) -> str:
|
|
27
|
+
return f"\033[2m{text}\033[0m"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _bold(text: str) -> str:
|
|
31
|
+
return f"\033[1m{text}\033[0m"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _slugify(name: str) -> str:
|
|
35
|
+
"""Convert 'WeatherBot' → 'weather-bot'."""
|
|
36
|
+
s = re.sub(r"([A-Z])", r"-\1", name).lstrip("-").lower()
|
|
37
|
+
s = re.sub(r"[^a-z0-9]+", "-", s)
|
|
38
|
+
return s.strip("-")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _strip_env_blocks(content: str, *, keep_redis: bool, keep_jwt: bool) -> str:
|
|
42
|
+
"""Remove conditional marker blocks that are not needed."""
|
|
43
|
+
if not keep_redis:
|
|
44
|
+
content = re.sub(r"##\[IF_REDIS\]##.*?##\[/IF_REDIS\]##\n?", "", content, flags=re.DOTALL)
|
|
45
|
+
else:
|
|
46
|
+
content = re.sub(r"##\[IF_REDIS\]##\n?", "", content)
|
|
47
|
+
content = re.sub(r"##\[/IF_REDIS\]##\n?", "", content)
|
|
48
|
+
|
|
49
|
+
if not keep_jwt:
|
|
50
|
+
content = re.sub(r"##\[IF_JWT\]##.*?##\[/IF_JWT\]##\n?", "", content, flags=re.DOTALL)
|
|
51
|
+
else:
|
|
52
|
+
content = re.sub(r"##\[IF_JWT\]##\n?", "", content)
|
|
53
|
+
content = re.sub(r"##\[/IF_JWT\]##\n?", "", content)
|
|
54
|
+
|
|
55
|
+
return content
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class InitCommand(BaseCommand):
|
|
59
|
+
"""Command to initialize a new agent project interactively."""
|
|
60
|
+
|
|
61
|
+
def execute(self, path: str = ".", force: bool = False, **kwargs: Any) -> int:
|
|
62
|
+
try:
|
|
63
|
+
self.output.print_banner(
|
|
64
|
+
"Init", "Create a new AgentFlow agent project", color="magenta"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
context = self._prompt_user()
|
|
68
|
+
if context is None:
|
|
69
|
+
typer.echo("\n Cancelled.")
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
self._print_summary(context)
|
|
73
|
+
|
|
74
|
+
base_path = Path(path)
|
|
75
|
+
base_path.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
|
|
77
|
+
is_prod = context["setup_type"] == "production"
|
|
78
|
+
template_dir = _TEMPLATES_DIR / ("prod" if is_prod else "dev")
|
|
79
|
+
|
|
80
|
+
typer.echo(f"\n {_bold('Creating project files...')}\n")
|
|
81
|
+
created = self._copy_template_dir(
|
|
82
|
+
template_dir, base_path, context, force=force, is_prod=is_prod
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Regenerate agentflow.json from the built config (overrides template copy)
|
|
86
|
+
config_path = base_path / "agentflow.json"
|
|
87
|
+
config = self._build_config(context, is_prod)
|
|
88
|
+
self._write_file(config_path, json.dumps(config, indent=2) + "\n", force=True)
|
|
89
|
+
if config_path not in created:
|
|
90
|
+
self._print_file_line(config_path, base_path)
|
|
91
|
+
|
|
92
|
+
agent_name = context["agent_name"]
|
|
93
|
+
typer.echo("")
|
|
94
|
+
typer.echo(_DIVIDER)
|
|
95
|
+
typer.echo(
|
|
96
|
+
" ✨ "
|
|
97
|
+
+ Colors.colorize(f'Project "{agent_name}" ready at ', "green")
|
|
98
|
+
+ Colors.colorize(str(base_path.resolve()), "cyan")
|
|
99
|
+
)
|
|
100
|
+
typer.echo(_DIVIDER)
|
|
101
|
+
|
|
102
|
+
self._print_next_steps(context, is_prod)
|
|
103
|
+
|
|
104
|
+
return 0
|
|
105
|
+
|
|
106
|
+
except FileOperationError as e:
|
|
107
|
+
return self.handle_error(e)
|
|
108
|
+
except Exception as e:
|
|
109
|
+
return self.handle_error(FileOperationError(f"Failed to initialize project: {e}"))
|
|
110
|
+
|
|
111
|
+
# ------------------------------------------------------------------
|
|
112
|
+
# Prompts
|
|
113
|
+
# ------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
def _prompt_user(self) -> dict | None: # noqa: PLR0911
|
|
116
|
+
agent_name = questionary.text(
|
|
117
|
+
"What is your agent name?",
|
|
118
|
+
default="MyAgent",
|
|
119
|
+
).ask()
|
|
120
|
+
if agent_name is None:
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
setup_choice = questionary.select(
|
|
124
|
+
"Quick Start or Production setup?",
|
|
125
|
+
choices=["Quick Start", "Production"],
|
|
126
|
+
default="Quick Start",
|
|
127
|
+
).ask()
|
|
128
|
+
if setup_choice is None:
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
is_prod = setup_choice == "Production"
|
|
132
|
+
|
|
133
|
+
context: dict[str, Any] = {
|
|
134
|
+
"agent_name": agent_name,
|
|
135
|
+
"agent_name_slug": _slugify(agent_name),
|
|
136
|
+
"setup_type": "production" if is_prod else "quick_start",
|
|
137
|
+
"auth": "none",
|
|
138
|
+
"rate_limit": "none",
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if not is_prod:
|
|
142
|
+
return context
|
|
143
|
+
|
|
144
|
+
# --- Production questions ---
|
|
145
|
+
|
|
146
|
+
auth_choice = questionary.select(
|
|
147
|
+
"Authentication type?",
|
|
148
|
+
choices=["None", "JWT", "Custom"],
|
|
149
|
+
default="None",
|
|
150
|
+
).ask()
|
|
151
|
+
if auth_choice is None:
|
|
152
|
+
return None
|
|
153
|
+
context["auth"] = auth_choice.lower()
|
|
154
|
+
|
|
155
|
+
rl_choice = questionary.select(
|
|
156
|
+
"Rate limiting?",
|
|
157
|
+
choices=["None", "Memory Based", "Redis Based"],
|
|
158
|
+
default="None",
|
|
159
|
+
).ask()
|
|
160
|
+
if rl_choice is None:
|
|
161
|
+
return None
|
|
162
|
+
context["rate_limit"] = {
|
|
163
|
+
"None": "none",
|
|
164
|
+
"Memory Based": "memory",
|
|
165
|
+
"Redis Based": "redis",
|
|
166
|
+
}[rl_choice]
|
|
167
|
+
|
|
168
|
+
if context["rate_limit"] != "none":
|
|
169
|
+
rl_requests = questionary.text(
|
|
170
|
+
"Max requests per window?",
|
|
171
|
+
default="100",
|
|
172
|
+
validate=lambda v: v.isdigit() and int(v) > 0 or "Enter a positive integer",
|
|
173
|
+
).ask()
|
|
174
|
+
if rl_requests is None:
|
|
175
|
+
return None
|
|
176
|
+
context["rl_requests"] = int(rl_requests)
|
|
177
|
+
|
|
178
|
+
rl_window = questionary.text(
|
|
179
|
+
"Window size (seconds)?",
|
|
180
|
+
default="60",
|
|
181
|
+
validate=lambda v: v.isdigit() and int(v) > 0 or "Enter a positive integer",
|
|
182
|
+
).ask()
|
|
183
|
+
if rl_window is None:
|
|
184
|
+
return None
|
|
185
|
+
context["rl_window"] = int(rl_window)
|
|
186
|
+
|
|
187
|
+
rl_by = questionary.select(
|
|
188
|
+
"Limit by?",
|
|
189
|
+
choices=["Per IP (recommended)", "Global"],
|
|
190
|
+
default="Per IP (recommended)",
|
|
191
|
+
).ask()
|
|
192
|
+
if rl_by is None:
|
|
193
|
+
return None
|
|
194
|
+
context["rl_by"] = "ip" if "IP" in rl_by else "global"
|
|
195
|
+
|
|
196
|
+
rl_proxy = questionary.confirm(
|
|
197
|
+
"Behind a reverse proxy? (reads real IP from forwarded headers)",
|
|
198
|
+
default=False,
|
|
199
|
+
).ask()
|
|
200
|
+
if rl_proxy is None:
|
|
201
|
+
return None
|
|
202
|
+
context["rl_trusted_proxy"] = rl_proxy
|
|
203
|
+
|
|
204
|
+
return context
|
|
205
|
+
|
|
206
|
+
# ------------------------------------------------------------------
|
|
207
|
+
# Output helpers
|
|
208
|
+
# ------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
def _print_summary(self, context: dict) -> None:
|
|
211
|
+
is_prod = context["setup_type"] == "production"
|
|
212
|
+
setup_label = "Production" if is_prod else "Quick Start"
|
|
213
|
+
|
|
214
|
+
typer.echo("")
|
|
215
|
+
typer.echo(_DIVIDER)
|
|
216
|
+
typer.echo(" " + _bold("Project Summary"))
|
|
217
|
+
typer.echo(_DIVIDER)
|
|
218
|
+
|
|
219
|
+
rows: list[tuple[str, str]] = [
|
|
220
|
+
("Agent name", context["agent_name"]),
|
|
221
|
+
("Package name", context["agent_name_slug"]),
|
|
222
|
+
("Setup", setup_label),
|
|
223
|
+
]
|
|
224
|
+
if is_prod:
|
|
225
|
+
auth = context["auth"]
|
|
226
|
+
rows.append(("Auth", "None" if auth == "none" else auth.upper()))
|
|
227
|
+
|
|
228
|
+
rl = context["rate_limit"]
|
|
229
|
+
if rl == "none":
|
|
230
|
+
rows.append(("Rate limit", "None"))
|
|
231
|
+
else:
|
|
232
|
+
rl_by = "Global" if context.get("rl_by") == "global" else "Per IP"
|
|
233
|
+
proxy = " · proxy headers on" if context.get("rl_trusted_proxy") else ""
|
|
234
|
+
rows.append(
|
|
235
|
+
(
|
|
236
|
+
"Rate limit",
|
|
237
|
+
f"{rl.capitalize()} · {context.get('rl_requests', 100)} req / "
|
|
238
|
+
f"{context.get('rl_window', 60)}s · {rl_by}{proxy}",
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
label_width = max(len(k) for k, _ in rows) + 2
|
|
243
|
+
for label, value in rows:
|
|
244
|
+
padded = (label + " ").ljust(label_width, "·")
|
|
245
|
+
typer.echo(
|
|
246
|
+
" " + Colors.colorize(padded, "cyan") + " " + Colors.colorize(value, "white")
|
|
247
|
+
)
|
|
248
|
+
typer.echo(_DIVIDER)
|
|
249
|
+
|
|
250
|
+
def _print_file_line(self, dest: Path, base_path: Path) -> None:
|
|
251
|
+
rel = dest.relative_to(base_path)
|
|
252
|
+
typer.echo(
|
|
253
|
+
" " + Colors.colorize("✓", "green") + " " + Colors.colorize(str(rel), "white")
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def _print_next_steps(self, context: dict, is_prod: bool) -> None:
|
|
257
|
+
steps: list[tuple[str, str]] = []
|
|
258
|
+
|
|
259
|
+
steps.append(("agentflow skills", "Install coding agent skills"))
|
|
260
|
+
|
|
261
|
+
if is_prod:
|
|
262
|
+
steps.append(("pre-commit install", "Set up Git hooks (ruff, bandit, etc.)"))
|
|
263
|
+
|
|
264
|
+
steps.append(("pip install google-genai", "Add the AI provider library"))
|
|
265
|
+
steps.append(("cp .env.example .env", "Copy env template, then fill in your API keys"))
|
|
266
|
+
|
|
267
|
+
if context["auth"] == "jwt":
|
|
268
|
+
steps.append(("# Set JWT_SECRET_KEY in .env", "Required for JWT auth to work"))
|
|
269
|
+
|
|
270
|
+
if context["rate_limit"] == "redis":
|
|
271
|
+
steps.append(("# Set REDIS_URL in .env", "Required for Redis rate limiting"))
|
|
272
|
+
|
|
273
|
+
steps.append(("agentflow play", "Launch your agent"))
|
|
274
|
+
|
|
275
|
+
typer.echo("")
|
|
276
|
+
typer.echo(" " + Colors.colorize("🚀 Next steps", "magenta"))
|
|
277
|
+
typer.echo("")
|
|
278
|
+
|
|
279
|
+
cmd_width = max(len(cmd) for cmd, _ in steps) + 2
|
|
280
|
+
for i, (cmd, description) in enumerate(steps, 1):
|
|
281
|
+
num = Colors.colorize(f" {i}", "cyan")
|
|
282
|
+
command = Colors.colorize(cmd.ljust(cmd_width), "yellow")
|
|
283
|
+
desc = _dim(description)
|
|
284
|
+
typer.echo(f"{num} {command} {desc}")
|
|
285
|
+
|
|
286
|
+
typer.echo("")
|
|
287
|
+
|
|
288
|
+
# ------------------------------------------------------------------
|
|
289
|
+
# Config generation
|
|
290
|
+
# ------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
def _build_config(self, context: dict, is_prod: bool) -> dict:
|
|
293
|
+
config: dict = {
|
|
294
|
+
"agent": "graph.agent:app",
|
|
295
|
+
"env": ".env",
|
|
296
|
+
"auth": None,
|
|
297
|
+
"thread_name_generator": None,
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if not is_prod:
|
|
301
|
+
return config
|
|
302
|
+
|
|
303
|
+
auth = context["auth"]
|
|
304
|
+
if auth == "jwt":
|
|
305
|
+
config["auth"] = {"method": "jwt"}
|
|
306
|
+
elif auth == "custom":
|
|
307
|
+
config["auth"] = {"method": "custom", "path": "auth.agent_auth:AgentAuth"}
|
|
308
|
+
|
|
309
|
+
config["thread_name_generator"] = "graph.thread_name_generator:MyNameGenerator"
|
|
310
|
+
config["injectq"] = "graph.agent:container"
|
|
311
|
+
|
|
312
|
+
rate_limit = context["rate_limit"]
|
|
313
|
+
if rate_limit != "none":
|
|
314
|
+
config["rate_limit"] = {
|
|
315
|
+
"enabled": True,
|
|
316
|
+
"backend": rate_limit,
|
|
317
|
+
"requests": context.get("rl_requests", 100),
|
|
318
|
+
"window": context.get("rl_window", 60),
|
|
319
|
+
"by": context.get("rl_by", "ip"),
|
|
320
|
+
"trusted_proxy_headers": context.get("rl_trusted_proxy", False),
|
|
321
|
+
"exclude_paths": ["/health", "/docs", "/redoc", "/openapi.json"],
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return config
|
|
325
|
+
|
|
326
|
+
# ------------------------------------------------------------------
|
|
327
|
+
# File helpers
|
|
328
|
+
# ------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
def _should_skip(self, src: Path, template_dir: Path, context: dict, is_prod: bool) -> bool:
|
|
331
|
+
"""Return True if this template file should not be copied."""
|
|
332
|
+
if any(part in _SKIP_DIRS for part in src.parts):
|
|
333
|
+
return True
|
|
334
|
+
if not is_prod:
|
|
335
|
+
return False
|
|
336
|
+
# auth/ is only included for custom auth; skip for none and jwt
|
|
337
|
+
rel_parts = src.relative_to(template_dir).parts
|
|
338
|
+
return rel_parts[0] == _AUTH_DIR and context["auth"] != "custom"
|
|
339
|
+
|
|
340
|
+
def _render(self, src: Path, context: dict, is_prod: bool) -> str:
|
|
341
|
+
content = src.read_text(encoding="utf-8")
|
|
342
|
+
|
|
343
|
+
# Strip conditional blocks in .env.example before substitution
|
|
344
|
+
if src.name == ".env.example" and is_prod:
|
|
345
|
+
content = _strip_env_blocks(
|
|
346
|
+
content,
|
|
347
|
+
keep_redis=context["rate_limit"] == "redis",
|
|
348
|
+
keep_jwt=context["auth"] == "jwt",
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
with contextlib.suppress(Exception):
|
|
352
|
+
content = Template(content).safe_substitute(context)
|
|
353
|
+
|
|
354
|
+
return content
|
|
355
|
+
|
|
356
|
+
def _copy_template_dir(
|
|
357
|
+
self,
|
|
358
|
+
template_dir: Path,
|
|
359
|
+
dest_dir: Path,
|
|
360
|
+
context: dict,
|
|
361
|
+
*,
|
|
362
|
+
force: bool,
|
|
363
|
+
is_prod: bool,
|
|
364
|
+
) -> set[Path]:
|
|
365
|
+
created: set[Path] = set()
|
|
366
|
+
for src in sorted(template_dir.rglob("*")):
|
|
367
|
+
if src.is_dir():
|
|
368
|
+
continue
|
|
369
|
+
if self._should_skip(src, template_dir, context, is_prod):
|
|
370
|
+
continue
|
|
371
|
+
rel = src.relative_to(template_dir)
|
|
372
|
+
dest = dest_dir / rel
|
|
373
|
+
content = self._render(src, context, is_prod)
|
|
374
|
+
self._write_file(dest, content, force=force)
|
|
375
|
+
self._print_file_line(dest, dest_dir)
|
|
376
|
+
created.add(dest)
|
|
377
|
+
return created
|
|
378
|
+
|
|
379
|
+
def _write_file(self, path: Path, content: str, *, force: bool) -> None:
|
|
380
|
+
try:
|
|
381
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
382
|
+
if path.exists() and not force:
|
|
383
|
+
raise FileOperationError(
|
|
384
|
+
f"File already exists: {path}. Use --force to overwrite.",
|
|
385
|
+
file_path=str(path),
|
|
386
|
+
)
|
|
387
|
+
path.write_text(content, encoding="utf-8")
|
|
388
|
+
self.logger.debug("Wrote file: %s", path)
|
|
389
|
+
except OSError as e:
|
|
390
|
+
raise FileOperationError(
|
|
391
|
+
f"Failed to write file {path}: {e}", file_path=str(path)
|
|
392
|
+
) from e
|
|
@@ -202,7 +202,7 @@ def init(
|
|
|
202
202
|
".",
|
|
203
203
|
"--path",
|
|
204
204
|
"-p",
|
|
205
|
-
help="Directory to initialize
|
|
205
|
+
help="Directory to initialize the agent project in",
|
|
206
206
|
),
|
|
207
207
|
force: bool = typer.Option(
|
|
208
208
|
False,
|
|
@@ -210,13 +210,6 @@ def init(
|
|
|
210
210
|
"-f",
|
|
211
211
|
help="Overwrite existing files if they exist",
|
|
212
212
|
),
|
|
213
|
-
prod: bool = typer.Option(
|
|
214
|
-
False,
|
|
215
|
-
"--prod",
|
|
216
|
-
help=(
|
|
217
|
-
"Initialize production-ready project (adds pyproject.toml and .pre-commit-config.yaml)"
|
|
218
|
-
),
|
|
219
|
-
),
|
|
220
213
|
verbose: bool = typer.Option(
|
|
221
214
|
False,
|
|
222
215
|
"--verbose",
|
|
@@ -230,13 +223,12 @@ def init(
|
|
|
230
223
|
help="Suppress all output except errors",
|
|
231
224
|
),
|
|
232
225
|
) -> None:
|
|
233
|
-
"""
|
|
234
|
-
# Setup logging
|
|
226
|
+
"""Interactively initialize a new agent project."""
|
|
235
227
|
setup_cli_logging(verbose=verbose, quiet=quiet)
|
|
236
228
|
|
|
237
229
|
try:
|
|
238
230
|
command = InitCommand(output)
|
|
239
|
-
exit_code = command.execute(path=path, force=force
|
|
231
|
+
exit_code = command.execute(path=path, force=force)
|
|
240
232
|
sys.exit(exit_code)
|
|
241
233
|
except Exception as e:
|
|
242
234
|
sys.exit(handle_exception(e))
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import random
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from agentflow.core import Agent, StateGraph, ToolNode
|
|
6
|
+
from agentflow.core.state import AgentState
|
|
7
|
+
from agentflow.core.state.stream_emitter import StreamEmitter
|
|
8
|
+
from agentflow.storage.checkpointer import InMemoryCheckpointer
|
|
9
|
+
from agentflow.utils.constants import END
|
|
10
|
+
from dotenv import load_dotenv
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
load_dotenv()
|
|
14
|
+
|
|
15
|
+
checkpointer = InMemoryCheckpointer()
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def call_weather_api(location: str) -> str:
|
|
21
|
+
is_failed = random.choice([True, False]) # Randomly simulate success or failure # noqa: S311
|
|
22
|
+
if is_failed:
|
|
23
|
+
raise Exception("Failed to fetch weather data due to a simulated API error.")
|
|
24
|
+
return f"The weather in {location} is sunny"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_weather(
|
|
28
|
+
location: str,
|
|
29
|
+
tool_call_id: str | None = None,
|
|
30
|
+
state: AgentState | None = None,
|
|
31
|
+
emit: StreamEmitter | None = None,
|
|
32
|
+
) -> str:
|
|
33
|
+
"""
|
|
34
|
+
Get the current weather for a specific location.
|
|
35
|
+
This demo shows injectable parameters: tool_call_id and state are automatically injected.
|
|
36
|
+
"""
|
|
37
|
+
# You can access injected parameters here
|
|
38
|
+
if tool_call_id:
|
|
39
|
+
logger.info(f"Tool call ID: {tool_call_id}")
|
|
40
|
+
if state and hasattr(state, "context"):
|
|
41
|
+
logger.info(f"Number of messages in context: {len(state.context)}") # type: ignore
|
|
42
|
+
if emit:
|
|
43
|
+
emit.progress("Fetching weather data...")
|
|
44
|
+
|
|
45
|
+
# return f"The weather in {location} is sunny"
|
|
46
|
+
|
|
47
|
+
result = ""
|
|
48
|
+
for i in range(3): # Try up to 3 times
|
|
49
|
+
try:
|
|
50
|
+
result = call_weather_api(location)
|
|
51
|
+
break # If successful, exit the loop
|
|
52
|
+
except Exception as e:
|
|
53
|
+
logger.error(f"Attempt {i + 1} failed: {e}")
|
|
54
|
+
result = f"Sorry, I couldn't fetch the weather for {location} after multiple attempts."
|
|
55
|
+
if emit:
|
|
56
|
+
emit.progress(f"Attempt {i + 1} failed, retrying...")
|
|
57
|
+
|
|
58
|
+
return result
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
tool_node = ToolNode(
|
|
62
|
+
[
|
|
63
|
+
get_weather,
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Create agent with tools
|
|
68
|
+
agent = Agent(
|
|
69
|
+
model="gemini-3-flash-preview",
|
|
70
|
+
provider="google",
|
|
71
|
+
system_prompt=[
|
|
72
|
+
{
|
|
73
|
+
"role": "system",
|
|
74
|
+
"content": """
|
|
75
|
+
You are a helpful assistant.
|
|
76
|
+
Your task is to assist the user in finding information and answering questions.
|
|
77
|
+
""",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"role": "user",
|
|
81
|
+
"content": f"Today Date is {datetime.now().strftime('%Y-%m-%d')}",
|
|
82
|
+
}, # Inject current date into system prompt
|
|
83
|
+
],
|
|
84
|
+
trim_context=True,
|
|
85
|
+
reasoning_config=True,
|
|
86
|
+
tool_node=tool_node,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def should_use_tools(state: AgentState) -> str:
|
|
91
|
+
"""Determine if we should use tools or end the conversation."""
|
|
92
|
+
if not state.context or len(state.context) == 0:
|
|
93
|
+
return "TOOL" # No context, might need tools
|
|
94
|
+
|
|
95
|
+
last_message = state.context[-1]
|
|
96
|
+
|
|
97
|
+
# If the last message is from assistant and has tool calls, go to TOOL
|
|
98
|
+
if (
|
|
99
|
+
hasattr(last_message, "tools_calls")
|
|
100
|
+
and last_message.tools_calls
|
|
101
|
+
and len(last_message.tools_calls) > 0
|
|
102
|
+
and last_message.role == "assistant"
|
|
103
|
+
):
|
|
104
|
+
return "TOOL"
|
|
105
|
+
|
|
106
|
+
# If last message is a tool result, we should be done (AI will make final response)
|
|
107
|
+
if last_message.role == "tool":
|
|
108
|
+
return "MAIN"
|
|
109
|
+
|
|
110
|
+
# Default to END for other cases
|
|
111
|
+
return END
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
graph = StateGraph()
|
|
115
|
+
graph.add_node("MAIN", agent)
|
|
116
|
+
graph.add_node("TOOL", tool_node)
|
|
117
|
+
|
|
118
|
+
# Add conditional edges from MAIN
|
|
119
|
+
graph.add_conditional_edges(
|
|
120
|
+
"MAIN",
|
|
121
|
+
should_use_tools,
|
|
122
|
+
{"TOOL": "TOOL", END: END},
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Always go back to MAIN after TOOL execution
|
|
126
|
+
graph.add_edge("TOOL", "MAIN")
|
|
127
|
+
graph.set_entry_point("MAIN")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
app = graph.compile(
|
|
131
|
+
checkpointer=checkpointer,
|
|
132
|
+
)
|