Skip to content

LangChain

Installation

Install the optional LangChain integrations:

uv add 'kedi[langchain]'

Other providers may require their own LangChain integration package.

Chat Models

> adapter: langchain
> model: openai:gpt-5.6-luna

String models are passed through langchain.chat_models.init_chat_model. An existing chat model object may be supplied directly to LangChainAdapter. A missing model fails when the adapter first runs.

Model Settings

Kedi supports common constructor/runtime fields including temperature, max_tokens, timeout, max_retries, sampling penalties, tool_choice, parallel_tool_calls, callbacks, metadata/tags, streaming controls, OpenAI-compatible endpoint fields, and reasoning/reasoning_effort.

For openrouter: model names, or models with an existing reasoning mapping, effort is written to reasoning={"effort": ...} while retaining the other reasoning options. Other models receive reasoning_effort.

The Python constructor's model_settings accepts native options without the DSL settings filter. An existing model is copied for each run: request fields such as reasoning are applied, and its model_kwargs are merged with constructor kwargs, constructor model_settings, then active profile settings. Original objects are not mutated. Explicit cache keys override generated history keys.

Configure endpoint, credentials, timeout and retries when constructing a native model. Changing those fields on an already initialized model would leave its existing clients unchanged, so Kedi rejects that combination. String models can receive those construction settings through the adapter.

Codex Responses Sessions

from kedi import codex_responses_model
from kedi.agent_adapter import LangChainAdapter
from kedi.agent_adapter.conversation import ConversationState

model = codex_responses_model(
    "gpt-5.6-luna", adapter="langchain", connection="websocket",
)
adapter = LangChainAdapter(model, model_settings={"reasoning": {"effort": "high"}})
conversation = ConversationState(session_id="release-review")
try:
    async with adapter.responses_session():
        for prompt in ("Review release amber.", "Recheck the selected release."):
            async with conversation.adapter_turn_async("langchain") as context:
                with adapter.conversation_scope(context):
                    answer = await adapter.invoke(prompt=prompt, instructions="Review the evidence.")
                context.record_exchange(prompt, answer)
finally:
    conversation.close()

Install kedi[codex-model,langchain] on Python 3.11 or newer. This selects codex-auth-helper[websocket]==1.8.0. Authentication uses the existing Codex login. See Codex Models for factory parameters and the distinction from the Codex App Server harness.

HTTP remains the default. Kedi owns one transport session for the complete agent run, including tool turns. An explicit responses_session() shares the connection across sequential calls, but does not manage message history itself. Child Kedi runs use isolated sessions. Exceptions, cancellation and early stream close release resources. Changes to history, instructions, schemas, tools or settings invalidate response-ID continuation and send full input.

Updated helpers give each adapter run its own routing turn, matching Pydantic. HTTP and WebSocket echo server-provided x-codex-turn-state within the run's tool loop and clear it for the next run, without closing a shared connection. It is not stored in history or metrics and does not guarantee a provider cache hit. Older helpers remain compatible without this feature.

Explicit HTTP and handshake 401s have bounded same-account reload/refresh recovery. Account changes require a new client, and permanent auth failures or exhausted 401s do not trigger HTTP fallback. Same-file refresh locking is in-process; accepted requests and uncertain sends are not replayed by auth recovery.

The helper maps active system messages to Codex instructions and retains the factory instruction when no active system message exists. Native LangChain tool, structured-output and stream-event conversion remain in use. HTTP invocation also consumes streaming responses internally.

Do not set use_previous_response_id or supply response IDs manually. WebSocket requires async native model calls or Kedi's sync wrappers; HTTP response-header capture is unavailable in this mode. With helper 1.8.0, ordinary ainvoke buffers each model response and retries transient WebSocket failures with full history. Completed local tools are not rerun by recovery. The client max_retries controls reconnects (default two), with bounded backoff; fallback="http" permits HTTP after retries are exhausted or the initial handshake fails. Lost provider work can still incur unreported cost.

The WebSocket factory uses automatic streaming selection. astream, explicit streaming=True, or streaming callbacks use the exposed-stream path, which does not replay partial output. Cancellation, permanent auth/permission failures and provider-hosted tools also prevent response replay. HTTP defaults are unchanged. The model can independently request a tool again; recovery is not an exactly-once tool guarantee. Install the pinned helper with uv add 'kedi[codex-model]'. transport_observer= receives content-free transport metrics, including receive failures and retry/fallback events.

Connection reuse supports cache reuse, but does not guarantee cache hits or a fixed hit percentage. Measure actual provider usage.

Structured Outputs

