10xscale-agentflow-cli 0.4.0__tar.gz → 0.5.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.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/PKG-INFO +2 -2
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/SOURCES.txt +17 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/requires.txt +1 -1
- 10xscale_agentflow_cli-0.5.0/AGENTFLOW_JSON.md +273 -0
- 10xscale_agentflow_cli-0.5.0/AUTHORIZATION_PLAN.md +101 -0
- 10xscale_agentflow_cli-0.5.0/AUTHORIZATION_PLAN_PHASE2.md +34 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/CLAUDE.md +25 -5
- 10xscale_agentflow_cli-0.5.0/CUSTOM_AUTH.md +216 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/PKG-INFO +2 -2
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow.json +1 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/build.py +51 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/init.py +19 -3
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/main.py +10 -1
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/defaults.py +193 -1
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/agentflow.json +9 -3
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/auth/agent_auth.py +1 -4
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/api-configuration.md +1 -1
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/cli/templates/skills/agent-skills/references/auth-and-authorization.md +149 -0
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/core/auth/authorization.py +369 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/auth/jwt_auth.py +1 -0
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/core/auth/ownership_resolver.py +147 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/auth/permissions.py +70 -3
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/core/auth/route_guard.py +79 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/graph_config.py +57 -7
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/media_settings.py +20 -2
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/settings.py +9 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/setup_middleware.py +159 -2
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/core/middleware/rate_limit/keying.py +82 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/request_limits.py +18 -1
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/loader.py +149 -14
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/main.py +59 -3
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/checkpointer/router.py +19 -2
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/checkpointer/services/checkpointer_service.py +29 -0
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/routers/evals/__init__.py +6 -0
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/routers/evals/router.py +38 -0
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/routers/evals/services/__init__.py +1 -0
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/routers/evals/services/eval_report_service.py +354 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/router.py +214 -2
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/schemas/graph_schemas.py +100 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/services/graph_service.py +528 -20
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/services/multimodal_preprocessor.py +5 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/media/__init__.py +62 -4
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/media/router.py +49 -6
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/setup_router.py +2 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/store/router.py +32 -27
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/store/services/store_service.py +3 -1
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/__init__.py +2 -2
- 10xscale_agentflow_cli-0.5.0/agentflow_cli/src/app/utils/telemetry_store.py +123 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/thread_name_generator.py +5 -5
- 10xscale_agentflow_cli-0.5.0/graph/__init__.py +1 -0
- 10xscale_agentflow_cli-0.5.0/graph/dummy_store.py +215 -0
- 10xscale_agentflow_cli-0.5.0/graph/fake_realtime_client.py +129 -0
- 10xscale_agentflow_cli-0.5.0/graph/live.py +79 -0
- 10xscale_agentflow_cli-0.5.0/graph/react.py +221 -0
- 10xscale_agentflow_cli-0.5.0/graph/thread_name_generator.py +18 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/pyproject.toml +3 -3
- 10xscale_agentflow_cli-0.4.0/agentflow_cli/cli/templates/skills/agent-skills/references/auth-and-authorization.md +0 -87
- 10xscale_agentflow_cli-0.4.0/agentflow_cli/src/app/core/auth/authorization.py +0 -90
- 10xscale_agentflow_cli-0.4.0/agentflow_cli/src/app/core/middleware/rate_limit/keying.py +0 -24
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/dependency_links.txt +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/entry_points.txt +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/not-zip-safe +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/10xscale_agentflow_cli.egg-info/top_level.txt +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/LICENSE +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/MANIFEST.in +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/README.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/api.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/eval.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/skills.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/test.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/commands/version.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/constants.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/core/config.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/core/output.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/core/validation.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/exceptions.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/logger.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/dev/agentflow.json +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/dev/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/dev/graph/agent.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/.pre-commot-config.yaml +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/auth/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/evals/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/evals/user_simulator_eval.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/evals/weather_agents_eval.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/agent.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/state.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/thread_name_generator.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/tools/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/tools/weather_tool.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/validators/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/validators/lifecyle.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/validators/manager.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/graph/validators/validators.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/tests/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/tests/conftest.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/tests/test_agent_eval.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/tests/test_catalog_tools.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/prod/tests/test_graph_nodes.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/agents-and-tools.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/api-client.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/api-settings-and-middleware.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/architecture.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/callbacks-and-command.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/checkpointing-and-threads.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/cli-commands.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/client-auth-and-errors.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/client-messages-invoke-stream.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/client-threads-memory-files.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/context-id-background.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/dependency-injection.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/evaluation.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/id-and-thread-name-generators.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/media-and-files.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/memory-and-store.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/prebuilt-agents-and-tools.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/production-runtime.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/providers-and-adapters.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/publishers-and-runtime-protocols.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/rate-limiting.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/realtime.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/remote-tools.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/rest-api-and-errors.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/security-and-validators.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/state-and-messages.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/state-graph.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/stream-emitter.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/streaming.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/testing-and-evaluation.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/agent-skills/references/unit-testing.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/claude/SKILL.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/codex/SKILL.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/copilot/SKILL.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/cli/templates/skills/copilot/agentflow.instructions.md +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/auth/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/auth/auth_backend.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/auth/base_auth.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/sentry_config.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/setup_logs.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/config/worker_middleware.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/exceptions/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/exceptions/general_exception.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/exceptions/handle_errors.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/exceptions/resources_exceptions.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/exceptions/user_exception.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/rate_limit/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/rate_limit/base.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/rate_limit/factory.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/rate_limit/memory.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/rate_limit/middleware.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/rate_limit/redis.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/middleware/security_headers.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/utils/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/core/utils/log_sanitizer.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/a2a.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/a2ui.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/checkpointer/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/checkpointer/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/checkpointer/schemas/checkpointer_schemas.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/checkpointer/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/realtime_guard.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/graph/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/media/schemas.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/ping/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/ping/router.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/store/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/store/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/store/schemas/store_schemas.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/routers/store/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/tasks/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/tasks/user_tasks.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/callable_helper.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/media/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/media/extractor.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/media/pipeline.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/parse_output.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/response_helper.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/schemas/output_schemas.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/schemas/user_schemas.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/snowflake_id_generator.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/utils/swagger_helper.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/agentflow_cli/src/app/worker.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/setup.cfg +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/tests/test_multimodal_sprint2_extraction.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/tests/test_sprint4_media_api.py +0 -0
- {10xscale_agentflow_cli-0.4.0 → 10xscale_agentflow_cli-0.5.0}/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
|
+
Version: 0.5.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>
|
|
@@ -22,7 +22,7 @@ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
|
22
22
|
Requires-Python: >=3.12
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: 10xscale-agentflow>=0.
|
|
25
|
+
Requires-Dist: 10xscale-agentflow>=0.9.0
|
|
26
26
|
Requires-Dist: fastapi
|
|
27
27
|
Requires-Dist: gunicorn
|
|
28
28
|
Requires-Dist: orjson
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
AGENTFLOW_JSON.md
|
|
2
|
+
AUTHORIZATION_PLAN.md
|
|
3
|
+
AUTHORIZATION_PLAN_PHASE2.md
|
|
1
4
|
CLAUDE.md
|
|
5
|
+
CUSTOM_AUTH.md
|
|
2
6
|
LICENSE
|
|
3
7
|
MANIFEST.in
|
|
4
8
|
README.md
|
|
@@ -104,7 +108,9 @@ agentflow_cli/src/app/core/auth/auth_backend.py
|
|
|
104
108
|
agentflow_cli/src/app/core/auth/authorization.py
|
|
105
109
|
agentflow_cli/src/app/core/auth/base_auth.py
|
|
106
110
|
agentflow_cli/src/app/core/auth/jwt_auth.py
|
|
111
|
+
agentflow_cli/src/app/core/auth/ownership_resolver.py
|
|
107
112
|
agentflow_cli/src/app/core/auth/permissions.py
|
|
113
|
+
agentflow_cli/src/app/core/auth/route_guard.py
|
|
108
114
|
agentflow_cli/src/app/core/config/__init__.py
|
|
109
115
|
agentflow_cli/src/app/core/config/graph_config.py
|
|
110
116
|
agentflow_cli/src/app/core/config/media_settings.py
|
|
@@ -140,6 +146,10 @@ agentflow_cli/src/app/routers/checkpointer/schemas/__init__.py
|
|
|
140
146
|
agentflow_cli/src/app/routers/checkpointer/schemas/checkpointer_schemas.py
|
|
141
147
|
agentflow_cli/src/app/routers/checkpointer/services/__init__.py
|
|
142
148
|
agentflow_cli/src/app/routers/checkpointer/services/checkpointer_service.py
|
|
149
|
+
agentflow_cli/src/app/routers/evals/__init__.py
|
|
150
|
+
agentflow_cli/src/app/routers/evals/router.py
|
|
151
|
+
agentflow_cli/src/app/routers/evals/services/__init__.py
|
|
152
|
+
agentflow_cli/src/app/routers/evals/services/eval_report_service.py
|
|
143
153
|
agentflow_cli/src/app/routers/graph/__init__.py
|
|
144
154
|
agentflow_cli/src/app/routers/graph/realtime_guard.py
|
|
145
155
|
agentflow_cli/src/app/routers/graph/router.py
|
|
@@ -167,6 +177,7 @@ agentflow_cli/src/app/utils/parse_output.py
|
|
|
167
177
|
agentflow_cli/src/app/utils/response_helper.py
|
|
168
178
|
agentflow_cli/src/app/utils/snowflake_id_generator.py
|
|
169
179
|
agentflow_cli/src/app/utils/swagger_helper.py
|
|
180
|
+
agentflow_cli/src/app/utils/telemetry_store.py
|
|
170
181
|
agentflow_cli/src/app/utils/thread_name_generator.py
|
|
171
182
|
agentflow_cli/src/app/utils/media/__init__.py
|
|
172
183
|
agentflow_cli/src/app/utils/media/extractor.py
|
|
@@ -174,6 +185,12 @@ agentflow_cli/src/app/utils/media/pipeline.py
|
|
|
174
185
|
agentflow_cli/src/app/utils/schemas/__init__.py
|
|
175
186
|
agentflow_cli/src/app/utils/schemas/output_schemas.py
|
|
176
187
|
agentflow_cli/src/app/utils/schemas/user_schemas.py
|
|
188
|
+
graph/__init__.py
|
|
189
|
+
graph/dummy_store.py
|
|
190
|
+
graph/fake_realtime_client.py
|
|
191
|
+
graph/live.py
|
|
192
|
+
graph/react.py
|
|
193
|
+
graph/thread_name_generator.py
|
|
177
194
|
tests/test_multimodal_sprint2_extraction.py
|
|
178
195
|
tests/test_sprint4_media_api.py
|
|
179
196
|
tests/test_utils_parse_and_callable.py
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# `agentflow.json` — Configuration Reference
|
|
2
|
+
|
|
3
|
+
This is the only file you write to turn your compiled graph into a running API server.
|
|
4
|
+
`agentflow api` reads it, resolves each key, and boots FastAPI + WebSocket around your graph.
|
|
5
|
+
|
|
6
|
+
Every key except `agent` is optional. Secrets never live here — they stay in the environment
|
|
7
|
+
(loaded from the file named by `env`).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Minimal (development)
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"agent": "graph.react:app"
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`agent` points at a compiled graph; everything else defaults. No auth, in-memory everything,
|
|
20
|
+
allow-all authorization. Enough to run locally.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Full shape
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"agent": "graph.react:app",
|
|
29
|
+
"env": ".env",
|
|
30
|
+
|
|
31
|
+
"auth": null,
|
|
32
|
+
"authorization": null,
|
|
33
|
+
|
|
34
|
+
"checkpointer": null,
|
|
35
|
+
"store": null,
|
|
36
|
+
"redis": null,
|
|
37
|
+
|
|
38
|
+
"injectq": null,
|
|
39
|
+
"thread_name_generator": null,
|
|
40
|
+
|
|
41
|
+
"rate_limit": {},
|
|
42
|
+
"websocket": {},
|
|
43
|
+
"observability": null
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Keys
|
|
50
|
+
|
|
51
|
+
### `agent` (required)
|
|
52
|
+
`"module:attribute"` resolving to a `CompiledGraph`. The loader accepts a `CompiledGraph`
|
|
53
|
+
object, or a sync/async factory that returns one.
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
"agent": "graph.react:app"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `env`
|
|
60
|
+
Path to a `.env` file, loaded at config-load time. Put all secrets here (JWT key, DB URLs,
|
|
61
|
+
API keys). Never inline secrets in this JSON.
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
"env": ".env"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `auth` — who is the caller? (authentication)
|
|
68
|
+
Produces a `user` dict with at least `user_id`. Three forms:
|
|
69
|
+
|
|
70
|
+
| Value | Meaning |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `null` | No authentication. All endpoints run unauthenticated (dev). |
|
|
73
|
+
| `"jwt"` | Built-in JWT bearer auth. Requires `JWT_SECRET_KEY` + `JWT_ALGORITHM` in env (fails at boot if missing). Token must carry `user_id` and `exp`. |
|
|
74
|
+
| `{"method": "custom", "path": "auth.backend:MyAuth"}` | Your own `BaseAuth` subclass (`from agentflow_cli import BaseAuth`). |
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
"auth": "jwt"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `authorization` — what may the caller do? (authorization)
|
|
81
|
+
Separate from `auth`. Controls object-level access (thread ownership), per-endpoint scopes,
|
|
82
|
+
and storage isolation. Four forms:
|
|
83
|
+
|
|
84
|
+
| Value | Meaning |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `null` | **Mode-based default**: `ownership` in production, `allow_all` in development. |
|
|
87
|
+
| `"ownership"` | Owner-only: a thread is readable/runnable only by the user who created it. Enforced on every thread-touching endpoint (invoke/stream/stop/fix + all checkpointer ops). |
|
|
88
|
+
| `"allow_all"` (aliases `"default"`, `"none"`) | Any authenticated user may do anything. |
|
|
89
|
+
| `"auth.backend:MyBackend"` | Your own `AuthorizationBackend` subclass. |
|
|
90
|
+
| `{...}` (object) | RBAC — see below. |
|
|
91
|
+
|
|
92
|
+
Plain owner-only:
|
|
93
|
+
```json
|
|
94
|
+
"authorization": "ownership"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
RBAC (roles → scopes, on top of owner-only isolation):
|
|
98
|
+
```json
|
|
99
|
+
"authorization": {
|
|
100
|
+
"backend": "rbac",
|
|
101
|
+
"roles": {
|
|
102
|
+
"admin": ["*"],
|
|
103
|
+
"member": ["graph:invoke", "graph:stream", "graph:read", "checkpointer:read"]
|
|
104
|
+
},
|
|
105
|
+
"default_scopes": ["graph:read"],
|
|
106
|
+
"isolation": "owner"
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `roles` — map each role (from the user's `roles`/`role` claim) to the scopes it grants.
|
|
111
|
+
`"*"` grants every scope.
|
|
112
|
+
- `default_scopes` — granted to everyone, even a user with no role.
|
|
113
|
+
- `isolation` — `"owner"` (owner-only storage, default) or `"none"` (any authenticated user
|
|
114
|
+
sees all rows).
|
|
115
|
+
|
|
116
|
+
Available scopes (`"<resource>:<action>"`):
|
|
117
|
+
|
|
118
|
+
| Resource | Scopes |
|
|
119
|
+
|---|---|
|
|
120
|
+
| graph | `graph:invoke`, `graph:stream`, `graph:stop`, `graph:fix`, `graph:setup`, `graph:read` |
|
|
121
|
+
| checkpointer | `checkpointer:read`, `checkpointer:write`, `checkpointer:delete` |
|
|
122
|
+
| memory (store) | `memory:read`, `memory:write`, `memory:delete` |
|
|
123
|
+
| files | `files:read`, `files:upload` |
|
|
124
|
+
| config | `config:read` |
|
|
125
|
+
|
|
126
|
+
Scopes are only enforced once an identity actually carries scopes (an RBAC role, or a JWT
|
|
127
|
+
`scopes` claim). Without them the server stays permissive — nothing breaks until you issue
|
|
128
|
+
scopes.
|
|
129
|
+
|
|
130
|
+
### `checkpointer` — durable thread state
|
|
131
|
+
`"module:attr"` resolving to a `BaseCheckpointer`. Omit for in-memory (state lost on restart).
|
|
132
|
+
Ownership-based authorization requires a checkpointer that can resolve thread owners
|
|
133
|
+
(Postgres/SQLite/in-memory all do; a bare base does not).
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
"checkpointer": "graph.infra:checkpointer"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `store` — long-term memory (vector store)
|
|
140
|
+
`"module:attr"` resolving to a `BaseStore` (Qdrant, Mem0, ...). Powers `/v1/store/*`. Scoped
|
|
141
|
+
per-user according to the active authorization isolation policy.
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
"store": "graph.infra:store"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `redis`
|
|
148
|
+
Redis URL. Shared by the rate-limiter (redis backend) and the ownership-cache L2 tier (so
|
|
149
|
+
ownership lookups are shared across workers instead of per-process).
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
"redis": "redis://localhost:6379/0"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### `injectq`
|
|
156
|
+
`"module:attr"` resolving to an InjectQ container, if you want to pre-bind dependencies
|
|
157
|
+
(db handles, config, `user_id`) for injection into your tools.
|
|
158
|
+
|
|
159
|
+
### `thread_name_generator`
|
|
160
|
+
`"module:attr"` resolving to a `ThreadNameGenerator` — auto-names new threads.
|
|
161
|
+
|
|
162
|
+
### `rate_limit`
|
|
163
|
+
Object. Omit or `{"enabled": false}` to disable.
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
"rate_limit": {
|
|
167
|
+
"enabled": true,
|
|
168
|
+
"backend": "redis",
|
|
169
|
+
"requests": 100,
|
|
170
|
+
"window": 60,
|
|
171
|
+
"by": "ip",
|
|
172
|
+
"trusted_proxy_headers": true,
|
|
173
|
+
"trusted_proxy_hops": 1,
|
|
174
|
+
"exclude_paths": ["/ping"],
|
|
175
|
+
"fail_open": true,
|
|
176
|
+
"redis": { "url": "redis://localhost:6379/0", "prefix": "agentflow:rate-limit" }
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
| Field | Default | Notes |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `enabled` | `true` | |
|
|
183
|
+
| `backend` | `"memory"` | `memory` \| `redis` \| `custom`. **`memory` counts per process — use `redis` for multi-worker.** For `custom`, bind a `BaseRateLimitBackend` in InjectQ. |
|
|
184
|
+
| `requests` | `100` | Allowed requests per window. |
|
|
185
|
+
| `window` | `60` | Window length in seconds. |
|
|
186
|
+
| `by` | `"ip"` | `ip` \| `user` \| `global`. |
|
|
187
|
+
| `trusted_proxy_headers` | `false` | Honour `X-Forwarded-For` only when `true` (i.e. behind a proxy you control). |
|
|
188
|
+
| `trusted_proxy_hops` | `1` | How many proxies you control appended to `X-Forwarded-For`; entries left of these are forgeable. |
|
|
189
|
+
| `exclude_paths` | `[]` | Paths exempt from limiting. |
|
|
190
|
+
| `fail_open` | `true` | On backend error: `true` = allow, `false` = deny. |
|
|
191
|
+
|
|
192
|
+
### `websocket`
|
|
193
|
+
Per-process cap on concurrent WebSocket connections (`/v1/graph/ws`, `/v1/graph/live`).
|
|
194
|
+
`null`/`0` = unlimited.
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
"websocket": { "max_connections": 100 }
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### `observability`
|
|
201
|
+
Declarative Logfire / LangSmith wiring. Tokens (`LOGFIRE_TOKEN`, `LANGSMITH_API_KEY`) stay in
|
|
202
|
+
the environment.
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
"observability": {
|
|
206
|
+
"level": "standard",
|
|
207
|
+
"logfire": { "enabled": true, "service_name": "my-agent" },
|
|
208
|
+
"langsmith": { "enabled": true, "project": "my-agent", "endpoint": null }
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Production example
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"agent": "graph.react:app",
|
|
219
|
+
"env": ".env",
|
|
220
|
+
|
|
221
|
+
"auth": "jwt",
|
|
222
|
+
"authorization": {
|
|
223
|
+
"backend": "rbac",
|
|
224
|
+
"roles": {
|
|
225
|
+
"admin": ["*"],
|
|
226
|
+
"member": ["graph:invoke", "graph:stream", "graph:read", "checkpointer:read", "memory:read", "memory:write"]
|
|
227
|
+
},
|
|
228
|
+
"default_scopes": [],
|
|
229
|
+
"isolation": "owner"
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
"checkpointer": "graph.infra:checkpointer",
|
|
233
|
+
"store": "graph.infra:store",
|
|
234
|
+
"redis": "redis://redis:6379/0",
|
|
235
|
+
|
|
236
|
+
"rate_limit": {
|
|
237
|
+
"enabled": true,
|
|
238
|
+
"backend": "redis",
|
|
239
|
+
"requests": 100,
|
|
240
|
+
"window": 60,
|
|
241
|
+
"by": "user",
|
|
242
|
+
"trusted_proxy_headers": true,
|
|
243
|
+
"redis": { "url": "redis://redis:6379/0" }
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
"websocket": { "max_connections": 500 }
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Required env for this example (in `.env`):
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
MODE=production
|
|
254
|
+
IS_DEBUG=false
|
|
255
|
+
ORIGINS=https://app.example.com
|
|
256
|
+
JWT_SECRET_KEY=<32+ char secret>
|
|
257
|
+
JWT_ALGORITHM=HS256
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Defaults at a glance
|
|
263
|
+
|
|
264
|
+
| If you omit... | You get |
|
|
265
|
+
|---|---|
|
|
266
|
+
| `auth` | No authentication. |
|
|
267
|
+
| `authorization` | `ownership` in production, `allow_all` in development. |
|
|
268
|
+
| `checkpointer` | In-memory (lost on restart). |
|
|
269
|
+
| `store` | No memory API. |
|
|
270
|
+
| `redis` | Ownership cache is L1-only (per-process); redis rate-limit backend unavailable. |
|
|
271
|
+
| `rate_limit` | No rate limiting. |
|
|
272
|
+
| `websocket` | Unlimited connections. |
|
|
273
|
+
| `observability` | None. |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Scalable Object-Level Authorization — Design & Plan
|
|
2
|
+
|
|
3
|
+
Status: DONE (all steps implemented, tested, documented)
|
|
4
|
+
Scope: `agentflow-api` (auth layer) + `agentflow` core (`aget_thread_owner` source-of-truth lookup)
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
|
|
8
|
+
Owner-only access to threads, enforced on **every** thread-touching step (invoke, stream,
|
|
9
|
+
stop, fix, and all checkpointer read/write/delete), **on by default in production** when the
|
|
10
|
+
developer enables auth, fully overridable, and **scalable** — no database round-trip per
|
|
11
|
+
request.
|
|
12
|
+
|
|
13
|
+
## Design principles
|
|
14
|
+
|
|
15
|
+
1. **Ownership is immutable.** A thread's owner is set at creation and never changes; only
|
|
16
|
+
deletion removes it. Therefore the owner is safe to cache aggressively (cache-forever)
|
|
17
|
+
and we essentially never re-hit the DB for a known thread.
|
|
18
|
+
2. **Single decision point.** One `AuthorizationBackend`, invoked before every handler. No
|
|
19
|
+
per-endpoint bespoke checks.
|
|
20
|
+
3. **Secure by construction.** No route can ship unprotected (enforced at boot).
|
|
21
|
+
4. **Graceful degradation.** No checkpointer / a checkpointer that can't resolve ownership →
|
|
22
|
+
warn + allow (nothing persisted to protect). Redis is optional.
|
|
23
|
+
|
|
24
|
+
## Components
|
|
25
|
+
|
|
26
|
+
### 1. Source of truth: `aget_thread_owner` (core) — DONE
|
|
27
|
+
|
|
28
|
+
`BaseCheckpointer.aget_thread_owner(thread_id) -> user_id | None`:
|
|
29
|
+
- base: raises `NotImplementedError` (so a backend can't silently report "no owner", which
|
|
30
|
+
would defeat owner-based authorization).
|
|
31
|
+
- `PgCheckpointer`: `SELECT user_id FROM threads WHERE thread_id = $1`.
|
|
32
|
+
- `InMemoryCheckpointer`, `SqliteCheckpointer`: read the stored thread record's `user_id`.
|
|
33
|
+
|
|
34
|
+
This is the DB-level lookup the cache sits in front of. Already implemented + unit tested.
|
|
35
|
+
|
|
36
|
+
### 2. `ThreadOwnershipResolver` (the scalable cache) — NEW (`agentflow-api`)
|
|
37
|
+
|
|
38
|
+
- **L1**: in-process LRU, bounded (default 10_000), immutable owners cached with **no TTL**.
|
|
39
|
+
- **L2**: Redis, reusing the app's existing Redis client when configured; key
|
|
40
|
+
`af:authz:owner:{thread_id}`. Gracefully L1-only when Redis is absent.
|
|
41
|
+
- `owner_of(thread_id) -> str | None`: L1 → L2 (fill L1) → DB `aget_thread_owner` (fill L2+L1).
|
|
42
|
+
**Only positive results are cached; `None` is never cached** — a nonexistent thread can
|
|
43
|
+
become owned by the very next request, so caching `None` would open a TOCTOU hole.
|
|
44
|
+
- `evict(thread_id)`: clears L1+L2. Called when a thread is deleted.
|
|
45
|
+
- Cost: first touch of a thread = 1 lookup; every subsequent request = in-process hit.
|
|
46
|
+
|
|
47
|
+
### 3. `OwnershipAuthorizationBackend` — rewire to use the resolver
|
|
48
|
+
|
|
49
|
+
Decision table (cached; no raw DB call):
|
|
50
|
+
- no `user_id` → deny
|
|
51
|
+
- non-thread resource (`store`, `files`) → allow (they self-scope)
|
|
52
|
+
- no `resource_id` → allow (list/create endpoints)
|
|
53
|
+
- `owner = resolver.owner_of(resource_id)`:
|
|
54
|
+
- `None` → allow (brand-new session / empty read)
|
|
55
|
+
- `owner == user_id` → allow
|
|
56
|
+
- `owner != user_id` → **deny, for every action including invoke/stream**
|
|
57
|
+
- resolver reports unsupported backend → warn + allow; resolver error → fail closed (deny).
|
|
58
|
+
|
|
59
|
+
### 4. Secure-by-construction enforcement (fail-closed at boot)
|
|
60
|
+
|
|
61
|
+
`assert_all_routes_protected(app)` runs at startup: walk every route; any non-public route
|
|
62
|
+
(allowlist: `/ping`) whose dependency tree lacks `RequirePermission` makes the server
|
|
63
|
+
**refuse to start** with a clear error. Keeps precise per-handler `(resource, action)`, adds
|
|
64
|
+
zero per-request overhead, and turns a forgotten guard into a deploy-time failure instead of
|
|
65
|
+
a silently-open production endpoint. (Delivers the "authorization on every step" guarantee
|
|
66
|
+
more robustly than a literal router dependency, which cannot cleanly derive each route's
|
|
67
|
+
action.)
|
|
68
|
+
|
|
69
|
+
### 5. Invalidation
|
|
70
|
+
|
|
71
|
+
`CheckpointerService.delete_thread` (and the `aclean_thread` path) calls
|
|
72
|
+
`resolver.evict(thread_id)`.
|
|
73
|
+
|
|
74
|
+
### 6. Config surface (unchanged)
|
|
75
|
+
|
|
76
|
+
`"authorization"`: `"ownership"` | `"allow_all"`/`"default"`/`"none"` | `"module:attr"` |
|
|
77
|
+
unset → `ownership` in production, `allow_all` in development. Developer choice always wins.
|
|
78
|
+
|
|
79
|
+
## Test plan
|
|
80
|
+
|
|
81
|
+
- Resolver: L1 hit, L2 promote-to-L1, DB fill, negative-not-cached, evict, LRU bound.
|
|
82
|
+
- Backend: full decision table over the cached path.
|
|
83
|
+
- Startup invariant: a route missing `RequirePermission` → boot raises; allowlist passes.
|
|
84
|
+
- Integration: non-owner invoke/stream/read/delete → 403; owner → ok; second call served from
|
|
85
|
+
cache (asserted with a call-counting fake checkpointer — no second DB hit).
|
|
86
|
+
- Core: `aget_thread_owner` for in-memory/sqlite (done).
|
|
87
|
+
|
|
88
|
+
## Docs
|
|
89
|
+
|
|
90
|
+
Update `docs/how-to/api-cli/add-auth.md` and `agentflow-api/CLAUDE.md`: caching model,
|
|
91
|
+
immutability, Redis opt-in, boot-time guarantee.
|
|
92
|
+
|
|
93
|
+
## Execution order
|
|
94
|
+
|
|
95
|
+
1. ThreadOwnershipResolver + unit tests.
|
|
96
|
+
2. Rewire OwnershipAuthorizationBackend onto the resolver + update tests.
|
|
97
|
+
3. Wire resolver into DI (loader) and evict on delete_thread.
|
|
98
|
+
4. Startup invariant `assert_all_routes_protected` + boot wiring + tests.
|
|
99
|
+
5. Integration tests (owner-only + cache-hit assertion).
|
|
100
|
+
6. Docs.
|
|
101
|
+
7. Full suite (api + core) green with coverage.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Phase 2 — Policy-driven isolation (single source of truth, non-hijackable)
|
|
2
|
+
|
|
3
|
+
Problem: `user_id` scoping in the checkpointer is just data partitioning on a supplied id.
|
|
4
|
+
It's not authorization, and `allow_all` (authz) can contradict the data layer. Fix: one
|
|
5
|
+
**trusted policy**, set only by the server from auth, drives both.
|
|
6
|
+
|
|
7
|
+
## The idea (short)
|
|
8
|
+
|
|
9
|
+
1. **Trusted policy in config, server-only.** The API injects `config["policy"] = {"scope": ...}`
|
|
10
|
+
built from the active authorization backend. It **overwrites/strips** any client-sent
|
|
11
|
+
`policy` (and already overwrites `user_id`), so the frontend can send whatever it wants —
|
|
12
|
+
ignored. Not hijackable.
|
|
13
|
+
- `OwnershipAuthorizationBackend.isolation_scope()` -> `"owner"`
|
|
14
|
+
- `DefaultAuthorizationBackend` / others -> `"none"`
|
|
15
|
+
|
|
16
|
+
2. **Checkpointer honors the policy.**
|
|
17
|
+
- `scope == "owner"` -> filter state/messages/threads by `user_id`.
|
|
18
|
+
- `scope == "none"` -> no filtering (allow_all genuinely returns everything).
|
|
19
|
+
- policy absent (direct core-lib call, no API) -> fall back to the checkpointer's own
|
|
20
|
+
`enforce_user_isolation` default (backward compatible).
|
|
21
|
+
Applies to pg (already scopes; make it read policy), **InMemory + sqlite (add scoping)**.
|
|
22
|
+
|
|
23
|
+
3. **Coherent.** allow_all -> no 403 + no data scope. ownership -> 403 + data scope. Same
|
|
24
|
+
policy drives both decisions. Kills the dev/InMemory leak because scoping no longer depends
|
|
25
|
+
on which checkpointer happens to filter.
|
|
26
|
+
|
|
27
|
+
## Steps
|
|
28
|
+
1. `AuthorizationBackend.isolation_scope()` (base `"none"`, ownership `"owner"`).
|
|
29
|
+
2. API config builders set trusted `config["policy"]` (checkpointer_service `_config`;
|
|
30
|
+
graph_service invoke/stream/stop/fix where `user_id` is set). Strip client `policy`.
|
|
31
|
+
3. Checkpointer scoping reads `config["policy"]["scope"]` (pg/inmemory/sqlite), fallback to
|
|
32
|
+
`enforce_user_isolation`.
|
|
33
|
+
4. Tests (non-owner blocked on InMemory too; allow_all returns everything; client-sent policy
|
|
34
|
+
ignored) + docs.
|
|
@@ -5,13 +5,16 @@ core framework see `agentflow/CLAUDE.md`; for the TS client, docs, or playground
|
|
|
5
5
|
for the monorepo overview see the workspace-root `CLAUDE.md`.
|
|
6
6
|
|
|
7
7
|
- Package name (PyPI): `10xscale-agentflow-cli`
|
|
8
|
-
- Version: `0.
|
|
8
|
+
- Version: `0.4.0` (`pyproject.toml`). `CLI_VERSION` and `agentflow_cli.__version__` are
|
|
9
9
|
single-sourced from the installed distribution metadata (falling back to `pyproject.toml`), so
|
|
10
|
-
`agentflow version` reports `0.
|
|
10
|
+
`agentflow version` reports `0.4.0` consistently. The previous `1.0.0` hardcode is gone.
|
|
11
11
|
- Requires: Python >= 3.12 · Status: `4 - Beta`
|
|
12
12
|
- Console entry point: `agentflow = agentflow_cli.cli.main:main`
|
|
13
13
|
- Depends on the core framework: `10xscale-agentflow>=0.7.0`.
|
|
14
14
|
|
|
15
|
+
- Depends on the core framework: `10xscale-agentflow>=0.9.0` (0.9.0 is the first release that
|
|
16
|
+
ships `agentflow.core.authz`, which the RBAC/scope code imports).
|
|
17
|
+
|
|
15
18
|
## What this package is
|
|
16
19
|
|
|
17
20
|
It turns an Agentflow `CompiledGraph` into a production FastAPI service, plus a Typer CLI to
|
|
@@ -76,8 +79,25 @@ and for redis backend a `redis` sub-object `{ "url", "prefix" }` (or shorthand U
|
|
|
76
79
|
load if missing). JWT logic lives in `core/auth/jwt_auth.py`.
|
|
77
80
|
- `"auth": {"method": "custom", "path": "module:attr"}` loads your `BaseAuth` subclass
|
|
78
81
|
(`from agentflow_cli import BaseAuth`).
|
|
79
|
-
- Authorization (RBAC
|
|
80
|
-
(`AuthorizationBackend` / `DefaultAuthorizationBackend`
|
|
82
|
+
- Authorization (RBAC / object-level) is separate: `core/auth/authorization.py`
|
|
83
|
+
(`AuthorizationBackend` / `DefaultAuthorizationBackend` / `OwnershipAuthorizationBackend`),
|
|
84
|
+
wired via the `authorization` key. That key accepts `"module:attr"` (custom), a built-in
|
|
85
|
+
name (`"ownership"` = owner-only thread access; `"allow_all"`/`"default"`/`"none"`), or
|
|
86
|
+
`null`. When unset it defaults **by mode**: `ownership` in production (secure by default),
|
|
87
|
+
`allow_all` in development. Selection lives in `loader._resolve_authorization_backend`;
|
|
88
|
+
`RequirePermission` passes `resource_id` (thread_id from path or body) to `authorize`.
|
|
89
|
+
- **Ownership is object-level and enforced on every thread-touching step** (invoke/stream/
|
|
90
|
+
stop/fix + all checkpointer read/write/delete): a thread is accessible only to its owner;
|
|
91
|
+
a foreign `invoke`/`stream` is rejected up front (403), never reaching the graph.
|
|
92
|
+
- **Scalable, not a DB call per request.** Ownership is immutable, so it is cached by
|
|
93
|
+
`core/auth/ownership_resolver.py::ThreadOwnershipResolver`: in-process LRU (L1) + optional
|
|
94
|
+
shared Redis (L2, reuses `config.redis`/`settings.REDIS_URL`). The backing lookup is
|
|
95
|
+
`BaseCheckpointer.aget_thread_owner` (implemented in pg/in-memory/sqlite; base raises
|
|
96
|
+
`NotImplementedError`). Cache is evicted on thread delete (`CheckpointerService.delete_thread`);
|
|
97
|
+
the L2 client is closed in the lifespan shutdown.
|
|
98
|
+
- **Secure by construction:** `core/auth/route_guard.py::assert_all_routes_protected` runs at
|
|
99
|
+
boot (`main.py` after `init_routes`) and refuses to start if any non-public route lacks a
|
|
100
|
+
`RequirePermission` guard (`/ping` is the only public path).
|
|
81
101
|
|
|
82
102
|
## HTTP + WebSocket surface (all under `/v1` except ping)
|
|
83
103
|
|
|
@@ -134,7 +154,7 @@ ruff check . && ruff format .
|
|
|
134
154
|
|
|
135
155
|
- **Version is now single-sourced.** `CLI_VERSION` (and `agentflow_cli.__version__`, which aliases
|
|
136
156
|
it) resolve from installed distribution metadata, falling back to `pyproject.toml`. `agentflow
|
|
137
|
-
version` reports `0.
|
|
157
|
+
version` reports `0.4.0` for both the CLI and package lines. (The old hardcoded `1.0.0` drift is
|
|
138
158
|
resolved.)
|
|
139
159
|
- **README shows `agentflow init --prod`** — that flag does not exist. `init` is interactive and
|
|
140
160
|
only accepts `--path` / `--force`.
|