Concurrency¶
Kedi is sequential by default. Parallel execution is opt-in and accelerates independent model templates without changing source syntax or expected results.
Sequential Default¶
Every >> or << call blocks until the adapter returns:
>> First independent result: [first: str].
>> Second independent result: [second: str].
This is easiest to debug and is appropriate when latency is unimportant, the adapter is not thread-safe, or calls have external ordering effects.
Enable Parallel Execution¶
Environment:
Accepted truthy values are 1, true, yes, and on; false values are 0,
false, no, off, or unset. A positive integer sets the worker count.
Invalid values are rejected rather than guessed.
Python:
Use the public form appropriate to the application. max_workers must be a
positive bound.
Automatic Dependencies¶
There is no parallel operator. The runtime follows value dependencies:
>> Incident <incident> affects [service: str].
>> Owner of <service>: [owner: str].
>> Incident <incident> occurred in [region: str].
>> Runbook for <region>: [runbook: str].
The service and region calls can start together. Each downstream call begins as soon as its own input resolves, so the two chains pipeline independently.
Promises and Forcing¶
Template outputs are represented internally as opaque promises until a value is
needed. Normal Kedi code does not observe them. A bare Python read or
globals()["name"] forces the value.
Advanced non-forcing operations such as globals().get("name"),
globals().items(), globals().values(), and dict(globals()) can expose the
raw promise for forwarding. Resolve it with kedi.force(value).
Using an unresolved promise as an ordinary value raises KediPromiseLeak
instead of silently stringifying, indexing, comparing, or serializing the wrong
object. Application logic should not catch and normalize this exception; it
indicates an interpreter/advanced-integration error.
Snapshot Semantics¶
When a template is scheduled, Kedi snapshots its value environment by value. A later assignment on the main thread cannot alter that call's inputs.
Sequential and parallel results must be identical. Parallel mode is not a consistency option and must not be used to create races intentionally.
Failure Draining¶
Every scheduled template runs, including one whose output is never consumed. Before a scope returns or propagates another failure, Kedi drains its work. The first model failure is raised; additional concurrent failures are logged.
This prevents silent background exceptions and resource leaks. It also means a
fire-and-forget >> still has cost and can fail.
Adapter Thread Safety¶
Parallel execution may call an adapter's synchronous production path from several worker threads. Built-in adapters are designed for this contract. A custom adapter must be thread-safe or serialize its own critical section.
Agent/tool calls must also keep invocation scopes isolated. Do not store request-specific mutable state on a shared adapter without synchronization.
Shared Pools¶
Thread pools are process-global and cached by worker count. The first request for one size creates that pool; later runs using the same size reuse it. Select a small bound based on provider rate limits and workload, not CPU count alone.
Adaptive Job Manager¶
JobManagerEngine is an advanced opt-in engine that adds AIMD concurrency,
transient-error retries with exponential backoff and jitter, and a circuit
breaker. It is not selected by the public parallel() helper.
Construct it explicitly through compile_program(engine=...) when operating a
rate-limited backend and when retry semantics are acceptable. Do not enable
automatic retries for non-idempotent external effects without a deduplication
strategy.