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
package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
"""Regenerate job registry + worker for replaying the LLM judge.
|
|
2
|
+
|
|
3
|
+
In-memory only; process-local. Survives the worker thread but not a
|
|
4
|
+
backend restart. v2 will move job state to storage.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import random
|
|
11
|
+
import threading
|
|
12
|
+
import time
|
|
13
|
+
import uuid
|
|
14
|
+
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from typing import Any, Literal
|
|
17
|
+
|
|
18
|
+
from reflexio.models.api_schema.internal_schema import SessionDescriptor
|
|
19
|
+
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
20
|
+
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
21
|
+
from reflexio.server.services.agent_success_evaluation.group_evaluation_runner import (
|
|
22
|
+
run_group_evaluation,
|
|
23
|
+
)
|
|
24
|
+
from reflexio.server.services.evaluation_overview.eval_sampler import (
|
|
25
|
+
SampleCandidate,
|
|
26
|
+
sample_candidates,
|
|
27
|
+
)
|
|
28
|
+
from reflexio.server.services.storage.storage_base import BaseStorage
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
JobStatus = Literal["running", "completed", "cancelled", "error"]
|
|
33
|
+
"""Lifecycle states for a regenerate job.
|
|
34
|
+
|
|
35
|
+
``"completed"`` means the worker loop finished iterating, regardless of whether
|
|
36
|
+
every session succeeded — per-session pass/fail counts are in the ``completed``
|
|
37
|
+
and ``failed`` counters. ``"error"`` means the worker itself crashed before or
|
|
38
|
+
during iteration (e.g. storage was unavailable). ``"cancelled"`` means a caller
|
|
39
|
+
set the cancel event and the worker observed it between sessions.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
DEFAULT_TTL_SECONDS = 3600
|
|
43
|
+
_FAILURE_CAP = 50
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class JobFailure:
|
|
48
|
+
session_id: str
|
|
49
|
+
reason: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class RegenJob:
|
|
54
|
+
job_id: str
|
|
55
|
+
org_id: str
|
|
56
|
+
from_ts: int
|
|
57
|
+
to_ts: int
|
|
58
|
+
status: JobStatus
|
|
59
|
+
total: int
|
|
60
|
+
completed: int = 0
|
|
61
|
+
failed: int = 0
|
|
62
|
+
failures: list[JobFailure] = field(default_factory=list)
|
|
63
|
+
cancel_event: threading.Event = field(default_factory=threading.Event)
|
|
64
|
+
started_at: float = field(default_factory=time.time)
|
|
65
|
+
"""Unix seconds (wall clock) at job creation — returned to API clients."""
|
|
66
|
+
finished_at: float | None = None
|
|
67
|
+
"""Unix seconds (wall clock) when the worker exited; ``None`` while running."""
|
|
68
|
+
total_candidates: int = 0
|
|
69
|
+
"""Total candidate sessions discovered in the (from_ts, to_ts) window before sampling."""
|
|
70
|
+
sampled_count: int = 0
|
|
71
|
+
"""Number of sessions actually sampled from the candidate pool for this job."""
|
|
72
|
+
concurrency_limit: int = 0
|
|
73
|
+
"""Worker concurrency cap applied to this job (0 = unset/sequential)."""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class RegenJobRegistry:
|
|
77
|
+
"""Process-local job registry. One active singleton job per org."""
|
|
78
|
+
|
|
79
|
+
def __init__(self) -> None:
|
|
80
|
+
self._jobs: dict[str, RegenJob] = {}
|
|
81
|
+
self._by_org: dict[str, str] = {}
|
|
82
|
+
self._lock = threading.Lock()
|
|
83
|
+
|
|
84
|
+
def create(
|
|
85
|
+
self,
|
|
86
|
+
*,
|
|
87
|
+
org_id: str,
|
|
88
|
+
from_ts: int,
|
|
89
|
+
to_ts: int,
|
|
90
|
+
total: int,
|
|
91
|
+
) -> RegenJob:
|
|
92
|
+
"""Register a new running job. Raises RuntimeError when an actively-running
|
|
93
|
+
job exists for the org.
|
|
94
|
+
|
|
95
|
+
Only *running* jobs block; a previous completed/cancelled/errored job for
|
|
96
|
+
the same key is replaced. Eviction by TTL is a separate cleanup concern —
|
|
97
|
+
we don't want users to wait an hour after a completed run before they can
|
|
98
|
+
regenerate again.
|
|
99
|
+
"""
|
|
100
|
+
with self._lock:
|
|
101
|
+
self._evict_completed_locked(DEFAULT_TTL_SECONDS)
|
|
102
|
+
key = org_id
|
|
103
|
+
active = self._active_job_for_locked(key)
|
|
104
|
+
if active is not None:
|
|
105
|
+
raise RuntimeError("A regenerate is already running for this org")
|
|
106
|
+
job = RegenJob(
|
|
107
|
+
job_id=uuid.uuid4().hex,
|
|
108
|
+
org_id=org_id,
|
|
109
|
+
from_ts=from_ts,
|
|
110
|
+
to_ts=to_ts,
|
|
111
|
+
status="running",
|
|
112
|
+
total=total,
|
|
113
|
+
)
|
|
114
|
+
self._jobs[job.job_id] = job
|
|
115
|
+
self._by_org[key] = job.job_id
|
|
116
|
+
return job
|
|
117
|
+
|
|
118
|
+
def get(self, job_id: str) -> RegenJob | None:
|
|
119
|
+
with self._lock:
|
|
120
|
+
self._evict_completed_locked(DEFAULT_TTL_SECONDS)
|
|
121
|
+
return self._jobs.get(job_id)
|
|
122
|
+
|
|
123
|
+
def cancel(self, job_id: str) -> None:
|
|
124
|
+
with self._lock:
|
|
125
|
+
job = self._jobs.get(job_id)
|
|
126
|
+
if job is not None:
|
|
127
|
+
job.cancel_event.set()
|
|
128
|
+
|
|
129
|
+
def has_active(self, org_id: str) -> bool:
|
|
130
|
+
with self._lock:
|
|
131
|
+
self._evict_completed_locked(DEFAULT_TTL_SECONDS)
|
|
132
|
+
return self._active_job_for_locked(org_id) is not None
|
|
133
|
+
|
|
134
|
+
def _active_job_for_locked(self, key: str) -> RegenJob | None:
|
|
135
|
+
"""Return the running job for an org, or None when no live job exists.
|
|
136
|
+
|
|
137
|
+
A registry entry whose job has already finished
|
|
138
|
+
(``completed`` / ``cancelled`` / ``error``) is treated as having no active
|
|
139
|
+
job — the previous run finished and the user can start a new one. The
|
|
140
|
+
registry still holds the finished job until TTL eviction so status polls
|
|
141
|
+
keep working, but it doesn't block new submissions.
|
|
142
|
+
"""
|
|
143
|
+
job_id = self._by_org.get(key)
|
|
144
|
+
if job_id is None:
|
|
145
|
+
return None
|
|
146
|
+
job = self._jobs.get(job_id)
|
|
147
|
+
if job is None or job.status != "running":
|
|
148
|
+
return None
|
|
149
|
+
return job
|
|
150
|
+
|
|
151
|
+
def evict_completed_older_than(self, ttl_seconds: int) -> None:
|
|
152
|
+
with self._lock:
|
|
153
|
+
self._evict_completed_locked(ttl_seconds)
|
|
154
|
+
|
|
155
|
+
def _evict_completed_locked(self, ttl_seconds: int) -> None:
|
|
156
|
+
now = time.time()
|
|
157
|
+
drop = [
|
|
158
|
+
jid
|
|
159
|
+
for jid, j in self._jobs.items()
|
|
160
|
+
if j.status in ("completed", "cancelled", "error")
|
|
161
|
+
and j.finished_at is not None
|
|
162
|
+
and (now - j.finished_at) > ttl_seconds
|
|
163
|
+
]
|
|
164
|
+
for jid in drop:
|
|
165
|
+
j = self._jobs.pop(jid)
|
|
166
|
+
self._by_org.pop(j.org_id, None)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# Single process-local instance.
|
|
170
|
+
REGEN_JOBS = RegenJobRegistry()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _load_first_request(
|
|
174
|
+
storage: BaseStorage,
|
|
175
|
+
user_id: str,
|
|
176
|
+
session_id: str,
|
|
177
|
+
cache: dict[str, tuple[int, dict[str, Any]]],
|
|
178
|
+
) -> tuple[int, dict[str, Any]]:
|
|
179
|
+
"""Return the (created_at, metadata) of a session's earliest request, memoized.
|
|
180
|
+
|
|
181
|
+
The regen worker can see multiple SessionDescriptors for the same
|
|
182
|
+
session_id (one per distinct agent_version/source tuple). This
|
|
183
|
+
helper guarantees each session_id triggers at most one storage call,
|
|
184
|
+
mirroring the amortized pattern F2's evaluation overview service
|
|
185
|
+
uses.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
storage (BaseStorage): Storage backend bound to the request_context.
|
|
189
|
+
user_id (str): Owner of the session's requests.
|
|
190
|
+
session_id (str): Session whose first-request data to return.
|
|
191
|
+
cache (dict[str, tuple[int, dict[str, Any]]]): Memoization dict
|
|
192
|
+
keyed by session_id; updated in place.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
tuple[int, dict[str, Any]]: ``(first_created_at, first_metadata)``.
|
|
196
|
+
Falls back to ``(0, {})`` when the session has no requests (the
|
|
197
|
+
descriptor is still kept so the regen worker can attempt
|
|
198
|
+
evaluation; the sampler simply treats it as the epoch-zero day
|
|
199
|
+
bucket and the untagged group).
|
|
200
|
+
"""
|
|
201
|
+
cached = cache.get(session_id)
|
|
202
|
+
if cached is not None:
|
|
203
|
+
return cached
|
|
204
|
+
try:
|
|
205
|
+
requests = storage.get_requests_by_session(user_id, session_id)
|
|
206
|
+
except Exception as e: # noqa: BLE001 — per-session resilience boundary
|
|
207
|
+
logger.warning(
|
|
208
|
+
"Failed to fetch requests for session %s during F3 sampler candidate "
|
|
209
|
+
"discovery (%s); falling back to (created_at=0, metadata={}). The "
|
|
210
|
+
"session will be retried in the per-session loop below.",
|
|
211
|
+
session_id,
|
|
212
|
+
e,
|
|
213
|
+
)
|
|
214
|
+
cache[session_id] = (0, {})
|
|
215
|
+
return cache[session_id]
|
|
216
|
+
if not requests:
|
|
217
|
+
logger.warning(
|
|
218
|
+
"Session %s has no requests in storage despite being returned by "
|
|
219
|
+
"get_session_ids_in_window (possible race or contract violation); "
|
|
220
|
+
"falling back to (created_at=0, metadata={}).",
|
|
221
|
+
session_id,
|
|
222
|
+
)
|
|
223
|
+
cache[session_id] = (0, {})
|
|
224
|
+
return cache[session_id]
|
|
225
|
+
first = min(requests, key=lambda r: r.created_at)
|
|
226
|
+
cache[session_id] = (first.created_at, first.metadata or {})
|
|
227
|
+
return cache[session_id]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _build_sample_candidates(
|
|
231
|
+
storage: BaseStorage,
|
|
232
|
+
descriptors: list[SessionDescriptor],
|
|
233
|
+
) -> list[SampleCandidate]:
|
|
234
|
+
"""Convert raw SessionDescriptors into SampleCandidates with metadata.
|
|
235
|
+
|
|
236
|
+
Reads the first-request data for each distinct session_id at most
|
|
237
|
+
once via ``_load_first_request``'s cache, then assembles one
|
|
238
|
+
``SampleCandidate`` per descriptor. ``created_at`` is sourced from
|
|
239
|
+
the first request's timestamp so the day-bucket stratum aligns with
|
|
240
|
+
the session's wall clock (not the regen window's edges).
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
storage (BaseStorage): Storage backend used to load per-session data.
|
|
244
|
+
descriptors (list[SessionDescriptor]): Raw descriptors emitted by
|
|
245
|
+
``storage.get_session_ids_in_window``.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
list[SampleCandidate]: One candidate per descriptor, ready for the
|
|
249
|
+
pure ``sample_candidates`` function.
|
|
250
|
+
"""
|
|
251
|
+
cache: dict[str, tuple[int, dict[str, Any]]] = {}
|
|
252
|
+
candidates: list[SampleCandidate] = []
|
|
253
|
+
for sd in descriptors:
|
|
254
|
+
created_at, metadata = _load_first_request(
|
|
255
|
+
storage, sd.user_id, sd.session_id, cache
|
|
256
|
+
)
|
|
257
|
+
candidates.append(
|
|
258
|
+
SampleCandidate(
|
|
259
|
+
session_id=sd.session_id,
|
|
260
|
+
user_id=sd.user_id,
|
|
261
|
+
agent_version=sd.agent_version,
|
|
262
|
+
source=sd.source,
|
|
263
|
+
created_at=created_at,
|
|
264
|
+
first_request_metadata=metadata,
|
|
265
|
+
)
|
|
266
|
+
)
|
|
267
|
+
return candidates
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _dispatch_one(
|
|
271
|
+
sc: SampleCandidate,
|
|
272
|
+
*,
|
|
273
|
+
job: RegenJob,
|
|
274
|
+
request_context: RequestContext,
|
|
275
|
+
llm_client: LiteLLMClient,
|
|
276
|
+
) -> None:
|
|
277
|
+
"""Run the LLM judge for one sampled candidate.
|
|
278
|
+
|
|
279
|
+
Honors ``job.cancel_event`` as an early-exit by raising a sentinel
|
|
280
|
+
``_CancelledError`` so the dispatcher can distinguish cancellations from
|
|
281
|
+
real failures.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
sc (SampleCandidate): Session to grade.
|
|
285
|
+
job (RegenJob): Owning job; the cancel event is read here so
|
|
286
|
+
workers already dequeued from the pool can bail out fast
|
|
287
|
+
instead of running the full judge after cancellation.
|
|
288
|
+
request_context (RequestContext): Storage/config/prompt carrier
|
|
289
|
+
forwarded to ``run_group_evaluation``.
|
|
290
|
+
llm_client (LiteLLMClient): Shared LLM client forwarded to
|
|
291
|
+
``run_group_evaluation``.
|
|
292
|
+
|
|
293
|
+
Raises:
|
|
294
|
+
_CancelledError: When the cancel event is set before this worker
|
|
295
|
+
starts its judge call.
|
|
296
|
+
Exception: Whatever ``run_group_evaluation`` itself raised.
|
|
297
|
+
"""
|
|
298
|
+
if job.cancel_event.is_set():
|
|
299
|
+
raise _CancelledError
|
|
300
|
+
run_group_evaluation(
|
|
301
|
+
org_id=job.org_id,
|
|
302
|
+
user_id=sc.user_id,
|
|
303
|
+
session_id=sc.session_id,
|
|
304
|
+
agent_version=sc.agent_version,
|
|
305
|
+
source=sc.source,
|
|
306
|
+
request_context=request_context,
|
|
307
|
+
llm_client=llm_client,
|
|
308
|
+
force_regenerate=True,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class _CancelledError(Exception):
|
|
313
|
+
"""Sentinel raised by a worker that observed ``job.cancel_event``.
|
|
314
|
+
|
|
315
|
+
Distinguishes a clean cancellation (must not count as a failure)
|
|
316
|
+
from any other exception ``run_group_evaluation`` might raise.
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def run_regen(
|
|
321
|
+
*,
|
|
322
|
+
job: RegenJob,
|
|
323
|
+
request_context: RequestContext,
|
|
324
|
+
llm_client: LiteLLMClient,
|
|
325
|
+
rng: random.Random | None = None,
|
|
326
|
+
) -> None:
|
|
327
|
+
"""Worker body. Samples candidates per stratum, then drives ``run_group_evaluation``.
|
|
328
|
+
|
|
329
|
+
Step 1 enumerates all candidate sessions in ``[from_ts, to_ts]`` via
|
|
330
|
+
``storage.get_session_ids_in_window``. Step 2 stratifies them by
|
|
331
|
+
(day-bucket x F2 group) and samples up to
|
|
332
|
+
``config.eval_sample_n_per_stratum`` per stratum — giving the regen
|
|
333
|
+
pipeline predictable cost regardless of traffic volume. Step 3
|
|
334
|
+
dispatches the sampled subset through a ``ThreadPoolExecutor`` whose
|
|
335
|
+
``max_workers`` is bound by ``config.eval_concurrency_limit``,
|
|
336
|
+
capping LLM provider rate-limit pressure.
|
|
337
|
+
|
|
338
|
+
On normal completion of the sampled work, sets
|
|
339
|
+
``job.status = "completed"`` even if individual sessions raised —
|
|
340
|
+
per-session failures are recorded in ``job.failed`` and
|
|
341
|
+
``job.failures`` (capped at ``_FAILURE_CAP`` to bound memory). Sets
|
|
342
|
+
``job.status = "error"`` only if the worker itself crashes (e.g.
|
|
343
|
+
storage misconfigured).
|
|
344
|
+
|
|
345
|
+
Cancellation semantics:
|
|
346
|
+
- ``job.cancel_event`` may be set at any time during the worker run.
|
|
347
|
+
- Futures already executing ``run_group_evaluation`` finish naturally
|
|
348
|
+
(Python threads cannot be safely interrupted mid-LLM-call).
|
|
349
|
+
- Futures the pool dequeues AFTER the event is set short-circuit at
|
|
350
|
+
the dispatch boundary by raising a private ``_CancelledError``,
|
|
351
|
+
which is silently dropped — not counted as a success or failure.
|
|
352
|
+
- The post-loop ``job.cancel_event.is_set()`` check is authoritative:
|
|
353
|
+
even if every submitted future happened to complete before the
|
|
354
|
+
user clicked cancel, the job is reported as ``"cancelled"``.
|
|
355
|
+
- Consequence: when the job is cancelled,
|
|
356
|
+
``job.completed + job.failed`` may be strictly less than
|
|
357
|
+
``job.sampled_count``. Consumers reading
|
|
358
|
+
``RegenerateStatusResponse`` must accept this invariant.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
job (RegenJob): Pre-registered job whose counters
|
|
362
|
+
(``total_candidates``, ``sampled_count``, ``concurrency_limit``,
|
|
363
|
+
``completed``, ``failed``) and ``status`` this worker mutates in
|
|
364
|
+
place.
|
|
365
|
+
request_context (RequestContext): Carrier for storage, config, and
|
|
366
|
+
prompt manager. The configurator's current Config is read to
|
|
367
|
+
pick up ``eval_sample_n_per_stratum`` and ``eval_concurrency_limit``.
|
|
368
|
+
llm_client (LiteLLMClient): Shared LLM client used by
|
|
369
|
+
``run_group_evaluation`` per session.
|
|
370
|
+
rng (random.Random | None): Optional seeded RNG for reproducible
|
|
371
|
+
sampling. Defaults to an unseeded ``random.Random()`` so callers
|
|
372
|
+
that don't care about reproducibility don't need to pass anything.
|
|
373
|
+
"""
|
|
374
|
+
try:
|
|
375
|
+
storage = request_context.storage
|
|
376
|
+
if storage is None:
|
|
377
|
+
raise RuntimeError("storage is not configured")
|
|
378
|
+
config = request_context.configurator.get_config()
|
|
379
|
+
job.concurrency_limit = config.eval_concurrency_limit
|
|
380
|
+
|
|
381
|
+
descriptors = storage.get_session_ids_in_window(
|
|
382
|
+
from_ts=job.from_ts, to_ts=job.to_ts
|
|
383
|
+
)
|
|
384
|
+
job.total_candidates = len(descriptors)
|
|
385
|
+
|
|
386
|
+
candidates = _build_sample_candidates(storage, descriptors)
|
|
387
|
+
sampled = sample_candidates(
|
|
388
|
+
candidates,
|
|
389
|
+
n_per_stratum=config.eval_sample_n_per_stratum,
|
|
390
|
+
rng=rng or random.Random(), # noqa: S311 — sampling, not crypto
|
|
391
|
+
)
|
|
392
|
+
job.sampled_count = len(sampled)
|
|
393
|
+
|
|
394
|
+
observed_cancel = _run_pool(
|
|
395
|
+
sampled,
|
|
396
|
+
job=job,
|
|
397
|
+
request_context=request_context,
|
|
398
|
+
llm_client=llm_client,
|
|
399
|
+
)
|
|
400
|
+
job.status = "cancelled" if observed_cancel else "completed"
|
|
401
|
+
except Exception: # noqa: BLE001 — worker boundary
|
|
402
|
+
job.status = "error"
|
|
403
|
+
logger.exception("Regen worker crashed for job=%s", job.job_id)
|
|
404
|
+
finally:
|
|
405
|
+
job.finished_at = time.time()
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _run_pool(
|
|
409
|
+
sampled: list[SampleCandidate],
|
|
410
|
+
*,
|
|
411
|
+
job: RegenJob,
|
|
412
|
+
request_context: RequestContext,
|
|
413
|
+
llm_client: LiteLLMClient,
|
|
414
|
+
) -> bool:
|
|
415
|
+
"""Dispatch ``sampled`` through a ThreadPoolExecutor and aggregate results.
|
|
416
|
+
|
|
417
|
+
Updates ``job.completed`` / ``job.failed`` / ``job.failures`` (capped
|
|
418
|
+
at ``_FAILURE_CAP``) as futures resolve. When ``job.cancel_event``
|
|
419
|
+
fires the pool stops submitting new work; futures already running
|
|
420
|
+
finish, but their cancellation sentinels are silently dropped.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
sampled (list[SampleCandidate]): Candidates already chosen by
|
|
424
|
+
the stratified sampler.
|
|
425
|
+
job (RegenJob): Owning job whose counters this function mutates.
|
|
426
|
+
request_context (RequestContext): Forwarded to each per-session
|
|
427
|
+
worker via ``_dispatch_one``.
|
|
428
|
+
llm_client (LiteLLMClient): Forwarded to each per-session worker
|
|
429
|
+
via ``_dispatch_one``.
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
bool: ``True`` if cancellation was observed at any point
|
|
433
|
+
(caller should set ``job.status = "cancelled"``); ``False`` if
|
|
434
|
+
every submitted future ran to completion (success or failure)
|
|
435
|
+
without cancellation.
|
|
436
|
+
"""
|
|
437
|
+
if not sampled:
|
|
438
|
+
return False
|
|
439
|
+
max_workers = max(1, job.concurrency_limit)
|
|
440
|
+
observed_cancel = False
|
|
441
|
+
with ThreadPoolExecutor(max_workers=max_workers) as pool:
|
|
442
|
+
future_to_sc: dict[Future[None], SampleCandidate] = {
|
|
443
|
+
pool.submit(
|
|
444
|
+
_dispatch_one,
|
|
445
|
+
sc,
|
|
446
|
+
job=job,
|
|
447
|
+
request_context=request_context,
|
|
448
|
+
llm_client=llm_client,
|
|
449
|
+
): sc
|
|
450
|
+
for sc in sampled
|
|
451
|
+
}
|
|
452
|
+
for fut in as_completed(future_to_sc):
|
|
453
|
+
sc = future_to_sc[fut]
|
|
454
|
+
try:
|
|
455
|
+
fut.result()
|
|
456
|
+
job.completed += 1
|
|
457
|
+
except _CancelledError:
|
|
458
|
+
# cancel_event was set before this future started; the
|
|
459
|
+
# post-loop check below is the single source of truth for
|
|
460
|
+
# the cancelled state. Don't touch counters here.
|
|
461
|
+
continue
|
|
462
|
+
except Exception as e: # noqa: BLE001 — worker boundary
|
|
463
|
+
job.failed += 1
|
|
464
|
+
if len(job.failures) < _FAILURE_CAP:
|
|
465
|
+
job.failures.append(
|
|
466
|
+
JobFailure(session_id=sc.session_id, reason=str(e)[:200])
|
|
467
|
+
)
|
|
468
|
+
logger.warning("Regen failed for session=%s: %s", sc.session_id, e)
|
|
469
|
+
if job.cancel_event.is_set():
|
|
470
|
+
observed_cancel = True
|
|
471
|
+
return observed_cancel
|