tiphys.bootstrap

Application bootstrap and context factory.

This module is the Composition Root - the single place where the entire application object graph is assembled.

  1"""
  2Application bootstrap and context factory.
  3
  4This module is the Composition Root - the single place where
  5the entire application object graph is assembled.
  6"""
  7
  8from __future__ import annotations
  9
 10from pathlib import Path
 11from typing import TYPE_CHECKING, Any
 12
 13from tiphys.config import TiphysConfig, load_config
 14from tiphys.context import AppContext, set_context
 15
 16if TYPE_CHECKING:
 17    from tiphys.hooks.manager import HookManager
 18    from tiphys.plugins.registry import PluginRegistry
 19    from tiphys.routing.registry import AgentRegistry
 20    from tiphys.routing.resolver import RouteResolver
 21    from tiphys.security.policy import PolicyEngine
 22    from tiphys.server.bus import EventBus
 23    from tiphys.tools.base import ToolRegistry
 24
 25
 26async def create_app_context(
 27    config: TiphysConfig | None = None,
 28    config_path: Path | None = None,
 29    *,
 30    # Optional overrides for testing
 31    event_bus: EventBus | None = None,
 32    hook_manager: HookManager | None = None,
 33    tool_registry: ToolRegistry | None = None,
 34    agent_registry: AgentRegistry | None = None,
 35    plugin_registry: PluginRegistry | None = None,
 36    route_resolver: RouteResolver | None = None,
 37    policy_engine: PolicyEngine | None = None,
 38    register_tools: bool = True,
 39    run_startup: bool = True,
 40    set_as_current: bool = True,
 41) -> AppContext:
 42    """
 43    Create and initialize the application context.
 44
 45    This is the main factory function for bootstrapping the application.
 46    It creates all services, wires dependencies, and runs initialization.
 47
 48    Args:
 49        config: Optional pre-loaded config. Loaded from environment if not provided.
 50        config_path: Optional path to config file.
 51        event_bus: Optional EventBus instance (for testing).
 52        hook_manager: Optional HookManager instance (for testing).
 53        tool_registry: Optional ToolRegistry instance (for testing).
 54        agent_registry: Optional AgentRegistry instance (for testing).
 55        plugin_registry: Optional PluginRegistry instance (for testing).
 56        route_resolver: Optional RouteResolver instance (for testing).
 57        policy_engine: Optional PolicyEngine instance (for testing).
 58        register_tools: Whether to register built-in tools. Defaults to True.
 59        run_startup: Whether to run startup hooks. Defaults to True.
 60        set_as_current: Whether to set as current context. Defaults to True.
 61
 62    Returns:
 63        Fully initialized AppContext.
 64
 65    Example:
 66        # Standard usage
 67        ctx = await create_app_context()
 68
 69        # With custom config
 70        ctx = await create_app_context(config=my_config)
 71
 72        # For testing with mocks
 73        ctx = await create_app_context(
 74            config=test_config,
 75            event_bus=mock_bus,
 76            run_startup=False,
 77            set_as_current=False,
 78        )
 79    """
 80    # Load config if not provided
 81    if config is None:
 82        config = load_config()
 83
 84    # Create the context with all provided overrides
 85    ctx = AppContext(
 86        config=config,
 87        event_bus=event_bus,  # type: ignore[arg-type]
 88        hook_manager=hook_manager,  # type: ignore[arg-type]
 89        tool_registry=tool_registry,  # type: ignore[arg-type]
 90        agent_registry=agent_registry,  # type: ignore[arg-type]
 91        plugin_registry=plugin_registry,
 92        route_resolver=route_resolver,
 93        policy_engine=policy_engine,
 94    )
 95
 96    # Register built-in tools
 97    if register_tools:
 98        from tiphys.tools import register_builtin_tools
 99
