Skip to content

Framework interoperability

Use this guide when a useful tool or agent already exists in another framework, or when another runtime needs to consume a Tesserix agent. The adapter should preserve the smallest boundary that carries the required lifecycle. It should not pretend that two frameworks have the same policy, identity, state, or recovery model.

The model provider remains independent of every choice on this page. A wrapped or exported Tesserix agent can run on OpenAI, Anthropic, Gemini, Groq, xAI/Grok, OpenRouter, a local model, a compatible gateway, or any conforming ModelProvider.

Choose one boundary

flowchart TD
    START[Existing asset or consumer] --> SAME{Same process?}
    SAME -->|yes| KIND{Tool or agent?}
    KIND -->|tool| TOOL[Import under Tesserix tool policy]
    KIND -->|agent| ROLE{How should Tesserix call it?}
    ROLE -->|model-selected capability| WTool[Wrap as a typed tool]
    ROLE -->|supervisor-selected specialist| WAgent[Wrap as a typed sub-agent]
    SAME -->|no| LIFE{Needs task state, identity,<br/>cancellation or artifacts?}
    LIFE -->|yes| A2A[Official A2A task delegation]
    LIFE -->|no, capability call only| MCP[Authenticated MCP tool]
    START --> OUT{Another framework consumes<br/>a Tesserix agent?}
    OUT -->|same process| DIRECT[OpenAI-compatible descriptor<br/>and typed callable]
    OUT -->|tool protocol| MCPX[Export through MCP]
    OUT -->|agent protocol| A2AX[Export through official A2A]

    classDef choice fill:#fff4d6,stroke:#a46700,color:#4f3500,stroke-width:1.5px
    classDef local fill:#e8f1ff,stroke:#2457a7,color:#102a43,stroke-width:1.5px
    classDef remote fill:#e8f7ee,stroke:#247a46,color:#123b25,stroke-width:1.5px
    class SAME,KIND,ROLE,LIFE,OUT choice
    class TOOL,WTool,WAgent,DIRECT local
    class MCP,MCPX,A2A,A2AX remote
Situation Public surface What remains outside the adapter
Import a typed callable, class tool, or OpenAI function descriptor import_tool / import_toolset Foreign implementation and its downstream credentials
Import a Google FunctionTool import_google_adk_tool / import_google_adk_toolset Google function body and any application services it calls
Call an existing agent as one model-visible capability wrap_agent_as_tool Foreign runtime internals and credentials
Add an existing agent to a supervisor roster wrap_agent_as_subagent Foreign runtime internals and credentials
Add a Google BaseAgent to a Tesserix supervisor wrap_google_adk_agent plus GoogleAdkAgentInvoker Google Runner, sessions, plugins, artifacts and credentials
Give an in-process framework a callable Tesserix agent export_as_tool Host authentication and transport
Publish a Tesserix agent as an authenticated capability export_as_mcp_tool MCP transport host, authentication and durable effects
Publish a Tesserix agent with task lifecycle export_as_a2a A2A routes, authentication, task store, subscriptions and recovery

MCP invokes a capability. Official Agent2Agent (A2A) delegates a task to an independently addressable agent. Use A2A when task identity, progress, cancellation, durable state, artifacts, or agent discovery crosses a process boundary. Do not flatten that lifecycle into an MCP function merely because both protocols can carry JSON.

Import a foreign tool

The generic importer accepts a typed callable, a common class-tool shape, an OpenAI function descriptor paired with an implementation, or an already translated Tesserix tool. Admission happens before registry registration.

from tesserix_adk.adapters import ToolImportPolicy, import_tool
from tesserix_adk.core import Idempotency
from tesserix_adk.tools import ToolContext


async def catalog_search(*, query: str, context: ToolContext) -> dict[str, object]:
    return {"tenant": context.tenant, "query": query, "items": []}


search_tool = import_tool(
    catalog_search,
    policy=ToolImportPolicy(
        timeout_seconds=5,
        max_concurrency=4,
        requires_approval=False,
        idempotency=Idempotency.READ_ONLY,
    ),
    provenance="legacy-catalog:v1",
)

ToolImportPolicy deliberately has no idempotency default. Unsupported JSON Schema, missing caller-context propagation, duplicate names, ambiguous implementations, or undeclared repeat behavior raises ToolTranslationError before the foreign body runs. The resulting tool still receives Tesserix argument validation, approval, concurrency, timeout, attribution and registry allowlisting.

For a Google FunctionTool, install tesserix-adk[google-adk] and use import_google_adk_tool or import_google_adk_toolset. The Google invocation surface is retained, while the ephemeral Google tool context receives only credential-free run, tenant, user, narrowed scope, and W3C trace state. See the Google Agent Development Kit bridge.

