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,689 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextvars
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
import uuid
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
11
|
+
from concurrent.futures import TimeoutError as FuturesTimeoutError
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
from reflexio.defaults import resolve_agent_version
|
|
16
|
+
from reflexio.models.api_schema.service_schemas import (
|
|
17
|
+
Interaction,
|
|
18
|
+
PublishUserInteractionRequest,
|
|
19
|
+
Request,
|
|
20
|
+
)
|
|
21
|
+
from reflexio.models.config_schema import Config
|
|
22
|
+
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
23
|
+
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
24
|
+
from reflexio.server.services.agent_success_evaluation.delayed_group_evaluator import (
|
|
25
|
+
GroupEvaluationScheduler,
|
|
26
|
+
)
|
|
27
|
+
from reflexio.server.services.agent_success_evaluation.group_evaluation_runner import (
|
|
28
|
+
run_group_evaluation,
|
|
29
|
+
)
|
|
30
|
+
from reflexio.server.services.operation_state_utils import OperationStateManager
|
|
31
|
+
from reflexio.server.services.playbook.playbook_generation_service import (
|
|
32
|
+
PlaybookGenerationService,
|
|
33
|
+
)
|
|
34
|
+
from reflexio.server.services.playbook.playbook_service_utils import (
|
|
35
|
+
PlaybookGenerationRequest,
|
|
36
|
+
)
|
|
37
|
+
from reflexio.server.services.profile.profile_generation_service import (
|
|
38
|
+
ProfileGenerationService,
|
|
39
|
+
)
|
|
40
|
+
from reflexio.server.services.profile.profile_generation_service_utils import (
|
|
41
|
+
ProfileGenerationRequest,
|
|
42
|
+
)
|
|
43
|
+
from reflexio.server.services.reflection.reflection_service import ReflectionService
|
|
44
|
+
from reflexio.server.services.reflection.reflection_service_utils import (
|
|
45
|
+
ReflectionServiceRequest,
|
|
46
|
+
)
|
|
47
|
+
from reflexio.server.services.storage.retention import (
|
|
48
|
+
delete_count_for_retention,
|
|
49
|
+
get_row_retention_limits,
|
|
50
|
+
)
|
|
51
|
+
from reflexio.server.tracing import sentry_tags
|
|
52
|
+
from reflexio.server.usage_metrics import record_usage_event
|
|
53
|
+
|
|
54
|
+
if TYPE_CHECKING:
|
|
55
|
+
from reflexio.server.services.unified_search_service import UnifiedSearchService
|
|
56
|
+
|
|
57
|
+
logger = logging.getLogger(__name__)
|
|
58
|
+
# Stale lock timeout - if cleanup started > 10 min ago and still "in_progress", assume it crashed
|
|
59
|
+
CLEANUP_STALE_LOCK_SECONDS = 600
|
|
60
|
+
# Timeout for the outer generation service parallel execution
|
|
61
|
+
GENERATION_SERVICE_TIMEOUT_SECONDS = 600
|
|
62
|
+
_STALL_WARNING_PREFIX = "Reflexio learning is paused"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _retention_cleanup_interval_seconds() -> float:
|
|
66
|
+
raw = os.getenv("REFLEXIO_RETENTION_CLEANUP_INTERVAL_SECONDS", "300") or "300"
|
|
67
|
+
try:
|
|
68
|
+
return max(0.0, float(raw))
|
|
69
|
+
except ValueError:
|
|
70
|
+
logger.warning(
|
|
71
|
+
"Invalid REFLEXIO_RETENTION_CLEANUP_INTERVAL_SECONDS=%r; using 300",
|
|
72
|
+
raw,
|
|
73
|
+
)
|
|
74
|
+
return 300.0
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
_RETENTION_CLEANUP_INTERVAL_SECONDS = _retention_cleanup_interval_seconds()
|
|
78
|
+
_retention_cleanup_last_run: dict[tuple[str, str], float] = {}
|
|
79
|
+
_retention_cleanup_lock = threading.Lock()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class GenerationServiceResult:
|
|
84
|
+
"""Result of a GenerationService.run call.
|
|
85
|
+
|
|
86
|
+
Exposes the internally generated request_id plus any warnings so callers
|
|
87
|
+
(CLI, API) can report back to users where their publish landed.
|
|
88
|
+
|
|
89
|
+
Attributes:
|
|
90
|
+
request_id (str | None): The UUID assigned to this publish call, or
|
|
91
|
+
None when ``run()`` returned early before generating one (e.g.
|
|
92
|
+
empty request, missing ``user_id``, or no interactions).
|
|
93
|
+
warnings (list[str]): Non-fatal warnings raised by individual
|
|
94
|
+
generation services during the run.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
request_id: str | None = None
|
|
98
|
+
warnings: list[str] = field(default_factory=list)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class GenerationService:
|
|
102
|
+
"""
|
|
103
|
+
Main service for orchestrating profile, playbook, and agent success evaluation generation.
|
|
104
|
+
|
|
105
|
+
This service coordinates multiple generation services (profile, playbook, agent success)
|
|
106
|
+
and manages the overall interaction processing workflow.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def __init__(
|
|
110
|
+
self,
|
|
111
|
+
llm_client: LiteLLMClient,
|
|
112
|
+
request_context: RequestContext,
|
|
113
|
+
) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Initialize the generation service.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
llm_client: Pre-configured LLM client for making API calls.
|
|
119
|
+
request_context: Request context with storage and configurator.
|
|
120
|
+
"""
|
|
121
|
+
self.client = llm_client
|
|
122
|
+
self.storage = request_context.storage
|
|
123
|
+
self.org_id = request_context.org_id
|
|
124
|
+
self.configurator = request_context.configurator
|
|
125
|
+
self.request_context = request_context
|
|
126
|
+
|
|
127
|
+
# ===============================
|
|
128
|
+
# public methods
|
|
129
|
+
# ===============================
|
|
130
|
+
|
|
131
|
+
def run(
|
|
132
|
+
self, publish_user_interaction_request: PublishUserInteractionRequest
|
|
133
|
+
) -> GenerationServiceResult:
|
|
134
|
+
"""
|
|
135
|
+
Process a user interaction request by storing interactions and triggering generation services.
|
|
136
|
+
|
|
137
|
+
Profile and playbook generation services run inline in parallel. Agent success
|
|
138
|
+
evaluation is deferred via GroupEvaluationScheduler when a session_id is present,
|
|
139
|
+
so the full session can be evaluated after a period of inactivity.
|
|
140
|
+
|
|
141
|
+
Each generation service (profile, playbook) handles its own:
|
|
142
|
+
- Data collection based on extractor-specific configs
|
|
143
|
+
- Stride checking based on extractor-specific settings
|
|
144
|
+
- Operation state tracking per extractor
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
publish_user_interaction_request: The incoming user interaction request
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
GenerationServiceResult: The request_id assigned to this publish call
|
|
151
|
+
and any non-fatal warnings raised by individual generation services.
|
|
152
|
+
"""
|
|
153
|
+
result = GenerationServiceResult()
|
|
154
|
+
|
|
155
|
+
if not publish_user_interaction_request:
|
|
156
|
+
logger.error("Received None publish_user_interaction_request")
|
|
157
|
+
return result
|
|
158
|
+
|
|
159
|
+
user_id = publish_user_interaction_request.user_id
|
|
160
|
+
if not user_id:
|
|
161
|
+
logger.error("Received None user_id in publish_user_interaction_request")
|
|
162
|
+
return result
|
|
163
|
+
|
|
164
|
+
# Check if cleanup is needed before adding new interactions.
|
|
165
|
+
self._cleanup_storage_tables_if_needed()
|
|
166
|
+
|
|
167
|
+
publish_start = time.perf_counter()
|
|
168
|
+
# Resolve agent_version: explicit > env var > default. Resolved here
|
|
169
|
+
# (before the try) so success and failure telemetry share the same value.
|
|
170
|
+
agent_version = resolve_agent_version(
|
|
171
|
+
publish_user_interaction_request.agent_version
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
# Always generate a new UUID for request_id
|
|
176
|
+
request_id = str(uuid.uuid4())
|
|
177
|
+
result.request_id = request_id
|
|
178
|
+
|
|
179
|
+
new_interactions: list[Interaction] = (
|
|
180
|
+
GenerationService.get_interaction_from_publish_user_interaction_request(
|
|
181
|
+
publish_user_interaction_request, request_id
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if not new_interactions:
|
|
186
|
+
logger.info(
|
|
187
|
+
"No interactions from the publish user interaction request: %s, get all interactions for the user: %s",
|
|
188
|
+
request_id,
|
|
189
|
+
user_id,
|
|
190
|
+
)
|
|
191
|
+
return result
|
|
192
|
+
|
|
193
|
+
record_usage_event(
|
|
194
|
+
org_id=self.org_id,
|
|
195
|
+
user_id=user_id,
|
|
196
|
+
request_id=request_id,
|
|
197
|
+
session_id=publish_user_interaction_request.session_id or None,
|
|
198
|
+
source=publish_user_interaction_request.source,
|
|
199
|
+
agent_version=agent_version,
|
|
200
|
+
event_name="publish_request_received",
|
|
201
|
+
event_category="publish",
|
|
202
|
+
outcome="received",
|
|
203
|
+
count_value=len(new_interactions),
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Store Request — propagate customer-stamped metadata so the
|
|
207
|
+
# eval pipeline (e.g. F2 sticky-group aggregator) can read it
|
|
208
|
+
# back from the first request of each session.
|
|
209
|
+
new_request = Request(
|
|
210
|
+
request_id=request_id,
|
|
211
|
+
user_id=user_id,
|
|
212
|
+
source=publish_user_interaction_request.source,
|
|
213
|
+
agent_version=agent_version,
|
|
214
|
+
session_id=publish_user_interaction_request.session_id or None,
|
|
215
|
+
metadata=publish_user_interaction_request.metadata,
|
|
216
|
+
)
|
|
217
|
+
self.storage.add_request(new_request) # type: ignore[reportOptionalMemberAccess]
|
|
218
|
+
|
|
219
|
+
# Add interactions to storage (bulk insert with batched embedding generation)
|
|
220
|
+
self.storage.add_user_interactions_bulk( # type: ignore[reportOptionalMemberAccess]
|
|
221
|
+
user_id=user_id, interactions=new_interactions
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Extract source (empty string treated as None)
|
|
225
|
+
source = publish_user_interaction_request.source or None
|
|
226
|
+
|
|
227
|
+
if (
|
|
228
|
+
not publish_user_interaction_request.override_learning_stall
|
|
229
|
+
and (stall_warning := self._active_learning_stall_warning()) is not None
|
|
230
|
+
):
|
|
231
|
+
result.warnings.append(stall_warning)
|
|
232
|
+
logger.warning("%s; skipping automatic extraction", stall_warning)
|
|
233
|
+
record_usage_event(
|
|
234
|
+
org_id=self.org_id,
|
|
235
|
+
user_id=user_id,
|
|
236
|
+
request_id=request_id,
|
|
237
|
+
session_id=new_request.session_id,
|
|
238
|
+
source=source,
|
|
239
|
+
agent_version=agent_version,
|
|
240
|
+
event_name="publish_request_succeeded",
|
|
241
|
+
event_category="publish",
|
|
242
|
+
outcome="success",
|
|
243
|
+
count_value=len(new_interactions),
|
|
244
|
+
duration_ms=int((time.perf_counter() - publish_start) * 1000),
|
|
245
|
+
metadata={"warning_count": len(result.warnings)},
|
|
246
|
+
)
|
|
247
|
+
return result
|
|
248
|
+
|
|
249
|
+
# Reflection runs as its own sliding-window step BEFORE the
|
|
250
|
+
# extractor pool spins up, so any replacements it makes are
|
|
251
|
+
# visible to the extractors when they retrieve existing
|
|
252
|
+
# profile/playbook context. Wrapped in a broad except so a
|
|
253
|
+
# reflection bug never breaks the publish.
|
|
254
|
+
self._maybe_run_reflection(
|
|
255
|
+
user_id=user_id, agent_version=agent_version, source=source
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Create generation services and requests
|
|
259
|
+
# Each service writes to separate storage tables and has no dependencies on others
|
|
260
|
+
profile_generation_service = ProfileGenerationService(
|
|
261
|
+
llm_client=self.client, request_context=self.request_context
|
|
262
|
+
)
|
|
263
|
+
profile_generation_request = ProfileGenerationRequest(
|
|
264
|
+
user_id=user_id,
|
|
265
|
+
request_id=request_id,
|
|
266
|
+
source=source,
|
|
267
|
+
force_extraction=publish_user_interaction_request.force_extraction,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
playbook_generation_service = PlaybookGenerationService(
|
|
271
|
+
llm_client=self.client,
|
|
272
|
+
request_context=self.request_context,
|
|
273
|
+
skip_aggregation=publish_user_interaction_request.skip_aggregation,
|
|
274
|
+
)
|
|
275
|
+
playbook_generation_request = PlaybookGenerationRequest(
|
|
276
|
+
request_id=request_id,
|
|
277
|
+
agent_version=agent_version,
|
|
278
|
+
user_id=user_id,
|
|
279
|
+
source=source,
|
|
280
|
+
force_extraction=publish_user_interaction_request.force_extraction,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Run profile and playbook generation services in parallel
|
|
284
|
+
# Each service creates its own internal ThreadPoolExecutor for extractors
|
|
285
|
+
# This is safe because we create separate, independent pool instances
|
|
286
|
+
# Uses manual executor management to avoid blocking on shutdown(wait=True)
|
|
287
|
+
# when threads are hung on LLM calls
|
|
288
|
+
executor = ThreadPoolExecutor(max_workers=2)
|
|
289
|
+
try:
|
|
290
|
+
# Each thread needs its own context copy — Context.run() is non-reentrant
|
|
291
|
+
futures = [
|
|
292
|
+
executor.submit(
|
|
293
|
+
contextvars.copy_context().run,
|
|
294
|
+
profile_generation_service.run,
|
|
295
|
+
profile_generation_request,
|
|
296
|
+
),
|
|
297
|
+
executor.submit(
|
|
298
|
+
contextvars.copy_context().run,
|
|
299
|
+
playbook_generation_service.run,
|
|
300
|
+
playbook_generation_request,
|
|
301
|
+
),
|
|
302
|
+
]
|
|
303
|
+
|
|
304
|
+
# Collect results and handle any exceptions
|
|
305
|
+
# Each service failure is logged but doesn't block others
|
|
306
|
+
service_names = ["profile_generation", "playbook_generation"]
|
|
307
|
+
for future, service_name in zip(futures, service_names, strict=True):
|
|
308
|
+
try:
|
|
309
|
+
future.result(timeout=GENERATION_SERVICE_TIMEOUT_SECONDS)
|
|
310
|
+
except FuturesTimeoutError: # noqa: PERF203
|
|
311
|
+
msg = f"{service_name} timed out after {GENERATION_SERVICE_TIMEOUT_SECONDS}s"
|
|
312
|
+
with sentry_tags(
|
|
313
|
+
subsystem="generation",
|
|
314
|
+
service=service_name,
|
|
315
|
+
request_id=request_id,
|
|
316
|
+
error_type="timeout",
|
|
317
|
+
):
|
|
318
|
+
logger.error("%s for request %s", msg, request_id)
|
|
319
|
+
result.warnings.append(msg)
|
|
320
|
+
except Exception as e:
|
|
321
|
+
msg = f"{service_name} failed: {e}"
|
|
322
|
+
with sentry_tags(
|
|
323
|
+
subsystem="generation",
|
|
324
|
+
service=service_name,
|
|
325
|
+
request_id=request_id,
|
|
326
|
+
error_type=type(e).__name__,
|
|
327
|
+
):
|
|
328
|
+
logger.exception(
|
|
329
|
+
"Generation service failed for request %s", request_id,
|
|
330
|
+
)
|
|
331
|
+
result.warnings.append(msg)
|
|
332
|
+
finally:
|
|
333
|
+
executor.shutdown(wait=False, cancel_futures=True)
|
|
334
|
+
|
|
335
|
+
# Schedule delayed group evaluation if session_id is present
|
|
336
|
+
self._schedule_group_evaluation_if_needed(
|
|
337
|
+
new_request=new_request,
|
|
338
|
+
user_id=user_id,
|
|
339
|
+
agent_version=agent_version,
|
|
340
|
+
source=source,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
record_usage_event(
|
|
344
|
+
org_id=self.org_id,
|
|
345
|
+
user_id=user_id,
|
|
346
|
+
request_id=request_id,
|
|
347
|
+
session_id=new_request.session_id,
|
|
348
|
+
source=source,
|
|
349
|
+
agent_version=agent_version,
|
|
350
|
+
backend="classic",
|
|
351
|
+
event_name="publish_request_succeeded",
|
|
352
|
+
event_category="publish",
|
|
353
|
+
outcome="success",
|
|
354
|
+
count_value=len(new_interactions),
|
|
355
|
+
duration_ms=int((time.perf_counter() - publish_start) * 1000),
|
|
356
|
+
metadata={"warning_count": len(result.warnings)},
|
|
357
|
+
)
|
|
358
|
+
return result
|
|
359
|
+
|
|
360
|
+
except Exception as e:
|
|
361
|
+
record_usage_event(
|
|
362
|
+
org_id=self.org_id,
|
|
363
|
+
user_id=user_id,
|
|
364
|
+
request_id=result.request_id,
|
|
365
|
+
session_id=publish_user_interaction_request.session_id or None,
|
|
366
|
+
source=publish_user_interaction_request.source,
|
|
367
|
+
agent_version=agent_version,
|
|
368
|
+
event_name="publish_request_failed",
|
|
369
|
+
event_category="publish",
|
|
370
|
+
outcome="failed",
|
|
371
|
+
duration_ms=int((time.perf_counter() - publish_start) * 1000),
|
|
372
|
+
error_kind=type(e).__name__,
|
|
373
|
+
)
|
|
374
|
+
with sentry_tags(
|
|
375
|
+
subsystem="generation",
|
|
376
|
+
op="refresh_profile",
|
|
377
|
+
org_id=self.org_id,
|
|
378
|
+
user_id=user_id,
|
|
379
|
+
request_id=result.request_id,
|
|
380
|
+
error_type=type(e).__name__,
|
|
381
|
+
):
|
|
382
|
+
logger.exception(
|
|
383
|
+
"Failed to refresh user profile for user id: %s", user_id,
|
|
384
|
+
)
|
|
385
|
+
raise
|
|
386
|
+
|
|
387
|
+
# ===============================
|
|
388
|
+
# private methods
|
|
389
|
+
# ===============================
|
|
390
|
+
|
|
391
|
+
def _schedule_group_evaluation_if_needed(
|
|
392
|
+
self,
|
|
393
|
+
*,
|
|
394
|
+
new_request: Request,
|
|
395
|
+
user_id: str,
|
|
396
|
+
agent_version: str,
|
|
397
|
+
source: str | None,
|
|
398
|
+
) -> None:
|
|
399
|
+
"""Enqueue agent-success evaluation for this session, if session_id is set.
|
|
400
|
+
|
|
401
|
+
Must be called once per publish — from BOTH the classic and the agentic
|
|
402
|
+
extraction code paths — so that ``AgentSuccessEvaluationResult`` records
|
|
403
|
+
get produced regardless of which backend is in use. Skipping this for
|
|
404
|
+
the agentic path was the silent root cause of empty /evaluations tiles.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
new_request (Request): The just-stored request whose session is being
|
|
408
|
+
published into. ``new_request.session_id`` gates scheduling.
|
|
409
|
+
user_id (str): The user owning the session.
|
|
410
|
+
agent_version (str): Agent version string carried into the evaluator.
|
|
411
|
+
source (str | None): Optional source label.
|
|
412
|
+
"""
|
|
413
|
+
session_id = new_request.session_id
|
|
414
|
+
if not session_id:
|
|
415
|
+
return
|
|
416
|
+
|
|
417
|
+
scheduler = GroupEvaluationScheduler.get_instance()
|
|
418
|
+
key = (self.org_id, user_id, session_id)
|
|
419
|
+
|
|
420
|
+
def make_callback(
|
|
421
|
+
_org_id: str,
|
|
422
|
+
_user_id: str,
|
|
423
|
+
_sid: str,
|
|
424
|
+
_av: str,
|
|
425
|
+
_src: str | None,
|
|
426
|
+
_rc: RequestContext,
|
|
427
|
+
_llm: LiteLLMClient,
|
|
428
|
+
) -> Callable[[], None]:
|
|
429
|
+
def callback() -> None:
|
|
430
|
+
run_group_evaluation(
|
|
431
|
+
org_id=_org_id,
|
|
432
|
+
user_id=_user_id,
|
|
433
|
+
session_id=_sid,
|
|
434
|
+
agent_version=_av,
|
|
435
|
+
source=_src,
|
|
436
|
+
request_context=_rc,
|
|
437
|
+
llm_client=_llm,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
return callback
|
|
441
|
+
|
|
442
|
+
scheduler.schedule(
|
|
443
|
+
key,
|
|
444
|
+
make_callback(
|
|
445
|
+
self.org_id,
|
|
446
|
+
user_id,
|
|
447
|
+
session_id,
|
|
448
|
+
agent_version,
|
|
449
|
+
source,
|
|
450
|
+
self.request_context,
|
|
451
|
+
self.client,
|
|
452
|
+
),
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
def _maybe_run_reflection(
|
|
456
|
+
self, *, user_id: str, agent_version: str, source: str | None
|
|
457
|
+
) -> None:
|
|
458
|
+
"""Best-effort reflection pass before extraction.
|
|
459
|
+
|
|
460
|
+
Any failure is caught and logged so the surrounding publish
|
|
461
|
+
flow (extraction + delayed evaluation) is unaffected.
|
|
462
|
+
"""
|
|
463
|
+
try:
|
|
464
|
+
service = ReflectionService(
|
|
465
|
+
request_context=self.request_context,
|
|
466
|
+
llm_client=self.client,
|
|
467
|
+
)
|
|
468
|
+
service.run(
|
|
469
|
+
ReflectionServiceRequest(
|
|
470
|
+
user_id=user_id,
|
|
471
|
+
agent_version=agent_version,
|
|
472
|
+
source=source,
|
|
473
|
+
)
|
|
474
|
+
)
|
|
475
|
+
except Exception as exc: # noqa: BLE001 — must not break publish
|
|
476
|
+
# Promoted to logger.exception so Sentry's LoggingIntegration
|
|
477
|
+
# captures the event. The except still doesn't re-raise — the
|
|
478
|
+
# publish loop continues — but on-call now sees the failure
|
|
479
|
+
# instead of it being buried at WARNING level.
|
|
480
|
+
with sentry_tags(
|
|
481
|
+
subsystem="generation",
|
|
482
|
+
op="reflection",
|
|
483
|
+
org_id=self.org_id,
|
|
484
|
+
user_id=user_id,
|
|
485
|
+
error_type=type(exc).__name__,
|
|
486
|
+
):
|
|
487
|
+
logger.exception("reflection step failed for user %s", user_id)
|
|
488
|
+
|
|
489
|
+
def _cleanup_storage_tables_if_needed(self) -> None:
|
|
490
|
+
"""Best-effort publish-boundary cleanup for capped storage tables."""
|
|
491
|
+
now = time.monotonic()
|
|
492
|
+
limits = {
|
|
493
|
+
target_name: limit
|
|
494
|
+
for target_name, limit in get_row_retention_limits().items()
|
|
495
|
+
if limit > 0 and self._should_check_retention_target(target_name, now)
|
|
496
|
+
}
|
|
497
|
+
if not limits:
|
|
498
|
+
return
|
|
499
|
+
|
|
500
|
+
try:
|
|
501
|
+
mgr = OperationStateManager(
|
|
502
|
+
self.storage, # type: ignore[reportArgumentType]
|
|
503
|
+
self.org_id,
|
|
504
|
+
"storage_table_cleanup", # type: ignore[reportArgumentType]
|
|
505
|
+
)
|
|
506
|
+
if not mgr.acquire_simple_lock(stale_seconds=CLEANUP_STALE_LOCK_SECONDS):
|
|
507
|
+
return
|
|
508
|
+
|
|
509
|
+
try:
|
|
510
|
+
for target_name, limit in limits.items():
|
|
511
|
+
# Isolate per-target failures so one bad table does not
|
|
512
|
+
# short-circuit cleanup for every subsequent target.
|
|
513
|
+
try:
|
|
514
|
+
self._cleanup_retention_target(target_name, limit)
|
|
515
|
+
except Exception as e: # noqa: BLE001
|
|
516
|
+
with sentry_tags(
|
|
517
|
+
subsystem="generation",
|
|
518
|
+
op="cleanup_retention_target",
|
|
519
|
+
org_id=self.org_id,
|
|
520
|
+
target_name=target_name,
|
|
521
|
+
error_type=type(e).__name__,
|
|
522
|
+
):
|
|
523
|
+
logger.exception(
|
|
524
|
+
"Failed to cleanup retention target %s", target_name,
|
|
525
|
+
)
|
|
526
|
+
finally:
|
|
527
|
+
mgr.release_simple_lock()
|
|
528
|
+
|
|
529
|
+
except Exception as e:
|
|
530
|
+
with sentry_tags(
|
|
531
|
+
subsystem="generation",
|
|
532
|
+
op="cleanup_storage_tables",
|
|
533
|
+
org_id=self.org_id,
|
|
534
|
+
error_type=type(e).__name__,
|
|
535
|
+
):
|
|
536
|
+
logger.exception("Failed to cleanup storage tables")
|
|
537
|
+
# Don't raise - cleanup failure shouldn't block normal operation
|
|
538
|
+
|
|
539
|
+
def _should_check_retention_target(self, target_name: str, now: float) -> bool:
|
|
540
|
+
if _RETENTION_CLEANUP_INTERVAL_SECONDS <= 0:
|
|
541
|
+
return True
|
|
542
|
+
key = (self.org_id, target_name)
|
|
543
|
+
with _retention_cleanup_lock:
|
|
544
|
+
last_run = _retention_cleanup_last_run.get(key)
|
|
545
|
+
if (
|
|
546
|
+
last_run is not None
|
|
547
|
+
and now - last_run < _RETENTION_CLEANUP_INTERVAL_SECONDS
|
|
548
|
+
):
|
|
549
|
+
return False
|
|
550
|
+
_retention_cleanup_last_run[key] = now
|
|
551
|
+
return True
|
|
552
|
+
|
|
553
|
+
def _active_learning_stall_warning(self) -> str | None:
|
|
554
|
+
"""Return a warning when extraction should not auto-retry.
|
|
555
|
+
|
|
556
|
+
Plugin publishes should still store raw interactions while the local
|
|
557
|
+
LLM provider is blocked by auth or billing, but they
|
|
558
|
+
must not keep invoking extraction on every publish. Only callers that
|
|
559
|
+
pass ``override_learning_stall=True`` bypass this check so an explicit
|
|
560
|
+
retry after reauth can clear the stall state on a successful provider
|
|
561
|
+
call.
|
|
562
|
+
"""
|
|
563
|
+
try:
|
|
564
|
+
stall_state = self.storage.get_stall_state() # type: ignore[reportOptionalMemberAccess]
|
|
565
|
+
except (AttributeError, NotImplementedError):
|
|
566
|
+
return None
|
|
567
|
+
except Exception as exc: # noqa: BLE001 - stall telemetry must not block publish.
|
|
568
|
+
logger.debug("Failed to read stall_state before extraction: %s", exc)
|
|
569
|
+
return None
|
|
570
|
+
|
|
571
|
+
if not getattr(stall_state, "stalled", False):
|
|
572
|
+
return None
|
|
573
|
+
reason = getattr(stall_state, "reason", None) or "unknown"
|
|
574
|
+
suffix = (
|
|
575
|
+
"reauthenticate the active coding-agent provider, then run an explicit "
|
|
576
|
+
"override retry to resume."
|
|
577
|
+
if reason == "auth_error"
|
|
578
|
+
else "wait for the limit/reset condition to clear, then run an explicit "
|
|
579
|
+
"override retry to resume."
|
|
580
|
+
)
|
|
581
|
+
return f"{_STALL_WARNING_PREFIX} ({reason}); {suffix}"
|
|
582
|
+
|
|
583
|
+
def _cleanup_retention_target(self, target_name: str, limit: int) -> None:
|
|
584
|
+
total_count = self.storage.count_retention_target_rows(target_name) # type: ignore[reportOptionalMemberAccess]
|
|
585
|
+
if total_count < limit:
|
|
586
|
+
return
|
|
587
|
+
delete_count = delete_count_for_retention(total_count)
|
|
588
|
+
deleted = self.storage.delete_oldest_retention_target_rows( # type: ignore[reportOptionalMemberAccess]
|
|
589
|
+
target_name,
|
|
590
|
+
delete_count,
|
|
591
|
+
)
|
|
592
|
+
logger.info(
|
|
593
|
+
"Cleaned up %d oldest %s row(s) (total was %d, limit %d)",
|
|
594
|
+
deleted,
|
|
595
|
+
target_name,
|
|
596
|
+
total_count,
|
|
597
|
+
limit,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
# ===============================
|
|
601
|
+
# static methods
|
|
602
|
+
# ===============================
|
|
603
|
+
|
|
604
|
+
@staticmethod
|
|
605
|
+
def get_interaction_from_publish_user_interaction_request(
|
|
606
|
+
publish_user_interaction_request: PublishUserInteractionRequest,
|
|
607
|
+
request_id: str,
|
|
608
|
+
) -> list[Interaction]:
|
|
609
|
+
"""get interaction from publish user interaction request
|
|
610
|
+
|
|
611
|
+
Args:
|
|
612
|
+
publish_user_interaction_request (PublishUserInteractionRequest): The publish user interaction request
|
|
613
|
+
request_id (str): The request ID generated by the service
|
|
614
|
+
|
|
615
|
+
Returns:
|
|
616
|
+
list[Interaction]: List of interactions created from the request
|
|
617
|
+
"""
|
|
618
|
+
interaction_data_list = publish_user_interaction_request.interaction_data_list
|
|
619
|
+
|
|
620
|
+
user_id = publish_user_interaction_request.user_id
|
|
621
|
+
# Honor the client-provided ``created_at`` — InteractionData defaults
|
|
622
|
+
# it to client-side ``now()`` on construction, so it's always populated.
|
|
623
|
+
# Apps that publish backdated conversations (e.g., a benchmark replay
|
|
624
|
+
# of 2023 chats run in 2026) need the wall-clock time preserved so the
|
|
625
|
+
# extraction agent has a real temporal anchor for relative-time
|
|
626
|
+
# references like "X weeks ago" / "yesterday". Stamping server-now here
|
|
627
|
+
# would erase that anchor and force every event onto today's date.
|
|
628
|
+
return [
|
|
629
|
+
Interaction(
|
|
630
|
+
# interaction_id is auto-generated by DB
|
|
631
|
+
user_id=user_id,
|
|
632
|
+
request_id=request_id,
|
|
633
|
+
created_at=interaction_data.created_at,
|
|
634
|
+
content=interaction_data.content,
|
|
635
|
+
role=interaction_data.role,
|
|
636
|
+
user_action=interaction_data.user_action,
|
|
637
|
+
user_action_description=interaction_data.user_action_description,
|
|
638
|
+
interacted_image_url=interaction_data.interacted_image_url,
|
|
639
|
+
image_encoding=interaction_data.image_encoding,
|
|
640
|
+
shadow_content=interaction_data.shadow_content,
|
|
641
|
+
expert_content=interaction_data.expert_content,
|
|
642
|
+
tools_used=interaction_data.tools_used,
|
|
643
|
+
citations=interaction_data.citations,
|
|
644
|
+
)
|
|
645
|
+
for interaction_data in interaction_data_list
|
|
646
|
+
]
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def build_extraction_service(
|
|
650
|
+
config: Config,
|
|
651
|
+
*,
|
|
652
|
+
llm_client: LiteLLMClient,
|
|
653
|
+
request_context: RequestContext,
|
|
654
|
+
) -> ProfileGenerationService:
|
|
655
|
+
"""Return the profile extraction service.
|
|
656
|
+
|
|
657
|
+
Args:
|
|
658
|
+
config (Config): Top-level ``Config`` (unused; kept for API consistency).
|
|
659
|
+
llm_client (LiteLLMClient): Configured ``LiteLLMClient``.
|
|
660
|
+
request_context (RequestContext): Current request context.
|
|
661
|
+
|
|
662
|
+
Returns:
|
|
663
|
+
ProfileGenerationService: Classic profile extraction service.
|
|
664
|
+
"""
|
|
665
|
+
del config # unused — agentic path bypasses this factory
|
|
666
|
+
return ProfileGenerationService(
|
|
667
|
+
llm_client=llm_client, request_context=request_context
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
def build_search_service(
|
|
672
|
+
config: Config, # noqa: ARG001
|
|
673
|
+
*,
|
|
674
|
+
llm_client: LiteLLMClient,
|
|
675
|
+
request_context: RequestContext,
|
|
676
|
+
) -> UnifiedSearchService:
|
|
677
|
+
"""Build the unified search service.
|
|
678
|
+
|
|
679
|
+
Args:
|
|
680
|
+
config (Config): Top-level ``Config`` (unused; kept for API consistency).
|
|
681
|
+
llm_client (LiteLLMClient): Configured ``LiteLLMClient``.
|
|
682
|
+
request_context (RequestContext): Current request context.
|
|
683
|
+
|
|
684
|
+
Returns:
|
|
685
|
+
A ``UnifiedSearchService`` holding ``llm_client`` and ``request_context``.
|
|
686
|
+
"""
|
|
687
|
+
from reflexio.server.services.unified_search_service import UnifiedSearchService
|
|
688
|
+
|
|
689
|
+
return UnifiedSearchService(llm_client=llm_client, request_context=request_context)
|