100        register_builtin_tools(ctx.tool_registry)
101
102    # Wire Castor kernel services (L1 Guard + L2 Deep Guard)
103    if config.budget.enabled:
104        _wire_castor_guard(ctx)
105        _wire_castor_kernel(ctx)
106
107    # Set as current context
108    if set_as_current:
109        set_context(ctx)
110
111    # Run startup hooks
112    if run_startup:
113        await ctx.startup()
114
115    return ctx
116
117
118def create_app_context_sync(
119    config: TiphysConfig | None = None,
120    **kwargs: Any,
121) -> AppContext:
122    """
123    Create application context synchronously (without running async startup).
124
125    Useful for testing or when you need to create context outside async context.
126
127    Args:
128        config: Optional pre-loaded config.
129        **kwargs: Additional arguments passed to AppContext.
130
131    Returns:
132        AppContext (startup hooks not run).
133    """
134    if config is None:
135        config = load_config()
136
137    ctx = AppContext(config=config, **kwargs)
138
139    from tiphys.tools import register_builtin_tools
140
141    register_builtin_tools(ctx.tool_registry)
142
143    # Wire Castor kernel services (L1 Guard + L2 Deep Guard)
144    if config.budget.enabled:
145        _wire_castor_guard(ctx)
146        _wire_castor_kernel(ctx)
147
148    set_context(ctx)
149
150    return ctx
151
152
153def _wire_castor_guard(ctx: AppContext) -> None:
154    """Create and attach Castor L1 Guard services to the AppContext."""
155    from castor import CapabilityManager, SyscallGate
156    from castor.gate.registry import ToolRegistry as CastorToolRegistry
157
158    from tiphys.kernel.bridge import HITLBridge
159    from tiphys.kernel.budget import SessionBudgetManager
160    from tiphys.kernel.guard import TiphysGuard
161    from tiphys.kernel.tools import register_chela_tools
162
163    # Build Castor tool registry from Tiphys's registered tools
164    castor_tool_registry = CastorToolRegistry()
165    register_chela_tools(ctx.tool_registry, castor_tool_registry)
166
167    # Create Castor subsystems
168    gate = SyscallGate(castor_tool_registry)
169    cap_mgr = CapabilityManager()
170
171    # Assemble guard and budget manager
172    ctx.castor_guard = TiphysGuard(gate, cap_mgr)
173    ctx.session_budget_mgr = SessionBudgetManager(ctx.config.budget, cap_mgr)
174    ctx.hitl_bridge = HITLBridge(ctx.event_bus)
175
176
177def _wire_castor_kernel(ctx: AppContext) -> None:
178    """Create and attach Castor L2 Deep Guard services to the AppContext."""
179    from castor import Castor
180
181    from tiphys.kernel.bridge import CheckpointHITLBridge
182    from tiphys.kernel.runner import CastorAgentRunner
183
184    # Build the Castor kernel facade (reuses L1 guard's Gate if available)
185    gate = ctx.castor_guard.gate if ctx.castor_guard else None
186    cap_mgr = ctx.castor_guard.capability_manager if ctx.castor_guard else None
187    kernel = Castor(
188        gate=gate,
189        capability_manager=cap_mgr,
190        store=ctx.checkpoint_store,
191        default_budgets=ctx.config.budget.default_budgets,
192    )
193    ctx.castor_kernel = kernel
194
195    # Create CastorAgentRunner
196    ctx.castor_agent_runner = CastorAgentRunner(context=ctx)
197
198    # Create L2 checkpoint HITL bridge
199    ctx.checkpoint_hitl_bridge = CheckpointHITLBridge(
200        event_bus=ctx.event_bus,
201        kernel=kernel,
202    )
async def create_app_context( config: tiphys.TiphysConfig | None = None, config_path: pathlib.Path | None = None, *, event_bus: tiphys.server.EventBus | None = None, hook_manager: tiphys.hooks.HookManager | None = None, tool_registry: tiphys.tools.base.ToolRegistry | None = None, agent_registry: tiphys.routing.AgentRegistry | None = None, plugin_registry: tiphys.plugins.PluginRegistry | None = None, route_resolver: tiphys.routing.RouteResolver | None = None, policy_engine: tiphys.security.PolicyEngine | None = None, register_tools: bool = True, run_startup: bool = True, set_as_current: bool = True) -> tiphys.context.AppContext:
 27async def create_app_context(
 28    config: TiphysConfig | None = None,
 29    config_path: Path | None = None,
 30    *,
 31    # Optional overrides for testing
 32    event_bus: EventBus | None = None,
 33    hook_manager: HookManager | None = None,
 34    tool_registry: ToolRegistry | None = None,
 35    agent_registry: AgentRegistry | None = None,
 36    plugin_registry: PluginRegistry | None = None,
 37    route_resolver: RouteResolver | None = None,
 38    policy_engine: PolicyEngine | None = None,
 39    register_tools: bool = True,
 40    run_startup: bool = True,
 41    set_as_current: bool = True,
 42) -> AppContext:
 43    """
 44    Create and initialize the application context.
 45
 46    This is the main factory function for bootstrapping the application.
 47    It creates all services, wires dependencies, and runs initialization.
 48
 49    Args:
 50        config: Optional pre-loaded config. Loaded from environment if not provided.
 51        config_path: Optional path to config file.
 52        event_bus: Optional EventBus instance (for testing).
 53        hook_manager: Optional HookManager instance (for testing).
 54        tool_registry: Optional ToolRegistry instance (for testing).
 55        agent_registry: Optional AgentRegistry instance (for testing).
 56        plugin_registry: Optional PluginRegistry instance (for testing).
 57        route_resolver: Optional RouteResolver instance (for testing).
 58        policy_engine: Optional PolicyEngine instance (for testing).
 59        register_tools: Whether to register built-in tools. Defaults to True.
 60        run_startup: Whether to run startup hooks. Defaults to True.
 61        set_as_current: Whether to set as current context. Defaults to True.
 62
 63    Returns:
 64        Fully initialized AppContext.
 65
 66    Example:
 67        # Standard usage
 68        ctx = await create_app_context()
 69
 70        # With custom config
 71        ctx = await create_app_context(config=my_config)
 72
 73        # For testing with mocks
 74        ctx = await create_app_context(
 75            config=test_config,
 76            event_bus=mock_bus,
 77            run_startup=False,
 78            set_as_current=False,
 79        )
 80    """
 81    # Load config if not provided
 82    if config is None:
 83        config = load_config()
 84
 85    # Create the context with all provided overrides
 86    ctx = AppContext(
 87        config=config,
 88        event_bus=event_bus,  # type: ignore[arg-type]
 89        hook_manager=hook_manager,  # type: ignore[arg-type]
 90        tool_registry=tool_registry,  # type: ignore[arg-type]
 91        agent_registry=agent_registry,  # type: ignore[arg-type]
 92        plugin_registry=plugin_registry,
 93        route_resolver=route_resolver,
 94        policy_engine=policy_engine,
 95    )
 96
 97    # Register built-in tools
 98    if register_tools:
 99        from tiphys.tools import register_builtin_tools
