KsADK

Frameworks

KsADK supports common Python agent framework families through runtime adapters. The public contract is simple: expose an agent object, declare the framework, and run the project through agentengine.

Supported Families

FrameworkInstall extraTypical export
Google ADKksadk[adk]root_agent = Agent(...)
LangGraphksadk[langgraph]root_agent = graph.compile()
LangChainksadk[langchain] or framework dependencies`root_agent = prompt
DeepAgentsksadk[deepagents]root_agent = create_deep_agent(...)

Framework Runtime Architecture

KsADK treats every framework adapter as a small boundary around the user's native agent object. The local server, Web UI, session store, and OpenAI-compatible endpoints do not call framework-specific APIs directly. They call the runner contract, and the runner owns the framework details.

Framework runtime architecture

The important design point is that framework detection is static while runner loading is executable. Detection reads config files and source text; loading imports the configured module and validates the exported object. That keeps diagnostics clear: a project that cannot be detected has a packaging/config problem, while a project that detects correctly but fails to load has an import, dependency, or exported-object problem.

LayerStable responsibilityTypical failure to check
detectionfind framework, entry point, package path, and exported variablemissing or inconsistent agentengine.yaml
factorymap DetectionResult.type to a concrete runnerunsupported framework value
runner loadingimport the module and validate the exported agent objectdependency import error or wrong agent_variable
conversation runtimenormalize input, history, attachments, and platform contextmalformed payload or session conflict
protocol surfaceserialize the result as Web UI, SSE, Responses, or Chat CompletionsAPI format mismatch

Google ADK

KsADK keeps the ADK programming model intact. The application still exports a Google ADK Agent; KsADK detects the project, imports the configured object, wraps it in the local runner, and exposes the same local CLI, Web UI, and HTTP protocols used by other framework families.

agent.py
from google.adk.agents import Agent

def hello(name: str) -> dict:
    return {"message": f"Hello, {name}!"}

root_agent = Agent(
    name="hello_agent",
    description="Minimal ADK example",
    instruction="You are a helpful assistant.",
    tools=[hello],
)

Project config:

agentengine.yaml
name: hello-agent
framework: adk
entry_point: agent.py
agent_variable: root_agent

Recommended setup:

bash
python -m venv .venv
source .venv/bin/activate
pip install -U "ksadk[adk]"
agentengine run . -i
agentengine web . --no-open

For ADK projects, optional KsADK integrations such as knowledge search, long-term memory tools, MCP toolsets, and Skill Runtime tools are injected during ADK runner loading when their environment variables are configured. A minimal ADK tutorial should leave those variables unset so the first run only depends on the ADK agent object and model configuration.

Common ADK loading failures:

Error patternCheck
project detected as unknownagentengine.yaml exists and sets framework: adk
configured object is missingagent_variable matches the exported Python variable
model calls failprovider env vars are visible inside the project virtualenv
optional tools are missingthe matching KsADK feature flags and dependencies are installed

LangGraph

agent.py
from langgraph.graph import END, StateGraph

class State(TypedDict):
    messages: Annotated[list, operator.add]

llm = ChatOpenAI(model="my-model", base_url="https://api.example.com/v1", api_key="sk-test")

def chat(state: State):
    return {"messages": [llm.invoke(state["messages"])]}

graph = StateGraph(State)
graph.add_node("chat", chat)
graph.set_entry_point("chat")
graph.add_edge("chat", END)

root_agent = graph.compile()

Project config:

agentengine.yaml
name: langgraph-agent
framework: langgraph
entry_point: agent.py
agent_variable: root_agent

LangChain

agent.py
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="my-model", base_url="https://api.example.com/v1", api_key="sk-test")
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("human", "{input}"),
])

root_agent = prompt | llm | StrOutputParser()

Project config:

agentengine.yaml
name: langchain-agent
framework: langchain
entry_point: agent.py
agent_variable: root_agent

DeepAgents

agent.py
llm = ChatOpenAI(model="my-model", base_url="https://api.example.com/v1", api_key="sk-test")
root_agent = create_deep_agent(model=llm)

Project config:

agentengine.yaml
name: deep-agent
framework: deepagents
entry_point: agent.py
agent_variable: root_agent

Detection Order

KsADK first checks explicit project configuration. If no config file exists, it tries common project shapes:

__init__.py
agent.py
agentengine.yaml
langgraph.json
  • a package with agent.py, main.py, or app.py
  • a package __init__.py that exports common agent variables
  • a script-style project with agent.py, main.py, or app.py

Explicit YAML is recommended for public examples because it is easier to review and less dependent on heuristics.

Detection Details

Detection is a static step. It reads configuration files and source text, but it does not execute the user agent module. That keeps framework detection separate from framework loading.

The detection result carries these values into the runner factory:

FieldWhy it matters
typeselects the runner adapter
nameused for display and runtime metadata
entry_pointPython file to import during runner loading
package_pathpackage or directory that contains the entry point
agent_variableexported object to load from the entry point
confidencediagnostic signal for convention-based detection

If a configured entry file exists but does not export the configured variable, fix the export or the agent_variable setting. Do not work around this by adding import side effects that create global state indirectly.

Detection To Runner Pipeline

Explicit configuration is the recommended path for public examples, but the detector also supports convention-based projects. The pipeline below is useful when reviewing examples or debugging why a project was loaded as the wrong framework.

Detection to runner pipeline

The runner factory applies a small LangChain compatibility patch, then creates one of the concrete runners. This is intentionally a narrow switch instead of a plugin registry: the public contract is easier to audit, and new framework families can be reviewed as explicit additions.

Runner Loading Behavior

Each runner keeps the framework's native execution model:

RunnerLoading pathNative execution
ADKimports the configured ADK Agent and wraps it in a Google ADK runnerADK Runner.run_async()
LangGraphimports the configured graph objectgraph invoke / ainvoke / event stream
LangChainimports the configured runnable, chain, or callablerunnable/callable invoke and stream
DeepAgentsreuses the LangGraph runner pathcompiled graph execution

The adapters normalize the result into {"output": ...} for non-streaming calls and semantic chunks for streaming calls. They do not rewrite the user's agent into a different framework.

Runner Responsibilities

All framework adapters implement the same public responsibilities:

ResponsibilityMeaning
loadimport the configured module and validate the exported object
prepareapply per-request model overrides where supported
invokerun one non-streaming turn
streamrun one streaming turn
closerelease framework or runtime resources on shutdown

This keeps the HTTP server and Web UI independent from framework-specific objects. Framework-specific behavior belongs in the adapter or in the application's own hook functions.

Custom Input Hooks

LangGraph and LangChain applications often use custom state shapes. Add a hook in the configured entry module when the default mapping is not enough:

agent.py
def ksadk_prepare_state(payload: dict, session_context: dict) -> dict:
    return {
        "messages": payload.get("input_messages", []),
        "question": payload.get("input", ""),
        "knowledge": session_context.get("kb_context"),
        "memory": session_context.get("memory_context"),
    }
agent.py
def ksadk_prepare_input(payload: dict, session_context: dict) -> dict:
    return {
        "question": payload.get("input", ""),
        "history": session_context.get("history", []),
        "attachments": payload.get("attachment_results", []),
    }

Hooks make examples easier to test because business code receives a stable, explicit dictionary instead of reading local UI events or session internals.

Model Overrides

Requests can provide a model override through the CLI or HTTP payload. KsADK normalizes the requested model and calls the runner before execution. The effect depends on the framework:

Framework familyTypical behavior
ADKapplies the requested model to the loaded agent tree when possible
LangGraphsynchronizes model environment variables and reloads the module when needed
LangChainsynchronizes model environment variables and reloads the module when needed
Remote runnerforwards the model in the outgoing OpenAI-compatible payload

For deterministic examples, set a default model in .env or your provider configuration, then use request-level overrides only when you need to test model selection.

Session Continuity

Frameworks differ in how much native session state they expose. KsADK describes that capability through runner session adapters:

Continuity pathMeaning
transcript replayKsADK projects prior session events back into model history
standard hookuser hook receives structured history and session context
framework checkpointframework runtime keeps recoverable state
native sessionframework has its own session service or equivalent state

Transcript replay is the portable baseline. Native checkpoint or session paths are useful when the framework supports them, but examples should still behave reasonably when only transcript replay is available.

New in 0.6.7

KsADK distinguishes two resume semantics through GetAgentUiBootstrap.RuntimeCapabilities.ResumeRun.ResumeMode. LangGraph declares time_travel, which can roll back to a historical checkpoint. ADK declares forward_only, which continues only along the framework's native event/invocation continuity. The default runner is none. The list, preview, and resume entry points are provided by the three actions ListSessionCheckpoints, GetCheckpointResumePreview, and ResumeRun; whether they are enabled follows the bootstrap capability.

Framework familyResumeModeMeaning
LangGraphtime_travelcan roll back to a historical checkpoint
ADKforward_onlycontinues only along native event/invocation continuity
default runnernoneno resume capability declared; entry points stay disabled

Local Invocation

All framework examples should support the same local commands:

bash
agentengine run . -i
agentengine web . --no-open

Hosted deployment examples are optional and must provide a local fallback.

On this page