Wrap a foreign agent

Use a typed tool when the parent model may select the capability. Use a typed sub-agent when deterministic supervisor routing selects a specialist. Both wrappers validate input and output, reserve projected usage before dispatch, share the caller's budget, narrow scopes and tools, propagate cancellation and W3C trace context, enforce recursion and timeout ceilings, and apply output guardrails.

from pydantic import BaseModel, ConfigDict

from tesserix_adk.adapters import (
    ForeignAgentContext,
    ForeignAgentReply,
    WrappedAgentPolicy,
    wrap_agent_as_subagent,
    wrap_agent_as_tool,
)
from tesserix_adk.core import Idempotency, Usage


class ResearchRequest(BaseModel):
    model_config = ConfigDict(extra="forbid")
    question: str


class ResearchAnswer(BaseModel):
    model_config = ConfigDict(extra="forbid")
    answer: str


async def invoke_existing(
    request: ResearchRequest,
    context: ForeignAgentContext,
) -> ForeignAgentReply[ResearchAnswer]:
    context.raise_if_cancelled()
    raw = await existing_runtime.run(
        question=request.question,
        tenant=context.tenant,
        user=context.user,
        scopes=context.scopes,
        trace=context.trace,
    )
    return ForeignAgentReply(output=raw.output, usage=raw.usage)


policy = WrappedAgentPolicy(
    timeout_seconds=30,
    projected_usage=Usage(input_tokens=2_000, output_tokens=500),
    scopes=("research:read",),
    tools=("catalog_search",),
    requires_approval=False,
    idempotency=Idempotency.IDEMPOTENT,
)

research_tool = wrap_agent_as_tool(
    invoke_existing,
    name="legacy_research",
    input_type=ResearchRequest,
    output_type=ResearchAnswer,
    policy=policy,
)
research_specialist = wrap_agent_as_subagent(
    invoke_existing,
    name="legacy_research",
    input_type=ResearchRequest,
    output_type=ResearchAnswer,
    policy=policy,
)

ForeignAgentContext has no credential field. The application resolves credentials at the foreign runtime's outbound boundary. A callback that ignores the supplied tenant, scope, cancellation, or budget context cannot be made safe by the wrapper and must not be admitted.

For a Google BaseAgent, use wrap_google_adk_agent with an application-owned GoogleAdkAgentInvoker. That explicit callback is where the application retains its Google Runner, tenant-scoped session service, plugins, artifacts and credential setup.

Effectful foreign work has an important uncertainty boundary: if cancellation or timeout happens after dispatch and the outcome cannot be proven, the wrapper raises IndeterminateOutcomeError. Retry only when the downstream operation has a stable idempotency key that returns the original result.

Export a Tesserix agent

All exports drive the normal AgentRunner; they do not create a second execution loop. The agent must declare structured output so the foreign consumer receives a stable, versioned ExportedAgentResult success-or-error envelope.

Direct and MCP function exports also need a request schema. Declare them with TypedAgent[InputT, OutputT] or TypedAgentDefinition[InputT, OutputT]; the export invokes run_typed and therefore keeps the same guardrails, budget, identity, trace and provider path as a local run. Official A2A's text ingress continues to accept the stable AgentDefinition[OutputT] contract.

Direct descriptor and callable

from tesserix_adk.adapters import ExportInvocation, export_as_tool
from tesserix_adk.core import Principal


exported = export_as_tool(
    runner,
    definition,
    name="research_agent",
    description="Answer one research question with cited evidence.",
    timeout_seconds=30,
)

descriptor_for_registry = exported.descriptor
pinned_fingerprint = exported.descriptor_fingerprint
exported.assert_descriptor(pinned_fingerprint)

result = await exported.invoke(
    {"question": "Where is Kyoto?"},
    ExportInvocation(
        tenant="acme",
        user="ada",
        scopes=("research:read",),
        trace={"traceparent": "00-..."},
        principal=Principal(
            subject="ada",
            tenant="acme",
            scopes=frozenset({"research:read"}),
        ),
    ),
)

Authentication is checked before arguments are parsed or provider work begins. The host must build ExportInvocation from a verified identity, never from model-controlled arguments. Consumers pin descriptor_fingerprint; drift raises ExportDescriptorDriftError before the incompatible call.

Failures use stable codes such as authorisation, budget_refusal, guardrail_block, schema_violation, provider_outage, and timeout. The envelope never copies provider bodies, prompts, tool arguments, credentials, or partial output into its public message.

MCP capability

from tesserix_adk.adapters import export_as_mcp_tool


