Files
LangBot/dev-docs/architecture/application-api.md

6.5 KiB

Application API foundation

The application package provides a callable business boundary inside Core. A consumer supplies a trusted identity and operation arguments, then receives a validated result or a stable application error. HTTP, MCP, the management assistant and lbctl retain their existing entrypoints in this change; their adoption of this boundary belongs in separate changes.

Workspace operations

ap.application_api.operation_catalog() returns the explicit operation allowlist, with version, permission, principal constraints, side effects, execution mode, and JSON schemas for inputs and results. The catalog covers the existing Workspace management capabilities:

Area Capabilities
Pipelines and agents CRUD, metadata, extension configuration, migration preview/execute, diagnostic runs, run history and events
Models and providers LLM/embedding/rerank CRUD and tests, defaults, discovery, provider credential authorization
Bots and platforms CRUD, routes and dry runs, messages, administrators, adapter metadata and credential setup sessions
Knowledge Bases, ingestion tasks, files, retrieval, engine schemas and parser discovery
Extensions Plugin installation/configuration/assets/logs, MCP servers/resources, skills and files, tools
Workspace Current workspace, language, membership, invitations, API keys and webhooks
Operations Monitoring and exports, governance and audit, task status, Box visibility, setup wizard and storage statistics
Conversations Management-assistant conversations/runs and Pipeline chat history, reset, connections and broadcast

Service-backed operations reuse existing business signatures to build strict Pydantic inputs. Only methods explicitly listed in service_operations.py are exposed; adding a public service method does not publish an operation. Domain configuration objects remain dictionaries because their schemas are owned by providers, plugins or the existing resource services. Those services retain validation, quotas, secret placeholder restoration and runtime side effects.

# context is established by a trusted authenticator, never from request JSON.
result = await ap.application_api.execute(
    'pipeline.get', context, {'pipeline_uuid': pipeline_uuid}
)

async for frame in ap.application_api.stream(
    'agent.debug.stream', context,
    {'agent_uuid': agent_uuid, 'payload': {'text': 'hello'}},
):
    consume(frame)

The Workspace comes only from RequestContext. Each invocation checks the operation permission and the current execution binding/generation, then carries that tenant and its message language through the business call. Additional identity constraints remain where required by the business service: membership, interactive provider authorization, assistant conversations and Pipeline migration require an account. API-key grants are not replaced by the creator's role. Authentication, key revocation/expiry and current account membership must be resolved by the trusted caller before constructing the context.

Secret reads require the corresponding secret-management permission. Mutating operations preserve the domain's existing authorization and resource ownership checks. Audit recording uses the existing Workspace configuration and bounded writer, with operation identity and outcome; raw arguments are not copied into the generic trace. Queued tasks retain their Workspace/generation and revalidate runtime admission before accessing plugins.

ApplicationAPIException.error carries code, message, status_code and optional structured details. Protocol adapters map that object to their own response shape. Invalid inputs and outputs fail explicitly. Cancellation is not converted into success, and writes are never automatically retried. Pipeline run timeouts retain the existing unknown outcome: a timeout does not establish that execution failed or was rolled back.

Streaming scopes live in isolated producer tasks with bounded queues. Closing an Agent debug stream cancels its execution. Management-assistant streaming retains its existing detached-run behavior; use the explicit stop operation to cancel an assistant run. Consumers should close partially consumed iterators with contextlib.aclosing.

Execution-context operations

ExecutionAPI publishes the existing Core business actions available to an installed plugin or a running processor. Its catalog describes each action's input/output schema, streaming mode and required plugin/run scope. It includes model and RAG access, tools, event replies and platform actions, state/history, run control and interactions, and Box/file operations.

from langbot.pkg.api.application.execution import ExecutionAPI, ExecutionAPIContext

api = ExecutionAPI(ap)
catalog = api.catalog()
context = ExecutionAPIContext(binding=trusted_installation_binding, run_id=run_id)
result = await api.invoke(operation_id, context, arguments)

The caller must supply the trusted installation binding established by Core. The foundation invokes the existing secured action dispatcher, preserving installation revision/grant checks, active placement and frozen run resources. A run-bound context also verifies that the run belongs to that installation's Workspace and plugin. Arguments cannot override the run ID or fall back to the legacy plugin path by omitting it. Plugin-only operations remain explicit and cannot be called with a run-bound context. Stream isolation also prevents one consumer's context from escaping into another consumer's task.

Scope and adoption

This foundation covers the Workspace and execution business capabilities listed in its explicit catalogs. Plugin publishing to Space and Git synchronization remain in their existing HTTP routes. Instance administration, account login/bootstrap, public ingress, OAuth callbacks, transport assets and internal Runtime handshake/chunk/ping messages remain with their owning boundaries. Composite HTTP response layouts (such as a combined monitoring page) are consumer projections of these operations. This does not add new platform APIs or new instance-level powers.

Existing routes do not call the new application dispatcher. No SDK protocol or lbctl command is changed by this foundation.

Consumer adoption should verify the same operation through each selected transport, including denied access, missing resources, invalid inputs, cancellation and secret handling. The existing Core smoke exercises current consumers; it does not by itself prove a new consumer integration.