claude-smart 0.2.44 → 0.2.46
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 +34 -5
- package/bin/claude-smart.js +295 -5
- package/package.json +22 -3
- package/plugin/.claude-plugin/plugin.json +4 -2
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/README.md +22 -2
- package/plugin/commands/clear-all.md +1 -0
- package/plugin/commands/dashboard.md +1 -0
- package/plugin/commands/learn.md +1 -0
- package/plugin/commands/restart.md +1 -0
- package/plugin/commands/show.md +1 -0
- package/plugin/dashboard/app/configure/env/page.tsx +40 -14
- package/plugin/dashboard/app/configure/server/page.tsx +51 -1
- package/plugin/dashboard/app/preferences/[id]/page.tsx +8 -8
- package/plugin/dashboard/app/skills/project/[id]/page.tsx +7 -3
- package/plugin/dashboard/app/skills/shared/[id]/page.tsx +10 -3
- package/plugin/dashboard/lib/claude-settings-file.ts +20 -10
- package/plugin/dashboard/lib/reflexio-client.ts +16 -0
- package/plugin/dashboard/lib/status.ts +10 -3
- package/plugin/dashboard/lib/types.ts +18 -6
- package/plugin/hooks/codex-hooks.json +0 -1
- package/plugin/opencode/assistant-buffer.ts +108 -0
- package/plugin/opencode/dist/assistant-buffer.js +96 -0
- package/plugin/opencode/dist/internal.js +12 -0
- package/plugin/opencode/dist/payload.js +85 -0
- package/plugin/opencode/dist/server.mjs +158 -0
- package/plugin/opencode/internal.ts +18 -0
- package/plugin/opencode/package.json +3 -0
- package/plugin/opencode/payload.ts +90 -0
- package/plugin/opencode/server.mts +174 -0
- package/plugin/opencode/tsconfig.json +13 -0
- package/plugin/pyproject.toml +20 -3
- package/plugin/scripts/_lib.sh +77 -29
- package/plugin/scripts/backend-service.sh +27 -5
- package/plugin/scripts/dashboard-service.sh +7 -5
- package/plugin/scripts/ensure-plugin-root.sh +4 -4
- package/plugin/scripts/hook_entry.sh +3 -3
- package/plugin/scripts/opencode-claude-compat +4 -0
- package/plugin/scripts/opencode-claude-compat.cmd +3 -0
- package/plugin/scripts/opencode-claude-compat.js +225 -0
- package/plugin/scripts/smart-install.sh +10 -8
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +304 -6
- package/plugin/src/claude_smart/env_config.py +12 -4
- package/plugin/src/claude_smart/events/session_start.py +26 -7
- package/plugin/src/claude_smart/events/stop.py +1 -1
- package/plugin/src/claude_smart/ids.py +1 -1
- package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
- package/plugin/src/claude_smart/runtime.py +7 -1
- package/plugin/uv.lock +1 -1
- package/plugin/vendor/reflexio/.env.example +54 -30
- package/plugin/vendor/reflexio/README.md +14 -8
- package/plugin/vendor/reflexio/pyproject.toml +13 -1
- package/plugin/vendor/reflexio/reflexio/README.md +1 -0
- package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
- package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
- package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
- package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
- package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
- package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
- package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +210 -50
- package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
- package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
- package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
- package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
- package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
- package/plugin/vendor/reflexio/reflexio/client/client.py +57 -13
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
- package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +238 -10
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +16 -5
- package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +198 -6
- package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +29 -20
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +2 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
- package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +52 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +88 -7
- package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
- package/plugin/vendor/reflexio/reflexio/server/README.md +45 -32
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
- package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
- package/plugin/vendor/reflexio/reflexio/server/_auth.py +65 -2
- package/plugin/vendor/reflexio/reflexio/server/api.py +734 -85
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +3 -1
- package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
- package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
- package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
- package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
- package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
- package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +266 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +26 -11
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +39 -16
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +193 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
- package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +11 -12
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +316 -178
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +84 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
- package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +30 -22
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
- package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +83 -6
- package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +27 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +642 -197
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +61 -104
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +628 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +978 -184
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +519 -128
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +77 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +131 -20
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +36 -53
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +243 -7
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +121 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +60 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +229 -32
- package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
- package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
- package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
- package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
- package/scripts/setup-claude-smart.sh +8 -3
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
- /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_extractor.py → components/extractor.py} +0 -0
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from collections import defaultdict
|
|
2
3
|
|
|
3
4
|
logger = logging.getLogger(__name__)
|
|
4
5
|
|
|
5
6
|
from datetime import UTC, datetime
|
|
7
|
+
from typing import Protocol
|
|
6
8
|
|
|
7
9
|
from reflexio.lib._base import (
|
|
8
10
|
STORAGE_NOT_CONFIGURED_MSG,
|
|
9
11
|
ReflexioBase,
|
|
10
12
|
_require_storage,
|
|
11
13
|
)
|
|
14
|
+
from reflexio.models.api_schema.domain.entities import (
|
|
15
|
+
LineageEvent,
|
|
16
|
+
ProfileChangeLog,
|
|
17
|
+
UserProfile,
|
|
18
|
+
)
|
|
12
19
|
from reflexio.models.api_schema.retriever_schema import (
|
|
13
20
|
GetProfileStatisticsResponse,
|
|
14
21
|
GetUserProfilesRequest,
|
|
@@ -36,7 +43,7 @@ from reflexio.models.api_schema.service_schemas import (
|
|
|
36
43
|
UpgradeProfilesRequest,
|
|
37
44
|
UpgradeProfilesResponse,
|
|
38
45
|
)
|
|
39
|
-
from reflexio.server.services.profile.
|
|
46
|
+
from reflexio.server.services.profile.service import (
|
|
40
47
|
ProfileGenerationService,
|
|
41
48
|
)
|
|
42
49
|
from reflexio.server.tracing import profile_step
|
|
@@ -199,15 +206,21 @@ class ProfilesMixin(ReflexioBase):
|
|
|
199
206
|
)
|
|
200
207
|
|
|
201
208
|
def get_profile_change_logs(self) -> ProfileChangeLogResponse:
|
|
202
|
-
"""Get profile change logs.
|
|
209
|
+
"""Get profile change logs, served from the lineage reconstruction.
|
|
210
|
+
|
|
211
|
+
The change-log view is rebuilt on demand from ``lineage_event`` linkage
|
|
212
|
+
joined to survivor/tombstone content via
|
|
213
|
+
:func:`reconstruct_profile_change_log`. The legacy ``profile_change_logs``
|
|
214
|
+
table is no longer written (B3 Task 6) or read (B3 Task 7); it is retained
|
|
215
|
+
frozen until its removal in Task 8.
|
|
203
216
|
|
|
204
217
|
Returns:
|
|
205
|
-
ProfileChangeLogResponse: Response containing
|
|
218
|
+
ProfileChangeLogResponse: Response containing the reconstructed
|
|
219
|
+
profile change logs.
|
|
206
220
|
"""
|
|
207
221
|
if not self._is_storage_configured():
|
|
208
222
|
return ProfileChangeLogResponse(success=True, profile_change_logs=[])
|
|
209
|
-
|
|
210
|
-
return ProfileChangeLogResponse(success=True, profile_change_logs=changelogs)
|
|
223
|
+
return reconstruct_profile_change_log(self._get_storage())
|
|
211
224
|
|
|
212
225
|
@_require_storage(DeleteUserProfileResponse)
|
|
213
226
|
def delete_profile(
|
|
@@ -401,7 +414,7 @@ class ProfilesMixin(ReflexioBase):
|
|
|
401
414
|
status_filter = [None] # Default to current profiles
|
|
402
415
|
|
|
403
416
|
profiles = self._get_storage().get_user_profile(
|
|
404
|
-
request.user_id, status_filter=status_filter
|
|
417
|
+
request.user_id, status_filter=status_filter, tags=request.tags
|
|
405
418
|
)
|
|
406
419
|
profiles = sorted(
|
|
407
420
|
profiles, key=lambda x: x.last_modified_timestamp, reverse=True
|
|
@@ -543,3 +556,182 @@ class ProfilesMixin(ReflexioBase):
|
|
|
543
556
|
return GetProfileStatisticsResponse(
|
|
544
557
|
success=False, msg=f"Failed to get profile statistics: {str(e)}"
|
|
545
558
|
)
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
# ---------------------------------------------------------------------------
|
|
562
|
+
# Standalone read-side reconstruction (Phase B3 Task 2)
|
|
563
|
+
# ---------------------------------------------------------------------------
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
class ChangeLogReadStorage(Protocol):
|
|
567
|
+
"""The storage read surface ``reconstruct_profile_change_log`` requires.
|
|
568
|
+
|
|
569
|
+
Both the real ``BaseStorage`` backends and the read-only
|
|
570
|
+
``RestStorageReader`` satisfy this structurally — no inheritance required —
|
|
571
|
+
so reconstruction can run against either without an unsound ``cast`` to
|
|
572
|
+
``BaseStorage``.
|
|
573
|
+
"""
|
|
574
|
+
|
|
575
|
+
org_id: str
|
|
576
|
+
|
|
577
|
+
def get_lineage_events(
|
|
578
|
+
self,
|
|
579
|
+
*,
|
|
580
|
+
entity_type: str | None = ...,
|
|
581
|
+
entity_id: str | None = ...,
|
|
582
|
+
org_id: str | None = ...,
|
|
583
|
+
request_id: str | None = ...,
|
|
584
|
+
) -> list[LineageEvent]: ...
|
|
585
|
+
|
|
586
|
+
def get_distinct_generated_from_request_ids(self) -> list[str]: ...
|
|
587
|
+
|
|
588
|
+
def get_profiles_by_generated_from_request_id(
|
|
589
|
+
self, request_id: str
|
|
590
|
+
) -> list[UserProfile]: ...
|
|
591
|
+
|
|
592
|
+
def get_all_generated_profiles(self) -> list[UserProfile]: ...
|
|
593
|
+
|
|
594
|
+
def get_profile_by_id(
|
|
595
|
+
self, profile_id: str, *, include_tombstones: bool = ...
|
|
596
|
+
) -> UserProfile | None: ...
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def reconstruct_profile_change_log(
|
|
600
|
+
storage: ChangeLogReadStorage,
|
|
601
|
+
*,
|
|
602
|
+
limit: int = 100,
|
|
603
|
+
) -> ProfileChangeLogResponse:
|
|
604
|
+
"""Rebuild the ProfileChangeLog view using time-travel-stable signals.
|
|
605
|
+
|
|
606
|
+
Uses two immutable / stable signals to classify every dedup run:
|
|
607
|
+
|
|
608
|
+
* **added(R)** — profiles whose ``generated_from_request_id == R``. This
|
|
609
|
+
column is set at creation and never changes, so it correctly classifies
|
|
610
|
+
a profile as "added in run R" even if it is later tombstoned in run R2.
|
|
611
|
+
Tombstones are included so the content is available.
|
|
612
|
+
|
|
613
|
+
* **removed(R)** — entity_ids of ``status_change`` lineage events with
|
|
614
|
+
``to_status == "superseded"`` and ``request_id == R``. This is the
|
|
615
|
+
exact signature emitted by ``supersede_profiles_by_ids`` (the dedup
|
|
616
|
+
soft-delete path). It is distinct from reflection which emits
|
|
617
|
+
``op="revise"``, so reflection events are never mis-counted as removals.
|
|
618
|
+
|
|
619
|
+
Groups are formed over the union of request_ids from both signals.
|
|
620
|
+
Request_id ``""`` is skipped — it would merge unrelated runs.
|
|
621
|
+
A row is emitted only when ``added or removed`` is non-empty (matching
|
|
622
|
+
legacy semantics: the legacy table was written only when
|
|
623
|
+
``all_new_profiles or superseded_profiles``).
|
|
624
|
+
|
|
625
|
+
When a removed profile's tombstone has been physically purged (GDPR GC),
|
|
626
|
+
it is silently omitted from ``removed_profiles`` rather than crashing.
|
|
627
|
+
|
|
628
|
+
Args:
|
|
629
|
+
storage (ChangeLogReadStorage): Storage read surface to query (any
|
|
630
|
+
BaseStorage backend or the read-only ``RestStorageReader``).
|
|
631
|
+
limit (int): Maximum number of reconstructed entries to return.
|
|
632
|
+
Defaults to 100.
|
|
633
|
+
|
|
634
|
+
Returns:
|
|
635
|
+
ProfileChangeLogResponse: ``success=True`` with reconstructed rows
|
|
636
|
+
ordered most-recent first (by max event ``created_at`` in each
|
|
637
|
+
request_id group), capped at ``limit``.
|
|
638
|
+
"""
|
|
639
|
+
if limit <= 0:
|
|
640
|
+
return ProfileChangeLogResponse(success=True, profile_change_logs=[])
|
|
641
|
+
|
|
642
|
+
all_events = storage.get_lineage_events(
|
|
643
|
+
entity_type="profile", org_id=storage.org_id
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
# Dedup soft-delete signature: status_change to_status=="superseded".
|
|
647
|
+
# Each such event records one profile removed in the dedup run ``request_id``.
|
|
648
|
+
# Distinct from reflection which emits op="revise" — so revise events are
|
|
649
|
+
# never counted as removals here.
|
|
650
|
+
removal_by_req: dict[str, list[str]] = defaultdict(list)
|
|
651
|
+
sort_key: dict[str, tuple[int, int]] = {} # request_id -> (created_at, event_id)
|
|
652
|
+
for evt in all_events:
|
|
653
|
+
key = evt.request_id
|
|
654
|
+
if not key:
|
|
655
|
+
continue # skip empty-string request_ids — never merge unrelated runs
|
|
656
|
+
cur = sort_key.get(key, (0, 0))
|
|
657
|
+
if (evt.created_at, evt.event_id) > cur:
|
|
658
|
+
sort_key[key] = (evt.created_at, evt.event_id)
|
|
659
|
+
if evt.op == "status_change" and evt.to_status == "superseded":
|
|
660
|
+
removal_by_req[key].append(evt.entity_id)
|
|
661
|
+
|
|
662
|
+
# Resolve the "added" side for every run in ONE bulk read, grouped by each
|
|
663
|
+
# profile's immutable generated_from_request_id. This replaces a read per
|
|
664
|
+
# candidate request_id, which fanned out over the org's whole dedup history
|
|
665
|
+
# before the limit slice below — a hot-path N+1 on network-backed storage now
|
|
666
|
+
# that the live endpoint serves this reconstruction.
|
|
667
|
+
added_by_req: dict[str, list] = defaultdict(list)
|
|
668
|
+
for profile in storage.get_all_generated_profiles():
|
|
669
|
+
added_by_req[profile.generated_from_request_id].append(profile)
|
|
670
|
+
|
|
671
|
+
# Candidate request_ids are the UNION of:
|
|
672
|
+
# (a) lineage EVENT request_ids — runs that produced a dedup removal
|
|
673
|
+
# (status_change/superseded event); and
|
|
674
|
+
# (b) request_ids stamped on profile rows (the keys of added_by_req) —
|
|
675
|
+
# discovers ADD-ONLY dedup runs (new profiles, nothing superseded) that
|
|
676
|
+
# emit no lineage event. ``get_all_generated_profiles`` already excludes
|
|
677
|
+
# the empty-string sentinel, so unrelated runs are never merged.
|
|
678
|
+
#
|
|
679
|
+
# This closes the reconstruction-completeness gap for add-only runs: the
|
|
680
|
+
# legacy `add_profile_change_log` fired whenever `all_new_profiles or
|
|
681
|
+
# superseded_profiles` was non-empty, so a run with only adds was still
|
|
682
|
+
# recorded. The (b) path mirrors that.
|
|
683
|
+
#
|
|
684
|
+
# For add-only runs (in set (b) but not (a)), no event timestamp exists.
|
|
685
|
+
# We derive their sort key from the max `last_modified_timestamp` of the
|
|
686
|
+
# profiles in that group — set at creation, giving a sensible most-recent-first
|
|
687
|
+
# ordering relative to event-timestamped runs. The secondary key is 0.
|
|
688
|
+
candidate_req_ids: set[str] = set(sort_key.keys()) | set(added_by_req.keys())
|
|
689
|
+
|
|
690
|
+
def _effective_sort_key(req_id: str) -> tuple[int, int]:
|
|
691
|
+
"""Return (timestamp, event_id) for sorting; for add-only runs fall back to
|
|
692
|
+
the max last_modified_timestamp of the profiles in that group."""
|
|
693
|
+
if req_id in sort_key:
|
|
694
|
+
return sort_key[req_id]
|
|
695
|
+
profiles = added_by_req.get(req_id, [])
|
|
696
|
+
max_ts = max((p.last_modified_timestamp for p in profiles), default=0)
|
|
697
|
+
return (max_ts, 0)
|
|
698
|
+
|
|
699
|
+
sorted_keys = sorted(
|
|
700
|
+
candidate_req_ids,
|
|
701
|
+
key=_effective_sort_key,
|
|
702
|
+
reverse=True,
|
|
703
|
+
)[:limit]
|
|
704
|
+
|
|
705
|
+
logs: list[ProfileChangeLog] = []
|
|
706
|
+
for req_id in sorted_keys:
|
|
707
|
+
# added: profiles whose generated_from_request_id == req_id (any status,
|
|
708
|
+
# include tombstones — a profile added in R1 and tombstoned in R2 is still
|
|
709
|
+
# "added in R1").
|
|
710
|
+
added = added_by_req[req_id]
|
|
711
|
+
|
|
712
|
+
# removed: dedup-superseded profiles from this run's lineage events.
|
|
713
|
+
removed: list = []
|
|
714
|
+
for entity_id in removal_by_req.get(req_id, []):
|
|
715
|
+
profile = storage.get_profile_by_id(entity_id, include_tombstones=True)
|
|
716
|
+
if profile is not None:
|
|
717
|
+
removed.append(profile)
|
|
718
|
+
# Tombstone physically purged (GDPR GC) → silently omit; no crash.
|
|
719
|
+
|
|
720
|
+
if not added and not removed:
|
|
721
|
+
# No dedup activity for this request_id — skip to match legacy semantics.
|
|
722
|
+
continue
|
|
723
|
+
|
|
724
|
+
ts, _ = _effective_sort_key(req_id)
|
|
725
|
+
user_id = added[0].user_id if added else removed[0].user_id
|
|
726
|
+
logs.append(
|
|
727
|
+
ProfileChangeLog(
|
|
728
|
+
id=0,
|
|
729
|
+
user_id=user_id,
|
|
730
|
+
request_id=req_id,
|
|
731
|
+
created_at=ts,
|
|
732
|
+
added_profiles=added,
|
|
733
|
+
removed_profiles=removed,
|
|
734
|
+
)
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
return ProfileChangeLogResponse(success=True, profile_change_logs=logs)
|
|
@@ -41,7 +41,7 @@ class ReflectionMixin(ReflexioBase):
|
|
|
41
41
|
|
|
42
42
|
# Local import keeps the heavy service module out of facade
|
|
43
43
|
# cold-start when reflection is disabled.
|
|
44
|
-
from reflexio.server.services.reflection.
|
|
44
|
+
from reflexio.server.services.reflection.service import (
|
|
45
45
|
ReflectionService,
|
|
46
46
|
)
|
|
47
47
|
|
|
@@ -13,6 +13,7 @@ from reflexio.models.api_schema.retriever_schema import (
|
|
|
13
13
|
)
|
|
14
14
|
from reflexio.server.llm.model_defaults import ModelRole, resolve_model_name
|
|
15
15
|
from reflexio.server.site_var.site_var_manager import SiteVarManager
|
|
16
|
+
from reflexio.server.tracing import profile_step
|
|
16
17
|
|
|
17
18
|
_LOGGER = logging.getLogger(__name__)
|
|
18
19
|
|
|
@@ -136,32 +137,40 @@ class SearchMixin(ReflexioBase):
|
|
|
136
137
|
if isinstance(request, dict):
|
|
137
138
|
request = UnifiedSearchRequest(**request)
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
with profile_step(
|
|
141
|
+
"search.prepare",
|
|
142
|
+
enabled=bool(request.enable_reformulation),
|
|
143
|
+
has_conversation_history=bool(request.conversation_history),
|
|
144
|
+
search_mode=request.search_mode,
|
|
145
|
+
):
|
|
146
|
+
config = self.request_context.configurator.get_config()
|
|
147
|
+
config_llm_config = config.llm_config if config else None
|
|
148
|
+
|
|
149
|
+
# Resolve pre_retrieval_model_name: config override -> site var -> auto-detect.
|
|
150
|
+
model_setting = SiteVarManager().get_site_var("llm_model_setting")
|
|
151
|
+
site_var = model_setting if isinstance(model_setting, dict) else {}
|
|
152
|
+
api_key_config = config.api_key_config if config else None
|
|
153
|
+
|
|
154
|
+
pre_retrieval_model_name = resolve_model_name(
|
|
155
|
+
ModelRole.PRE_RETRIEVAL,
|
|
156
|
+
site_var_value=site_var.get("pre_retrieval_model_name"),
|
|
157
|
+
config_override=config_llm_config.pre_retrieval_model_name
|
|
158
|
+
if config_llm_config
|
|
159
|
+
else None,
|
|
160
|
+
api_key_config=api_key_config,
|
|
161
|
+
)
|
|
162
|
+
storage = self._get_storage()
|
|
163
|
+
prompt_manager = self.request_context.prompt_manager
|
|
164
|
+
retrieval_floor = config.retrieval_floor if config else None
|
|
140
165
|
|
|
141
166
|
from reflexio.server.services.unified_search_service import run_unified_search
|
|
142
167
|
|
|
143
|
-
config_llm_config = config.llm_config if config else None
|
|
144
|
-
|
|
145
|
-
# Resolve pre_retrieval_model_name: config override → site var → auto-detect
|
|
146
|
-
model_setting = SiteVarManager().get_site_var("llm_model_setting")
|
|
147
|
-
site_var = model_setting if isinstance(model_setting, dict) else {}
|
|
148
|
-
api_key_config = config.api_key_config if config else None
|
|
149
|
-
|
|
150
|
-
pre_retrieval_model_name = resolve_model_name(
|
|
151
|
-
ModelRole.PRE_RETRIEVAL,
|
|
152
|
-
site_var_value=site_var.get("pre_retrieval_model_name"),
|
|
153
|
-
config_override=config_llm_config.pre_retrieval_model_name
|
|
154
|
-
if config_llm_config
|
|
155
|
-
else None,
|
|
156
|
-
api_key_config=api_key_config,
|
|
157
|
-
)
|
|
158
|
-
|
|
159
168
|
return run_unified_search(
|
|
160
169
|
request=request,
|
|
161
170
|
org_id=org_id,
|
|
162
|
-
storage=
|
|
171
|
+
storage=storage,
|
|
163
172
|
llm_client=self.llm_client,
|
|
164
|
-
prompt_manager=
|
|
173
|
+
prompt_manager=prompt_manager,
|
|
165
174
|
pre_retrieval_model_name=pre_retrieval_model_name,
|
|
166
|
-
retrieval_floor=
|
|
175
|
+
retrieval_floor=retrieval_floor,
|
|
167
176
|
)
|
|
@@ -24,7 +24,7 @@ from reflexio.models.api_schema.service_schemas import (
|
|
|
24
24
|
UpgradeUserPlaybooksResponse,
|
|
25
25
|
)
|
|
26
26
|
from reflexio.models.config_schema import SearchOptions
|
|
27
|
-
from reflexio.server.services.playbook.
|
|
27
|
+
from reflexio.server.services.playbook.service import (
|
|
28
28
|
PlaybookGenerationService,
|
|
29
29
|
)
|
|
30
30
|
from reflexio.server.tracing import profile_step
|
|
@@ -57,6 +57,7 @@ class UserPlaybookMixin(ReflexioBase):
|
|
|
57
57
|
playbook_name=request.playbook_name,
|
|
58
58
|
agent_version=request.agent_version,
|
|
59
59
|
status_filter=request.status_filter,
|
|
60
|
+
tags=request.tags,
|
|
60
61
|
)
|
|
61
62
|
return GetUserPlaybooksResponse(
|
|
62
63
|
success=True,
|
|
@@ -118,6 +118,11 @@ __all__ = [
|
|
|
118
118
|
"ShareLink",
|
|
119
119
|
"AdminInvalidateCacheRequest",
|
|
120
120
|
"AdminInvalidateCacheResponse",
|
|
121
|
+
"PlaybookRetrievalLogItem",
|
|
122
|
+
"PlaybookRetrievalLog",
|
|
123
|
+
"LineageEvent",
|
|
124
|
+
"LineageContext",
|
|
125
|
+
"RecordRef",
|
|
121
126
|
]
|
|
122
127
|
|
|
123
128
|
# ===============================
|
|
@@ -179,11 +184,7 @@ class Request(BaseModel):
|
|
|
179
184
|
"""A user-issued request that begins or continues a session.
|
|
180
185
|
|
|
181
186
|
A Request is the unit of work the agent reacts to. Multiple Requests
|
|
182
|
-
share a ``session_id`` to form a multi-turn session.
|
|
183
|
-
``metadata`` dict carries per-request key/value annotations stamped by
|
|
184
|
-
customer integration code — distinct from ``playbook_metadata`` (a
|
|
185
|
-
JSON-encoded string) used by ``Playbook``-family entities elsewhere in
|
|
186
|
-
this module.
|
|
187
|
+
share a ``session_id`` to form a multi-turn session.
|
|
187
188
|
|
|
188
189
|
Attributes:
|
|
189
190
|
request_id (str): Unique identifier for this request.
|
|
@@ -192,22 +193,10 @@ class Request(BaseModel):
|
|
|
192
193
|
to the current UTC time.
|
|
193
194
|
source (str): Free-form origin tag (integration name, etc.).
|
|
194
195
|
agent_version (str): The agent version that handled this request.
|
|
195
|
-
session_id (str
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
- ``reflexio_retrieval_enabled`` (bool): F2 group-by signal;
|
|
201
|
-
customer integration code stamps this to indicate whether
|
|
202
|
-
Reflexio retrieval was active for the session. Read by the
|
|
203
|
-
``/api/get_evaluation_overview`` aggregator from the FIRST
|
|
204
|
-
request of each session for sticky group assignment.
|
|
205
|
-
|
|
206
|
-
Distinct from ``playbook_metadata`` on ``Playbook``-family
|
|
207
|
-
entities (which is a JSON-encoded string, not a dict).
|
|
208
|
-
On-the-wire serialization assumes JSON-encodable values;
|
|
209
|
-
non-JSON values like ``datetime`` or ``set`` will fail at
|
|
210
|
-
the storage / API boundary.
|
|
196
|
+
session_id (str): Non-empty session this request belongs to.
|
|
197
|
+
evaluation_only (bool): Whether this request is stored for
|
|
198
|
+
session-level evaluation only and must be excluded from
|
|
199
|
+
profile/playbook learning windows.
|
|
211
200
|
"""
|
|
212
201
|
|
|
213
202
|
request_id: str
|
|
@@ -215,8 +204,8 @@ class Request(BaseModel):
|
|
|
215
204
|
created_at: int = Field(default_factory=lambda: int(datetime.now(UTC).timestamp()))
|
|
216
205
|
source: str = ""
|
|
217
206
|
agent_version: str = ""
|
|
218
|
-
session_id:
|
|
219
|
-
|
|
207
|
+
session_id: NonEmptyStr
|
|
208
|
+
evaluation_only: bool = False
|
|
220
209
|
|
|
221
210
|
|
|
222
211
|
# information about the user profile generated from the user interaction
|
|
@@ -237,10 +226,14 @@ class UserProfile(BaseModel):
|
|
|
237
226
|
None # Retained provenance data column (merged on dedup); new profiles write None.
|
|
238
227
|
)
|
|
239
228
|
expanded_terms: str | None = None
|
|
229
|
+
tags: list[str] | None = None # None = not yet tagged; [] = tagged, no match
|
|
230
|
+
source_interaction_ids: list[int] = Field(default_factory=list)
|
|
240
231
|
embedding: EmbeddingVector = []
|
|
241
232
|
source_span: str | None = None
|
|
242
233
|
notes: str | None = None
|
|
243
234
|
reader_angle: str | None = None
|
|
235
|
+
merged_into: str | None = None
|
|
236
|
+
superseded_by: str | None = None
|
|
244
237
|
|
|
245
238
|
|
|
246
239
|
# user playbook for agents
|
|
@@ -261,10 +254,13 @@ class UserPlaybook(BaseModel):
|
|
|
261
254
|
source: str | None = None # source of the interaction that generated this playbook
|
|
262
255
|
source_interaction_ids: list[int] = Field(default_factory=list)
|
|
263
256
|
expanded_terms: str | None = None
|
|
257
|
+
tags: list[str] | None = None # None = not yet tagged; [] = tagged, no match
|
|
264
258
|
embedding: EmbeddingVector = []
|
|
265
259
|
source_span: str | None = None
|
|
266
260
|
notes: str | None = None
|
|
267
261
|
reader_angle: str | None = None
|
|
262
|
+
merged_into: int | None = None
|
|
263
|
+
superseded_by: int | None = None
|
|
268
264
|
|
|
269
265
|
|
|
270
266
|
class ProfileChangeLog(BaseModel):
|
|
@@ -274,7 +270,6 @@ class ProfileChangeLog(BaseModel):
|
|
|
274
270
|
created_at: int = Field(default_factory=lambda: int(datetime.now(UTC).timestamp()))
|
|
275
271
|
added_profiles: list[UserProfile]
|
|
276
272
|
removed_profiles: list[UserProfile]
|
|
277
|
-
mentioned_profiles: list[UserProfile]
|
|
278
273
|
|
|
279
274
|
|
|
280
275
|
class AgentPlaybook(BaseModel):
|
|
@@ -289,10 +284,13 @@ class AgentPlaybook(BaseModel):
|
|
|
289
284
|
playbook_status: PlaybookStatus = PlaybookStatus.PENDING
|
|
290
285
|
playbook_metadata: str = ""
|
|
291
286
|
expanded_terms: str | None = None
|
|
287
|
+
tags: list[str] | None = None # None = not yet tagged; [] = tagged, no match
|
|
292
288
|
embedding: EmbeddingVector = []
|
|
293
289
|
status: Status | None = (
|
|
294
290
|
None # used for tracking intermediate states during playbook aggregation. Status.ARCHIVED for playbooks during aggregation process, None for current playbooks
|
|
295
291
|
)
|
|
292
|
+
merged_into: int | None = None
|
|
293
|
+
superseded_by: int | None = None
|
|
296
294
|
|
|
297
295
|
|
|
298
296
|
class PlaybookOptimizationJob(BaseModel):
|
|
@@ -330,6 +328,7 @@ class PlaybookOptimizationCandidate(BaseModel):
|
|
|
330
328
|
parent_candidate_ids: list[int] = Field(default_factory=list)
|
|
331
329
|
aggregate_score: float | None = None
|
|
332
330
|
is_winner: bool = False
|
|
331
|
+
metadata_json: str = "{}"
|
|
333
332
|
created_at: int = Field(default_factory=lambda: int(datetime.now(UTC).timestamp()))
|
|
334
333
|
|
|
335
334
|
|
|
@@ -384,6 +383,7 @@ class AgentPlaybookSourceWindow(BaseModel):
|
|
|
384
383
|
|
|
385
384
|
class AgentSuccessEvaluationResult(BaseModel):
|
|
386
385
|
result_id: int = 0
|
|
386
|
+
user_id: str = ""
|
|
387
387
|
agent_version: str
|
|
388
388
|
session_id: str
|
|
389
389
|
is_success: bool
|
|
@@ -398,6 +398,100 @@ class AgentSuccessEvaluationResult(BaseModel):
|
|
|
398
398
|
embedding: EmbeddingVector = []
|
|
399
399
|
|
|
400
400
|
|
|
401
|
+
class PlaybookRetrievalLogItem(BaseModel):
|
|
402
|
+
"""One retrieved agent playbook plus the serve-time attribution snapshot."""
|
|
403
|
+
|
|
404
|
+
retrieval_log_item_id: int = 0
|
|
405
|
+
retrieval_log_id: int = 0
|
|
406
|
+
ordinal: int
|
|
407
|
+
agent_playbook_id: int
|
|
408
|
+
source_user_playbook_ids: list[int] = Field(default_factory=list)
|
|
409
|
+
source_interaction_ids_by_user_playbook_id: dict[str, list[int]] = Field(
|
|
410
|
+
default_factory=dict
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
class PlaybookRetrievalLog(BaseModel):
|
|
415
|
+
"""A retrieval-log header with ordered item rows.
|
|
416
|
+
|
|
417
|
+
Used by retrieval-capture consumers to correlate retrieval decisions with
|
|
418
|
+
downstream outcomes. ``retrieval_log_id`` is assigned by the storage layer;
|
|
419
|
+
``shown_items`` stores ids and serve-time attribution snapshots only.
|
|
420
|
+
"""
|
|
421
|
+
|
|
422
|
+
retrieval_log_id: int = 0
|
|
423
|
+
request_id: str
|
|
424
|
+
session_id: str
|
|
425
|
+
interaction_id: int | None = None
|
|
426
|
+
user_id: str
|
|
427
|
+
query: str | None = None
|
|
428
|
+
agent_version: str | None = None
|
|
429
|
+
shown_items: list[PlaybookRetrievalLogItem] = Field(default_factory=list)
|
|
430
|
+
created_at: int = 0
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class LineageEvent(BaseModel):
|
|
434
|
+
"""Append-only, content-free provenance record. NEVER carries content/PII.
|
|
435
|
+
|
|
436
|
+
Attributes:
|
|
437
|
+
event_id (int): PK assigned by storage (0 = not yet persisted).
|
|
438
|
+
org_id (str): Owning org (tenant) — required for RLS / isolation.
|
|
439
|
+
entity_type (str): One of "profile" | "user_playbook" | "agent_playbook".
|
|
440
|
+
entity_id (str): The affected record's id, stringified (profile_id is str).
|
|
441
|
+
op (str): create|revise|merge|aggregate|archive|soft_delete|hard_delete|purge|status_change.
|
|
442
|
+
prov_relation (str): W3C PROV relation (see spec §14).
|
|
443
|
+
source_ids (list[str]): Records merged/superseded into entity_id.
|
|
444
|
+
actor (str): Who/what triggered it (consolidator|reflection|offline_optimizer|...).
|
|
445
|
+
request_id (str): Triggering request — part of the idempotency key.
|
|
446
|
+
reason (str): Free-text rationale (no PII).
|
|
447
|
+
created_at (int): Unix epoch seconds (0 = unset; storage stamps it).
|
|
448
|
+
"""
|
|
449
|
+
|
|
450
|
+
event_id: int = 0
|
|
451
|
+
org_id: str
|
|
452
|
+
entity_type: str
|
|
453
|
+
entity_id: str
|
|
454
|
+
op: str
|
|
455
|
+
prov_relation: str = ""
|
|
456
|
+
source_ids: list[str] = []
|
|
457
|
+
actor: str = ""
|
|
458
|
+
request_id: str = ""
|
|
459
|
+
reason: str = ""
|
|
460
|
+
created_at: int = 0
|
|
461
|
+
from_status: str | None = None
|
|
462
|
+
to_status: str | None = None
|
|
463
|
+
status_namespace: str | None = None
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class LineageContext(BaseModel):
|
|
467
|
+
"""Caller-supplied intent the storage layer can't infer.
|
|
468
|
+
|
|
469
|
+
Required for merge/supersede/aggregate; optional for create/revise/archive.
|
|
470
|
+
"""
|
|
471
|
+
|
|
472
|
+
op_kind: str
|
|
473
|
+
actor: str = ""
|
|
474
|
+
source_ids: list[str] = []
|
|
475
|
+
reason: str = ""
|
|
476
|
+
request_id: str | None = None
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class RecordRef(BaseModel):
|
|
480
|
+
"""Result of resolve_current — the live survivor's id and whether its body was purged.
|
|
481
|
+
|
|
482
|
+
Attributes:
|
|
483
|
+
id: Primary key of the live survivor record.
|
|
484
|
+
is_purged: True when the survivor's content body has been blanked by
|
|
485
|
+
``purge_content`` (GDPR/erasure). Any consumer that dereferences the
|
|
486
|
+
resolved record's content MUST treat ``is_purged=True`` as "erased —
|
|
487
|
+
skip or treat as absent." Reading blank content as if it were valid
|
|
488
|
+
is a silent data-quality bug.
|
|
489
|
+
"""
|
|
490
|
+
|
|
491
|
+
id: str
|
|
492
|
+
is_purged: bool = False
|
|
493
|
+
|
|
494
|
+
|
|
401
495
|
class ShareLink(BaseModel):
|
|
402
496
|
"""A shareable public link that maps a token to a resource within an org.
|
|
403
497
|
|
|
@@ -563,26 +657,21 @@ class PublishUserInteractionRequest(BaseModel):
|
|
|
563
657
|
agent_version: str = (
|
|
564
658
|
"" # this is used for aggregating interactions for generating agent playbooks
|
|
565
659
|
)
|
|
566
|
-
session_id:
|
|
660
|
+
session_id: NonEmptyStr # used for grouping requests together
|
|
567
661
|
skip_aggregation: bool = (
|
|
568
662
|
False # when True, extract profiles/playbooks but skip aggregation
|
|
569
663
|
)
|
|
570
664
|
force_extraction: bool = False # when True, bypass all extraction gates (stride_size, cheap pre-filter, LLM should_run) and always run extractors
|
|
665
|
+
evaluation_only: bool = False # when True, store for evaluation and permanently exclude from profile/playbook extraction
|
|
571
666
|
override_learning_stall: bool = False # when True, run extraction even if a provider auth/billing stall is recorded
|
|
572
|
-
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
573
|
-
"""Per-request annotations stamped by customer integration code.
|
|
574
|
-
|
|
575
|
-
Mirrors ``Request.metadata`` — the publish path copies this dict
|
|
576
|
-
onto the ``Request`` row it creates so the eval pipeline (and the
|
|
577
|
-
F2 sticky-group aggregator in particular) can read it back from
|
|
578
|
-
the first request of each session.
|
|
579
667
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
668
|
+
@model_validator(mode="after")
|
|
669
|
+
def validate_evaluation_only(self) -> Self:
|
|
670
|
+
if self.evaluation_only and self.force_extraction:
|
|
671
|
+
raise ValueError("evaluation_only cannot be combined with force_extraction")
|
|
672
|
+
if self.evaluation_only and not self.session_id:
|
|
673
|
+
raise ValueError("evaluation_only publishes require session_id")
|
|
674
|
+
return self
|
|
586
675
|
|
|
587
676
|
|
|
588
677
|
# publish user interaction response
|
|
@@ -42,6 +42,10 @@ class Status(str, Enum): # noqa: UP042 - CURRENT=None is not compatible with St
|
|
|
42
42
|
ARCHIVE_IN_PROGRESS = (
|
|
43
43
|
"archive_in_progress" # temporary status during downgrade operation
|
|
44
44
|
)
|
|
45
|
+
MERGED = "merged" # tombstone: consolidated into a survivor (merged_into set)
|
|
46
|
+
SUPERSEDED = (
|
|
47
|
+
"superseded" # tombstone: replaced by a new version (superseded_by set)
|
|
48
|
+
)
|
|
45
49
|
|
|
46
50
|
|
|
47
51
|
class OperationStatus(StrEnum):
|