claude-smart 0.2.45 → 0.2.47
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 +47 -10
- package/bin/claude-smart.js +535 -23
- 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 +27 -6
- 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/layout.tsx +20 -0
- 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 +232 -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 +251 -0
- package/plugin/opencode/tsconfig.json +13 -0
- package/plugin/pyproject.toml +25 -4
- package/plugin/scripts/_lib.sh +5 -1
- package/plugin/scripts/backend-service.sh +22 -2
- package/plugin/scripts/ensure-plugin-root.sh +4 -4
- package/plugin/scripts/hook_entry.sh +1 -1
- 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 +17 -9
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +498 -12
- package/plugin/src/claude_smart/context_format.py +9 -9
- package/plugin/src/claude_smart/cs_cite.py +66 -19
- 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 +5 -5
- package/plugin/vendor/reflexio/.env.example +54 -30
- package/plugin/vendor/reflexio/README.md +17 -11
- package/plugin/vendor/reflexio/pyproject.toml +13 -1
- package/plugin/vendor/reflexio/reflexio/README.md +4 -1
- 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 +212 -52
- 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/cli/utils.py +44 -1
- package/plugin/vendor/reflexio/reflexio/client/client.py +154 -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 +246 -10
- package/plugin/vendor/reflexio/reflexio/lib/_base.py +15 -0
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +17 -5
- package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +224 -21
- package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +52 -25
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +11 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +1 -0
- 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/domain/governance.py +117 -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 +97 -3
- 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 +104 -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 +58 -33
- 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/api.py +899 -103
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +4 -2
- package/plugin/vendor/reflexio/reflexio/server/auth.py +90 -0
- 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/extensions.py +213 -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/model_defaults.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1 -1
- 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/rerank/cross_encoder_reranker.py +12 -1
- 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 +278 -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 +28 -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 +47 -16
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
- package/plugin/vendor/reflexio/reflexio/server/services/governance/config.py +52 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +378 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/subject_refs.py +34 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +219 -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 +18 -11
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_prompt_processing.py +100 -0
- 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} +334 -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_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} +31 -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/recency.py +211 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +99 -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 +31 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +681 -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 +16 -2
- 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 +644 -197
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +106 -119
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +1965 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +630 -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 +31 -1369
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +756 -210
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +148 -34
- 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/sqlite_storage/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +952 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +189 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_optimization.py +247 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +145 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +838 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +150 -23
- 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 +40 -57
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_governance.py +148 -0
- 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 +4 -677
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +134 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +62 -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/storage/storage_base/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +365 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +124 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_optimization.py +85 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_source_linkage.py +47 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +333 -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 +372 -34
- 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/_auth.py +0 -25
- 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
|
@@ -10,10 +10,14 @@ from reflexio.server.services.agent_success_evaluation import _eval_health
|
|
|
10
10
|
from reflexio.server.services.agent_success_evaluation.agent_success_evaluation_utils import (
|
|
11
11
|
AgentSuccessEvaluationRequest,
|
|
12
12
|
)
|
|
13
|
-
from reflexio.server.services.agent_success_evaluation.
|
|
13
|
+
from reflexio.server.services.agent_success_evaluation.components.evaluator import (
|
|
14
14
|
AgentSuccessEvaluator,
|
|
15
15
|
)
|
|
16
16
|
from reflexio.server.services.base_generation_service import BaseGenerationService
|
|
17
|
+
from reflexio.server.services.extractor_interaction_utils import (
|
|
18
|
+
filter_interactions_by_source,
|
|
19
|
+
get_effective_source_filter,
|
|
20
|
+
)
|
|
17
21
|
|
|
18
22
|
logger = logging.getLogger(__name__)
|
|
19
23
|
|
|
@@ -23,12 +27,14 @@ class AgentSuccessGenerationServiceConfig:
|
|
|
23
27
|
"""Runtime configuration for agent success evaluation service shared across all extractors.
|
|
24
28
|
|
|
25
29
|
Attributes:
|
|
30
|
+
user_id: The user whose session slice is being evaluated
|
|
26
31
|
session_id: The session being evaluated
|
|
27
32
|
agent_version: The agent version
|
|
28
33
|
request_interaction_data_models: The interactions to evaluate
|
|
29
34
|
source: Source of the interactions
|
|
30
35
|
"""
|
|
31
36
|
|
|
37
|
+
user_id: str
|
|
32
38
|
session_id: str
|
|
33
39
|
agent_version: str
|
|
34
40
|
request_interaction_data_models: list[RequestInteractionDataModel]
|
|
@@ -76,6 +82,7 @@ class AgentSuccessEvaluationService(
|
|
|
76
82
|
AgentSuccessGenerationServiceConfig object
|
|
77
83
|
"""
|
|
78
84
|
return AgentSuccessGenerationServiceConfig(
|
|
85
|
+
user_id=request.user_id,
|
|
79
86
|
session_id=request.session_id,
|
|
80
87
|
agent_version=request.agent_version,
|
|
81
88
|
request_interaction_data_models=request.request_interaction_data_models,
|
|
@@ -115,6 +122,34 @@ class AgentSuccessEvaluationService(
|
|
|
115
122
|
agent_context=self.configurator.get_agent_context(),
|
|
116
123
|
)
|
|
117
124
|
|
|
125
|
+
def _collect_scoped_interactions_for_precheck(
|
|
126
|
+
self, extractor_config: AgentSuccessConfig
|
|
127
|
+
) -> tuple[list[RequestInteractionDataModel], AgentSuccessConfig]:
|
|
128
|
+
"""Use the session slice already loaded by the group runner.
|
|
129
|
+
|
|
130
|
+
The generic pre-check queries storage for learnable interaction windows,
|
|
131
|
+
which intentionally excludes evaluation-only requests. Agent-success
|
|
132
|
+
evaluation is allowed to run on evaluation-only sessions, so its
|
|
133
|
+
pre-check must inspect the request models passed to this service.
|
|
134
|
+
"""
|
|
135
|
+
service_config = self.service_config
|
|
136
|
+
if service_config is None:
|
|
137
|
+
raise RuntimeError("Agent success pre-check requires service_config")
|
|
138
|
+
session_data_models = service_config.request_interaction_data_models
|
|
139
|
+
should_skip, source_filter = get_effective_source_filter(
|
|
140
|
+
extractor_config, service_config.source
|
|
141
|
+
)
|
|
142
|
+
if should_skip:
|
|
143
|
+
self._last_precheck_sessions = []
|
|
144
|
+
return [], extractor_config
|
|
145
|
+
|
|
146
|
+
scoped_models = filter_interactions_by_source(
|
|
147
|
+
session_data_models,
|
|
148
|
+
source_filter,
|
|
149
|
+
)
|
|
150
|
+
self._last_precheck_sessions = scoped_models
|
|
151
|
+
return scoped_models, extractor_config
|
|
152
|
+
|
|
118
153
|
def _process_results(self, results: list) -> None:
|
|
119
154
|
"""
|
|
120
155
|
Process and save agent success evaluation results.
|
|
@@ -20,6 +20,7 @@ from reflexio.models.api_schema.internal_schema import RequestInteractionDataMod
|
|
|
20
20
|
from reflexio.models.api_schema.service_schemas import Status
|
|
21
21
|
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
22
22
|
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
23
|
+
from reflexio.server.llm.token_accounting import RunTokenTotals
|
|
23
24
|
from reflexio.server.services.extraction.outcome import ExtractionOutcome
|
|
24
25
|
from reflexio.server.services.extractor_config_utils import (
|
|
25
26
|
filter_extractor_configs,
|
|
@@ -165,6 +166,10 @@ class BaseGenerationService(
|
|
|
165
166
|
ABC,
|
|
166
167
|
Generic[TExtractorConfig, TExtractor, TGenerationServiceConfig, TRequest], # noqa: UP046
|
|
167
168
|
):
|
|
169
|
+
# Only profile/playbook GENERATION services bill the ② Learning line;
|
|
170
|
+
# reflection/consolidation/aggregation/evaluation are bundled, not metered.
|
|
171
|
+
# Default is False so any future subclass is safe by default (opt-IN).
|
|
172
|
+
EMITS_LEARNING_BILLING: bool = False
|
|
168
173
|
"""
|
|
169
174
|
Base class for generation services that run one configured extractor.
|
|
170
175
|
|
|
@@ -209,6 +214,11 @@ class BaseGenerationService(
|
|
|
209
214
|
"timed_out": 0,
|
|
210
215
|
}
|
|
211
216
|
self._last_extraction_run_ids: list[str] = []
|
|
217
|
+
self._last_token_totals: RunTokenTotals | None = None
|
|
218
|
+
# Window fetched by the should-run gate (_collect_scoped_interactions_for_precheck),
|
|
219
|
+
# stashed so the billing path (_extraction_input_text) can reuse it instead of
|
|
220
|
+
# re-querying storage. None when the gate did not run (bypass paths).
|
|
221
|
+
self._last_precheck_sessions: list[Any] | None = None
|
|
212
222
|
|
|
213
223
|
def _usage_pipeline(self) -> str | None:
|
|
214
224
|
service_name = self._get_service_name()
|
|
@@ -252,6 +262,139 @@ class BaseGenerationService(
|
|
|
252
262
|
metadata=metadata,
|
|
253
263
|
)
|
|
254
264
|
|
|
265
|
+
def _extraction_input_text(self, prepared: "PreparedGenerationRun[Any]") -> str:
|
|
266
|
+
"""Return the interaction content fed to the extractor as a single string.
|
|
267
|
+
|
|
268
|
+
Replays the same storage query the extractor uses (same user_id, source,
|
|
269
|
+
window params) so ``count_input_tokens`` sees the same text the LLM saw.
|
|
270
|
+
Returns an empty string when storage is unavailable or no interactions exist.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
prepared: The prepared generation run, used to access extractor_config
|
|
274
|
+
for window/source parameters.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
str: Formatted interaction history string, or "" if nothing is found.
|
|
278
|
+
"""
|
|
279
|
+
from reflexio.server.services.service_utils import (
|
|
280
|
+
format_sessions_to_history_string,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
if self.storage is None or self.service_config is None:
|
|
284
|
+
return ""
|
|
285
|
+
# Reuse the window the should-run gate already fetched
|
|
286
|
+
# (_collect_scoped_interactions_for_precheck stashed it). Same query params,
|
|
287
|
+
# so the token count is byte-identical — and we avoid a second storage read.
|
|
288
|
+
if self._last_precheck_sessions is not None:
|
|
289
|
+
return format_sessions_to_history_string(self._last_precheck_sessions)
|
|
290
|
+
# Fallback storage read: used ONLY when the gate did not pre-fetch
|
|
291
|
+
# (bypass paths: auto_run=False, force_extraction, skip_should_run_check,
|
|
292
|
+
# mock mode). Re-fetches the extractor's input window so billing token
|
|
293
|
+
# counting sees exactly the text the LLM saw.
|
|
294
|
+
try:
|
|
295
|
+
root_config = self.request_context.configurator.get_config()
|
|
296
|
+
global_window_size = (
|
|
297
|
+
getattr(root_config, "window_size", None) if root_config else None
|
|
298
|
+
)
|
|
299
|
+
global_stride_size = (
|
|
300
|
+
getattr(root_config, "stride_size", None) if root_config else None
|
|
301
|
+
)
|
|
302
|
+
window_size, _ = get_extractor_window_params(
|
|
303
|
+
prepared.extractor_config, global_window_size, global_stride_size
|
|
304
|
+
)
|
|
305
|
+
should_skip, effective_source = get_effective_source_filter(
|
|
306
|
+
prepared.extractor_config, getattr(self.service_config, "source", None)
|
|
307
|
+
)
|
|
308
|
+
if should_skip:
|
|
309
|
+
return ""
|
|
310
|
+
session_data_models, _ = self.storage.get_last_k_interactions_grouped(
|
|
311
|
+
user_id=getattr(self.service_config, "user_id", None),
|
|
312
|
+
k=window_size,
|
|
313
|
+
sources=effective_source,
|
|
314
|
+
start_time=getattr(self.service_config, "rerun_start_time", None),
|
|
315
|
+
end_time=getattr(self.service_config, "rerun_end_time", None),
|
|
316
|
+
**self._get_precheck_interaction_query_kwargs(),
|
|
317
|
+
)
|
|
318
|
+
return format_sessions_to_history_string(session_data_models)
|
|
319
|
+
except Exception:
|
|
320
|
+
logger.warning(
|
|
321
|
+
"_extraction_input_text failed; billing_input_tokens will be 0",
|
|
322
|
+
exc_info=True,
|
|
323
|
+
)
|
|
324
|
+
return ""
|
|
325
|
+
|
|
326
|
+
def _record_billing_learning_events(
|
|
327
|
+
self, *, prepared: "PreparedGenerationRun[Any]", generated_count: int
|
|
328
|
+
) -> None:
|
|
329
|
+
"""Emit the ② Learning billing events. Called ONLY when extraction fired.
|
|
330
|
+
|
|
331
|
+
Emits ``learnings_generated`` (value facet) and ``extraction_tokens``
|
|
332
|
+
(cost facet) via the OSS emission helpers. ``platform_storage`` is left
|
|
333
|
+
``None`` here and resolved enterprise-side at rollup (Phase 1).
|
|
334
|
+
|
|
335
|
+
Gated by ``EMITS_LEARNING_BILLING`` — only profile/playbook generation
|
|
336
|
+
services opt in. Evaluation, reflection, consolidation and aggregation
|
|
337
|
+
are bundled and must NOT separately meter the ② Learning line.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
prepared: The prepared generation run (used for input-text computation).
|
|
341
|
+
generated_count: Number of learnings produced by this extraction run.
|
|
342
|
+
"""
|
|
343
|
+
if not self.EMITS_LEARNING_BILLING:
|
|
344
|
+
return
|
|
345
|
+
|
|
346
|
+
try:
|
|
347
|
+
from reflexio.server.billing_meter import (
|
|
348
|
+
record_extraction_tokens,
|
|
349
|
+
record_learnings_generated,
|
|
350
|
+
)
|
|
351
|
+
from reflexio.server.billing_signals import (
|
|
352
|
+
count_input_tokens,
|
|
353
|
+
platform_llm_from_config,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
config = self.request_context.configurator.get_config()
|
|
357
|
+
platform_llm = platform_llm_from_config(config)
|
|
358
|
+
ctx = self._usage_context()
|
|
359
|
+
|
|
360
|
+
# session_id is intentionally not passed: the generation path has no
|
|
361
|
+
# session_id source. _usage_context() never includes it, and neither
|
|
362
|
+
# the Profile/Playbook service configs nor their requests carry a
|
|
363
|
+
# session_id (unlike the Application-line path in server/api.py, which
|
|
364
|
+
# reads request_id/session_id off the search request payload). Learning
|
|
365
|
+
# events therefore meter without session attribution by design.
|
|
366
|
+
|
|
367
|
+
# ② Learning — value: learnings generated (helper no-ops on count <= 0).
|
|
368
|
+
record_learnings_generated(
|
|
369
|
+
org_id=ctx["org_id"],
|
|
370
|
+
count=generated_count,
|
|
371
|
+
platform_llm=platform_llm,
|
|
372
|
+
platform_storage=None,
|
|
373
|
+
pipeline=ctx.get("pipeline"),
|
|
374
|
+
request_id=ctx.get("request_id"),
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
# ② Learning — cost: input-anchored extraction tokens + real provider tokens.
|
|
378
|
+
totals = self._last_token_totals or RunTokenTotals()
|
|
379
|
+
billing_input_tokens = count_input_tokens(
|
|
380
|
+
self._extraction_input_text(prepared)
|
|
381
|
+
)
|
|
382
|
+
record_extraction_tokens(
|
|
383
|
+
org_id=ctx["org_id"],
|
|
384
|
+
billing_input_tokens=billing_input_tokens,
|
|
385
|
+
prompt_tokens=totals.prompt_tokens,
|
|
386
|
+
completion_tokens=totals.completion_tokens,
|
|
387
|
+
platform_llm=platform_llm,
|
|
388
|
+
platform_storage=None,
|
|
389
|
+
pipeline=ctx.get("pipeline"),
|
|
390
|
+
request_id=ctx.get("request_id"),
|
|
391
|
+
)
|
|
392
|
+
except Exception:
|
|
393
|
+
logger.warning(
|
|
394
|
+
"_record_billing_learning_events failed; billing learning events not emitted",
|
|
395
|
+
exc_info=True,
|
|
396
|
+
)
|
|
397
|
+
|
|
255
398
|
@staticmethod
|
|
256
399
|
def _count_generated_results(result: Any) -> int:
|
|
257
400
|
if isinstance(result, list):
|
|
@@ -675,6 +818,7 @@ class BaseGenerationService(
|
|
|
675
818
|
},
|
|
676
819
|
)
|
|
677
820
|
self._last_extraction_run_ids = []
|
|
821
|
+
self._last_token_totals = None
|
|
678
822
|
result = self._execute_extractor(
|
|
679
823
|
prepared.extractor_config, prepared.identifier
|
|
680
824
|
)
|
|
@@ -704,6 +848,9 @@ class BaseGenerationService(
|
|
|
704
848
|
),
|
|
705
849
|
},
|
|
706
850
|
)
|
|
851
|
+
self._record_billing_learning_events(
|
|
852
|
+
prepared=prepared, generated_count=generated_count
|
|
853
|
+
)
|
|
707
854
|
|
|
708
855
|
except Exception as e:
|
|
709
856
|
self._record_generation_event(
|
|
@@ -737,6 +884,13 @@ class BaseGenerationService(
|
|
|
737
884
|
Returns:
|
|
738
885
|
PreparedGenerationRun when generation should proceed, otherwise None.
|
|
739
886
|
"""
|
|
887
|
+
# Reset BEFORE the should-run gate runs. The gate
|
|
888
|
+
# (_collect_scoped_interactions_for_precheck) stashes its fetched window
|
|
889
|
+
# here for the billing path to reuse. On bypass paths (auto_run=False,
|
|
890
|
+
# force_extraction, skip_should_run_check, mock mode) the gate never runs,
|
|
891
|
+
# so this stays None and billing falls back to its own fetch.
|
|
892
|
+
self._last_precheck_sessions = None
|
|
893
|
+
|
|
740
894
|
self.service_config = self._load_generation_service_config(request)
|
|
741
895
|
|
|
742
896
|
extractor_config = self._load_extractor_config()
|
|
@@ -834,6 +988,7 @@ class BaseGenerationService(
|
|
|
834
988
|
if isinstance(result, ExtractionOutcome):
|
|
835
989
|
if result.run_id:
|
|
836
990
|
self._last_extraction_run_ids.append(result.run_id)
|
|
991
|
+
self._last_token_totals = result.token_totals
|
|
837
992
|
if result.status == "completed" and result.items:
|
|
838
993
|
return result.items
|
|
839
994
|
logger.info(
|
|
@@ -1128,6 +1283,8 @@ class BaseGenerationService(
|
|
|
1128
1283
|
extractor_config, getattr(self.service_config, "source", None)
|
|
1129
1284
|
)
|
|
1130
1285
|
if should_skip:
|
|
1286
|
+
# Stash for the billing path to reuse (same window the gate saw).
|
|
1287
|
+
self._last_precheck_sessions = []
|
|
1131
1288
|
return [], extractor_config
|
|
1132
1289
|
|
|
1133
1290
|
window_size, _ = get_extractor_window_params(
|
|
@@ -1142,6 +1299,9 @@ class BaseGenerationService(
|
|
|
1142
1299
|
**extra_kwargs,
|
|
1143
1300
|
)
|
|
1144
1301
|
|
|
1302
|
+
# Stash for the billing path (_extraction_input_text) to reuse instead of
|
|
1303
|
+
# re-querying storage for billing_input_tokens.
|
|
1304
|
+
self._last_precheck_sessions = session_data_models
|
|
1145
1305
|
return session_data_models, extractor_config
|
|
1146
1306
|
|
|
1147
1307
|
def _get_precheck_interaction_query_kwargs(self) -> dict:
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from collections.abc import Callable
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
from typing import Any, ClassVar
|
|
7
8
|
|
|
8
9
|
from pydantic import BaseModel
|
|
@@ -81,6 +82,10 @@ class BaseConfigurator(ABC):
|
|
|
81
82
|
"""Normalize raw API config payloads before Pydantic validation."""
|
|
82
83
|
return config
|
|
83
84
|
|
|
85
|
+
def get_prompt_bank_paths(self) -> list[Path]:
|
|
86
|
+
"""Return additional prompt banks this configurator contributes."""
|
|
87
|
+
return []
|
|
88
|
+
|
|
84
89
|
def get_agent_context(self) -> str:
|
|
85
90
|
context = self.get_config().agent_context_prompt
|
|
86
91
|
if not context:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# evaluation_overview
|
|
2
|
+
|
|
3
|
+
Read-side aggregation module for `POST /api/get_evaluation_overview`.
|
|
4
|
+
|
|
5
|
+
- `service.py` is the request-path entry point. It loads evaluation, citation, Braintrust, and optional shadow verdict data, then composes `GetEvaluationOverviewResponse`.
|
|
6
|
+
- `components/` contains pure read-side aggregation helpers used by the service and focused tests.
|
|
7
|
+
- `eval_sampler.py` stays at the package root because regenerate jobs also use it to sample evaluation sessions.
|
|
8
|
+
|
|
9
|
+
This module mutates no core state. Keep response-shape changes in API schema tests and service integration tests.
|
package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py
ADDED
|
File without changes
|
|
@@ -11,6 +11,7 @@ from collections.abc import Mapping
|
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
|
|
13
13
|
CitationKey = tuple[str, str] # (kind, real_id) — matches PlaybookApplicationStat
|
|
14
|
+
SessionIdentity = tuple[str, str] # (user_id, session_id)
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
@dataclass(frozen=True)
|
|
@@ -36,19 +37,19 @@ class RuleAttribution:
|
|
|
36
37
|
|
|
37
38
|
def compute_net_sessions(
|
|
38
39
|
*,
|
|
39
|
-
citations_by_session: Mapping[
|
|
40
|
-
is_success_by_session: Mapping[
|
|
40
|
+
citations_by_session: Mapping[SessionIdentity, list[CitationKey]],
|
|
41
|
+
is_success_by_session: Mapping[SessionIdentity, bool],
|
|
41
42
|
rule_titles: Mapping[CitationKey, str],
|
|
42
43
|
top_n: int,
|
|
43
44
|
) -> list[RuleAttribution]:
|
|
44
45
|
"""Aggregate net sessions per rule and return the top N by net_sessions.
|
|
45
46
|
|
|
46
47
|
Args:
|
|
47
|
-
citations_by_session (Mapping[
|
|
48
|
-
session in the window, the list of `(kind, real_id)` citations
|
|
48
|
+
citations_by_session (Mapping[SessionIdentity, list[CitationKey]]): For
|
|
49
|
+
each user/session slice in the window, the list of `(kind, real_id)` citations
|
|
49
50
|
harvested from its interactions.
|
|
50
|
-
is_success_by_session (Mapping[
|
|
51
|
-
outcome.
|
|
51
|
+
is_success_by_session (Mapping[SessionIdentity, bool]): The evaluated
|
|
52
|
+
outcome. User/session slices not in this map are skipped on both sides.
|
|
52
53
|
rule_titles (Mapping[CitationKey, str]): Pre-loaded display titles
|
|
53
54
|
for each rule (empty string when the underlying row is gone).
|
|
54
55
|
top_n (int): How many rows to return at most. Ordering: net_sessions
|
|
@@ -65,8 +66,8 @@ def compute_net_sessions(
|
|
|
65
66
|
# Ordering preserves caller-provided iteration order; the frontend sorts
|
|
66
67
|
# the detail band by created_at when displaying.
|
|
67
68
|
sessions_by_rule: dict[CitationKey, list[str]] = {}
|
|
68
|
-
for
|
|
69
|
-
outcome = is_success_by_session.get(
|
|
69
|
+
for session_key, citations in citations_by_session.items():
|
|
70
|
+
outcome = is_success_by_session.get(session_key)
|
|
70
71
|
if outcome is None:
|
|
71
72
|
continue
|
|
72
73
|
# A rule cited multiple times in the same session counts once.
|
|
@@ -76,7 +77,7 @@ def compute_net_sessions(
|
|
|
76
77
|
successes[key] = successes.get(key, 0) + 1
|
|
77
78
|
else:
|
|
78
79
|
failures[key] = failures.get(key, 0) + 1
|
|
79
|
-
sessions_by_rule.setdefault(key, []).append(
|
|
80
|
+
sessions_by_rule.setdefault(key, []).append(session_key[1])
|
|
80
81
|
|
|
81
82
|
all_keys = set(successes) | set(failures)
|
|
82
83
|
rows = [
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
DB-free and LLM-free. Operates on SampleCandidate tuples emitted by the
|
|
4
4
|
regen worker's candidate-discovery step; returns the sampled subset.
|
|
5
5
|
|
|
6
|
-
Stratification key: (day_bucket,
|
|
7
|
-
86400-second boundaries.
|
|
8
|
-
|
|
9
|
-
for treatment / control / untagged.
|
|
6
|
+
Stratification key: (day_bucket, first_request_source). Day buckets are
|
|
7
|
+
aligned to 86400-second boundaries. The source value is sticky per session
|
|
8
|
+
and comes from the session's earliest request.
|
|
10
9
|
"""
|
|
11
10
|
|
|
12
11
|
from __future__ import annotations
|
|
@@ -15,12 +14,6 @@ import random
|
|
|
15
14
|
from collections import defaultdict
|
|
16
15
|
from collections.abc import Iterable
|
|
17
16
|
from dataclasses import dataclass
|
|
18
|
-
from typing import Any
|
|
19
|
-
|
|
20
|
-
from reflexio.server.services.evaluation_overview.group_aggregation import (
|
|
21
|
-
GroupAssignment,
|
|
22
|
-
assign_group_from_metadata,
|
|
23
|
-
)
|
|
24
17
|
|
|
25
18
|
# Day bucket width in seconds. Strata are aligned to (ts // _DAY) * _DAY.
|
|
26
19
|
_DAY = 86_400
|
|
@@ -31,8 +24,7 @@ class SampleCandidate:
|
|
|
31
24
|
"""One candidate for the regen pipeline's sampling step.
|
|
32
25
|
|
|
33
26
|
Carries everything the regen worker needs to dispatch a per-session
|
|
34
|
-
evaluation, plus the first-request
|
|
35
|
-
group for stratification.
|
|
27
|
+
evaluation, plus the first-request source used for stratification.
|
|
36
28
|
|
|
37
29
|
Attributes:
|
|
38
30
|
session_id: The session to evaluate.
|
|
@@ -41,8 +33,8 @@ class SampleCandidate:
|
|
|
41
33
|
source: Optional source tag (passed through to run_group_evaluation).
|
|
42
34
|
created_at: Unix epoch seconds of the session's most relevant
|
|
43
35
|
timestamp; used for day-bucket alignment.
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
first_request_source: Source on the session's first request, read once
|
|
37
|
+
during candidate discovery. Empty string is a real stratum.
|
|
46
38
|
"""
|
|
47
39
|
|
|
48
40
|
session_id: str
|
|
@@ -50,27 +42,26 @@ class SampleCandidate:
|
|
|
50
42
|
agent_version: str
|
|
51
43
|
source: str | None
|
|
52
44
|
created_at: int
|
|
53
|
-
|
|
45
|
+
first_request_source: str
|
|
54
46
|
|
|
55
47
|
|
|
56
|
-
def
|
|
48
|
+
def stratify_by_day_and_source(
|
|
57
49
|
candidates: Iterable[SampleCandidate],
|
|
58
|
-
) -> dict[tuple[int,
|
|
59
|
-
"""Bucket candidates by (day_bucket,
|
|
50
|
+
) -> dict[tuple[int, str], list[SampleCandidate]]:
|
|
51
|
+
"""Bucket candidates by (day_bucket, first_request_source).
|
|
60
52
|
|
|
61
53
|
Args:
|
|
62
54
|
candidates: Candidate tuples emitted by the regen candidate-discovery
|
|
63
55
|
step.
|
|
64
56
|
|
|
65
57
|
Returns:
|
|
66
|
-
Dict from (day_bucket_start,
|
|
58
|
+
Dict from (day_bucket_start, source) to the candidate list for that
|
|
67
59
|
stratum. Empty strata are absent; the dict has only populated keys.
|
|
68
60
|
"""
|
|
69
|
-
strata: dict[tuple[int,
|
|
61
|
+
strata: dict[tuple[int, str], list[SampleCandidate]] = defaultdict(list)
|
|
70
62
|
for c in candidates:
|
|
71
63
|
day_bucket = (c.created_at // _DAY) * _DAY
|
|
72
|
-
|
|
73
|
-
strata[(day_bucket, group)].append(c)
|
|
64
|
+
strata[(day_bucket, c.first_request_source)].append(c)
|
|
74
65
|
return dict(strata)
|
|
75
66
|
|
|
76
67
|
|
|
@@ -105,7 +96,7 @@ def sample_candidates(
|
|
|
105
96
|
n_per_stratum: int,
|
|
106
97
|
rng: random.Random,
|
|
107
98
|
) -> list[SampleCandidate]:
|
|
108
|
-
"""Stratify by (day x
|
|
99
|
+
"""Stratify by (day x source), then sample per stratum, then flatten.
|
|
109
100
|
|
|
110
101
|
Predictable cost across runs: at most ``n_per_stratum * num_strata``
|
|
111
102
|
items returned, regardless of traffic volume.
|
|
@@ -119,7 +110,7 @@ def sample_candidates(
|
|
|
119
110
|
Returns:
|
|
120
111
|
Flattened sampled list.
|
|
121
112
|
"""
|
|
122
|
-
strata =
|
|
113
|
+
strata = stratify_by_day_and_source(candidates)
|
|
123
114
|
sampled: list[SampleCandidate] = []
|
|
124
115
|
for stratum_candidates in strata.values():
|
|
125
116
|
sampled.extend(sample_per_stratum(stratum_candidates, n_per_stratum, rng))
|