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
|
@@ -4,6 +4,7 @@ Prompt management using file system prompt bank with markdown frontmatter files.
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
import re
|
|
7
|
+
from collections.abc import Sequence
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
@@ -75,28 +76,37 @@ class PromptManager:
|
|
|
75
76
|
|
|
76
77
|
def __init__(
|
|
77
78
|
self,
|
|
78
|
-
prompt_bank_path: str | None = None,
|
|
79
|
+
prompt_bank_path: str | Path | None = None,
|
|
79
80
|
version_override: dict[str, str] | None = None,
|
|
81
|
+
extra_prompt_bank_paths: Sequence[str | Path] | None = None,
|
|
80
82
|
):
|
|
81
83
|
"""
|
|
82
84
|
Initialize the PromptManager.
|
|
83
85
|
|
|
84
86
|
Args:
|
|
85
|
-
prompt_bank_path (str, optional): Path to the prompt bank directory.
|
|
87
|
+
prompt_bank_path (str | Path, optional): Path to the primary prompt bank directory.
|
|
86
88
|
version_override (dict[str, str], optional): Map of prompt_id → version string to override the active version.
|
|
89
|
+
extra_prompt_bank_paths (Sequence[str | Path], optional): Additional prompt bank directories.
|
|
87
90
|
"""
|
|
88
91
|
if prompt_bank_path is None:
|
|
89
92
|
current_dir = Path(__file__).parent
|
|
90
93
|
self.prompt_bank_path = current_dir / "prompt_bank"
|
|
91
94
|
else:
|
|
92
95
|
self.prompt_bank_path = Path(prompt_bank_path)
|
|
96
|
+
self.prompt_bank_paths = [self.prompt_bank_path]
|
|
97
|
+
if extra_prompt_bank_paths:
|
|
98
|
+
self.prompt_bank_paths.extend(
|
|
99
|
+
Path(path) for path in extra_prompt_bank_paths
|
|
100
|
+
)
|
|
93
101
|
|
|
94
102
|
self.version_override = version_override
|
|
95
103
|
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
for path in self.prompt_bank_paths:
|
|
105
|
+
if not path.exists():
|
|
106
|
+
logger.warning("Prompt bank path does not exist: %s", path)
|
|
98
107
|
|
|
99
108
|
self._cache: dict[str, Prompt] = {}
|
|
109
|
+
self._validate_unique_prompt_ids()
|
|
100
110
|
|
|
101
111
|
# ==============================
|
|
102
112
|
# Public methods
|
|
@@ -148,13 +158,13 @@ class PromptManager:
|
|
|
148
158
|
Returns:
|
|
149
159
|
list[str]: List of version strings.
|
|
150
160
|
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
versions: list[str] = []
|
|
162
|
+
for prompt_dir in self._prompt_dirs(prompt_id):
|
|
163
|
+
versions.extend(
|
|
164
|
+
p.name.removeprefix("v").removesuffix(".prompt.md")
|
|
165
|
+
for p in sorted(prompt_dir.glob("v*.prompt.md"))
|
|
166
|
+
)
|
|
167
|
+
return versions
|
|
158
168
|
|
|
159
169
|
def get_active_version(self, prompt_id: str) -> str | None:
|
|
160
170
|
"""
|
|
@@ -177,21 +187,65 @@ class PromptManager:
|
|
|
177
187
|
Returns:
|
|
178
188
|
list[str]: List of prompt IDs.
|
|
179
189
|
"""
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
prompt_ids: list[str] = []
|
|
191
|
+
seen: set[str] = set()
|
|
192
|
+
for prompt_bank_path in self.prompt_bank_paths:
|
|
193
|
+
if not prompt_bank_path.exists():
|
|
194
|
+
continue
|
|
195
|
+
for item in prompt_bank_path.iterdir():
|
|
196
|
+
if (
|
|
197
|
+
item.is_dir()
|
|
198
|
+
and item.name not in seen
|
|
199
|
+
and any(item.glob("v*.prompt.md"))
|
|
200
|
+
):
|
|
201
|
+
prompt_ids.append(item.name)
|
|
202
|
+
seen.add(item.name)
|
|
203
|
+
return prompt_ids
|
|
187
204
|
|
|
188
205
|
# ==============================
|
|
189
206
|
# Private methods
|
|
190
207
|
# ==============================
|
|
191
208
|
|
|
209
|
+
def _prompt_dirs(self, prompt_id: str) -> list[Path]:
|
|
210
|
+
"""Return configured prompt directories for a prompt ID."""
|
|
211
|
+
return [
|
|
212
|
+
prompt_bank_path / prompt_id
|
|
213
|
+
for prompt_bank_path in self.prompt_bank_paths
|
|
214
|
+
if (prompt_bank_path / prompt_id).is_dir()
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
def _validate_unique_prompt_ids(self) -> None:
|
|
218
|
+
"""Reject prompt IDs that appear in more than one configured prompt bank."""
|
|
219
|
+
locations: dict[str, list[Path]] = {}
|
|
220
|
+
for prompt_bank_path in self.prompt_bank_paths:
|
|
221
|
+
if not prompt_bank_path.exists():
|
|
222
|
+
continue
|
|
223
|
+
for item in prompt_bank_path.iterdir():
|
|
224
|
+
if item.is_dir() and any(item.glob("v*.prompt.md")):
|
|
225
|
+
locations.setdefault(item.name, []).append(item)
|
|
226
|
+
|
|
227
|
+
duplicates = {
|
|
228
|
+
prompt_id: paths for prompt_id, paths in locations.items() if len(paths) > 1
|
|
229
|
+
}
|
|
230
|
+
if duplicates:
|
|
231
|
+
details = "; ".join(
|
|
232
|
+
f"{prompt_id}: {', '.join(str(path) for path in paths)}"
|
|
233
|
+
for prompt_id, paths in sorted(duplicates.items())
|
|
234
|
+
)
|
|
235
|
+
raise ValueError(f"Duplicate prompt_id found in prompt banks: {details}")
|
|
236
|
+
|
|
192
237
|
def _load_prompt(self, prompt_id: str, version: str) -> Prompt | None:
|
|
193
238
|
"""Load a single prompt file by prompt_id and version string."""
|
|
194
|
-
path
|
|
239
|
+
path: Path | None = None
|
|
240
|
+
for prompt_dir in self._prompt_dirs(prompt_id):
|
|
241
|
+
candidate = prompt_dir / f"v{version}.prompt.md"
|
|
242
|
+
if candidate.is_file():
|
|
243
|
+
path = candidate
|
|
244
|
+
break
|
|
245
|
+
if path is None:
|
|
246
|
+
logger.warning("Prompt file not found: %s v%s", prompt_id, version)
|
|
247
|
+
return None
|
|
248
|
+
|
|
195
249
|
try:
|
|
196
250
|
raw = path.read_text(encoding="utf-8")
|
|
197
251
|
except FileNotFoundError:
|
|
@@ -217,8 +271,8 @@ class PromptManager:
|
|
|
217
271
|
|
|
218
272
|
def _find_active_version(self, prompt_id: str) -> str | None:
|
|
219
273
|
"""Scan .prompt.md files to find the latest one with active: true."""
|
|
220
|
-
|
|
221
|
-
if not
|
|
274
|
+
prompt_dirs = self._prompt_dirs(prompt_id)
|
|
275
|
+
if not prompt_dirs:
|
|
222
276
|
return None
|
|
223
277
|
|
|
224
278
|
def _semver_key(p: Path) -> tuple[int, ...]:
|
|
@@ -239,17 +293,20 @@ class PromptManager:
|
|
|
239
293
|
return (0,)
|
|
240
294
|
|
|
241
295
|
latest: str | None = None
|
|
242
|
-
for
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
296
|
+
for prompt_dir in prompt_dirs:
|
|
297
|
+
for path in sorted(
|
|
298
|
+
prompt_dir.glob("v*.prompt.md"), key=_semver_key, reverse=True
|
|
299
|
+
):
|
|
300
|
+
try:
|
|
301
|
+
raw = path.read_text(encoding="utf-8")
|
|
302
|
+
meta, _ = _parse_frontmatter(raw)
|
|
303
|
+
if meta.get("active"):
|
|
304
|
+
latest = path.name.removeprefix("v").removesuffix(".prompt.md")
|
|
305
|
+
break
|
|
306
|
+
except (ValueError, OSError):
|
|
307
|
+
continue
|
|
308
|
+
if latest:
|
|
309
|
+
break
|
|
253
310
|
return latest
|
|
254
311
|
|
|
255
312
|
def _get_prompt(self, prompt_id: str, version: str | None = None) -> Prompt | None:
|
|
@@ -5,6 +5,19 @@ Description: Core business-logic layer — LLM orchestration, extraction, evalua
|
|
|
5
5
|
|
|
6
6
|
**Service Boundary**: services own the LLM/extraction/evaluation/storage logic; API endpoints only authenticate, build `RequestContext`, and delegate into `Reflexio` or a focused service helper.
|
|
7
7
|
|
|
8
|
+
## LLM Pipeline Module Contract
|
|
9
|
+
|
|
10
|
+
LLM/pipeline modules use a shared vocabulary across OSS and enterprise:
|
|
11
|
+
`service.py` for request-path entry points, `runner.py` for manual/background
|
|
12
|
+
workflow entry points, `scheduler.py` for periodic/deferred execution,
|
|
13
|
+
`config.py` for module-owned config, `models.py` for module-local data shapes,
|
|
14
|
+
and `components/` for internal extractors, judges, proposers, aggregators,
|
|
15
|
+
evaluators, gates, and resolvers.
|
|
16
|
+
|
|
17
|
+
Files are optional. Do not create empty files only to satisfy the vocabulary.
|
|
18
|
+
Complete cutover migrations update consumers, tests, docs, and monkeypatch
|
|
19
|
+
strings before deleting old import paths in the same PR.
|
|
20
|
+
|
|
8
21
|
## Orchestration & Base Infrastructure
|
|
9
22
|
|
|
10
23
|
| File | Purpose |
|
|
@@ -13,32 +26,34 @@ Description: Core business-logic layer — LLM orchestration, extraction, evalua
|
|
|
13
26
|
| `base_generation_service.py` | `BaseGenerationService` — abstract base; the **Service Pattern** (load configs → create actors → run in parallel → save results). Per-extractor timeout `EXTRACTOR_TIMEOUT_SECONDS = 300`. |
|
|
14
27
|
| `operation_state_utils.py` | `OperationStateManager` — all `_operation_state` access (progress, concurrency locks, extractor/aggregator bookmarks, cluster fingerprints, cancellation). |
|
|
15
28
|
| `extractor_config_utils.py`, `extractor_interaction_utils.py` | Filter extractors by source / `allow_manual_trigger` / names; per-extractor stride + window + bookmark handling. |
|
|
16
|
-
| `deduplication_utils.py`, `service_utils.py`, `embedding_text.py` | LLM dedup helpers (used by `
|
|
29
|
+
| `deduplication_utils.py`, `service_utils.py`, `embedding_text.py` | LLM dedup helpers (used by `ProfileConsolidator` + `PlaybookConsolidator`), message construction / JSON extraction / response logging, embedding text builders. |
|
|
17
30
|
|
|
18
31
|
## Generation Services
|
|
19
32
|
|
|
20
33
|
| Directory | Entry class | Key files |
|
|
21
34
|
|-----------|-------------|-----------|
|
|
22
|
-
| `profile/` | `ProfileGenerationService` | `
|
|
23
|
-
| `playbook/` | `PlaybookGenerationService` | `
|
|
24
|
-
| `agent_success_evaluation/` | `AgentSuccessEvaluationService` | `
|
|
25
|
-
| `reflection/` | `ReflectionService` | `
|
|
35
|
+
| `profile/` | `ProfileGenerationService` | `service.py`, `components/extractor.py`, `components/consolidator.py` |
|
|
36
|
+
| `playbook/` | `PlaybookGenerationService` | `components/extractor.py`, `components/consolidator.py`, `components/aggregator.py` (cluster-fingerprint change detection) — has its own [README](playbook/README.md) |
|
|
37
|
+
| `agent_success_evaluation/` | `AgentSuccessEvaluationService` | `service.py` (session-level service), `runner.py` (`run_group_evaluation`), `scheduler.py` (`GroupEvaluationScheduler`, 10-min defer), `regen_jobs.py`, `components/evaluator.py` |
|
|
38
|
+
| `reflection/` | `ReflectionService` | `service.py`, `components/extractor.py` — post-horizon reflection; runs **before** extraction so extractors read post-reflection state |
|
|
26
39
|
|
|
27
40
|
## Async Extraction
|
|
28
41
|
|
|
29
42
|
| Directory | Purpose |
|
|
30
43
|
|-----------|---------|
|
|
31
|
-
| `extraction/` |
|
|
44
|
+
| `extraction/` | Shared async extraction runtime: `resumable_agent.py`, `resume_scheduler.py`, `resume_worker.py`, `pending_tool_call_dispatch.py` (`ask_human`), `prior_answer_search.py`, `agent_run_records.py`, and `outcome.py`. Long-horizon / tool-mediated extraction continues outside the request path. See [README](extraction/README.md). |
|
|
32
45
|
|
|
33
46
|
## Evaluation, Search & Integrations
|
|
34
47
|
|
|
35
48
|
| Path | Purpose |
|
|
36
49
|
|------|---------|
|
|
37
|
-
| `shadow_comparison/` | `ShadowComparisonJudge`
|
|
38
|
-
| `evaluation_overview/` | Dashboard rollups: `service.py
|
|
39
|
-
| `playbook_optimizer/` | Scenario-based playbook optimization: `optimizer.py`, `scheduler.py`, `rollout.py`, `judge.py`, `scenario_resolver.py`, `gepa_adapter.py`, `assistant_webhook.py`. |
|
|
50
|
+
| `shadow_comparison/` | `ShadowComparisonJudge` (`judge.py`) plus pure outcome helpers (`outcome.py`) - per-turn regular-vs-shadow verdicts written to a separate table. Compact by design; see [README](shadow_comparison/README.md). |
|
|
51
|
+
| `evaluation_overview/` | Dashboard/read-side rollups: `service.py` entry point, `components/` aggregation helpers, and root `eval_sampler.py` shared with regenerate jobs. See [README](evaluation_overview/README.md). |
|
|
52
|
+
| `playbook_optimizer/` | Scenario-based playbook optimization: mature flat package with `optimizer.py`, `scheduler.py`, `rollout.py`, `judge.py`, `models.py`, `scenario_resolver.py`, `gepa_adapter.py`, and `assistant_webhook.py`. See [README](playbook_optimizer/README.md). |
|
|
40
53
|
| `braintrust/` | Braintrust export/sync: `service.py`, `client.py`, `_cron.py`, `_encryption.py`. |
|
|
41
|
-
| `
|
|
54
|
+
| `lineage/` | Current-record resolution and tombstone GC: `resolve.py`, `gc_scheduler.py`. |
|
|
55
|
+
| `pre_retrieval/` | `QueryReformulator` (`_query_reformulator.py`) + `DocumentExpander` (`_document_expander.py`) - query rewrite and doc expansion for recall. Compact by design; see [README](pre_retrieval/README.md). |
|
|
56
|
+
| `tagging/` | `TaggingService` (`service.py`) + deferred `tagging_scheduler.py` - post-generation profile/playbook tagging. Compact by design; see [README](tagging/README.md). |
|
|
42
57
|
| `unified_search_service.py` | `run_unified_search()` — two-phase parallel search across profiles / agent playbooks / user playbooks. |
|
|
43
58
|
| `retrieval/` | `relevance_floor.py` — result relevance thresholding. |
|
|
44
59
|
|
|
@@ -46,7 +61,7 @@ Description: Core business-logic layer — LLM orchestration, extraction, evalua
|
|
|
46
61
|
|
|
47
62
|
| Path | Purpose |
|
|
48
63
|
|------|---------|
|
|
49
|
-
| `storage/` | `storage_base/` (`BaseStorage` split by domain) + `sqlite_storage/` + `retention*.py`. Access via `request_context.storage` only. |
|
|
64
|
+
| `storage/` | `storage_base/` (`BaseStorage` split by domain, including `_lineage.py`) + `sqlite_storage/` (including lineage/tombstones) + `retention*.py`. Access via `request_context.storage` only. |
|
|
50
65
|
| `configurator/` | `DefaultConfigurator` — loads YAML config and creates the storage backend. |
|
|
51
66
|
|
|
52
67
|
## Key Rules
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# agent_success_evaluation
|
|
2
|
+
|
|
3
|
+
Session-level agent success evaluation module.
|
|
4
|
+
|
|
5
|
+
## Module Shape
|
|
6
|
+
|
|
7
|
+
- `service.py`: `AgentSuccessEvaluationService`, the request-path service that runs configured evaluators and saves result rows.
|
|
8
|
+
- `runner.py`: `run_group_evaluation(...)`, the background/manual workflow entry point that loads a session, runs the service, dispatches shadow comparison, and marks operation state.
|
|
9
|
+
- `scheduler.py`: `GroupEvaluationScheduler`, the deferred inactivity scheduler.
|
|
10
|
+
- `components/evaluator.py`: `AgentSuccessEvaluator`, the LLM evaluator component.
|
|
11
|
+
- `regen_jobs.py`: regeneration job planning and execution; remains root-level because API/admin regenerate flows import it directly.
|
|
12
|
+
- `_eval_health.py`: producer/scheduler health counters.
|
|
13
|
+
- `agent_success_evaluation_constants.py`: prompt/model output constants.
|
|
14
|
+
- `agent_success_evaluation_utils.py`: request DTO and prompt-message construction helpers.
|
|
15
|
+
|
|
16
|
+
## Prompt IDs
|
|
17
|
+
|
|
18
|
+
- Owns `agent_success_evaluation`.
|
|
19
|
+
- Keeps historical/configured prompt ID `agent_success_evaluation_with_comparison` stable where prompt mapping tests require it.
|
|
20
|
+
|
|
21
|
+
Do not reintroduce the deleted service/evaluator/runner/scheduler legacy
|
|
22
|
+
module files.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Agent success evaluation service package."""
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from typing import Literal
|
|
5
5
|
|
|
6
|
-
from pydantic import
|
|
6
|
+
from pydantic import ConfigDict, Field
|
|
7
|
+
|
|
8
|
+
from reflexio.models.structured_output import StrictStructuredOutput
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
@dataclass(frozen=True)
|
|
@@ -14,7 +16,7 @@ class AgentSuccessEvaluationConstants:
|
|
|
14
16
|
AGENT_SUCCESS_EVALUATION_PROMPT_ID = "agent_success_evaluation"
|
|
15
17
|
|
|
16
18
|
|
|
17
|
-
class AgentSuccessEvaluationOutput(
|
|
19
|
+
class AgentSuccessEvaluationOutput(StrictStructuredOutput):
|
|
18
20
|
"""
|
|
19
21
|
Unified output schema for agent success evaluation.
|
|
20
22
|
|
|
@@ -19,6 +19,7 @@ from reflexio.server.services.service_utils import (
|
|
|
19
19
|
class AgentSuccessEvaluationRequest(BaseModel):
|
|
20
20
|
"""Request schema for agent success evaluation"""
|
|
21
21
|
|
|
22
|
+
user_id: str = ""
|
|
22
23
|
session_id: str
|
|
23
24
|
agent_version: str
|
|
24
25
|
request_interaction_data_models: list[RequestInteractionDataModel]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import random
|
|
5
4
|
from datetime import UTC, datetime
|
|
6
5
|
from typing import TYPE_CHECKING
|
|
7
6
|
|
|
@@ -34,7 +33,7 @@ from reflexio.server.services.service_utils import (
|
|
|
34
33
|
from reflexio.server.site_var.site_var_manager import SiteVarManager
|
|
35
34
|
|
|
36
35
|
if TYPE_CHECKING:
|
|
37
|
-
from reflexio.server.services.agent_success_evaluation.
|
|
36
|
+
from reflexio.server.services.agent_success_evaluation.service import (
|
|
38
37
|
AgentSuccessGenerationServiceConfig,
|
|
39
38
|
)
|
|
40
39
|
|
|
@@ -104,7 +103,7 @@ class AgentSuccessEvaluator:
|
|
|
104
103
|
|
|
105
104
|
Treats all request_interaction_data_models as a single conversation.
|
|
106
105
|
Applies source filtering based on extractor config.
|
|
107
|
-
|
|
106
|
+
Sampling is handled by callers before invoking the evaluator.
|
|
108
107
|
|
|
109
108
|
Returns:
|
|
110
109
|
List of AgentSuccessEvaluationResult objects (single result for the group)
|
|
@@ -130,19 +129,6 @@ class AgentSuccessEvaluator:
|
|
|
130
129
|
# No matching interactions after source filter
|
|
131
130
|
return []
|
|
132
131
|
|
|
133
|
-
# Check sampling rate once per group
|
|
134
|
-
if self.config.sampling_rate < 1.0:
|
|
135
|
-
random_value = random.random() # noqa: S311
|
|
136
|
-
if random_value >= self.config.sampling_rate:
|
|
137
|
-
logger.info(
|
|
138
|
-
"Skipping evaluation for session %s due to sampling rate. "
|
|
139
|
-
"sampling_rate=%s, random_value=%.3f",
|
|
140
|
-
self.service_config.session_id,
|
|
141
|
-
self.config.sampling_rate,
|
|
142
|
-
random_value,
|
|
143
|
-
)
|
|
144
|
-
return []
|
|
145
|
-
|
|
146
132
|
result = self._evaluate_group(request_interaction_data_models)
|
|
147
133
|
return [result] if result else []
|
|
148
134
|
|
|
@@ -288,6 +274,7 @@ class AgentSuccessEvaluator:
|
|
|
288
274
|
request_interaction_data_models
|
|
289
275
|
)
|
|
290
276
|
return AgentSuccessEvaluationResult(
|
|
277
|
+
user_id=self.service_config.user_id,
|
|
291
278
|
session_id=self.service_config.session_id,
|
|
292
279
|
agent_version=self.service_config.agent_version,
|
|
293
280
|
evaluation_name=get_extractor_name(self.config),
|
package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py
CHANGED
|
@@ -13,12 +13,12 @@ import time
|
|
|
13
13
|
import uuid
|
|
14
14
|
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
|
|
15
15
|
from dataclasses import dataclass, field
|
|
16
|
-
from typing import
|
|
16
|
+
from typing import Literal
|
|
17
17
|
|
|
18
18
|
from reflexio.models.api_schema.internal_schema import SessionDescriptor
|
|
19
19
|
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
20
20
|
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
21
|
-
from reflexio.server.services.agent_success_evaluation.
|
|
21
|
+
from reflexio.server.services.agent_success_evaluation.runner import (
|
|
22
22
|
run_group_evaluation,
|
|
23
23
|
)
|
|
24
24
|
from reflexio.server.services.evaluation_overview.eval_sampler import (
|
|
@@ -170,74 +170,16 @@ class RegenJobRegistry:
|
|
|
170
170
|
REGEN_JOBS = RegenJobRegistry()
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
def _load_first_request(
|
|
174
|
-
storage: BaseStorage,
|
|
175
|
-
user_id: str,
|
|
176
|
-
session_id: str,
|
|
177
|
-
cache: dict[str, tuple[int, dict[str, Any]]],
|
|
178
|
-
) -> tuple[int, dict[str, Any]]:
|
|
179
|
-
"""Return the (created_at, metadata) of a session's earliest request, memoized.
|
|
180
|
-
|
|
181
|
-
The regen worker can see multiple SessionDescriptors for the same
|
|
182
|
-
session_id (one per distinct agent_version/source tuple). This
|
|
183
|
-
helper guarantees each session_id triggers at most one storage call,
|
|
184
|
-
mirroring the amortized pattern F2's evaluation overview service
|
|
185
|
-
uses.
|
|
186
|
-
|
|
187
|
-
Args:
|
|
188
|
-
storage (BaseStorage): Storage backend bound to the request_context.
|
|
189
|
-
user_id (str): Owner of the session's requests.
|
|
190
|
-
session_id (str): Session whose first-request data to return.
|
|
191
|
-
cache (dict[str, tuple[int, dict[str, Any]]]): Memoization dict
|
|
192
|
-
keyed by session_id; updated in place.
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
tuple[int, dict[str, Any]]: ``(first_created_at, first_metadata)``.
|
|
196
|
-
Falls back to ``(0, {})`` when the session has no requests (the
|
|
197
|
-
descriptor is still kept so the regen worker can attempt
|
|
198
|
-
evaluation; the sampler simply treats it as the epoch-zero day
|
|
199
|
-
bucket and the untagged group).
|
|
200
|
-
"""
|
|
201
|
-
cached = cache.get(session_id)
|
|
202
|
-
if cached is not None:
|
|
203
|
-
return cached
|
|
204
|
-
try:
|
|
205
|
-
requests = storage.get_requests_by_session(user_id, session_id)
|
|
206
|
-
except Exception as e: # noqa: BLE001 — per-session resilience boundary
|
|
207
|
-
logger.warning(
|
|
208
|
-
"Failed to fetch requests for session %s during F3 sampler candidate "
|
|
209
|
-
"discovery (%s); falling back to (created_at=0, metadata={}). The "
|
|
210
|
-
"session will be retried in the per-session loop below.",
|
|
211
|
-
session_id,
|
|
212
|
-
e,
|
|
213
|
-
)
|
|
214
|
-
cache[session_id] = (0, {})
|
|
215
|
-
return cache[session_id]
|
|
216
|
-
if not requests:
|
|
217
|
-
logger.warning(
|
|
218
|
-
"Session %s has no requests in storage despite being returned by "
|
|
219
|
-
"get_session_ids_in_window (possible race or contract violation); "
|
|
220
|
-
"falling back to (created_at=0, metadata={}).",
|
|
221
|
-
session_id,
|
|
222
|
-
)
|
|
223
|
-
cache[session_id] = (0, {})
|
|
224
|
-
return cache[session_id]
|
|
225
|
-
first = min(requests, key=lambda r: r.created_at)
|
|
226
|
-
cache[session_id] = (first.created_at, first.metadata or {})
|
|
227
|
-
return cache[session_id]
|
|
228
|
-
|
|
229
|
-
|
|
230
173
|
def _build_sample_candidates(
|
|
231
174
|
storage: BaseStorage,
|
|
232
175
|
descriptors: list[SessionDescriptor],
|
|
233
176
|
) -> list[SampleCandidate]:
|
|
234
|
-
"""Convert raw SessionDescriptors into SampleCandidates
|
|
177
|
+
"""Convert raw SessionDescriptors into SampleCandidates.
|
|
235
178
|
|
|
236
|
-
Reads
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
the
|
|
240
|
-
the session's wall clock (not the regen window's edges).
|
|
179
|
+
Reads first-request data for all distinct session_ids in one storage call,
|
|
180
|
+
then assembles one ``SampleCandidate`` per descriptor. ``created_at`` is
|
|
181
|
+
sourced from the first request's timestamp so the day-bucket stratum aligns
|
|
182
|
+
with the session's wall clock (not the regen window's edges).
|
|
241
183
|
|
|
242
184
|
Args:
|
|
243
185
|
storage (BaseStorage): Storage backend used to load per-session data.
|
|
@@ -248,20 +190,34 @@ def _build_sample_candidates(
|
|
|
248
190
|
list[SampleCandidate]: One candidate per descriptor, ready for the
|
|
249
191
|
pure ``sample_candidates`` function.
|
|
250
192
|
"""
|
|
251
|
-
|
|
193
|
+
pairs = sorted({(sd.user_id, sd.session_id) for sd in descriptors})
|
|
194
|
+
try:
|
|
195
|
+
first_requests = storage.get_first_requests_by_user_session_pairs(pairs)
|
|
196
|
+
except Exception as e: # noqa: BLE001 — discovery should not abort the whole job
|
|
197
|
+
logger.warning(
|
|
198
|
+
"Failed to bulk fetch first requests during F3 sampler candidate "
|
|
199
|
+
"discovery (%s); falling back to epoch-zero source buckets.",
|
|
200
|
+
e,
|
|
201
|
+
)
|
|
202
|
+
first_requests = {}
|
|
203
|
+
|
|
252
204
|
candidates: list[SampleCandidate] = []
|
|
253
205
|
for sd in descriptors:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
206
|
+
first = first_requests.get((sd.user_id, sd.session_id))
|
|
207
|
+
if first is None:
|
|
208
|
+
logger.warning(
|
|
209
|
+
"Session %s has no first request in storage despite being returned by "
|
|
210
|
+
"get_session_ids_in_window; falling back to (created_at=0, source='').",
|
|
211
|
+
sd.session_id,
|
|
212
|
+
)
|
|
257
213
|
candidates.append(
|
|
258
214
|
SampleCandidate(
|
|
259
215
|
session_id=sd.session_id,
|
|
260
216
|
user_id=sd.user_id,
|
|
261
217
|
agent_version=sd.agent_version,
|
|
262
218
|
source=sd.source,
|
|
263
|
-
created_at=created_at,
|
|
264
|
-
|
|
219
|
+
created_at=first.created_at if first else 0,
|
|
220
|
+
first_request_source=(first.source or "") if first else "",
|
|
265
221
|
)
|
|
266
222
|
)
|
|
267
223
|
return candidates
|
|
@@ -328,7 +284,7 @@ def run_regen(
|
|
|
328
284
|
|
|
329
285
|
Step 1 enumerates all candidate sessions in ``[from_ts, to_ts]`` via
|
|
330
286
|
``storage.get_session_ids_in_window``. Step 2 stratifies them by
|
|
331
|
-
(day-bucket x
|
|
287
|
+
(day-bucket x first request source) and samples up to
|
|
332
288
|
``config.eval_sample_n_per_stratum`` per stratum — giving the regen
|
|
333
289
|
pipeline predictable cost regardless of traffic volume. Step 3
|
|
334
290
|
dispatches the sampled subset through a ``ThreadPoolExecutor`` whose
|
|
@@ -15,15 +15,16 @@ from reflexio.server.api_endpoints.request_context import RequestContext
|
|
|
15
15
|
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
16
16
|
from reflexio.server.services.agent_success_evaluation import _eval_health
|
|
17
17
|
from reflexio.server.services.agent_success_evaluation._eval_health import SkipReason
|
|
18
|
-
from reflexio.server.services.agent_success_evaluation.agent_success_evaluation_service import (
|
|
19
|
-
AgentSuccessEvaluationService,
|
|
20
|
-
)
|
|
21
18
|
from reflexio.server.services.agent_success_evaluation.agent_success_evaluation_utils import (
|
|
22
19
|
AgentSuccessEvaluationRequest,
|
|
23
20
|
)
|
|
24
|
-
from reflexio.server.services.agent_success_evaluation.
|
|
21
|
+
from reflexio.server.services.agent_success_evaluation.scheduler import (
|
|
25
22
|
_EFFECTIVE_DELAY_SECONDS,
|
|
26
23
|
)
|
|
24
|
+
from reflexio.server.services.agent_success_evaluation.service import (
|
|
25
|
+
AgentSuccessEvaluationService,
|
|
26
|
+
)
|
|
27
|
+
from reflexio.server.services.extractor_config_utils import get_extractor_name
|
|
27
28
|
from reflexio.server.services.shadow_comparison.judge import ShadowComparisonJudge
|
|
28
29
|
|
|
29
30
|
logger = logging.getLogger(__name__)
|
|
@@ -166,13 +167,13 @@ def run_group_evaluation(
|
|
|
166
167
|
# afterwards cannot remove the new rows.
|
|
167
168
|
old_result_ids: list[int] = []
|
|
168
169
|
if force_regenerate:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
config = request_context.configurator.get_config()
|
|
171
|
+
old_result_ids = storage.get_agent_success_evaluation_result_ids( # type: ignore[reportOptionalMemberAccess]
|
|
172
|
+
user_id=user_id,
|
|
173
|
+
session_id=session_id,
|
|
174
|
+
evaluation_name=get_extractor_name(config),
|
|
175
|
+
agent_version=agent_version,
|
|
174
176
|
)
|
|
175
|
-
old_result_ids = [r.result_id for r in prior_rows if r.session_id == session_id]
|
|
176
177
|
|
|
177
178
|
logger.info(
|
|
178
179
|
"Running group evaluation for session=%s with %d requests and %d interactions"
|
|
@@ -185,6 +186,7 @@ def run_group_evaluation(
|
|
|
185
186
|
)
|
|
186
187
|
|
|
187
188
|
evaluation_request = AgentSuccessEvaluationRequest(
|
|
189
|
+
user_id=user_id,
|
|
188
190
|
session_id=session_id,
|
|
189
191
|
agent_version=agent_version,
|
|
190
192
|
source=source,
|
|
@@ -18,9 +18,17 @@ from reflexio.server.services.agent_success_evaluation import _eval_health
|
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
|
|
21
|
+
# Default delay in seconds before evaluating a group after the last request.
|
|
22
|
+
_DEFAULT_DELAY_SECONDS = 600 # 10 minutes
|
|
23
23
|
|
|
24
|
+
# Inactivity delay before a session is evaluated. Override the default via the
|
|
25
|
+
# GROUP_EVALUATION_DELAY_SECONDS environment variable (in seconds).
|
|
26
|
+
GROUP_EVALUATION_DELAY_SECONDS = int(
|
|
27
|
+
os.environ.get("GROUP_EVALUATION_DELAY_SECONDS", str(_DEFAULT_DELAY_SECONDS))
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Kept as a patch point for tests. Production should use the full inactivity
|
|
31
|
+
# delay unless a test deliberately lowers this constant.
|
|
24
32
|
IS_TEST_ENV = os.environ.get("IS_TEST_ENV", "false").strip() == "true"
|
|
25
33
|
_EFFECTIVE_DELAY_SECONDS = 30 if IS_TEST_ENV else GROUP_EVALUATION_DELAY_SECONDS
|
|
26
34
|
|