claude-smart 0.2.42 → 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 +3 -3
- package/README.md +1 -1
- package/package.json +9 -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/pyproject.toml +2 -2
- package/plugin/scripts/_lib.sh +91 -0
- package/plugin/scripts/backend-service.sh +1 -0
- package/plugin/scripts/cli.sh +1 -0
- 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/hook_entry.sh +1 -0
- package/plugin/scripts/smart-install.sh +1 -0
- 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,734 @@
|
|
|
1
|
+
"""Service to generate user profiles from interactions"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import uuid
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from datetime import UTC, datetime
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
13
|
+
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
14
|
+
|
|
15
|
+
from reflexio.models.api_schema.internal_schema import RequestInteractionDataModel
|
|
16
|
+
from reflexio.models.api_schema.service_schemas import (
|
|
17
|
+
DeleteUserProfileRequest,
|
|
18
|
+
DowngradeProfilesResponse,
|
|
19
|
+
ManualProfileGenerationRequest,
|
|
20
|
+
ManualProfileGenerationResponse,
|
|
21
|
+
ProfileChangeLog,
|
|
22
|
+
RerunProfileGenerationRequest,
|
|
23
|
+
RerunProfileGenerationResponse,
|
|
24
|
+
Status,
|
|
25
|
+
UpgradeProfilesResponse,
|
|
26
|
+
UserProfile,
|
|
27
|
+
)
|
|
28
|
+
from reflexio.models.config_schema import ProfileExtractorConfig
|
|
29
|
+
from reflexio.server.services.base_generation_service import (
|
|
30
|
+
BaseGenerationService,
|
|
31
|
+
StatusChangeOperation,
|
|
32
|
+
)
|
|
33
|
+
from reflexio.server.services.profile.profile_extractor import ProfileExtractor
|
|
34
|
+
from reflexio.server.services.profile.profile_generation_service_utils import (
|
|
35
|
+
ProfileGenerationRequest,
|
|
36
|
+
ProfileGenerationServiceConstants,
|
|
37
|
+
)
|
|
38
|
+
from reflexio.server.services.service_utils import (
|
|
39
|
+
format_sessions_to_history_string,
|
|
40
|
+
)
|
|
41
|
+
from reflexio.server.tracing import sentry_tags
|
|
42
|
+
|
|
43
|
+
logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class ProfileGenerationServiceConfig:
|
|
48
|
+
"""Runtime configuration for profile generation service shared across all extractors.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
user_id: The user ID
|
|
52
|
+
request_id: The request ID
|
|
53
|
+
source: Source of the interactions (triggering source)
|
|
54
|
+
existing_data: Existing profiles for the user
|
|
55
|
+
allow_manual_trigger: Whether to allow extractors with manual_trigger=True
|
|
56
|
+
output_pending_status: Whether to output profiles with PENDING status
|
|
57
|
+
rerun_start_time: Optional start time filter for rerun flows (Unix timestamp)
|
|
58
|
+
rerun_end_time: Optional end time filter for rerun flows (Unix timestamp)
|
|
59
|
+
auto_run: True for regular flow (checks stride_size), False for rerun/manual (skips stride_size)
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
user_id: str
|
|
63
|
+
request_id: str
|
|
64
|
+
source: str | None = None
|
|
65
|
+
existing_data: Any = None
|
|
66
|
+
allow_manual_trigger: bool = False
|
|
67
|
+
output_pending_status: bool = False
|
|
68
|
+
rerun_start_time: int | None = None
|
|
69
|
+
rerun_end_time: int | None = None
|
|
70
|
+
auto_run: bool = True
|
|
71
|
+
force_extraction: bool = False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ProfileGenerationService(
|
|
75
|
+
BaseGenerationService[
|
|
76
|
+
ProfileExtractorConfig,
|
|
77
|
+
ProfileExtractor,
|
|
78
|
+
ProfileGenerationServiceConfig,
|
|
79
|
+
ProfileGenerationRequest,
|
|
80
|
+
]
|
|
81
|
+
):
|
|
82
|
+
"""Service to generate user profiles from interactions"""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
llm_client: LiteLLMClient,
|
|
87
|
+
request_context: RequestContext,
|
|
88
|
+
allow_manual_trigger: bool = False,
|
|
89
|
+
output_pending_status: bool = False,
|
|
90
|
+
) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Initialize the profile generation service.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
llm_client: Unified LLM client supporting both OpenAI and Claude
|
|
96
|
+
request_context: Request context with storage, configurator, and org_id
|
|
97
|
+
allow_manual_trigger: Whether to allow extractors with manual_trigger=True
|
|
98
|
+
output_pending_status: Whether to output profiles with PENDING status (for rerun)
|
|
99
|
+
"""
|
|
100
|
+
super().__init__(llm_client=llm_client, request_context=request_context)
|
|
101
|
+
self.allow_manual_trigger = allow_manual_trigger
|
|
102
|
+
self.output_pending_status = output_pending_status
|
|
103
|
+
|
|
104
|
+
def _load_generation_service_config(
|
|
105
|
+
self, request: ProfileGenerationRequest
|
|
106
|
+
) -> ProfileGenerationServiceConfig:
|
|
107
|
+
"""
|
|
108
|
+
Extract parameters from ProfileGenerationRequest.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
request: ProfileGenerationRequest containing request interaction groups and metadata
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
ProfileGenerationServiceConfig object
|
|
115
|
+
"""
|
|
116
|
+
# Get existing profiles for the user
|
|
117
|
+
# When output_pending_status is True (rerun mode), only include pending profiles as existing data
|
|
118
|
+
# This allows the LLM to generate fresh profiles instead of just mentioning current ones
|
|
119
|
+
if self.output_pending_status:
|
|
120
|
+
existing_profiles = self.storage.get_user_profile( # type: ignore[reportOptionalMemberAccess]
|
|
121
|
+
request.user_id, status_filter=[Status.PENDING]
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
existing_profiles = self.storage.get_user_profile(request.user_id) # type: ignore[reportOptionalMemberAccess]
|
|
125
|
+
|
|
126
|
+
return ProfileGenerationServiceConfig(
|
|
127
|
+
user_id=request.user_id,
|
|
128
|
+
request_id=request.request_id,
|
|
129
|
+
source=request.source,
|
|
130
|
+
existing_data=existing_profiles,
|
|
131
|
+
allow_manual_trigger=self.allow_manual_trigger,
|
|
132
|
+
output_pending_status=self.output_pending_status,
|
|
133
|
+
rerun_start_time=request.rerun_start_time,
|
|
134
|
+
rerun_end_time=request.rerun_end_time,
|
|
135
|
+
auto_run=request.auto_run,
|
|
136
|
+
force_extraction=request.force_extraction,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def _process_results(self, results: list[list[UserProfile]]) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Process, deduplicate, and apply all extracted profiles. Called once after all extractors complete.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
results: List of profile lists from extractors (one list per successful extractor)
|
|
145
|
+
"""
|
|
146
|
+
self._finalize_extracted_items(
|
|
147
|
+
[p for result in results if result for p in result]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def _finalize_extracted_items(self, all_new_profiles: list[UserProfile]) -> None:
|
|
151
|
+
"""Deduplicate, persist, and changelog extracted profile items."""
|
|
152
|
+
user_id = self.service_config.user_id # type: ignore[reportOptionalMemberAccess]
|
|
153
|
+
source = self.service_config.source # type: ignore[reportOptionalMemberAccess]
|
|
154
|
+
request_id = self.service_config.request_id # type: ignore[reportOptionalMemberAccess]
|
|
155
|
+
|
|
156
|
+
existing_ids_to_delete: list[str] = []
|
|
157
|
+
superseded_profiles: list[UserProfile] = []
|
|
158
|
+
|
|
159
|
+
# Always run deduplicator when enabled and there are new profiles
|
|
160
|
+
if all_new_profiles:
|
|
161
|
+
from reflexio.server.site_var.feature_flags import is_deduplicator_enabled
|
|
162
|
+
|
|
163
|
+
if is_deduplicator_enabled(self.org_id):
|
|
164
|
+
from reflexio.server.services.profile.profile_deduplicator import (
|
|
165
|
+
ProfileDeduplicator,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
deduplicator = ProfileDeduplicator(
|
|
169
|
+
request_context=self.request_context,
|
|
170
|
+
llm_client=self.client,
|
|
171
|
+
output_pending_status=self.output_pending_status,
|
|
172
|
+
)
|
|
173
|
+
all_new_profiles, existing_ids_to_delete, superseded_profiles = (
|
|
174
|
+
deduplicator.deduplicate(all_new_profiles, user_id, request_id)
|
|
175
|
+
)
|
|
176
|
+
logger.info(
|
|
177
|
+
"Profile updates after deduplication: %d profiles, %d existing to delete",
|
|
178
|
+
len(all_new_profiles),
|
|
179
|
+
len(existing_ids_to_delete),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Set source and status for all profiles
|
|
183
|
+
for profile in all_new_profiles:
|
|
184
|
+
profile.source = source
|
|
185
|
+
profile.status = Status.PENDING if self.output_pending_status else None
|
|
186
|
+
|
|
187
|
+
# Save new profiles
|
|
188
|
+
if all_new_profiles:
|
|
189
|
+
try:
|
|
190
|
+
self.storage.add_user_profile(user_id, all_new_profiles) # type: ignore[reportOptionalMemberAccess]
|
|
191
|
+
except Exception as e:
|
|
192
|
+
with sentry_tags(
|
|
193
|
+
subsystem="profile_generation",
|
|
194
|
+
op="save_profiles",
|
|
195
|
+
org_id=self.org_id,
|
|
196
|
+
user_id=user_id,
|
|
197
|
+
request_id=request_id,
|
|
198
|
+
error_type=type(e).__name__,
|
|
199
|
+
):
|
|
200
|
+
logger.exception(
|
|
201
|
+
"Failed to save profiles for user id: %s", user_id,
|
|
202
|
+
)
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
# Delete superseded existing profiles
|
|
206
|
+
if existing_ids_to_delete:
|
|
207
|
+
for profile_id in existing_ids_to_delete:
|
|
208
|
+
try:
|
|
209
|
+
self.storage.delete_user_profile( # type: ignore[reportOptionalMemberAccess]
|
|
210
|
+
DeleteUserProfileRequest(
|
|
211
|
+
user_id=user_id,
|
|
212
|
+
profile_id=profile_id,
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
except Exception as e: # noqa: PERF203
|
|
216
|
+
with sentry_tags(
|
|
217
|
+
subsystem="profile_generation",
|
|
218
|
+
op="delete_superseded_profile",
|
|
219
|
+
org_id=self.org_id,
|
|
220
|
+
user_id=user_id,
|
|
221
|
+
request_id=request_id,
|
|
222
|
+
profile_id=profile_id,
|
|
223
|
+
error_type=type(e).__name__,
|
|
224
|
+
):
|
|
225
|
+
logger.exception(
|
|
226
|
+
"Failed to delete superseded profile %s for user %s",
|
|
227
|
+
profile_id, user_id,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Create profile changelog post-deduplication
|
|
231
|
+
if all_new_profiles or superseded_profiles:
|
|
232
|
+
try:
|
|
233
|
+
profile_change_log = ProfileChangeLog(
|
|
234
|
+
id=0, # Auto-generated by storage
|
|
235
|
+
user_id=user_id,
|
|
236
|
+
request_id=request_id,
|
|
237
|
+
created_at=int(datetime.now(UTC).timestamp()),
|
|
238
|
+
added_profiles=all_new_profiles,
|
|
239
|
+
removed_profiles=superseded_profiles,
|
|
240
|
+
mentioned_profiles=[],
|
|
241
|
+
)
|
|
242
|
+
self.storage.add_profile_change_log(profile_change_log) # type: ignore[reportOptionalMemberAccess]
|
|
243
|
+
except Exception as e:
|
|
244
|
+
with sentry_tags(
|
|
245
|
+
subsystem="profile_generation",
|
|
246
|
+
op="add_profile_change_log",
|
|
247
|
+
org_id=self.org_id,
|
|
248
|
+
user_id=user_id,
|
|
249
|
+
request_id=request_id,
|
|
250
|
+
error_type=type(e).__name__,
|
|
251
|
+
):
|
|
252
|
+
logger.exception(
|
|
253
|
+
"Failed to add profile change log for user %s", user_id,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def check_and_update_profiles(self, profiles: list[UserProfile]) -> None:
|
|
257
|
+
"""check if the profiles are expired and update them if they are"""
|
|
258
|
+
raise NotImplementedError
|
|
259
|
+
|
|
260
|
+
def _load_extractor_config(self) -> ProfileExtractorConfig | None:
|
|
261
|
+
"""
|
|
262
|
+
Load the configured profile extractor from configurator.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
ProfileExtractorConfig | None: The configured profile extractor, if enabled.
|
|
266
|
+
"""
|
|
267
|
+
root_config = self.configurator.get_config()
|
|
268
|
+
return getattr(root_config, "profile_extractor_config", None)
|
|
269
|
+
|
|
270
|
+
def _create_extractor(
|
|
271
|
+
self,
|
|
272
|
+
extractor_config: ProfileExtractorConfig,
|
|
273
|
+
service_config: ProfileGenerationServiceConfig,
|
|
274
|
+
) -> ProfileExtractor:
|
|
275
|
+
"""
|
|
276
|
+
Create a ProfileExtractor instance from configuration.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
extractor_config: ProfileExtractorConfig configuration object from YAML
|
|
280
|
+
service_config: ProfileGenerationServiceConfig containing runtime parameters
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
ProfileExtractor instance
|
|
284
|
+
"""
|
|
285
|
+
return ProfileExtractor(
|
|
286
|
+
request_context=self.request_context,
|
|
287
|
+
llm_client=self.client,
|
|
288
|
+
extractor_config=extractor_config,
|
|
289
|
+
service_config=service_config,
|
|
290
|
+
agent_context=self.configurator.get_agent_context(),
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def _build_should_run_prompt(
|
|
294
|
+
self,
|
|
295
|
+
scoped_config: ProfileExtractorConfig,
|
|
296
|
+
session_data_models: list[RequestInteractionDataModel],
|
|
297
|
+
) -> str | None:
|
|
298
|
+
"""
|
|
299
|
+
Build prompt for consolidated should_extract_profile check.
|
|
300
|
+
|
|
301
|
+
Renders the configured extractor's profile definition and override
|
|
302
|
+
condition for one LLM call.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
scoped_config: Profile extractor config that had scoped interactions
|
|
306
|
+
session_data_models: Deduplicated request interaction data models
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
str | None: The rendered prompt, or None if no criteria to check
|
|
310
|
+
"""
|
|
311
|
+
new_interactions = format_sessions_to_history_string(session_data_models)
|
|
312
|
+
agent_context = self.configurator.get_agent_context()
|
|
313
|
+
prompt_manager = self.request_context.prompt_manager
|
|
314
|
+
|
|
315
|
+
criteria_parts = []
|
|
316
|
+
if scoped_config.extraction_definition_prompt:
|
|
317
|
+
criteria_parts.append(
|
|
318
|
+
f"definition: {scoped_config.extraction_definition_prompt.strip()}"
|
|
319
|
+
)
|
|
320
|
+
if scoped_config.should_extract_profile_prompt_override:
|
|
321
|
+
criteria_parts.append(
|
|
322
|
+
"condition: "
|
|
323
|
+
f"{scoped_config.should_extract_profile_prompt_override.strip()}"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
combined_criteria = "; ".join(criteria_parts)
|
|
327
|
+
if not combined_criteria:
|
|
328
|
+
return None
|
|
329
|
+
|
|
330
|
+
return prompt_manager.render_prompt(
|
|
331
|
+
ProfileGenerationServiceConstants.PROFILE_SHOULD_GENERATE_PROMPT_ID,
|
|
332
|
+
{
|
|
333
|
+
"agent_context_prompt": agent_context,
|
|
334
|
+
"should_extract_profile_prompt": combined_criteria,
|
|
335
|
+
"new_interactions": new_interactions,
|
|
336
|
+
},
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def _get_extractor_state_service_name(self) -> str:
|
|
340
|
+
"""
|
|
341
|
+
Get the service name for stride_size bookmark lookups.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
str: "profile_extractor" for OperationStateManager stride_size checks
|
|
345
|
+
"""
|
|
346
|
+
return "profile_extractor"
|
|
347
|
+
|
|
348
|
+
def _get_service_name(self) -> str:
|
|
349
|
+
"""
|
|
350
|
+
Get the name of the service for logging and operation state tracking.
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Service name string - "rerun_profile_generation" for rerun operations,
|
|
354
|
+
"profile_generation" for regular operations
|
|
355
|
+
"""
|
|
356
|
+
if self.output_pending_status:
|
|
357
|
+
return "rerun_profile_generation"
|
|
358
|
+
return "profile_generation"
|
|
359
|
+
|
|
360
|
+
def _get_base_service_name(self) -> str:
|
|
361
|
+
"""
|
|
362
|
+
Get the base service name for OperationStateManager keys.
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
str: "profile_generation"
|
|
366
|
+
"""
|
|
367
|
+
return "profile_generation"
|
|
368
|
+
|
|
369
|
+
def _should_track_in_progress(self) -> bool:
|
|
370
|
+
"""
|
|
371
|
+
Profile generation should track in-progress state to prevent duplicates.
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
bool: True - profile generation tracks in-progress state
|
|
375
|
+
"""
|
|
376
|
+
return True
|
|
377
|
+
|
|
378
|
+
def _get_lock_scope_id(self, request: ProfileGenerationRequest) -> str | None:
|
|
379
|
+
"""
|
|
380
|
+
Get the scope ID for lock key construction.
|
|
381
|
+
|
|
382
|
+
Profile generation is user-scoped, so returns user_id.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
request: The ProfileGenerationRequest
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
str: The user_id from the request
|
|
389
|
+
"""
|
|
390
|
+
return request.user_id
|
|
391
|
+
|
|
392
|
+
# ===============================
|
|
393
|
+
# Rerun hook implementations (override base class methods)
|
|
394
|
+
# ===============================
|
|
395
|
+
|
|
396
|
+
def _get_rerun_user_ids(self, request: RerunProfileGenerationRequest) -> list[str]:
|
|
397
|
+
"""Get user IDs to process. Extractors collect their own data.
|
|
398
|
+
|
|
399
|
+
Identifies unique user_ids with matching requests via storage-level filtering.
|
|
400
|
+
|
|
401
|
+
Args:
|
|
402
|
+
request: RerunProfileGenerationRequest with optional filters
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
List of user IDs to process
|
|
406
|
+
"""
|
|
407
|
+
return self.storage.get_rerun_user_ids( # type: ignore[reportOptionalMemberAccess]
|
|
408
|
+
user_id=request.user_id,
|
|
409
|
+
start_time=(
|
|
410
|
+
int(request.start_time.timestamp()) if request.start_time else None
|
|
411
|
+
),
|
|
412
|
+
end_time=(int(request.end_time.timestamp()) if request.end_time else None),
|
|
413
|
+
source=request.source,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
def _build_rerun_request_params(
|
|
417
|
+
self, request: RerunProfileGenerationRequest
|
|
418
|
+
) -> dict:
|
|
419
|
+
"""Build request params dict for operation state tracking.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
request: Original rerun request
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Dictionary of request parameters
|
|
426
|
+
"""
|
|
427
|
+
return {
|
|
428
|
+
"user_id": request.user_id,
|
|
429
|
+
"start_time": (
|
|
430
|
+
request.start_time.isoformat() if request.start_time else None
|
|
431
|
+
),
|
|
432
|
+
"end_time": request.end_time.isoformat() if request.end_time else None,
|
|
433
|
+
"source": request.source,
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
def _create_run_request_for_item(
|
|
437
|
+
self,
|
|
438
|
+
user_id: str,
|
|
439
|
+
request: RerunProfileGenerationRequest | ManualProfileGenerationRequest,
|
|
440
|
+
) -> ProfileGenerationRequest:
|
|
441
|
+
"""Create ProfileGenerationRequest for a single user.
|
|
442
|
+
|
|
443
|
+
Handles both rerun and manual request types.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
user_id: The user ID to process
|
|
447
|
+
request: The original rerun or manual request
|
|
448
|
+
|
|
449
|
+
Returns:
|
|
450
|
+
ProfileGenerationRequest for this user with filter constraints
|
|
451
|
+
"""
|
|
452
|
+
# Handle rerun requests (have start_time/end_time datetime objects)
|
|
453
|
+
if isinstance(request, RerunProfileGenerationRequest):
|
|
454
|
+
return ProfileGenerationRequest(
|
|
455
|
+
user_id=user_id,
|
|
456
|
+
request_id=f"rerun_{uuid.uuid4().hex[:8]}",
|
|
457
|
+
source=request.source,
|
|
458
|
+
rerun_start_time=(
|
|
459
|
+
int(request.start_time.timestamp()) if request.start_time else None
|
|
460
|
+
),
|
|
461
|
+
rerun_end_time=(
|
|
462
|
+
int(request.end_time.timestamp()) if request.end_time else None
|
|
463
|
+
),
|
|
464
|
+
auto_run=False,
|
|
465
|
+
)
|
|
466
|
+
# Handle manual requests (ManualProfileGenerationRequest)
|
|
467
|
+
return ProfileGenerationRequest(
|
|
468
|
+
user_id=user_id,
|
|
469
|
+
request_id=f"manual_{uuid.uuid4().hex[:8]}",
|
|
470
|
+
source=request.source,
|
|
471
|
+
auto_run=False,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
def _create_rerun_response(
|
|
475
|
+
self, success: bool, msg: str, count: int
|
|
476
|
+
) -> RerunProfileGenerationResponse:
|
|
477
|
+
"""Create RerunProfileGenerationResponse.
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
success: Whether the operation succeeded
|
|
481
|
+
msg: Status message
|
|
482
|
+
count: Number of profiles generated
|
|
483
|
+
|
|
484
|
+
Returns:
|
|
485
|
+
RerunProfileGenerationResponse
|
|
486
|
+
"""
|
|
487
|
+
return RerunProfileGenerationResponse(
|
|
488
|
+
success=success,
|
|
489
|
+
msg=msg,
|
|
490
|
+
profiles_generated=count,
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
def _get_generated_count(
|
|
494
|
+
self,
|
|
495
|
+
request: RerunProfileGenerationRequest,
|
|
496
|
+
processed_user_ids: list[str] | None = None,
|
|
497
|
+
) -> int:
|
|
498
|
+
"""Get the count of profiles generated during rerun.
|
|
499
|
+
|
|
500
|
+
Counts profiles with PENDING status for each processed user.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
request: The rerun request object
|
|
504
|
+
processed_user_ids: List of user IDs processed in the batch
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
Number of profiles generated
|
|
508
|
+
"""
|
|
509
|
+
user_ids = processed_user_ids or ([request.user_id] if request.user_id else [])
|
|
510
|
+
total = 0
|
|
511
|
+
for user_id in user_ids:
|
|
512
|
+
profiles = self.storage.get_user_profile( # type: ignore[reportOptionalMemberAccess]
|
|
513
|
+
user_id=user_id,
|
|
514
|
+
status_filter=[Status.PENDING],
|
|
515
|
+
)
|
|
516
|
+
total += len(profiles)
|
|
517
|
+
return total
|
|
518
|
+
|
|
519
|
+
# ===============================
|
|
520
|
+
# Upgrade/Downgrade hook implementations (override base class methods)
|
|
521
|
+
# ===============================
|
|
522
|
+
|
|
523
|
+
def _has_items_with_status(
|
|
524
|
+
self,
|
|
525
|
+
status: Status | None,
|
|
526
|
+
request: ProfileGenerationRequest, # noqa: ARG002
|
|
527
|
+
) -> bool:
|
|
528
|
+
"""Check if profiles exist with given status.
|
|
529
|
+
|
|
530
|
+
Args:
|
|
531
|
+
status: The status to check for (None for CURRENT)
|
|
532
|
+
request: The upgrade/downgrade request object
|
|
533
|
+
|
|
534
|
+
Returns:
|
|
535
|
+
bool: True if any matching profiles exist
|
|
536
|
+
"""
|
|
537
|
+
user_ids = self.storage.get_user_ids_with_status(status=status) # type: ignore[reportOptionalMemberAccess]
|
|
538
|
+
return bool(user_ids)
|
|
539
|
+
|
|
540
|
+
def _delete_items_by_status(
|
|
541
|
+
self,
|
|
542
|
+
status: Status,
|
|
543
|
+
request: ProfileGenerationRequest, # noqa: ARG002
|
|
544
|
+
) -> int:
|
|
545
|
+
"""Delete profiles with given status.
|
|
546
|
+
|
|
547
|
+
Args:
|
|
548
|
+
status: The status of profiles to delete
|
|
549
|
+
request: The upgrade/downgrade request object
|
|
550
|
+
|
|
551
|
+
Returns:
|
|
552
|
+
int: Number of profiles deleted
|
|
553
|
+
"""
|
|
554
|
+
return self.storage.delete_all_profiles_by_status(status=status) # type: ignore[reportOptionalMemberAccess]
|
|
555
|
+
|
|
556
|
+
def _update_items_status(
|
|
557
|
+
self,
|
|
558
|
+
old_status: Status | None,
|
|
559
|
+
new_status: Status | None,
|
|
560
|
+
request: ProfileGenerationRequest, # noqa: ARG002
|
|
561
|
+
user_ids: list[str] | None = None, # noqa: ARG002
|
|
562
|
+
) -> int:
|
|
563
|
+
"""Update profiles from old_status to new_status.
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
old_status: The current status to match (None for CURRENT)
|
|
567
|
+
new_status: The new status to set (None for CURRENT)
|
|
568
|
+
request: The upgrade/downgrade request object
|
|
569
|
+
user_ids: Optional pre-computed list of user IDs to filter by
|
|
570
|
+
|
|
571
|
+
Returns:
|
|
572
|
+
int: Number of profiles updated
|
|
573
|
+
"""
|
|
574
|
+
return self.storage.update_all_profiles_status( # type: ignore[reportOptionalMemberAccess]
|
|
575
|
+
old_status, new_status, user_ids=user_ids
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
def _get_affected_user_ids_for_upgrade(
|
|
579
|
+
self, request: ProfileGenerationRequest
|
|
580
|
+
) -> list[str] | None:
|
|
581
|
+
"""Get user IDs to filter by for upgrade operations.
|
|
582
|
+
|
|
583
|
+
Args:
|
|
584
|
+
request: The upgrade request object
|
|
585
|
+
|
|
586
|
+
Returns:
|
|
587
|
+
Optional[list[str]]: List of user IDs with PENDING profiles, or None for no filtering
|
|
588
|
+
"""
|
|
589
|
+
if hasattr(request, "only_affected_users") and request.only_affected_users: # type: ignore[reportAttributeAccessIssue]
|
|
590
|
+
return self.storage.get_user_ids_with_status(Status.PENDING) # type: ignore[reportOptionalMemberAccess]
|
|
591
|
+
return None
|
|
592
|
+
|
|
593
|
+
def _get_affected_user_ids_for_downgrade(
|
|
594
|
+
self, request: ProfileGenerationRequest
|
|
595
|
+
) -> list[str] | None:
|
|
596
|
+
"""Get user IDs to filter by for downgrade operations.
|
|
597
|
+
|
|
598
|
+
Args:
|
|
599
|
+
request: The downgrade request object
|
|
600
|
+
|
|
601
|
+
Returns:
|
|
602
|
+
Optional[list[str]]: List of user IDs with ARCHIVED profiles, or None for no filtering
|
|
603
|
+
"""
|
|
604
|
+
if hasattr(request, "only_affected_users") and request.only_affected_users: # type: ignore[reportAttributeAccessIssue]
|
|
605
|
+
return self.storage.get_user_ids_with_status(Status.ARCHIVED) # type: ignore[reportOptionalMemberAccess]
|
|
606
|
+
return None
|
|
607
|
+
|
|
608
|
+
def _create_status_change_response(
|
|
609
|
+
self,
|
|
610
|
+
operation: StatusChangeOperation,
|
|
611
|
+
success: bool,
|
|
612
|
+
counts: dict,
|
|
613
|
+
msg: str,
|
|
614
|
+
) -> UpgradeProfilesResponse | DowngradeProfilesResponse:
|
|
615
|
+
"""Create upgrade or downgrade response object for profiles.
|
|
616
|
+
|
|
617
|
+
Args:
|
|
618
|
+
operation: The operation type (UPGRADE or DOWNGRADE)
|
|
619
|
+
success: Whether the operation succeeded
|
|
620
|
+
counts: Dictionary of counts
|
|
621
|
+
msg: Status message
|
|
622
|
+
|
|
623
|
+
Returns:
|
|
624
|
+
UpgradeProfilesResponse or DowngradeProfilesResponse
|
|
625
|
+
"""
|
|
626
|
+
if operation == StatusChangeOperation.UPGRADE:
|
|
627
|
+
return UpgradeProfilesResponse(
|
|
628
|
+
success=success,
|
|
629
|
+
profiles_deleted=counts.get("deleted", 0),
|
|
630
|
+
profiles_archived=counts.get("archived", 0),
|
|
631
|
+
profiles_promoted=counts.get("promoted", 0),
|
|
632
|
+
message=msg,
|
|
633
|
+
)
|
|
634
|
+
# DOWNGRADE
|
|
635
|
+
return DowngradeProfilesResponse(
|
|
636
|
+
success=success,
|
|
637
|
+
profiles_demoted=counts.get("demoted", 0),
|
|
638
|
+
profiles_restored=counts.get("restored", 0),
|
|
639
|
+
message=msg,
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
# ===============================
|
|
643
|
+
# Manual Regular Generation (window-sized, CURRENT output)
|
|
644
|
+
# ===============================
|
|
645
|
+
|
|
646
|
+
def run_manual_regular(
|
|
647
|
+
self, request: ManualProfileGenerationRequest
|
|
648
|
+
) -> ManualProfileGenerationResponse:
|
|
649
|
+
"""
|
|
650
|
+
Run profile generation with window-sized interactions and CURRENT output.
|
|
651
|
+
|
|
652
|
+
This is a manual trigger that behaves like regular generation
|
|
653
|
+
(uses window_size, outputs CURRENT profiles) but only runs
|
|
654
|
+
profile extraction (not feedback or agent success).
|
|
655
|
+
|
|
656
|
+
Each extractor collects its own data using its configured window_size.
|
|
657
|
+
Uses progress tracking via OperationStateManager.
|
|
658
|
+
|
|
659
|
+
Args:
|
|
660
|
+
request: ManualProfileGenerationRequest with optional user_id, source, and extractor_names
|
|
661
|
+
|
|
662
|
+
Returns:
|
|
663
|
+
ManualProfileGenerationResponse with success status and count
|
|
664
|
+
"""
|
|
665
|
+
state_manager = self._create_state_manager()
|
|
666
|
+
|
|
667
|
+
try:
|
|
668
|
+
# Check for existing in-progress operation
|
|
669
|
+
error = state_manager.check_in_progress()
|
|
670
|
+
if error:
|
|
671
|
+
return ManualProfileGenerationResponse(
|
|
672
|
+
success=False, msg=error, profiles_generated=0
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
# 1. Get users to process
|
|
676
|
+
if request.user_id:
|
|
677
|
+
user_ids = [request.user_id]
|
|
678
|
+
else:
|
|
679
|
+
user_ids = self.storage.get_all_user_ids() # type: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess]
|
|
680
|
+
|
|
681
|
+
if not user_ids:
|
|
682
|
+
return ManualProfileGenerationResponse(
|
|
683
|
+
success=True,
|
|
684
|
+
msg="No users found to process",
|
|
685
|
+
profiles_generated=0,
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
# 2. Run batch with progress tracking
|
|
689
|
+
request_params = {
|
|
690
|
+
"user_id": request.user_id,
|
|
691
|
+
"source": request.source,
|
|
692
|
+
"mode": "manual_regular",
|
|
693
|
+
}
|
|
694
|
+
users_processed, _ = self._run_batch_with_progress(
|
|
695
|
+
user_ids=user_ids,
|
|
696
|
+
request=request, # type: ignore[reportArgumentType]
|
|
697
|
+
request_params=request_params,
|
|
698
|
+
state_manager=state_manager,
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
# 3. Count generated profiles (CURRENT status = None)
|
|
702
|
+
total_profiles = self._count_manual_generated(request)
|
|
703
|
+
|
|
704
|
+
return ManualProfileGenerationResponse(
|
|
705
|
+
success=True,
|
|
706
|
+
msg=f"Generated {total_profiles} profiles for {users_processed} user(s)",
|
|
707
|
+
profiles_generated=total_profiles,
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
except Exception as e:
|
|
711
|
+
state_manager.mark_progress_failed(str(e))
|
|
712
|
+
return ManualProfileGenerationResponse(
|
|
713
|
+
success=False,
|
|
714
|
+
msg=f"Failed to run manual profile generation: {str(e)}",
|
|
715
|
+
profiles_generated=0,
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
def _count_manual_generated(self, request: ManualProfileGenerationRequest) -> int:
|
|
719
|
+
"""
|
|
720
|
+
Count profiles generated during manual regular generation.
|
|
721
|
+
|
|
722
|
+
Counts profiles with CURRENT status (None), optionally filtered by user_id.
|
|
723
|
+
|
|
724
|
+
Args:
|
|
725
|
+
request: The manual generation request object
|
|
726
|
+
|
|
727
|
+
Returns:
|
|
728
|
+
Number of profiles with CURRENT status
|
|
729
|
+
"""
|
|
730
|
+
profiles = self.storage.get_user_profile( # type: ignore[reportOptionalMemberAccess]
|
|
731
|
+
user_id=request.user_id, # type: ignore[reportArgumentType]
|
|
732
|
+
status_filter=[None], # CURRENT profiles
|
|
733
|
+
)
|
|
734
|
+
return len(profiles)
|