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,27 +1,31 @@
|
|
|
1
1
|
"""Aggregator that composes hero, tiles, rule attribution, and distribution.
|
|
2
2
|
|
|
3
|
-
The service
|
|
4
|
-
and
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The service bulk-loads the requested evaluation window plus related source,
|
|
4
|
+
citation, Braintrust, and optional shadow verdict rows, then returns a
|
|
5
|
+
GetEvaluationOverviewResponse. It's invoked from the FastAPI route handler; the
|
|
6
|
+
storage is the same BaseStorage the rest of the server uses, so the same
|
|
7
|
+
instance is reused via request_context.
|
|
7
8
|
"""
|
|
8
9
|
|
|
9
10
|
from __future__ import annotations
|
|
10
11
|
|
|
12
|
+
import logging
|
|
13
|
+
import time
|
|
11
14
|
from collections import defaultdict
|
|
12
15
|
from collections.abc import Iterable
|
|
13
16
|
from dataclasses import dataclass
|
|
14
17
|
from datetime import UTC, datetime
|
|
18
|
+
from typing import Any
|
|
15
19
|
|
|
16
20
|
from reflexio.models.api_schema.braintrust_schema import ImportedScore
|
|
17
21
|
from reflexio.models.api_schema.domain.entities import (
|
|
18
22
|
AgentSuccessEvaluationResult,
|
|
19
|
-
Request,
|
|
20
23
|
)
|
|
21
24
|
from reflexio.models.api_schema.eval_overview_schema import (
|
|
22
25
|
BraintrustTileRow,
|
|
23
26
|
BucketLiteral,
|
|
24
27
|
ContextTile,
|
|
28
|
+
EvaluationSourceSetRequest,
|
|
25
29
|
GetEvaluationOverviewRequest,
|
|
26
30
|
GetEvaluationOverviewResponse,
|
|
27
31
|
HeroBlock,
|
|
@@ -31,29 +35,29 @@ from reflexio.models.api_schema.eval_overview_schema import (
|
|
|
31
35
|
RuleAttributionRow,
|
|
32
36
|
ScoreDistribution,
|
|
33
37
|
ShadowWinRateTrend,
|
|
34
|
-
|
|
38
|
+
SourceSetComparison,
|
|
39
|
+
SourceSetEvaluationMetrics,
|
|
35
40
|
)
|
|
36
41
|
from reflexio.models.config_schema import Config
|
|
37
|
-
from reflexio.server.services.evaluation_overview.distribution import (
|
|
42
|
+
from reflexio.server.services.evaluation_overview.components.distribution import (
|
|
38
43
|
BUCKET_LABELS,
|
|
39
44
|
bucket_corrections,
|
|
40
45
|
)
|
|
41
|
-
from reflexio.server.services.evaluation_overview.
|
|
42
|
-
compute_trend_by_group,
|
|
43
|
-
)
|
|
44
|
-
from reflexio.server.services.evaluation_overview.hero_state import (
|
|
46
|
+
from reflexio.server.services.evaluation_overview.components.hero_state import (
|
|
45
47
|
compute_hero_state,
|
|
46
48
|
)
|
|
47
|
-
from reflexio.server.services.evaluation_overview.rule_attribution import (
|
|
49
|
+
from reflexio.server.services.evaluation_overview.components.rule_attribution import (
|
|
48
50
|
compute_net_sessions,
|
|
49
51
|
)
|
|
50
|
-
from reflexio.server.services.evaluation_overview.shadow_aggregation import (
|
|
52
|
+
from reflexio.server.services.evaluation_overview.components.shadow_aggregation import (
|
|
51
53
|
compute_shadow_win_rate_trend,
|
|
52
54
|
)
|
|
53
55
|
|
|
54
56
|
_DAY_SECONDS = 24 * 60 * 60
|
|
55
57
|
_WEEK_SECONDS = 7 * 24 * 60 * 60
|
|
56
58
|
_TOP_N_RULES = 5
|
|
59
|
+
_LOGGER = logging.getLogger(__name__)
|
|
60
|
+
ResultKey = tuple[str, str]
|
|
57
61
|
|
|
58
62
|
|
|
59
63
|
@dataclass
|
|
@@ -65,7 +69,7 @@ class EvaluationOverviewService:
|
|
|
65
69
|
Stateless across calls — safe to reuse the instance across requests.
|
|
66
70
|
"""
|
|
67
71
|
|
|
68
|
-
storage:
|
|
72
|
+
storage: Any
|
|
69
73
|
config: Config
|
|
70
74
|
|
|
71
75
|
def run(
|
|
@@ -85,18 +89,25 @@ class EvaluationOverviewService:
|
|
|
85
89
|
so every tile would display "no baseline" regardless of how much
|
|
86
90
|
data the org has.
|
|
87
91
|
"""
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
# Tile + distribution baselines are always last-7d-vs-prior-7d,
|
|
93
|
+
# anchored to ``request.to_ts`` (which is "now" from the frontend's
|
|
94
|
+
# perspective).
|
|
95
|
+
cur_7d_from = max(request.from_ts, request.to_ts - _WEEK_SECONDS)
|
|
96
|
+
prev_to = cur_7d_from
|
|
97
|
+
prev_from = max(0, prev_to - _WEEK_SECONDS)
|
|
98
|
+
load_from = min(request.from_ts, prev_from)
|
|
99
|
+
|
|
100
|
+
start = time.perf_counter()
|
|
101
|
+
all_results = self.storage.get_agent_success_evaluation_results_in_window( # type: ignore[attr-defined]
|
|
102
|
+
from_ts=load_from,
|
|
103
|
+
to_ts=request.to_ts,
|
|
104
|
+
agent_version=None,
|
|
90
105
|
)
|
|
106
|
+
self._log_phase("eval_results", start, rows=len(all_results))
|
|
107
|
+
|
|
91
108
|
results = [
|
|
92
109
|
r for r in all_results if request.from_ts <= r.created_at <= request.to_ts
|
|
93
110
|
]
|
|
94
|
-
|
|
95
|
-
# Tile + distribution baselines are always last-7d-vs-prior-7d, anchored
|
|
96
|
-
# to ``request.to_ts`` (which is "now" from the frontend's perspective).
|
|
97
|
-
cur_7d_from = max(request.from_ts, request.to_ts - _WEEK_SECONDS)
|
|
98
|
-
prev_to = cur_7d_from
|
|
99
|
-
prev_from = max(0, prev_to - _WEEK_SECONDS)
|
|
100
111
|
results_current_7d = [
|
|
101
112
|
r for r in all_results if cur_7d_from <= r.created_at <= request.to_ts
|
|
102
113
|
]
|
|
@@ -105,23 +116,76 @@ class EvaluationOverviewService:
|
|
|
105
116
|
]
|
|
106
117
|
|
|
107
118
|
earliest_eval_ts = min((r.created_at for r in all_results), default=None)
|
|
119
|
+
result_keys = list(
|
|
120
|
+
dict.fromkeys((r.user_id, r.session_id) for r in results if r.session_id)
|
|
121
|
+
)
|
|
122
|
+
if request.source_sets:
|
|
123
|
+
source_keys = list(
|
|
124
|
+
dict.fromkeys(
|
|
125
|
+
(r.user_id, r.session_id)
|
|
126
|
+
for r in (*results, *results_current_7d, *results_prev_7d)
|
|
127
|
+
if r.session_id
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
source_keys = result_keys
|
|
132
|
+
start = time.perf_counter()
|
|
133
|
+
session_sources = self._build_first_request_sources(source_keys)
|
|
134
|
+
self._log_phase(
|
|
135
|
+
"session_sources",
|
|
136
|
+
start,
|
|
137
|
+
sessions=len(set(source_keys)),
|
|
138
|
+
rows=len(session_sources),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
start = time.perf_counter()
|
|
142
|
+
citations_by_session, rule_titles = self._load_citations(result_keys)
|
|
143
|
+
self._log_phase(
|
|
144
|
+
"citations",
|
|
145
|
+
start,
|
|
146
|
+
sessions=len(set(result_keys)),
|
|
147
|
+
rows=sum(len(v) for v in citations_by_session.values()),
|
|
148
|
+
)
|
|
149
|
+
|
|
108
150
|
hero = self._build_hero(request, results, earliest_eval_ts)
|
|
109
151
|
tiles = self._build_tiles(results_current_7d, results_prev_7d)
|
|
110
|
-
attribution = self._build_attribution(
|
|
152
|
+
attribution = self._build_attribution(
|
|
153
|
+
results, citations_by_session, rule_titles
|
|
154
|
+
)
|
|
111
155
|
distribution = self._build_distribution(results_current_7d, results_prev_7d)
|
|
112
|
-
|
|
156
|
+
start = time.perf_counter()
|
|
157
|
+
current_scores, prior_scores = self._load_braintrust_scores(
|
|
113
158
|
cur_7d_from, request.to_ts, prev_from, prev_to
|
|
114
159
|
)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
self._log_phase(
|
|
161
|
+
"braintrust",
|
|
162
|
+
start,
|
|
163
|
+
current_rows=len(current_scores),
|
|
164
|
+
prior_rows=len(prior_scores),
|
|
165
|
+
)
|
|
166
|
+
braintrust_tiles = self._build_braintrust_tiles_from_scores(
|
|
167
|
+
current_scores, prior_scores
|
|
168
|
+
)
|
|
169
|
+
start = time.perf_counter()
|
|
170
|
+
shadow_win_rate_trend = (
|
|
171
|
+
self._build_shadow_win_rate_trend(request.from_ts, request.to_ts)
|
|
172
|
+
if request.include_shadow
|
|
173
|
+
else ShadowWinRateTrend(
|
|
174
|
+
judge_prompt_version=self.config.shadow_comparison_judge_prompt_version
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
self._log_phase("shadow", start, enabled=request.include_shadow)
|
|
178
|
+
source_set_comparison = self._build_source_set_comparison(
|
|
179
|
+
source_sets=request.source_sets,
|
|
180
|
+
results=results,
|
|
181
|
+
current=results_current_7d,
|
|
182
|
+
previous=results_prev_7d,
|
|
183
|
+
session_sources=session_sources,
|
|
184
|
+
bucket=request.bucket,
|
|
185
|
+
citations_by_session=citations_by_session,
|
|
186
|
+
rule_titles=rule_titles,
|
|
187
|
+
current_scores=current_scores,
|
|
188
|
+
prior_scores=prior_scores,
|
|
125
189
|
)
|
|
126
190
|
|
|
127
191
|
return GetEvaluationOverviewResponse(
|
|
@@ -130,8 +194,8 @@ class EvaluationOverviewService:
|
|
|
130
194
|
rule_attribution=attribution,
|
|
131
195
|
score_distribution=distribution,
|
|
132
196
|
braintrust_tiles=braintrust_tiles,
|
|
133
|
-
success_rate_trend_by_group=success_rate_trend_by_group,
|
|
134
197
|
shadow_win_rate_trend=shadow_win_rate_trend,
|
|
198
|
+
source_set_comparison=source_set_comparison,
|
|
135
199
|
)
|
|
136
200
|
|
|
137
201
|
# --- private helpers ---
|
|
@@ -198,12 +262,14 @@ class EvaluationOverviewService:
|
|
|
198
262
|
)
|
|
199
263
|
|
|
200
264
|
def _build_attribution(
|
|
201
|
-
self,
|
|
265
|
+
self,
|
|
266
|
+
results: list[AgentSuccessEvaluationResult],
|
|
267
|
+
citations_by_session: dict[ResultKey, list[tuple[str, str]]],
|
|
268
|
+
rule_titles: dict[tuple[str, str], str],
|
|
202
269
|
) -> list[RuleAttributionRow]:
|
|
203
|
-
is_success_by_session = {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
)
|
|
270
|
+
is_success_by_session = {
|
|
271
|
+
(r.user_id, r.session_id): r.is_success for r in results
|
|
272
|
+
}
|
|
207
273
|
rows = compute_net_sessions(
|
|
208
274
|
citations_by_session=citations_by_session,
|
|
209
275
|
is_success_by_session=is_success_by_session,
|
|
@@ -224,51 +290,57 @@ class EvaluationOverviewService:
|
|
|
224
290
|
]
|
|
225
291
|
|
|
226
292
|
def _load_citations(
|
|
227
|
-
self,
|
|
228
|
-
) -> tuple[dict[
|
|
229
|
-
"""Pull `Interaction.citations` keyed by session, with title lookup.
|
|
293
|
+
self, result_keys: list[ResultKey]
|
|
294
|
+
) -> tuple[dict[ResultKey, list[tuple[str, str]]], dict[tuple[str, str], str]]:
|
|
295
|
+
"""Pull `Interaction.citations` keyed by user/session, with title lookup.
|
|
230
296
|
|
|
231
297
|
Falls back to empty data when the underlying storage method returns
|
|
232
298
|
no interactions (default behavior on backends that haven't yet
|
|
233
299
|
implemented `get_interactions_by_session`).
|
|
234
300
|
"""
|
|
235
|
-
|
|
236
|
-
for
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
kind = getattr(cite, "kind", None)
|
|
248
|
-
rid = getattr(cite, "real_id", None)
|
|
249
|
-
if kind and rid:
|
|
250
|
-
citations_by_session[sid].append((kind, str(rid)))
|
|
251
|
-
# Titles via existing playbook_application_stats lookup
|
|
252
|
-
stats = self.storage.get_playbook_application_stats(days_back=30) # type: ignore[attr-defined]
|
|
253
|
-
rule_titles = {(s.kind, s.real_id): s.title for s in stats}
|
|
301
|
+
wanted = set(result_keys)
|
|
302
|
+
session_ids = sorted({session_id for _, session_id in result_keys})
|
|
303
|
+
citations_by_session: dict[ResultKey, list[tuple[str, str]]] = defaultdict(list)
|
|
304
|
+
rule_titles: dict[tuple[str, str], str] = {}
|
|
305
|
+
for citation in self.storage.get_citations_by_session_ids(session_ids): # type: ignore[attr-defined]
|
|
306
|
+
result_key = (citation.user_id, citation.session_id)
|
|
307
|
+
if result_key not in wanted:
|
|
308
|
+
continue
|
|
309
|
+
key = (citation.kind, citation.real_id)
|
|
310
|
+
citations_by_session[result_key].append(key)
|
|
311
|
+
if citation.title and key not in rule_titles:
|
|
312
|
+
rule_titles[key] = citation.title
|
|
254
313
|
return citations_by_session, rule_titles
|
|
255
314
|
|
|
256
|
-
def
|
|
257
|
-
self,
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
connected" and hides the Braintrust strip entirely.
|
|
264
|
-
"""
|
|
315
|
+
def _load_braintrust_scores(
|
|
316
|
+
self,
|
|
317
|
+
from_ts: int,
|
|
318
|
+
to_ts: int,
|
|
319
|
+
prev_from: int,
|
|
320
|
+
prev_to: int,
|
|
321
|
+
) -> tuple[list[ImportedScore], list[ImportedScore]]:
|
|
265
322
|
org_id = self._org_id()
|
|
266
323
|
if not org_id:
|
|
267
|
-
return []
|
|
324
|
+
return [], []
|
|
268
325
|
current = self.storage.get_imported_scores(org_id, from_ts, to_ts) # type: ignore[attr-defined]
|
|
269
326
|
if not current:
|
|
270
|
-
return []
|
|
327
|
+
return [], []
|
|
271
328
|
prior = self.storage.get_imported_scores(org_id, prev_from, prev_to) # type: ignore[attr-defined]
|
|
329
|
+
return current, prior
|
|
330
|
+
|
|
331
|
+
def _build_braintrust_tiles_from_scores(
|
|
332
|
+
self,
|
|
333
|
+
current: list[ImportedScore],
|
|
334
|
+
prior: list[ImportedScore],
|
|
335
|
+
session_ids: set[str] | None = None,
|
|
336
|
+
) -> list[BraintrustTileRow]:
|
|
337
|
+
"""Aggregate imported_score rows per scorer_name for current + prior windows."""
|
|
338
|
+
if session_ids is not None:
|
|
339
|
+
current = [s for s in current if s.session_id in session_ids]
|
|
340
|
+
if not current:
|
|
341
|
+
return []
|
|
342
|
+
if session_ids is not None:
|
|
343
|
+
prior = [s for s in prior if s.session_id in session_ids]
|
|
272
344
|
cur_agg = _aggregate_imported_scores(current)
|
|
273
345
|
prior_agg = _aggregate_imported_scores(prior)
|
|
274
346
|
rows: list[BraintrustTileRow] = []
|
|
@@ -288,6 +360,81 @@ class EvaluationOverviewService:
|
|
|
288
360
|
)
|
|
289
361
|
return rows
|
|
290
362
|
|
|
363
|
+
def _build_source_set_comparison(
|
|
364
|
+
self,
|
|
365
|
+
*,
|
|
366
|
+
source_sets: list[EvaluationSourceSetRequest],
|
|
367
|
+
results: list[AgentSuccessEvaluationResult],
|
|
368
|
+
current: list[AgentSuccessEvaluationResult],
|
|
369
|
+
previous: list[AgentSuccessEvaluationResult],
|
|
370
|
+
session_sources: dict[ResultKey, str],
|
|
371
|
+
bucket: BucketLiteral,
|
|
372
|
+
citations_by_session: dict[ResultKey, list[tuple[str, str]]],
|
|
373
|
+
rule_titles: dict[tuple[str, str], str],
|
|
374
|
+
current_scores: list[ImportedScore],
|
|
375
|
+
prior_scores: list[ImportedScore],
|
|
376
|
+
) -> SourceSetComparison:
|
|
377
|
+
"""Build request-source cohort metrics for the evaluation page."""
|
|
378
|
+
available_sources = sorted(
|
|
379
|
+
{session_sources.get((r.user_id, r.session_id), "") for r in results}
|
|
380
|
+
)
|
|
381
|
+
if not source_sets:
|
|
382
|
+
return SourceSetComparison(available_sources=available_sources)
|
|
383
|
+
|
|
384
|
+
requested_sources = {source for s in source_sets for source in s.sources}
|
|
385
|
+
unmatched = sum(
|
|
386
|
+
1
|
|
387
|
+
for r in results
|
|
388
|
+
if session_sources.get((r.user_id, r.session_id), "")
|
|
389
|
+
not in requested_sources
|
|
390
|
+
)
|
|
391
|
+
rows: list[SourceSetEvaluationMetrics] = []
|
|
392
|
+
for source_set in source_sets:
|
|
393
|
+
source_values = set(source_set.sources)
|
|
394
|
+
set_results = [
|
|
395
|
+
r
|
|
396
|
+
for r in results
|
|
397
|
+
if session_sources.get((r.user_id, r.session_id), "") in source_values
|
|
398
|
+
]
|
|
399
|
+
set_current = [
|
|
400
|
+
r
|
|
401
|
+
for r in current
|
|
402
|
+
if session_sources.get((r.user_id, r.session_id), "") in source_values
|
|
403
|
+
]
|
|
404
|
+
set_previous = [
|
|
405
|
+
r
|
|
406
|
+
for r in previous
|
|
407
|
+
if session_sources.get((r.user_id, r.session_id), "") in source_values
|
|
408
|
+
]
|
|
409
|
+
session_ids = {r.session_id for r in set_results if r.session_id}
|
|
410
|
+
rows.append(
|
|
411
|
+
SourceSetEvaluationMetrics(
|
|
412
|
+
label=source_set.label,
|
|
413
|
+
sources=list(source_set.sources),
|
|
414
|
+
session_count=len(set_results),
|
|
415
|
+
session_ids=sorted(session_ids),
|
|
416
|
+
success_rate_pp=_success_rate(set_results) * 100,
|
|
417
|
+
buckets=_buckets(set_results, bucket),
|
|
418
|
+
context_tiles=self._build_tiles(set_current, set_previous),
|
|
419
|
+
score_distribution=self._build_distribution(
|
|
420
|
+
set_current, set_previous
|
|
421
|
+
),
|
|
422
|
+
rule_attribution=self._build_attribution(
|
|
423
|
+
set_results, citations_by_session, rule_titles
|
|
424
|
+
),
|
|
425
|
+
braintrust_tiles=self._build_braintrust_tiles_from_scores(
|
|
426
|
+
current_scores,
|
|
427
|
+
prior_scores,
|
|
428
|
+
session_ids=session_ids,
|
|
429
|
+
),
|
|
430
|
+
)
|
|
431
|
+
)
|
|
432
|
+
return SourceSetComparison(
|
|
433
|
+
available_sources=available_sources,
|
|
434
|
+
sets=rows,
|
|
435
|
+
unmatched_session_count=unmatched,
|
|
436
|
+
)
|
|
437
|
+
|
|
291
438
|
def _org_id(self) -> str:
|
|
292
439
|
"""Resolve org_id from request_context when available; else empty string."""
|
|
293
440
|
# The service is constructed with `storage` + `config`; org_id isn't a
|
|
@@ -331,97 +478,14 @@ class EvaluationOverviewService:
|
|
|
331
478
|
verdicts, judge_prompt_version=pinned_version
|
|
332
479
|
)
|
|
333
480
|
|
|
334
|
-
def
|
|
335
|
-
self,
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
``metadata.reflexio_retrieval_enabled``, then delegates to the pure
|
|
343
|
-
``compute_trend_by_group`` aggregator. Returns the default empty
|
|
344
|
-
``SuccessRateTrendByGroup`` when ``results`` is empty.
|
|
345
|
-
|
|
346
|
-
Args:
|
|
347
|
-
results (list[AgentSuccessEvaluationResult]): Eval results in the
|
|
348
|
-
trend window.
|
|
349
|
-
bucket (str): Bucket granularity literal (``"week"`` or ``"day"``).
|
|
350
|
-
|
|
351
|
-
Returns:
|
|
352
|
-
SuccessRateTrendByGroup: Three curves (any of which may be empty).
|
|
353
|
-
"""
|
|
354
|
-
if not results:
|
|
355
|
-
return SuccessRateTrendByGroup()
|
|
356
|
-
bucket_seconds = _WEEK_SECONDS if bucket == "week" else _DAY_SECONDS
|
|
357
|
-
outcomes = self._build_group_outcomes(results)
|
|
358
|
-
return compute_trend_by_group(outcomes, bucket_seconds)
|
|
359
|
-
|
|
360
|
-
def _build_group_outcomes(
|
|
361
|
-
self,
|
|
362
|
-
results: list[AgentSuccessEvaluationResult],
|
|
363
|
-
) -> list[tuple[str, int, bool, dict]]:
|
|
364
|
-
"""Pair each eval result with its session's first-request metadata.
|
|
365
|
-
|
|
366
|
-
Caches ``session_id → first_request_metadata`` so storage is hit
|
|
367
|
-
once per distinct session, not once per result. Sessions without a
|
|
368
|
-
matching request fall through with an empty-dict metadata, which the
|
|
369
|
-
downstream aggregator routes to the UNTAGGED bucket.
|
|
370
|
-
|
|
371
|
-
Args:
|
|
372
|
-
results (list[AgentSuccessEvaluationResult]): Eval results to
|
|
373
|
-
annotate with their session's first-request metadata.
|
|
374
|
-
|
|
375
|
-
Returns:
|
|
376
|
-
list[tuple[str, int, bool, dict]]: Tuples of
|
|
377
|
-
``(session_id, created_at, is_success, first_request_metadata)``
|
|
378
|
-
suitable for :func:`compute_trend_by_group`.
|
|
379
|
-
"""
|
|
380
|
-
session_ids = {r.session_id for r in results if r.session_id}
|
|
381
|
-
first_request_metadata: dict[str, dict] = {}
|
|
382
|
-
for sid in session_ids:
|
|
383
|
-
reqs = self._get_session_requests(sid)
|
|
384
|
-
if reqs:
|
|
385
|
-
first = min(reqs, key=lambda r: r.created_at)
|
|
386
|
-
first_request_metadata[sid] = first.metadata or {}
|
|
387
|
-
else:
|
|
388
|
-
first_request_metadata[sid] = {}
|
|
389
|
-
|
|
390
|
-
return [
|
|
391
|
-
(
|
|
392
|
-
r.session_id or "",
|
|
393
|
-
r.created_at,
|
|
394
|
-
r.is_success,
|
|
395
|
-
first_request_metadata.get(r.session_id or "", {}),
|
|
396
|
-
)
|
|
397
|
-
for r in results
|
|
398
|
-
]
|
|
399
|
-
|
|
400
|
-
def _get_session_requests(self, session_id: str) -> list[Request]:
|
|
401
|
-
"""Return every request in ``session_id`` regardless of user.
|
|
402
|
-
|
|
403
|
-
Uses ``BaseStorage.get_sessions(session_id=...)`` because the
|
|
404
|
-
per-session, user-id-required ``get_requests_by_session`` doesn't
|
|
405
|
-
fit our caller (eval results don't carry ``user_id``). All locally
|
|
406
|
-
testable backends ignore the ``user_id`` filter when it's ``None``,
|
|
407
|
-
and ``top_k`` is raised well above realistic per-session counts so
|
|
408
|
-
we don't truncate.
|
|
409
|
-
|
|
410
|
-
Args:
|
|
411
|
-
session_id (str): The session whose requests to fetch.
|
|
412
|
-
|
|
413
|
-
Returns:
|
|
414
|
-
list[Request]: All requests in the session, in storage order.
|
|
415
|
-
"""
|
|
416
|
-
grouped = self.storage.get_sessions( # type: ignore[attr-defined]
|
|
417
|
-
session_id=session_id, top_k=1000
|
|
418
|
-
)
|
|
419
|
-
return [
|
|
420
|
-
entry.request
|
|
421
|
-
for entries in grouped.values()
|
|
422
|
-
for entry in entries
|
|
423
|
-
if entry.request is not None
|
|
424
|
-
]
|
|
481
|
+
def _build_first_request_sources(
|
|
482
|
+
self, result_keys: list[ResultKey]
|
|
483
|
+
) -> dict[ResultKey, str]:
|
|
484
|
+
"""Map each user/session slice to its earliest request's source."""
|
|
485
|
+
first_requests = self.storage.get_first_requests_by_user_session_pairs(
|
|
486
|
+
result_keys
|
|
487
|
+
) # type: ignore[attr-defined]
|
|
488
|
+
return {key: row.source or "" for key, row in first_requests.items()}
|
|
425
489
|
|
|
426
490
|
def _build_distribution(
|
|
427
491
|
self,
|
|
@@ -440,6 +504,16 @@ class EvaluationOverviewService:
|
|
|
440
504
|
labels=list(BUCKET_LABELS),
|
|
441
505
|
)
|
|
442
506
|
|
|
507
|
+
def _log_phase(self, phase: str, started_at: float, **metadata: object) -> None:
|
|
508
|
+
duration_ms = int((time.perf_counter() - started_at) * 1000)
|
|
509
|
+
fields = " ".join(f"{key}={value}" for key, value in metadata.items())
|
|
510
|
+
_LOGGER.info(
|
|
511
|
+
"evaluation_overview phase=%s duration_ms=%d %s",
|
|
512
|
+
phase,
|
|
513
|
+
duration_ms,
|
|
514
|
+
fields,
|
|
515
|
+
)
|
|
516
|
+
|
|
443
517
|
|
|
444
518
|
# --- module-level helpers (pure) ---
|
|
445
519
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# services/extraction
|
|
2
|
+
|
|
3
|
+
Shared async extraction runtime for profile and playbook pipelines.
|
|
4
|
+
|
|
5
|
+
This package is intentionally domain-neutral. Profile and playbook modules own
|
|
6
|
+
their prompts, schemas, extractor semantics, and storage decisions; this package
|
|
7
|
+
owns the reusable runtime needed when extraction pauses, waits for more
|
|
8
|
+
information, and resumes outside the request path.
|
|
9
|
+
|
|
10
|
+
## Files
|
|
11
|
+
|
|
12
|
+
| File | Responsibility |
|
|
13
|
+
|------|----------------|
|
|
14
|
+
| `resumable_agent.py` | Runs extraction agents, records agent usage, injects resolved pending-tool context, and exposes pending tool-call helpers. |
|
|
15
|
+
| `pending_tool_call_dispatch.py` | Implements the `ask_human` and pending-info tool dispatch flow. |
|
|
16
|
+
| `prior_answer_search.py` | Finds and formats previous human answers for async extraction context. |
|
|
17
|
+
| `agent_run_records.py` | Builds durable extraction-agent run records and source interaction identity. |
|
|
18
|
+
| `resume_scheduler.py` | Schedules due paused extraction runs in a background singleton. |
|
|
19
|
+
| `resume_worker.py` | Resumes paused runs, rebuilds request context, and records retry state. |
|
|
20
|
+
| `outcome.py` | Provides the generic extraction outcome wrapper used by callers. |
|
|
21
|
+
|
|
22
|
+
## Boundary Rules
|
|
23
|
+
|
|
24
|
+
- Keep profile-specific and playbook-specific extraction behavior in their own
|
|
25
|
+
modules; call this package only for shared async runtime concerns.
|
|
26
|
+
- Add a new file here when the behavior is shared by more than one extraction
|
|
27
|
+
caller or is part of the resumable runtime itself.
|
|
28
|
+
- Split into subpackages only when a responsibility grows large enough that a
|
|
29
|
+
flat package stops being easier to scan.
|
|
30
|
+
- Do not recreate removed legacy modules such as `tools.py`, `plan.py`, or
|
|
31
|
+
`invariants.py`; use the current focused files above.
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
|
-
from typing import Literal
|
|
6
|
+
from typing import TYPE_CHECKING, Literal
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from reflexio.server.llm.token_accounting import RunTokenTotals
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
@dataclass(frozen=True)
|
|
@@ -13,12 +16,19 @@ class ExtractionOutcome[T]:
|
|
|
13
16
|
status: Literal["completed", "empty"]
|
|
14
17
|
items: list[T] = field(default_factory=list)
|
|
15
18
|
run_id: str | None = None
|
|
19
|
+
token_totals: RunTokenTotals | None = None
|
|
16
20
|
|
|
17
21
|
@classmethod
|
|
18
22
|
def completed(
|
|
19
|
-
cls,
|
|
23
|
+
cls,
|
|
24
|
+
items: list[T],
|
|
25
|
+
*,
|
|
26
|
+
run_id: str | None = None,
|
|
27
|
+
token_totals: RunTokenTotals | None = None,
|
|
20
28
|
) -> ExtractionOutcome[T]:
|
|
21
|
-
return cls(
|
|
29
|
+
return cls(
|
|
30
|
+
status="completed", items=items, run_id=run_id, token_totals=token_totals
|
|
31
|
+
)
|
|
22
32
|
|
|
23
33
|
@classmethod
|
|
24
34
|
def empty(cls, *, run_id: str | None = None) -> ExtractionOutcome[T]:
|
package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py
CHANGED
|
@@ -11,6 +11,7 @@ from typing import Annotated, Any
|
|
|
11
11
|
from pydantic import BaseModel, Field, field_validator
|
|
12
12
|
|
|
13
13
|
from reflexio.models.config_schema import PendingToolCallConfig
|
|
14
|
+
from reflexio.models.structured_output import StrictStructuredOutput
|
|
14
15
|
from reflexio.server.llm.tools import (
|
|
15
16
|
AsyncAccepted,
|
|
16
17
|
AsyncInfoTool,
|
|
@@ -31,7 +32,7 @@ from reflexio.server.usage_metrics import record_usage_event
|
|
|
31
32
|
logger = logging.getLogger(__name__)
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
class AskHumanArgs(
|
|
35
|
+
class AskHumanArgs(StrictStructuredOutput):
|
|
35
36
|
"""Ask Agent Builder for missing extraction information and continue now."""
|
|
36
37
|
|
|
37
38
|
question: Annotated[str, Field(min_length=1)]
|
|
@@ -46,7 +47,7 @@ class AskHumanArgs(BaseModel):
|
|
|
46
47
|
return value
|
|
47
48
|
|
|
48
49
|
|
|
49
|
-
class AttachPendingInfoRequestArgs(
|
|
50
|
+
class AttachPendingInfoRequestArgs(StrictStructuredOutput):
|
|
50
51
|
"""Attach this run to a relevant pending Prior Knowledge request."""
|
|
51
52
|
|
|
52
53
|
pending_tool_call_id: Annotated[str, Field(min_length=1)]
|