claude-smart 0.2.41 → 0.2.43
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.
- package/.claude-plugin/marketplace.json +17 -0
- package/README.md +1 -1
- package/bin/claude-smart.js +86 -48
- package/package.json +10 -3
- package/plugin/.claude-plugin/plugin.json +9 -3
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/README.md +2 -2
- package/plugin/dashboard/next.config.ts +9 -1
- package/plugin/pyproject.toml +2 -2
- package/plugin/scripts/_lib.sh +91 -0
- package/plugin/scripts/backend-service.sh +46 -15
- package/plugin/scripts/cli.sh +29 -1
- package/plugin/scripts/codex-hook.js +72 -4
- package/plugin/scripts/dashboard-build.sh +1 -0
- package/plugin/scripts/dashboard-service.sh +1 -0
- package/plugin/scripts/ensure-plugin-root.sh +7 -14
- package/plugin/scripts/hook_entry.sh +1 -0
- package/plugin/scripts/smart-install.sh +18 -2
- package/plugin/src/claude_smart/cli.py +72 -38
- package/plugin/src/claude_smart/context_format.py +11 -12
- package/plugin/src/claude_smart/cs_cite.py +26 -12
- package/plugin/src/claude_smart/ids.py +13 -5
- package/plugin/uv.lock +1 -1
- package/plugin/vendor/reflexio/.env.example +53 -0
- package/plugin/vendor/reflexio/LICENSE +201 -0
- package/plugin/vendor/reflexio/README.md +338 -0
- package/plugin/vendor/reflexio/pyproject.toml +271 -0
- package/plugin/vendor/reflexio/reflexio/README.md +184 -0
- package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
- package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
- package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
- package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
- package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
- package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
- package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +266 -0
- package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +961 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
- package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
- package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
- package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
- package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
- package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
- package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
- package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
- package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
- package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
- package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
- package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
- package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
- package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
- package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
- package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
- package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
- package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
- package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
- package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
- package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
- package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
- package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
- package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
- package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
- package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1103 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +766 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +280 -0
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
- package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
- package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
- package/plugin/vendor/reflexio/reflexio/server/README.md +616 -0
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
- package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
- package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
- package/plugin/vendor/reflexio/reflexio/server/api.py +2714 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/account_api.py +143 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/health_api.py +91 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/pending_tool_call_api.py +572 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +66 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +540 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +50 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/stall_state_api.py +100 -0
- package/plugin/vendor/reflexio/reflexio/server/cache/__init__.py +15 -0
- package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +208 -0
- package/plugin/vendor/reflexio/reflexio/server/correlation.py +46 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/__init__.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +110 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1595 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +112 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +469 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1122 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_stream_parser.py +197 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +210 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +213 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +255 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/__init__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +177 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +699 -0
- package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +179 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/_dispatchers.py +54 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/README.md +121 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation/v1.0.0.prompt.md +58 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation_with_comparison/v1.0.0.prompt.md +76 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/answer_synthesis/v1.5.2.prompt.md +88 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/compress_session_for_query/v1.3.0.prompt.md +31 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +20 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.0.0.prompt.md +53 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.1.0.prompt.md +57 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.2.0.prompt.md +68 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.3.0.prompt.md +70 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.4.0.prompt.md +77 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.5.0.prompt.md +82 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +83 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.1.0.prompt.md +193 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +206 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0-deprecated.prompt.md +66 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0.prompt.md +43 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.1.0.prompt.md +46 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0-deprecated.prompt.md +64 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0.prompt.md +39 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.1.0.prompt.md +39 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.2.0.prompt.md +47 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +58 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.0.2.prompt.md +254 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +279 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +127 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +340 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1626 -0
- package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
- package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
- package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
- package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +351 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +468 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +777 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +91 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +689 -0
- package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +960 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +741 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +734 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +800 -0
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +70 -0
- package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +671 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1253 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +372 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +568 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
- package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
- package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
- package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
- package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
- package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
|
@@ -0,0 +1,908 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import IntEnum, StrEnum
|
|
5
|
+
from typing import Any, Literal, Self
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
8
|
+
|
|
9
|
+
from .api_schema.validators import (
|
|
10
|
+
NonEmptyStr,
|
|
11
|
+
SafeHttpUrl,
|
|
12
|
+
SanitizedNonEmptyStr,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Embedding vector dimensions. Changing this requires a DB migration and re-embedding,
|
|
16
|
+
# so it is intentionally a constant rather than a configurable setting.
|
|
17
|
+
EMBEDDING_DIMENSIONS = 512
|
|
18
|
+
|
|
19
|
+
# Default sliding window parameters for extraction
|
|
20
|
+
DEFAULT_WINDOW_SIZE = 10
|
|
21
|
+
DEFAULT_STRIDE_SIZE = 5
|
|
22
|
+
|
|
23
|
+
# Deprecated aliases kept for older imports.
|
|
24
|
+
DEFAULT_BATCH_SIZE = DEFAULT_WINDOW_SIZE
|
|
25
|
+
DEFAULT_BATCH_INTERVAL = DEFAULT_STRIDE_SIZE
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ExtractionPreset(StrEnum):
|
|
29
|
+
"""Named extraction presets that bundle window_size and stride_size.
|
|
30
|
+
|
|
31
|
+
Each preset targets a specific conversation pattern:
|
|
32
|
+
- quick_chat: Short conversations (support bots, quick Q&A)
|
|
33
|
+
- standard: General-purpose conversational agents (default)
|
|
34
|
+
- long_form: Long conversations (coding assistants, research)
|
|
35
|
+
- high_volume: High-traffic agents (1000+ daily interactions)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
QUICK_CHAT = "quick_chat"
|
|
39
|
+
STANDARD = "standard"
|
|
40
|
+
LONG_FORM = "long_form"
|
|
41
|
+
HIGH_VOLUME = "high_volume"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Preset parameter values: (window_size, stride_size)
|
|
45
|
+
_PRESET_VALUES: dict[ExtractionPreset, tuple[int, int]] = {
|
|
46
|
+
ExtractionPreset.QUICK_CHAT: (5, 3),
|
|
47
|
+
ExtractionPreset.STANDARD: (DEFAULT_WINDOW_SIZE, DEFAULT_STRIDE_SIZE),
|
|
48
|
+
ExtractionPreset.LONG_FORM: (25, 10),
|
|
49
|
+
ExtractionPreset.HIGH_VOLUME: (15, 8),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# Field migration maps (old stored JSON name → new Python attr name)
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
_CONFIG_FIELD_MIGRATION: dict[str, str] = {
|
|
57
|
+
"batch_size": "window_size",
|
|
58
|
+
"batch_interval": "stride_size",
|
|
59
|
+
"extraction_window_size": "window_size",
|
|
60
|
+
"extraction_window_stride": "stride_size",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_AGGREGATOR_FIELD_MIGRATION: dict[str, str] = {
|
|
64
|
+
"min_feedback_threshold": "min_cluster_size",
|
|
65
|
+
"refresh_count": "reaggregation_trigger_count",
|
|
66
|
+
"similarity_threshold": "clustering_similarity",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_EXTRACTOR_OVERRIDE_MIGRATION: dict[str, str] = {
|
|
70
|
+
"batch_size_override": "window_size_override",
|
|
71
|
+
"batch_interval_override": "stride_size_override",
|
|
72
|
+
"extraction_window_size_override": "window_size_override",
|
|
73
|
+
"extraction_window_stride_override": "stride_size_override",
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_PROFILE_CONFIG_FIELD_MIGRATION: dict[str, str] = {
|
|
77
|
+
"profile_content_definition_prompt": "extraction_definition_prompt",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_PLAYBOOK_CONFIG_FIELD_MIGRATION: dict[str, str] = {
|
|
81
|
+
"feedback_definition_prompt": "extraction_definition_prompt",
|
|
82
|
+
"playbook_definition_prompt": "extraction_definition_prompt",
|
|
83
|
+
"feedback_aggregator_config": "aggregation_config",
|
|
84
|
+
"playbook_aggregator_config": "aggregation_config",
|
|
85
|
+
"playbook_name": "extractor_name",
|
|
86
|
+
"feedback_name": "extractor_name",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _migrate_dict(data: Any, mapping: dict[str, str]) -> Any:
|
|
91
|
+
"""Rename old field names to new ones in a raw dict before Pydantic validates.
|
|
92
|
+
|
|
93
|
+
Creates a shallow copy to avoid mutating the caller's dict.
|
|
94
|
+
"""
|
|
95
|
+
if isinstance(data, dict):
|
|
96
|
+
data = dict(data)
|
|
97
|
+
for old, new in mapping.items():
|
|
98
|
+
if old in data and new not in data:
|
|
99
|
+
data[new] = data.pop(old)
|
|
100
|
+
return data
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Retired list-valued config fields and the singular field that replaced them.
|
|
104
|
+
# The first configured entry wins when an old list contains multiple items.
|
|
105
|
+
_LEGACY_SINGLE_CONFIG_FIELDS: tuple[tuple[str, str], ...] = (
|
|
106
|
+
("profile_extractor_configs", "profile_extractor_config"),
|
|
107
|
+
("user_playbook_extractor_configs", "user_playbook_extractor_config"),
|
|
108
|
+
("playbook_configs", "user_playbook_extractor_config"),
|
|
109
|
+
("agent_feedback_configs", "user_playbook_extractor_config"),
|
|
110
|
+
("agent_success_configs", "agent_success_config"),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _first_config_entry(value: Any) -> Any:
|
|
115
|
+
if isinstance(value, list):
|
|
116
|
+
return value[0] if value else None
|
|
117
|
+
return value
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def normalize_legacy_config_shape(data: dict[str, Any]) -> dict[str, Any]:
|
|
121
|
+
"""Map retired list-valued config fields onto current singular fields.
|
|
122
|
+
|
|
123
|
+
This is a stored-data upgrade path applied at storage load boundaries: any
|
|
124
|
+
config persisted before the single-extractor refactor still carries list
|
|
125
|
+
keys (e.g. ``agent_success_configs``) that ``Config`` would otherwise drop
|
|
126
|
+
as unknown fields, silently losing the user's customization. Legacy keys are
|
|
127
|
+
removed from the returned payload and the first configured entry wins.
|
|
128
|
+
|
|
129
|
+
Returns a shallow copy; the caller's dict is not mutated.
|
|
130
|
+
"""
|
|
131
|
+
normalized = dict(data)
|
|
132
|
+
for legacy_field, current_field in _LEGACY_SINGLE_CONFIG_FIELDS:
|
|
133
|
+
if legacy_field not in normalized:
|
|
134
|
+
continue
|
|
135
|
+
if current_field not in normalized:
|
|
136
|
+
normalized[current_field] = _first_config_entry(normalized[legacy_field])
|
|
137
|
+
del normalized[legacy_field]
|
|
138
|
+
return normalized
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class _ExtractorWindowOverrideCompatMixin:
|
|
142
|
+
@property
|
|
143
|
+
def batch_size_override(self) -> int | None:
|
|
144
|
+
"""Deprecated alias for window_size_override."""
|
|
145
|
+
return self.window_size_override # type: ignore[attr-defined]
|
|
146
|
+
|
|
147
|
+
@batch_size_override.setter
|
|
148
|
+
def batch_size_override(self, value: int | None) -> None:
|
|
149
|
+
self.window_size_override = value # type: ignore[attr-defined]
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def batch_interval_override(self) -> int | None:
|
|
153
|
+
"""Deprecated alias for stride_size_override."""
|
|
154
|
+
return self.stride_size_override # type: ignore[attr-defined]
|
|
155
|
+
|
|
156
|
+
@batch_interval_override.setter
|
|
157
|
+
def batch_interval_override(self, value: int | None) -> None:
|
|
158
|
+
self.stride_size_override = value # type: ignore[attr-defined]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class SearchMode(StrEnum):
|
|
162
|
+
"""Search mode for hybrid search functionality.
|
|
163
|
+
|
|
164
|
+
Controls how search queries are processed:
|
|
165
|
+
- VECTOR: Pure vector similarity search using embeddings
|
|
166
|
+
- FTS: Pure full-text search using PostgreSQL tsvector
|
|
167
|
+
- HYBRID: Combined search using Reciprocal Rank Fusion (RRF)
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
VECTOR = "vector"
|
|
171
|
+
FTS = "fts"
|
|
172
|
+
HYBRID = "hybrid"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dataclass
|
|
176
|
+
class SearchOptions:
|
|
177
|
+
"""Engine-level search parameters that are pre-computed or not part of the API request."""
|
|
178
|
+
|
|
179
|
+
query_embedding: list[float] | None = field(default=None)
|
|
180
|
+
search_mode: SearchMode = field(default=SearchMode.HYBRID)
|
|
181
|
+
fresh: bool = field(default=False)
|
|
182
|
+
rrf_k: int = field(default=60)
|
|
183
|
+
vector_weight: float = field(default=1.0)
|
|
184
|
+
fts_weight: float = field(default=1.0)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class StorageConfigTest(IntEnum):
|
|
188
|
+
UNKNOWN = 0
|
|
189
|
+
INCOMPLETE = 1
|
|
190
|
+
FAILED = 2
|
|
191
|
+
SUCCEEDED = 3
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class StorageConfigSQLite(BaseModel):
|
|
195
|
+
"""SQLite storage configuration."""
|
|
196
|
+
|
|
197
|
+
db_path: str | None = None # None = use LOCAL_STORAGE_PATH env var default
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class StorageConfigSupabase(BaseModel):
|
|
201
|
+
model_config = ConfigDict(populate_by_name=True, serialize_by_alias=True)
|
|
202
|
+
|
|
203
|
+
url: NonEmptyStr
|
|
204
|
+
key: NonEmptyStr
|
|
205
|
+
db_url: NonEmptyStr
|
|
206
|
+
schema_name: str | None = Field(default=None, alias="schema")
|
|
207
|
+
read_url: NonEmptyStr | None = None
|
|
208
|
+
read_key: NonEmptyStr | None = None
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class StorageConfigPostgres(BaseModel):
|
|
212
|
+
model_config = ConfigDict(populate_by_name=True, serialize_by_alias=True)
|
|
213
|
+
|
|
214
|
+
storage_type: Literal["postgres"] = Field(default="postgres", alias="type")
|
|
215
|
+
db_url: NonEmptyStr
|
|
216
|
+
schema_name: str | None = Field(default=None, alias="schema")
|
|
217
|
+
pool_size: int = Field(default=10, ge=1)
|
|
218
|
+
# Seconds a query waits for a free pooled connection before failing. Bounds the
|
|
219
|
+
# back-pressure applied when concurrent queries exceed pool_size.
|
|
220
|
+
pool_acquire_timeout: float = Field(default=30.0, gt=0)
|
|
221
|
+
read_db_url: NonEmptyStr | None = None
|
|
222
|
+
read_pool_size: int | None = Field(default=None, ge=1)
|
|
223
|
+
read_pool_acquire_timeout: float | None = Field(default=None, gt=0)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class StorageConfigManagedSupabase(BaseModel):
|
|
227
|
+
"""Redacted API response for platform-managed Supabase storage."""
|
|
228
|
+
|
|
229
|
+
managed_by: Literal["platform"]
|
|
230
|
+
schema_present: bool = True
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
StorageConfig = (
|
|
234
|
+
StorageConfigSQLite
|
|
235
|
+
| StorageConfigSupabase
|
|
236
|
+
| StorageConfigPostgres
|
|
237
|
+
| StorageConfigManagedSupabase
|
|
238
|
+
| None
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class AzureOpenAIConfig(BaseModel):
|
|
243
|
+
"""Azure OpenAI specific configuration."""
|
|
244
|
+
|
|
245
|
+
api_key: NonEmptyStr
|
|
246
|
+
endpoint: SafeHttpUrl # e.g., "https://your-resource.openai.azure.com/"
|
|
247
|
+
api_version: str = "2024-02-15-preview"
|
|
248
|
+
deployment_name: str | None = None # Optional, can be specified per request
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class OpenAIConfig(BaseModel):
|
|
252
|
+
"""OpenAI API configuration (direct or Azure)."""
|
|
253
|
+
|
|
254
|
+
api_key: str | None = None # Direct OpenAI API key
|
|
255
|
+
azure_config: AzureOpenAIConfig | None = None # Azure OpenAI configuration
|
|
256
|
+
|
|
257
|
+
@model_validator(mode="after")
|
|
258
|
+
def check_at_least_one_auth(self) -> Self:
|
|
259
|
+
"""Validate that at least one of api_key or azure_config is provided."""
|
|
260
|
+
if self.api_key is not None and not self.api_key.strip():
|
|
261
|
+
self.api_key = None
|
|
262
|
+
if not self.api_key and not self.azure_config:
|
|
263
|
+
raise ValueError(
|
|
264
|
+
"At least one of 'api_key' or 'azure_config' must be provided"
|
|
265
|
+
)
|
|
266
|
+
return self
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class AnthropicConfig(BaseModel):
|
|
270
|
+
"""Anthropic API configuration."""
|
|
271
|
+
|
|
272
|
+
api_key: NonEmptyStr
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class OpenRouterConfig(BaseModel):
|
|
276
|
+
"""OpenRouter API configuration."""
|
|
277
|
+
|
|
278
|
+
api_key: NonEmptyStr
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class GeminiConfig(BaseModel):
|
|
282
|
+
"""Google Gemini API configuration."""
|
|
283
|
+
|
|
284
|
+
api_key: NonEmptyStr
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class MiniMaxConfig(BaseModel):
|
|
288
|
+
"""MiniMax API configuration."""
|
|
289
|
+
|
|
290
|
+
api_key: NonEmptyStr
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class DeepSeekConfig(BaseModel):
|
|
294
|
+
"""DeepSeek API configuration."""
|
|
295
|
+
|
|
296
|
+
api_key: NonEmptyStr
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class DashScopeConfig(BaseModel):
|
|
300
|
+
"""Alibaba DashScope (Qwen) API configuration."""
|
|
301
|
+
|
|
302
|
+
api_key: NonEmptyStr
|
|
303
|
+
api_base: str | None = None # None = default; set for intl vs China endpoint
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class ZAIConfig(BaseModel):
|
|
307
|
+
"""Zhipu AI (GLM) API configuration."""
|
|
308
|
+
|
|
309
|
+
api_key: NonEmptyStr
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class MoonshotConfig(BaseModel):
|
|
313
|
+
"""Moonshot (Kimi) API configuration."""
|
|
314
|
+
|
|
315
|
+
api_key: NonEmptyStr
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class XAIConfig(BaseModel):
|
|
319
|
+
"""xAI (Grok) API configuration."""
|
|
320
|
+
|
|
321
|
+
api_key: NonEmptyStr
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class CustomEndpointConfig(BaseModel):
|
|
325
|
+
"""Custom OpenAI-compatible endpoint configuration.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
model (str): Model name to use (e.g., 'openai/mistral', 'mistral'). Passed as-is to LiteLLM.
|
|
329
|
+
api_key (str): API key for the custom endpoint.
|
|
330
|
+
api_base (SafeHttpUrl): Base URL of the custom endpoint (e.g., 'http://localhost:8000/v1').
|
|
331
|
+
Validated against SSRF: always blocks cloud metadata endpoints;
|
|
332
|
+
blocks private IPs when REFLEXIO_BLOCK_PRIVATE_URLS=true.
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
model: NonEmptyStr
|
|
336
|
+
api_key: NonEmptyStr
|
|
337
|
+
api_base: SafeHttpUrl
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class APIKeyConfig(BaseModel):
|
|
341
|
+
"""
|
|
342
|
+
API key configuration for LLM providers.
|
|
343
|
+
|
|
344
|
+
Supports OpenAI (direct and Azure), Anthropic, OpenRouter, Google Gemini, MiniMax,
|
|
345
|
+
DeepSeek, DashScope (Qwen), Zhipu AI (GLM), Moonshot (Kimi), xAI (Grok), and custom
|
|
346
|
+
OpenAI-compatible endpoints. When custom_endpoint is configured with non-empty fields,
|
|
347
|
+
it takes priority over all other providers for LLM completion calls (but not embeddings).
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
custom_endpoint: CustomEndpointConfig | None = None
|
|
351
|
+
openai: OpenAIConfig | None = None
|
|
352
|
+
anthropic: AnthropicConfig | None = None
|
|
353
|
+
openrouter: OpenRouterConfig | None = None
|
|
354
|
+
gemini: GeminiConfig | None = None
|
|
355
|
+
minimax: MiniMaxConfig | None = None
|
|
356
|
+
deepseek: DeepSeekConfig | None = None
|
|
357
|
+
dashscope: DashScopeConfig | None = None
|
|
358
|
+
zai: ZAIConfig | None = None
|
|
359
|
+
moonshot: MoonshotConfig | None = None
|
|
360
|
+
xai: XAIConfig | None = None
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
class DeduplicationConfig(BaseModel):
|
|
364
|
+
"""Configuration for playbook deduplication search parameters.
|
|
365
|
+
|
|
366
|
+
Controls the hybrid search behavior when looking for existing playbooks
|
|
367
|
+
to deduplicate against.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
search_threshold: Minimum similarity score for search results (0.0-1.0).
|
|
371
|
+
search_top_k: Maximum number of existing playbooks to retrieve per new playbook.
|
|
372
|
+
max_unified_content_chars: Soft cap on a unified playbook's content length.
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
search_threshold: float = Field(
|
|
376
|
+
default=0.4,
|
|
377
|
+
ge=0.0,
|
|
378
|
+
le=1.0,
|
|
379
|
+
description="Minimum similarity score for deduplication search results.",
|
|
380
|
+
)
|
|
381
|
+
search_top_k: int = Field(
|
|
382
|
+
default=5,
|
|
383
|
+
ge=1,
|
|
384
|
+
description="Maximum number of existing playbooks to retrieve per new playbook.",
|
|
385
|
+
)
|
|
386
|
+
max_unified_content_chars: int = Field(
|
|
387
|
+
default=1200,
|
|
388
|
+
gt=0,
|
|
389
|
+
description=(
|
|
390
|
+
"Soft cap on a unified playbook's content length; unify that would "
|
|
391
|
+
"exceed it should prefer differentiate/keep-separate. Enforced as a "
|
|
392
|
+
"warning-only backstop in the consolidator apply path."
|
|
393
|
+
),
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
SINGLETON_PROFILE_EXTRACTOR_NAME = "profile"
|
|
398
|
+
SINGLETON_USER_PLAYBOOK_NAME = "playbook"
|
|
399
|
+
SINGLETON_AGENT_SUCCESS_EVALUATION_NAME = "agent_success"
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
class ProfileExtractorConfig(_ExtractorWindowOverrideCompatMixin, BaseModel):
|
|
403
|
+
# Deprecated: kept for back-compat with stored configs. Extraction is singleton
|
|
404
|
+
# (one profile extractor per org), so the name is accepted but ignored.
|
|
405
|
+
extractor_name: NonEmptyStr | None = None
|
|
406
|
+
extraction_definition_prompt: SanitizedNonEmptyStr
|
|
407
|
+
context_prompt: str | None = None
|
|
408
|
+
metadata_definition_prompt: str | None = None
|
|
409
|
+
should_extract_profile_prompt_override: str | None = None
|
|
410
|
+
request_sources_enabled: list[str] | None = (
|
|
411
|
+
None # default enabled for all sources, if set, only extract profiles from the enabled request sources
|
|
412
|
+
)
|
|
413
|
+
manual_trigger: bool = False # require manual triggering (rerun) to run extraction and skip auto extraction if set to True
|
|
414
|
+
window_size_override: int | None = Field(default=None, gt=0)
|
|
415
|
+
stride_size_override: int | None = Field(default=None, gt=0)
|
|
416
|
+
|
|
417
|
+
@model_validator(mode="before")
|
|
418
|
+
@classmethod
|
|
419
|
+
def _migrate_field_names(cls, data: Any) -> Any:
|
|
420
|
+
data = _migrate_dict(data, _PROFILE_CONFIG_FIELD_MIGRATION)
|
|
421
|
+
return _migrate_dict(data, _EXTRACTOR_OVERRIDE_MIGRATION)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class PlaybookAggregatorConfig(BaseModel):
|
|
425
|
+
min_cluster_size: int = Field(default=2, ge=1)
|
|
426
|
+
reaggregation_trigger_count: int = Field(default=2, ge=1)
|
|
427
|
+
clustering_similarity: float = Field(
|
|
428
|
+
default=0.3,
|
|
429
|
+
ge=0.0,
|
|
430
|
+
le=1.0,
|
|
431
|
+
description=(
|
|
432
|
+
"Cosine similarity threshold for clustering. Higher = tighter clusters. "
|
|
433
|
+
"Default 0.3 is a compromise that works for both cloud embeddings "
|
|
434
|
+
"(OpenAI text-embedding-3-*, Gemini) and the local zero-padded "
|
|
435
|
+
"MiniLM-L6-v2 embedder. Cloud embeddings typically tolerate 0.4-0.6; "
|
|
436
|
+
"the local embedder's 384-dim vectors zero-padded to 512 produce "
|
|
437
|
+
"lower cosine similarities and need ~0.15-0.3 to cluster at all."
|
|
438
|
+
),
|
|
439
|
+
)
|
|
440
|
+
direction_overlap_threshold: float = Field(
|
|
441
|
+
default=0.6,
|
|
442
|
+
ge=0.0,
|
|
443
|
+
le=1.0,
|
|
444
|
+
description="Token overlap threshold for grouping playbooks by direction.",
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
@model_validator(mode="before")
|
|
448
|
+
@classmethod
|
|
449
|
+
def _migrate_field_names(cls, data: Any) -> Any:
|
|
450
|
+
return _migrate_dict(data, _AGGREGATOR_FIELD_MIGRATION)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
class UserPlaybookExtractorConfig(_ExtractorWindowOverrideCompatMixin, BaseModel):
|
|
454
|
+
# Deprecated: kept for back-compat with stored configs. Extraction is singleton
|
|
455
|
+
# (one playbook extractor per org), so the name is accepted but ignored.
|
|
456
|
+
extractor_name: NonEmptyStr | None = None
|
|
457
|
+
extraction_definition_prompt: SanitizedNonEmptyStr
|
|
458
|
+
context_prompt: str | None = None
|
|
459
|
+
metadata_definition_prompt: str | None = None
|
|
460
|
+
aggregation_config: PlaybookAggregatorConfig | None = None
|
|
461
|
+
deduplication_config: DeduplicationConfig | None = None
|
|
462
|
+
request_sources_enabled: list[str] | None = (
|
|
463
|
+
None # default enabled for all sources, if set, only extract user playbooks from the enabled request sources
|
|
464
|
+
)
|
|
465
|
+
window_size_override: int | None = Field(default=None, gt=0)
|
|
466
|
+
stride_size_override: int | None = Field(default=None, gt=0)
|
|
467
|
+
|
|
468
|
+
@model_validator(mode="before")
|
|
469
|
+
@classmethod
|
|
470
|
+
def _migrate_field_names(cls, data: Any) -> Any:
|
|
471
|
+
data = _migrate_dict(data, _PLAYBOOK_CONFIG_FIELD_MIGRATION)
|
|
472
|
+
return _migrate_dict(data, _EXTRACTOR_OVERRIDE_MIGRATION)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
# Backward-compatible alias (deprecated — use UserPlaybookExtractorConfig)
|
|
476
|
+
PlaybookConfig = UserPlaybookExtractorConfig
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class ToolUseConfig(BaseModel):
|
|
480
|
+
tool_name: NonEmptyStr
|
|
481
|
+
tool_description: NonEmptyStr
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
# define what success looks like for agent
|
|
485
|
+
class AgentSuccessConfig(_ExtractorWindowOverrideCompatMixin, BaseModel):
|
|
486
|
+
# Deprecated: kept for back-compat with stored configs. Evaluation is singleton
|
|
487
|
+
# (one agent-success evaluator per org), so the name is accepted but ignored.
|
|
488
|
+
evaluation_name: NonEmptyStr | None = None
|
|
489
|
+
success_definition_prompt: SanitizedNonEmptyStr
|
|
490
|
+
metadata_definition_prompt: str | None = None
|
|
491
|
+
sampling_rate: float = Field(
|
|
492
|
+
default=1.0, ge=0.0, le=1.0
|
|
493
|
+
) # fraction of window of interactions to be sampled for success evaluation
|
|
494
|
+
window_size_override: int | None = Field(default=None, gt=0)
|
|
495
|
+
stride_size_override: int | None = Field(default=None, gt=0)
|
|
496
|
+
|
|
497
|
+
@model_validator(mode="before")
|
|
498
|
+
@classmethod
|
|
499
|
+
def _migrate_field_names(cls, data: Any) -> Any:
|
|
500
|
+
return _migrate_dict(data, _EXTRACTOR_OVERRIDE_MIGRATION)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
class ReflectionConfig(BaseModel):
|
|
504
|
+
"""Configuration for the sliding-window reflection step.
|
|
505
|
+
|
|
506
|
+
Reflection runs inside ``GenerationService.run`` as its own
|
|
507
|
+
sliding-window step (window = global ``window_size``, stride = global
|
|
508
|
+
``stride_size``, bookmark via ``OperationStateManager``). When
|
|
509
|
+
the gate opens and at least one Assistant interaction in the window
|
|
510
|
+
cites a current user playbook / user profile row, the LLM is asked
|
|
511
|
+
whether any cited rows should be replaced. When ``enabled`` is
|
|
512
|
+
False the step short-circuits.
|
|
513
|
+
|
|
514
|
+
Args:
|
|
515
|
+
enabled (bool): Master switch. When False, no LLM call is made.
|
|
516
|
+
model (str | None): Optional model name override. Falls back to
|
|
517
|
+
``LLMConfig.generation_model_name`` and then the site
|
|
518
|
+
default for ``ModelRole.GENERATION`` when None.
|
|
519
|
+
post_horizon_size (int): Minimum interactions after a citation before
|
|
520
|
+
reflection judges it with full confidence. Citations near the recent
|
|
521
|
+
edge of the window with fewer than this many follow-up turns get a
|
|
522
|
+
'last_chance' judgment with the prompt biased toward no_change.
|
|
523
|
+
Set to 0 to disable the filter (legacy behavior).
|
|
524
|
+
max_revisions_per_pass (int): Cap on the number of revision decisions
|
|
525
|
+
applied in a single reflection pass (regularization). Once the cap
|
|
526
|
+
is hit, remaining revision-intent decisions are skipped and counted
|
|
527
|
+
in ``ReflectionResult.capped_count``.
|
|
528
|
+
"""
|
|
529
|
+
|
|
530
|
+
enabled: bool = True
|
|
531
|
+
model: str | None = None
|
|
532
|
+
post_horizon_size: int = Field(
|
|
533
|
+
default=3,
|
|
534
|
+
description=(
|
|
535
|
+
"Minimum interactions after a citation before reflection judges "
|
|
536
|
+
"it with full confidence. Citations near the recent edge of the "
|
|
537
|
+
"window with fewer than this many follow-up turns get a "
|
|
538
|
+
"'last_chance' judgment with the prompt biased toward no_change. "
|
|
539
|
+
"Set to 0 to disable the filter (legacy behavior)."
|
|
540
|
+
),
|
|
541
|
+
ge=0,
|
|
542
|
+
)
|
|
543
|
+
max_revisions_per_pass: int = Field(
|
|
544
|
+
default=8,
|
|
545
|
+
gt=0,
|
|
546
|
+
description=(
|
|
547
|
+
"Cap on revision decisions applied per reflection pass "
|
|
548
|
+
"(regularization; excess are skipped)."
|
|
549
|
+
),
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
class RetrievalFloorConfig(BaseModel):
|
|
554
|
+
"""Read-path relevance floor: drop search results below a per-arm cross-encoder score.
|
|
555
|
+
|
|
556
|
+
Floors are RAW cross-encoder logits (ms-marco-MiniLM), not probabilities. On this
|
|
557
|
+
corpus strongly relevant items score roughly 0..-3, weak/marginal items -3..-5,
|
|
558
|
+
and clear junk -6..-11. A default of -3 keeps strong matches while dropping the
|
|
559
|
+
weak tail that drives false-positive citations. Calibrate per arm on real data.
|
|
560
|
+
"""
|
|
561
|
+
|
|
562
|
+
enabled: bool = True
|
|
563
|
+
pool_size: int = Field(
|
|
564
|
+
default=30,
|
|
565
|
+
gt=0,
|
|
566
|
+
description="Candidates fetched per arm before flooring + cap to top_k.",
|
|
567
|
+
)
|
|
568
|
+
profile_floor: float = -3.0
|
|
569
|
+
user_playbook_floor: float = -3.0
|
|
570
|
+
agent_playbook_floor: float = -3.0
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
class PlaybookOptimizerConfig(BaseModel):
|
|
574
|
+
"""Configuration for GEPA-backed playbook content optimization.
|
|
575
|
+
|
|
576
|
+
The optimizer is opt-in (``enabled=False`` by default) and requires
|
|
577
|
+
*exactly one* assistant backend to actually do anything. The two
|
|
578
|
+
backends are mutually exclusive — see ``check_single_assistant_backend``
|
|
579
|
+
below.
|
|
580
|
+
"""
|
|
581
|
+
|
|
582
|
+
# --- gating ------------------------------------------------------------
|
|
583
|
+
enabled: bool = False
|
|
584
|
+
optimize_agent_playbooks: bool = False
|
|
585
|
+
optimize_user_playbooks: bool = False
|
|
586
|
+
auto_update_pending_agent_playbooks: bool = True
|
|
587
|
+
auto_update_user_playbooks: bool = False
|
|
588
|
+
|
|
589
|
+
# --- GEPA budget -------------------------------------------------------
|
|
590
|
+
max_metric_calls: int = Field(default=20, gt=0)
|
|
591
|
+
max_turns: int = Field(default=4, gt=0)
|
|
592
|
+
early_stop_score: float = Field(default=0.9, ge=0.0, le=1.0)
|
|
593
|
+
reflection_minibatch_size: int = Field(default=2, gt=0)
|
|
594
|
+
max_validation_windows: int = Field(default=2, gt=0)
|
|
595
|
+
min_commit_windows: int = Field(default=2, gt=0)
|
|
596
|
+
min_commit_score: float = Field(default=0.75, ge=0.0, le=1.0)
|
|
597
|
+
min_commit_likert: int = Field(default=4, ge=1, le=5)
|
|
598
|
+
use_merge: bool = True
|
|
599
|
+
max_merge_invocations: int = Field(default=5, ge=0)
|
|
600
|
+
reflection_model: str | None = None
|
|
601
|
+
|
|
602
|
+
# --- assistant backend: webhook ---------------------------------------
|
|
603
|
+
webhook_url: str | None = None
|
|
604
|
+
webhook_auth_header: str | None = None
|
|
605
|
+
# The webhook_* timeout/retry/backoff fields apply to BOTH backends —
|
|
606
|
+
# the prefix is preserved purely to avoid a config-schema migration.
|
|
607
|
+
webhook_timeout_seconds: int = Field(default=60, gt=0)
|
|
608
|
+
webhook_max_retries: int = Field(default=3, ge=0)
|
|
609
|
+
webhook_backoff_base_seconds: float = Field(default=1.0, ge=0.0)
|
|
610
|
+
|
|
611
|
+
# --- assistant backend: local script ----------------------------------
|
|
612
|
+
# Absolute path to the executable. The optimizer spawns
|
|
613
|
+
# [assistant_script_path, *assistant_script_args] per turn, hands the
|
|
614
|
+
# rollout payload over stdin, and reads {"content": "..."} from stdout.
|
|
615
|
+
# See playbook_optimizer/assistant_webhook.py::LocalScriptAssistant.
|
|
616
|
+
assistant_script_path: str | None = None
|
|
617
|
+
assistant_script_args: list[str] = Field(default_factory=list)
|
|
618
|
+
|
|
619
|
+
# --- scheduler --------------------------------------------------------
|
|
620
|
+
scheduler_jitter_seconds: float = Field(default=1.0, ge=0.0)
|
|
621
|
+
cooldown_after_aborts_seconds: int = Field(default=3600, ge=0)
|
|
622
|
+
abort_cooldown_threshold: int = Field(default=2, ge=1)
|
|
623
|
+
|
|
624
|
+
@model_validator(mode="after")
|
|
625
|
+
def check_single_assistant_backend(self) -> Self:
|
|
626
|
+
# Two backends configured at once would create ambiguous behavior
|
|
627
|
+
# (which one wins?), so reject at load time rather than picking one
|
|
628
|
+
# silently in _create_assistant.
|
|
629
|
+
if self.webhook_url and self.assistant_script_path:
|
|
630
|
+
raise ValueError(
|
|
631
|
+
"Configure only one playbook optimizer assistant backend: "
|
|
632
|
+
"webhook_url or assistant_script_path"
|
|
633
|
+
)
|
|
634
|
+
return self
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
@dataclass(frozen=True)
|
|
638
|
+
class EffectivePendingToolCallConfig:
|
|
639
|
+
"""Resolved pending-tool-call settings after applying tool overrides."""
|
|
640
|
+
|
|
641
|
+
max_pending_followups_per_scope: int
|
|
642
|
+
pending_ttl_seconds: int
|
|
643
|
+
dedup_cache_seconds: int
|
|
644
|
+
prior_answer_valid_seconds: int
|
|
645
|
+
similarity_threshold: float
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
class PendingToolCallToolOverrideConfig(BaseModel):
|
|
649
|
+
"""Optional per-tool pending-call limits."""
|
|
650
|
+
|
|
651
|
+
max_pending_followups_per_scope: int | None = Field(default=None, gt=0)
|
|
652
|
+
pending_ttl_seconds: int | None = Field(default=None, gt=0)
|
|
653
|
+
dedup_cache_seconds: int | None = Field(default=None, gt=0)
|
|
654
|
+
prior_answer_valid_seconds: int | None = Field(default=None, gt=0)
|
|
655
|
+
similarity_threshold: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
class PendingToolCallConfig(BaseModel):
|
|
659
|
+
"""Configuration for non-blocking pending tool calls."""
|
|
660
|
+
|
|
661
|
+
enabled: bool = False
|
|
662
|
+
max_pending_followups_per_scope: int = Field(default=10, gt=0)
|
|
663
|
+
pending_ttl_seconds: int = Field(default=86_400, gt=0)
|
|
664
|
+
dedup_cache_seconds: int = Field(default=300, gt=0)
|
|
665
|
+
prior_answer_valid_seconds: int = Field(default=2_592_000, gt=0)
|
|
666
|
+
similarity_threshold: float = Field(default=0.0, ge=0.0, le=1.0)
|
|
667
|
+
resume_poll_interval_seconds: float = Field(default=5.0, gt=0)
|
|
668
|
+
resume_claim_ttl_seconds: int = Field(default=600, gt=0)
|
|
669
|
+
max_resume_attempts: int = Field(default=3, ge=0)
|
|
670
|
+
max_finalization_attempts: int = Field(default=3, ge=0)
|
|
671
|
+
hmac_secrets: list[str] = Field(default_factory=list)
|
|
672
|
+
tool_overrides: dict[str, PendingToolCallToolOverrideConfig] = Field(
|
|
673
|
+
default_factory=dict
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
def for_tool(self, tool_name: str) -> EffectivePendingToolCallConfig:
|
|
677
|
+
"""Return base settings with an optional exact tool-name override."""
|
|
678
|
+
override = self.tool_overrides.get(tool_name)
|
|
679
|
+
|
|
680
|
+
def _value(name: str) -> Any:
|
|
681
|
+
if override is not None:
|
|
682
|
+
override_value = getattr(override, name)
|
|
683
|
+
if override_value is not None:
|
|
684
|
+
return override_value
|
|
685
|
+
return getattr(self, name)
|
|
686
|
+
|
|
687
|
+
return EffectivePendingToolCallConfig(
|
|
688
|
+
max_pending_followups_per_scope=_value("max_pending_followups_per_scope"),
|
|
689
|
+
pending_ttl_seconds=_value("pending_ttl_seconds"),
|
|
690
|
+
dedup_cache_seconds=_value("dedup_cache_seconds"),
|
|
691
|
+
prior_answer_valid_seconds=_value("prior_answer_valid_seconds"),
|
|
692
|
+
similarity_threshold=_value("similarity_threshold"),
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
class LLMConfig(BaseModel):
|
|
697
|
+
"""
|
|
698
|
+
LLM model configuration overrides.
|
|
699
|
+
|
|
700
|
+
These settings override the default model names from llm_model_setting.json site variable.
|
|
701
|
+
If a field is None, the default from site variable is used.
|
|
702
|
+
"""
|
|
703
|
+
|
|
704
|
+
should_run_model_name: str | None = None # Model for "should run extraction" checks
|
|
705
|
+
generation_model_name: str | None = (
|
|
706
|
+
None # Model for generation and evaluation tasks
|
|
707
|
+
)
|
|
708
|
+
embedding_model_name: str | None = None # Model for embedding generation
|
|
709
|
+
pre_retrieval_model_name: str | None = (
|
|
710
|
+
None # Model for pre-retrieval query reformulation
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def _default_profile_extractor_config() -> ProfileExtractorConfig:
|
|
715
|
+
return ProfileExtractorConfig(
|
|
716
|
+
extraction_definition_prompt=(
|
|
717
|
+
"Extract key information about the user and their working "
|
|
718
|
+
"environment: name, role, preferences, and stable facts the "
|
|
719
|
+
"agent needs to know to serve the user correctly — including "
|
|
720
|
+
"data/schema details (table names, column types, units, join "
|
|
721
|
+
"paths), metric definitions the user enforces, and tool "
|
|
722
|
+
"quirks or workarounds the user relies on. Do NOT extract "
|
|
723
|
+
"behavioral rules for the agent (those belong in the "
|
|
724
|
+
"playbook extractor)."
|
|
725
|
+
),
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def _default_user_playbook_extractor_config() -> UserPlaybookExtractorConfig:
|
|
730
|
+
return UserPlaybookExtractorConfig(
|
|
731
|
+
extraction_definition_prompt="Extract playbook rules about agent performance, including areas where the agent was helpful, areas for improvement, and any issues encountered during the interaction.",
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
class Config(BaseModel):
|
|
736
|
+
# define where user configuration is stored at
|
|
737
|
+
storage_config: StorageConfig
|
|
738
|
+
storage_config_test: StorageConfigTest | None = StorageConfigTest.UNKNOWN
|
|
739
|
+
# define agent working environment, tool can use and action space
|
|
740
|
+
agent_context_prompt: str | None = None
|
|
741
|
+
# tools agent can use (shared across success evaluation and playbook extraction)
|
|
742
|
+
tool_can_use: list[ToolUseConfig] | None = None
|
|
743
|
+
# user level memory
|
|
744
|
+
profile_extractor_config: ProfileExtractorConfig | None = Field(
|
|
745
|
+
default_factory=_default_profile_extractor_config
|
|
746
|
+
)
|
|
747
|
+
# user playbook extraction
|
|
748
|
+
user_playbook_extractor_config: UserPlaybookExtractorConfig | None = Field(
|
|
749
|
+
default_factory=_default_user_playbook_extractor_config
|
|
750
|
+
)
|
|
751
|
+
# agent level success
|
|
752
|
+
agent_success_config: AgentSuccessConfig | None = None
|
|
753
|
+
# extraction preset — selects bundled window_size/stride_size values
|
|
754
|
+
extraction_preset: ExtractionPreset | None = None
|
|
755
|
+
# extraction parameters
|
|
756
|
+
window_size: int = Field(default=DEFAULT_WINDOW_SIZE, gt=0)
|
|
757
|
+
stride_size: int = Field(default=DEFAULT_STRIDE_SIZE, gt=0)
|
|
758
|
+
# API key configuration for LLM providers
|
|
759
|
+
api_key_config: APIKeyConfig | None = None
|
|
760
|
+
# LLM model configuration overrides
|
|
761
|
+
llm_config: LLMConfig | None = None
|
|
762
|
+
# Post-publish reflection service configuration
|
|
763
|
+
reflection_config: ReflectionConfig = Field(default_factory=ReflectionConfig)
|
|
764
|
+
# Read-path relevance floor (per-arm cross-encoder score cutoff)
|
|
765
|
+
retrieval_floor: RetrievalFloorConfig = Field(default_factory=RetrievalFloorConfig)
|
|
766
|
+
# Optional GEPA-backed playbook content optimizer
|
|
767
|
+
playbook_optimizer_config: PlaybookOptimizerConfig = Field(
|
|
768
|
+
default_factory=PlaybookOptimizerConfig
|
|
769
|
+
)
|
|
770
|
+
# Optional non-blocking async information tools for classic extraction.
|
|
771
|
+
pending_tool_call_config: PendingToolCallConfig = Field(
|
|
772
|
+
default_factory=PendingToolCallConfig
|
|
773
|
+
)
|
|
774
|
+
# Skip the LLM pre-extraction eligibility check (always run extraction)
|
|
775
|
+
skip_should_run_check: bool = False
|
|
776
|
+
# Enable storage-time document expansion for improved FTS recall
|
|
777
|
+
enable_document_expansion: bool = False
|
|
778
|
+
# Whether this org has opted into shadow-mode runs. Drives /healthz/eval
|
|
779
|
+
# liveness derivation and the /api/get_evaluation_overview hero state
|
|
780
|
+
# machine. When True, each publish optionally schedules a parallel
|
|
781
|
+
# "without Reflexio" generation for side-by-side comparison.
|
|
782
|
+
shadow_mode_enabled: bool = False
|
|
783
|
+
eval_sample_n_per_stratum: int = Field(
|
|
784
|
+
default=200,
|
|
785
|
+
gt=0,
|
|
786
|
+
description=(
|
|
787
|
+
"F3: stratified-sample cap per (day × group) stratum in the regen "
|
|
788
|
+
"pipeline. Strata with fewer items are kept whole. Predictable cost "
|
|
789
|
+
"regardless of traffic volume."
|
|
790
|
+
),
|
|
791
|
+
)
|
|
792
|
+
eval_concurrency_limit: int = Field(
|
|
793
|
+
default=10,
|
|
794
|
+
gt=0,
|
|
795
|
+
description=(
|
|
796
|
+
"F3: max simultaneous LLM judge calls in flight per regen job, "
|
|
797
|
+
"enforced via a ThreadPoolExecutor. Bound to respect provider "
|
|
798
|
+
"rate limits."
|
|
799
|
+
),
|
|
800
|
+
)
|
|
801
|
+
shadow_comparison_judge_prompt_version: NonEmptyStr = Field(
|
|
802
|
+
default="v1.0.0",
|
|
803
|
+
description=(
|
|
804
|
+
"F1: pinned judge prompt version for per-turn shadow comparison. "
|
|
805
|
+
"Verdicts are stored with the version that produced them; the "
|
|
806
|
+
"dashboard filters to this org's current pinned version so a "
|
|
807
|
+
"future rubric bump doesn't silently mix epochs into the headline."
|
|
808
|
+
),
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
@model_validator(mode="before")
|
|
812
|
+
@classmethod
|
|
813
|
+
def _migrate_field_names(cls, data: Any) -> Any:
|
|
814
|
+
"""Rename old field names from stored JSON to current names.
|
|
815
|
+
|
|
816
|
+
Also strips None values for fields that have non-optional defaults,
|
|
817
|
+
so rows missing these columns fall back to defaults instead of
|
|
818
|
+
failing validation.
|
|
819
|
+
"""
|
|
820
|
+
data = _migrate_dict(data, _CONFIG_FIELD_MIGRATION)
|
|
821
|
+
if isinstance(data, dict):
|
|
822
|
+
for key in (
|
|
823
|
+
"window_size",
|
|
824
|
+
"stride_size",
|
|
825
|
+
"reflection_config",
|
|
826
|
+
"playbook_optimizer_config",
|
|
827
|
+
"pending_tool_call_config",
|
|
828
|
+
"retrieval_floor",
|
|
829
|
+
):
|
|
830
|
+
if key in data and data[key] is None:
|
|
831
|
+
del data[key]
|
|
832
|
+
return data
|
|
833
|
+
|
|
834
|
+
@model_validator(mode="after")
|
|
835
|
+
def apply_extraction_preset(self) -> Self:
|
|
836
|
+
"""Apply preset values when window_size/stride_size are at defaults.
|
|
837
|
+
|
|
838
|
+
If a preset is selected but the user also explicitly set window_size or
|
|
839
|
+
stride_size, the explicit values win (checked via model_fields_set).
|
|
840
|
+
"""
|
|
841
|
+
if self.extraction_preset is None:
|
|
842
|
+
return self
|
|
843
|
+
|
|
844
|
+
preset_values = _PRESET_VALUES.get(self.extraction_preset)
|
|
845
|
+
if preset_values is None:
|
|
846
|
+
return self
|
|
847
|
+
|
|
848
|
+
preset_window_size, preset_stride_size = preset_values
|
|
849
|
+
if "window_size" not in self.model_fields_set:
|
|
850
|
+
self.window_size = preset_window_size
|
|
851
|
+
if "stride_size" not in self.model_fields_set:
|
|
852
|
+
self.stride_size = preset_stride_size
|
|
853
|
+
|
|
854
|
+
return self
|
|
855
|
+
|
|
856
|
+
@model_validator(mode="after")
|
|
857
|
+
def check_stride_size_le_window_size(self) -> Self:
|
|
858
|
+
"""Validate that stride_size <= window_size."""
|
|
859
|
+
if self.stride_size > self.window_size:
|
|
860
|
+
raise ValueError("stride_size must be <= window_size")
|
|
861
|
+
return self
|
|
862
|
+
|
|
863
|
+
@model_validator(mode="after")
|
|
864
|
+
def check_pending_tool_calls_storage_backend(self) -> Self:
|
|
865
|
+
"""Pending tool calls require a database-backed storage backend.
|
|
866
|
+
|
|
867
|
+
``storage_config is None`` is allowed: in enterprise deployments storage
|
|
868
|
+
is configured centrally (via ``REFLEXIO_STORAGE``) and the per-org config
|
|
869
|
+
blob carries ``None`` rather than a concrete backend. The only removed
|
|
870
|
+
non-database backend (``disk``) is no longer representable as a
|
|
871
|
+
``StorageConfig``, so a ``None`` here always denotes a deployment-managed
|
|
872
|
+
database backend (sqlite/supabase/postgres).
|
|
873
|
+
"""
|
|
874
|
+
if (
|
|
875
|
+
self.pending_tool_call_config.enabled
|
|
876
|
+
and self.storage_config is not None
|
|
877
|
+
and not isinstance(
|
|
878
|
+
self.storage_config,
|
|
879
|
+
(
|
|
880
|
+
StorageConfigSQLite,
|
|
881
|
+
StorageConfigSupabase,
|
|
882
|
+
StorageConfigPostgres,
|
|
883
|
+
StorageConfigManagedSupabase,
|
|
884
|
+
),
|
|
885
|
+
)
|
|
886
|
+
):
|
|
887
|
+
raise ValueError(
|
|
888
|
+
"pending_tool_call_config.enabled requires sqlite, supabase, or postgres storage"
|
|
889
|
+
)
|
|
890
|
+
return self
|
|
891
|
+
|
|
892
|
+
@property
|
|
893
|
+
def batch_size(self) -> int:
|
|
894
|
+
"""Deprecated alias for window_size."""
|
|
895
|
+
return self.window_size
|
|
896
|
+
|
|
897
|
+
@batch_size.setter
|
|
898
|
+
def batch_size(self, value: int) -> None:
|
|
899
|
+
self.window_size = value
|
|
900
|
+
|
|
901
|
+
@property
|
|
902
|
+
def batch_interval(self) -> int:
|
|
903
|
+
"""Deprecated alias for stride_size."""
|
|
904
|
+
return self.stride_size
|
|
905
|
+
|
|
906
|
+
@batch_interval.setter
|
|
907
|
+
def batch_interval(self, value: int) -> None:
|
|
908
|
+
self.stride_size = value
|