claude-smart 0.2.42 → 0.2.44
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/bin/claude-smart.js +2 -2
- 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 +23 -3
- package/plugin/pyproject.toml +3 -3
- package/plugin/scripts/_lib.sh +91 -0
- package/plugin/scripts/backend-service.sh +51 -4
- package/plugin/scripts/cli.sh +3 -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 +1 -0
- package/plugin/scripts/hook_entry.sh +6 -3
- package/plugin/scripts/smart-install.sh +3 -2
- package/plugin/src/README.md +57 -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 +126 -5
- package/plugin/vendor/reflexio/.env.example +62 -0
- package/plugin/vendor/reflexio/LICENSE +201 -0
- package/plugin/vendor/reflexio/README.md +338 -0
- package/plugin/vendor/reflexio/pyproject.toml +274 -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 +265 -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 +964 -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 +1112 -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 +768 -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 +333 -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 +622 -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 +2868 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +34 -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 +562 -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 +359 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1871 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +140 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +479 -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 +338 -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 +288 -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 +187 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +716 -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_consolidation/v2.3.1.prompt.md +69 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +71 -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 +283 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.2.prompt.md +234 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +244 -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 +137 -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/README.md +58 -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 +336 -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 +1668 -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/embedding_text.py +62 -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 +358 -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 +535 -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 +779 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +94 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +702 -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 +1045 -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 +772 -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 +737 -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 +803 -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 +80 -0
- package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +756 -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 +1298 -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 +384 -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 +572 -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,964 @@
|
|
|
1
|
+
"""Interactive setup wizard for Reflexio integrations.
|
|
2
|
+
|
|
3
|
+
Note: a previous ``claude-code`` subcommand was removed; see the
|
|
4
|
+
submodule README migration notes for cleanup of legacy hook entries
|
|
5
|
+
in ``~/.claude/settings.json``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
import shutil
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Annotated
|
|
17
|
+
|
|
18
|
+
import typer
|
|
19
|
+
|
|
20
|
+
app = typer.Typer(
|
|
21
|
+
help=(
|
|
22
|
+
"Configure Reflexio: run 'init' for plain CLI setup, use 'openclaw' "
|
|
23
|
+
"to install host-tool hooks, or use 'openai-codex' to configure "
|
|
24
|
+
"Codex OAuth tokens."
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
_PROVIDERS: dict[str, dict[str, str]] = {
|
|
29
|
+
"openai": {
|
|
30
|
+
"env_var": "OPENAI_API_KEY",
|
|
31
|
+
"model": "gpt-5.4-mini",
|
|
32
|
+
"display": "OpenAI",
|
|
33
|
+
},
|
|
34
|
+
"anthropic": {
|
|
35
|
+
"env_var": "ANTHROPIC_API_KEY",
|
|
36
|
+
"model": "claude-sonnet-4-6",
|
|
37
|
+
"display": "Anthropic",
|
|
38
|
+
},
|
|
39
|
+
"gemini": {
|
|
40
|
+
"env_var": "GEMINI_API_KEY",
|
|
41
|
+
"model": "gemini-3-flash-preview",
|
|
42
|
+
"display": "Gemini",
|
|
43
|
+
},
|
|
44
|
+
"deepseek": {
|
|
45
|
+
"env_var": "DEEPSEEK_API_KEY",
|
|
46
|
+
"model": "deepseek-chat",
|
|
47
|
+
"display": "DeepSeek",
|
|
48
|
+
},
|
|
49
|
+
"openrouter": {
|
|
50
|
+
"env_var": "OPENROUTER_API_KEY",
|
|
51
|
+
"model": "gemini-3-flash-preview",
|
|
52
|
+
"display": "OpenRouter",
|
|
53
|
+
},
|
|
54
|
+
"minimax": {
|
|
55
|
+
"env_var": "MINIMAX_API_KEY",
|
|
56
|
+
"model": "MiniMax-M2.7",
|
|
57
|
+
"display": "MiniMax",
|
|
58
|
+
},
|
|
59
|
+
"dashscope": {
|
|
60
|
+
"env_var": "DASHSCOPE_API_KEY",
|
|
61
|
+
"model": "qwen-plus",
|
|
62
|
+
"display": "DashScope",
|
|
63
|
+
},
|
|
64
|
+
"xai": {"env_var": "XAI_API_KEY", "model": "grok-3-mini", "display": "xAI"},
|
|
65
|
+
"moonshot": {
|
|
66
|
+
"env_var": "MOONSHOT_API_KEY",
|
|
67
|
+
"model": "moonshot-v1-8k",
|
|
68
|
+
"display": "Moonshot",
|
|
69
|
+
},
|
|
70
|
+
"zai": {"env_var": "ZAI_API_KEY", "model": "glm-4-flash", "display": "ZAI"},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_EMBEDDING_PROVIDERS: frozenset[str] = frozenset({"openai", "gemini"})
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _set_env_var(env_path: Path, key: str, value: str) -> None:
|
|
77
|
+
"""Write or update an environment variable in a .env file.
|
|
78
|
+
|
|
79
|
+
Thin wrapper around :func:`reflexio.cli.env_loader.set_env_var` kept
|
|
80
|
+
for backward compatibility with tests that import this name.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
env_path (Path): Path to the .env file.
|
|
84
|
+
key (str): Environment variable name.
|
|
85
|
+
value (str): Environment variable value.
|
|
86
|
+
"""
|
|
87
|
+
from reflexio.cli.env_loader import set_env_var
|
|
88
|
+
|
|
89
|
+
set_env_var(env_path, key, value)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _prompt_llm_provider(env_path: Path) -> tuple[str, str, str]:
|
|
93
|
+
"""Interactively prompt the user to choose an LLM provider and API key.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
env_path (Path): Path to the .env file for writing the key.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
tuple[str, str, str]: The display name, default model, and provider key
|
|
100
|
+
for the chosen provider.
|
|
101
|
+
"""
|
|
102
|
+
provider_keys = list(_PROVIDERS.keys())
|
|
103
|
+
|
|
104
|
+
typer.echo("\nWhich LLM provider for feedback extraction?")
|
|
105
|
+
for idx, key in enumerate(provider_keys, 1):
|
|
106
|
+
display = _PROVIDERS[key]["display"]
|
|
107
|
+
model = _PROVIDERS[key]["model"]
|
|
108
|
+
typer.echo(f" [{idx}] {display:<14s} ({model})")
|
|
109
|
+
|
|
110
|
+
choice = typer.prompt("Choice", type=int)
|
|
111
|
+
if not 1 <= choice <= len(provider_keys):
|
|
112
|
+
typer.echo(f"Error: choice must be between 1 and {len(provider_keys)}")
|
|
113
|
+
raise typer.Exit(1)
|
|
114
|
+
|
|
115
|
+
selected_key = provider_keys[choice - 1]
|
|
116
|
+
provider_info = _PROVIDERS[selected_key]
|
|
117
|
+
env_var = provider_info["env_var"]
|
|
118
|
+
model = provider_info["model"]
|
|
119
|
+
display_name = provider_info["display"]
|
|
120
|
+
|
|
121
|
+
api_key = typer.prompt(f"Enter your {env_var}")
|
|
122
|
+
if not api_key.strip():
|
|
123
|
+
typer.echo("Error: API key cannot be empty")
|
|
124
|
+
raise typer.Exit(1)
|
|
125
|
+
_set_env_var(env_path, env_var, api_key)
|
|
126
|
+
|
|
127
|
+
return display_name, model, selected_key
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# Map embedding provider keys to their canonical model names. Used by both
|
|
131
|
+
# the interactive prompt (writes the choice to org config) and the
|
|
132
|
+
# ``--embedding`` flag (skips the prompt entirely for CI). Kept here so the
|
|
133
|
+
# two call sites can't drift on what e.g. "gemini" actually means.
|
|
134
|
+
_EMBEDDING_MODEL_NAMES: dict[str, str] = {
|
|
135
|
+
"local": "local/minilm-l6-v2",
|
|
136
|
+
"openai": "text-embedding-3-small",
|
|
137
|
+
"gemini": "gemini/gemini-embedding-001",
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Valid values for the ``--embedding`` flag across every setup command.
|
|
142
|
+
# Defined once here so a typo in one command surface (init, openclaw)
|
|
143
|
+
# doesn't silently fall through to "auto" in another.
|
|
144
|
+
_VALID_EMBEDDING_FLAGS: frozenset[str] = frozenset(
|
|
145
|
+
{"auto", "local", "openai", "gemini"}
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _build_embedding_choices() -> list[tuple[str, str | None, str]]:
|
|
150
|
+
"""Build the interactive embedding-provider menu at call time.
|
|
151
|
+
|
|
152
|
+
The local option is included only when ``chromadb`` is importable; built
|
|
153
|
+
dynamically so the menu always reflects the current Python environment
|
|
154
|
+
rather than a snapshot frozen at module load.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
list[tuple[str, str | None, str]]: ``(provider_key, env_var_name,
|
|
158
|
+
display_label)`` rows. ``env_var_name`` is ``None`` for the local
|
|
159
|
+
provider (no API key needed).
|
|
160
|
+
"""
|
|
161
|
+
from reflexio.server.llm.providers.local_embedding_provider import (
|
|
162
|
+
is_chromadb_importable,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
choices: list[tuple[str, str | None, str]] = []
|
|
166
|
+
if is_chromadb_importable():
|
|
167
|
+
choices.append(
|
|
168
|
+
(
|
|
169
|
+
"local",
|
|
170
|
+
None,
|
|
171
|
+
"Local (in-process MiniLM-L6-v2; ~25 MB; no API key needed)",
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
choices.extend(
|
|
175
|
+
[
|
|
176
|
+
("openai", "OPENAI_API_KEY", "OpenAI (text-embedding-3-small)"),
|
|
177
|
+
("gemini", "GEMINI_API_KEY", "Gemini (gemini-embedding-001)"),
|
|
178
|
+
]
|
|
179
|
+
)
|
|
180
|
+
return choices
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _is_non_interactive() -> bool:
|
|
184
|
+
"""Return True when prompts must be skipped (CI / scripted use).
|
|
185
|
+
|
|
186
|
+
Two triggers:
|
|
187
|
+
|
|
188
|
+
- stdin is not a TTY (``nohup``, container, pipe-fed shell)
|
|
189
|
+
- ``REFLEXIO_NONINTERACTIVE=1`` in the environment (explicit opt-out)
|
|
190
|
+
"""
|
|
191
|
+
if os.environ.get("REFLEXIO_NONINTERACTIVE") == "1":
|
|
192
|
+
return True
|
|
193
|
+
return not sys.stdin.isatty()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _prompt_embedding_provider(env_path: Path, llm_provider_key: str) -> str | None:
|
|
197
|
+
"""Prompt for an embedding-capable API key if the LLM provider lacks embedding support.
|
|
198
|
+
|
|
199
|
+
Skips the prompt when the LLM provider already supports embeddings, or
|
|
200
|
+
when the environment is non-interactive (no TTY or
|
|
201
|
+
``REFLEXIO_NONINTERACTIVE=1``). In the non-interactive case the first
|
|
202
|
+
available choice is returned without writing to ``.env``.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
env_path (Path): Path to the .env file for writing the key.
|
|
206
|
+
llm_provider_key (str): The provider key selected for LLM generation.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
str | None: Display name of the embedding provider, or None if the LLM
|
|
210
|
+
provider already supports embeddings.
|
|
211
|
+
"""
|
|
212
|
+
if llm_provider_key in _EMBEDDING_PROVIDERS:
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
choices = _build_embedding_choices()
|
|
216
|
+
if not choices:
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
# Non-interactive: pick the first available option without prompting. When
|
|
220
|
+
# chromadb is importable that's local (no key required); otherwise it's
|
|
221
|
+
# OpenAI or Gemini, which still won't have an API key but at least the
|
|
222
|
+
# caller knows the wizard didn't block.
|
|
223
|
+
if _is_non_interactive():
|
|
224
|
+
provider_key, env_var, _ = choices[0]
|
|
225
|
+
if env_var is None:
|
|
226
|
+
# Local needs no key — nothing to write.
|
|
227
|
+
return _provider_display(provider_key)
|
|
228
|
+
return _provider_display(provider_key)
|
|
229
|
+
|
|
230
|
+
llm_display = _PROVIDERS[llm_provider_key]["display"]
|
|
231
|
+
typer.echo(f"\nYour LLM provider ({llm_display}) doesn't support text embeddings.")
|
|
232
|
+
typer.echo("Reflexio needs an embedding model for semantic search.\n")
|
|
233
|
+
typer.echo("Which provider for embeddings?")
|
|
234
|
+
for idx, (_, _, label) in enumerate(choices, 1):
|
|
235
|
+
typer.echo(f" [{idx}] {label}")
|
|
236
|
+
|
|
237
|
+
choice = typer.prompt("Choice", type=int, default=1)
|
|
238
|
+
if not 1 <= choice <= len(choices):
|
|
239
|
+
typer.echo(f"Error: choice must be between 1 and {len(choices)}")
|
|
240
|
+
raise typer.Exit(1)
|
|
241
|
+
|
|
242
|
+
provider_key, env_var, _ = choices[choice - 1]
|
|
243
|
+
if env_var is None:
|
|
244
|
+
# Local: no API key needed.
|
|
245
|
+
return _provider_display(provider_key)
|
|
246
|
+
|
|
247
|
+
api_key = typer.prompt(f"Enter your {env_var}")
|
|
248
|
+
if not api_key.strip():
|
|
249
|
+
typer.echo("Error: API key cannot be empty")
|
|
250
|
+
raise typer.Exit(1)
|
|
251
|
+
_set_env_var(env_path, env_var, api_key)
|
|
252
|
+
|
|
253
|
+
return _provider_display(provider_key)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _provider_display(provider_key: str) -> str:
|
|
257
|
+
"""Return the user-facing display name for a provider key.
|
|
258
|
+
|
|
259
|
+
The local provider isn't in ``_PROVIDERS`` (which only lists LLM
|
|
260
|
+
providers), so this helper centralizes the special case.
|
|
261
|
+
"""
|
|
262
|
+
if provider_key == "local":
|
|
263
|
+
return "Local (MiniLM-L6-v2)"
|
|
264
|
+
return _PROVIDERS[provider_key]["display"]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _write_embedding_model_to_org_config(model_name: str) -> None:
|
|
268
|
+
"""Persist the user's embedding choice to the default-org config file.
|
|
269
|
+
|
|
270
|
+
Loads the existing config, updates ``llm_config.embedding_model_name``,
|
|
271
|
+
and writes it back. All other fields are preserved. Reuses the same
|
|
272
|
+
``LocalFileConfigStorage`` round-trip pattern as ``save_storage_to_config``.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
model_name: Canonical model name to persist
|
|
276
|
+
(e.g. ``"local/minilm-l6-v2"``).
|
|
277
|
+
"""
|
|
278
|
+
from reflexio.models.config_schema import LLMConfig
|
|
279
|
+
from reflexio.server.services.configurator.local_file_config_storage import (
|
|
280
|
+
LocalFileConfigStorage,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
storage = LocalFileConfigStorage("self-host-org")
|
|
284
|
+
config = storage.load_config()
|
|
285
|
+
if config.llm_config is None:
|
|
286
|
+
config.llm_config = LLMConfig(embedding_model_name=model_name)
|
|
287
|
+
else:
|
|
288
|
+
config.llm_config.embedding_model_name = model_name
|
|
289
|
+
storage.save_config(config)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _choose_embedding_provider(env_path: Path, *, embedding_flag: str) -> str | None:
|
|
293
|
+
"""Run the upfront embedding-provider step for ``setup init``.
|
|
294
|
+
|
|
295
|
+
Behaviour matrix:
|
|
296
|
+
|
|
297
|
+
+-----------------+----------------+-------------------------------------+
|
|
298
|
+
| ``embedding`` | TTY? | What happens |
|
|
299
|
+
+=================+================+=====================================+
|
|
300
|
+
| ``"local"`` / | (any) | Write the matching model to org |
|
|
301
|
+
| ``"openai"`` / | | config; no prompt. |
|
|
302
|
+
| ``"gemini"`` | | |
|
|
303
|
+
+-----------------+----------------+-------------------------------------+
|
|
304
|
+
| ``"auto"`` | non-interactive| No prompt, no org-config write — |
|
|
305
|
+
| | | runtime auto-detection (Layer A) |
|
|
306
|
+
| | | picks the embedder. |
|
|
307
|
+
+-----------------+----------------+-------------------------------------+
|
|
308
|
+
| ``"auto"`` | interactive | Show the menu (default = local |
|
|
309
|
+
| | | when chromadb is importable). Write |
|
|
310
|
+
| | | the choice to org config; for |
|
|
311
|
+
| | | OpenAI / Gemini also collect the |
|
|
312
|
+
| | | API key inline. |
|
|
313
|
+
+-----------------+----------------+-------------------------------------+
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
env_path: Path to the user's .env file. Used to write the cloud
|
|
317
|
+
embedding API key when the user picks OpenAI / Gemini in the
|
|
318
|
+
interactive prompt.
|
|
319
|
+
embedding_flag: Value of the ``--embedding`` flag. ``"auto"`` is
|
|
320
|
+
the default and means "ask interactively, or fall back to
|
|
321
|
+
runtime auto-detection if there's no TTY."
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
str | None: Display name of the chosen embedding provider, or None
|
|
325
|
+
when no override was written (auto + non-interactive, or no
|
|
326
|
+
choices available).
|
|
327
|
+
"""
|
|
328
|
+
if embedding_flag in _EMBEDDING_MODEL_NAMES:
|
|
329
|
+
# Explicit non-default flag wins over interactive / auto-detection.
|
|
330
|
+
# ``--embedding=local`` requires chromadb at runtime, so refuse to
|
|
331
|
+
# persist a broken override the same way the interactive flow
|
|
332
|
+
# hides the option in that situation.
|
|
333
|
+
if embedding_flag == "local":
|
|
334
|
+
from reflexio.server.llm.providers.local_embedding_provider import (
|
|
335
|
+
is_chromadb_importable,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
if not is_chromadb_importable():
|
|
339
|
+
typer.echo(
|
|
340
|
+
"Error: --embedding=local requires chromadb. "
|
|
341
|
+
"Install it with `pip install chromadb` or pick "
|
|
342
|
+
"openai/gemini/auto."
|
|
343
|
+
)
|
|
344
|
+
raise typer.Exit(1)
|
|
345
|
+
_write_embedding_model_to_org_config(_EMBEDDING_MODEL_NAMES[embedding_flag])
|
|
346
|
+
return _provider_display(embedding_flag)
|
|
347
|
+
|
|
348
|
+
# embedding_flag == "auto" from here on.
|
|
349
|
+
if _is_non_interactive():
|
|
350
|
+
# No TTY → runtime auto-detection picks the embedder. No write.
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
choices = _build_embedding_choices()
|
|
354
|
+
if not choices:
|
|
355
|
+
# No providers available (chromadb not importable AND no cloud
|
|
356
|
+
# embedders in scope). Defer to runtime auto-detection, which will
|
|
357
|
+
# raise a clear error if nothing matches.
|
|
358
|
+
return None
|
|
359
|
+
|
|
360
|
+
typer.echo("\nChoose embedding provider:")
|
|
361
|
+
for idx, (_, _, label) in enumerate(choices, 1):
|
|
362
|
+
suffix = " — recommended" if idx == 1 else ""
|
|
363
|
+
typer.echo(f" [{idx}] {label}{suffix}")
|
|
364
|
+
|
|
365
|
+
choice = typer.prompt("Choice", type=int, default=1)
|
|
366
|
+
if not 1 <= choice <= len(choices):
|
|
367
|
+
typer.echo(f"Error: choice must be between 1 and {len(choices)}")
|
|
368
|
+
raise typer.Exit(1)
|
|
369
|
+
|
|
370
|
+
provider_key, env_var, _ = choices[choice - 1]
|
|
371
|
+
|
|
372
|
+
# For cloud embedders the user clearly wants that provider, so collect
|
|
373
|
+
# the API key inline if it isn't already set. Local has env_var=None.
|
|
374
|
+
# Validation runs BEFORE the org-config write so a blank API key
|
|
375
|
+
# leaves ``llm_config.embedding_model_name`` untouched rather than
|
|
376
|
+
# mutating it to a provider that still isn't configured.
|
|
377
|
+
if env_var is not None and not os.environ.get(env_var):
|
|
378
|
+
api_key = typer.prompt(f"Enter your {env_var}")
|
|
379
|
+
if not api_key.strip():
|
|
380
|
+
typer.echo("Error: API key cannot be empty")
|
|
381
|
+
raise typer.Exit(1)
|
|
382
|
+
_set_env_var(env_path, env_var, api_key)
|
|
383
|
+
|
|
384
|
+
_write_embedding_model_to_org_config(_EMBEDDING_MODEL_NAMES[provider_key])
|
|
385
|
+
return _provider_display(provider_key)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
_LOCAL_SERVER_URL = "http://localhost:8081"
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _prompt_local_sqlite(env_path: Path) -> str:
|
|
392
|
+
"""Option 1 — local SQLite with a local Reflexio server.
|
|
393
|
+
|
|
394
|
+
Writes ``REFLEXIO_URL`` pointing at the local server so the CLI
|
|
395
|
+
and any installed integration hooks (e.g., OpenClaw) know where
|
|
396
|
+
to connect.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
env_path (Path): Path to the .env file.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
str: Storage label for the wizard summary.
|
|
403
|
+
"""
|
|
404
|
+
_set_env_var(env_path, "REFLEXIO_URL", _LOCAL_SERVER_URL)
|
|
405
|
+
return "SQLite (local)"
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _prompt_managed_reflexio(env_path: Path) -> str:
|
|
409
|
+
"""Option 2 — point the CLI at reflexio.ai + verify via whoami.
|
|
410
|
+
|
|
411
|
+
Prompts for a Reflexio API key, writes ``REFLEXIO_URL`` and
|
|
412
|
+
``REFLEXIO_API_KEY`` to ``.env``, then calls ``whoami()`` to
|
|
413
|
+
verify the account and show resolved storage per-org.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
env_path (Path): Path to the .env file.
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
str: Storage label for the wizard summary.
|
|
420
|
+
"""
|
|
421
|
+
reflexio_api_key = typer.prompt("Reflexio API key")
|
|
422
|
+
if not reflexio_api_key.strip():
|
|
423
|
+
typer.echo("Error: API key cannot be empty")
|
|
424
|
+
raise typer.Exit(1)
|
|
425
|
+
|
|
426
|
+
from reflexio.defaults import DEFAULT_SERVER_URL
|
|
427
|
+
|
|
428
|
+
_set_env_var(env_path, "REFLEXIO_URL", DEFAULT_SERVER_URL)
|
|
429
|
+
_set_env_var(env_path, "REFLEXIO_API_KEY", reflexio_api_key)
|
|
430
|
+
|
|
431
|
+
try:
|
|
432
|
+
from reflexio.client.client import ReflexioClient
|
|
433
|
+
|
|
434
|
+
client = ReflexioClient(
|
|
435
|
+
api_key=reflexio_api_key, url_endpoint=DEFAULT_SERVER_URL
|
|
436
|
+
)
|
|
437
|
+
resp = client.whoami()
|
|
438
|
+
except Exception as exc: # noqa: BLE001
|
|
439
|
+
typer.echo(f"\n (could not verify account — {type(exc).__name__}: {exc})")
|
|
440
|
+
return "Managed Reflexio"
|
|
441
|
+
|
|
442
|
+
if not resp.success:
|
|
443
|
+
typer.echo(
|
|
444
|
+
f"\n (account verification failed: {resp.message or 'unknown error'})"
|
|
445
|
+
)
|
|
446
|
+
return "Managed Reflexio"
|
|
447
|
+
|
|
448
|
+
# Detect the "server is in self-host mode" case. If the remote server
|
|
449
|
+
# returns the canonical ``self-host-org`` default org id, it means
|
|
450
|
+
# auth isn't being enforced — anyone hitting the endpoint without a
|
|
451
|
+
# token would see the same response. The user's API key was not
|
|
452
|
+
# actually validated, and any publishes will land in the server's
|
|
453
|
+
# shared default storage instead of the user's per-org Supabase.
|
|
454
|
+
if resp.org_id == "self-host-org":
|
|
455
|
+
typer.echo(
|
|
456
|
+
"\n ⚠ The remote server returned the default 'self-host-org' "
|
|
457
|
+
"identity instead of your real org."
|
|
458
|
+
)
|
|
459
|
+
typer.echo(
|
|
460
|
+
" Your API key was NOT validated. The server is running in "
|
|
461
|
+
"self-host mode, which means:"
|
|
462
|
+
)
|
|
463
|
+
typer.echo(
|
|
464
|
+
" • All publishes will land in the server's shared "
|
|
465
|
+
"storage, not your per-org Supabase."
|
|
466
|
+
)
|
|
467
|
+
typer.echo(
|
|
468
|
+
" • Other users hitting the same server share the same data namespace."
|
|
469
|
+
)
|
|
470
|
+
typer.echo(
|
|
471
|
+
" Contact the server operator to enable enterprise auth, "
|
|
472
|
+
"or point REFLEXIO_URL at a deployment that enforces it."
|
|
473
|
+
)
|
|
474
|
+
return "Managed Reflexio"
|
|
475
|
+
|
|
476
|
+
typer.echo("\n Verified cloud account:")
|
|
477
|
+
typer.echo(f" Org ID: {resp.org_id}")
|
|
478
|
+
typer.echo(f" Storage type: {resp.storage_type or 'unconfigured'}")
|
|
479
|
+
if resp.storage_label:
|
|
480
|
+
marker = "[configured]" if resp.storage_configured else "[unconfigured]"
|
|
481
|
+
typer.echo(f" Storage: {resp.storage_label} {marker}")
|
|
482
|
+
if not resp.storage_configured:
|
|
483
|
+
typer.echo(
|
|
484
|
+
"\n ⚠ Your org has no storage configured at "
|
|
485
|
+
f"{DEFAULT_SERVER_URL}/settings."
|
|
486
|
+
)
|
|
487
|
+
typer.echo(
|
|
488
|
+
" Publishes will succeed but no data will be written until "
|
|
489
|
+
"you configure it."
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
return "Managed Reflexio"
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def _prompt_self_hosted(env_path: Path) -> str:
|
|
496
|
+
"""Option 3 — point the CLI at a self-hosted Reflexio server.
|
|
497
|
+
|
|
498
|
+
Prompts for a Reflexio API key and writes ``REFLEXIO_URL`` (defaulting
|
|
499
|
+
to localhost) and ``REFLEXIO_API_KEY`` to ``.env``.
|
|
500
|
+
|
|
501
|
+
Args:
|
|
502
|
+
env_path (Path): Path to the .env file for writing credentials.
|
|
503
|
+
|
|
504
|
+
Returns:
|
|
505
|
+
str: Storage label for the wizard summary.
|
|
506
|
+
"""
|
|
507
|
+
reflexio_url = typer.prompt("Reflexio server URL", default=_LOCAL_SERVER_URL)
|
|
508
|
+
reflexio_api_key = typer.prompt("Reflexio API key")
|
|
509
|
+
if not reflexio_api_key.strip():
|
|
510
|
+
typer.echo("Error: API key cannot be empty")
|
|
511
|
+
raise typer.Exit(1)
|
|
512
|
+
|
|
513
|
+
_set_env_var(env_path, "REFLEXIO_URL", reflexio_url)
|
|
514
|
+
_set_env_var(env_path, "REFLEXIO_API_KEY", reflexio_api_key)
|
|
515
|
+
|
|
516
|
+
return "Self-hosted Reflexio"
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def _prompt_storage(env_path: Path) -> str:
|
|
520
|
+
"""Interactively prompt the user to choose a storage backend.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
env_path (Path): Path to the .env file to update.
|
|
524
|
+
|
|
525
|
+
Returns:
|
|
526
|
+
str: The storage mode label for the wizard summary.
|
|
527
|
+
"""
|
|
528
|
+
typer.echo("\nWhere should Reflexio store data?")
|
|
529
|
+
typer.echo(" [1] Local SQLite (default, no setup needed)")
|
|
530
|
+
typer.echo(
|
|
531
|
+
" [2] Managed Reflexio (reflexio.ai — storage managed at reflexio.ai/settings)"
|
|
532
|
+
)
|
|
533
|
+
typer.echo(" [3] Self-hosted Reflexio (connect to your own server)")
|
|
534
|
+
|
|
535
|
+
choice = typer.prompt("Choice", type=int, default=1)
|
|
536
|
+
if choice == 1:
|
|
537
|
+
return _prompt_local_sqlite(env_path)
|
|
538
|
+
if choice == 2:
|
|
539
|
+
return _prompt_managed_reflexio(env_path)
|
|
540
|
+
if choice == 3:
|
|
541
|
+
return _prompt_self_hosted(env_path)
|
|
542
|
+
|
|
543
|
+
typer.echo("Error: choice must be 1, 2, or 3")
|
|
544
|
+
raise typer.Exit(1)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _install_openclaw_integration() -> bool:
|
|
548
|
+
"""Install the Reflexio plugin into OpenClaw via the plugin system.
|
|
549
|
+
|
|
550
|
+
Returns:
|
|
551
|
+
bool: True if the plugin was verified as registered.
|
|
552
|
+
|
|
553
|
+
Raises:
|
|
554
|
+
typer.Exit: If the openclaw CLI is not found on PATH.
|
|
555
|
+
"""
|
|
556
|
+
if not shutil.which("openclaw"):
|
|
557
|
+
typer.echo("Error: openclaw CLI not found. Install from https://openclaw.ai")
|
|
558
|
+
raise typer.Exit(1)
|
|
559
|
+
|
|
560
|
+
import reflexio
|
|
561
|
+
|
|
562
|
+
pkg_dir = Path(reflexio.__file__).parent
|
|
563
|
+
plugin_dir = pkg_dir / "integrations" / "openclaw" / "plugin"
|
|
564
|
+
|
|
565
|
+
if not plugin_dir.exists():
|
|
566
|
+
typer.echo(f"Error: plugin directory not found at {plugin_dir}")
|
|
567
|
+
raise typer.Exit(1)
|
|
568
|
+
|
|
569
|
+
# Clean install: remove any existing installation and stale extension dir
|
|
570
|
+
subprocess.run(
|
|
571
|
+
["openclaw", "plugins", "uninstall", "--force", "reflexio-federated"],
|
|
572
|
+
check=False,
|
|
573
|
+
capture_output=True,
|
|
574
|
+
text=True,
|
|
575
|
+
)
|
|
576
|
+
stale_ext = Path.home() / ".openclaw" / "extensions" / "reflexio-federated"
|
|
577
|
+
shutil.rmtree(stale_ext, ignore_errors=True)
|
|
578
|
+
|
|
579
|
+
# Install plugin and restart gateway so inspect sees the new state
|
|
580
|
+
try:
|
|
581
|
+
subprocess.run(
|
|
582
|
+
["openclaw", "plugins", "install", str(plugin_dir)],
|
|
583
|
+
check=True,
|
|
584
|
+
capture_output=True,
|
|
585
|
+
text=True,
|
|
586
|
+
)
|
|
587
|
+
subprocess.run(
|
|
588
|
+
["openclaw", "plugins", "enable", "reflexio-federated"],
|
|
589
|
+
check=True,
|
|
590
|
+
capture_output=True,
|
|
591
|
+
text=True,
|
|
592
|
+
)
|
|
593
|
+
subprocess.run(
|
|
594
|
+
["openclaw", "gateway", "restart"],
|
|
595
|
+
check=True,
|
|
596
|
+
capture_output=True,
|
|
597
|
+
text=True,
|
|
598
|
+
)
|
|
599
|
+
except subprocess.CalledProcessError as exc:
|
|
600
|
+
typer.echo(f"Error: openclaw command failed: {exc.stderr or exc.stdout}")
|
|
601
|
+
raise typer.Exit(1) from exc
|
|
602
|
+
|
|
603
|
+
# Verify — match exact "Status: loaded" to avoid false positives from
|
|
604
|
+
# "not loaded" or "unloaded"
|
|
605
|
+
result = subprocess.run(
|
|
606
|
+
["openclaw", "plugins", "inspect", "reflexio-federated"],
|
|
607
|
+
capture_output=True,
|
|
608
|
+
text=True,
|
|
609
|
+
)
|
|
610
|
+
if re.search(r"Status:\s*loaded\b", result.stdout):
|
|
611
|
+
typer.echo("Plugin installed and registered")
|
|
612
|
+
return True
|
|
613
|
+
|
|
614
|
+
typer.echo(
|
|
615
|
+
"Error: Plugin not loaded -- check 'openclaw plugins inspect reflexio-federated'"
|
|
616
|
+
)
|
|
617
|
+
return False
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def _uninstall_openclaw() -> None:
|
|
621
|
+
"""Remove the Reflexio integration from OpenClaw."""
|
|
622
|
+
typer.confirm(
|
|
623
|
+
"This will remove the Reflexio integration from OpenClaw. Continue?",
|
|
624
|
+
abort=True,
|
|
625
|
+
)
|
|
626
|
+
if shutil.which("openclaw"):
|
|
627
|
+
subprocess.run(
|
|
628
|
+
["openclaw", "plugins", "disable", "reflexio-federated"],
|
|
629
|
+
check=False,
|
|
630
|
+
capture_output=True,
|
|
631
|
+
text=True,
|
|
632
|
+
)
|
|
633
|
+
subprocess.run(
|
|
634
|
+
["openclaw", "plugins", "uninstall", "--force", "reflexio-federated"],
|
|
635
|
+
check=False,
|
|
636
|
+
capture_output=True,
|
|
637
|
+
text=True,
|
|
638
|
+
)
|
|
639
|
+
else:
|
|
640
|
+
typer.echo("Warning: openclaw CLI not found on PATH, skipping plugin removal")
|
|
641
|
+
|
|
642
|
+
# Remove setup markers
|
|
643
|
+
from reflexio.cli.paths import reflexio_home
|
|
644
|
+
|
|
645
|
+
reflexio_dir = reflexio_home()
|
|
646
|
+
if reflexio_dir.exists():
|
|
647
|
+
for marker in reflexio_dir.glob(".setup_complete_*"):
|
|
648
|
+
marker.unlink(missing_ok=True)
|
|
649
|
+
typer.echo(f"Removed setup marker: {marker}")
|
|
650
|
+
|
|
651
|
+
typer.echo("Reflexio integration fully removed from OpenClaw.")
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
@app.command("openclaw")
|
|
655
|
+
def openclaw(
|
|
656
|
+
uninstall: Annotated[
|
|
657
|
+
bool,
|
|
658
|
+
typer.Option(
|
|
659
|
+
"--uninstall", help="Remove the Reflexio integration from OpenClaw"
|
|
660
|
+
),
|
|
661
|
+
] = False,
|
|
662
|
+
embedding: Annotated[
|
|
663
|
+
str,
|
|
664
|
+
typer.Option(
|
|
665
|
+
"--embedding",
|
|
666
|
+
help=(
|
|
667
|
+
"Embedding provider: 'local' (in-process MiniLM), 'openai', "
|
|
668
|
+
"'gemini', or 'auto' (default — let runtime auto-detection "
|
|
669
|
+
"pick). Skips the interactive prompt."
|
|
670
|
+
),
|
|
671
|
+
),
|
|
672
|
+
] = "auto",
|
|
673
|
+
) -> None:
|
|
674
|
+
"""Set up (or remove) the Reflexio integration for OpenClaw."""
|
|
675
|
+
if uninstall:
|
|
676
|
+
_uninstall_openclaw()
|
|
677
|
+
return
|
|
678
|
+
|
|
679
|
+
if embedding not in _VALID_EMBEDDING_FLAGS:
|
|
680
|
+
typer.echo(
|
|
681
|
+
f"Error: --embedding must be one of "
|
|
682
|
+
f"{sorted(_VALID_EMBEDDING_FLAGS)}, got {embedding!r}"
|
|
683
|
+
)
|
|
684
|
+
raise typer.Exit(1)
|
|
685
|
+
|
|
686
|
+
# Step 1: Load .env path. Always target ~/.reflexio/.env — running setup
|
|
687
|
+
# from a worktree or project root that happens to contain its own .env
|
|
688
|
+
# would otherwise pollute that file via load_reflexio_env's CWD-first
|
|
689
|
+
# search. Setup writes are user-global, not project-local.
|
|
690
|
+
from reflexio.cli.env_loader import ensure_user_env_for_setup
|
|
691
|
+
|
|
692
|
+
env_path = ensure_user_env_for_setup()
|
|
693
|
+
if env_path is None:
|
|
694
|
+
typer.echo("Error: could not locate or create a .env file")
|
|
695
|
+
raise typer.Exit(1)
|
|
696
|
+
|
|
697
|
+
# Step 2: LLM provider
|
|
698
|
+
display_name, model, _provider_key = _prompt_llm_provider(env_path)
|
|
699
|
+
|
|
700
|
+
# Step 3: Storage. Decided BEFORE the embedding step because Managed /
|
|
701
|
+
# Self-hosted modes own their own embedding config server-side, and a
|
|
702
|
+
# local override would just shadow the operator's choice.
|
|
703
|
+
storage_label = _prompt_storage(env_path)
|
|
704
|
+
|
|
705
|
+
# Step 3.5: Upfront embedding-provider step. Local is the default when
|
|
706
|
+
# chromadb is importable; the choice persists to org config so it
|
|
707
|
+
# survives later cloud-key changes. Skipped for remote storage modes
|
|
708
|
+
# for the reason above.
|
|
709
|
+
is_remote = storage_label in {"Managed Reflexio", "Self-hosted Reflexio"}
|
|
710
|
+
embedding_label: str | None = None
|
|
711
|
+
if not is_remote:
|
|
712
|
+
embedding_label = _choose_embedding_provider(env_path, embedding_flag=embedding)
|
|
713
|
+
|
|
714
|
+
# Step 4: Install OpenClaw integration
|
|
715
|
+
typer.echo("")
|
|
716
|
+
hook_ok = _install_openclaw_integration()
|
|
717
|
+
|
|
718
|
+
# Step 5: Summary
|
|
719
|
+
hook_status = "reflexio-federated" if hook_ok else "reflexio-federated (unverified)"
|
|
720
|
+
|
|
721
|
+
typer.echo("")
|
|
722
|
+
typer.echo("Setup complete!")
|
|
723
|
+
typer.echo(f" LLM Provider: {display_name} ({model})")
|
|
724
|
+
if embedding_label:
|
|
725
|
+
typer.echo(f" Embedding Provider: {embedding_label}")
|
|
726
|
+
typer.echo(f" Storage: {storage_label}")
|
|
727
|
+
typer.echo(f" Plugin: {hook_status}")
|
|
728
|
+
typer.echo("")
|
|
729
|
+
typer.echo("Next steps:")
|
|
730
|
+
typer.echo(" 1. Restart OpenClaw gateway: openclaw gateway restart")
|
|
731
|
+
typer.echo(
|
|
732
|
+
" 2. Start a conversation -- Reflexio will capture and learn automatically"
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
# ---------------------------------------------------------------------------
|
|
737
|
+
# Generic (integration-less) setup
|
|
738
|
+
# ---------------------------------------------------------------------------
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
@app.command("init")
|
|
742
|
+
def init(
|
|
743
|
+
skip_llm: Annotated[
|
|
744
|
+
bool,
|
|
745
|
+
typer.Option(
|
|
746
|
+
"--skip-llm",
|
|
747
|
+
help=(
|
|
748
|
+
"Skip the LLM provider prompt (use when you're only "
|
|
749
|
+
"going to publish to a managed Reflexio server, which "
|
|
750
|
+
"manages its own LLM keys server-side)"
|
|
751
|
+
),
|
|
752
|
+
),
|
|
753
|
+
] = False,
|
|
754
|
+
embedding: Annotated[
|
|
755
|
+
str,
|
|
756
|
+
typer.Option(
|
|
757
|
+
"--embedding",
|
|
758
|
+
help=(
|
|
759
|
+
"Embedding provider: 'local' (in-process MiniLM), 'openai', "
|
|
760
|
+
"'gemini', or 'auto' (default — let runtime auto-detection "
|
|
761
|
+
"pick). Skips the interactive prompt."
|
|
762
|
+
),
|
|
763
|
+
),
|
|
764
|
+
] = "auto",
|
|
765
|
+
) -> None:
|
|
766
|
+
"""Configure Reflexio without installing any integration.
|
|
767
|
+
|
|
768
|
+
Writes ``REFLEXIO_URL`` / ``REFLEXIO_API_KEY`` / LLM provider keys
|
|
769
|
+
/ storage backend into ``~/.reflexio/.env``. This is the command
|
|
770
|
+
to run if you're using the ``reflexio`` CLI directly from your
|
|
771
|
+
shell and don't need the OpenClaw hook installation.
|
|
772
|
+
|
|
773
|
+
Under the hood it reuses the same ``_prompt_storage`` +
|
|
774
|
+
``_prompt_llm_provider`` helpers the integration setup commands
|
|
775
|
+
use, so the flow and the resulting ``.env`` are identical to what
|
|
776
|
+
you'd get from those commands minus the hook-installation step.
|
|
777
|
+
|
|
778
|
+
Args:
|
|
779
|
+
skip_llm: When True, skip the LLM provider prompt. Useful if
|
|
780
|
+
you're only going to point the CLI at a managed Reflexio
|
|
781
|
+
server, which handles extraction with its own LLM keys.
|
|
782
|
+
embedding: Embedding-provider selector for non-interactive use.
|
|
783
|
+
``"auto"`` (default) leaves the choice to runtime
|
|
784
|
+
auto-detection. ``"local"`` / ``"openai"`` / ``"gemini"``
|
|
785
|
+
persist the corresponding model to org config and skip the
|
|
786
|
+
prompt. Honors ``REFLEXIO_NONINTERACTIVE=1`` (skips the
|
|
787
|
+
prompt and behaves as ``"auto"`` when the flag is left at
|
|
788
|
+
its default).
|
|
789
|
+
"""
|
|
790
|
+
if embedding not in _VALID_EMBEDDING_FLAGS:
|
|
791
|
+
typer.echo(
|
|
792
|
+
f"Error: --embedding must be one of "
|
|
793
|
+
f"{sorted(_VALID_EMBEDDING_FLAGS)}, got {embedding!r}"
|
|
794
|
+
)
|
|
795
|
+
raise typer.Exit(1)
|
|
796
|
+
|
|
797
|
+
# Always target ~/.reflexio/.env — see ensure_user_env_for_setup docstring
|
|
798
|
+
# for why we don't honor a CWD-local .env in setup commands.
|
|
799
|
+
from reflexio.cli.env_loader import ensure_user_env_for_setup
|
|
800
|
+
|
|
801
|
+
env_path = ensure_user_env_for_setup()
|
|
802
|
+
if env_path is None:
|
|
803
|
+
typer.echo("Error: could not locate or create a .env file")
|
|
804
|
+
raise typer.Exit(1)
|
|
805
|
+
|
|
806
|
+
# Step 1: Storage (ask first — managed mode doesn't need an LLM key)
|
|
807
|
+
storage_label = _prompt_storage(env_path)
|
|
808
|
+
|
|
809
|
+
# Step 2: LLM provider (skipped for managed mode — the remote server
|
|
810
|
+
# handles extraction so the local .env doesn't need an LLM key).
|
|
811
|
+
# Also skipped when the user explicitly passes --skip-llm.
|
|
812
|
+
is_managed = storage_label == "Managed Reflexio"
|
|
813
|
+
is_remote = storage_label in {"Managed Reflexio", "Self-hosted Reflexio"}
|
|
814
|
+
display_name: str | None = None
|
|
815
|
+
model: str | None = None
|
|
816
|
+
embedding_label: str | None = None
|
|
817
|
+
if is_managed:
|
|
818
|
+
typer.echo(
|
|
819
|
+
"\nSkipping LLM provider — Managed Reflexio handles "
|
|
820
|
+
"extraction server-side with its own model keys."
|
|
821
|
+
)
|
|
822
|
+
elif skip_llm:
|
|
823
|
+
typer.echo("\nSkipping LLM provider per --skip-llm.")
|
|
824
|
+
else:
|
|
825
|
+
display_name, model, _ = _prompt_llm_provider(env_path)
|
|
826
|
+
|
|
827
|
+
# Step 2.5: Upfront embedding-provider step. Local is the default when
|
|
828
|
+
# chromadb is importable; the choice is persisted to org config so it
|
|
829
|
+
# survives later cloud-key changes. Skipped for both Managed and
|
|
830
|
+
# Self-hosted modes — the remote server owns its own model config and
|
|
831
|
+
# a local override would just shadow whatever the operator set there.
|
|
832
|
+
# Replaces the legacy ``_prompt_embedding_provider`` call here — that
|
|
833
|
+
# helper still exists for the ``services start`` first-run wizard.
|
|
834
|
+
if not is_remote:
|
|
835
|
+
embedding_label = _choose_embedding_provider(env_path, embedding_flag=embedding)
|
|
836
|
+
|
|
837
|
+
# Step 3: Summary — no integration to print
|
|
838
|
+
typer.echo("")
|
|
839
|
+
typer.echo("Setup complete!")
|
|
840
|
+
if display_name and model:
|
|
841
|
+
typer.echo(f" LLM Provider: {display_name} ({model})")
|
|
842
|
+
if embedding_label:
|
|
843
|
+
typer.echo(f" Embedding Provider: {embedding_label}")
|
|
844
|
+
typer.echo(f" Storage: {storage_label}")
|
|
845
|
+
typer.echo(f" .env: {env_path}")
|
|
846
|
+
typer.echo("")
|
|
847
|
+
typer.echo(
|
|
848
|
+
"Next: run 'reflexio status whoami' to verify the connection "
|
|
849
|
+
"(managed mode) or 'reflexio services start' to launch the "
|
|
850
|
+
"local backend (SQLite / self-hosted mode)."
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
@app.command("openai-codex")
|
|
855
|
+
def openai_codex_setup(
|
|
856
|
+
no_browser: Annotated[
|
|
857
|
+
bool,
|
|
858
|
+
typer.Option(
|
|
859
|
+
"--no-browser",
|
|
860
|
+
help="Don't auto-open the browser; print the URL to copy/paste instead.",
|
|
861
|
+
),
|
|
862
|
+
] = False,
|
|
863
|
+
timeout: Annotated[
|
|
864
|
+
int,
|
|
865
|
+
typer.Option(
|
|
866
|
+
"--timeout",
|
|
867
|
+
help="Seconds to wait for the OAuth callback before failing.",
|
|
868
|
+
),
|
|
869
|
+
] = 300,
|
|
870
|
+
show: Annotated[
|
|
871
|
+
bool,
|
|
872
|
+
typer.Option(
|
|
873
|
+
"--show",
|
|
874
|
+
help="Print currently saved Codex token metadata and exit (no login).",
|
|
875
|
+
),
|
|
876
|
+
] = False,
|
|
877
|
+
logout: Annotated[
|
|
878
|
+
bool,
|
|
879
|
+
typer.Option(
|
|
880
|
+
"--logout",
|
|
881
|
+
help="Delete the saved Codex token file and exit.",
|
|
882
|
+
),
|
|
883
|
+
] = False,
|
|
884
|
+
) -> None:
|
|
885
|
+
"""Sign in to OpenAI via your ChatGPT subscription (Codex OAuth).
|
|
886
|
+
|
|
887
|
+
Stores access + refresh tokens at ``~/.reflexio/auth/openai-codex.json``.
|
|
888
|
+
The codex proxy and any other reflexio component that needs OpenAI auth
|
|
889
|
+
reads from this file directly — no dependency on OpenClaw or any other
|
|
890
|
+
CLI. The proxy auto-refreshes the access token when it nears expiry.
|
|
891
|
+
|
|
892
|
+
Run this once; the codex proxy (``codex_proxy.py``) then picks up the
|
|
893
|
+
stored tokens automatically on start.
|
|
894
|
+
|
|
895
|
+
Re-run this command if your subscription tier changes or the
|
|
896
|
+
refresh_token gets revoked (rare).
|
|
897
|
+
"""
|
|
898
|
+
# Imported here so plain `reflexio --help` doesn't require the OAuth
|
|
899
|
+
# module to load (slight startup speedup; mostly cosmetic).
|
|
900
|
+
from reflexio.cli.codex_auth import (
|
|
901
|
+
REFLEXIO_CODEX_TOKENS_PATH,
|
|
902
|
+
get_fresh_tokens,
|
|
903
|
+
load_tokens_raw,
|
|
904
|
+
login_interactive,
|
|
905
|
+
)
|
|
906
|
+
|
|
907
|
+
if logout:
|
|
908
|
+
if REFLEXIO_CODEX_TOKENS_PATH.exists():
|
|
909
|
+
REFLEXIO_CODEX_TOKENS_PATH.unlink()
|
|
910
|
+
typer.echo(f"Removed {REFLEXIO_CODEX_TOKENS_PATH}")
|
|
911
|
+
else:
|
|
912
|
+
typer.echo("No saved Codex tokens to remove.")
|
|
913
|
+
return
|
|
914
|
+
|
|
915
|
+
if show:
|
|
916
|
+
tokens = load_tokens_raw()
|
|
917
|
+
if tokens is None:
|
|
918
|
+
typer.echo(f"No tokens at {REFLEXIO_CODEX_TOKENS_PATH}.")
|
|
919
|
+
typer.echo("Run `reflexio setup openai-codex` to sign in.")
|
|
920
|
+
raise typer.Exit(1)
|
|
921
|
+
typer.echo(f" path: {REFLEXIO_CODEX_TOKENS_PATH}")
|
|
922
|
+
typer.echo(f" email: {tokens.email}")
|
|
923
|
+
typer.echo(f" plan_type: {tokens.plan_type}")
|
|
924
|
+
typer.echo(
|
|
925
|
+
f" account_id ...{tokens.account_id[-8:]}"
|
|
926
|
+
if tokens.account_id
|
|
927
|
+
else " account_id (empty)"
|
|
928
|
+
)
|
|
929
|
+
typer.echo(f" expires_at: {tokens.expires_at} (unix epoch)")
|
|
930
|
+
typer.echo(f" expired: {tokens.is_expired()}")
|
|
931
|
+
return
|
|
932
|
+
|
|
933
|
+
typer.echo("Starting OpenAI Codex OAuth flow...")
|
|
934
|
+
try:
|
|
935
|
+
tokens = login_interactive(
|
|
936
|
+
open_browser=not no_browser,
|
|
937
|
+
timeout_s=timeout,
|
|
938
|
+
)
|
|
939
|
+
except TimeoutError as e:
|
|
940
|
+
typer.echo(f"Timed out: {e}")
|
|
941
|
+
raise typer.Exit(1) from e
|
|
942
|
+
except ValueError as e:
|
|
943
|
+
typer.echo(f"Login failed: {e}")
|
|
944
|
+
raise typer.Exit(1) from e
|
|
945
|
+
|
|
946
|
+
typer.echo("")
|
|
947
|
+
typer.echo("Sign-in successful.")
|
|
948
|
+
typer.echo(f" saved to: {REFLEXIO_CODEX_TOKENS_PATH}")
|
|
949
|
+
if tokens.email:
|
|
950
|
+
typer.echo(f" email: {tokens.email}")
|
|
951
|
+
typer.echo(f" plan_type: {tokens.plan_type}")
|
|
952
|
+
typer.echo("")
|
|
953
|
+
typer.echo("Verify the token resolves cleanly via the proxy's health endpoint:")
|
|
954
|
+
typer.echo(" curl -s http://127.0.0.1:11435/health | jq")
|
|
955
|
+
typer.echo("")
|
|
956
|
+
typer.echo(
|
|
957
|
+
"If the saved plan_type doesn't match what you expect (e.g. shows "
|
|
958
|
+
"'plus' instead of 'max-x20'), wait a minute for OpenAI to propagate "
|
|
959
|
+
"the subscription change and re-run this command — the JWT is issued "
|
|
960
|
+
"at sign-in time."
|
|
961
|
+
)
|
|
962
|
+
# Exercise the refresh path immediately so any clock skew between the
|
|
963
|
+
# JWT's `exp` claim and our local clock is caught now, not at first use.
|
|
964
|
+
_ = get_fresh_tokens()
|