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
package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"""Abstract user playbook CRUD + search declarations."""
|
|
2
|
+
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
|
|
5
|
+
from reflexio.models.api_schema.common import BlockingIssue
|
|
6
|
+
from reflexio.models.api_schema.domain import Status, UserPlaybook
|
|
7
|
+
from reflexio.models.api_schema.retriever_schema import SearchUserPlaybookRequest
|
|
8
|
+
from reflexio.models.config_schema import SearchOptions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UserPlaybookStoreMixin:
|
|
12
|
+
"""Abstract user playbook CRUD + search methods."""
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def save_user_playbooks(self, user_playbooks: list[UserPlaybook]) -> None:
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def get_user_playbooks(
|
|
20
|
+
self,
|
|
21
|
+
limit: int = 100,
|
|
22
|
+
user_id: str | None = None,
|
|
23
|
+
playbook_name: str | None = None,
|
|
24
|
+
agent_version: str | None = None,
|
|
25
|
+
status_filter: list[Status | None] | None = None,
|
|
26
|
+
start_time: int | None = None,
|
|
27
|
+
end_time: int | None = None,
|
|
28
|
+
include_embedding: bool = False,
|
|
29
|
+
tags: list[str] | None = None,
|
|
30
|
+
offset: int = 0,
|
|
31
|
+
user_playbook_id: int | None = None,
|
|
32
|
+
request_id: str | None = None,
|
|
33
|
+
query: str | None = None,
|
|
34
|
+
) -> list[UserPlaybook]:
|
|
35
|
+
"""Get user playbooks from storage.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
limit (int): Maximum number of playbooks to return
|
|
39
|
+
user_playbook_id (int, optional): Exact user playbook ID to retrieve.
|
|
40
|
+
user_id (str, optional): The user ID to filter by. If None, returns playbooks for all users.
|
|
41
|
+
request_id (str, optional): Request ID that generated the playbook.
|
|
42
|
+
query (str, optional): Case-insensitive text filter across visible fields.
|
|
43
|
+
playbook_name (str, optional): The playbook name to filter by. If None, returns all user playbooks.
|
|
44
|
+
agent_version (str, optional): The agent version to filter by. If None, returns all agent versions.
|
|
45
|
+
status_filter (list[Optional[Status]], optional): List of status values to filter by.
|
|
46
|
+
Can include None (current), Status.PENDING (from rerun), Status.ARCHIVED (old).
|
|
47
|
+
If None, returns playbooks with all statuses.
|
|
48
|
+
start_time (int, optional): Unix timestamp. Only return playbooks created at or after this time.
|
|
49
|
+
end_time (int, optional): Unix timestamp. Only return playbooks created at or before this time.
|
|
50
|
+
include_embedding (bool): If True, fetch and parse embedding vectors. Defaults to False.
|
|
51
|
+
tags (list[str], optional): Match playbooks having any of these tags.
|
|
52
|
+
offset (int): Number of matching rows to skip. Defaults to 0.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
list[UserPlaybook]: List of user playbook objects
|
|
56
|
+
"""
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def count_user_playbooks(
|
|
61
|
+
self,
|
|
62
|
+
user_id: str | None = None,
|
|
63
|
+
playbook_name: str | None = None,
|
|
64
|
+
min_user_playbook_id: int | None = None,
|
|
65
|
+
agent_version: str | None = None,
|
|
66
|
+
status_filter: list[Status | None] | None = None,
|
|
67
|
+
) -> int:
|
|
68
|
+
"""Count user playbooks in storage efficiently.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
user_id (str, optional): The user ID to filter by. If None, counts playbooks for all users.
|
|
72
|
+
playbook_name (str, optional): The playbook name to filter by. If None, counts all user playbooks.
|
|
73
|
+
min_user_playbook_id (int, optional): Only count playbooks with user_playbook_id greater than this value.
|
|
74
|
+
agent_version (str, optional): The agent version to filter by. If None, counts all agent versions.
|
|
75
|
+
status_filter (list[Optional[Status]], optional): List of status values to filter by.
|
|
76
|
+
Can include None (current), Status.PENDING (from rerun), Status.ARCHIVED (old).
|
|
77
|
+
If None, returns playbooks with all statuses.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
int: Count of user playbooks matching the filters
|
|
81
|
+
"""
|
|
82
|
+
raise NotImplementedError
|
|
83
|
+
|
|
84
|
+
@abstractmethod
|
|
85
|
+
def count_user_playbooks_by_session(self, session_id: str) -> int:
|
|
86
|
+
"""Count user playbooks linked to a session via request_id -> requests.session_id.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
session_id (str): The session ID to count user playbooks for
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
int: Count of user playbooks linked to the session
|
|
93
|
+
"""
|
|
94
|
+
raise NotImplementedError
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def delete_all_user_playbooks(self) -> None:
|
|
98
|
+
"""Delete all user playbooks from storage."""
|
|
99
|
+
raise NotImplementedError
|
|
100
|
+
|
|
101
|
+
@abstractmethod
|
|
102
|
+
def delete_all_user_playbooks_by_playbook_name(
|
|
103
|
+
self, playbook_name: str, agent_version: str | None = None
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Delete all user playbooks by playbook name from storage.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
playbook_name (str): The playbook name to delete
|
|
109
|
+
agent_version (str, optional): The agent version to filter by. If None, deletes all agent versions.
|
|
110
|
+
"""
|
|
111
|
+
raise NotImplementedError
|
|
112
|
+
|
|
113
|
+
@abstractmethod
|
|
114
|
+
def delete_user_playbook(self, user_playbook_id: int) -> None:
|
|
115
|
+
"""Delete a user playbook by ID.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
user_playbook_id (int): The ID of the user playbook to delete
|
|
119
|
+
"""
|
|
120
|
+
raise NotImplementedError
|
|
121
|
+
|
|
122
|
+
@abstractmethod
|
|
123
|
+
def update_all_user_playbooks_status(
|
|
124
|
+
self,
|
|
125
|
+
old_status: Status | None,
|
|
126
|
+
new_status: Status | None,
|
|
127
|
+
agent_version: str | None = None,
|
|
128
|
+
playbook_name: str | None = None,
|
|
129
|
+
) -> int:
|
|
130
|
+
"""Update all user playbooks with old_status to new_status atomically.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
old_status: The current status to match (None for CURRENT)
|
|
134
|
+
new_status: The new status to set (None for CURRENT)
|
|
135
|
+
agent_version: Optional filter by agent version
|
|
136
|
+
playbook_name: Optional filter by playbook name
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
int: Number of user playbooks updated
|
|
140
|
+
"""
|
|
141
|
+
raise NotImplementedError
|
|
142
|
+
|
|
143
|
+
@abstractmethod
|
|
144
|
+
def delete_all_user_playbooks_by_status(
|
|
145
|
+
self,
|
|
146
|
+
status: Status,
|
|
147
|
+
agent_version: str | None = None,
|
|
148
|
+
playbook_name: str | None = None,
|
|
149
|
+
) -> int:
|
|
150
|
+
"""Delete all user playbooks with the given status atomically.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
status: The status of user playbooks to delete
|
|
154
|
+
agent_version: Optional filter by agent version
|
|
155
|
+
playbook_name: Optional filter by playbook name
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
int: Number of user playbooks deleted
|
|
159
|
+
"""
|
|
160
|
+
raise NotImplementedError
|
|
161
|
+
|
|
162
|
+
@abstractmethod
|
|
163
|
+
def delete_user_playbooks_by_ids(
|
|
164
|
+
self, user_playbook_ids: list[int], *, emit_hard_delete: bool = True
|
|
165
|
+
) -> int:
|
|
166
|
+
"""Delete user playbooks by their IDs.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
user_playbook_ids: List of user_playbook_id values to delete
|
|
170
|
+
emit_hard_delete: When True (default), append a ``hard_delete``
|
|
171
|
+
lineage event per id (genuine erasure). Set False for rollback
|
|
172
|
+
cleanup of a never-live row (e.g. a lost supersede CAS), so no
|
|
173
|
+
spurious audit event is recorded.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
int: Number of user playbooks deleted
|
|
177
|
+
"""
|
|
178
|
+
raise NotImplementedError
|
|
179
|
+
|
|
180
|
+
@abstractmethod
|
|
181
|
+
def get_user_playbooks_by_ids(
|
|
182
|
+
self,
|
|
183
|
+
user_id: str,
|
|
184
|
+
user_playbook_ids: list[int],
|
|
185
|
+
status_filter: list[Status | None] | None = None,
|
|
186
|
+
) -> list[UserPlaybook]:
|
|
187
|
+
"""Fetch the subset of a user's playbooks whose ids are in the list.
|
|
188
|
+
|
|
189
|
+
Server-side filter on (``user_id``, ``user_playbook_id IN (...)``)
|
|
190
|
+
so callers (e.g. the reflection service resolving a small set of
|
|
191
|
+
cited playbook ids) avoid scanning every playbook for the user.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
user_id (str): Owning user id.
|
|
195
|
+
user_playbook_ids (list[int]): Playbook ids to fetch. Empty
|
|
196
|
+
list returns ``[]`` without hitting storage.
|
|
197
|
+
status_filter (list[Status | None] | None): Statuses to
|
|
198
|
+
include. ``None`` (default) means CURRENT only — same
|
|
199
|
+
default as ``get_user_playbooks`` for consistency.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
list[UserPlaybook]: Matching playbooks. Order is unspecified.
|
|
203
|
+
Ids that do not exist (or do not match the user / status
|
|
204
|
+
filter) are silently omitted.
|
|
205
|
+
"""
|
|
206
|
+
raise NotImplementedError
|
|
207
|
+
|
|
208
|
+
@abstractmethod
|
|
209
|
+
def get_user_playbook_by_id(
|
|
210
|
+
self, user_playbook_id: int, *, include_tombstones: bool = False
|
|
211
|
+
) -> UserPlaybook | None:
|
|
212
|
+
"""Fetch one user playbook by primary key.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
user_playbook_id: The user_playbook_id to look up.
|
|
216
|
+
include_tombstones: When False (default), MERGED/SUPERSEDED rows
|
|
217
|
+
return None. Set to True for lineage resolution (resolve_current).
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
The UserPlaybook if found and not filtered, otherwise None.
|
|
221
|
+
"""
|
|
222
|
+
raise NotImplementedError
|
|
223
|
+
|
|
224
|
+
@abstractmethod
|
|
225
|
+
def get_user_playbooks_by_ids_any_user(
|
|
226
|
+
self,
|
|
227
|
+
user_playbook_ids: list[int],
|
|
228
|
+
status_filter: list[Status | None] | None = None,
|
|
229
|
+
) -> list[UserPlaybook]:
|
|
230
|
+
"""Fetch user playbooks by ids without requiring a single owner id."""
|
|
231
|
+
raise NotImplementedError
|
|
232
|
+
|
|
233
|
+
@abstractmethod
|
|
234
|
+
def archive_user_playbook_by_id(self, user_id: str, user_playbook_id: int) -> bool:
|
|
235
|
+
"""Atomically archive a single user playbook by id, only if CURRENT.
|
|
236
|
+
|
|
237
|
+
Flips the row's ``status`` from ``None`` (CURRENT) to
|
|
238
|
+
``Status.ARCHIVED``. No-op when the playbook does not exist, has
|
|
239
|
+
a different ``user_id``, or is already non-current.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
user_id (str): Owning user id; used as a guard so callers
|
|
243
|
+
cannot accidentally archive another user's playbook.
|
|
244
|
+
user_playbook_id (int): The user_playbook_id to archive.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
bool: True if a row was archived; False otherwise.
|
|
248
|
+
"""
|
|
249
|
+
raise NotImplementedError
|
|
250
|
+
|
|
251
|
+
@abstractmethod
|
|
252
|
+
def has_user_playbooks_with_status(
|
|
253
|
+
self,
|
|
254
|
+
status: Status | None,
|
|
255
|
+
agent_version: str | None = None,
|
|
256
|
+
playbook_name: str | None = None,
|
|
257
|
+
) -> bool:
|
|
258
|
+
"""Check if any user playbooks exist with given status and filters.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
status: The status to check for (None for CURRENT)
|
|
262
|
+
agent_version: Optional filter by agent version
|
|
263
|
+
playbook_name: Optional filter by playbook name
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
bool: True if any matching user playbooks exist
|
|
267
|
+
"""
|
|
268
|
+
raise NotImplementedError
|
|
269
|
+
|
|
270
|
+
@abstractmethod
|
|
271
|
+
def update_user_playbook(
|
|
272
|
+
self,
|
|
273
|
+
user_playbook_id: int,
|
|
274
|
+
playbook_name: str | None = None,
|
|
275
|
+
content: str | None = None,
|
|
276
|
+
trigger: str | None = None,
|
|
277
|
+
rationale: str | None = None,
|
|
278
|
+
blocking_issue: BlockingIssue | None = None,
|
|
279
|
+
tags: list[str] | None = None,
|
|
280
|
+
) -> None:
|
|
281
|
+
"""Update editable fields of a user playbook. Only non-None fields are updated.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
user_playbook_id (int): The ID of the user playbook to update
|
|
285
|
+
playbook_name (str, optional): New playbook name
|
|
286
|
+
content (str, optional): New content text
|
|
287
|
+
trigger (str, optional): New trigger text
|
|
288
|
+
rationale (str, optional): New rationale text
|
|
289
|
+
blocking_issue (BlockingIssue, optional): New blocking issue
|
|
290
|
+
tags (list[str], optional): Replacement tags
|
|
291
|
+
|
|
292
|
+
Raises:
|
|
293
|
+
ValueError: If user playbook with the given ID is not found
|
|
294
|
+
"""
|
|
295
|
+
raise NotImplementedError
|
|
296
|
+
|
|
297
|
+
@abstractmethod
|
|
298
|
+
def supersede_user_playbooks_by_ids(
|
|
299
|
+
self, user_playbook_ids: list[int], request_id: str
|
|
300
|
+
) -> int:
|
|
301
|
+
"""Soft-delete user playbooks by setting status to SUPERSEDED.
|
|
302
|
+
|
|
303
|
+
Eligible rows (CURRENT, PENDING, or ARCHIVED; not already MERGED /
|
|
304
|
+
SUPERSEDED) are transitioned to SUPERSEDED and emit one status_change
|
|
305
|
+
lineage event under the shared request id. This is the user-playbook
|
|
306
|
+
analogue of the existing agent/profile soft-supersede helpers and
|
|
307
|
+
preserves dead-source content for point-in-time attribution reads.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
user_playbook_ids (list[int]): User playbook ids to supersede.
|
|
311
|
+
request_id (str): Shared request id for all emitted lineage events.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
int: Number of user playbooks actually updated.
|
|
315
|
+
"""
|
|
316
|
+
raise NotImplementedError
|
|
317
|
+
|
|
318
|
+
@abstractmethod
|
|
319
|
+
def search_user_playbooks(
|
|
320
|
+
self,
|
|
321
|
+
request: SearchUserPlaybookRequest,
|
|
322
|
+
options: SearchOptions | None = None,
|
|
323
|
+
) -> list[UserPlaybook]:
|
|
324
|
+
"""Search user playbooks with advanced filtering including semantic search.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
request (SearchUserPlaybookRequest): Search request with query, filters, and pagination
|
|
328
|
+
options (SearchOptions, optional): Engine-level search parameters (e.g. pre-computed embedding)
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
list[UserPlaybook]: List of matching user playbook objects
|
|
332
|
+
"""
|
|
333
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# tagging
|
|
2
|
+
|
|
3
|
+
Compact post-generation entity tagging capability.
|
|
4
|
+
|
|
5
|
+
- `service.py` tags profiles and playbooks with the configured tagging prompts.
|
|
6
|
+
- `tagging_scheduler.py` debounces post-publish tagging and rebuilds request context for background execution.
|
|
7
|
+
|
|
8
|
+
This package intentionally does not use `components/`: the service and scheduler are the only module responsibilities.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Post-generation entity tagging services."""
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from pydantic import ConfigDict, Field
|
|
7
|
+
|
|
8
|
+
from reflexio.models.api_schema.service_schemas import (
|
|
9
|
+
AgentPlaybook,
|
|
10
|
+
UserPlaybook,
|
|
11
|
+
UserProfile,
|
|
12
|
+
)
|
|
13
|
+
from reflexio.models.structured_output import StrictStructuredOutput
|
|
14
|
+
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
15
|
+
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
16
|
+
from reflexio.server.llm.model_defaults import ModelRole, resolve_model_name
|
|
17
|
+
from reflexio.server.services.service_utils import log_llm_messages, log_model_response
|
|
18
|
+
from reflexio.server.site_var.site_var_manager import SiteVarManager
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
TAGGING_PROMPT_ID = "tagging"
|
|
23
|
+
|
|
24
|
+
# Upper bound on how many current playbooks a single tagging pass will scan for
|
|
25
|
+
# untagged entries. Tagging is idempotent (already-tagged entities are skipped),
|
|
26
|
+
# so steady-state passes only tag newly generated entities; this bound just keeps
|
|
27
|
+
# a one-time backfill from being silently truncated at the storage default of 100.
|
|
28
|
+
_TAGGING_FETCH_LIMIT = 1000
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TagsOutput(StrictStructuredOutput):
|
|
32
|
+
tags: list[str] = Field(default_factory=list)
|
|
33
|
+
|
|
34
|
+
model_config = ConfigDict(
|
|
35
|
+
extra="allow",
|
|
36
|
+
json_schema_extra={"additionalProperties": False},
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TaggingService:
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
llm_client: LiteLLMClient,
|
|
44
|
+
request_context: RequestContext,
|
|
45
|
+
) -> None:
|
|
46
|
+
self.client = llm_client
|
|
47
|
+
self.request_context = request_context
|
|
48
|
+
self.configurator = request_context.configurator
|
|
49
|
+
self.storage = request_context.storage
|
|
50
|
+
|
|
51
|
+
model_setting = SiteVarManager().get_site_var("llm_model_setting")
|
|
52
|
+
site_var = model_setting if isinstance(model_setting, dict) else {}
|
|
53
|
+
config = self.configurator.get_config()
|
|
54
|
+
llm_config = config.llm_config if config else None
|
|
55
|
+
api_key_config = config.api_key_config if config else None
|
|
56
|
+
self.model_name = resolve_model_name(
|
|
57
|
+
ModelRole.GENERATION,
|
|
58
|
+
site_var_value=site_var.get("default_generation_model_name"),
|
|
59
|
+
config_override=llm_config.generation_model_name if llm_config else None,
|
|
60
|
+
api_key_config=api_key_config,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def run(
|
|
64
|
+
self,
|
|
65
|
+
*,
|
|
66
|
+
user_id: str,
|
|
67
|
+
agent_version: str,
|
|
68
|
+
tag_profiles: bool = True,
|
|
69
|
+
tag_playbooks: bool = True,
|
|
70
|
+
) -> None:
|
|
71
|
+
if self.storage is None:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
config = self.configurator.get_config()
|
|
75
|
+
if config is None:
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
profile_prompt = getattr(
|
|
79
|
+
config.profile_extractor_config, "tagging_definition_prompt", None
|
|
80
|
+
)
|
|
81
|
+
user_playbook_prompt = getattr(
|
|
82
|
+
config.user_playbook_extractor_config, "tagging_definition_prompt", None
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if tag_profiles and profile_prompt:
|
|
86
|
+
self._tag_profiles(
|
|
87
|
+
user_id=user_id, tagging_definition_prompt=profile_prompt
|
|
88
|
+
)
|
|
89
|
+
if tag_playbooks and user_playbook_prompt:
|
|
90
|
+
self._tag_user_playbooks(
|
|
91
|
+
user_id=user_id,
|
|
92
|
+
agent_version=agent_version,
|
|
93
|
+
tagging_definition_prompt=user_playbook_prompt,
|
|
94
|
+
)
|
|
95
|
+
self._tag_agent_playbooks(
|
|
96
|
+
agent_version=agent_version,
|
|
97
|
+
tagging_definition_prompt=user_playbook_prompt,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def _tag_profiles(self, *, user_id: str, tagging_definition_prompt: str) -> None:
|
|
101
|
+
profiles = self.storage.get_user_profile(user_id) # type: ignore[union-attr]
|
|
102
|
+
for profile in profiles:
|
|
103
|
+
if profile.tags is not None:
|
|
104
|
+
continue # already tagged (incl. empty result) — tag each entity once
|
|
105
|
+
tags = self._generate_tags(
|
|
106
|
+
tagging_definition_prompt=tagging_definition_prompt,
|
|
107
|
+
content=self._profile_content(profile),
|
|
108
|
+
)
|
|
109
|
+
self.storage.update_user_profile_tags( # type: ignore[union-attr]
|
|
110
|
+
user_id, profile.profile_id, tags
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def _tag_user_playbooks(
|
|
114
|
+
self,
|
|
115
|
+
*,
|
|
116
|
+
user_id: str,
|
|
117
|
+
agent_version: str,
|
|
118
|
+
tagging_definition_prompt: str,
|
|
119
|
+
) -> None:
|
|
120
|
+
playbooks = self.storage.get_user_playbooks( # type: ignore[union-attr]
|
|
121
|
+
limit=_TAGGING_FETCH_LIMIT,
|
|
122
|
+
user_id=user_id,
|
|
123
|
+
agent_version=agent_version,
|
|
124
|
+
status_filter=[None],
|
|
125
|
+
)
|
|
126
|
+
for playbook in playbooks:
|
|
127
|
+
if playbook.tags is not None:
|
|
128
|
+
continue # already tagged (incl. empty result) — tag each entity once
|
|
129
|
+
tags = self._generate_tags(
|
|
130
|
+
tagging_definition_prompt=tagging_definition_prompt,
|
|
131
|
+
content=self._playbook_content(playbook),
|
|
132
|
+
)
|
|
133
|
+
self.storage.update_user_playbook( # type: ignore[union-attr]
|
|
134
|
+
playbook.user_playbook_id,
|
|
135
|
+
tags=tags,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def _tag_agent_playbooks(
|
|
139
|
+
self,
|
|
140
|
+
*,
|
|
141
|
+
agent_version: str,
|
|
142
|
+
tagging_definition_prompt: str,
|
|
143
|
+
) -> None:
|
|
144
|
+
playbooks = self.storage.get_agent_playbooks( # type: ignore[union-attr]
|
|
145
|
+
limit=_TAGGING_FETCH_LIMIT,
|
|
146
|
+
agent_version=agent_version,
|
|
147
|
+
status_filter=[None],
|
|
148
|
+
)
|
|
149
|
+
for playbook in playbooks:
|
|
150
|
+
if playbook.tags is not None:
|
|
151
|
+
continue # already tagged (incl. empty result) — tag each entity once
|
|
152
|
+
tags = self._generate_tags(
|
|
153
|
+
tagging_definition_prompt=tagging_definition_prompt,
|
|
154
|
+
content=self._playbook_content(playbook),
|
|
155
|
+
)
|
|
156
|
+
self.storage.update_agent_playbook( # type: ignore[union-attr]
|
|
157
|
+
playbook.agent_playbook_id,
|
|
158
|
+
tags=tags,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def _generate_tags(
|
|
162
|
+
self, *, tagging_definition_prompt: str, content: str
|
|
163
|
+
) -> list[str]:
|
|
164
|
+
if os.getenv("MOCK_LLM_RESPONSE", "").lower() == "true":
|
|
165
|
+
return ["example_tag"]
|
|
166
|
+
|
|
167
|
+
prompt = self.request_context.prompt_manager.render_prompt(
|
|
168
|
+
TAGGING_PROMPT_ID,
|
|
169
|
+
{
|
|
170
|
+
"tagging_definition_prompt": tagging_definition_prompt.strip(),
|
|
171
|
+
"content": content,
|
|
172
|
+
},
|
|
173
|
+
)
|
|
174
|
+
messages = [{"role": "user", "content": prompt}]
|
|
175
|
+
log_llm_messages(logger, "Tagging", messages)
|
|
176
|
+
response = self.client.generate_chat_response(
|
|
177
|
+
messages=messages,
|
|
178
|
+
model=self.model_name,
|
|
179
|
+
response_format=TagsOutput,
|
|
180
|
+
)
|
|
181
|
+
log_model_response(logger, "Tagging response", response)
|
|
182
|
+
if not isinstance(response, TagsOutput):
|
|
183
|
+
logger.warning(
|
|
184
|
+
"Unexpected response type from tagging LLM: %s", type(response)
|
|
185
|
+
)
|
|
186
|
+
return []
|
|
187
|
+
return [tag.strip() for tag in response.tags if tag.strip()]
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def _profile_content(profile: UserProfile) -> str:
|
|
191
|
+
return profile.content
|
|
192
|
+
|
|
193
|
+
@staticmethod
|
|
194
|
+
def _playbook_content(playbook: UserPlaybook | AgentPlaybook) -> str:
|
|
195
|
+
parts = [playbook.content]
|
|
196
|
+
if playbook.trigger:
|
|
197
|
+
parts.append(f"Trigger: {playbook.trigger}")
|
|
198
|
+
if playbook.rationale:
|
|
199
|
+
parts.append(f"Rationale: {playbook.rationale}")
|
|
200
|
+
return "\n".join(part for part in parts if part)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Singleton scheduler for deferred, off-publish-path entity tagging.
|
|
2
|
+
|
|
3
|
+
Tagging runs an LLM call per newly generated profile/playbook, so it must not
|
|
4
|
+
block the publish request. This scheduler mirrors
|
|
5
|
+
:class:`GroupEvaluationScheduler`: a single daemon thread with a min-heap, where
|
|
6
|
+
each publish upserts the fire time for its ``(org_id, user_id, agent_version)``
|
|
7
|
+
key. Rapid successive publishes for the same key debounce into a single tagging
|
|
8
|
+
pass; when the timer fires, the tagging callback runs on its own daemon thread.
|
|
9
|
+
|
|
10
|
+
Tagging is idempotent (already-tagged entities are skipped), so a deferred pass
|
|
11
|
+
naturally handles both newly generated entities and the one-time backfill that
|
|
12
|
+
happens when a tagging definition is first configured.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import heapq
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
import threading
|
|
21
|
+
import time
|
|
22
|
+
from collections.abc import Callable
|
|
23
|
+
|
|
24
|
+
from reflexio.server.api_endpoints.request_context import RequestContext
|
|
25
|
+
from reflexio.server.llm.litellm_client import LiteLLMClient
|
|
26
|
+
from reflexio.server.services.tagging.service import TaggingService
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
# Delay before a tagging pass fires after the last publish for a key. Long enough
|
|
31
|
+
# to debounce a burst of publishes into one pass, short enough that tags appear
|
|
32
|
+
# promptly. Kept as a patch point for tests.
|
|
33
|
+
TAGGING_DELAY_SECONDS = 15
|
|
34
|
+
IS_TEST_ENV = os.environ.get("IS_TEST_ENV", "false").strip().lower() == "true"
|
|
35
|
+
_EFFECTIVE_DELAY_SECONDS = 1 if IS_TEST_ENV else TAGGING_DELAY_SECONDS
|
|
36
|
+
|
|
37
|
+
# (org_id, user_id, agent_version)
|
|
38
|
+
TaggingKey = tuple[str, str, str]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TaggingScheduler:
|
|
42
|
+
"""Singleton scheduler that fires entity tagging after a short debounce."""
|
|
43
|
+
|
|
44
|
+
_instance = None
|
|
45
|
+
_lock = threading.Lock()
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def get_instance(cls) -> TaggingScheduler:
|
|
49
|
+
if cls._instance is None:
|
|
50
|
+
with cls._lock:
|
|
51
|
+
if cls._instance is None:
|
|
52
|
+
cls._instance = cls()
|
|
53
|
+
return cls._instance
|
|
54
|
+
|
|
55
|
+
def __init__(self) -> None:
|
|
56
|
+
self._scheduled: dict[TaggingKey, tuple[float, Callable]] = {}
|
|
57
|
+
self._heap: list[tuple[float, TaggingKey]] = []
|
|
58
|
+
self._mutex = threading.Lock()
|
|
59
|
+
self._wake_event = threading.Event()
|
|
60
|
+
self._thread = threading.Thread(
|
|
61
|
+
target=self._scheduler_loop, daemon=True, name="tagging-scheduler"
|
|
62
|
+
)
|
|
63
|
+
self._thread.start()
|
|
64
|
+
logger.info("TaggingScheduler started")
|
|
65
|
+
|
|
66
|
+
def schedule(self, key: TaggingKey, callback: Callable) -> None:
|
|
67
|
+
"""Schedule or reschedule a tagging pass for ``key`` (slides the fire time forward)."""
|
|
68
|
+
fire_time = time.monotonic() + _EFFECTIVE_DELAY_SECONDS
|
|
69
|
+
with self._mutex:
|
|
70
|
+
self._scheduled[key] = (fire_time, callback)
|
|
71
|
+
heapq.heappush(self._heap, (fire_time, key))
|
|
72
|
+
self._wake_event.set()
|
|
73
|
+
|
|
74
|
+
def _scheduler_loop(self) -> None:
|
|
75
|
+
while True:
|
|
76
|
+
try:
|
|
77
|
+
with self._mutex:
|
|
78
|
+
next_fire_time = self._heap[0][0] if self._heap else None
|
|
79
|
+
|
|
80
|
+
if next_fire_time is None:
|
|
81
|
+
self._wake_event.wait()
|
|
82
|
+
self._wake_event.clear()
|
|
83
|
+
continue
|
|
84
|
+
|
|
85
|
+
wait_seconds = next_fire_time - time.monotonic()
|
|
86
|
+
if wait_seconds > 0:
|
|
87
|
+
self._wake_event.wait(timeout=wait_seconds)
|
|
88
|
+
self._wake_event.clear()
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
with self._mutex:
|
|
92
|
+
while self._heap and self._heap[0][0] <= time.monotonic():
|
|
93
|
+
fire_time, key = heapq.heappop(self._heap)
|
|
94
|
+
|
|
95
|
+
current = self._scheduled.get(key)
|
|
96
|
+
if current is None:
|
|
97
|
+
continue
|
|
98
|
+
current_fire_time, callback = current
|
|
99
|
+
if abs(current_fire_time - fire_time) > 0.001:
|
|
100
|
+
# Superseded by a newer schedule for the same key.
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
del self._scheduled[key]
|
|
104
|
+
t = threading.Thread(
|
|
105
|
+
target=self._run_callback,
|
|
106
|
+
args=(key, callback),
|
|
107
|
+
daemon=True,
|
|
108
|
+
name=f"tagging-{key[1][:20]}",
|
|
109
|
+
)
|
|
110
|
+
t.start()
|
|
111
|
+
except Exception:
|
|
112
|
+
logger.exception("Error in tagging scheduler loop")
|
|
113
|
+
time.sleep(1)
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def _run_callback(key: TaggingKey, callback: Callable) -> None:
|
|
117
|
+
try:
|
|
118
|
+
logger.info("Firing tagging for key=%s", key)
|
|
119
|
+
callback()
|
|
120
|
+
logger.info("Completed tagging for key=%s", key)
|
|
121
|
+
except Exception:
|
|
122
|
+
logger.exception("Tagging callback failed for key=%s", key)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def schedule_tagging(
|
|
126
|
+
*,
|
|
127
|
+
org_id: str,
|
|
128
|
+
user_id: str,
|
|
129
|
+
agent_version: str,
|
|
130
|
+
request_context: RequestContext,
|
|
131
|
+
llm_client: LiteLLMClient,
|
|
132
|
+
) -> None:
|
|
133
|
+
"""Enqueue a deferred tagging pass for the given user/agent off the publish path."""
|
|
134
|
+
if not user_id:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
key: TaggingKey = (org_id, user_id, agent_version)
|
|
138
|
+
storage_base_dir = getattr(request_context, "storage_base_dir", None)
|
|
139
|
+
|
|
140
|
+
def callback() -> None:
|
|
141
|
+
fresh_context = RequestContext(
|
|
142
|
+
org_id=org_id,
|
|
143
|
+
storage_base_dir=storage_base_dir,
|
|
144
|
+
)
|
|
145
|
+
TaggingService(llm_client=llm_client, request_context=fresh_context).run(
|
|
146
|
+
user_id=user_id, agent_version=agent_version
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
TaggingScheduler.get_instance().schedule(key, callback)
|