Files
LangBot/src/langbot/pkg/agent/runner/host_models.py
T

245 lines
7.6 KiB
Python

"""Agent event envelope and binding models for LangBot Host.
These are Host-internal models, not exposed to SDK.
"""
from __future__ import annotations
import typing
import pydantic
from langbot_plugin.api.entities.builtin.runner.event import (
ActorContext,
SubjectContext,
RawEventRef,
)
from langbot_plugin.api.entities.builtin.runner.input import AgentInput
from langbot_plugin.api.entities.builtin.runner.delivery import DeliveryContext
class LegacyRunnerIdentity(pydantic.BaseModel):
"""Host-captured native Query identity; never populated from event data/params."""
workspace_id: str | None = None
bot_id: str | None = None
pipeline_id: str | None = None
query_launcher_type: str | None = None
query_launcher_id: str | None = None
session_launcher_type: str | None = None
session_launcher_id: str | None = None
class AgentEventEnvelope(pydantic.BaseModel):
"""Event envelope for LangBot Host event gateway.
This is the unified input model that replaces Query-first approach.
IM / WebUI / API / EventRouter all produce this envelope.
"""
event_id: str
"""Unique event identifier."""
event_type: str
"""Event type (message.received, message.recalled, etc.)."""
event_time: int | None = None
"""Event timestamp (epoch seconds)."""
source: str
"""Event source (platform, webui, api, scheduler, system)."""
source_event_type: str | None = None
"""Original source event type, when available."""
bot_id: str | None = None
"""Bot UUID handling this event."""
workspace_id: str | None = None
"""Workspace ID (for multi-tenant)."""
conversation_id: str | None = None
"""Conversation ID."""
thread_id: str | None = None
"""Thread ID (for platforms supporting threads)."""
actor: ActorContext | None = None
"""Actor (who triggered the event)."""
subject: SubjectContext | None = None
"""Subject (what the event is about)."""
input: AgentInput
"""Event input."""
delivery: DeliveryContext
"""Delivery context."""
raw_ref: RawEventRef | None = None
"""Reference to raw event payload."""
data: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
"""Small structured event payload. Large payloads should be referenced via raw_ref."""
legacy_identity: LegacyRunnerIdentity | None = None
"""Host-only provenance, separate from untrusted event payload and adapter params."""
# Binding scope types
class BindingScope(pydantic.BaseModel):
"""Scope for agent binding."""
scope_type: typing.Literal['agent', 'bot', 'workspace', 'global'] = 'agent'
"""Scope type."""
scope_id: str | None = None
"""Scope identifier (agent_id, bot_uuid, etc.)."""
class ResourcePolicy(pydantic.BaseModel):
"""Resource policy for agent binding.
Controls what resources the runner can access.
"""
allowed_model_uuids: list[str] | None = None
"""Additional model UUID grants. None means no additional model grants."""
allowed_tool_names: list[str] | None = None
"""Additional tool name grants. None means no additional tool grants."""
allowed_tool_sources: dict[str, dict[str, str | None]] | None = None
"""Host-resolved implementation identity for each allowed tool name."""
allowed_platform_tool_names: list[str] = pydantic.Field(default_factory=list)
"""Platform and event action tools explicitly granted by the Agent owner."""
allow_all_tools: bool = False
"""Whether all tools visible to the current Host scope are granted."""
allowed_kb_uuids: list[str] | None = None
"""Additional knowledge base UUID grants. None means no additional KB grants."""
allowed_skill_names: list[str] | None = None
"""Allowed skill names. None means all currently visible skills are allowed."""
allow_plugin_storage: bool = True
"""Whether plugin storage is allowed."""
allow_workspace_storage: bool = False
"""Whether workspace storage is allowed."""
class StatePolicy(pydantic.BaseModel):
"""State policy for agent binding.
Controls state management behavior.
"""
enable_state: bool = True
"""Whether host-owned state is enabled."""
state_scopes: list[typing.Literal['conversation', 'actor', 'subject', 'runner']] = pydantic.Field(
default_factory=lambda: ['conversation', 'actor']
)
"""Enabled state scopes."""
class DeliveryPolicy(pydantic.BaseModel):
"""Delivery policy for agent binding.
Controls how results are delivered.
"""
enable_streaming: bool = True
"""Whether streaming output is enabled."""
enable_reply: bool = True
"""Whether reply is enabled."""
enable_interactions: bool = False
"""Whether the binding permits structured interaction delivery."""
max_message_size: int | None = None
"""Maximum message size."""
class AgentConfig(pydantic.BaseModel):
"""Host-side Agent configuration.
Product-level Agents are independent from Pipelines. A Pipeline entry path
can project its config into this runtime-only model without creating or
updating a persisted Agent.
"""
agent_id: str | None = None
"""Host-side Agent/config identifier."""
processor_type: typing.Literal['agent', 'pipeline', 'event_processor'] = 'agent'
"""Product processor kind represented by this runtime config."""
processor_id: str | None = None
"""Stable product processor identifier."""
runner_id: str
"""Runner ID to invoke."""
runner_config: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
"""Agent/runner binding configuration."""
resource_policy: ResourcePolicy = pydantic.Field(default_factory=ResourcePolicy)
"""Resource policy for this Agent."""
state_policy: StatePolicy = pydantic.Field(default_factory=StatePolicy)
"""State policy for this Agent."""
delivery_policy: DeliveryPolicy = pydantic.Field(default_factory=DeliveryPolicy)
"""Delivery policy for this Agent."""
event_types: list[str] = pydantic.Field(default_factory=lambda: ['message.received'])
"""Event types this Agent handles."""
metadata: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
"""Non-protocol diagnostic metadata, such as legacy config source."""
class AgentBinding(pydantic.BaseModel):
"""Binding configuration for mapping events to runners.
This is a Host-internal, runtime-only model for event-to-runner binding.
Projecting Pipeline config into it is not a persistence migration.
"""
binding_id: str
"""Unique binding identifier."""
scope: BindingScope = pydantic.Field(default_factory=BindingScope)
"""Binding scope."""
event_types: list[str] = pydantic.Field(default_factory=lambda: ['message.received'])
"""Event types this binding handles."""
runner_id: str
"""Runner ID to invoke."""
runner_config: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
"""Current Agent/runner configuration."""
resource_policy: ResourcePolicy = pydantic.Field(default_factory=ResourcePolicy)
"""Resource policy."""
state_policy: StatePolicy = pydantic.Field(default_factory=StatePolicy)
"""State policy."""
delivery_policy: DeliveryPolicy = pydantic.Field(default_factory=DeliveryPolicy)
"""Delivery policy."""
agent_id: str | None = None
"""Host-side Agent/config identifier for this binding."""
processor_type: typing.Literal['agent', 'pipeline', 'event_processor'] = 'agent'
"""Product processor kind selected for this binding."""
processor_id: str | None = None
"""Stable product processor identifier used for callback resume."""