100
101        register_builtin_tools(ctx.tool_registry)
102
103    # Wire Castor kernel services (L1 Guard + L2 Deep Guard)
104    if config.budget.enabled:
105        _wire_castor_guard(ctx)
106        _wire_castor_kernel(ctx)
107
108    # Set as current context
109    if set_as_current:
110        set_context(ctx)
111
112    # Run startup hooks
113    if run_startup:
114        await ctx.startup()
115
116    return ctx

Create and initialize the application context.

This is the main factory function for bootstrapping the application. It creates all services, wires dependencies, and runs initialization.

Args: config: Optional pre-loaded config. Loaded from environment if not provided. config_path: Optional path to config file. event_bus: Optional EventBus instance (for testing). hook_manager: Optional HookManager instance (for testing). tool_registry: Optional ToolRegistry instance (for testing). agent_registry: Optional AgentRegistry instance (for testing). plugin_registry: Optional PluginRegistry instance (for testing). route_resolver: Optional RouteResolver instance (for testing). policy_engine: Optional PolicyEngine instance (for testing). register_tools: Whether to register built-in tools. Defaults to True. run_startup: Whether to run startup hooks. Defaults to True. set_as_current: Whether to set as current context. Defaults to True.

Returns: Fully initialized AppContext.

Example: # Standard usage ctx = await create_app_context()

# With custom config
ctx = await create_app_context(config=my_config)

# For testing with mocks
ctx = await create_app_context(
    config=test_config,
    event_bus=mock_bus,
    run_startup=False,
    set_as_current=False,
)
def create_app_context_sync( config: tiphys.TiphysConfig | None = None, **kwargs: Any) -> tiphys.context.AppContext:
119def create_app_context_sync(
120    config: TiphysConfig | None = None,
121    **kwargs: Any,
122) -> AppContext:
123    """
124    Create application context synchronously (without running async startup).
125
126    Useful for testing or when you need to create context outside async context.
127
128    Args:
129        config: Optional pre-loaded config.
130        **kwargs: Additional arguments passed to AppContext.
131
132    Returns:
133        AppContext (startup hooks not run).
134    """
135    if config is None:
136        config = load_config()
137
138    ctx = AppContext(config=config, **kwargs)
139
140    from tiphys.tools import register_builtin_tools
141
142    register_builtin_tools(ctx.tool_registry)
143
144    # Wire Castor kernel services (L1 Guard + L2 Deep Guard)
145    if config.budget.enabled:
146        _wire_castor_guard(ctx)
147        _wire_castor_kernel(ctx)
148
149    set_context(ctx)
150
151    return ctx

Create application context synchronously (without running async startup).

Useful for testing or when you need to create context outside async context.

Args: config: Optional pre-loaded config. **kwargs: Additional arguments passed to AppContext.

Returns: AppContext (startup hooks not run).