Temporal
If your agents run on Temporal, KeletPlugin propagates session context across start_workflow → workflow → child workflow → activity so traces and signals are linked end-to-end. Register on the client (Python: workers inherit automatically; TypeScript: also pass to Worker.create).
How it works
Section titled “How it works”KeletPlugin registers Kelet’s client + worker interceptors via Temporal’s Plugin API. On start_workflow, the current agentic_session() is stamped into Temporal headers (x-kelet-session-id, x-kelet-user-id, x-kelet-metadata) using Temporal’s default PayloadConverter. The worker side reads them back, restoring session context (Python contextvars / TS AsyncLocalStorage) so kelet.signal() and auto-instrumentation resolve the session without arg-threading.
Kelet bundles Temporal’s own OpenTelemetryPlugin by default so OTel trace context links workflow + activity spans automatically — auto-skipped when you’ve already registered OTel yourself.
Install
Section titled “Install”Python
uv add "kelet[temporal]"# or: pip install "kelet[temporal]"TypeScript
npm install kelet @temporalio/plugin @temporalio/interceptors-opentelemetryRegister the plugin
Section titled “Register the plugin”Configure Kelet once at process start, then register KeletPlugin on the Temporal client.
- Python:
Pluginregistered on the client automatically applies to everyWorkerconstructed from that client — you don’t need to pass it again. - TypeScript: pass the plugin to both
new Client(...)andWorker.create(...). The TypeScript SDK doesn’t auto-propagate plugins from client to worker.
Python
import keletfrom kelet.temporal import KeletPluginfrom temporalio.client import Clientfrom temporalio.worker import Worker
kelet.configure(api_key="...", project="my-agent")
client = await Client.connect("localhost:7233", plugins=[KeletPlugin()])worker = Worker(client, task_queue="ai", workflows=[MyWorkflow], activities=[my_activity])TypeScript
import { configure } from 'kelet';import { KeletPlugin } from 'kelet/temporal';import { Client } from '@temporalio/client';import { Worker } from '@temporalio/worker';
configure({ apiKey: process.env.KELET_API_KEY!, project: 'my-agent' });
const plugin = new KeletPlugin({ otelPluginOptions: { resource, spanProcessor } });const client = new Client({ /* ...connection... */, plugins: [plugin] });const worker = await Worker.create({ workflowsPath: require.resolve('./workflows'), activities, taskQueue: 'ai', plugins: [plugin],});Wrap workflow starts in agentic_session()
Section titled “Wrap workflow starts in agentic_session()”When you start a workflow, wrap the call in agentic_session() (or agenticSession() in TS). The session ID, user ID, and metadata propagate into the workflow run and every activity it schedules.
Python
async with kelet.agentic_session(session_id="conv-42", user_id="user-7"): await client.execute_workflow(MyWorkflow.run, ..., id="wf-1", task_queue="ai")TypeScript
import { agenticSession } from 'kelet';
await agenticSession({ sessionId: 'conv-42', userId: 'user-7' }, async () => { await client.workflow.execute(MyWorkflow, { args: [...], workflowId: 'wf-1', taskQueue: 'ai', });});Verify
Section titled “Verify”Run a workflow that calls an activity. In the Kelet console, the workflow span and every activity / child-workflow span should share one gen_ai.conversation.id. If kelet.signal() is called from inside an activity, it should attach to the same session.
KeletPlugin() options
Section titled “KeletPlugin() options”| Option (Python / TS) | Type | Default | Behavior |
|---|---|---|---|
auto_session / autoSession | bool | Callable[[Info], str?] | False / false | Auto-derive a session when no agentic_session is set. True extracts the segment after /session/ in the workflow ID; otherwise pass a callable. Must be deterministic for workflow replay. |
activityAutoSession (TS only) | bool | (Info) => string? | false | Activity-side fallback for workflows started outside the TS client (CLI, schedules, other-language clients). See the inline note below. |
include_otel_plugin / includeOtelPlugin | bool / boolean | True / true | Bundle Temporal’s OpenTelemetryPlugin so workflow + activity OTel spans link into one trace. Auto-skipped if a prior plugin in the plugins=[...] list already registered an OTel interceptor. |
otelPluginOptions (TS only, required when bundling) | OpenTelemetryPluginOptions | — | Forwarded verbatim to OpenTelemetryPlugin (resource + spanProcessor). |
Python: kelet.configure() option that affects Temporal behavior:
| Option | Type | Default | Behavior |
|---|---|---|---|
signal_failure_mode | "swallow" | "raise" | "swallow" | When kelet.signal() is called from workflow code it dispatches through a Temporal activity (HTTP from workflows is non-deterministic). After Temporal exhausts retries, this controls failure behavior. "swallow" logs + drops; "raise" surfaces an ApplicationError to the workflow. |
Propagated headers
Section titled “Propagated headers”Encoded via PayloadConverter.default, so any custom payload converter / encryption you already use Just Works.
| Header | Source |
|---|---|
x-kelet-session-id | agentic_session(session_id=...) |
x-kelet-user-id | agentic_session(user_id=...) |
x-kelet-metadata | agentic_session(**metadata_kwargs) (Py) / agenticSession({ metadata }) (TS) |
Outbound calls that propagate the session from workflow code:
start_activity, start_local_activity, start_child_workflow, signal_child_workflow, signal_external_workflow, continue_as_new.
kelet.signal() and agentic_session() inside workflow code
Section titled “kelet.signal() and agentic_session() inside workflow code”- On worker shutdown,
KeletPluginflushes Kelet’s span processor with a 10-second timeout. If the Kelet API is slow or unreachable, shutdown proceeds anyway with a warning log — your worker won’t hang. - The Python plugin requires
temporalio>=1.7.0. The TypeScript plugin requires@temporalio/plugin(thePluginAPI was added in@temporalio/*1.17).
See also
Section titled “See also”- Python SDK reference —
kelet.configure(),kelet.agentic_session(),kelet.signal() - TypeScript SDK reference — same for TypeScript
- Temporal docs: Python observability, TypeScript observability