10xgraph-api 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 10xgraph_api-0.7.0.dist-info/METADATA +618 -0
- 10xgraph_api-0.7.0.dist-info/RECORD +203 -0
- 10xgraph_api-0.7.0.dist-info/WHEEL +5 -0
- 10xgraph_api-0.7.0.dist-info/entry_points.txt +3 -0
- 10xgraph_api-0.7.0.dist-info/licenses/LICENSE +21 -0
- 10xgraph_api-0.7.0.dist-info/top_level.txt +2 -0
- agentflow_cli/__init__.py +69 -0
- tenxgraph_api/__init__.py +23 -0
- tenxgraph_api/cli/__init__.py +6 -0
- tenxgraph_api/cli/capabilities.py +127 -0
- tenxgraph_api/cli/commands/__init__.py +49 -0
- tenxgraph_api/cli/commands/api.py +262 -0
- tenxgraph_api/cli/commands/audit.py +213 -0
- tenxgraph_api/cli/commands/build.py +305 -0
- tenxgraph_api/cli/commands/config.py +71 -0
- tenxgraph_api/cli/commands/demo.py +93 -0
- tenxgraph_api/cli/commands/eval.py +909 -0
- tenxgraph_api/cli/commands/init.py +531 -0
- tenxgraph_api/cli/commands/skills.py +532 -0
- tenxgraph_api/cli/commands/test.py +113 -0
- tenxgraph_api/cli/commands/version.py +47 -0
- tenxgraph_api/cli/config_editor/__init__.py +15 -0
- tenxgraph_api/cli/config_editor/schema.py +566 -0
- tenxgraph_api/cli/config_editor/server.py +240 -0
- tenxgraph_api/cli/config_editor/static/app.css +2 -0
- tenxgraph_api/cli/config_editor/static/app.js +3 -0
- tenxgraph_api/cli/config_editor/static/favicon.svg +11 -0
- tenxgraph_api/cli/config_editor/static/index.html +20 -0
- tenxgraph_api/cli/config_editor/store.py +120 -0
- tenxgraph_api/cli/config_editor/validation.py +377 -0
- tenxgraph_api/cli/constants.py +112 -0
- tenxgraph_api/cli/context.py +46 -0
- tenxgraph_api/cli/core/__init__.py +0 -0
- tenxgraph_api/cli/core/animations.py +550 -0
- tenxgraph_api/cli/core/config.py +279 -0
- tenxgraph_api/cli/core/output.py +625 -0
- tenxgraph_api/cli/core/prompts.py +220 -0
- tenxgraph_api/cli/core/screen.py +287 -0
- tenxgraph_api/cli/core/steps.py +621 -0
- tenxgraph_api/cli/core/theme.py +242 -0
- tenxgraph_api/cli/core/validation.py +251 -0
- tenxgraph_api/cli/exceptions.py +129 -0
- tenxgraph_api/cli/logger.py +84 -0
- tenxgraph_api/cli/main.py +936 -0
- tenxgraph_api/cli/templates/__init__.py +0 -0
- tenxgraph_api/cli/templates/defaults.py +844 -0
- tenxgraph_api/cli/templates/dev/.env.example +1 -0
- tenxgraph_api/cli/templates/dev/10xgraph.json +16 -0
- tenxgraph_api/cli/templates/dev/graph/__init__.py +0 -0
- tenxgraph_api/cli/templates/dev/graph/agent.py +63 -0
- tenxgraph_api/cli/templates/prod/.env.example +75 -0
- tenxgraph_api/cli/templates/prod/.pre-commit-config.yaml +50 -0
- tenxgraph_api/cli/templates/prod/.python-version +1 -0
- tenxgraph_api/cli/templates/prod/10xgraph.json +42 -0
- tenxgraph_api/cli/templates/prod/auth/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/auth/agent_auth.py +46 -0
- tenxgraph_api/cli/templates/prod/evals/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/evals/user_simulator_eval.py +76 -0
- tenxgraph_api/cli/templates/prod/evals/weather_agents_eval.py +53 -0
- tenxgraph_api/cli/templates/prod/graph/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/graph/agent.py +50 -0
- tenxgraph_api/cli/templates/prod/graph/state.py +5 -0
- tenxgraph_api/cli/templates/prod/graph/thread_name_generator.py +7 -0
- tenxgraph_api/cli/templates/prod/graph/tools/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/graph/tools/weather_tool.py +43 -0
- tenxgraph_api/cli/templates/prod/graph/validators/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/graph/validators/lifecyle.py +107 -0
- tenxgraph_api/cli/templates/prod/graph/validators/manager.py +9 -0
- tenxgraph_api/cli/templates/prod/graph/validators/validators.py +21 -0
- tenxgraph_api/cli/templates/prod/pyproject.toml +79 -0
- tenxgraph_api/cli/templates/prod/tests/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/tests/conftest.py +6 -0
- tenxgraph_api/cli/templates/prod/tests/test_agent_eval.py +78 -0
- tenxgraph_api/cli/templates/prod/tests/test_catalog_tools.py +47 -0
- tenxgraph_api/cli/templates/prod/tests/test_graph_nodes.py +57 -0
- tenxgraph_api/cli/templates/skills/10xgraph/SKILL.md +92 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/agents-and-tools.md +389 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/api-client.md +61 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/api-configuration.md +75 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/api-settings-and-middleware.md +89 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/architecture.md +91 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/auth-and-authorization.md +149 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/callbacks-and-command.md +283 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/checkpointing-and-threads.md +63 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/cli-commands.md +73 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/client-auth-and-errors.md +94 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/client-messages-invoke-stream.md +115 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/client-threads-memory-files.md +80 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/context-id-background.md +80 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/dependency-injection.md +58 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/evaluation.md +500 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/id-and-thread-name-generators.md +69 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/media-and-files.md +66 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/memory-and-store.md +70 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/prebuilt-agents-and-tools.md +394 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/production-runtime.md +56 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/providers-and-adapters.md +89 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/publishers-and-runtime-protocols.md +84 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/rate-limiting.md +194 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/realtime.md +172 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/remote-tools.md +55 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/rest-api-and-errors.md +97 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/security-and-validators.md +86 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/state-and-messages.md +68 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/state-graph.md +232 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/stream-emitter.md +144 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/streaming.md +53 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/testing-and-evaluation.md +64 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/unit-testing.md +202 -0
- tenxgraph_api/cli/templates/skills/copilot/10xgraph.instructions.md +108 -0
- tenxgraph_api/py.typed +0 -0
- tenxgraph_api/src/__init__.py +0 -0
- tenxgraph_api/src/app/__init__.py +13 -0
- tenxgraph_api/src/app/core/__init__.py +15 -0
- tenxgraph_api/src/app/core/auth/__init__.py +0 -0
- tenxgraph_api/src/app/core/auth/auth_backend.py +38 -0
- tenxgraph_api/src/app/core/auth/authorization.py +379 -0
- tenxgraph_api/src/app/core/auth/base_auth.py +27 -0
- tenxgraph_api/src/app/core/auth/jwt_auth.py +122 -0
- tenxgraph_api/src/app/core/auth/ownership_resolver.py +170 -0
- tenxgraph_api/src/app/core/auth/permissions.py +354 -0
- tenxgraph_api/src/app/core/auth/request_config.py +130 -0
- tenxgraph_api/src/app/core/auth/route_guard.py +105 -0
- tenxgraph_api/src/app/core/config/__init__.py +0 -0
- tenxgraph_api/src/app/core/config/graph_config.py +532 -0
- tenxgraph_api/src/app/core/config/media_settings.py +72 -0
- tenxgraph_api/src/app/core/config/sentry_config.py +60 -0
- tenxgraph_api/src/app/core/config/settings.py +202 -0
- tenxgraph_api/src/app/core/config/setup_logs.py +65 -0
- tenxgraph_api/src/app/core/config/setup_middleware.py +483 -0
- tenxgraph_api/src/app/core/config/worker_middleware.py +99 -0
- tenxgraph_api/src/app/core/exceptions/__init__.py +17 -0
- tenxgraph_api/src/app/core/exceptions/general_exception.py +58 -0
- tenxgraph_api/src/app/core/exceptions/handle_errors.py +363 -0
- tenxgraph_api/src/app/core/exceptions/resources_exceptions.py +72 -0
- tenxgraph_api/src/app/core/exceptions/user_exception.py +58 -0
- tenxgraph_api/src/app/core/middleware/__init__.py +25 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/__init__.py +15 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/base.py +27 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/factory.py +98 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/keying.py +133 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/memory.py +98 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/middleware.py +90 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/redis.py +115 -0
- tenxgraph_api/src/app/core/middleware/request_limits.py +154 -0
- tenxgraph_api/src/app/core/middleware/security_headers.py +239 -0
- tenxgraph_api/src/app/core/utils/__init__.py +14 -0
- tenxgraph_api/src/app/core/utils/log_sanitizer.py +216 -0
- tenxgraph_api/src/app/loader.py +516 -0
- tenxgraph_api/src/app/main.py +180 -0
- tenxgraph_api/src/app/routers/__init__.py +4 -0
- tenxgraph_api/src/app/routers/ag_ui/__init__.py +10 -0
- tenxgraph_api/src/app/routers/ag_ui/converter.py +195 -0
- tenxgraph_api/src/app/routers/ag_ui/event_mapper.py +353 -0
- tenxgraph_api/src/app/routers/ag_ui/router.py +90 -0
- tenxgraph_api/src/app/routers/ag_ui/service.py +193 -0
- tenxgraph_api/src/app/routers/checkpointer/__init__.py +1 -0
- tenxgraph_api/src/app/routers/checkpointer/router.py +482 -0
- tenxgraph_api/src/app/routers/checkpointer/schemas/__init__.py +1 -0
- tenxgraph_api/src/app/routers/checkpointer/schemas/checkpointer_schemas.py +121 -0
- tenxgraph_api/src/app/routers/checkpointer/services/__init__.py +1 -0
- tenxgraph_api/src/app/routers/checkpointer/services/checkpointer_service.py +300 -0
- tenxgraph_api/src/app/routers/evals/__init__.py +6 -0
- tenxgraph_api/src/app/routers/evals/router.py +38 -0
- tenxgraph_api/src/app/routers/evals/services/__init__.py +1 -0
- tenxgraph_api/src/app/routers/evals/services/eval_report_service.py +354 -0
- tenxgraph_api/src/app/routers/graph/__init__.py +6 -0
- tenxgraph_api/src/app/routers/graph/realtime_guard.py +161 -0
- tenxgraph_api/src/app/routers/graph/router.py +821 -0
- tenxgraph_api/src/app/routers/graph/schemas/__init__.py +1 -0
- tenxgraph_api/src/app/routers/graph/schemas/graph_schemas.py +386 -0
- tenxgraph_api/src/app/routers/graph/services/__init__.py +1 -0
- tenxgraph_api/src/app/routers/graph/services/graph_service.py +1219 -0
- tenxgraph_api/src/app/routers/graph/services/multimodal_preprocessor.py +164 -0
- tenxgraph_api/src/app/routers/media/__init__.py +506 -0
- tenxgraph_api/src/app/routers/media/router.py +242 -0
- tenxgraph_api/src/app/routers/media/schemas.py +39 -0
- tenxgraph_api/src/app/routers/ping/__init__.py +4 -0
- tenxgraph_api/src/app/routers/ping/router.py +28 -0
- tenxgraph_api/src/app/routers/setup_router.py +60 -0
- tenxgraph_api/src/app/routers/store/__init__.py +4 -0
- tenxgraph_api/src/app/routers/store/router.py +200 -0
- tenxgraph_api/src/app/routers/store/schemas/__init__.py +28 -0
- tenxgraph_api/src/app/routers/store/schemas/store_schemas.py +200 -0
- tenxgraph_api/src/app/routers/store/services/__init__.py +4 -0
- tenxgraph_api/src/app/routers/store/services/store_service.py +203 -0
- tenxgraph_api/src/app/tasks/__init__.py +0 -0
- tenxgraph_api/src/app/tasks/user_tasks.py +38 -0
- tenxgraph_api/src/app/utils/__init__.py +12 -0
- tenxgraph_api/src/app/utils/callable_helper.py +26 -0
- tenxgraph_api/src/app/utils/media/__init__.py +15 -0
- tenxgraph_api/src/app/utils/media/extractor.py +172 -0
- tenxgraph_api/src/app/utils/media/pipeline.py +83 -0
- tenxgraph_api/src/app/utils/parse_output.py +17 -0
- tenxgraph_api/src/app/utils/response_helper.py +129 -0
- tenxgraph_api/src/app/utils/schemas/__init__.py +11 -0
- tenxgraph_api/src/app/utils/schemas/output_schemas.py +28 -0
- tenxgraph_api/src/app/utils/schemas/user_schemas.py +13 -0
- tenxgraph_api/src/app/utils/snowflake_id_generator.py +90 -0
- tenxgraph_api/src/app/utils/swagger_helper.py +160 -0
- tenxgraph_api/src/app/utils/telemetry_store.py +123 -0
- tenxgraph_api/src/app/utils/thread_name_generator.py +304 -0
- tenxgraph_api/src/app/worker.py +91 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Browser-based editor for ``10xgraph.json`` served by ``10xgraph config``."""
|
|
2
|
+
|
|
3
|
+
from tenxgraph_api.cli.config_editor.schema import build_schema
|
|
4
|
+
from tenxgraph_api.cli.config_editor.server import ConfigEditorServer
|
|
5
|
+
from tenxgraph_api.cli.config_editor.store import ConfigConflictError, ConfigFileStore
|
|
6
|
+
from tenxgraph_api.cli.config_editor.validation import validate_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ConfigConflictError",
|
|
11
|
+
"ConfigEditorServer",
|
|
12
|
+
"ConfigFileStore",
|
|
13
|
+
"build_schema",
|
|
14
|
+
"validate_config",
|
|
15
|
+
]
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
"""Declarative description of every ``10xgraph.json`` option the editor shows.
|
|
2
|
+
|
|
3
|
+
The browser page renders itself from :func:`build_schema`, so adding a new
|
|
4
|
+
configuration key only needs a new entry here (plus a rule in ``validation``).
|
|
5
|
+
|
|
6
|
+
Section shape::
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
"id": "rate_limit", # stable id, used by validation issues
|
|
10
|
+
"title": "Rate limiting",
|
|
11
|
+
"description": "...",
|
|
12
|
+
"key": "rate_limit", # top-level key, or None for root-level fields
|
|
13
|
+
"optional": True, # renders an on/off toggle for the whole key
|
|
14
|
+
"off_summary": "...", # what happens while the key is absent
|
|
15
|
+
"default": {...}, # value written when the toggle is switched on
|
|
16
|
+
"widget": None, # custom renderer: "auth", "authorization", "remote_tools"
|
|
17
|
+
"fields": [...], # generic fields, paths are relative to the root
|
|
18
|
+
"notes": ["..."], # extra hints (secrets that belong in .env, ...)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Field shape::
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
"path": ["rate_limit", "redis", "url"],
|
|
25
|
+
"label": "Redis URL",
|
|
26
|
+
"type": "text" | "number" | "bool" | "select" | "list",
|
|
27
|
+
"help": "...",
|
|
28
|
+
"placeholder": "...",
|
|
29
|
+
"options": [...], # select only
|
|
30
|
+
"min": 0,
|
|
31
|
+
"step": 1, # number only
|
|
32
|
+
"required": False,
|
|
33
|
+
"default": ..., # value the server assumes when the key is absent
|
|
34
|
+
"group": "Backend", # fields sharing a group render together
|
|
35
|
+
"show_if": {"path": [...], "equals": value},
|
|
36
|
+
}
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
import copy
|
|
42
|
+
from typing import Any
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
DOCS_URL = "https://10xgraph.com/docs/reference/api-cli/configuration"
|
|
46
|
+
|
|
47
|
+
# Mirrors authorization.all_scopes(); kept in sync by a unit test so the
|
|
48
|
+
# editor never imports the core framework just to render suggestions.
|
|
49
|
+
AUTHORIZATION_SCOPES: tuple[str, ...] = (
|
|
50
|
+
"checkpointer:delete",
|
|
51
|
+
"checkpointer:read",
|
|
52
|
+
"checkpointer:write",
|
|
53
|
+
"config:read",
|
|
54
|
+
"files:read",
|
|
55
|
+
"files:upload",
|
|
56
|
+
"graph:fix",
|
|
57
|
+
"graph:invoke",
|
|
58
|
+
"graph:read",
|
|
59
|
+
"graph:setup",
|
|
60
|
+
"graph:stop",
|
|
61
|
+
"graph:stream",
|
|
62
|
+
"store:delete",
|
|
63
|
+
"store:read",
|
|
64
|
+
"store:write",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
BUILTIN_AUTHORIZATION: tuple[str, ...] = ("ownership", "allow_all", "default", "none")
|
|
68
|
+
|
|
69
|
+
# Keys read by the CLI or the API server. Anything else is preserved but flagged.
|
|
70
|
+
KNOWN_TOP_LEVEL_KEYS: frozenset[str] = frozenset(
|
|
71
|
+
{
|
|
72
|
+
"agent",
|
|
73
|
+
"env",
|
|
74
|
+
"auth",
|
|
75
|
+
"authorization",
|
|
76
|
+
"rate_limit",
|
|
77
|
+
"websocket",
|
|
78
|
+
"ag_ui",
|
|
79
|
+
"observability",
|
|
80
|
+
"injectq",
|
|
81
|
+
"store",
|
|
82
|
+
"checkpointer",
|
|
83
|
+
"thread_name_generator",
|
|
84
|
+
"redis",
|
|
85
|
+
"remote_tools",
|
|
86
|
+
"test",
|
|
87
|
+
"evaluation",
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
_SECTIONS: list[dict[str, Any]] = [
|
|
92
|
+
{
|
|
93
|
+
"id": "core",
|
|
94
|
+
"title": "Core",
|
|
95
|
+
"description": "The compiled graph the server runs and the dotenv file it loads.",
|
|
96
|
+
"key": None,
|
|
97
|
+
"optional": False,
|
|
98
|
+
"fields": [
|
|
99
|
+
{
|
|
100
|
+
"path": ["agent"],
|
|
101
|
+
"label": "Agent graph",
|
|
102
|
+
"type": "text",
|
|
103
|
+
"required": True,
|
|
104
|
+
"placeholder": "graph.react:app",
|
|
105
|
+
"help": "Import path of the compiled graph, as module:attribute.",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"path": ["env"],
|
|
109
|
+
"label": "Env file",
|
|
110
|
+
"type": "text",
|
|
111
|
+
"placeholder": ".env",
|
|
112
|
+
"help": "Dotenv file loaded before the graph starts. Leave empty to skip.",
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "auth",
|
|
118
|
+
"title": "Authentication",
|
|
119
|
+
"description": "Who is calling the API. Leave off for local development.",
|
|
120
|
+
"key": "auth",
|
|
121
|
+
"optional": True,
|
|
122
|
+
"off_summary": "Every request is accepted without authentication.",
|
|
123
|
+
"default": "jwt",
|
|
124
|
+
"widget": "auth",
|
|
125
|
+
"fields": [],
|
|
126
|
+
"notes": [
|
|
127
|
+
"JWT needs JWT_SECRET_KEY and JWT_ALGORITHM in your .env file.",
|
|
128
|
+
"Custom auth points at a BaseAuth subclass, as module:attribute.",
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"id": "authorization",
|
|
133
|
+
"title": "Authorization",
|
|
134
|
+
"description": (
|
|
135
|
+
"What an authenticated user may do. When off, production uses ownership "
|
|
136
|
+
"and development allows everything."
|
|
137
|
+
),
|
|
138
|
+
"key": "authorization",
|
|
139
|
+
"optional": True,
|
|
140
|
+
"off_summary": "Production enforces ownership checks; development allows everything.",
|
|
141
|
+
"default": "ownership",
|
|
142
|
+
"widget": "authorization",
|
|
143
|
+
"fields": [],
|
|
144
|
+
"scopes": list(AUTHORIZATION_SCOPES),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "rate_limit",
|
|
148
|
+
"title": "Rate limiting",
|
|
149
|
+
"description": "Sliding-window request limits applied to every REST call.",
|
|
150
|
+
"key": "rate_limit",
|
|
151
|
+
"optional": True,
|
|
152
|
+
"off_summary": "Requests are not rate limited.",
|
|
153
|
+
"default": {
|
|
154
|
+
"enabled": True,
|
|
155
|
+
"backend": "memory",
|
|
156
|
+
"requests": 100,
|
|
157
|
+
"window": 60,
|
|
158
|
+
"by": "ip",
|
|
159
|
+
"exclude_paths": ["/ping", "/docs", "/redoc", "/openapi.json"],
|
|
160
|
+
},
|
|
161
|
+
"fields": [
|
|
162
|
+
{
|
|
163
|
+
"path": ["rate_limit", "enabled"],
|
|
164
|
+
"group": "Limits",
|
|
165
|
+
"default": True,
|
|
166
|
+
"label": "Enabled",
|
|
167
|
+
"type": "bool",
|
|
168
|
+
"help": "Turn off to keep the settings without enforcing them.",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"path": ["rate_limit", "requests"],
|
|
172
|
+
"group": "Limits",
|
|
173
|
+
"label": "Requests per window",
|
|
174
|
+
"type": "number",
|
|
175
|
+
"min": 1,
|
|
176
|
+
"step": 1,
|
|
177
|
+
"placeholder": "100",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"path": ["rate_limit", "window"],
|
|
181
|
+
"group": "Limits",
|
|
182
|
+
"label": "Window (seconds)",
|
|
183
|
+
"type": "number",
|
|
184
|
+
"min": 1,
|
|
185
|
+
"step": 1,
|
|
186
|
+
"placeholder": "60",
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"path": ["rate_limit", "by"],
|
|
190
|
+
"group": "Limits",
|
|
191
|
+
"default": "ip",
|
|
192
|
+
"label": "Limit by",
|
|
193
|
+
"type": "select",
|
|
194
|
+
"options": ["ip", "user", "global"],
|
|
195
|
+
"help": "Count requests per client IP, per authenticated user, or all together.",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"path": ["rate_limit", "backend"],
|
|
199
|
+
"group": "Backend",
|
|
200
|
+
"default": "memory",
|
|
201
|
+
"label": "Backend",
|
|
202
|
+
"type": "select",
|
|
203
|
+
"options": ["memory", "redis", "custom"],
|
|
204
|
+
"help": (
|
|
205
|
+
"memory counts per process. Use redis for multiple workers. custom "
|
|
206
|
+
"expects a BaseRateLimitBackend bound in InjectQ."
|
|
207
|
+
),
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"path": ["rate_limit", "redis", "url"],
|
|
211
|
+
"group": "Backend",
|
|
212
|
+
"label": "Redis URL",
|
|
213
|
+
"type": "text",
|
|
214
|
+
"placeholder": "${REDIS_URL}",
|
|
215
|
+
"help": "Supports $VAR and ${VAR}. Not needed if Redis is bound in InjectQ.",
|
|
216
|
+
"show_if": {"path": ["rate_limit", "backend"], "equals": "redis"},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"path": ["rate_limit", "redis", "prefix"],
|
|
220
|
+
"group": "Backend",
|
|
221
|
+
"label": "Redis key prefix",
|
|
222
|
+
"type": "text",
|
|
223
|
+
"placeholder": "10xgraph:rate-limit",
|
|
224
|
+
"show_if": {"path": ["rate_limit", "backend"], "equals": "redis"},
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"path": ["rate_limit", "fail_open"],
|
|
228
|
+
"group": "Backend",
|
|
229
|
+
"default": True,
|
|
230
|
+
"label": "Fail open",
|
|
231
|
+
"type": "bool",
|
|
232
|
+
"help": "Allow requests when the backend errors. Off means deny.",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"path": ["rate_limit", "trusted_proxy_headers"],
|
|
236
|
+
"group": "Proxy",
|
|
237
|
+
"default": False,
|
|
238
|
+
"label": "Trust X-Forwarded-For",
|
|
239
|
+
"type": "bool",
|
|
240
|
+
"help": "Only when the app sits behind a proxy you control.",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"path": ["rate_limit", "trusted_proxy_hops"],
|
|
244
|
+
"group": "Proxy",
|
|
245
|
+
"label": "Trusted proxy hops",
|
|
246
|
+
"type": "number",
|
|
247
|
+
"min": 1,
|
|
248
|
+
"step": 1,
|
|
249
|
+
"placeholder": "1",
|
|
250
|
+
"show_if": {"path": ["rate_limit", "trusted_proxy_headers"], "equals": True},
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"path": ["rate_limit", "trusted_proxies"],
|
|
254
|
+
"group": "Proxy",
|
|
255
|
+
"label": "Trusted proxy networks",
|
|
256
|
+
"type": "list",
|
|
257
|
+
"placeholder": "10.0.0.0/8",
|
|
258
|
+
"help": (
|
|
259
|
+
"IPs or CIDR ranges your proxy connects from. X-Forwarded-For is ignored "
|
|
260
|
+
"for anyone else, so clients that reach the app directly cannot spoof it."
|
|
261
|
+
),
|
|
262
|
+
"show_if": {"path": ["rate_limit", "trusted_proxy_headers"], "equals": True},
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"path": ["rate_limit", "exclude_paths"],
|
|
266
|
+
"group": "Excluded paths",
|
|
267
|
+
"label": "Excluded paths",
|
|
268
|
+
"type": "list",
|
|
269
|
+
"placeholder": "/ping",
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"id": "websocket",
|
|
275
|
+
"title": "WebSocket",
|
|
276
|
+
"description": "Caps on concurrent realtime and streaming connections, per process.",
|
|
277
|
+
"key": "websocket",
|
|
278
|
+
"optional": True,
|
|
279
|
+
"off_summary": "Concurrent WebSocket connections are not capped.",
|
|
280
|
+
"default": {"max_connections": 1000, "max_connections_per_user": 10},
|
|
281
|
+
"fields": [
|
|
282
|
+
{
|
|
283
|
+
"path": ["websocket", "max_connections"],
|
|
284
|
+
"label": "Max connections",
|
|
285
|
+
"type": "number",
|
|
286
|
+
"min": 0,
|
|
287
|
+
"step": 1,
|
|
288
|
+
"placeholder": "1000",
|
|
289
|
+
"help": "Per worker process. Defaults to 1000; 0 means unlimited.",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"path": ["websocket", "max_connections_per_user"],
|
|
293
|
+
"label": "Max connections per user",
|
|
294
|
+
"type": "number",
|
|
295
|
+
"min": 0,
|
|
296
|
+
"step": 1,
|
|
297
|
+
"placeholder": "10",
|
|
298
|
+
"help": "Stops one account holding every slot. Defaults to 10; 0 means unlimited.",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"path": ["websocket", "realtime_models"],
|
|
302
|
+
"label": "Realtime models clients may pick",
|
|
303
|
+
"type": "list",
|
|
304
|
+
"placeholder": "gemini-2.5-flash-live",
|
|
305
|
+
"help": (
|
|
306
|
+
"Models a /v1/graph/live client may request. Any other request uses the "
|
|
307
|
+
"agent's own model. Empty means clients cannot choose."
|
|
308
|
+
),
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"id": "ag_ui",
|
|
314
|
+
"title": "AG-UI",
|
|
315
|
+
"description": "Serve the graph over the AG-UI protocol, for clients such as CopilotKit.",
|
|
316
|
+
"key": "ag_ui",
|
|
317
|
+
"optional": True,
|
|
318
|
+
"off_summary": "The AG-UI endpoint (POST /v1/ag-ui) is not mounted.",
|
|
319
|
+
"default": {"enabled": True},
|
|
320
|
+
"fields": [
|
|
321
|
+
{
|
|
322
|
+
"path": ["ag_ui", "enabled"],
|
|
323
|
+
"default": False,
|
|
324
|
+
"label": "Enabled",
|
|
325
|
+
"type": "bool",
|
|
326
|
+
"help": "Mounts POST /v1/ag-ui. It uses the same auth as /v1/graph/stream.",
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"path": ["ag_ui", "allow_client_tools"],
|
|
330
|
+
"default": True,
|
|
331
|
+
"label": "Allow client tools",
|
|
332
|
+
"type": "bool",
|
|
333
|
+
"help": (
|
|
334
|
+
"Offer the tools a client sends (e.g. CopilotKit useFrontendTool) to the "
|
|
335
|
+
"model for that run. Off: only tools listed in remote_tools."
|
|
336
|
+
),
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
"notes": [
|
|
340
|
+
'Needs the ag-ui extra: pip install "10xgraph-api[ag-ui]".',
|
|
341
|
+
"Client tools run in the caller's browser, cannot reuse a server tool's name, and are "
|
|
342
|
+
"size-limited.",
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"id": "observability",
|
|
347
|
+
"title": "Observability",
|
|
348
|
+
"description": "Trace graph runs to Logfire and/or LangSmith.",
|
|
349
|
+
"key": "observability",
|
|
350
|
+
"optional": True,
|
|
351
|
+
"off_summary": "Graph runs are not traced.",
|
|
352
|
+
"default": {
|
|
353
|
+
"level": "standard",
|
|
354
|
+
"logfire": {"enabled": False},
|
|
355
|
+
"langsmith": {"enabled": False},
|
|
356
|
+
},
|
|
357
|
+
"fields": [
|
|
358
|
+
{
|
|
359
|
+
"path": ["observability", "level"],
|
|
360
|
+
"group": "Tracing",
|
|
361
|
+
"default": "standard",
|
|
362
|
+
"label": "Level",
|
|
363
|
+
"type": "select",
|
|
364
|
+
"options": ["spans", "standard", "full"],
|
|
365
|
+
"help": "full records prompts and tool I/O and may contain PII.",
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"path": ["observability", "logfire", "enabled"],
|
|
369
|
+
"group": "Logfire",
|
|
370
|
+
"default": False,
|
|
371
|
+
"label": "Logfire",
|
|
372
|
+
"type": "bool",
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"path": ["observability", "logfire", "service_name"],
|
|
376
|
+
"group": "Logfire",
|
|
377
|
+
"label": "Logfire service name",
|
|
378
|
+
"type": "text",
|
|
379
|
+
"placeholder": "my-agent",
|
|
380
|
+
"show_if": {"path": ["observability", "logfire", "enabled"], "equals": True},
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"path": ["observability", "logfire", "send_to_logfire"],
|
|
384
|
+
"group": "Logfire",
|
|
385
|
+
"default": True,
|
|
386
|
+
"label": "Send to Logfire",
|
|
387
|
+
"type": "bool",
|
|
388
|
+
"show_if": {"path": ["observability", "logfire", "enabled"], "equals": True},
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"path": ["observability", "logfire", "console"],
|
|
392
|
+
"group": "Logfire",
|
|
393
|
+
"default": False,
|
|
394
|
+
"label": "Print spans to console",
|
|
395
|
+
"type": "bool",
|
|
396
|
+
"show_if": {"path": ["observability", "logfire", "enabled"], "equals": True},
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"path": ["observability", "langsmith", "enabled"],
|
|
400
|
+
"group": "LangSmith",
|
|
401
|
+
"default": False,
|
|
402
|
+
"label": "LangSmith",
|
|
403
|
+
"type": "bool",
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"path": ["observability", "langsmith", "project"],
|
|
407
|
+
"group": "LangSmith",
|
|
408
|
+
"label": "LangSmith project",
|
|
409
|
+
"type": "text",
|
|
410
|
+
"placeholder": "my-agent",
|
|
411
|
+
"show_if": {"path": ["observability", "langsmith", "enabled"], "equals": True},
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
"path": ["observability", "langsmith", "endpoint"],
|
|
415
|
+
"group": "LangSmith",
|
|
416
|
+
"label": "LangSmith endpoint",
|
|
417
|
+
"type": "text",
|
|
418
|
+
"placeholder": "https://api.smith.langchain.com/otel",
|
|
419
|
+
"show_if": {"path": ["observability", "langsmith", "enabled"], "equals": True},
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
"notes": ["Tokens stay in .env: LOGFIRE_TOKEN and LANGSMITH_API_KEY."],
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"id": "plugins",
|
|
426
|
+
"title": "Plugins",
|
|
427
|
+
"description": "Optional objects loaded by import path. Leave a field empty to skip it.",
|
|
428
|
+
"key": None,
|
|
429
|
+
"optional": False,
|
|
430
|
+
"fields": [
|
|
431
|
+
{
|
|
432
|
+
"path": ["injectq"],
|
|
433
|
+
"group": "Import paths",
|
|
434
|
+
"label": "InjectQ container",
|
|
435
|
+
"type": "text",
|
|
436
|
+
"placeholder": "graph.dependencies:container",
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"path": ["store"],
|
|
440
|
+
"group": "Import paths",
|
|
441
|
+
"label": "Memory store",
|
|
442
|
+
"type": "text",
|
|
443
|
+
"placeholder": "graph.dependencies:store",
|
|
444
|
+
"help": "A BaseStore instance for long-term memory.",
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"path": ["checkpointer"],
|
|
448
|
+
"group": "Import paths",
|
|
449
|
+
"label": "Checkpointer",
|
|
450
|
+
"type": "text",
|
|
451
|
+
"placeholder": "graph.dependencies:checkpointer",
|
|
452
|
+
"help": (
|
|
453
|
+
"Not applied by the API server yet. Pass the checkpointer to "
|
|
454
|
+
"graph.compile() instead."
|
|
455
|
+
),
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"path": ["thread_name_generator"],
|
|
459
|
+
"group": "Import paths",
|
|
460
|
+
"label": "Thread name generator",
|
|
461
|
+
"type": "text",
|
|
462
|
+
"placeholder": "graph.thread_name_generator:MyNameGenerator",
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
"path": ["redis"],
|
|
466
|
+
"group": "Connections",
|
|
467
|
+
"label": "Redis URL",
|
|
468
|
+
"type": "text",
|
|
469
|
+
"placeholder": "redis://localhost:6379/0",
|
|
470
|
+
"help": (
|
|
471
|
+
"Shared cache for ownership checks. Used as-is: $VAR is not expanded "
|
|
472
|
+
"here, so leave it empty to fall back to REDIS_URL."
|
|
473
|
+
),
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"id": "remote_tools",
|
|
479
|
+
"title": "Remote tools",
|
|
480
|
+
"description": "Tools the model can call that run in the client, not on the server.",
|
|
481
|
+
"key": "remote_tools",
|
|
482
|
+
"optional": True,
|
|
483
|
+
"off_summary": "The model can only call tools that run on the server.",
|
|
484
|
+
"default": [],
|
|
485
|
+
"widget": "remote_tools",
|
|
486
|
+
"fields": [],
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
"id": "test",
|
|
490
|
+
"title": "Testing",
|
|
491
|
+
"description": "Defaults for 10xgraph test.",
|
|
492
|
+
"key": "test",
|
|
493
|
+
"optional": True,
|
|
494
|
+
"off_summary": "10xgraph test uses its built-in defaults.",
|
|
495
|
+
"default": {"path": "tests", "coverage": False},
|
|
496
|
+
"fields": [
|
|
497
|
+
{"path": ["test", "path"], "label": "Tests path", "type": "text"},
|
|
498
|
+
{"path": ["test", "coverage"], "label": "Coverage", "type": "bool", "default": False},
|
|
499
|
+
{
|
|
500
|
+
"path": ["test", "coverage_threshold"],
|
|
501
|
+
"label": "Coverage threshold (%)",
|
|
502
|
+
"type": "number",
|
|
503
|
+
"min": 0,
|
|
504
|
+
"step": 1,
|
|
505
|
+
"placeholder": "80",
|
|
506
|
+
"show_if": {"path": ["test", "coverage"], "equals": True},
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
"id": "evaluation",
|
|
512
|
+
"title": "Evaluation",
|
|
513
|
+
"description": "Defaults for 10xgraph eval.",
|
|
514
|
+
"key": "evaluation",
|
|
515
|
+
"optional": True,
|
|
516
|
+
"off_summary": "10xgraph eval uses its built-in defaults.",
|
|
517
|
+
"default": {
|
|
518
|
+
"directory": "evals",
|
|
519
|
+
"output_dir": "eval_reports",
|
|
520
|
+
"threshold": 0.75,
|
|
521
|
+
"parallel": False,
|
|
522
|
+
"max_concurrency": 4,
|
|
523
|
+
},
|
|
524
|
+
"fields": [
|
|
525
|
+
{"path": ["evaluation", "directory"], "label": "Eval directory", "type": "text"},
|
|
526
|
+
{"path": ["evaluation", "output_dir"], "label": "Report directory", "type": "text"},
|
|
527
|
+
{
|
|
528
|
+
"path": ["evaluation", "threshold"],
|
|
529
|
+
"label": "Pass threshold",
|
|
530
|
+
"type": "number",
|
|
531
|
+
"min": 0,
|
|
532
|
+
"step": 0.05,
|
|
533
|
+
"help": "Between 0 and 1.",
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
"path": ["evaluation", "parallel"],
|
|
537
|
+
"label": "Run in parallel",
|
|
538
|
+
"type": "bool",
|
|
539
|
+
"default": False,
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
"path": ["evaluation", "max_concurrency"],
|
|
543
|
+
"label": "Max concurrency",
|
|
544
|
+
"type": "number",
|
|
545
|
+
"min": 1,
|
|
546
|
+
"step": 1,
|
|
547
|
+
"show_if": {"path": ["evaluation", "parallel"], "equals": True},
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
},
|
|
551
|
+
]
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def build_schema() -> dict[str, Any]:
|
|
555
|
+
"""Return a fresh, JSON-serialisable copy of the editor schema."""
|
|
556
|
+
return {"docs_url": DOCS_URL, "sections": copy.deepcopy(_SECTIONS)}
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def section_for_key(key: str) -> str:
|
|
560
|
+
"""Map a top-level config key to the id of the section that renders it."""
|
|
561
|
+
for section in _SECTIONS:
|
|
562
|
+
if section["key"] == key:
|
|
563
|
+
return section["id"]
|
|
564
|
+
if section["key"] is None and any(f["path"][0] == key for f in section["fields"]):
|
|
565
|
+
return section["id"]
|
|
566
|
+
return "core"
|