flows prototype plan #
Goal #
Build the smallest useful Letta-native workflow layer on top of the Letta Agent SDK.
The prototype lets the current persistent agent open fresh conversations, fork inherited conversation history, return to either kind of conversation, run them concurrently, and observe the work through structured events.
Central model #
The root identity is resolved in this order:
agentIdpassed by the caller;LETTA_AGENT_IDfrom the environment;AGENT_IDfrom the Letta Code harness.
Failure to resolve an identity is an error. flows must not silently create a new agent.
The first vocabulary is deliberately small:
fresh: create a conversation with a fresh transcript on the root agent and run one turn;fork: copy an owned conversation's in-context history into a persistent new conversation and run one turn;resume: resume an existing conversation and run one turn;parallel: run lazy tasks concurrently with a configurable limit;map: apply a lazy task to each item using the same scheduler;phase: scope structured progress events and human-readable labels.
fresh starts an empty transcript. fork uses the Agent SDK's native persistent conversation fork and can copy full history or stop at one source message, inclusive.
Public API sketch #
const result = await flow(
{ concurrency: 4 },
async ($) => {
const perspectives = await $.parallel([
() => $.fresh("Make the optimistic case"),
() => $.fresh("Make the skeptical case"),
]);
return $.fresh({
prompt: `Synthesize:\n${perspectives.values().join("\n\n")}`,
});
},
);
Every agent turn returns a discriminated result:
type FlowResult<T> =
| { ok: true; value: T; run: RunMetadata }
| { ok: false; error: FlowError; run: RunMetadata };
Successful fresh-conversation metadata includes its agentId and conversationId, making the conversation navigable after the workflow finishes.
Milestone 1: package and contracts #
- Scaffold a Bun-first TypeScript package.
- Depend on
@letta-ai/letta-agent-sdk. - Define public result, error, run metadata, event, schema, client-adapter, and option types.
- Keep the SDK behind a narrow adapter so orchestration tests can use a deterministic fake.
Milestone 2: execution scope #
- Resolve the root agent without creating one.
- Own one client and one concurrency scheduler per flow run.
- Track active sessions and close them in
finally. - Track phase context without using module-global state.
- Emit workflow, phase, operation, and turn lifecycle events.
Milestone 3: conversation navigation #
- Implement
freshwith a new SDK conversation on the root agent. - Implement
resumewith an existing conversation ID. - Preserve conversation and run metadata in success and failure values.
- Pass through supported session choices such as
stateless, model, and reasoning effort. - Do not automatically retry turns: an interrupted send may already have reached the runtime.
Milestone 4: composition #
- Implement lazy
paralleltasks with stable result ordering. - Enforce the scope concurrency limit across nested calls.
- Implement
mapas an indexed convenience over the same scheduler. - Provide a collection object with
values(),failures(), andall(). - Allow callers to express minimum-success policy themselves before adding framework policy.
Milestone 5: output boundaries #
- Accept a minimal parser contract compatible with libraries exposing
parse. - Ask for JSON when a parser is present.
- Extract JSON conservatively and validate it at runtime.
- Report parse and validation failures as structured failures.
- Do not add automatic model-based repair in the first version.
Milestone 6: proving example #
Build a small advisory-panel example:
- open several fresh perspective conversations;
- collect successful outputs;
- explicitly pass them into a fresh synthesis conversation;
- print the final answer and conversation IDs.
This demonstrates current semantics honestly: shared agent identity and memory, separate fresh transcripts, explicit handoff, and navigability.
Test strategy #
Use a fake client adapter and fake sessions to test without models or credentials:
- agent resolution precedence and missing-agent failure;
- fresh transcript versus resumed conversation;
- conversation IDs retained in results;
- concurrency never exceeds the configured limit;
- result ordering remains input ordering;
- one agent turn failure does not reject the whole collection; ordinary JavaScript exceptions retain normal rejection semantics;
- sessions close on success, failure, and thrown workflow callbacks;
- schema parsing succeeds and produces structured failures;
- phase and operation events contain the correct local phase;
- stateless and other supported options reach the adapter;
- no retry occurs after an ambiguous turn failure.
Add one opt-in live example after deterministic tests pass.
Explicit deferrals #
- Cross-agent execution
- Ephemeral agent creation
- Read-only memory mode
- Persistent workflow checkpoints and replay
- Artifact storage
- Automatic retries or output repair
- Static DAG definitions
- A generic
mapReducehelper
Publication proving ground — 2026-09-03 #
The Public Knowledge batch example adds a bounded editorial workflow without changing the core DSL:
- a JSON manifest defines the finite batch, article contract, public source URLs, and local source packets;
- host code reads and hashes evidence before any model call;
- each draft, review, optional revision, and second review runs in a fresh stateless conversation on the existing agent;
- model sessions have no tools, skills, or memory access;
- runtime parsers validate claim inventories and reviewer decisions;
- deterministic checks block private paths, runtime identifiers, unsafe markup, unresolved links, source mismatches, and document-shape errors;
- private run artifacts retain conversation IDs, run IDs, packet and output hashes, timing, cost, findings, and failures;
- the flow has no Git, site-checkout, deployment, protocol-write, or publication authority.
This deliberately keeps artifact admission outside the flow. A human or separately authorized integration process must inspect candidates, run repository publication gates, and verify the live effects.
These remain possible experiments, not assumed requirements.
Completion criteria #
The first prototype is complete when:
- the public example is short and truthful;
- deterministic tests cover lifecycle, concurrency, navigation, and failures;
- package type-check and tests pass;
- a real Letta agent can run the advisory example by supplying its agent ID;
- the README distinguishes fresh transcript, inherited fork, and resume behavior.
Prototype checkpoint — 2026-08-21 #
Implemented:
- root-agent resolution with no silent agent creation;
- API/local harness selection from the root agent ID;
fresh, transcript-inheritingfork, and identity-checkedresumeoperations;- active-turn concurrency limiting,
parallel, andmap; - structured results, runtime output parsing, phases, and lifecycle events;
- operation tracking and scope cleanup, including fire-and-forget work;
- an advisory-panel example;
- deterministic lifecycle and concurrency tests.
Added 2026-08-31:
- native full-history and checkpoint conversation forks;
- source-agent ownership checks before fork creation;
- source conversation and checkpoint provenance in run metadata;
- hidden fork support with explicit persistent lifecycle semantics.
- a fork-variants example that continues one source draft along two inherited transcript paths.
Validation:
bun run checkpasses;bun testpasses with 18 tests;- a live one-conversation smoke test returned
FLOWS_READY; - the live advisory panel completed despite one of three perspective conversations failing, then synthesized the two surviving perspectives.
Still explicitly deferred:
- a settled-result contract for arbitrary JavaScript callback exceptions;
- turn-scoped model selection;
- workflow persistence, artifacts, and cancellation timeouts.