Kedi builds a Pydantic output model and calls create_agent with a response format. It reads LangChain's structured_response field and fails if the agent does not provide one.

Subagent JSON Schema uses LangChain ToolStrategy, preserving the child schema rather than inventing a Kedi output format.

Tool Binding

Kedi tools become StructuredTool instances with JSON argument schemas. Sync and async functions retain the correct invocation path. Kedi's approval middleware guards projected tools and preserves tool metadata.

MCP Tools

MultiServerMCPClient maps:

  • Kedi stdio to LangChain stdio;
  • Kedi SSE to sse;
  • Kedi HTTP to streamable_http.

MCP tools are added to each agent run. External MCP tools are treated as mutating by default and upgraded to sensitive when arguments target dotenv secret files.

Native Tool Artifacts

When artifacts are enabled, LangChain-native and MCP tool results cross Kedi's artifact-admission middleware before their ToolMessage is committed to history. Large successful content is replaced by the same compact ArtifactRef representation used by Kedi-defined tools.

The original tool_call_id and message metadata remain attached to the result. Error ToolMessage values remain native errors, approval and hook ordering are unchanged, and tools already wrapped by Kedi are not admitted twice. Request-time cache markers are projected only for the provider call and are not persisted in canonical conversation history.

CodeMode

> codemode: enabled replaces LangChain's model-facing application tools with search_tools, get_tool_schema, and execute_code. Scoped Kedi tools and MultiServerMCPClient tools enter one run-scoped catalog. Nested calls retain Kedi argument validation and inline approval; the direct-call approval middleware does not approve the three controls a second time.

LangChain receives Monty and boundary failures as failed tool results, allowing the model to correct a snippet without terminating the complete agent run. See CodeMode for the shared contract.

Subagent Lifecycle

LangChain supports foreground/background child runs. Request, tool-call and token limits apply to the native child loop. Graph recursion is an additional guard, not a substitute for a request limit. Usage is collected per model response, independently of messages retained in history, and reported to Kedi's budget observer.

Run Limits and Tool Corrections

LangChainAdapter(default_usage_limits=UsageLimits(...)) uses the same limit object as PydanticAdapter. A call's usage_limits overrides that default; explicit None uses normal run defaults. Import UsageLimits from pydantic_ai.

Request and successful tool-call limits are checked before dispatch, including reservations for parallel tools. Input, output, total and per-request input token limits use provider-reported usage. These input limits include cached tokens; Kedi's separate model-request budget uses uncached input. Provider-exact preflight token counting and USD cost_limit are unsupported here and fail before sending a model request rather than silently going unenforced.

Use config={...} for native LangGraph configuration. A recursion_limit keyword is also forwarded into config; neither is inserted into the model's message state. Caller callbacks are preserved when Kedi streaming callbacks are added.

Filesystem, terminal, dynamic-workflow, subagent and artifact errors use the same Kedi correction messages as Pydantic AI. The model may correct a failed tool call up to tool_retries=3 times per tool per run by default. The adapter does not automatically execute the same command again. Unclassified application exceptions and cancellation still propagate. Output-validation retries remain framework-native.

Exact History Archives

Both framework adapters accept the same opt-in policy:

from kedi.agent_adapter import LangChainAdapter
from kedi.agent_adapter.compaction import HistoryArchiveSettings

adapter = LangChainAdapter(
    history_archive=HistoryArchiveSettings(
        threshold_tokens=32_000,
        preserve_recent_tokens=12_000,
        minimum_reduction_tokens=8_000,
    ),
)

Supply the model normally and enable Kedi artifacts for the run. Without an active artifact manager and enabled policy, archival does nothing.

Old completed tool exchanges are stored losslessly as native message records and replaced by a checkpoint containing an artifact reference and tool-outcome counts. This is not LLM summarization and does not introduce a DSL compaction mode. The original user request, protected messages, unresolved tool-call pairs, earlier checkpoints and recent tail remain intact. Provider input growth triggers the policy when available; otherwise a conservative local estimate is used.

Graph history is persistently replaced, so archived messages do not return on the next tool turn. Each checkpoint changes the cache epoch once. Token and cache-read usage remain counted even after the corresponding messages leave history. Storage or quota failures leave history unchanged. Exact archives can contain sensitive tool output; apply the artifact store's retention/access policy accordingly.

For direct message processing, LangChainArtifactHistoryProcessor is exported from kedi.agent_adapter.compaction; using it alone does not manage graph state.

Capability Limits

Backend-specific settings still depend on the selected chat model. Native approval middleware covers tools represented in the LangChain agent; it cannot grant capabilities the provider itself does not expose.