tandem-server 0.6.2

HTTP server for Tandem engine APIs
use std::sync::Arc;

use axum::http::StatusCode;
use axum::Json;
use serde_json::Value;
use tandem_core::{
    AgentRegistry, CancellationRegistry, ConfigStore, EngineLoop, EventBus, PermissionManager,
    PluginRegistry, Storage,
};
use tandem_memory::{
    MemoryCapabilityToken, MemoryPromoteRequest, MemoryPromoteResponse, MemoryPutRequest,
    MemoryPutResponse,
};
use tandem_providers::ProviderRegistry;
use tandem_runtime::{LspManager, McpRegistry, PtyManager, WorkspaceIndex};
use tandem_tools::{GovernedToolDispatcher, ToolRegistry};
use tandem_types::HostRuntimeContext;
use tandem_types::{TenantContext, VerifiedTenantContext};
use tokio::sync::RwLock;

use crate::automation_v2::governance::GovernanceActorRef;
use crate::{AppState, RuntimeState};

#[derive(Debug, Clone)]
pub struct EvalAutomationV2GateDecisionInput {
    pub decision: String,
    pub reason: Option<String>,
}

pub struct EvalRuntimeStateParts {
    pub storage: Arc<Storage>,
    pub config: ConfigStore,
    pub event_bus: EventBus,
    pub providers: ProviderRegistry,
    pub plugins: PluginRegistry,
    pub agents: AgentRegistry,
    pub tool_dispatcher: GovernedToolDispatcher,
    pub tools: ToolRegistry,
    pub permissions: PermissionManager,
    pub mcp: McpRegistry,
    pub pty: PtyManager,
    pub lsp: LspManager,
    pub auth: Arc<RwLock<std::collections::HashMap<String, String>>>,
    pub logs: Arc<RwLock<Vec<Value>>>,
    pub workspace_index: WorkspaceIndex,
    pub cancellations: CancellationRegistry,
    pub engine_loop: EngineLoop,
    pub host_runtime_context: HostRuntimeContext,
}

pub async fn mark_eval_state_ready(
    state: &mut AppState,
    parts: EvalRuntimeStateParts,
) -> anyhow::Result<()> {
    let EvalRuntimeStateParts {
        storage,
        config,
        event_bus,
        providers,
        plugins,
        agents,
        tool_dispatcher,
        tools,
        permissions,
        mcp,
        pty,
        lsp,
        auth,
        logs,
        workspace_index,
        cancellations,
        engine_loop,
        host_runtime_context,
    } = parts;

    #[cfg(feature = "browser")]
    let browser = {
        let app_config = config.get().await;
        let browser = crate::BrowserSubsystem::new(app_config.browser.clone());
        let _ = browser.refresh_status().await;
        browser
    };

    state
        .mark_ready(RuntimeState {
            storage,
            config,
            event_bus,
            providers,
            plugins,
            agents,
            tool_dispatcher,
            tools,
            permissions,
            mcp,
            pty,
            lsp,
            auth,
            logs,
            workspace_index,
            cancellations,
            engine_loop,
            host_runtime_context,
            #[cfg(feature = "browser")]
            browser,
        })
        .await
}

pub async fn run_automation_v2_executor(state: AppState) {
    crate::app::state::automation::run_automation_v2_executor(state).await;
}

pub async fn automations_v2_run_gate_decide_inner(
    state: AppState,
    tenant_context: TenantContext,
    verified_tenant_context: Option<VerifiedTenantContext>,
    run_id: String,
    input: EvalAutomationV2GateDecisionInput,
    decider: GovernanceActorRef,
) -> Result<Json<Value>, (StatusCode, Json<Value>)> {
    crate::http::routines_automations::automations_v2_run_gate_decide_inner(
        state,
        tenant_context,
        verified_tenant_context,
        run_id,
        crate::http::routines_automations::AutomationV2GateDecisionInput {
            decision: input.decision,
            reason: input.reason,
        },
        decider,
    )
    .await
}

pub async fn memory_put_impl(
    state: &AppState,
    tenant_context: &TenantContext,
    request: MemoryPutRequest,
    capability: Option<MemoryCapabilityToken>,
) -> Result<MemoryPutResponse, StatusCode> {
    crate::http::memory_put_impl(state, tenant_context, request, capability).await
}

pub async fn memory_promote_impl(
    state: &AppState,
    tenant_context: &TenantContext,
    request: MemoryPromoteRequest,
    capability: Option<MemoryCapabilityToken>,
) -> Result<MemoryPromoteResponse, StatusCode> {
    crate::http::memory_promote_impl(state, tenant_context, request, capability).await
}

pub async fn enrich_verified_context_with_inbound_cross_tenant_grants(
    state: &AppState,
    verified: &mut VerifiedTenantContext,
) {
    crate::http::cross_tenant_grants::enrich_verified_context_with_inbound_cross_tenant_grants(
        state, verified,
    )
    .await;
}