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,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Feature flags module for gating features per organization.
|
|
3
|
+
|
|
4
|
+
Reads feature flag configuration from site_var and provides helpers
|
|
5
|
+
to check whether a given feature is enabled for an organization.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from reflexio.server.site_var.site_var_manager import SiteVarManager
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _get_feature_flags_config() -> dict:
|
|
16
|
+
"""
|
|
17
|
+
Load the feature_flags site var configuration.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
dict: The full feature flags config, or empty dict if not found.
|
|
21
|
+
"""
|
|
22
|
+
config = SiteVarManager().get_site_var("feature_flags")
|
|
23
|
+
if config is None or not isinstance(config, dict):
|
|
24
|
+
logger.warning(
|
|
25
|
+
"feature_flags site var not found or invalid, defaulting to empty config"
|
|
26
|
+
)
|
|
27
|
+
return {}
|
|
28
|
+
return config
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def is_feature_enabled(org_id: str, feature_name: str) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
Check if a feature is enabled for a given organization.
|
|
34
|
+
|
|
35
|
+
A feature is enabled if:
|
|
36
|
+
- The feature's "enabled" field is True (globally enabled), OR
|
|
37
|
+
- The org_id is in the feature's "enabled_org_ids" list.
|
|
38
|
+
|
|
39
|
+
If the feature is not found in config, it defaults to enabled (fail-open).
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
org_id (str): The organization ID to check
|
|
43
|
+
feature_name (str): The feature flag name (e.g. "deduplicator")
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
bool: True if the feature is enabled for this org
|
|
47
|
+
"""
|
|
48
|
+
config = _get_feature_flags_config()
|
|
49
|
+
feature_config = config.get(feature_name)
|
|
50
|
+
|
|
51
|
+
if feature_config is None:
|
|
52
|
+
# Unknown feature — default to enabled (fail-open)
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
if feature_config.get("enabled", False):
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
enabled_org_ids = feature_config.get("enabled_org_ids", [])
|
|
59
|
+
return org_id in enabled_org_ids
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_all_feature_flags(org_id: str) -> dict[str, bool]:
|
|
63
|
+
"""
|
|
64
|
+
Get the resolved enabled/disabled state of all feature flags for an organization.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
org_id (str): The organization ID to check
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
dict[str, bool]: Mapping of feature name to enabled status
|
|
71
|
+
"""
|
|
72
|
+
config = _get_feature_flags_config()
|
|
73
|
+
result: dict[str, bool] = {}
|
|
74
|
+
for feature_name in config:
|
|
75
|
+
result[feature_name] = is_feature_enabled(org_id, feature_name)
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def is_invitation_only_enabled() -> bool:
|
|
80
|
+
"""
|
|
81
|
+
Check if invitation-only registration mode is enabled globally.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
bool: True if invitation-only mode is enabled
|
|
85
|
+
"""
|
|
86
|
+
config = _get_feature_flags_config()
|
|
87
|
+
invitation_config = config.get("invitation_only")
|
|
88
|
+
if invitation_config is None:
|
|
89
|
+
return False
|
|
90
|
+
return invitation_config.get("enabled", False)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def is_deduplicator_enabled(org_id: str) -> bool:
|
|
94
|
+
"""
|
|
95
|
+
Convenience check for whether the deduplicator is enabled for an org.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
org_id (str): The organization ID to check
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
bool: True if deduplicator is enabled
|
|
102
|
+
"""
|
|
103
|
+
return is_feature_enabled(org_id, "deduplicator")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def is_resumable_extraction_agent_enabled(org_id: str) -> bool:
|
|
107
|
+
"""
|
|
108
|
+
Convenience check for whether classic extraction should use the resumable agent.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
org_id (str): The organization ID to check
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
bool: True if the resumable extraction agent is enabled
|
|
115
|
+
"""
|
|
116
|
+
return is_feature_enabled(org_id, "resumable_extraction_agent")
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import redis
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SiteVarManager:
|
|
11
|
+
"""
|
|
12
|
+
Manages site variables by loading JSON or text files from a source directory and caching them in Redis.
|
|
13
|
+
Each file in the source directory represents a site variable with the filename as the key.
|
|
14
|
+
Supports both .json and .txt files.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, source_dir: str | None = None, enable_redis: bool = False):
|
|
18
|
+
"""
|
|
19
|
+
Initialize the SiteVarManager with a source directory for site variable files.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
source_dir (Optional[str]): Directory containing JSON or text files for site variables
|
|
23
|
+
enable_redis (bool): Whether to enable Redis caching (default: False)
|
|
24
|
+
"""
|
|
25
|
+
self.source_dir = source_dir or str(Path(__file__).parent / "site_var_sources")
|
|
26
|
+
self.enable_redis = enable_redis
|
|
27
|
+
self.redis = (
|
|
28
|
+
redis.Redis(host="localhost", port=6379, db=0) if enable_redis else None
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# In-memory cache to avoid repeated file/Redis access
|
|
32
|
+
self._cache: dict[str, str | dict] = {}
|
|
33
|
+
|
|
34
|
+
# Ensure source directory exists
|
|
35
|
+
if not Path(self.source_dir).exists():
|
|
36
|
+
logger.warning(
|
|
37
|
+
"Source directory %s does not exist, creating it", self.source_dir
|
|
38
|
+
)
|
|
39
|
+
Path(self.source_dir).mkdir(parents=True, exist_ok=True)
|
|
40
|
+
|
|
41
|
+
def get_site_var(self, name: str) -> str | dict | None:
|
|
42
|
+
"""
|
|
43
|
+
Get a site variable by name. Checks in-memory cache first, then Redis cache (if enabled), then loads from file.
|
|
44
|
+
Supports both JSON and text files.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
name (str): Name of the site variable to retrieve
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Optional[str | dict]: The site variable value as JSON dict (for JSON files) or plain text (for text files), or None if not found
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
# First check in-memory cache
|
|
54
|
+
if name in self._cache:
|
|
55
|
+
logger.debug("Retrieved site var %s from in-memory cache", name)
|
|
56
|
+
return self._cache[name]
|
|
57
|
+
|
|
58
|
+
# Then try to get from Redis cache if enabled
|
|
59
|
+
if self.enable_redis and self.redis is not None:
|
|
60
|
+
cached_value = self.redis.get(name)
|
|
61
|
+
if cached_value is not None:
|
|
62
|
+
logger.debug("Retrieved site var %s from Redis cache", name)
|
|
63
|
+
decoded_value = cached_value.decode("utf-8") # type: ignore[reportAttributeAccessIssue]
|
|
64
|
+
# Try to parse as JSON for dict values
|
|
65
|
+
try:
|
|
66
|
+
parsed_value = json.loads(decoded_value)
|
|
67
|
+
self._cache[name] = parsed_value
|
|
68
|
+
return parsed_value
|
|
69
|
+
except json.JSONDecodeError:
|
|
70
|
+
# It's a plain text value
|
|
71
|
+
self._cache[name] = decoded_value
|
|
72
|
+
return decoded_value
|
|
73
|
+
|
|
74
|
+
# If not in cache or Redis disabled, try to load from file
|
|
75
|
+
content = self._load_from_file(name)
|
|
76
|
+
if content is not None:
|
|
77
|
+
# Cache in memory
|
|
78
|
+
self._cache[name] = content
|
|
79
|
+
|
|
80
|
+
# Cache in Redis for future use if enabled
|
|
81
|
+
if self.enable_redis and self.redis is not None:
|
|
82
|
+
# Convert dict to JSON string for Redis storage
|
|
83
|
+
redis_value = (
|
|
84
|
+
json.dumps(content) if isinstance(content, dict) else content
|
|
85
|
+
)
|
|
86
|
+
self.redis.set(name, redis_value)
|
|
87
|
+
logger.debug("Cached site var %s in Redis", name)
|
|
88
|
+
return content
|
|
89
|
+
logger.warning("Site var %s not found in Redis or files", name)
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
except redis.RedisError as e:
|
|
93
|
+
logger.error("Redis error while getting site var %s: %s", name, str(e))
|
|
94
|
+
# Fallback to file-based loading
|
|
95
|
+
content = self._load_from_file(name)
|
|
96
|
+
if content is not None:
|
|
97
|
+
self._cache[name] = content
|
|
98
|
+
return content
|
|
99
|
+
except Exception as e:
|
|
100
|
+
logger.error("Error loading site var %s: %s", name, str(e))
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
def evict_cache(self) -> None:
|
|
104
|
+
"""
|
|
105
|
+
Evict (clear) all cached site variables from in-memory cache.
|
|
106
|
+
This forces fresh loading from Redis or files on next access.
|
|
107
|
+
"""
|
|
108
|
+
cache_size = len(self._cache)
|
|
109
|
+
self._cache.clear()
|
|
110
|
+
logger.info("Evicted %d site variables from in-memory cache", cache_size)
|
|
111
|
+
|
|
112
|
+
def get_cache_stats(self) -> dict[str, int]:
|
|
113
|
+
"""
|
|
114
|
+
Get statistics about the in-memory cache.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
dict[str, int]: Cache statistics including size and key count
|
|
118
|
+
"""
|
|
119
|
+
return {
|
|
120
|
+
"cache_size": len(self._cache),
|
|
121
|
+
"cached_keys": len(list(self._cache.keys())),
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
def load_all_site_vars(self) -> dict[str, str | dict]:
|
|
125
|
+
"""
|
|
126
|
+
Load all site variables from files in the source directory and cache them in memory and Redis (if enabled).
|
|
127
|
+
Supports both JSON and text files.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
dict[str, str | dict]: Dictionary mapping site var names to their values
|
|
131
|
+
"""
|
|
132
|
+
site_vars = {}
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
if not Path(self.source_dir).exists():
|
|
136
|
+
logger.warning("Source directory %s does not exist", self.source_dir)
|
|
137
|
+
return site_vars
|
|
138
|
+
|
|
139
|
+
for filename in [p.name for p in Path(self.source_dir).iterdir()]:
|
|
140
|
+
if filename.endswith((".json", ".txt")):
|
|
141
|
+
name = self._get_name_from_filename(filename)
|
|
142
|
+
value = self.get_site_var(name) # This will use cache automatically
|
|
143
|
+
if value is not None:
|
|
144
|
+
site_vars[name] = value
|
|
145
|
+
|
|
146
|
+
logger.info(
|
|
147
|
+
"Loaded %d site variables, %d now in cache",
|
|
148
|
+
len(site_vars),
|
|
149
|
+
len(self._cache),
|
|
150
|
+
)
|
|
151
|
+
return site_vars
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error("Error loading site variables from directory: %s", str(e))
|
|
155
|
+
return site_vars
|
|
156
|
+
|
|
157
|
+
def list_site_vars(self) -> list[str]:
|
|
158
|
+
"""
|
|
159
|
+
List all available site variable names from the source directory.
|
|
160
|
+
Supports both .json and .txt files.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
list[str]: List of site variable names
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
if not Path(self.source_dir).exists():
|
|
167
|
+
return []
|
|
168
|
+
|
|
169
|
+
return [
|
|
170
|
+
entry.stem
|
|
171
|
+
for entry in Path(self.source_dir).iterdir()
|
|
172
|
+
if entry.name.endswith((".json", ".txt"))
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error("Error listing site variables: %s", str(e))
|
|
177
|
+
return []
|
|
178
|
+
|
|
179
|
+
def _find_file_path(self, name: str) -> str | None:
|
|
180
|
+
"""
|
|
181
|
+
Find the file path for a site variable, checking both .json and .txt extensions.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
name (str): Name of the site variable
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Optional[str]: Path to the file if found, None otherwise
|
|
188
|
+
"""
|
|
189
|
+
json_path = Path(self.source_dir) / f"{name}.json"
|
|
190
|
+
txt_path = Path(self.source_dir) / f"{name}.txt"
|
|
191
|
+
|
|
192
|
+
if json_path.exists():
|
|
193
|
+
return str(json_path)
|
|
194
|
+
if txt_path.exists():
|
|
195
|
+
return str(txt_path)
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
def _load_file_content(self, file_path: str) -> str | dict | None:
|
|
199
|
+
"""
|
|
200
|
+
Load content from a file, handling both JSON and text files.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
file_path (str): Path to the file to load
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Optional[str]: File content as string, or None if error
|
|
207
|
+
"""
|
|
208
|
+
try:
|
|
209
|
+
if not Path(file_path).exists():
|
|
210
|
+
logger.error("File %s does not exist", file_path)
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
if file_path.endswith(".txt"):
|
|
214
|
+
with Path(file_path).open(encoding="utf-8") as f:
|
|
215
|
+
return f.read().strip()
|
|
216
|
+
if file_path.endswith(".json"):
|
|
217
|
+
try:
|
|
218
|
+
# Parse to validate JSON, then return as string
|
|
219
|
+
with Path(file_path).open(encoding="utf-8") as f:
|
|
220
|
+
return json.load(f)
|
|
221
|
+
except json.JSONDecodeError as e:
|
|
222
|
+
logger.error("Invalid JSON in file %s: %s", file_path, str(e))
|
|
223
|
+
return None
|
|
224
|
+
else:
|
|
225
|
+
logger.error(
|
|
226
|
+
"Unsupported file type: %s. Use 'json' or 'txt'", file_path
|
|
227
|
+
)
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
except OSError as e:
|
|
231
|
+
logger.error("Error reading file %s: %s", file_path, str(e))
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
def _load_from_file(self, name: str) -> str | dict | None:
|
|
235
|
+
"""
|
|
236
|
+
Load a site variable directly from file (fallback method).
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
name (str): Name of the site variable
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Optional[str]: The site variable value, or None if not found
|
|
243
|
+
"""
|
|
244
|
+
file_path = self._find_file_path(name)
|
|
245
|
+
if file_path:
|
|
246
|
+
return self._load_file_content(file_path)
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
def _get_name_from_filename(self, filename: str) -> str:
|
|
250
|
+
"""
|
|
251
|
+
Extract the site variable name from a filename by removing the extension.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
filename (str): Filename with extension
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
str: Site variable name without extension
|
|
258
|
+
"""
|
|
259
|
+
if filename.endswith(".json"):
|
|
260
|
+
return filename[:-5]
|
|
261
|
+
if filename.endswith(".txt"):
|
|
262
|
+
return filename[:-4]
|
|
263
|
+
return filename
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Optional tracing hook for request-path profiling.
|
|
2
|
+
|
|
3
|
+
This module intentionally has no observability-vendor dependency. Deployments
|
|
4
|
+
that want tracing can register a tracer; deployments that do not register one
|
|
5
|
+
pay only a cheap context-manager/no-op cost.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from collections.abc import Iterator, Mapping
|
|
12
|
+
from contextlib import AbstractContextManager, contextmanager
|
|
13
|
+
from typing import Any, Protocol
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TraceSpan(Protocol):
|
|
19
|
+
"""Minimal span handle exposed to shared Reflexio code."""
|
|
20
|
+
|
|
21
|
+
def set_data(self, key: str, value: Any) -> None:
|
|
22
|
+
"""Attach low-cardinality metadata to the active span."""
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Tracer(Protocol):
|
|
27
|
+
"""Process-global tracer interface configured by enterprise startup."""
|
|
28
|
+
|
|
29
|
+
def span(self, name: str, **data: Any) -> AbstractContextManager[TraceSpan]:
|
|
30
|
+
"""Create a span context manager."""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _NoopTraceSpan:
|
|
35
|
+
def set_data(self, key: str, value: Any) -> None:
|
|
36
|
+
del key, value
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
_NOOP_SPAN = _NoopTraceSpan()
|
|
40
|
+
_tracer: Tracer | None = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def configure_tracer(tracer: Tracer | None) -> None:
|
|
44
|
+
"""Set the process-global tracer.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
tracer: Tracer implementation, or None to disable tracing.
|
|
48
|
+
"""
|
|
49
|
+
global _tracer
|
|
50
|
+
_tracer = tracer
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@contextmanager
|
|
54
|
+
def profile_step(name: str, **data: Any) -> Iterator[TraceSpan]:
|
|
55
|
+
"""Profile a named step if tracing is configured.
|
|
56
|
+
|
|
57
|
+
Tracing must never make product requests fail. Errors from creating,
|
|
58
|
+
entering, or exiting the tracing span are logged and swallowed. Exceptions
|
|
59
|
+
raised by the profiled product code are still propagated unchanged.
|
|
60
|
+
"""
|
|
61
|
+
tracer = _tracer
|
|
62
|
+
if tracer is None:
|
|
63
|
+
yield _NOOP_SPAN
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
span_cm = tracer.span(name, **data)
|
|
68
|
+
span = span_cm.__enter__()
|
|
69
|
+
except Exception as exc: # noqa: BLE001
|
|
70
|
+
logger.warning("Tracer failed to start span %s: %s", name, exc)
|
|
71
|
+
yield _NOOP_SPAN
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
yield span
|
|
76
|
+
except BaseException as exc:
|
|
77
|
+
try:
|
|
78
|
+
span_cm.__exit__(type(exc), exc, exc.__traceback__)
|
|
79
|
+
except Exception as tracer_exc: # noqa: BLE001
|
|
80
|
+
logger.warning("Tracer failed to finish span %s: %s", name, tracer_exc)
|
|
81
|
+
raise
|
|
82
|
+
else:
|
|
83
|
+
try:
|
|
84
|
+
span_cm.__exit__(None, None, None)
|
|
85
|
+
except Exception as exc: # noqa: BLE001
|
|
86
|
+
logger.warning("Tracer failed to finish span %s: %s", name, exc)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def set_span_data(span: TraceSpan, values: Mapping[str, Any]) -> None:
|
|
90
|
+
"""Best-effort helper for attaching multiple span fields."""
|
|
91
|
+
for key, value in values.items():
|
|
92
|
+
try:
|
|
93
|
+
span.set_data(key, value)
|
|
94
|
+
except Exception as exc: # noqa: BLE001
|
|
95
|
+
logger.warning("Tracer failed to set span data %s: %s", key, exc)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@contextmanager
|
|
99
|
+
def sentry_tags(**tags: Any) -> Iterator[None]:
|
|
100
|
+
"""Attach tags to any Sentry events produced inside the block.
|
|
101
|
+
|
|
102
|
+
Used inside ``except`` handlers, immediately wrapping a
|
|
103
|
+
``logger.exception(...)`` call, so the event auto-captured by
|
|
104
|
+
Sentry's ``LoggingIntegration`` is filterable by org / subsystem.
|
|
105
|
+
|
|
106
|
+
No-op when ``sentry-sdk`` is not installed (the OS package does not
|
|
107
|
+
declare it as a dependency; enterprise deployments pull it in).
|
|
108
|
+
Tag values that are ``None`` are skipped to avoid noisy "None" tags.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
**tags: arbitrary tag name → value pairs. Values are stringified.
|
|
112
|
+
|
|
113
|
+
Yields:
|
|
114
|
+
None. Re-enters the active Sentry scope for the duration of the
|
|
115
|
+
``with`` block.
|
|
116
|
+
"""
|
|
117
|
+
try:
|
|
118
|
+
import sentry_sdk # type: ignore[import-not-found]
|
|
119
|
+
except ImportError:
|
|
120
|
+
yield
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
# Mirrors `profile_step` above: instrumentation must never make a product
|
|
124
|
+
# request fail. If the Sentry SDK throws while opening or closing the
|
|
125
|
+
# scope, log and continue rather than letting the exception escape the
|
|
126
|
+
# caller's `with sentry_tags(...)` block and mask the original failure.
|
|
127
|
+
# `new_scope()` is the sentry-sdk >=2.0 replacement for the deprecated
|
|
128
|
+
# `push_scope()`; the AttributeError on the older 1.x SDK is caught by
|
|
129
|
+
# the broad `except` below so the helper still degrades cleanly.
|
|
130
|
+
try:
|
|
131
|
+
scope_cm = sentry_sdk.new_scope()
|
|
132
|
+
scope = scope_cm.__enter__()
|
|
133
|
+
except Exception as exc: # noqa: BLE001
|
|
134
|
+
logger.warning("Failed to open Sentry scope for tags: %s", exc)
|
|
135
|
+
yield
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
for key, value in tags.items():
|
|
139
|
+
if value is None:
|
|
140
|
+
continue
|
|
141
|
+
try:
|
|
142
|
+
scope.set_tag(key, str(value))
|
|
143
|
+
except Exception as exc: # noqa: BLE001
|
|
144
|
+
logger.warning("Failed to set Sentry tag %s: %s", key, exc)
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
yield
|
|
148
|
+
except BaseException as exc:
|
|
149
|
+
try:
|
|
150
|
+
scope_cm.__exit__(type(exc), exc, exc.__traceback__)
|
|
151
|
+
except Exception as cleanup_exc: # noqa: BLE001
|
|
152
|
+
logger.warning("Failed to close Sentry scope: %s", cleanup_exc)
|
|
153
|
+
raise
|
|
154
|
+
else:
|
|
155
|
+
try:
|
|
156
|
+
scope_cm.__exit__(None, None, None)
|
|
157
|
+
except Exception as exc: # noqa: BLE001
|
|
158
|
+
logger.warning("Failed to close Sentry scope: %s", exc)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Optional usage metrics hook.
|
|
2
|
+
|
|
3
|
+
This module intentionally has no storage or vendor dependency. Deployments that
|
|
4
|
+
want usage metrics can register a recorder; deployments that do not register one
|
|
5
|
+
pay only a cheap function-call/no-op cost.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
import time
|
|
12
|
+
from collections.abc import Callable, Mapping
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(slots=True, frozen=True)
|
|
20
|
+
class UsageEvent:
|
|
21
|
+
org_id: str
|
|
22
|
+
event_name: str
|
|
23
|
+
event_category: str
|
|
24
|
+
user_id: str | None = None
|
|
25
|
+
request_id: str | None = None
|
|
26
|
+
session_id: str | None = None
|
|
27
|
+
pipeline: str | None = None
|
|
28
|
+
entity_type: str | None = None
|
|
29
|
+
entity_id: str | None = None
|
|
30
|
+
extractor_name: str | None = None
|
|
31
|
+
playbook_name: str | None = None
|
|
32
|
+
source: str | None = None
|
|
33
|
+
agent_version: str | None = None
|
|
34
|
+
backend: str | None = None
|
|
35
|
+
outcome: str | None = None
|
|
36
|
+
count_value: int = 1
|
|
37
|
+
duration_ms: int | None = None
|
|
38
|
+
error_kind: str | None = None
|
|
39
|
+
metadata: Mapping[str, Any] = field(default_factory=dict)
|
|
40
|
+
created_at: float = field(default_factory=time.time)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
UsageEventRecorder = Callable[[UsageEvent], None]
|
|
44
|
+
|
|
45
|
+
_recorder: UsageEventRecorder | None = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def configure_usage_event_recorder(recorder: UsageEventRecorder | None) -> None:
|
|
49
|
+
"""Set the process-global usage metrics recorder.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
recorder: Callable that accepts UsageEvent, or None to disable metrics.
|
|
53
|
+
"""
|
|
54
|
+
global _recorder
|
|
55
|
+
_recorder = recorder
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def record_usage_event(
|
|
59
|
+
*,
|
|
60
|
+
org_id: str,
|
|
61
|
+
event_name: str,
|
|
62
|
+
event_category: str,
|
|
63
|
+
user_id: str | None = None,
|
|
64
|
+
request_id: str | None = None,
|
|
65
|
+
session_id: str | None = None,
|
|
66
|
+
pipeline: str | None = None,
|
|
67
|
+
entity_type: str | None = None,
|
|
68
|
+
entity_id: str | None = None,
|
|
69
|
+
extractor_name: str | None = None,
|
|
70
|
+
playbook_name: str | None = None,
|
|
71
|
+
source: str | None = None,
|
|
72
|
+
agent_version: str | None = None,
|
|
73
|
+
backend: str | None = None,
|
|
74
|
+
outcome: str | None = None,
|
|
75
|
+
count_value: int = 1,
|
|
76
|
+
duration_ms: int | None = None,
|
|
77
|
+
error_kind: str | None = None,
|
|
78
|
+
metadata: Mapping[str, Any] | None = None,
|
|
79
|
+
) -> None:
|
|
80
|
+
"""Record one usage event if a recorder is configured.
|
|
81
|
+
|
|
82
|
+
The product path must never fail because metrics failed, so this function
|
|
83
|
+
catches and logs all recorder errors.
|
|
84
|
+
"""
|
|
85
|
+
recorder = _recorder
|
|
86
|
+
if recorder is None:
|
|
87
|
+
return
|
|
88
|
+
try:
|
|
89
|
+
recorder(
|
|
90
|
+
UsageEvent(
|
|
91
|
+
org_id=str(org_id),
|
|
92
|
+
event_name=event_name,
|
|
93
|
+
event_category=event_category,
|
|
94
|
+
user_id=user_id,
|
|
95
|
+
request_id=request_id,
|
|
96
|
+
session_id=session_id,
|
|
97
|
+
pipeline=pipeline,
|
|
98
|
+
entity_type=entity_type,
|
|
99
|
+
entity_id=entity_id,
|
|
100
|
+
extractor_name=extractor_name,
|
|
101
|
+
playbook_name=playbook_name,
|
|
102
|
+
source=source,
|
|
103
|
+
agent_version=agent_version,
|
|
104
|
+
backend=backend,
|
|
105
|
+
outcome=outcome,
|
|
106
|
+
count_value=count_value,
|
|
107
|
+
duration_ms=duration_ms,
|
|
108
|
+
error_kind=error_kind,
|
|
109
|
+
metadata=metadata or {},
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
except Exception as exc: # noqa: BLE001
|
|
113
|
+
logger.warning("Usage metrics recorder failed: %s", exc)
|