mcp_server = export_as_mcp_tool(
    runner,
    definition,
    name="research_agent",
    description="Answer one research question with cited evidence.",
    per_tenant_calls=8,
)

The returned server requires an authenticated tenant when the host connects a session. The application still owns the stdio/HTTP host, authentication middleware, rate-limit storage, downstream durability, and network policy. Export only the generated allowlisted tool; do not expose the runner or raw provider client.

Official A2A task

from tesserix_adk.adapters import A2AInterface, A2ASkill, export_as_a2a


published = export_as_a2a(
    runner,
    definition,
    resolve=resolve_verified_principal,
    description="Answer research questions.",
    provider_url="https://agents.example.com",
    interfaces=(
        A2AInterface(
            url="https://agents.example.com/a2a/research",
            protocol_binding="JSONRPC",
        ),
    ),
    skills=(
        A2ASkill(
            id="research",
            name="Research",
            description="Answer one research question.",
            tags=("research",),
        ),
    ),
)

published.card is reviewed control-plane metadata; published.executor is the official server executor. The application mounts official routes, verifies issuer/audience/expiry and per-agent entitlement, resolves a core Principal, and supplies a tenant-scoped durable TaskStore. The resolver also protects cancellation. See Official A2A interoperability for the full support matrix.

What crosses each boundary

sequenceDiagram
    autonumber
    participant H as Authenticated host
    participant A as Tesserix adapter
    participant R as AgentRunner / registry
    participant F as Foreign framework or protocol
    participant D as Downstream effect

    H->>A: Verified principal + tenant + held scopes + deadline
    A->>A: Validate schema and intersect authority
    A->>R: Pinned tool/agent + shared budget + trace
    R->>F: Typed request + narrowed credential-free context
    F->>D: Resolve short-lived credential at outbound boundary
    D-->>F: Typed or measured outcome
    F-->>R: Structured output + usage
    R->>R: Guardrail, budget and schema validation
    R-->>A: Typed result or stable failure envelope
    A-->>H: Attributed terminal outcome
Context Import/wrap Direct/MCP export Official A2A export
Tenant and user Supplied by Tesserix caller Verified by host and compared at ingress Resolved from authenticated server context
Scopes and tools Intersected with wrapper policy Requested scopes must be held by principal Resolver and application entitlement policy narrow them
Credentials Never placed in foreign context Never accepted in function arguments Never accepted in task message metadata
Budget and usage Shared ledger; measured usage or declared estimate Shared narrower budget when supplied Runner budget under authenticated task execution
Trace W3C fields only W3C fields only Transport/server context into runner
Cancellation Propagated; effect may become indeterminate Cooperative token plus hard timeout Official task cancellation with principal re-check
Descriptor/schema Admitted before registry registration Canonical descriptor and fingerprint Reviewed Agent Card, explicit skills and interfaces

Authority only narrows. If identity, policy, budget, capability admission, or schema validation is unavailable, execution fails closed. Telemetry export may degrade under a documented bound because observability is not authorization.

Gateway and registry integration

A registry stores reviewed metadata and endpoints, never executable MCP code, provider credentials, prompts, or private agent instructions. A gateway authenticates the caller, applies rate and payload limits, and routes to a pinned descriptor. The in-flight run continues against that pinned surface if the registry later becomes unavailable.

For a custom official A2A registry, implement A2ARegistry.resolve(name) and use a2a_client_from_registry; verify signatures, issuer policy, endpoint allowlists, expiry, and that the returned card name matches the requested name. For a custom gateway binding, register the official SDK transport producer through a2a_client_factory. MCP gateways use McpTransport or the documented AgentGateway route reconciliation. See Integrations and gateways.

Verification checklist

Before enabling an adapter in production:

  • run its network-free positive, validation, timeout, cancellation, duplicate, budget, guardrail, and another-tenant tests;
  • pin provider capabilities and imported/exported descriptors to the reviewed deployment;
  • prove that unavailable identity, policy, budget, schema, or credential resolution fails before model or effectful work;
  • prove that a timeout after an effect starts is either deduplicated downstream or recorded as indeterminate;
  • keep credentials out of definitions, registry records, prompts, trace fields, MCP arguments, A2A messages, and ForeignAgentContext;
  • assign ownership for authentication, persistence, subscriptions, crash recovery, cancellation, quotas, and rollback on the application side of the boundary;
  • use the staged migration path and compare quality, cost, latency, safety, and recovery evidence before removing the old route.

The Google Agent Development Kit bridge gives the framework-specific assembly, while Agent lifecycle and platform architecture shows how these boundaries fit between evaluation, registry approval, canary, execution, recovery, and feedback.