mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-12 08:46:02 +00:00
refactor(agent-runner): simplify event-first entry path
This commit is contained in:
@@ -1,44 +1,25 @@
|
||||
"""Configuration migration for agent runner IDs."""
|
||||
"""Helpers for the current AgentRunner config shape."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing
|
||||
|
||||
from .id import is_plugin_runner_id
|
||||
|
||||
|
||||
# Mapping from old built-in runner names to official plugin runner IDs
|
||||
OLD_RUNNER_TO_PLUGIN_RUNNER_ID = {
|
||||
'local-agent': 'plugin:langbot/local-agent/default',
|
||||
'dify-service-api': 'plugin:langbot/dify-agent/default',
|
||||
'n8n-service-api': 'plugin:langbot/n8n-agent/default',
|
||||
'coze-api': 'plugin:langbot/coze-agent/default',
|
||||
'dashscope-app-api': 'plugin:langbot/dashscope-agent/default',
|
||||
'langflow-api': 'plugin:langbot/langflow-agent/default',
|
||||
'tbox-app-api': 'plugin:langbot/tbox-agent/default',
|
||||
}
|
||||
|
||||
|
||||
class ConfigMigration:
|
||||
"""Configuration migration helper for agent runner IDs.
|
||||
"""Configuration helper for agent runner IDs.
|
||||
|
||||
Responsibilities:
|
||||
- Resolve runner ID from new ai.runner.id or old ai.runner.runner
|
||||
- Map old built-in runner names to official plugin runner IDs
|
||||
- Resolve runner ID from ai.runner.id
|
||||
- Extract current Agent/runner config from ai.runner_config
|
||||
- Migrate old ai.<runner-name> blocks into ai.runner_config
|
||||
- Keep the current config container shape stable on save
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def resolve_runner_id(pipeline_config: dict[str, typing.Any]) -> str | None:
|
||||
"""Resolve runner ID from pipeline configuration.
|
||||
|
||||
Priority:
|
||||
1. New format: ai.runner.id (must be plugin:* format)
|
||||
2. Old format: ai.runner.runner (mapped to plugin:* if built-in)
|
||||
"""Resolve runner ID from current configuration.
|
||||
|
||||
Args:
|
||||
pipeline_config: Pipeline configuration dict
|
||||
pipeline_config: Current configuration container
|
||||
|
||||
Returns:
|
||||
Runner ID string, or None if not configured
|
||||
@@ -46,26 +27,9 @@ class ConfigMigration:
|
||||
ai_config = pipeline_config.get('ai', {})
|
||||
runner_config = ai_config.get('runner', {})
|
||||
|
||||
# Check new format first
|
||||
runner_id = runner_config.get('id')
|
||||
if runner_id:
|
||||
if is_plugin_runner_id(runner_id):
|
||||
return runner_id
|
||||
# If it's not a plugin ID, try to map it as old runner name
|
||||
return OLD_RUNNER_TO_PLUGIN_RUNNER_ID.get(runner_id, runner_id)
|
||||
|
||||
# Check old format
|
||||
old_runner_name = runner_config.get('runner')
|
||||
if old_runner_name:
|
||||
# If already plugin:* format, return directly
|
||||
if is_plugin_runner_id(old_runner_name):
|
||||
return old_runner_name
|
||||
# Map old built-in runner to official plugin ID
|
||||
mapped_id = OLD_RUNNER_TO_PLUGIN_RUNNER_ID.get(old_runner_name)
|
||||
if mapped_id:
|
||||
return mapped_id
|
||||
# Return old name if no mapping exists (will error in registry)
|
||||
return old_runner_name
|
||||
return runner_id
|
||||
|
||||
return None
|
||||
|
||||
@@ -74,14 +38,10 @@ class ConfigMigration:
|
||||
pipeline_config: dict[str, typing.Any],
|
||||
runner_id: str,
|
||||
) -> dict[str, typing.Any]:
|
||||
"""Resolve Agent/runner configuration from pipeline configuration.
|
||||
|
||||
Runtime code should only read the migrated format. Legacy
|
||||
ai.<runner-name> blocks are handled by migration helpers, not by the
|
||||
hot path.
|
||||
"""Resolve Agent/runner configuration from the current container.
|
||||
|
||||
Args:
|
||||
pipeline_config: Pipeline configuration dict
|
||||
pipeline_config: Current configuration container
|
||||
runner_id: Resolved runner ID
|
||||
|
||||
Returns:
|
||||
@@ -89,79 +49,18 @@ class ConfigMigration:
|
||||
"""
|
||||
ai_config = pipeline_config.get('ai', {})
|
||||
|
||||
# Check new format
|
||||
runner_configs = ai_config.get('runner_config', {})
|
||||
if runner_id in runner_configs:
|
||||
return runner_configs[runner_id]
|
||||
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def resolve_legacy_runner_config(
|
||||
pipeline_config: dict[str, typing.Any],
|
||||
runner_id: str,
|
||||
) -> dict[str, typing.Any]:
|
||||
"""Resolve old ai.<runner-name> config for migration only."""
|
||||
ai_config = pipeline_config.get('ai', {})
|
||||
|
||||
# Try to find old runner name from runner_id
|
||||
old_runner_name = None
|
||||
for old_name, mapped_id in OLD_RUNNER_TO_PLUGIN_RUNNER_ID.items():
|
||||
if mapped_id == runner_id:
|
||||
old_runner_name = old_name
|
||||
break
|
||||
|
||||
if old_runner_name:
|
||||
old_config = ai_config.get(old_runner_name, {})
|
||||
if old_config:
|
||||
return ConfigMigration.normalize_runner_config_for_migration(runner_id, old_config)
|
||||
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def normalize_runner_config_for_migration(
|
||||
runner_id: str,
|
||||
runner_config: dict[str, typing.Any],
|
||||
) -> dict[str, typing.Any]:
|
||||
"""Normalize released legacy runner config before storing Agent/runner config.
|
||||
|
||||
Runtime code should not carry aliases. This helper is intentionally used
|
||||
only by config migration so AgentRunner implementations can consume the
|
||||
current manifest-defined field names.
|
||||
"""
|
||||
normalized = dict(runner_config)
|
||||
|
||||
if runner_id == OLD_RUNNER_TO_PLUGIN_RUNNER_ID['local-agent']:
|
||||
legacy_kb = normalized.pop('knowledge-base', None)
|
||||
if 'knowledge-bases' not in normalized:
|
||||
if isinstance(legacy_kb, str) and legacy_kb and legacy_kb not in {'__none__', '__none'}:
|
||||
normalized['knowledge-bases'] = [legacy_kb]
|
||||
elif legacy_kb is not None:
|
||||
normalized['knowledge-bases'] = []
|
||||
|
||||
return normalized
|
||||
|
||||
@staticmethod
|
||||
def get_old_runner_name(runner_id: str) -> str | None:
|
||||
"""Get old runner name from mapped runner ID.
|
||||
|
||||
Args:
|
||||
runner_id: Plugin runner ID
|
||||
|
||||
Returns:
|
||||
Old runner name if mapped, None otherwise
|
||||
"""
|
||||
for old_name, mapped_id in OLD_RUNNER_TO_PLUGIN_RUNNER_ID.items():
|
||||
if mapped_id == runner_id:
|
||||
return old_name
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_expire_time(pipeline_config: dict[str, typing.Any]) -> int:
|
||||
"""Get conversation expire time from configuration.
|
||||
|
||||
Args:
|
||||
pipeline_config: Pipeline configuration dict
|
||||
pipeline_config: Current configuration container
|
||||
|
||||
Returns:
|
||||
Expire time in seconds (0 means no expiry)
|
||||
@@ -172,54 +71,23 @@ class ConfigMigration:
|
||||
|
||||
@staticmethod
|
||||
def migrate_pipeline_config(pipeline_config: dict[str, typing.Any]) -> dict[str, typing.Any]:
|
||||
"""Migrate pipeline config to new format.
|
||||
|
||||
This converts old ai.runner.runner and ai.<runner-name> to
|
||||
new ai.runner.id and ai.runner_config format.
|
||||
"""Normalize the current config container before saving.
|
||||
|
||||
Args:
|
||||
pipeline_config: Original pipeline configuration
|
||||
pipeline_config: Original configuration
|
||||
|
||||
Returns:
|
||||
Migrated pipeline configuration
|
||||
Configuration with explicit ai.runner and ai.runner_config containers
|
||||
"""
|
||||
# Create copy
|
||||
new_config = dict(pipeline_config)
|
||||
ai_config = new_config.get('ai', {})
|
||||
if not ai_config:
|
||||
if 'ai' not in new_config:
|
||||
return new_config
|
||||
|
||||
runner_config = ai_config.get('runner', {})
|
||||
runner_configs = ai_config.get('runner_config', {})
|
||||
ai_config = dict(new_config.get('ai', {}))
|
||||
|
||||
# Resolve runner ID
|
||||
runner_id = ConfigMigration.resolve_runner_id(pipeline_config)
|
||||
if runner_id:
|
||||
# Set new format
|
||||
runner_config['id'] = runner_id
|
||||
# Remove old runner field if present
|
||||
if 'runner' in runner_config and is_plugin_runner_id(runner_config['runner']):
|
||||
# Already migrated plugin:* format, keep as id
|
||||
pass
|
||||
elif 'runner' in runner_config:
|
||||
# Old built-in runner name, remove after migration
|
||||
old_name = runner_config['runner']
|
||||
if old_name in OLD_RUNNER_TO_PLUGIN_RUNNER_ID:
|
||||
del runner_config['runner']
|
||||
runner_config = dict(ai_config.get('runner', {}))
|
||||
runner_configs = dict(ai_config.get('runner_config', {}))
|
||||
|
||||
# Migrate runner config
|
||||
resolved_config = ConfigMigration.resolve_runner_config(pipeline_config, runner_id)
|
||||
if not resolved_config:
|
||||
resolved_config = ConfigMigration.resolve_legacy_runner_config(pipeline_config, runner_id)
|
||||
if resolved_config:
|
||||
resolved_config = ConfigMigration.normalize_runner_config_for_migration(runner_id, resolved_config)
|
||||
runner_configs[runner_id] = resolved_config
|
||||
# Remove old runner config block
|
||||
for old_name, mapped_id in OLD_RUNNER_TO_PLUGIN_RUNNER_ID.items():
|
||||
if mapped_id == runner_id and old_name in ai_config:
|
||||
del ai_config[old_name]
|
||||
|
||||
# Update configs
|
||||
ai_config['runner'] = runner_config
|
||||
ai_config['runner_config'] = runner_configs
|
||||
new_config['ai'] = ai_config
|
||||
|
||||
Reference in New Issue
Block a user