attune-ai 2.0.0__py3-none-any.whl
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.
- attune/__init__.py +358 -0
- attune/adaptive/__init__.py +13 -0
- attune/adaptive/task_complexity.py +127 -0
- attune/agent_monitoring.py +414 -0
- attune/cache/__init__.py +117 -0
- attune/cache/base.py +166 -0
- attune/cache/dependency_manager.py +256 -0
- attune/cache/hash_only.py +251 -0
- attune/cache/hybrid.py +457 -0
- attune/cache/storage.py +285 -0
- attune/cache_monitor.py +356 -0
- attune/cache_stats.py +298 -0
- attune/cli/__init__.py +152 -0
- attune/cli/__main__.py +12 -0
- attune/cli/commands/__init__.py +1 -0
- attune/cli/commands/batch.py +264 -0
- attune/cli/commands/cache.py +248 -0
- attune/cli/commands/help.py +331 -0
- attune/cli/commands/info.py +140 -0
- attune/cli/commands/inspect.py +436 -0
- attune/cli/commands/inspection.py +57 -0
- attune/cli/commands/memory.py +48 -0
- attune/cli/commands/metrics.py +92 -0
- attune/cli/commands/orchestrate.py +184 -0
- attune/cli/commands/patterns.py +207 -0
- attune/cli/commands/profiling.py +202 -0
- attune/cli/commands/provider.py +98 -0
- attune/cli/commands/routing.py +285 -0
- attune/cli/commands/setup.py +96 -0
- attune/cli/commands/status.py +235 -0
- attune/cli/commands/sync.py +166 -0
- attune/cli/commands/tier.py +121 -0
- attune/cli/commands/utilities.py +114 -0
- attune/cli/commands/workflow.py +579 -0
- attune/cli/core.py +32 -0
- attune/cli/parsers/__init__.py +68 -0
- attune/cli/parsers/batch.py +118 -0
- attune/cli/parsers/cache.py +65 -0
- attune/cli/parsers/help.py +41 -0
- attune/cli/parsers/info.py +26 -0
- attune/cli/parsers/inspect.py +66 -0
- attune/cli/parsers/metrics.py +42 -0
- attune/cli/parsers/orchestrate.py +61 -0
- attune/cli/parsers/patterns.py +54 -0
- attune/cli/parsers/provider.py +40 -0
- attune/cli/parsers/routing.py +110 -0
- attune/cli/parsers/setup.py +42 -0
- attune/cli/parsers/status.py +47 -0
- attune/cli/parsers/sync.py +31 -0
- attune/cli/parsers/tier.py +33 -0
- attune/cli/parsers/workflow.py +77 -0
- attune/cli/utils/__init__.py +1 -0
- attune/cli/utils/data.py +242 -0
- attune/cli/utils/helpers.py +68 -0
- attune/cli_legacy.py +3957 -0
- attune/cli_minimal.py +1159 -0
- attune/cli_router.py +437 -0
- attune/cli_unified.py +814 -0
- attune/config/__init__.py +66 -0
- attune/config/xml_config.py +286 -0
- attune/config.py +545 -0
- attune/coordination.py +870 -0
- attune/core.py +1511 -0
- attune/core_modules/__init__.py +15 -0
- attune/cost_tracker.py +626 -0
- attune/dashboard/__init__.py +41 -0
- attune/dashboard/app.py +512 -0
- attune/dashboard/simple_server.py +435 -0
- attune/dashboard/standalone_server.py +547 -0
- attune/discovery.py +306 -0
- attune/emergence.py +306 -0
- attune/exceptions.py +123 -0
- attune/feedback_loops.py +373 -0
- attune/hot_reload/README.md +473 -0
- attune/hot_reload/__init__.py +62 -0
- attune/hot_reload/config.py +83 -0
- attune/hot_reload/integration.py +229 -0
- attune/hot_reload/reloader.py +298 -0
- attune/hot_reload/watcher.py +183 -0
- attune/hot_reload/websocket.py +177 -0
- attune/levels.py +577 -0
- attune/leverage_points.py +441 -0
- attune/logging_config.py +261 -0
- attune/mcp/__init__.py +10 -0
- attune/mcp/server.py +506 -0
- attune/memory/__init__.py +237 -0
- attune/memory/claude_memory.py +469 -0
- attune/memory/config.py +224 -0
- attune/memory/control_panel.py +1290 -0
- attune/memory/control_panel_support.py +145 -0
- attune/memory/cross_session.py +845 -0
- attune/memory/edges.py +179 -0
- attune/memory/encryption.py +159 -0
- attune/memory/file_session.py +770 -0
- attune/memory/graph.py +570 -0
- attune/memory/long_term.py +913 -0
- attune/memory/long_term_types.py +99 -0
- attune/memory/mixins/__init__.py +25 -0
- attune/memory/mixins/backend_init_mixin.py +249 -0
- attune/memory/mixins/capabilities_mixin.py +208 -0
- attune/memory/mixins/handoff_mixin.py +208 -0
- attune/memory/mixins/lifecycle_mixin.py +49 -0
- attune/memory/mixins/long_term_mixin.py +352 -0
- attune/memory/mixins/promotion_mixin.py +109 -0
- attune/memory/mixins/short_term_mixin.py +182 -0
- attune/memory/nodes.py +179 -0
- attune/memory/redis_bootstrap.py +540 -0
- attune/memory/security/__init__.py +31 -0
- attune/memory/security/audit_logger.py +932 -0
- attune/memory/security/pii_scrubber.py +640 -0
- attune/memory/security/secrets_detector.py +678 -0
- attune/memory/short_term.py +2192 -0
- attune/memory/simple_storage.py +302 -0
- attune/memory/storage/__init__.py +15 -0
- attune/memory/storage_backend.py +167 -0
- attune/memory/summary_index.py +583 -0
- attune/memory/types.py +446 -0
- attune/memory/unified.py +182 -0
- attune/meta_workflows/__init__.py +74 -0
- attune/meta_workflows/agent_creator.py +248 -0
- attune/meta_workflows/builtin_templates.py +567 -0
- attune/meta_workflows/cli_commands/__init__.py +56 -0
- attune/meta_workflows/cli_commands/agent_commands.py +321 -0
- attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
- attune/meta_workflows/cli_commands/config_commands.py +232 -0
- attune/meta_workflows/cli_commands/memory_commands.py +182 -0
- attune/meta_workflows/cli_commands/template_commands.py +354 -0
- attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
- attune/meta_workflows/cli_meta_workflows.py +59 -0
- attune/meta_workflows/form_engine.py +292 -0
- attune/meta_workflows/intent_detector.py +409 -0
- attune/meta_workflows/models.py +569 -0
- attune/meta_workflows/pattern_learner.py +738 -0
- attune/meta_workflows/plan_generator.py +384 -0
- attune/meta_workflows/session_context.py +397 -0
- attune/meta_workflows/template_registry.py +229 -0
- attune/meta_workflows/workflow.py +984 -0
- attune/metrics/__init__.py +12 -0
- attune/metrics/collector.py +31 -0
- attune/metrics/prompt_metrics.py +194 -0
- attune/models/__init__.py +172 -0
- attune/models/__main__.py +13 -0
- attune/models/adaptive_routing.py +437 -0
- attune/models/auth_cli.py +444 -0
- attune/models/auth_strategy.py +450 -0
- attune/models/cli.py +655 -0
- attune/models/empathy_executor.py +354 -0
- attune/models/executor.py +257 -0
- attune/models/fallback.py +762 -0
- attune/models/provider_config.py +282 -0
- attune/models/registry.py +472 -0
- attune/models/tasks.py +359 -0
- attune/models/telemetry/__init__.py +71 -0
- attune/models/telemetry/analytics.py +594 -0
- attune/models/telemetry/backend.py +196 -0
- attune/models/telemetry/data_models.py +431 -0
- attune/models/telemetry/storage.py +489 -0
- attune/models/token_estimator.py +420 -0
- attune/models/validation.py +280 -0
- attune/monitoring/__init__.py +52 -0
- attune/monitoring/alerts.py +946 -0
- attune/monitoring/alerts_cli.py +448 -0
- attune/monitoring/multi_backend.py +271 -0
- attune/monitoring/otel_backend.py +362 -0
- attune/optimization/__init__.py +19 -0
- attune/optimization/context_optimizer.py +272 -0
- attune/orchestration/__init__.py +67 -0
- attune/orchestration/agent_templates.py +707 -0
- attune/orchestration/config_store.py +499 -0
- attune/orchestration/execution_strategies.py +2111 -0
- attune/orchestration/meta_orchestrator.py +1168 -0
- attune/orchestration/pattern_learner.py +696 -0
- attune/orchestration/real_tools.py +931 -0
- attune/pattern_cache.py +187 -0
- attune/pattern_library.py +542 -0
- attune/patterns/debugging/all_patterns.json +81 -0
- attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
- attune/patterns/refactoring_memory.json +89 -0
- attune/persistence.py +564 -0
- attune/platform_utils.py +265 -0
- attune/plugins/__init__.py +28 -0
- attune/plugins/base.py +361 -0
- attune/plugins/registry.py +268 -0
- attune/project_index/__init__.py +32 -0
- attune/project_index/cli.py +335 -0
- attune/project_index/index.py +667 -0
- attune/project_index/models.py +504 -0
- attune/project_index/reports.py +474 -0
- attune/project_index/scanner.py +777 -0
- attune/project_index/scanner_parallel.py +291 -0
- attune/prompts/__init__.py +61 -0
- attune/prompts/config.py +77 -0
- attune/prompts/context.py +177 -0
- attune/prompts/parser.py +285 -0
- attune/prompts/registry.py +313 -0
- attune/prompts/templates.py +208 -0
- attune/redis_config.py +302 -0
- attune/redis_memory.py +799 -0
- attune/resilience/__init__.py +56 -0
- attune/resilience/circuit_breaker.py +256 -0
- attune/resilience/fallback.py +179 -0
- attune/resilience/health.py +300 -0
- attune/resilience/retry.py +209 -0
- attune/resilience/timeout.py +135 -0
- attune/routing/__init__.py +43 -0
- attune/routing/chain_executor.py +433 -0
- attune/routing/classifier.py +217 -0
- attune/routing/smart_router.py +234 -0
- attune/routing/workflow_registry.py +343 -0
- attune/scaffolding/README.md +589 -0
- attune/scaffolding/__init__.py +35 -0
- attune/scaffolding/__main__.py +14 -0
- attune/scaffolding/cli.py +240 -0
- attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
- attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
- attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
- attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
- attune/socratic/__init__.py +256 -0
- attune/socratic/ab_testing.py +958 -0
- attune/socratic/blueprint.py +533 -0
- attune/socratic/cli.py +703 -0
- attune/socratic/collaboration.py +1114 -0
- attune/socratic/domain_templates.py +924 -0
- attune/socratic/embeddings.py +738 -0
- attune/socratic/engine.py +794 -0
- attune/socratic/explainer.py +682 -0
- attune/socratic/feedback.py +772 -0
- attune/socratic/forms.py +629 -0
- attune/socratic/generator.py +732 -0
- attune/socratic/llm_analyzer.py +637 -0
- attune/socratic/mcp_server.py +702 -0
- attune/socratic/session.py +312 -0
- attune/socratic/storage.py +667 -0
- attune/socratic/success.py +730 -0
- attune/socratic/visual_editor.py +860 -0
- attune/socratic/web_ui.py +958 -0
- attune/telemetry/__init__.py +39 -0
- attune/telemetry/agent_coordination.py +475 -0
- attune/telemetry/agent_tracking.py +367 -0
- attune/telemetry/approval_gates.py +545 -0
- attune/telemetry/cli.py +1231 -0
- attune/telemetry/commands/__init__.py +14 -0
- attune/telemetry/commands/dashboard_commands.py +696 -0
- attune/telemetry/event_streaming.py +409 -0
- attune/telemetry/feedback_loop.py +567 -0
- attune/telemetry/usage_tracker.py +591 -0
- attune/templates.py +754 -0
- attune/test_generator/__init__.py +38 -0
- attune/test_generator/__main__.py +14 -0
- attune/test_generator/cli.py +234 -0
- attune/test_generator/generator.py +355 -0
- attune/test_generator/risk_analyzer.py +216 -0
- attune/test_generator/templates/unit_test.py.jinja2 +272 -0
- attune/tier_recommender.py +384 -0
- attune/tools.py +183 -0
- attune/trust/__init__.py +28 -0
- attune/trust/circuit_breaker.py +579 -0
- attune/trust_building.py +527 -0
- attune/validation/__init__.py +19 -0
- attune/validation/xml_validator.py +281 -0
- attune/vscode_bridge.py +173 -0
- attune/workflow_commands.py +780 -0
- attune/workflow_patterns/__init__.py +33 -0
- attune/workflow_patterns/behavior.py +249 -0
- attune/workflow_patterns/core.py +76 -0
- attune/workflow_patterns/output.py +99 -0
- attune/workflow_patterns/registry.py +255 -0
- attune/workflow_patterns/structural.py +288 -0
- attune/workflows/__init__.py +539 -0
- attune/workflows/autonomous_test_gen.py +1268 -0
- attune/workflows/base.py +2667 -0
- attune/workflows/batch_processing.py +342 -0
- attune/workflows/bug_predict.py +1084 -0
- attune/workflows/builder.py +273 -0
- attune/workflows/caching.py +253 -0
- attune/workflows/code_review.py +1048 -0
- attune/workflows/code_review_adapters.py +312 -0
- attune/workflows/code_review_pipeline.py +722 -0
- attune/workflows/config.py +645 -0
- attune/workflows/dependency_check.py +644 -0
- attune/workflows/document_gen/__init__.py +25 -0
- attune/workflows/document_gen/config.py +30 -0
- attune/workflows/document_gen/report_formatter.py +162 -0
- attune/workflows/document_gen/workflow.py +1426 -0
- attune/workflows/document_manager.py +216 -0
- attune/workflows/document_manager_README.md +134 -0
- attune/workflows/documentation_orchestrator.py +1205 -0
- attune/workflows/history.py +510 -0
- attune/workflows/keyboard_shortcuts/__init__.py +39 -0
- attune/workflows/keyboard_shortcuts/generators.py +391 -0
- attune/workflows/keyboard_shortcuts/parsers.py +416 -0
- attune/workflows/keyboard_shortcuts/prompts.py +295 -0
- attune/workflows/keyboard_shortcuts/schema.py +193 -0
- attune/workflows/keyboard_shortcuts/workflow.py +509 -0
- attune/workflows/llm_base.py +363 -0
- attune/workflows/manage_docs.py +87 -0
- attune/workflows/manage_docs_README.md +134 -0
- attune/workflows/manage_documentation.py +821 -0
- attune/workflows/new_sample_workflow1.py +149 -0
- attune/workflows/new_sample_workflow1_README.md +150 -0
- attune/workflows/orchestrated_health_check.py +849 -0
- attune/workflows/orchestrated_release_prep.py +600 -0
- attune/workflows/output.py +413 -0
- attune/workflows/perf_audit.py +863 -0
- attune/workflows/pr_review.py +762 -0
- attune/workflows/progress.py +785 -0
- attune/workflows/progress_server.py +322 -0
- attune/workflows/progressive/README 2.md +454 -0
- attune/workflows/progressive/README.md +454 -0
- attune/workflows/progressive/__init__.py +82 -0
- attune/workflows/progressive/cli.py +219 -0
- attune/workflows/progressive/core.py +488 -0
- attune/workflows/progressive/orchestrator.py +723 -0
- attune/workflows/progressive/reports.py +520 -0
- attune/workflows/progressive/telemetry.py +274 -0
- attune/workflows/progressive/test_gen.py +495 -0
- attune/workflows/progressive/workflow.py +589 -0
- attune/workflows/refactor_plan.py +694 -0
- attune/workflows/release_prep.py +895 -0
- attune/workflows/release_prep_crew.py +969 -0
- attune/workflows/research_synthesis.py +404 -0
- attune/workflows/routing.py +168 -0
- attune/workflows/secure_release.py +593 -0
- attune/workflows/security_adapters.py +297 -0
- attune/workflows/security_audit.py +1329 -0
- attune/workflows/security_audit_phase3.py +355 -0
- attune/workflows/seo_optimization.py +633 -0
- attune/workflows/step_config.py +234 -0
- attune/workflows/telemetry_mixin.py +269 -0
- attune/workflows/test5.py +125 -0
- attune/workflows/test5_README.md +158 -0
- attune/workflows/test_coverage_boost_crew.py +849 -0
- attune/workflows/test_gen/__init__.py +52 -0
- attune/workflows/test_gen/ast_analyzer.py +249 -0
- attune/workflows/test_gen/config.py +88 -0
- attune/workflows/test_gen/data_models.py +38 -0
- attune/workflows/test_gen/report_formatter.py +289 -0
- attune/workflows/test_gen/test_templates.py +381 -0
- attune/workflows/test_gen/workflow.py +655 -0
- attune/workflows/test_gen.py +54 -0
- attune/workflows/test_gen_behavioral.py +477 -0
- attune/workflows/test_gen_parallel.py +341 -0
- attune/workflows/test_lifecycle.py +526 -0
- attune/workflows/test_maintenance.py +627 -0
- attune/workflows/test_maintenance_cli.py +590 -0
- attune/workflows/test_maintenance_crew.py +840 -0
- attune/workflows/test_runner.py +622 -0
- attune/workflows/tier_tracking.py +531 -0
- attune/workflows/xml_enhanced_crew.py +285 -0
- attune_ai-2.0.0.dist-info/METADATA +1026 -0
- attune_ai-2.0.0.dist-info/RECORD +457 -0
- attune_ai-2.0.0.dist-info/WHEEL +5 -0
- attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
- attune_ai-2.0.0.dist-info/top_level.txt +5 -0
- attune_healthcare/__init__.py +13 -0
- attune_healthcare/monitors/__init__.py +9 -0
- attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
- attune_healthcare/monitors/monitoring/__init__.py +44 -0
- attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
- attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
- attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
- attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
- attune_llm/README.md +553 -0
- attune_llm/__init__.py +28 -0
- attune_llm/agent_factory/__init__.py +53 -0
- attune_llm/agent_factory/adapters/__init__.py +85 -0
- attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
- attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
- attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
- attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
- attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
- attune_llm/agent_factory/adapters/native.py +228 -0
- attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
- attune_llm/agent_factory/base.py +305 -0
- attune_llm/agent_factory/crews/__init__.py +67 -0
- attune_llm/agent_factory/crews/code_review.py +1113 -0
- attune_llm/agent_factory/crews/health_check.py +1262 -0
- attune_llm/agent_factory/crews/refactoring.py +1128 -0
- attune_llm/agent_factory/crews/security_audit.py +1018 -0
- attune_llm/agent_factory/decorators.py +287 -0
- attune_llm/agent_factory/factory.py +558 -0
- attune_llm/agent_factory/framework.py +193 -0
- attune_llm/agent_factory/memory_integration.py +328 -0
- attune_llm/agent_factory/resilient.py +320 -0
- attune_llm/agents_md/__init__.py +22 -0
- attune_llm/agents_md/loader.py +218 -0
- attune_llm/agents_md/parser.py +271 -0
- attune_llm/agents_md/registry.py +307 -0
- attune_llm/claude_memory.py +466 -0
- attune_llm/cli/__init__.py +8 -0
- attune_llm/cli/sync_claude.py +487 -0
- attune_llm/code_health.py +1313 -0
- attune_llm/commands/__init__.py +51 -0
- attune_llm/commands/context.py +375 -0
- attune_llm/commands/loader.py +301 -0
- attune_llm/commands/models.py +231 -0
- attune_llm/commands/parser.py +371 -0
- attune_llm/commands/registry.py +429 -0
- attune_llm/config/__init__.py +29 -0
- attune_llm/config/unified.py +291 -0
- attune_llm/context/__init__.py +22 -0
- attune_llm/context/compaction.py +455 -0
- attune_llm/context/manager.py +434 -0
- attune_llm/contextual_patterns.py +361 -0
- attune_llm/core.py +907 -0
- attune_llm/git_pattern_extractor.py +435 -0
- attune_llm/hooks/__init__.py +24 -0
- attune_llm/hooks/config.py +306 -0
- attune_llm/hooks/executor.py +289 -0
- attune_llm/hooks/registry.py +302 -0
- attune_llm/hooks/scripts/__init__.py +39 -0
- attune_llm/hooks/scripts/evaluate_session.py +201 -0
- attune_llm/hooks/scripts/first_time_init.py +285 -0
- attune_llm/hooks/scripts/pre_compact.py +207 -0
- attune_llm/hooks/scripts/session_end.py +183 -0
- attune_llm/hooks/scripts/session_start.py +163 -0
- attune_llm/hooks/scripts/suggest_compact.py +225 -0
- attune_llm/learning/__init__.py +30 -0
- attune_llm/learning/evaluator.py +438 -0
- attune_llm/learning/extractor.py +514 -0
- attune_llm/learning/storage.py +560 -0
- attune_llm/levels.py +227 -0
- attune_llm/pattern_confidence.py +414 -0
- attune_llm/pattern_resolver.py +272 -0
- attune_llm/pattern_summary.py +350 -0
- attune_llm/providers.py +967 -0
- attune_llm/routing/__init__.py +32 -0
- attune_llm/routing/model_router.py +362 -0
- attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
- attune_llm/security/PHASE2_COMPLETE.md +384 -0
- attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- attune_llm/security/QUICK_REFERENCE.md +316 -0
- attune_llm/security/README.md +262 -0
- attune_llm/security/__init__.py +62 -0
- attune_llm/security/audit_logger.py +929 -0
- attune_llm/security/audit_logger_example.py +152 -0
- attune_llm/security/pii_scrubber.py +640 -0
- attune_llm/security/secrets_detector.py +678 -0
- attune_llm/security/secrets_detector_example.py +304 -0
- attune_llm/security/secure_memdocs.py +1192 -0
- attune_llm/security/secure_memdocs_example.py +278 -0
- attune_llm/session_status.py +745 -0
- attune_llm/state.py +246 -0
- attune_llm/utils/__init__.py +5 -0
- attune_llm/utils/tokens.py +349 -0
- attune_software/SOFTWARE_PLUGIN_README.md +57 -0
- attune_software/__init__.py +13 -0
- attune_software/cli/__init__.py +120 -0
- attune_software/cli/inspect.py +362 -0
- attune_software/cli.py +574 -0
- attune_software/plugin.py +188 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Hook Registry
|
|
2
|
+
|
|
3
|
+
Central registry for managing and dispatching hooks by event type.
|
|
4
|
+
|
|
5
|
+
Copyright 2025 Smart-AI-Memory
|
|
6
|
+
Licensed under Fair Source License 0.9
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from attune_llm.hooks.config import (
|
|
14
|
+
HookConfig,
|
|
15
|
+
HookDefinition,
|
|
16
|
+
HookEvent,
|
|
17
|
+
HookMatcher,
|
|
18
|
+
HookRule,
|
|
19
|
+
HookType,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class HookRegistry:
|
|
26
|
+
"""Central registry for hook management and dispatch.
|
|
27
|
+
|
|
28
|
+
The registry handles:
|
|
29
|
+
- Loading hook configuration
|
|
30
|
+
- Matching events to hooks
|
|
31
|
+
- Dispatching hooks to the executor
|
|
32
|
+
- Tracking hook execution results
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
registry = HookRegistry()
|
|
36
|
+
registry.load_config(config)
|
|
37
|
+
|
|
38
|
+
# Register a Python function hook
|
|
39
|
+
registry.register(
|
|
40
|
+
event=HookEvent.SESSION_START,
|
|
41
|
+
handler=my_session_start_handler,
|
|
42
|
+
description="Initialize session state"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Fire hooks for an event
|
|
46
|
+
results = await registry.fire(
|
|
47
|
+
HookEvent.SESSION_START,
|
|
48
|
+
context={"session_id": "abc123"}
|
|
49
|
+
)
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, config: HookConfig | None = None):
|
|
53
|
+
"""Initialize the hook registry.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
config: Optional hook configuration to load
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
self.config = config or HookConfig()
|
|
60
|
+
self._python_handlers: dict[str, Callable] = {}
|
|
61
|
+
self._execution_log: list[dict[str, Any]] = []
|
|
62
|
+
|
|
63
|
+
def load_config(self, config: HookConfig) -> None:
|
|
64
|
+
"""Load or replace hook configuration.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
config: New hook configuration
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
self.config = config
|
|
71
|
+
logger.info("Loaded hook configuration with %d event types", len(config.hooks))
|
|
72
|
+
|
|
73
|
+
def register(
|
|
74
|
+
self,
|
|
75
|
+
event: HookEvent,
|
|
76
|
+
handler: Callable[..., Any],
|
|
77
|
+
description: str = "",
|
|
78
|
+
matcher: HookMatcher | None = None,
|
|
79
|
+
priority: int = 0,
|
|
80
|
+
) -> str:
|
|
81
|
+
"""Register a Python function as a hook handler.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
event: Event type to hook
|
|
85
|
+
handler: Python callable to execute
|
|
86
|
+
description: Human-readable description
|
|
87
|
+
matcher: Optional matcher for conditional execution
|
|
88
|
+
priority: Execution priority (higher = earlier)
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Handler ID for later reference
|
|
92
|
+
|
|
93
|
+
"""
|
|
94
|
+
# Generate unique handler ID
|
|
95
|
+
handler_id = f"{event.value}_{handler.__name__}_{id(handler)}"
|
|
96
|
+
self._python_handlers[handler_id] = handler
|
|
97
|
+
|
|
98
|
+
# Create hook definition pointing to the handler
|
|
99
|
+
hook_def = HookDefinition(
|
|
100
|
+
type=HookType.PYTHON,
|
|
101
|
+
command=handler_id,
|
|
102
|
+
description=description,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
self.config.add_hook(
|
|
106
|
+
event=event,
|
|
107
|
+
hook=hook_def,
|
|
108
|
+
matcher=matcher,
|
|
109
|
+
priority=priority,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
logger.debug("Registered hook '%s' for event %s", handler_id, event.value)
|
|
113
|
+
return handler_id
|
|
114
|
+
|
|
115
|
+
def unregister(self, handler_id: str) -> bool:
|
|
116
|
+
"""Unregister a hook handler by ID.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
handler_id: Handler ID returned from register()
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
True if handler was found and removed
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
if handler_id in self._python_handlers:
|
|
126
|
+
del self._python_handlers[handler_id]
|
|
127
|
+
# Remove from config rules
|
|
128
|
+
for event_rules in self.config.hooks.values():
|
|
129
|
+
for rule in event_rules:
|
|
130
|
+
rule.hooks = [h for h in rule.hooks if h.command != handler_id]
|
|
131
|
+
logger.debug("Unregistered hook '%s'", handler_id)
|
|
132
|
+
return True
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
def get_matching_hooks(
|
|
136
|
+
self,
|
|
137
|
+
event: HookEvent,
|
|
138
|
+
context: dict[str, Any],
|
|
139
|
+
) -> list[tuple[HookRule, HookDefinition]]:
|
|
140
|
+
"""Get all hooks that match the given event and context.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
event: Event type
|
|
144
|
+
context: Event context for matching
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
List of (rule, hook) tuples that match
|
|
148
|
+
|
|
149
|
+
"""
|
|
150
|
+
if not self.config.enabled:
|
|
151
|
+
return []
|
|
152
|
+
|
|
153
|
+
matching = []
|
|
154
|
+
for rule in self.config.get_hooks_for_event(event):
|
|
155
|
+
if rule.matcher.matches(context):
|
|
156
|
+
for hook in rule.hooks:
|
|
157
|
+
matching.append((rule, hook))
|
|
158
|
+
|
|
159
|
+
return matching
|
|
160
|
+
|
|
161
|
+
async def fire(
|
|
162
|
+
self,
|
|
163
|
+
event: HookEvent,
|
|
164
|
+
context: dict[str, Any] | None = None,
|
|
165
|
+
) -> list[dict[str, Any]]:
|
|
166
|
+
"""Fire all matching hooks for an event.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
event: Event type to fire
|
|
170
|
+
context: Event context for matching and execution
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
List of execution results
|
|
174
|
+
|
|
175
|
+
"""
|
|
176
|
+
from attune_llm.hooks.executor import HookExecutor
|
|
177
|
+
|
|
178
|
+
context = context or {}
|
|
179
|
+
matching_hooks = self.get_matching_hooks(event, context)
|
|
180
|
+
|
|
181
|
+
if not matching_hooks:
|
|
182
|
+
logger.debug("No hooks matched for event %s", event.value)
|
|
183
|
+
return []
|
|
184
|
+
|
|
185
|
+
logger.info(
|
|
186
|
+
"Firing %d hook(s) for event %s",
|
|
187
|
+
len(matching_hooks),
|
|
188
|
+
event.value,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
executor = HookExecutor(python_handlers=self._python_handlers)
|
|
192
|
+
results = []
|
|
193
|
+
|
|
194
|
+
for _rule, hook in matching_hooks:
|
|
195
|
+
try:
|
|
196
|
+
result = await executor.execute(hook, context)
|
|
197
|
+
execution_record = {
|
|
198
|
+
"event": event.value,
|
|
199
|
+
"hook": hook.command,
|
|
200
|
+
"description": hook.description,
|
|
201
|
+
"success": result.get("success", False),
|
|
202
|
+
"output": result.get("output"),
|
|
203
|
+
"error": result.get("error"),
|
|
204
|
+
"duration_ms": result.get("duration_ms"),
|
|
205
|
+
}
|
|
206
|
+
results.append(execution_record)
|
|
207
|
+
|
|
208
|
+
if self.config.log_executions:
|
|
209
|
+
self._execution_log.append(execution_record)
|
|
210
|
+
|
|
211
|
+
except Exception as e:
|
|
212
|
+
error_record = {
|
|
213
|
+
"event": event.value,
|
|
214
|
+
"hook": hook.command,
|
|
215
|
+
"success": False,
|
|
216
|
+
"error": str(e),
|
|
217
|
+
}
|
|
218
|
+
results.append(error_record)
|
|
219
|
+
logger.error("Hook execution failed: %s - %s", hook.command, e)
|
|
220
|
+
|
|
221
|
+
if hook.on_error == "raise":
|
|
222
|
+
raise
|
|
223
|
+
|
|
224
|
+
return results
|
|
225
|
+
|
|
226
|
+
def fire_sync(
|
|
227
|
+
self,
|
|
228
|
+
event: HookEvent,
|
|
229
|
+
context: dict[str, Any] | None = None,
|
|
230
|
+
) -> list[dict[str, Any]]:
|
|
231
|
+
"""Synchronous version of fire().
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
event: Event type to fire
|
|
235
|
+
context: Event context
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
List of execution results
|
|
239
|
+
|
|
240
|
+
"""
|
|
241
|
+
import asyncio
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
loop = asyncio.get_running_loop()
|
|
245
|
+
# If we're in an async context, use run_coroutine_threadsafe
|
|
246
|
+
|
|
247
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
248
|
+
self.fire(event, context),
|
|
249
|
+
loop,
|
|
250
|
+
)
|
|
251
|
+
return future.result(timeout=self.config.default_timeout)
|
|
252
|
+
except RuntimeError:
|
|
253
|
+
# No running loop, create one
|
|
254
|
+
return asyncio.run(self.fire(event, context))
|
|
255
|
+
|
|
256
|
+
def get_execution_log(
|
|
257
|
+
self,
|
|
258
|
+
limit: int = 100,
|
|
259
|
+
event_filter: HookEvent | None = None,
|
|
260
|
+
) -> list[dict[str, Any]]:
|
|
261
|
+
"""Get recent hook execution log entries.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
limit: Maximum entries to return
|
|
265
|
+
event_filter: Optional event type filter
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
List of execution records
|
|
269
|
+
|
|
270
|
+
"""
|
|
271
|
+
log = self._execution_log
|
|
272
|
+
if event_filter:
|
|
273
|
+
log = [e for e in log if e.get("event") == event_filter.value]
|
|
274
|
+
return log[-limit:]
|
|
275
|
+
|
|
276
|
+
def clear_execution_log(self) -> None:
|
|
277
|
+
"""Clear the execution log."""
|
|
278
|
+
self._execution_log.clear()
|
|
279
|
+
|
|
280
|
+
def get_stats(self) -> dict[str, Any]:
|
|
281
|
+
"""Get hook registry statistics.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Dictionary with stats
|
|
285
|
+
|
|
286
|
+
"""
|
|
287
|
+
total_hooks = sum(
|
|
288
|
+
sum(len(rule.hooks) for rule in rules) for rules in self.config.hooks.values()
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
executions = len(self._execution_log)
|
|
292
|
+
successes = sum(1 for e in self._execution_log if e.get("success"))
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
"enabled": self.config.enabled,
|
|
296
|
+
"total_hooks": total_hooks,
|
|
297
|
+
"event_types": len([v for v in self.config.hooks.values() if v]),
|
|
298
|
+
"python_handlers": len(self._python_handlers),
|
|
299
|
+
"total_executions": executions,
|
|
300
|
+
"successful_executions": successes,
|
|
301
|
+
"success_rate": (successes / executions * 100) if executions else 0,
|
|
302
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Hook Scripts
|
|
2
|
+
|
|
3
|
+
Pre-built hook scripts for common Empathy Framework events.
|
|
4
|
+
|
|
5
|
+
Architectural patterns inspired by everything-claude-code by Affaan Mustafa.
|
|
6
|
+
See: https://github.com/affaan-m/everything-claude-code (MIT License)
|
|
7
|
+
See: ACKNOWLEDGMENTS.md for full attribution.
|
|
8
|
+
|
|
9
|
+
Copyright 2025 Smart-AI-Memory
|
|
10
|
+
Licensed under Fair Source License 0.9
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from attune_llm.hooks.scripts.evaluate_session import (
|
|
14
|
+
apply_learned_patterns,
|
|
15
|
+
get_learning_summary,
|
|
16
|
+
run_evaluate_session,
|
|
17
|
+
)
|
|
18
|
+
from attune_llm.hooks.scripts.first_time_init import (
|
|
19
|
+
check_init,
|
|
20
|
+
handle_init_response,
|
|
21
|
+
initialize_project,
|
|
22
|
+
)
|
|
23
|
+
from attune_llm.hooks.scripts.pre_compact import run_pre_compact
|
|
24
|
+
from attune_llm.hooks.scripts.session_end import main as session_end
|
|
25
|
+
from attune_llm.hooks.scripts.session_start import main as session_start
|
|
26
|
+
from attune_llm.hooks.scripts.suggest_compact import main as suggest_compact
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"session_start",
|
|
30
|
+
"session_end",
|
|
31
|
+
"suggest_compact",
|
|
32
|
+
"run_pre_compact",
|
|
33
|
+
"run_evaluate_session",
|
|
34
|
+
"get_learning_summary",
|
|
35
|
+
"apply_learned_patterns",
|
|
36
|
+
"check_init",
|
|
37
|
+
"handle_init_response",
|
|
38
|
+
"initialize_project",
|
|
39
|
+
]
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Evaluate Session Hook Script
|
|
2
|
+
|
|
3
|
+
Evaluates sessions at end for learning potential and extracts patterns.
|
|
4
|
+
Called during SessionEnd hook to enable continuous learning.
|
|
5
|
+
|
|
6
|
+
Architectural patterns inspired by everything-claude-code by Affaan Mustafa.
|
|
7
|
+
See: https://github.com/affaan-m/everything-claude-code (MIT License)
|
|
8
|
+
See: ACKNOWLEDGMENTS.md for full attribution.
|
|
9
|
+
|
|
10
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
11
|
+
Licensed under Fair Source 0.9
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def run_evaluate_session(context: dict[str, Any]) -> dict[str, Any]:
|
|
23
|
+
"""Evaluate a session for learning potential.
|
|
24
|
+
|
|
25
|
+
This hook is called at session end to:
|
|
26
|
+
1. Evaluate if the session has learning value
|
|
27
|
+
2. Extract patterns if valuable
|
|
28
|
+
3. Store patterns for future use
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
context: Hook context containing:
|
|
32
|
+
- collaboration_state: CollaborationState
|
|
33
|
+
- user_id: User identifier
|
|
34
|
+
- session_id: Session identifier
|
|
35
|
+
- storage_dir: Optional storage directory
|
|
36
|
+
- min_score: Optional minimum score for extraction
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Dict with:
|
|
40
|
+
- evaluated: Whether evaluation completed
|
|
41
|
+
- quality: Session quality rating
|
|
42
|
+
- score: Numeric score (0.0-1.0)
|
|
43
|
+
- patterns_extracted: Number of patterns extracted
|
|
44
|
+
- patterns_stored: Number of patterns stored
|
|
45
|
+
- learnable_topics: List of identified topics
|
|
46
|
+
- reasoning: Human-readable evaluation reasoning
|
|
47
|
+
- error: Error message if failed
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
collaboration_state = context.get("collaboration_state")
|
|
51
|
+
user_id = context.get("user_id")
|
|
52
|
+
session_id = context.get("session_id", "")
|
|
53
|
+
storage_dir = context.get("storage_dir", ".attune/learned_skills")
|
|
54
|
+
min_score = context.get("min_score", 0.4)
|
|
55
|
+
|
|
56
|
+
if not collaboration_state:
|
|
57
|
+
return {
|
|
58
|
+
"evaluated": False,
|
|
59
|
+
"error": "No collaboration state provided",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if not user_id:
|
|
63
|
+
user_id = collaboration_state.user_id
|
|
64
|
+
|
|
65
|
+
# Import learning components
|
|
66
|
+
from attune_llm.learning import (
|
|
67
|
+
LearnedSkillsStorage,
|
|
68
|
+
PatternExtractor,
|
|
69
|
+
SessionEvaluator,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Evaluate the session
|
|
73
|
+
evaluator = SessionEvaluator(min_score_for_extraction=min_score)
|
|
74
|
+
evaluation = evaluator.evaluate(collaboration_state)
|
|
75
|
+
|
|
76
|
+
result = {
|
|
77
|
+
"evaluated": True,
|
|
78
|
+
"quality": evaluation.quality.value,
|
|
79
|
+
"score": evaluation.score,
|
|
80
|
+
"learnable_topics": evaluation.learnable_topics,
|
|
81
|
+
"reasoning": evaluation.reasoning,
|
|
82
|
+
"patterns_extracted": 0,
|
|
83
|
+
"patterns_stored": 0,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Extract patterns if recommended
|
|
87
|
+
if evaluation.recommended_extraction:
|
|
88
|
+
extractor = PatternExtractor()
|
|
89
|
+
patterns = extractor.extract_patterns(collaboration_state, session_id)
|
|
90
|
+
|
|
91
|
+
result["patterns_extracted"] = len(patterns)
|
|
92
|
+
|
|
93
|
+
if patterns:
|
|
94
|
+
# Store patterns
|
|
95
|
+
storage = LearnedSkillsStorage(storage_dir=storage_dir)
|
|
96
|
+
stored_ids = storage.save_patterns(user_id, patterns)
|
|
97
|
+
result["patterns_stored"] = len(stored_ids)
|
|
98
|
+
|
|
99
|
+
# Include pattern summaries
|
|
100
|
+
result["pattern_summaries"] = [
|
|
101
|
+
{
|
|
102
|
+
"id": p.pattern_id,
|
|
103
|
+
"category": p.category.value,
|
|
104
|
+
"trigger": p.trigger[:50],
|
|
105
|
+
"confidence": p.confidence,
|
|
106
|
+
}
|
|
107
|
+
for p in patterns[:5] # Top 5
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
logger.info(
|
|
111
|
+
f"Extracted {len(patterns)} patterns, stored {len(stored_ids)} "
|
|
112
|
+
f"for user {user_id}"
|
|
113
|
+
)
|
|
114
|
+
else:
|
|
115
|
+
logger.debug(f"Session not recommended for extraction (score: {evaluation.score:.2f})")
|
|
116
|
+
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.exception(f"Session evaluation failed: {e}")
|
|
121
|
+
return {
|
|
122
|
+
"evaluated": False,
|
|
123
|
+
"error": str(e),
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_learning_summary(context: dict[str, Any]) -> dict[str, Any]:
|
|
128
|
+
"""Get learning summary for a user.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
context: Context with user_id and optional storage_dir
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Learning summary dictionary
|
|
135
|
+
"""
|
|
136
|
+
try:
|
|
137
|
+
user_id = context.get("user_id")
|
|
138
|
+
storage_dir = context.get("storage_dir", ".attune/learned_skills")
|
|
139
|
+
|
|
140
|
+
if not user_id:
|
|
141
|
+
return {"error": "No user_id provided"}
|
|
142
|
+
|
|
143
|
+
from attune_llm.learning import LearnedSkillsStorage
|
|
144
|
+
|
|
145
|
+
storage = LearnedSkillsStorage(storage_dir=storage_dir)
|
|
146
|
+
return storage.get_summary(user_id)
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.exception(f"Failed to get learning summary: {e}")
|
|
150
|
+
return {"error": str(e)}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def apply_learned_patterns(context: dict[str, Any]) -> str:
|
|
154
|
+
"""Generate context injection from learned patterns.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
context: Context with user_id, max_patterns, and optional filters
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Formatted markdown for context injection
|
|
161
|
+
"""
|
|
162
|
+
try:
|
|
163
|
+
user_id = context.get("user_id")
|
|
164
|
+
max_patterns = context.get("max_patterns", 5)
|
|
165
|
+
storage_dir = context.get("storage_dir", ".attune/learned_skills")
|
|
166
|
+
|
|
167
|
+
if not user_id:
|
|
168
|
+
return ""
|
|
169
|
+
|
|
170
|
+
from attune_llm.learning import LearnedSkillsStorage, PatternCategory
|
|
171
|
+
|
|
172
|
+
# Parse category filter if provided
|
|
173
|
+
categories = None
|
|
174
|
+
if cat_filter := context.get("categories"):
|
|
175
|
+
categories = [PatternCategory(c) for c in cat_filter]
|
|
176
|
+
|
|
177
|
+
storage = LearnedSkillsStorage(storage_dir=storage_dir)
|
|
178
|
+
return storage.format_patterns_for_context(
|
|
179
|
+
user_id,
|
|
180
|
+
max_patterns=max_patterns,
|
|
181
|
+
categories=categories,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
except Exception as e:
|
|
185
|
+
logger.exception(f"Failed to apply learned patterns: {e}")
|
|
186
|
+
return ""
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# Entry point for hook execution
|
|
190
|
+
if __name__ == "__main__":
|
|
191
|
+
print("Evaluate Session Hook Script")
|
|
192
|
+
print("This script is called at session end to evaluate learning potential")
|
|
193
|
+
print()
|
|
194
|
+
print("Required context keys:")
|
|
195
|
+
print(" - collaboration_state: CollaborationState object")
|
|
196
|
+
print(" - user_id: User identifier (optional, uses state.user_id)")
|
|
197
|
+
print()
|
|
198
|
+
print("Optional context keys:")
|
|
199
|
+
print(" - session_id: Session identifier")
|
|
200
|
+
print(" - storage_dir: Storage directory path")
|
|
201
|
+
print(" - min_score: Minimum score for extraction (default: 0.4)")
|