Skip to content

Commit eab41f5

Browse files
Oleksandr Taruraievclaude
authored andcommitted
docs(user-guide): document append_to_context for iterator context accumulation
Relates to EPMCDME-10900 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 46784df commit eab41f5

4 files changed

Lines changed: 179 additions & 4 deletions

docs/user-guide/workflows/configuration/context-management.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ task: |
233233
- ⚠️ **Simple lists**: Not added to context as variables (use output_key or wrap in dict)
234234
- ⚠️ **Plain strings**: Not added to context as variables (use output_key or output as JSON)
235235
- 💡 **Best practice**: Always output structured JSON from assistants for maximum flexibility
236+
- 💡 **Parallel iterations**: Use `append_to_context: true` with `output_key` to collect all iteration results into a list — without it, only the last iteration's value is retained
236237

237238
#### Accessing Context in Templates
238239

@@ -337,6 +338,40 @@ states:
337338
include_in_llm_history: false # Don't show raw IDs to LLM
338339
```
339340

341+
**append_to_context** (boolean, default: `false`)
342+
343+
Controls whether the current state's output is appended to an existing list in the context store rather than overwriting it.
344+
345+
- `true`: Output is accumulated — the value under `output_key` in the context store grows into a list across multiple executions (most useful with `iter_key` iterations)
346+
- `false` (default): Output overwrites the previous value under the same key
347+
348+
**When to use `true`:**
349+
350+
- Collecting results from all parallel `iter_key` iterations into a single list
351+
- Any scenario where multiple states write to the same key and all values must be preserved
352+
353+
**Requirements and constraints:**
354+
355+
- Use together with `output_key` to specify which context key accumulates the results
356+
- When `append_to_context: true`, the top-level state key (set by `output_key`) is **not** written — read the accumulated list from the context store only via `{{output_key}}`
357+
- Has no effect when `store_in_context: false`
358+
359+
```yaml
360+
states:
361+
- id: process-item
362+
assistant_id: processor
363+
task: "Analyze {{task}} and return a result object"
364+
next:
365+
state_id: aggregate
366+
output_key: results
367+
append_to_context: true # Each parallel branch appends; context_store["results"] = [r1, r2, r3]
368+
369+
- id: aggregate
370+
assistant_id: aggregator
371+
task: "Summarize all results: {{results}}"
372+
# {{results}} contains the full list from every iteration
373+
```
374+
340375
**clear_prior_messages** (boolean, default: `false`)
341376

342377
Clears all prior messages from the message history, creating a "fresh start" for the LLM context.
@@ -543,6 +578,18 @@ next:
543578

544579
Use case: When iterating over items, prevent context from accumulating across iterations. Each iteration gets only the current item, not data from previous iterations.
545580

581+
**Pattern 7: Accumulate All Iteration Results Into a List**
582+
583+
```yaml
584+
next:
585+
state_id: aggregate
586+
iter_key: items
587+
output_key: all_results
588+
append_to_context: true
589+
```
590+
591+
Use case: When iterating in parallel and you need to collect every branch's output into a single list. Without `append_to_context: true`, only the last branch's value is kept (last-value-wins). With it, `context_store["all_results"]` contains a list with one entry per iteration.
592+
546593
### 6.3 Dynamic Value Resolution
547594

548595
Dynamic value resolution enables you to use context store values throughout your workflow configuration using template syntax.

docs/user-guide/workflows/configuration/state-transitions.md

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,21 @@ The previous state can output various formats, and `iter_key` adapts accordingly
361361
- Two formats: dictionary key (`"items"`) or JSON Pointer (`"/data/items"`)
362362
- The extracted value must be a list or will be wrapped as single-item list
363363

364+
**append_to_context** (boolean, default: `false`):
365+
366+
- When `true`, each iteration's output is **appended** to a list in the context store instead of overwriting the previous value
367+
- When `false` (default), standard overwrite semantics apply — the last iteration's value wins on duplicate keys
368+
- Use together with `output_key` to control which context key accumulates the collected results
369+
- When `append_to_context: true` is combined with `output_key`, the top-level state key is **not** set — values are only available via the accumulated list in the context store
370+
371+
```yaml
372+
next:
373+
state_id: collect-results
374+
iter_key: items
375+
output_key: processed_items
376+
append_to_context: true # Each iteration appends its output; context_store["processed_items"] becomes a list
377+
```
378+
364379
#### Multi-Stage Iteration:
365380

366381
For multi-stage iteration (when you have multiple sequential states processing each item), the **same `iter_key` must be present in every state** included in the iteration chain.
@@ -550,6 +565,57 @@ states:
550565
4. After all branches complete, contexts and message histories are merged
551566
5. Merged results flow to `merge-results`
552567

568+
**Example 7: Accumulating Results Across Iterations**
569+
570+
When all iteration results must be preserved, use `append_to_context: true` so each parallel branch contributes to a shared list rather than overwriting it.
571+
572+
```yaml
573+
states:
574+
- id: get-tickets
575+
tool_id: jira-api
576+
tool_args:
577+
jql: "project = PROJ AND status = 'Open'"
578+
# Outputs: [{"id": "PROJ-1", "title": "Bug A"}, {"id": "PROJ-2", "title": "Bug B"}, {"id": "PROJ-3", "title": "Bug C"}]
579+
next:
580+
state_id: analyze-ticket
581+
iter_key: . # Iterate over the entire list
582+
583+
- id: analyze-ticket
584+
assistant_id: analyzer
585+
task: |
586+
Analyze ticket {{id}}: {{title}}
587+
Return a JSON object: {"ticket_id": "...", "severity": "low|medium|high", "summary": "..."}
588+
# Iteration 1 returns: {"ticket_id": "PROJ-1", "severity": "high", "summary": "..."}
589+
# Iteration 2 returns: {"ticket_id": "PROJ-2", "severity": "low", "summary": "..."}
590+
# Iteration 3 returns: {"ticket_id": "PROJ-3", "severity": "medium", "summary": "..."}
591+
next:
592+
state_id: create-report
593+
output_key: analyses
594+
append_to_context: true # Accumulate all results; context_store["analyses"] = [{...}, {...}, {...}]
595+
596+
- id: create-report
597+
assistant_id: reporter
598+
task: |
599+
Create a severity report based on all ticket analyses.
600+
Analyses: {{analyses}}
601+
# Receives the full list of all three analyses in {{analyses}}
602+
next:
603+
state_id: end
604+
```
605+
606+
**How it works:**
607+
608+
1. Three parallel branches process one ticket each
609+
2. Each branch writes its output with the `analyses` key via `append_to_context: true`
610+
3. The reducer appends each result to the list — no overwriting occurs
611+
4. `create-report` receives `analyses = [result_1, result_2, result_3]` in its context
612+
613+
:::tip
614+
`append_to_context: true` is the recommended way to collect results from all parallel iterations into a single list. It replaces the workaround of using unique per-iteration keys (`result_1`, `result_2`, ...).
615+
:::
616+
617+
---
618+
553619
#### Context Isolation and Merging:
554620

555621
Iterations have important context management characteristics that ensure proper isolation and aggregation:
@@ -571,9 +637,17 @@ Iterations have important context management characteristics that ensure proper
571637

572638
- When all parallel iterations complete (fan-in), their context stores are **merged**
573639
- The merge uses `add_or_replace_context_store` reducer
574-
- For duplicate keys across iterations, the **last value wins** (last iteration overwrites previous)
640+
- **Default (overwrite)**: for duplicate keys across iterations, the **last value wins** (last iteration overwrites previous)
641+
- **Accumulation mode**: when `append_to_context: true` is set on the iterating state, each iteration's output is **appended** to a list under the specified key — no values are lost
575642
- The merged context is then passed to the next state after iteration
576643

644+
**Choosing between overwrite and accumulation:**
645+
646+
| Mode | Config | Result for key `output` after 3 iterations |
647+
| ------------------- | -------------------------- | ----------------------------------------------- |
648+
| Overwrite (default) | `append_to_context: false` | `output = "result_3"` (only last) |
649+
| Accumulation | `append_to_context: true` | `output = ["result_1", "result_2", "result_3"]` |
650+
577651
**Message History Merging:**
578652

579653
- Similarly, message histories from all iterations are also merged
@@ -611,9 +685,9 @@ states:
611685
**Important Context Merging Notes:**
612686

613687
- Iterations are isolated during execution but merged after completion
614-
- Context keys set by multiple iterations will have only one final value (last wins)
615-
- To preserve all iteration results, use unique keys (e.g., `result_1`, `result_2`) or aggregate into lists
616-
- Message histories are fully preserved from all iterations
688+
- By default, context keys set by multiple iterations will have only one final value (last wins)
689+
- To preserve all iteration results, set `append_to_context: true` combined with `output_key` — the context key will accumulate all values as a list
690+
- Message histories are fully preserved from all iterations regardless of the merge mode
617691

618692
#### Important Notes:
619693

@@ -626,5 +700,7 @@ states:
626700
- Cannot combine `iter_key` with `state_ids` (parallel transitions) or `condition`/`switch`
627701
- Each iteration branch has isolated context and message history during execution
628702
- After all iterations complete, contexts and message histories are merged using LangGraph reducers
703+
- Use `append_to_context: true` to accumulate all iteration outputs into a list; without it, only the last iteration's value is retained for duplicate keys
704+
- `append_to_context: true` has no effect when `store_in_context: false`
629705

630706
---
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# How do I collect all results from parallel workflow iterations?
2+
3+
Use `append_to_context: true` together with `output_key` in the `next:` block of the
4+
iterating state. This tells the workflow engine to accumulate each iteration's output into
5+
a list rather than overwriting the previous value.
6+
7+
```yaml
8+
states:
9+
- id: process-item
10+
assistant_id: processor
11+
task: "Analyze {{task}} and return a result object"
12+
next:
13+
state_id: aggregate
14+
iter_key: items
15+
output_key: all_results
16+
append_to_context: true
17+
18+
- id: aggregate
19+
assistant_id: aggregator
20+
task: "Summarize all results: {{all_results}}"
21+
# {{all_results}} contains every iteration's output as a list
22+
```
23+
24+
By default (`append_to_context: false`), when multiple parallel branches write to the
25+
same context key, only the last branch's value is kept. Setting `append_to_context: true`
26+
preserves all values in `context_store["all_results"]` as an ordered list.
27+
28+
## Sources
29+
30+
- [State Transitions — Iterative Transitions](https://docs.codemie.ai/user-guide/workflows/configuration/state-transitions)
31+
- [Context Management — Context Control Flags](https://docs.codemie.ai/user-guide/workflows/configuration/context-management)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# What happens to context keys when multiple iterations write to the same key?
2+
3+
By default, when parallel `iter_key` iterations all write to the same context key, the
4+
**last iteration's value wins** — earlier values are silently overwritten during the
5+
fan-in merge.
6+
7+
To preserve every iteration's output, set `append_to_context: true` on the iterating
8+
state. With this flag, each branch appends its output to a list instead of overwriting:
9+
10+
| Mode | Config | Result after 3 iterations writing to `output` |
11+
| ------------------- | -------------------------- | ----------------------------------------------- |
12+
| Overwrite (default) | `append_to_context: false` | `output = "result_3"` (only last) |
13+
| Accumulation | `append_to_context: true` | `output = ["result_1", "result_2", "result_3"]` |
14+
15+
Use `append_to_context: true` together with `output_key` to name the accumulation key.
16+
The accumulated list is accessible via `{{output_key}}` in subsequent states.
17+
18+
## Sources
19+
20+
- [State Transitions — Context Isolation and Merging](https://docs.codemie.ai/user-guide/workflows/configuration/state-transitions)
21+
- [Context Management — Context Control Flags](https://docs.codemie.ai/user-guide/workflows/configuration/context-management)

0 commit comments

Comments
 (0)