Showing preview only (1,823K chars total). Download the full file or copy to clipboard to get everything.
Repository: The-Pocket/PocketFlow
Branch: main
Commit: 0271a7ea6d38
Files: 410
Total size: 1.7 MB
Directory structure:
gitextract_1kfwxukd/
├── .cursor/
│ └── rules/
│ ├── core_abstraction/
│ │ ├── async.mdc
│ │ ├── batch.mdc
│ │ ├── communication.mdc
│ │ ├── flow.mdc
│ │ ├── node.mdc
│ │ └── parallel.mdc
│ ├── design_pattern/
│ │ ├── agent.mdc
│ │ ├── mapreduce.mdc
│ │ ├── multi_agent.mdc
│ │ ├── rag.mdc
│ │ ├── structure.mdc
│ │ └── workflow.mdc
│ ├── guide_for_pocketflow.mdc
│ └── utility_function/
│ ├── chunking.mdc
│ ├── embedding.mdc
│ ├── llm.mdc
│ ├── text_to_speech.mdc
│ ├── vector.mdc
│ ├── viz.mdc
│ └── websearch.mdc
├── .cursorrules
├── .gitignore
├── LICENSE
├── README.md
├── cookbook/
│ ├── README.md
│ ├── data/
│ │ └── PaulGrahamEssaysLarge/
│ │ ├── addiction.txt
│ │ ├── aord.txt
│ │ ├── apple.txt
│ │ ├── avg.txt
│ │ └── before.txt
│ ├── pocketflow-a2a/
│ │ ├── README.md
│ │ ├── a2a_client.py
│ │ ├── a2a_server.py
│ │ ├── common/
│ │ │ ├── __init__.py
│ │ │ ├── client/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── card_resolver.py
│ │ │ │ └── client.py
│ │ │ ├── server/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── server.py
│ │ │ │ ├── task_manager.py
│ │ │ │ └── utils.py
│ │ │ ├── types.py
│ │ │ └── utils/
│ │ │ ├── in_memory_cache.py
│ │ │ └── push_notification_auth.py
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── task_manager.py
│ │ └── utils.py
│ ├── pocketflow-agent/
│ │ ├── README.md
│ │ ├── demo.ipynb
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-agent-skills/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── skills/
│ │ │ ├── checklist_writer.md
│ │ │ └── executive_brief.md
│ │ └── utils.py
│ ├── pocketflow-async-basic/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-batch/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── translations/
│ │ │ ├── README_CHINESE.md
│ │ │ ├── README_FRENCH.md
│ │ │ ├── README_GERMAN.md
│ │ │ ├── README_JAPANESE.md
│ │ │ ├── README_KOREAN.md
│ │ │ ├── README_PORTUGUESE.md
│ │ │ ├── README_RUSSIAN.md
│ │ │ └── README_SPANISH.md
│ │ └── utils.py
│ ├── pocketflow-batch-flow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-batch-node/
│ │ ├── README.md
│ │ ├── data/
│ │ │ └── sales.csv
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-chat/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-chat-guardrail/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-chat-memory/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── call_llm.py
│ │ ├── get_embedding.py
│ │ └── vector_index.py
│ ├── pocketflow-cli-hitl/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-code-generator/
│ │ ├── README.md
│ │ ├── doc/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── call_llm.py
│ │ └── code_executor.py
│ ├── pocketflow-communication/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-fastapi-background/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── static/
│ │ │ ├── index.html
│ │ │ └── progress.html
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-fastapi-hitl/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── server.py
│ │ ├── static/
│ │ │ └── style.css
│ │ ├── templates/
│ │ │ └── index.html
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── process_task.py
│ ├── pocketflow-fastapi-websocket/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── static/
│ │ │ └── index.html
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── stream_llm.py
│ ├── pocketflow-flow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ └── requirements.txt
│ ├── pocketflow-google-calendar/
│ │ ├── .gitignore
│ │ ├── Pipfile
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── google_calendar.py
│ ├── pocketflow-gradio-hitl/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── call_llm.py
│ │ ├── call_mock_api.py
│ │ ├── conversation.py
│ │ └── format_chat_history.py
│ ├── pocketflow-hello-world/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-llm-streaming/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-majority-vote/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-map-reduce/
│ │ ├── README.md
│ │ ├── data/
│ │ │ ├── resume1.txt
│ │ │ ├── resume2.txt
│ │ │ ├── resume3.txt
│ │ │ ├── resume4.txt
│ │ │ └── resume5.txt
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-mcp/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── simple_server.py
│ │ └── utils.py
│ ├── pocketflow-multi-agent/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-nested-batch/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── school/
│ │ ├── class_a/
│ │ │ ├── student1.txt
│ │ │ └── student2.txt
│ │ └── class_b/
│ │ ├── student3.txt
│ │ └── student4.txt
│ ├── pocketflow-node/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ └── call_llm.py
│ ├── pocketflow-parallel-batch/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── translations/
│ │ │ ├── README_CHINESE.md
│ │ │ ├── README_FRENCH.md
│ │ │ ├── README_GERMAN.md
│ │ │ ├── README_JAPANESE.md
│ │ │ ├── README_KOREAN.md
│ │ │ ├── README_PORTUGUESE.md
│ │ │ ├── README_RUSSIAN.md
│ │ │ └── README_SPANISH.md
│ │ └── utils.py
│ ├── pocketflow-parallel-batch-flow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-rag/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-streamlit-fsm/
│ │ ├── README.md
│ │ ├── app.py
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── generate_image.py
│ ├── pocketflow-structured-output/
│ │ ├── README.md
│ │ ├── data.txt
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-supervisor/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-tao/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── utils.py
│ ├── pocketflow-text2sql/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── populate_db.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ └── call_llm.py
│ ├── pocketflow-thinking/
│ │ ├── README.md
│ │ ├── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-tool-crawler/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ ├── crawler.py
│ │ │ └── parser.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tool-database/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ └── database.py
│ │ └── utils/
│ │ └── __init__.py
│ ├── pocketflow-tool-embeddings/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ └── embeddings.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tool-pdf-vision/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ ├── pdf.py
│ │ │ └── vision.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tool-search/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ ├── parser.py
│ │ │ └── search.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tracing/
│ │ ├── README.md
│ │ ├── examples/
│ │ │ ├── async_example.py
│ │ │ └── basic_example.py
│ │ ├── requirements.txt
│ │ ├── setup.py
│ │ ├── test_tracing.py
│ │ ├── tracing/
│ │ │ ├── __init__.py
│ │ │ ├── config.py
│ │ │ ├── core.py
│ │ │ └── decorator.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── setup.py
│ ├── pocketflow-visualization/
│ │ ├── README.md
│ │ ├── async_flow.py
│ │ ├── async_loop_flow.py
│ │ ├── visualize.py
│ │ └── viz/
│ │ ├── flow_visualization.html
│ │ └── flow_visualization.json
│ ├── pocketflow-voice-chat/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── audio_utils.py
│ │ ├── call_llm.py
│ │ ├── speech_to_text.py
│ │ └── text_to_speech.py
│ ├── pocketflow-workflow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ └── call_llm.py
│ └── pocketflow_demo.ipynb
├── docs/
│ ├── _config.yml
│ ├── _includes/
│ │ └── footer_custom.html
│ ├── core_abstraction/
│ │ ├── async.md
│ │ ├── batch.md
│ │ ├── communication.md
│ │ ├── flow.md
│ │ ├── index.md
│ │ ├── node.md
│ │ └── parallel.md
│ ├── design_pattern/
│ │ ├── agent.md
│ │ ├── index.md
│ │ ├── mapreduce.md
│ │ ├── multi_agent.md
│ │ ├── rag.md
│ │ ├── structure.md
│ │ └── workflow.md
│ ├── guide.md
│ ├── index.md
│ └── utility_function/
│ ├── chunking.md
│ ├── embedding.md
│ ├── index.md
│ ├── llm.md
│ ├── text_to_speech.md
│ ├── vector.md
│ ├── viz.md
│ └── websearch.md
├── pocketflow/
│ ├── __init__.py
│ └── __init__.pyi
├── setup.py
├── tests/
│ ├── test_async_batch_flow.py
│ ├── test_async_batch_node.py
│ ├── test_async_flow.py
│ ├── test_async_parallel_batch_flow.py
│ ├── test_async_parallel_batch_node.py
│ ├── test_batch_flow.py
│ ├── test_batch_node.py
│ ├── test_fall_back.py
│ ├── test_flow_basic.py
│ └── test_flow_composition.py
└── utils/
└── update_pocketflow_mdc.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .cursor/rules/core_abstraction/async.mdc
================================================
---
description: Guidelines for using PocketFlow, Core Abstraction, (Advanced) Async
globs:
alwaysApply: false
---
# (Advanced) Async
**Async** Nodes implement `prep_async()`, `exec_async()`, `exec_fallback_async()`, and/or `post_async()`. This is useful for:
1. **prep_async()**: For *fetching/reading data (files, APIs, DB)* in an I/O-friendly way.
2. **exec_async()**: Typically used for async LLM calls.
3. **post_async()**: For *awaiting user feedback*, *coordinating across multi-agents* or any additional async steps after `exec_async()`.
**Note**: `AsyncNode` must be wrapped in `AsyncFlow`. `AsyncFlow` can also include regular (sync) nodes.
### Example
```python
class SummarizeThenVerify(AsyncNode):
async def prep_async(self, shared):
# Example: read a file asynchronously
doc_text = await read_file_async(shared["doc_path"])
return doc_text
async def exec_async(self, prep_res):
# Example: async LLM call
summary = await call_llm_async(f"Summarize: {prep_res}")
return summary
async def post_async(self, shared, prep_res, exec_res):
# Example: wait for user feedback
decision = await gather_user_feedback(exec_res)
if decision == "approve":
shared["summary"] = exec_res
return "approve"
return "deny"
summarize_node = SummarizeThenVerify()
final_node = Finalize()
# Define transitions
summarize_node - "approve" >> final_node
summarize_node - "deny" >> summarize_node # retry
flow = AsyncFlow(start=summarize_node)
async def main():
shared = {"doc_path": "document.txt"}
await flow.run_async(shared)
print("Final Summary:", shared.get("summary"))
asyncio.run(main())
```
================================================
FILE: .cursor/rules/core_abstraction/batch.mdc
================================================
---
description: Guidelines for using PocketFlow, Core Abstraction, Batch
globs:
alwaysApply: false
---
# Batch
**Batch** makes it easier to handle large inputs in one Node or **rerun** a Flow multiple times. Example use cases:
- **Chunk-based** processing (e.g., splitting large texts).
- **Iterative** processing over lists of input items (e.g., user queries, files, URLs).
## 1. BatchNode
A **BatchNode** extends `Node` but changes `prep()` and `exec()`:
- **`prep(shared)`**: returns an **iterable** (e.g., list, generator).
- **`exec(item)`**: called **once** per item in that iterable.
- **`post(shared, prep_res, exec_res_list)`**: after all items are processed, receives a **list** of results (`exec_res_list`) and returns an **Action**.
### Example: Summarize a Large File
```python
class MapSummaries(BatchNode):
def prep(self, shared):
# Suppose we have a big file; chunk it
content = shared["data"]
chunk_size = 10000
chunks = [content[i:i+chunk_size] for i in range(0, len(content), chunk_size)]
return chunks
def exec(self, chunk):
prompt = f"Summarize this chunk in 10 words: {chunk}"
summary = call_llm(prompt)
return summary
def post(self, shared, prep_res, exec_res_list):
combined = "\n".join(exec_res_list)
shared["summary"] = combined
return "default"
map_summaries = MapSummaries()
flow = Flow(start=map_summaries)
flow.run(shared)
```
---
## 2. BatchFlow
A **BatchFlow** runs a **Flow** multiple times, each time with different `params`. Think of it as a loop that replays the Flow for each parameter set.
### Key Differences from BatchNode
**Important**: Unlike BatchNode, which processes items and modifies the shared store:
1. BatchFlow returns **parameters to pass to the child Flow**, not data to process
2. These parameters are accessed in child nodes via `self.params`, not from the shared store
3. Each child Flow runs independently with a different set of parameters
4. Child nodes can be regular Nodes, not BatchNodes (the batching happens at the Flow level)
### Example: Summarize Many Files
```python
class SummarizeAllFiles(BatchFlow):
def prep(self, shared):
# IMPORTANT: Return a list of param dictionaries (not data for processing)
filenames = list(shared["data"].keys()) # e.g., ["file1.txt", "file2.txt", ...]
return [{"filename": fn} for fn in filenames]
# Child node that accesses filename from params, not shared store
class LoadFile(Node):
def prep(self, shared):
# Access filename from params (not from shared)
filename = self.params["filename"] # Important! Use self.params, not shared
return filename
def exec(self, filename):
with open(filename, 'r') as f:
return f.read()
def post(self, shared, prep_res, exec_res):
# Store file content in shared
shared["current_file_content"] = exec_res
return "default"
# Summarize node that works on the currently loaded file
class Summarize(Node):
def prep(self, shared):
return shared["current_file_content"]
def exec(self, content):
prompt = f"Summarize this file in 50 words: {content}"
return call_llm(prompt)
def post(self, shared, prep_res, exec_res):
# Store summary in shared, indexed by current filename
filename = self.params["filename"] # Again, using params
if "summaries" not in shared:
shared["summaries"] = {}
shared["summaries"][filename] = exec_res
return "default"
# Create a per-file flow
load_file = LoadFile()
summarize = Summarize()
load_file >> summarize
summarize_file = Flow(start=load_file)
# Wrap in a BatchFlow to process all files
summarize_all_files = SummarizeAllFiles(start=summarize_file)
summarize_all_files.run(shared)
```
### Under the Hood
1. `prep(shared)` in the BatchFlow returns a list of param dicts—e.g., `[{"filename": "file1.txt"}, {"filename": "file2.txt"}, ...]`.
2. The **BatchFlow** loops through each dict. For each one:
- It merges the dict with the BatchFlow's own `params` (if any): `{**batch_flow.params, **dict_from_prep}`
- It calls `flow.run(shared)` using the merged parameters
- **IMPORTANT**: These parameters are passed to the child Flow's nodes via `self.params`, NOT via the shared store
3. This means the sub-Flow is run **repeatedly**, once for every param dict, with each node in the flow accessing the parameters via `self.params`.
---
## 3. Nested or Multi-Level Batches
You can nest a **BatchFlow** in another **BatchFlow**. For instance:
- **Outer** batch: returns a list of directory param dicts (e.g., `{"directory": "/pathA"}`, `{"directory": "/pathB"}`, ...).
- **Inner** batch: returning a list of per-file param dicts.
At each level, **BatchFlow** merges its own param dict with the parent’s. By the time you reach the **innermost** node, the final `params` is the merged result of **all** parents in the chain. This way, a nested structure can keep track of the entire context (e.g., directory + file name) at once.
```python
class FileBatchFlow(BatchFlow):
def prep(self, shared):
# Access directory from params (set by parent)
directory = self.params["directory"]
# e.g., files = ["file1.txt", "file2.txt", ...]
files = [f for f in os.listdir(directory) if f.endswith(".txt")]
return [{"filename": f} for f in files]
class DirectoryBatchFlow(BatchFlow):
def prep(self, shared):
directories = [ "/path/to/dirA", "/path/to/dirB"]
return [{"directory": d} for d in directories]
# The actual processing node
class ProcessFile(Node):
def prep(self, shared):
# Access both directory and filename from params
directory = self.params["directory"] # From outer batch
filename = self.params["filename"] # From inner batch
full_path = os.path.join(directory, filename)
return full_path
def exec(self, full_path):
# Process the file...
return f"Processed {full_path}"
def post(self, shared, prep_res, exec_res):
# Store results, perhaps indexed by path
if "results" not in shared:
shared["results"] = {}
shared["results"][prep_res] = exec_res
return "default"
# Set up the nested batch structure
process_node = ProcessFile()
inner_flow = FileBatchFlow(start=process_node)
outer_flow = DirectoryBatchFlow(start=inner_flow)
# Run it
outer_flow.run(shared)
```
================================================
FILE: .cursor/rules/core_abstraction/communication.mdc
================================================
---
description: Guidelines for using PocketFlow, Core Abstraction, Communication
globs:
alwaysApply: false
---
# Communication
Nodes and Flows **communicate** in 2 ways:
1. **Shared Store (for almost all the cases)**
- A global data structure (often an in-mem dict) that all nodes can read ( `prep()`) and write (`post()`).
- Great for data results, large content, or anything multiple nodes need.
- You shall design the data structure and populate it ahead.
- > **Separation of Concerns:** Use `Shared Store` for almost all cases to separate *Data Schema* from *Compute Logic*! This approach is both flexible and easy to manage, resulting in more maintainable code. `Params` is more a syntax sugar for [Batch](mdc:./batch.md).
{: .best-practice }
2. **Params (only for [Batch](mdc:./batch.md))**
- Each node has a local, ephemeral `params` dict passed in by the **parent Flow**, used as an identifier for tasks. Parameter keys and values shall be **immutable**.
- Good for identifiers like filenames or numeric IDs, in Batch mode.
If you know memory management, think of the **Shared Store** like a **heap** (shared by all function calls), and **Params** like a **stack** (assigned by the caller).
---
## 1. Shared Store
### Overview
A shared store is typically an in-mem dictionary, like:
```python
shared = {"data": {}, "summary": {}, "config": {...}, ...}
```
It can also contain local file handlers, DB connections, or a combination for persistence. We recommend deciding the data structure or DB schema first based on your app requirements.
### Example
```python
class LoadData(Node):
def post(self, shared, prep_res, exec_res):
# We write data to shared store
shared["data"] = "Some text content"
return None
class Summarize(Node):
def prep(self, shared):
# We read data from shared store
return shared["data"]
def exec(self, prep_res):
# Call LLM to summarize
prompt = f"Summarize: {prep_res}"
summary = call_llm(prompt)
return summary
def post(self, shared, prep_res, exec_res):
# We write summary to shared store
shared["summary"] = exec_res
return "default"
load_data = LoadData()
summarize = Summarize()
load_data >> summarize
flow = Flow(start=load_data)
shared = {}
flow.run(shared)
```
Here:
- `LoadData` writes to `shared["data"]`.
- `Summarize` reads from `shared["data"]`, summarizes, and writes to `shared["summary"]`.
---
## 2. Params
**Params** let you store *per-Node* or *per-Flow* config that doesn't need to live in the shared store. They are:
- **Immutable** during a Node's run cycle (i.e., they don't change mid-`prep->exec->post`).
- **Set** via `set_params()`.
- **Cleared** and updated each time a parent Flow calls it.
> Only set the uppermost Flow params because others will be overwritten by the parent Flow.
>
> If you need to set child node params, see [Batch](mdc:./batch.md).
{: .warning }
Typically, **Params** are identifiers (e.g., file name, page number). Use them to fetch the task you assigned or write to a specific part of the shared store.
### Example
```python
# 1) Create a Node that uses params
class SummarizeFile(Node):
def prep(self, shared):
# Access the node's param
filename = self.params["filename"]
return shared["data"].get(filename, "")
def exec(self, prep_res):
prompt = f"Summarize: {prep_res}"
return call_llm(prompt)
def post(self, shared, prep_res, exec_res):
filename = self.params["filename"]
shared["summary"][filename] = exec_res
return "default"
# 2) Set params
node = SummarizeFile()
# 3) Set Node params directly (for testing)
node.set_params({"filename": "doc1.txt"})
node.run(shared)
# 4) Create Flow
flow = Flow(start=node)
# 5) Set Flow params (overwrites node params)
flow.set_params({"filename": "doc2.txt"})
flow.run(shared) # The node summarizes doc2, not doc1
```
================================================
FILE: .cursor/rules/core_abstraction/flow.mdc
================================================
---
description: Guidelines for using PocketFlow, Core Abstraction, Flow
globs:
alwaysApply: false
---
# Flow
A **Flow** orchestrates a graph of Nodes. You can chain Nodes in a sequence or create branching depending on the **Actions** returned from each Node's `post()`.
## 1. Action-based Transitions
Each Node's `post()` returns an **Action** string. By default, if `post()` doesn't return anything, we treat that as `"default"`.
You define transitions with the syntax:
1. **Basic default transition**: `node_a >> node_b`
This means if `node_a.post()` returns `"default"`, go to `node_b`.
(Equivalent to `node_a - "default" >> node_b`)
2. **Named action transition**: `node_a - "action_name" >> node_b`
This means if `node_a.post()` returns `"action_name"`, go to `node_b`.
It's possible to create loops, branching, or multi-step flows.
## 2. Creating a Flow
A **Flow** begins with a **start** node. You call `Flow(start=some_node)` to specify the entry point. When you call `flow.run(shared)`, it executes the start node, looks at its returned Action from `post()`, follows the transition, and continues until there's no next node.
### Example: Simple Sequence
Here's a minimal flow of two nodes in a chain:
```python
node_a >> node_b
flow = Flow(start=node_a)
flow.run(shared)
```
- When you run the flow, it executes `node_a`.
- Suppose `node_a.post()` returns `"default"`.
- The flow then sees `"default"` Action is linked to `node_b` and runs `node_b`.
- `node_b.post()` returns `"default"` but we didn't define `node_b >> something_else`. So the flow ends there.
### Example: Branching & Looping
Here's a simple expense approval flow that demonstrates branching and looping. The `ReviewExpense` node can return three possible Actions:
- `"approved"`: expense is approved, move to payment processing
- `"needs_revision"`: expense needs changes, send back for revision
- `"rejected"`: expense is denied, finish the process
We can wire them like this:
```python
# Define the flow connections
review - "approved" >> payment # If approved, process payment
review - "needs_revision" >> revise # If needs changes, go to revision
review - "rejected" >> finish # If rejected, finish the process
revise >> review # After revision, go back for another review
payment >> finish # After payment, finish the process
flow = Flow(start=review)
```
Let's see how it flows:
1. If `review.post()` returns `"approved"`, the expense moves to the `payment` node
2. If `review.post()` returns `"needs_revision"`, it goes to the `revise` node, which then loops back to `review`
3. If `review.post()` returns `"rejected"`, it moves to the `finish` node and stops
```mermaid
flowchart TD
review[Review Expense] -->|approved| payment[Process Payment]
review -->|needs_revision| revise[Revise Report]
review -->|rejected| finish[Finish Process]
revise --> review
payment --> finish
```
### Running Individual Nodes vs. Running a Flow
- `node.run(shared)`: Just runs that node alone (calls `prep->exec->post()`), returns an Action.
- `flow.run(shared)`: Executes from the start node, follows Actions to the next node, and so on until the flow can't continue.
> `node.run(shared)` **does not** proceed to the successor.
> This is mainly for debugging or testing a single node.
>
> Always use `flow.run(...)` in production to ensure the full pipeline runs correctly.
{: .warning }
## 3. Nested Flows
A **Flow** can act like a Node, which enables powerful composition patterns. This means you can:
1. Use a Flow as a Node within another Flow's transitions.
2. Combine multiple smaller Flows into a larger Flow for reuse.
3. Node `params` will be a merging of **all** parents' `params`.
### Flow's Node Methods
A **Flow** is also a **Node**, so it will run `prep()` and `post()`. However:
- It **won't** run `exec()`, as its main logic is to orchestrate its nodes.
- `post()` always receives `None` for `exec_res` and should instead get the flow execution results from the shared store.
### Basic Flow Nesting
Here's how to connect a flow to another node:
```python
# Create a sub-flow
node_a >> node_b
subflow = Flow(start=node_a)
# Connect it to another node
subflow >> node_c
# Create the parent flow
parent_flow = Flow(start=subflow)
```
When `parent_flow.run()` executes:
1. It starts `subflow`
2. `subflow` runs through its nodes (`node_a->node_b`)
3. After `subflow` completes, execution continues to `node_c`
### Example: Order Processing Pipeline
Here's a practical example that breaks down order processing into nested flows:
```python
# Payment processing sub-flow
validate_payment >> process_payment >> payment_confirmation
payment_flow = Flow(start=validate_payment)
# Inventory sub-flow
check_stock >> reserve_items >> update_inventory
inventory_flow = Flow(start=check_stock)
# Shipping sub-flow
create_label >> assign_carrier >> schedule_pickup
shipping_flow = Flow(start=create_label)
# Connect the flows into a main order pipeline
payment_flow >> inventory_flow >> shipping_flow
# Create the master flow
order_pipeline = Flow(start=payment_flow)
# Run the entire pipeline
order_pipeline.run(shared_data)
```
This creates a clean separation of concerns while maintaining a clear execution path:
```mermaid
flowchart LR
subgraph order_pipeline[Order Pipeline]
subgraph paymentFlow["Payment Flow"]
A[Validate Payment] --> B[Process Payment] --> C[Payment Confirmation]
end
subgraph inventoryFlow["Inventory Flow"]
D[Check Stock] --> E[Reserve Items] --> F[Update Inventory]
end
subgraph shippingFlow["Shipping Flow"]
G[Create Label] --> H[Assign Carrier] --> I[Schedule Pickup]
end
paymentFlow --> inventoryFlow
inventoryFlow --> shippingFlow
end
```
================================================
FILE: .cursor/rules/core_abstraction/node.mdc
================================================
---
description: Guidelines for using PocketFlow, Core Abstraction, Node
globs:
alwaysApply: false
---
# Node
A **Node** is the smallest building block. Each Node has 3 steps `prep->exec->post`:
1. `prep(shared)`
- **Read and preprocess data** from `shared` store.
- Examples: *query DB, read files, or serialize data into a string*.
- Return `prep_res`, which is used by `exec()` and `post()`.
2. `exec(prep_res)`
- **Execute compute logic**, with optional retries and error handling (below).
- Examples: *(mostly) LLM calls, remote APIs, tool use*.
- ⚠️ This shall be only for compute and **NOT** access `shared`.
- ⚠️ If retries enabled, ensure idempotent implementation.
- ⚠️ Defer exception handling to the Node's built-in retry mechanism.
- Return `exec_res`, which is passed to `post()`.
3. `post(shared, prep_res, exec_res)`
- **Postprocess and write data** back to `shared`.
- Examples: *update DB, change states, log results*.
- **Decide the next action** by returning a *string* (`action = "default"` if *None*).
> **Why 3 steps?** To enforce the principle of *separation of concerns*. The data storage and data processing are operated separately.
>
> All steps are *optional*. E.g., you can only implement `prep` and `post` if you just need to process data.
{: .note }
### Fault Tolerance & Retries
You can **retry** `exec()` if it raises an exception via two parameters when define the Node:
- `max_retries` (int): Max times to run `exec()`. The default is `1` (**no** retry).
- `wait` (int): The time to wait (in **seconds**) before next retry. By default, `wait=0` (no waiting).
`wait` is helpful when you encounter rate-limits or quota errors from your LLM provider and need to back off.
```python
my_node = SummarizeFile(max_retries=3, wait=10)
```
When an exception occurs in `exec()`, the Node automatically retries until:
- It either succeeds, or
- The Node has retried `max_retries - 1` times already and fails on the last attempt.
You can get the current retry times (0-based) from `self.cur_retry`.
```python
class RetryNode(Node):
def exec(self, prep_res):
print(f"Retry {self.cur_retry} times")
raise Exception("Failed")
```
### Graceful Fallback
To **gracefully handle** the exception (after all retries) rather than raising it, override:
```python
def exec_fallback(self, prep_res, exc):
raise exc
```
By default, it just re-raises exception. But you can return a fallback result instead, which becomes the `exec_res` passed to `post()`.
### Example: Summarize file
```python
class SummarizeFile(Node):
def prep(self, shared):
return shared["data"]
def exec(self, prep_res):
if not prep_res:
return "Empty file content"
prompt = f"Summarize this text in 10 words: {prep_res}"
summary = call_llm(prompt) # might fail
return summary
def exec_fallback(self, prep_res, exc):
# Provide a simple fallback instead of crashing
return "There was an error processing your request."
def post(self, shared, prep_res, exec_res):
shared["summary"] = exec_res
# Return "default" by not returning
summarize_node = SummarizeFile(max_retries=3)
# node.run() calls prep->exec->post
# If exec() fails, it retries up to 3 times before calling exec_fallback()
action_result = summarize_node.run(shared)
print("Action returned:", action_result) # "default"
print("Summary stored:", shared["summary"])
```
================================================
FILE: .cursor/rules/core_abstraction/parallel.mdc
================================================
---
description: Guidelines for using PocketFlow, Core Abstraction, (Advanced) Parallel
globs:
alwaysApply: false
---
# (Advanced) Parallel
**Parallel** Nodes and Flows let you run multiple **Async** Nodes and Flows **concurrently**—for example, summarizing multiple texts at once. This can improve performance by overlapping I/O and compute.
> Because of Python’s GIL, parallel nodes and flows can’t truly parallelize CPU-bound tasks (e.g., heavy numerical computations). However, they excel at overlapping I/O-bound work—like LLM calls, database queries, API requests, or file I/O.
{: .warning }
> - **Ensure Tasks Are Independent**: If each item depends on the output of a previous item, **do not** parallelize.
>
> - **Beware of Rate Limits**: Parallel calls can **quickly** trigger rate limits on LLM services. You may need a **throttling** mechanism (e.g., semaphores or sleep intervals).
>
> - **Consider Single-Node Batch APIs**: Some LLMs offer a **batch inference** API where you can send multiple prompts in a single call. This is more complex to implement but can be more efficient than launching many parallel requests and mitigates rate limits.
{: .best-practice }
## AsyncParallelBatchNode
Like **AsyncBatchNode**, but run `exec_async()` in **parallel**:
```python
class ParallelSummaries(AsyncParallelBatchNode):
async def prep_async(self, shared):
# e.g., multiple texts
return shared["texts"]
async def exec_async(self, text):
prompt = f"Summarize: {text}"
return await call_llm_async(prompt)
async def post_async(self, shared, prep_res, exec_res_list):
shared["summary"] = "\n\n".join(exec_res_list)
return "default"
node = ParallelSummaries()
flow = AsyncFlow(start=node)
```
## AsyncParallelBatchFlow
Parallel version of **BatchFlow**. Each iteration of the sub-flow runs **concurrently** using different parameters:
```python
class SummarizeMultipleFiles(AsyncParallelBatchFlow):
async def prep_async(self, shared):
return [{"filename": f} for f in shared["files"]]
sub_flow = AsyncFlow(start=LoadAndSummarizeFile())
parallel_flow = SummarizeMultipleFiles(start=sub_flow)
await parallel_flow.run_async(shared)
```
================================================
FILE: .cursor/rules/design_pattern/agent.mdc
================================================
---
description: Guidelines for using PocketFlow, Design Pattern, Agent
globs:
alwaysApply: false
---
# Agent
Agent is a powerful design pattern in which nodes can take dynamic actions based on the context.
## Implement Agent with Graph
1. **Context and Action:** Implement nodes that supply context and perform actions.
2. **Branching:** Use branching to connect each action node to an agent node. Use action to allow the agent to direct the [flow](../core_abstraction/flow.md) between nodes—and potentially loop back for multi-step.
3. **Agent Node:** Provide a prompt to decide action—for example:
```python
f"""
### CONTEXT
Task: {task_description}
Previous Actions: {previous_actions}
Current State: {current_state}
### ACTION SPACE
[1] search
Description: Use web search to get results
Parameters:
- query (str): What to search for
[2] answer
Description: Conclude based on the results
Parameters:
- result (str): Final answer to provide
### NEXT ACTION
Decide the next action based on the current context and available action space.
Return your response in the following format:
```yaml
thinking: |
action:
parameters:
:
```"""
```
The core of building **high-performance** and **reliable** agents boils down to:
1. **Context Management:** Provide *relevant, minimal context.* For example, rather than including an entire chat history, retrieve the most relevant via [RAG](mdc:./rag.md). Even with larger context windows, LLMs still fall victim to ["lost in the middle"](https://arxiv.org/abs/2307.03172), overlooking mid-prompt content.
2. **Action Space:** Provide *a well-structured and unambiguous* set of actions—avoiding overlap like separate `read_databases` or `read_csvs`. Instead, import CSVs into the database.
## Example Good Action Design
- **Incremental:** Feed content in manageable chunks (500 lines or 1 page) instead of all at once.
- **Overview-zoom-in:** First provide high-level structure (table of contents, summary), then allow drilling into details (raw texts).
- **Parameterized/Programmable:** Instead of fixed actions, enable parameterized (columns to select) or programmable (SQL queries) actions, for example, to read CSV files.
- **Backtracking:** Let the agent undo the last step instead of restarting entirely, preserving progress when encountering errors or dead ends.
## Example: Search Agent
This agent:
1. Decides whether to search or answer
2. If searches, loops back to decide if more search needed
3. Answers when enough context gathered
```python
class DecideAction(Node):
def prep(self, shared):
context = shared.get("context", "No previous search")
query = shared["query"]
return query, context
def exec(self, inputs):
query, context = inputs
prompt = f"""
Given input: {query}
Previous search results: {context}
Should I: 1) Search web for more info 2) Answer with current knowledge
Output in yaml:
```yaml
action: search/answer
reason: why this action
search_term: search phrase if action is search
```"""
resp = call_llm(prompt)
yaml_str = resp.split("```yaml")[1].split("```")[0].strip()
result = yaml.safe_load(yaml_str)
assert isinstance(result, dict)
assert "action" in result
assert "reason" in result
assert result["action"] in ["search", "answer"]
if result["action"] == "search":
assert "search_term" in result
return result
def post(self, shared, prep_res, exec_res):
if exec_res["action"] == "search":
shared["search_term"] = exec_res["search_term"]
return exec_res["action"]
class SearchWeb(Node):
def prep(self, shared):
return shared["search_term"]
def exec(self, search_term):
return search_web(search_term)
def post(self, shared, prep_res, exec_res):
prev_searches = shared.get("context", [])
shared["context"] = prev_searches + [
{"term": shared["search_term"], "result": exec_res}
]
return "decide"
class DirectAnswer(Node):
def prep(self, shared):
return shared["query"], shared.get("context", "")
def exec(self, inputs):
query, context = inputs
return call_llm(f"Context: {context}\nAnswer: {query}")
def post(self, shared, prep_res, exec_res):
print(f"Answer: {exec_res}")
shared["answer"] = exec_res
# Connect nodes
decide = DecideAction()
search = SearchWeb()
answer = DirectAnswer()
decide - "search" >> search
decide - "answer" >> answer
search - "decide" >> decide # Loop back
flow = Flow(start=decide)
flow.run({"query": "Who won the Nobel Prize in Physics 2024?"})
```
================================================
FILE: .cursor/rules/design_pattern/mapreduce.mdc
================================================
---
description: Guidelines for using PocketFlow, Design Pattern, Map Reduce
globs:
alwaysApply: false
---
# Map Reduce
MapReduce is a design pattern suitable when you have either:
- Large input data (e.g., multiple files to process), or
- Large output data (e.g., multiple forms to fill)
and there is a logical way to break the task into smaller, ideally independent parts.
You first break down the task using [BatchNode](../core_abstraction/batch.md) in the map phase, followed by aggregation in the reduce phase.
### Example: Document Summarization
```python
class SummarizeAllFiles(BatchNode):
def prep(self, shared):
files_dict = shared["files"] # e.g. 10 files
return list(files_dict.items()) # [("file1.txt", "aaa..."), ("file2.txt", "bbb..."), ...]
def exec(self, one_file):
filename, file_content = one_file
summary_text = call_llm(f"Summarize the following file:\n{file_content}")
return (filename, summary_text)
def post(self, shared, prep_res, exec_res_list):
shared["file_summaries"] = dict(exec_res_list)
class CombineSummaries(Node):
def prep(self, shared):
return shared["file_summaries"]
def exec(self, file_summaries):
# format as: "File1: summary\nFile2: summary...\n"
text_list = []
for fname, summ in file_summaries.items():
text_list.append(f"{fname} summary:\n{summ}\n")
big_text = "\n---\n".join(text_list)
return call_llm(f"Combine these file summaries into one final summary:\n{big_text}")
def post(self, shared, prep_res, final_summary):
shared["all_files_summary"] = final_summary
batch_node = SummarizeAllFiles()
combine_node = CombineSummaries()
batch_node >> combine_node
flow = Flow(start=batch_node)
shared = {
"files": {
"file1.txt": "Alice was beginning to get very tired of sitting by her sister...",
"file2.txt": "Some other interesting text ...",
# ...
}
}
flow.run(shared)
print("Individual Summaries:", shared["file_summaries"])
print("\nFinal Summary:\n", shared["all_files_summary"])
```
> **Performance Tip**: The example above works sequentially. You can speed up the map phase by running it in parallel. See [(Advanced) Parallel](../core_abstraction/parallel.md) for more details.
{: .note }
================================================
FILE: .cursor/rules/design_pattern/multi_agent.mdc
================================================
---
description: Guidelines for using PocketFlow, Design Pattern, (Advanced) Multi-Agents
globs:
alwaysApply: false
---
# (Advanced) Multi-Agents
Multiple [Agents](mdc:./flow.md) can work together by handling subtasks and communicating the progress.
Communication between agents is typically implemented using message queues in shared storage.
> Most of time, you don't need Multi-Agents. Start with a simple solution first.
{: .best-practice }
### Example Agent Communication: Message Queue
Here's a simple example showing how to implement agent communication using `asyncio.Queue`.
The agent listens for messages, processes them, and continues listening:
```python
class AgentNode(AsyncNode):
async def prep_async(self, _):
message_queue = self.params["messages"]
message = await message_queue.get()
print(f"Agent received: {message}")
return message
# Create node and flow
agent = AgentNode()
agent >> agent # connect to self
flow = AsyncFlow(start=agent)
# Create heartbeat sender
async def send_system_messages(message_queue):
counter = 0
messages = [
"System status: all systems operational",
"Memory usage: normal",
"Network connectivity: stable",
"Processing load: optimal"
]
while True:
message = f"{messages[counter % len(messages)]} | timestamp_{counter}"
await message_queue.put(message)
counter += 1
await asyncio.sleep(1)
async def main():
message_queue = asyncio.Queue()
shared = {}
flow.set_params({"messages": message_queue})
# Run both coroutines
await asyncio.gather(
flow.run_async(shared),
send_system_messages(message_queue)
)
asyncio.run(main())
```
The output:
```
Agent received: System status: all systems operational | timestamp_0
Agent received: Memory usage: normal | timestamp_1
Agent received: Network connectivity: stable | timestamp_2
Agent received: Processing load: optimal | timestamp_3
```
### Interactive Multi-Agent Example: Taboo Game
Here's a more complex example where two agents play the word-guessing game Taboo.
One agent provides hints while avoiding forbidden words, and another agent tries to guess the target word:
```python
class AsyncHinter(AsyncNode):
async def prep_async(self, shared):
guess = await shared["hinter_queue"].get()
if guess == "GAME_OVER":
return None
return shared["target_word"], shared["forbidden_words"], shared.get("past_guesses", [])
async def exec_async(self, inputs):
if inputs is None:
return None
target, forbidden, past_guesses = inputs
prompt = f"Generate hint for '{target}'\nForbidden words: {forbidden}"
if past_guesses:
prompt += f"\nPrevious wrong guesses: {past_guesses}\nMake hint more specific."
prompt += "\nUse at most 5 words."
hint = call_llm(prompt)
print(f"\nHinter: Here's your hint - {hint}")
return hint
async def post_async(self, shared, prep_res, exec_res):
if exec_res is None:
return "end"
await shared["guesser_queue"].put(exec_res)
return "continue"
class AsyncGuesser(AsyncNode):
async def prep_async(self, shared):
hint = await shared["guesser_queue"].get()
return hint, shared.get("past_guesses", [])
async def exec_async(self, inputs):
hint, past_guesses = inputs
prompt = f"Given hint: {hint}, past wrong guesses: {past_guesses}, make a new guess. Directly reply a single word:"
guess = call_llm(prompt)
print(f"Guesser: I guess it's - {guess}")
return guess
async def post_async(self, shared, prep_res, exec_res):
if exec_res.lower() == shared["target_word"].lower():
print("Game Over - Correct guess!")
await shared["hinter_queue"].put("GAME_OVER")
return "end"
if "past_guesses" not in shared:
shared["past_guesses"] = []
shared["past_guesses"].append(exec_res)
await shared["hinter_queue"].put(exec_res)
return "continue"
async def main():
# Set up game
shared = {
"target_word": "nostalgia",
"forbidden_words": ["memory", "past", "remember", "feeling", "longing"],
"hinter_queue": asyncio.Queue(),
"guesser_queue": asyncio.Queue()
}
print("Game starting!")
print(f"Target word: {shared['target_word']}")
print(f"Forbidden words: {shared['forbidden_words']}")
# Initialize by sending empty guess to hinter
await shared["hinter_queue"].put("")
# Create nodes and flows
hinter = AsyncHinter()
guesser = AsyncGuesser()
# Set up flows
hinter_flow = AsyncFlow(start=hinter)
guesser_flow = AsyncFlow(start=guesser)
# Connect nodes to themselves
hinter - "continue" >> hinter
guesser - "continue" >> guesser
# Run both agents concurrently
await asyncio.gather(
hinter_flow.run_async(shared),
guesser_flow.run_async(shared)
)
asyncio.run(main())
```
The Output:
```
Game starting!
Target word: nostalgia
Forbidden words: ['memory', 'past', 'remember', 'feeling', 'longing']
Hinter: Here's your hint - Thinking of childhood summer days
Guesser: I guess it's - popsicle
Hinter: Here's your hint - When childhood cartoons make you emotional
Guesser: I guess it's - nostalgic
Hinter: Here's your hint - When old songs move you
Guesser: I guess it's - memories
Hinter: Here's your hint - That warm emotion about childhood
Guesser: I guess it's - nostalgia
Game Over - Correct guess!
```
================================================
FILE: .cursor/rules/design_pattern/rag.mdc
================================================
---
description: Guidelines for using PocketFlow, Design Pattern, RAG
globs:
alwaysApply: false
---
# RAG (Retrieval Augmented Generation)
For certain LLM tasks like answering questions, providing relevant context is essential. One common architecture is a **two-stage** RAG pipeline:
1. **Offline stage**: Preprocess and index documents ("building the index").
2. **Online stage**: Given a question, generate answers by retrieving the most relevant context.
---
## Stage 1: Offline Indexing
We create three Nodes:
1. `ChunkDocs` – [chunks](../utility_function/chunking.md) raw text.
2. `EmbedDocs` – [embeds](../utility_function/embedding.md) each chunk.
3. `StoreIndex` – stores embeddings into a [vector database](../utility_function/vector.md).
```python
class ChunkDocs(BatchNode):
def prep(self, shared):
# A list of file paths in shared["files"]. We process each file.
return shared["files"]
def exec(self, filepath):
# read file content. In real usage, do error handling.
with open(filepath, "r", encoding="utf-8") as f:
text = f.read()
# chunk by 100 chars each
chunks = []
size = 100
for i in range(0, len(text), size):
chunks.append(text[i : i + size])
return chunks
def post(self, shared, prep_res, exec_res_list):
# exec_res_list is a list of chunk-lists, one per file.
# flatten them all into a single list of chunks.
all_chunks = []
for chunk_list in exec_res_list:
all_chunks.extend(chunk_list)
shared["all_chunks"] = all_chunks
class EmbedDocs(BatchNode):
def prep(self, shared):
return shared["all_chunks"]
def exec(self, chunk):
return get_embedding(chunk)
def post(self, shared, prep_res, exec_res_list):
# Store the list of embeddings.
shared["all_embeds"] = exec_res_list
print(f"Total embeddings: {len(exec_res_list)}")
class StoreIndex(Node):
def prep(self, shared):
# We'll read all embeds from shared.
return shared["all_embeds"]
def exec(self, all_embeds):
# Create a vector index (faiss or other DB in real usage).
index = create_index(all_embeds)
return index
def post(self, shared, prep_res, index):
shared["index"] = index
# Wire them in sequence
chunk_node = ChunkDocs()
embed_node = EmbedDocs()
store_node = StoreIndex()
chunk_node >> embed_node >> store_node
OfflineFlow = Flow(start=chunk_node)
```
Usage example:
```python
shared = {
"files": ["doc1.txt", "doc2.txt"], # any text files
}
OfflineFlow.run(shared)
```
---
## Stage 2: Online Query & Answer
We have 3 nodes:
1. `EmbedQuery` – embeds the user’s question.
2. `RetrieveDocs` – retrieves top chunk from the index.
3. `GenerateAnswer` – calls the LLM with the question + chunk to produce the final answer.
```python
class EmbedQuery(Node):
def prep(self, shared):
return shared["question"]
def exec(self, question):
return get_embedding(question)
def post(self, shared, prep_res, q_emb):
shared["q_emb"] = q_emb
class RetrieveDocs(Node):
def prep(self, shared):
# We'll need the query embedding, plus the offline index/chunks
return shared["q_emb"], shared["index"], shared["all_chunks"]
def exec(self, inputs):
q_emb, index, chunks = inputs
I, D = search_index(index, q_emb, top_k=1)
best_id = I[0][0]
relevant_chunk = chunks[best_id]
return relevant_chunk
def post(self, shared, prep_res, relevant_chunk):
shared["retrieved_chunk"] = relevant_chunk
print("Retrieved chunk:", relevant_chunk[:60], "...")
class GenerateAnswer(Node):
def prep(self, shared):
return shared["question"], shared["retrieved_chunk"]
def exec(self, inputs):
question, chunk = inputs
prompt = f"Question: {question}\nContext: {chunk}\nAnswer:"
return call_llm(prompt)
def post(self, shared, prep_res, answer):
shared["answer"] = answer
print("Answer:", answer)
embed_qnode = EmbedQuery()
retrieve_node = RetrieveDocs()
generate_node = GenerateAnswer()
embed_qnode >> retrieve_node >> generate_node
OnlineFlow = Flow(start=embed_qnode)
```
Usage example:
```python
# Suppose we already ran OfflineFlow and have:
# shared["all_chunks"], shared["index"], etc.
shared["question"] = "Why do people like cats?"
OnlineFlow.run(shared)
# final answer in shared["answer"]
```
================================================
FILE: .cursor/rules/design_pattern/structure.mdc
================================================
---
description: Guidelines for using PocketFlow, Design Pattern, Structured Output
globs:
alwaysApply: false
---
# Structured Output
In many use cases, you may want the LLM to output a specific structure, such as a list or a dictionary with predefined keys.
There are several approaches to achieve a structured output:
- **Prompting** the LLM to strictly return a defined structure.
- Using LLMs that natively support **schema enforcement**.
- **Post-processing** the LLM's response to extract structured content.
In practice, **Prompting** is simple and reliable for modern LLMs.
### Example Use Cases
- Extracting Key Information
```yaml
product:
name: Widget Pro
price: 199.99
description: |
A high-quality widget designed for professionals.
Recommended for advanced users.
```
- Summarizing Documents into Bullet Points
```yaml
summary:
- This product is easy to use.
- It is cost-effective.
- Suitable for all skill levels.
```
- Generating Configuration Files
```yaml
server:
host: 127.0.0.1
port: 8080
ssl: true
```
## Prompt Engineering
When prompting the LLM to produce **structured** output:
1. **Wrap** the structure in code fences (e.g., `yaml`).
2. **Validate** that all required fields exist (and let `Node` handles retry).
### Example Text Summarization
```python
class SummarizeNode(Node):
def exec(self, prep_res):
# Suppose `prep_res` is the text to summarize.
prompt = f"""
Please summarize the following text as YAML, with exactly 3 bullet points
{prep_res}
Now, output:
```yaml
summary:
- bullet 1
- bullet 2
- bullet 3
```"""
response = call_llm(prompt)
yaml_str = response.split("```yaml")[1].split("```")[0].strip()
import yaml
structured_result = yaml.safe_load(yaml_str)
assert "summary" in structured_result
assert isinstance(structured_result["summary"], list)
return structured_result
```
> Besides using `assert` statements, another popular way to validate schemas is [Pydantic](https://github.com/pydantic/pydantic)
{: .note }
### Why YAML instead of JSON?
Current LLMs struggle with escaping. YAML is easier with strings since they don't always need quotes.
**In JSON**
```json
{
"dialogue": "Alice said: \"Hello Bob.\\nHow are you?\\nI am good.\""
}
```
- Every double quote inside the string must be escaped with `\"`.
- Each newline in the dialogue must be represented as `\n`.
**In YAML**
```yaml
dialogue: |
Alice said: "Hello Bob.
How are you?
I am good."
```
- No need to escape interior quotes—just place the entire text under a block literal (`|`).
- Newlines are naturally preserved without needing `\n`.
================================================
FILE: .cursor/rules/design_pattern/workflow.mdc
================================================
---
description: Guidelines for using PocketFlow, Design Pattern, Workflow
globs:
alwaysApply: false
---
# Workflow
Many real-world tasks are too complex for one LLM call. The solution is to **Task Decomposition**: decompose them into a [chain](../core_abstraction/flow.md) of multiple Nodes.
> - You don't want to make each task **too coarse**, because it may be *too complex for one LLM call*.
> - You don't want to make each task **too granular**, because then *the LLM call doesn't have enough context* and results are *not consistent across nodes*.
>
> You usually need multiple *iterations* to find the *sweet spot*. If the task has too many *edge cases*, consider using [Agents](mdc:./agent.md).
{: .best-practice }
### Example: Article Writing
```python
class GenerateOutline(Node):
def prep(self, shared): return shared["topic"]
def exec(self, topic): return call_llm(f"Create a detailed outline for an article about {topic}")
def post(self, shared, prep_res, exec_res): shared["outline"] = exec_res
class WriteSection(Node):
def prep(self, shared): return shared["outline"]
def exec(self, outline): return call_llm(f"Write content based on this outline: {outline}")
def post(self, shared, prep_res, exec_res): shared["draft"] = exec_res
class ReviewAndRefine(Node):
def prep(self, shared): return shared["draft"]
def exec(self, draft): return call_llm(f"Review and improve this draft: {draft}")
def post(self, shared, prep_res, exec_res): shared["final_article"] = exec_res
# Connect nodes
outline = GenerateOutline()
write = WriteSection()
review = ReviewAndRefine()
outline >> write >> review
# Create and run flow
writing_flow = Flow(start=outline)
shared = {"topic": "AI Safety"}
writing_flow.run(shared)
```
For *dynamic cases*, consider using [Agents](mdc:./agent.md).
================================================
FILE: .cursor/rules/guide_for_pocketflow.mdc
================================================
---
description: Guidelines for using PocketFlow, Agentic Coding
globs: **/*.py
alwaysApply: true
---
# DOCUMENTATION FIRST POLICY
**CRITICAL INSTRUCTION**: When implementing a Pocket Flow app:
1. **ALWAYS REQUEST MDC FILES FIRST** - Before writing any code, request and review all relevant MDC documentation files. This doc provides an explaination of the documents.
2. **UNDERSTAND THE FRAMEWORK** - Gain comprehensive understanding of the Pocket Flow framework from documentation
3. **AVOID ASSUMPTION-DRIVEN DEVELOPMENT** - Do not base your implementation on assumptions or guesswork. Even if the human didn't explicitly mention pocket flow in their request, if the code you are editing is using pocket flow, you should request relevant docs to help you understand best practice as well before editing.
**VERIFICATION**: Begin each implementation with a brief summary of the documentation you've reviewed to inform your approach.
# Agentic Coding: Humans Design, Agents code!
> If you are an AI agent involved in building LLM Systems, read this guide **VERY, VERY** carefully! This is the most important chapter in the entire document. Throughout development, you should always (1) start with a small and simple solution, (2) design at a high level (`docs/design.md`) before implementation, and (3) frequently ask humans for feedback and clarification.
{: .warning }
## Agentic Coding Steps
Agentic Coding should be a collaboration between Human System Design and Agent Implementation:
| Steps | Human | AI | Comment |
|:-----------------------|:----------:|:---------:|:------------------------------------------------------------------------|
| 1. Requirements | ★★★ High | ★☆☆ Low | Humans understand the requirements and context. |
| 2. Flow | ★★☆ Medium | ★★☆ Medium | Humans specify the high-level design, and the AI fills in the details. |
| 3. Utilities | ★★☆ Medium | ★★☆ Medium | Humans provide available external APIs and integrations, and the AI helps with implementation. |
| 4. Data | ★☆☆ Low | ★★★ High | AI designs the data schema, and humans verify. |
| 5. Node | ★☆☆ Low | ★★★ High | The AI helps design the node based on the flow. |
| 6. Implementation | ★☆☆ Low | ★★★ High | The AI implements the flow based on the design. |
| 7. Optimization | ★★☆ Medium | ★★☆ Medium | Humans evaluate the results, and the AI helps optimize. |
| 8. Reliability | ★☆☆ Low | ★★★ High | The AI writes test cases and addresses corner cases. |
1. **Requirements**: Clarify the requirements for your project, and evaluate whether an AI system is a good fit.
- Understand AI systems' strengths and limitations:
- **Good for**: Routine tasks requiring common sense (filling forms, replying to emails)
- **Good for**: Creative tasks with well-defined inputs (building slides, writing SQL)
- **Not good for**: Ambiguous problems requiring complex decision-making (business strategy, startup planning)
- **Keep It User-Centric:** Explain the "problem" from the user's perspective rather than just listing features.
- **Balance complexity vs. impact**: Aim to deliver the highest value features with minimal complexity early.
2. **Flow Design**: Outline at a high level, describe how your AI system orchestrates nodes.
- Identify applicable design patterns (e.g., [Map Reduce], [Agent], [RAG]).
- For each node in the flow, start with a high-level one-line description of what it does.
- If using **Map Reduce**, specify how to map (what to split) and how to reduce (how to combine).
- If using **Agent**, specify what are the inputs (context) and what are the possible actions.
- If using **RAG**, specify what to embed, noting that there's usually both offline (indexing) and online (retrieval) workflows.
- Outline the flow and draw it in a mermaid diagram. For example:
```mermaid
flowchart LR
start[Start] --> batch[Batch]
batch --> check[Check]
check -->|OK| process
check -->|Error| fix[Fix]
fix --> check
subgraph process[Process]
step1[Step 1] --> step2[Step 2]
end
process --> endNode[End]
```
- > **If Humans can't specify the flow, AI Agents can't automate it!** Before building an LLM system, thoroughly understand the problem and potential solution by manually solving example inputs to develop intuition.
{: .best-practice }
3. **Utilities**: Based on the Flow Design, identify and implement necessary utility functions.
- Think of your AI system as the brain. It needs a body—these *external utility functions*—to interact with the real world:
- Reading inputs (e.g., retrieving Slack messages, reading emails)
- Writing outputs (e.g., generating reports, sending emails)
- Using external tools (e.g., calling LLMs, searching the web)
- **NOTE**: *LLM-based tasks* (e.g., summarizing text, analyzing sentiment) are **NOT** utility functions; rather, they are *core functions* internal in the AI system.
- For each utility function, implement it and write a simple test.
- Document their input/output, as well as why they are necessary. For example:
- `name`: `get_embedding` (`utils/get_embedding.py`)
- `input`: `str`
- `output`: a vector of 3072 floats
- `necessity`: Used by the second node to embed text
- Example utility implementation:
```python
# utils/call_llm.py
from openai import OpenAI
def call_llm(prompt):
client = OpenAI(api_key="YOUR_API_KEY_HERE")
r = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
if __name__ == "__main__":
prompt = "What is the meaning of life?"
print(call_llm(prompt))
```
- > **Sometimes, design Utilities before Flow:** For example, for an LLM project to automate a legacy system, the bottleneck will likely be the available interface to that system. Start by designing the hardest utilities for interfacing, and then build the flow around them.
{: .best-practice }
- > **Avoid Exception Handling in Utilities**: If a utility function is called from a Node's `exec()` method, avoid using `try...except` blocks within the utility. Let the Node's built-in retry mechanism handle failures.
{: .warning }
4. **Data Design**: Design the shared store that nodes will use to communicate.
- One core design principle for PocketFlow is to use a well-designed [shared store]—a data contract that all nodes agree upon to retrieve and store data.
- For simple systems, use an in-memory dictionary.
- For more complex systems or when persistence is required, use a database.
- **Don't Repeat Yourself**: Use in-memory references or foreign keys.
- Example shared store design:
```python
shared = {
"user": {
"id": "user123",
"context": { # Another nested dict
"weather": {"temp": 72, "condition": "sunny"},
"location": "San Francisco"
}
},
"results": {} # Empty dict to store outputs
}
```
5. **Node Design**: Plan how each node will read and write data, and use utility functions.
- For each [Node], describe its type, how it reads and writes data, and which utility function it uses. Keep it specific but high-level without codes. For example:
- `type`: Regular (or Batch, or Async)
- `prep`: Read "text" from the shared store
- `exec`: Call the embedding utility function. **Avoid exception handling here**; let the Node's retry mechanism manage failures.
- `post`: Write "embedding" to the shared store
6. **Implementation**: Implement the initial nodes and flows based on the design.
- 🎉 If you've reached this step, humans have finished the design. Now *Agentic Coding* begins!
- **"Keep it simple, stupid!"** Avoid complex features and full-scale type checking.
- **FAIL FAST**! Leverage the built-in [Node] retry and fallback mechanisms to handle failures gracefully. This helps you quickly identify weak points in the system.
- Add logging throughout the code to facilitate debugging.
7. **Optimization**:
- **Use Intuition**: For a quick initial evaluation, human intuition is often a good start.
- **Redesign Flow (Back to Step 3)**: Consider breaking down tasks further, introducing agentic decisions, or better managing input contexts.
- If your flow design is already solid, move on to micro-optimizations:
- **Prompt Engineering**: Use clear, specific instructions with examples to reduce ambiguity.
- **In-Context Learning**: Provide robust examples for tasks that are difficult to specify with instructions alone.
- > **You'll likely iterate a lot!** Expect to repeat Steps 3–6 hundreds of times.
>
>
{: .best-practice }
8. **Reliability**
- **Node Retries**: Add checks in the node `exec` to ensure outputs meet requirements, and consider increasing `max_retries` and `wait` times.
- **Logging and Visualization**: Maintain logs of all attempts and visualize node results for easier debugging.
- **Self-Evaluation**: Add a separate node (powered by an LLM) to review outputs when results are uncertain.
## Example LLM Project File Structure
```
my_project/
├── main.py
├── nodes.py
├── flow.py
├── utils/
│ ├── __init__.py
│ ├── call_llm.py
│ └── search_web.py
├── requirements.txt
└── docs/
└── design.md
```
- **`docs/design.md`**: Contains project documentation for each step above. This should be *high-level* and *no-code*.
- **`utils/`**: Contains all utility functions.
- It's recommended to dedicate one Python file to each API call, for example `call_llm.py` or `search_web.py`.
- Each file should also include a `main()` function to try that API call
- **`nodes.py`**: Contains all the node definitions.
```python
# nodes.py
from pocketflow import Node
from utils.call_llm import call_llm
class GetQuestionNode(Node):
def exec(self, _):
# Get question directly from user input
user_question = input("Enter your question: ")
return user_question
def post(self, shared, prep_res, exec_res):
# Store the user's question
shared["question"] = exec_res
return "default" # Go to the next node
class AnswerNode(Node):
def prep(self, shared):
# Read question from shared
return shared["question"]
def exec(self, question):
# Call LLM to get the answer
return call_llm(question)
def post(self, shared, prep_res, exec_res):
# Store the answer in shared
shared["answer"] = exec_res
```
- **`flow.py`**: Implements functions that create flows by importing node definitions and connecting them.
```python
# flow.py
from pocketflow import Flow
from nodes import GetQuestionNode, AnswerNode
def create_qa_flow():
"""Create and return a question-answering flow."""
# Create nodes
get_question_node = GetQuestionNode()
answer_node = AnswerNode()
# Connect nodes in sequence
get_question_node >> answer_node
# Create flow starting with input node
return Flow(start=get_question_node)
```
- **`main.py`**: Serves as the project's entry point.
```python
# main.py
from flow import create_qa_flow
# Example main function
# Please replace this with your own main function
def main():
shared = {
"question": None, # Will be populated by GetQuestionNode from user input
"answer": None # Will be populated by AnswerNode
}
# Create the flow and run it
qa_flow = create_qa_flow()
qa_flow.run(shared)
print(f"Question: {shared['question']}")
print(f"Answer: {shared['answer']}")
if __name__ == "__main__":
main()
```
# Pocket Flow
A [100-line](https://github.com/the-pocket/PocketFlow/blob/main/pocketflow/__init__.py) minimalist LLM framework for *Agents, Task Decomposition, RAG, etc*.
- **Lightweight**: Just the core graph abstraction in 100 lines. ZERO dependencies, and vendor lock-in.
- **Expressive**: Everything you love from larger frameworks—([Multi-])[Agents], [Workflow], [RAG], and more.
- **Agentic-Coding**: Intuitive enough for AI agents to help humans build complex LLM applications.
## Core Abstraction
We model the LLM workflow as a **Graph + Shared Store**:
- [Node] handles simple (LLM) tasks.
- [Flow] connects nodes through **Actions** (labeled edges).
- [Shared Store] enables communication between nodes within flows.
- [Batch] nodes/flows allow for data-intensive tasks.
- [Async] nodes/flows allow waiting for asynchronous tasks.
- [(Advanced) Parallel] nodes/flows handle I/O-bound tasks.
## Design Pattern
From there, it’s easy to implement popular design patterns:
- [Agent] autonomously makes decisions.
- [Workflow] chains multiple tasks into pipelines.
- [RAG] integrates data retrieval with generation.
- [Map Reduce] splits data tasks into Map and Reduce steps.
- [Structured Output] formats outputs consistently.
- [(Advanced) Multi-Agents] coordinate multiple agents.
## Utility Function
We **do not** provide built-in utilities. Instead, we offer *examples*—please *implement your own*:
- [LLM Wrapper]
- [Viz and Debug]
- [Web Search]
- [Chunking]
- [Embedding]
- [Vector Databases]
- [Text-to-Speech]
**Why not built-in?**: I believe it's a *bad practice* for vendor-specific APIs in a general framework:
- *API Volatility*: Frequent changes lead to heavy maintenance for hardcoded APIs.
- *Flexibility*: You may want to switch vendors, use fine-tuned models, or run them locally.
- *Optimizations*: Prompt caching, batching, and streaming are easier without vendor lock-in.
## Ready to build your Apps?
Check out [Agentic Coding Guidance], the fastest way to develop LLM projects with Pocket Flow!
================================================
FILE: .cursor/rules/utility_function/chunking.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, Text Chunking
globs:
alwaysApply: false
---
# Text Chunking
We recommend some implementations of commonly used text chunking approaches.
> Text Chunking is more a micro optimization, compared to the Flow Design.
>
> It's recommended to start with the Naive Chunking and optimize later.
{: .best-practice }
---
## Example Python Code Samples
### 1. Naive (Fixed-Size) Chunking
Splits text by a fixed number of words, ignoring sentence or semantic boundaries.
```python
def fixed_size_chunk(text, chunk_size=100):
chunks = []
for i in range(0, len(text), chunk_size):
chunks.append(text[i : i + chunk_size])
return chunks
```
However, sentences are often cut awkwardly, losing coherence.
### 2. Sentence-Based Chunking
```python
import nltk
def sentence_based_chunk(text, max_sentences=2):
sentences = nltk.sent_tokenize(text)
chunks = []
for i in range(0, len(sentences), max_sentences):
chunks.append(" ".join(sentences[i : i + max_sentences]))
return chunks
```
However, might not handle very long sentences or paragraphs well.
### 3. Other Chunking
- **Paragraph-Based**: Split text by paragraphs (e.g., newlines). Large paragraphs can create big chunks.
- **Semantic**: Use embeddings or topic modeling to chunk by semantic boundaries.
- **Agentic**: Use an LLM to decide chunk boundaries based on context or meaning.
================================================
FILE: .cursor/rules/utility_function/embedding.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, Embedding
globs:
alwaysApply: false
---
# Embedding
Below you will find an overview table of various text embedding APIs, along with example Python code.
> Embedding is more a micro optimization, compared to the Flow Design.
>
> It's recommended to start with the most convenient one and optimize later.
{: .best-practice }
| **API** | **Free Tier** | **Pricing Model** | **Docs** |
| --- | --- | --- | --- |
| **OpenAI** | ~$5 credit | ~$0.0001/1K tokens | [OpenAI Embeddings](https://platform.openai.com/docs/api-reference/embeddings) |
| **Azure OpenAI** | $200 credit | Same as OpenAI (~$0.0001/1K tokens) | [Azure OpenAI Embeddings](https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource?tabs=portal) |
| **Google Vertex AI** | $300 credit | ~$0.025 / million chars | [Vertex AI Embeddings](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings) |
| **AWS Bedrock** | No free tier, but AWS credits may apply | ~$0.00002/1K tokens (Titan V2) | [Amazon Bedrock](https://docs.aws.amazon.com/bedrock/) |
| **Cohere** | Limited free tier | ~$0.0001/1K tokens | [Cohere Embeddings](https://docs.cohere.com/docs/cohere-embed) |
| **Hugging Face** | ~$0.10 free compute monthly | Pay per second of compute | [HF Inference API](https://huggingface.co/docs/api-inference) |
| **Jina** | 1M tokens free | Pay per token after | [Jina Embeddings](https://jina.ai/embeddings/) |
## Example Python Code
### 1. OpenAI
```python
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY")
response = client.embeddings.create(
model="text-embedding-ada-002",
input=text
)
# Extract the embedding vector from the response
embedding = response.data[0].embedding
embedding = np.array(embedding, dtype=np.float32)
print(embedding)
```
### 2. Azure OpenAI
```python
import openai
openai.api_type = "azure"
openai.api_base = "https://YOUR_RESOURCE_NAME.openai.azure.com"
openai.api_version = "2023-03-15-preview"
openai.api_key = "YOUR_AZURE_API_KEY"
resp = openai.Embedding.create(engine="ada-embedding", input="Hello world")
vec = resp["data"][0]["embedding"]
print(vec)
```
### 3. Google Vertex AI
```python
from vertexai.preview.language_models import TextEmbeddingModel
import vertexai
vertexai.init(project="YOUR_GCP_PROJECT_ID", location="us-central1")
model = TextEmbeddingModel.from_pretrained("textembedding-gecko@001")
emb = model.get_embeddings(["Hello world"])
print(emb[0])
```
### 4. AWS Bedrock
```python
import boto3, json
client = boto3.client("bedrock-runtime", region_name="us-east-1")
body = {"inputText": "Hello world"}
resp = client.invoke_model(modelId="amazon.titan-embed-text-v2:0", contentType="application/json", body=json.dumps(body))
resp_body = json.loads(resp["body"].read())
vec = resp_body["embedding"]
print(vec)
```
### 5. Cohere
```python
import cohere
co = cohere.Client("YOUR_API_KEY")
resp = co.embed(texts=["Hello world"])
vec = resp.embeddings[0]
print(vec)
```
### 6. Hugging Face
```python
import requests
API_URL = "https://api-inference.huggingface.co/models/sentence-transformers/all-MiniLM-L6-v2"
HEADERS = {"Authorization": "Bearer YOUR_HF_TOKEN"}
res = requests.post(API_URL, headers=HEADERS, json={"inputs": "Hello world"})
vec = res.json()[0]
print(vec)
```
### 7. Jina
```python
import requests
url = "https://api.jina.ai/v2/embed"
headers = {"Authorization": "Bearer YOUR_JINA_TOKEN"}
payload = {"data": ["Hello world"], "model": "jina-embeddings-v3"}
res = requests.post(url, headers=headers, json=payload)
vec = res.json()["data"][0]["embedding"]
print(vec)
```
================================================
FILE: .cursor/rules/utility_function/llm.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, LLM Wrapper
globs:
alwaysApply: false
---
# LLM Wrappers
Check out libraries like [litellm](https://github.com/BerriAI/litellm).
Here, we provide some minimal example implementations:
1. OpenAI
```python
def call_llm(prompt):
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY_HERE")
r = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
# Example usage
call_llm("How are you?")
```
> Store the API key in an environment variable like OPENAI_API_KEY for security.
{: .best-practice }
2. Claude (Anthropic)
```python
def call_llm(prompt):
from anthropic import Anthropic
client = Anthropic(api_key="YOUR_API_KEY_HERE")
r = client.messages.create(
model="claude-3-7-sonnet-20250219",
max_tokens=3000,
messages=[
{"role": "user", "content": prompt}
]
)
return r.content[0].text
```
3. Google (Generative AI Studio / PaLM API)
```python
def call_llm(prompt):
from google import genai
client = genai.Client(api_key='GEMINI_API_KEY')
response = client.models.generate_content(
model='gemini-2.0-flash-001',
contents=prompt
)
return response.text
```
4. Azure (Azure OpenAI)
```python
def call_llm(prompt):
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint="https://.openai.azure.com/",
api_key="YOUR_API_KEY_HERE",
api_version="2023-05-15"
)
r = client.chat.completions.create(
model="",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
```
5. Ollama (Local LLM)
```python
def call_llm(prompt):
from ollama import chat
response = chat(
model="llama2",
messages=[{"role": "user", "content": prompt}]
)
return response.message.content
```
6. DeepSeek
```python
def call_llm(prompt):
from openai import OpenAI
client = OpenAI(api_key="YOUR_DEEPSEEK_API_KEY", base_url="https://api.deepseek.com")
r = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
```
## Improvements
Feel free to enhance your `call_llm` function as needed. Here are examples:
- Handle chat history:
```python
def call_llm(messages):
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY_HERE")
r = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
return r.choices[0].message.content
```
- Add in-memory caching
```python
from functools import lru_cache
@lru_cache(maxsize=1000)
def call_llm(prompt):
# Your implementation here
pass
```
> ⚠️ Caching conflicts with Node retries, as retries yield the same result.
>
> To address this, you could use cached results only if not retried.
{: .warning }
```python
from functools import lru_cache
@lru_cache(maxsize=1000)
def cached_call(prompt):
pass
def call_llm(prompt, use_cache):
if use_cache:
return cached_call(prompt)
# Call the underlying function directly
return cached_call.__wrapped__(prompt)
class SummarizeNode(Node):
def exec(self, text):
return call_llm(f"Summarize: {text}", self.cur_retry==0)
```
- Enable logging:
```python
def call_llm(prompt):
import logging
logging.info(f"Prompt: {prompt}")
response = ... # Your implementation here
logging.info(f"Response: {response}")
return response
```
================================================
FILE: .cursor/rules/utility_function/text_to_speech.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, Text-to-Speech
globs:
alwaysApply: false
---
# Text-to-Speech
| **Service** | **Free Tier** | **Pricing Model** | **Docs** |
|----------------------|-----------------------|--------------------------------------------------------------|---------------------------------------------------------------------|
| **Amazon Polly** | 5M std + 1M neural | ~$4 /M (std), ~$16 /M (neural) after free tier | [Polly Docs](https://aws.amazon.com/polly/) |
| **Google Cloud TTS** | 4M std + 1M WaveNet | ~$4 /M (std), ~$16 /M (WaveNet) pay-as-you-go | [Cloud TTS Docs](https://cloud.google.com/text-to-speech) |
| **Azure TTS** | 500K neural ongoing | ~$15 /M (neural), discount at higher volumes | [Azure TTS Docs](https://azure.microsoft.com/products/cognitive-services/text-to-speech/) |
| **IBM Watson TTS** | 10K chars Lite plan | ~$0.02 /1K (i.e. ~$20 /M). Enterprise options available | [IBM Watson Docs](https://www.ibm.com/cloud/watson-text-to-speech) |
| **ElevenLabs** | 10K chars monthly | From ~$5/mo (30K chars) up to $330/mo (2M chars). Enterprise | [ElevenLabs Docs](https://elevenlabs.io) |
## Example Python Code
### Amazon Polly
```python
import boto3
polly = boto3.client("polly", region_name="us-east-1",
aws_access_key_id="YOUR_AWS_ACCESS_KEY_ID",
aws_secret_access_key="YOUR_AWS_SECRET_ACCESS_KEY")
resp = polly.synthesize_speech(
Text="Hello from Polly!",
OutputFormat="mp3",
VoiceId="Joanna"
)
with open("polly.mp3", "wb") as f:
f.write(resp["AudioStream"].read())
```
### Google Cloud TTS
```python
from google.cloud import texttospeech
client = texttospeech.TextToSpeechClient()
input_text = texttospeech.SynthesisInput(text="Hello from Google Cloud TTS!")
voice = texttospeech.VoiceSelectionParams(language_code="en-US")
audio_cfg = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)
resp = client.synthesize_speech(input=input_text, voice=voice, audio_config=audio_cfg)
with open("gcloud_tts.mp3", "wb") as f:
f.write(resp.audio_content)
```
### Azure TTS
```python
import azure.cognitiveservices.speech as speechsdk
speech_config = speechsdk.SpeechConfig(
subscription="AZURE_KEY", region="AZURE_REGION")
audio_cfg = speechsdk.audio.AudioConfig(filename="azure_tts.wav")
synthesizer = speechsdk.SpeechSynthesizer(
speech_config=speech_config,
audio_config=audio_cfg
)
synthesizer.speak_text_async("Hello from Azure TTS!").get()
```
### IBM Watson TTS
```python
from ibm_watson import TextToSpeechV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
auth = IAMAuthenticator("IBM_API_KEY")
service = TextToSpeechV1(authenticator=auth)
service.set_service_url("IBM_SERVICE_URL")
resp = service.synthesize(
"Hello from IBM Watson!",
voice="en-US_AllisonV3Voice",
accept="audio/mp3"
).get_result()
with open("ibm_tts.mp3", "wb") as f:
f.write(resp.content)
```
### ElevenLabs
```python
import requests
api_key = "ELEVENLABS_KEY"
voice_id = "ELEVENLABS_VOICE"
url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
headers = {"xi-api-key": api_key, "Content-Type": "application/json"}
json_data = {
"text": "Hello from ElevenLabs!",
"voice_settings": {"stability": 0.75, "similarity_boost": 0.75}
}
resp = requests.post(url, headers=headers, json=json_data)
with open("elevenlabs.mp3", "wb") as f:
f.write(resp.content)
```
================================================
FILE: .cursor/rules/utility_function/vector.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, Vector Databases
globs:
alwaysApply: false
---
# Vector Databases
Below is a table of the popular vector search solutions:
| **Tool** | **Free Tier** | **Pricing Model** | **Docs** |
| --- | --- | --- | --- |
| **FAISS** | N/A, self-host | Open-source | [Faiss.ai](https://faiss.ai) |
| **Pinecone** | 2GB free | From $25/mo | [pinecone.io](https://pinecone.io) |
| **Qdrant** | 1GB free cloud | Pay-as-you-go | [qdrant.tech](https://qdrant.tech) |
| **Weaviate** | 14-day sandbox | From $25/mo | [weaviate.io](https://weaviate.io) |
| **Milvus** | 5GB free cloud | PAYG or $99/mo dedicated | [milvus.io](https://milvus.io) |
| **Chroma** | N/A, self-host | Free (Apache 2.0) | [trychroma.com](https://trychroma.com) |
| **Redis** | 30MB free | From $5/mo | [redis.io](https://redis.io) |
---
## Example Python Code
Below are basic usage snippets for each tool.
### FAISS
```python
import faiss
import numpy as np
# Dimensionality of embeddings
d = 128
# Create a flat L2 index
index = faiss.IndexFlatL2(d)
# Random vectors
data = np.random.random((1000, d)).astype('float32')
index.add(data)
# Query
query = np.random.random((1, d)).astype('float32')
D, I = index.search(query, k=5)
print("Distances:", D)
print("Neighbors:", I)
```
### Pinecone
```python
import pinecone
pinecone.init(api_key="YOUR_API_KEY", environment="YOUR_ENV")
index_name = "my-index"
# Create the index if it doesn't exist
if index_name not in pinecone.list_indexes():
pinecone.create_index(name=index_name, dimension=128)
# Connect
index = pinecone.Index(index_name)
# Upsert
vectors = [
("id1", [0.1]*128),
("id2", [0.2]*128)
]
index.upsert(vectors)
# Query
response = index.query([[0.15]*128], top_k=3)
print(response)
```
### Qdrant
```python
import qdrant_client
from qdrant_client.models import Distance, VectorParams, PointStruct
client = qdrant_client.QdrantClient(
url="https://YOUR-QDRANT-CLOUD-ENDPOINT",
api_key="YOUR_API_KEY"
)
collection = "my_collection"
client.recreate_collection(
collection_name=collection,
vectors_config=VectorParams(size=128, distance=Distance.COSINE)
)
points = [
PointStruct(id=1, vector=[0.1]*128, payload={"type": "doc1"}),
PointStruct(id=2, vector=[0.2]*128, payload={"type": "doc2"}),
]
client.upsert(collection_name=collection, points=points)
results = client.search(
collection_name=collection,
query_vector=[0.15]*128,
limit=2
)
print(results)
```
### Weaviate
```python
import weaviate
client = weaviate.Client("https://YOUR-WEAVIATE-CLOUD-ENDPOINT")
schema = {
"classes": [
{
"class": "Article",
"vectorizer": "none"
}
]
}
client.schema.create(schema)
obj = {
"title": "Hello World",
"content": "Weaviate vector search"
}
client.data_object.create(obj, "Article", vector=[0.1]*128)
resp = (
client.query
.get("Article", ["title", "content"])
.with_near_vector({"vector": [0.15]*128})
.with_limit(3)
.do()
)
print(resp)
```
### Milvus
```python
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection
import numpy as np
connections.connect(alias="default", host="localhost", port="19530")
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=128)
]
schema = CollectionSchema(fields)
collection = Collection("MyCollection", schema)
emb = np.random.rand(10, 128).astype('float32')
ids = list(range(10))
collection.insert([ids, emb])
index_params = {
"index_type": "IVF_FLAT",
"params": {"nlist": 128},
"metric_type": "L2"
}
collection.create_index("embedding", index_params)
collection.load()
query_emb = np.random.rand(1, 128).astype('float32')
results = collection.search(query_emb, "embedding", param={"nprobe": 10}, limit=3)
print(results)
```
### Chroma
```python
import chromadb
from chromadb.config import Settings
client = chromadb.Client(Settings(
chroma_db_impl="duckdb+parquet",
persist_directory="./chroma_data"
))
coll = client.create_collection("my_collection")
vectors = [[0.1, 0.2, 0.3], [0.2, 0.2, 0.2]]
metas = [{"doc": "text1"}, {"doc": "text2"}]
ids = ["id1", "id2"]
coll.add(embeddings=vectors, metadatas=metas, ids=ids)
res = coll.query(query_embeddings=[[0.15, 0.25, 0.3]], n_results=2)
print(res)
```
### Redis
```python
import redis
import struct
r = redis.Redis(host="localhost", port=6379)
# Create index
r.execute_command(
"FT.CREATE", "my_idx", "ON", "HASH",
"SCHEMA", "embedding", "VECTOR", "FLAT", "6",
"TYPE", "FLOAT32", "DIM", "128",
"DISTANCE_METRIC", "L2"
)
# Insert
vec = struct.pack('128f', *[0.1]*128)
r.hset("doc1", mapping={"embedding": vec})
# Search
qvec = struct.pack('128f', *[0.15]*128)
q = "*=>[KNN 3 @embedding $BLOB AS dist]"
res = r.ft("my_idx").search(q, query_params={"BLOB": qvec})
print(res.docs)
```
================================================
FILE: .cursor/rules/utility_function/viz.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, Viz and Debug
globs:
alwaysApply: false
---
# Visualization and Debugging
Similar to LLM wrappers, we **don't** provide built-in visualization and debugging. Here, we recommend some *minimal* (and incomplete) implementations These examples can serve as a starting point for your own tooling.
## 1. Visualization with Mermaid
This code recursively traverses the nested graph, assigns unique IDs to each node, and treats Flow nodes as subgraphs to generate Mermaid syntax for a hierarchical visualization.
{% raw %}
```python
def build_mermaid(start):
ids, visited, lines = {}, set(), ["graph LR"]
ctr = 1
def get_id(n):
nonlocal ctr
return ids[n] if n in ids else (ids.setdefault(n, f"N{ctr}"), (ctr := ctr + 1))[0]
def link(a, b):
lines.append(f" {a} --> {b}")
def walk(node, parent=None):
if node in visited:
return parent and link(parent, get_id(node))
visited.add(node)
if isinstance(node, Flow):
node.start_node and parent and link(parent, get_id(node.start_node))
lines.append(f"\n subgraph sub_flow_{get_id(node)}[{type(node).__name__}]")
node.start_node and walk(node.start_node)
for nxt in node.successors.values():
node.start_node and walk(nxt, get_id(node.start_node)) or (parent and link(parent, get_id(nxt))) or walk(nxt)
lines.append(" end\n")
else:
lines.append(f" {(nid := get_id(node))}['{type(node).__name__}']")
parent and link(parent, nid)
[walk(nxt, nid) for nxt in node.successors.values()]
walk(start)
return "\n".join(lines)
```
{% endraw %}
For example, suppose we have a complex Flow for data science:
```python
class DataPrepBatchNode(BatchNode):
def prep(self,shared): return []
class ValidateDataNode(Node): pass
class FeatureExtractionNode(Node): pass
class TrainModelNode(Node): pass
class EvaluateModelNode(Node): pass
class ModelFlow(Flow): pass
class DataScienceFlow(Flow):pass
feature_node = FeatureExtractionNode()
train_node = TrainModelNode()
evaluate_node = EvaluateModelNode()
feature_node >> train_node >> evaluate_node
model_flow = ModelFlow(start=feature_node)
data_prep_node = DataPrepBatchNode()
validate_node = ValidateDataNode()
data_prep_node >> validate_node >> model_flow
data_science_flow = DataScienceFlow(start=data_prep_node)
result = build_mermaid(start=data_science_flow)
```
The code generates a Mermaid diagram:
```mermaid
graph LR
subgraph sub_flow_N1[DataScienceFlow]
N2['DataPrepBatchNode']
N3['ValidateDataNode']
N2 --> N3
N3 --> N4
subgraph sub_flow_N5[ModelFlow]
N4['FeatureExtractionNode']
N6['TrainModelNode']
N4 --> N6
N7['EvaluateModelNode']
N6 --> N7
end
end
```
For visualization based on d3.js, check out [the cookbook](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-visualization).
## 2. Call Stack Debugging
It would be useful to print the Node call stacks for debugging. This can be achieved by inspecting the runtime call stack:
```python
import inspect
def get_node_call_stack():
stack = inspect.stack()
node_names = []
seen_ids = set()
for frame_info in stack[1:]:
local_vars = frame_info.frame.f_locals
if 'self' in local_vars:
caller_self = local_vars['self']
if isinstance(caller_self, BaseNode) and id(caller_self) not in seen_ids:
seen_ids.add(id(caller_self))
node_names.append(type(caller_self).__name__)
return node_names
```
For example, suppose we have a complex Flow for data science:
```python
class DataPrepBatchNode(BatchNode):
def prep(self, shared): return []
class ValidateDataNode(Node): pass
class FeatureExtractionNode(Node): pass
class TrainModelNode(Node): pass
class EvaluateModelNode(Node):
def prep(self, shared):
stack = get_node_call_stack()
print("Call stack:", stack)
class ModelFlow(Flow): pass
class DataScienceFlow(Flow):pass
feature_node = FeatureExtractionNode()
train_node = TrainModelNode()
evaluate_node = EvaluateModelNode()
feature_node >> train_node >> evaluate_node
model_flow = ModelFlow(start=feature_node)
data_prep_node = DataPrepBatchNode()
validate_node = ValidateDataNode()
data_prep_node >> validate_node >> model_flow
data_science_flow = DataScienceFlow(start=data_prep_node)
data_science_flow.run({})
```
The output would be: `Call stack: ['EvaluateModelNode', 'ModelFlow', 'DataScienceFlow']`
For a more complete implementation, check out [the cookbook](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-tracing).
================================================
FILE: .cursor/rules/utility_function/websearch.mdc
================================================
---
description: Guidelines for using PocketFlow, Utility Function, Web Search
globs:
alwaysApply: false
---
# Web Search
We recommend some implementations of commonly used web search tools.
| **API** | **Free Tier** | **Pricing Model** | **Docs** |
|---------------------------------|-----------------------------------------------|-----------------------------------------------------------------|------------------------------------------------------------------------|
| **Google Custom Search JSON API** | 100 queries/day free | $5 per 1000 queries. | [Link](https://developers.google.com/custom-search/v1/overview) |
| **Bing Web Search API** | 1,000 queries/month | $15–$25 per 1,000 queries. | [Link](https://azure.microsoft.com/en-us/services/cognitive-services/bing-web-search-api/) |
| **DuckDuckGo Instant Answer** | Completely free (Instant Answers only, **no URLs**) | No paid plans; usage unlimited, but data is limited | [Link](https://duckduckgo.com/api) |
| **Brave Search API** | 2,000 queries/month free | $3 per 1k queries for Base, $5 per 1k for Pro | [Link](https://brave.com/search/api/) |
| **SerpApi** | 100 searches/month free | Start at $75/month for 5,000 searches| [Link](https://serpapi.com/) |
| **RapidAPI** | Many options | Many options | [Link](https://rapidapi.com/search?term=search&sortBy=ByRelevance) |
## Example Python Code
### 1. Google Custom Search JSON API
```python
import requests
API_KEY = "YOUR_API_KEY"
CX_ID = "YOUR_CX_ID"
query = "example"
url = "https://www.googleapis.com/customsearch/v1"
params = {
"key": API_KEY,
"cx": CX_ID,
"q": query
}
response = requests.get(url, params=params)
results = response.json()
print(results)
```
### 2. Bing Web Search API
```python
import requests
SUBSCRIPTION_KEY = "YOUR_BING_API_KEY"
query = "example"
url = "https://api.bing.microsoft.com/v7.0/search"
headers = {"Ocp-Apim-Subscription-Key": SUBSCRIPTION_KEY}
params = {"q": query}
response = requests.get(url, headers=headers, params=params)
results = response.json()
print(results)
```
### 3. DuckDuckGo Instant Answer
```python
import requests
query = "example"
url = "https://api.duckduckgo.com/"
params = {
"q": query,
"format": "json"
}
response = requests.get(url, params=params)
results = response.json()
print(results)
```
### 4. Brave Search API
```python
import requests
SUBSCRIPTION_TOKEN = "YOUR_BRAVE_API_TOKEN"
query = "example"
url = "https://api.search.brave.com/res/v1/web/search"
headers = {
"X-Subscription-Token": SUBSCRIPTION_TOKEN
}
params = {
"q": query
}
response = requests.get(url, headers=headers, params=params)
results = response.json()
print(results)
```
### 5. SerpApi
```python
import requests
API_KEY = "YOUR_SERPAPI_KEY"
query = "example"
url = "https://serpapi.com/search"
params = {
"engine": "google",
"q": query,
"api_key": API_KEY
}
response = requests.get(url, params=params)
results = response.json()
print(results)
```
================================================
FILE: .cursorrules
================================================
---
layout: default
title: "Agentic Coding"
---
# Agentic Coding: Humans Design, Agents code!
> If you are an AI agent involved in building LLM Systems, read this guide **VERY, VERY** carefully! This is the most important chapter in the entire document. Throughout development, you should always (1) start with a small and simple solution, (2) design at a high level (`docs/design.md`) before implementation, and (3) frequently ask humans for feedback and clarification.
{: .warning }
## Agentic Coding Steps
Agentic Coding should be a collaboration between Human System Design and Agent Implementation:
| Steps | Human | AI | Comment |
|:-----------------------|:----------:|:---------:|:------------------------------------------------------------------------|
| 1. Requirements | ★★★ High | ★☆☆ Low | Humans understand the requirements and context. |
| 2. Flow | ★★☆ Medium | ★★☆ Medium | Humans specify the high-level design, and the AI fills in the details. |
| 3. Utilities | ★★☆ Medium | ★★☆ Medium | Humans provide available external APIs and integrations, and the AI helps with implementation. |
| 4. Data | ★☆☆ Low | ★★★ High | AI designs the data schema, and humans verify. |
| 5. Node | ★☆☆ Low | ★★★ High | The AI helps design the node based on the flow. |
| 6. Implementation | ★☆☆ Low | ★★★ High | The AI implements the flow based on the design. |
| 7. Optimization | ★★☆ Medium | ★★☆ Medium | Humans evaluate the results, and the AI helps optimize. |
| 8. Reliability | ★☆☆ Low | ★★★ High | The AI writes test cases and addresses corner cases. |
1. **Requirements**: Clarify the requirements for your project, and evaluate whether an AI system is a good fit.
- Understand AI systems' strengths and limitations:
- **Good for**: Routine tasks requiring common sense (filling forms, replying to emails)
- **Good for**: Creative tasks with well-defined inputs (building slides, writing SQL)
- **Not good for**: Ambiguous problems requiring complex decision-making (business strategy, startup planning)
- **Keep It User-Centric:** Explain the "problem" from the user's perspective rather than just listing features.
- **Balance complexity vs. impact**: Aim to deliver the highest value features with minimal complexity early.
2. **Flow Design**: Outline at a high level, describe how your AI system orchestrates nodes.
- Identify applicable design patterns (e.g., [Map Reduce](./design_pattern/mapreduce.md), [Agent](./design_pattern/agent.md), [RAG](./design_pattern/rag.md)).
- For each node in the flow, start with a high-level one-line description of what it does.
- If using **Map Reduce**, specify how to map (what to split) and how to reduce (how to combine).
- If using **Agent**, specify what are the inputs (context) and what are the possible actions.
- If using **RAG**, specify what to embed, noting that there's usually both offline (indexing) and online (retrieval) workflows.
- Outline the flow and draw it in a mermaid diagram. For example:
```mermaid
flowchart LR
start[Start] --> batch[Batch]
batch --> check[Check]
check -->|OK| process
check -->|Error| fix[Fix]
fix --> check
subgraph process[Process]
step1[Step 1] --> step2[Step 2]
end
process --> endNode[End]
```
- > **If Humans can't specify the flow, AI Agents can't automate it!** Before building an LLM system, thoroughly understand the problem and potential solution by manually solving example inputs to develop intuition.
{: .best-practice }
3. **Utilities**: Based on the Flow Design, identify and implement necessary utility functions.
- Think of your AI system as the brain. It needs a body—these *external utility functions*—to interact with the real world:
<div align="center"><img src="https://github.com/the-pocket/.github/raw/main/assets/utility.png?raw=true" width="400"/></div>
- Reading inputs (e.g., retrieving Slack messages, reading emails)
- Writing outputs (e.g., generating reports, sending emails)
- Using external tools (e.g., calling LLMs, searching the web)
- **NOTE**: *LLM-based tasks* (e.g., summarizing text, analyzing sentiment) are **NOT** utility functions; rather, they are *core functions* internal in the AI system.
- For each utility function, implement it and write a simple test.
- Document their input/output, as well as why they are necessary. For example:
- `name`: `get_embedding` (`utils/get_embedding.py`)
- `input`: `str`
- `output`: a vector of 3072 floats
- `necessity`: Used by the second node to embed text
- Example utility implementation:
```python
# utils/call_llm.py
from openai import OpenAI
def call_llm(prompt):
client = OpenAI(api_key="YOUR_API_KEY_HERE")
r = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
if __name__ == "__main__":
prompt = "What is the meaning of life?"
print(call_llm(prompt))
```
- > **Sometimes, design Utilities before Flow:** For example, for an LLM project to automate a legacy system, the bottleneck will likely be the available interface to that system. Start by designing the hardest utilities for interfacing, and then build the flow around them.
{: .best-practice }
- > **Avoid Exception Handling in Utilities**: If a utility function is called from a Node's `exec()` method, avoid using `try...except` blocks within the utility. Let the Node's built-in retry mechanism handle failures.
{: .warning }
4. **Data Design**: Design the shared store that nodes will use to communicate.
- One core design principle for PocketFlow is to use a well-designed [shared store](./core_abstraction/communication.md)—a data contract that all nodes agree upon to retrieve and store data.
- For simple systems, use an in-memory dictionary.
- For more complex systems or when persistence is required, use a database.
- **Don't Repeat Yourself**: Use in-memory references or foreign keys.
- Example shared store design:
```python
shared = {
"user": {
"id": "user123",
"context": { # Another nested dict
"weather": {"temp": 72, "condition": "sunny"},
"location": "San Francisco"
}
},
"results": {} # Empty dict to store outputs
}
```
5. **Node Design**: Plan how each node will read and write data, and use utility functions.
- For each [Node](./core_abstraction/node.md), describe its type, how it reads and writes data, and which utility function it uses. Keep it specific but high-level without codes. For example:
- `type`: Regular (or Batch, or Async)
- `prep`: Read "text" from the shared store
- `exec`: Call the embedding utility function. **Avoid exception handling here**; let the Node's retry mechanism manage failures.
- `post`: Write "embedding" to the shared store
6. **Implementation**: Implement the initial nodes and flows based on the design.
- 🎉 If you've reached this step, humans have finished the design. Now *Agentic Coding* begins!
- **"Keep it simple, stupid!"** Avoid complex features and full-scale type checking.
- **FAIL FAST**! Leverage the built-in [Node](./core_abstraction/node.md) retry and fallback mechanisms to handle failures gracefully. This helps you quickly identify weak points in the system.
- Add logging throughout the code to facilitate debugging.
7. **Optimization**:
- **Use Intuition**: For a quick initial evaluation, human intuition is often a good start.
- **Redesign Flow (Back to Step 3)**: Consider breaking down tasks further, introducing agentic decisions, or better managing input contexts.
- If your flow design is already solid, move on to micro-optimizations:
- **Prompt Engineering**: Use clear, specific instructions with examples to reduce ambiguity.
- **In-Context Learning**: Provide robust examples for tasks that are difficult to specify with instructions alone.
- > **You'll likely iterate a lot!** Expect to repeat Steps 3–6 hundreds of times.
>
> <div align="center"><img src="https://github.com/the-pocket/.github/raw/main/assets/success.png?raw=true" width="400"/></div>
{: .best-practice }
8. **Reliability**
- **Node Retries**: Add checks in the node `exec` to ensure outputs meet requirements, and consider increasing `max_retries` and `wait` times.
- **Logging and Visualization**: Maintain logs of all attempts and visualize node results for easier debugging.
- **Self-Evaluation**: Add a separate node (powered by an LLM) to review outputs when results are uncertain.
## Example LLM Project File Structure
```
my_project/
├── main.py
├── nodes.py
├── flow.py
├── utils/
│ ├── __init__.py
│ ├── call_llm.py
│ └── search_web.py
├── requirements.txt
└── docs/
└── design.md
```
- **`requirements.txt`**: Lists the Python dependencies for the project.
```
PyYAML
pocketflow
```
- **`docs/design.md`**: Contains project documentation for each step above. This should be *high-level* and *no-code*.
~~~
# Design Doc: Your Project Name
> Please DON'T remove notes for AI
## Requirements
> Notes for AI: Keep it simple and clear.
> If the requirements are abstract, write concrete user stories
## Flow Design
> Notes for AI:
> 1. Consider the design patterns of agent, map-reduce, rag, and workflow. Apply them if they fit.
> 2. Present a concise, high-level description of the workflow.
### Applicable Design Pattern:
1. Map the file summary into chunks, then reduce these chunks into a final summary.
2. Agentic file finder
- *Context*: The entire summary of the file
- *Action*: Find the file
### Flow high-level Design:
1. **First Node**: This node is for ...
2. **Second Node**: This node is for ...
3. **Third Node**: This node is for ...
```mermaid
flowchart TD
firstNode[First Node] --> secondNode[Second Node]
secondNode --> thirdNode[Third Node]
```
## Utility Functions
> Notes for AI:
> 1. Understand the utility function definition thoroughly by reviewing the doc.
> 2. Include only the necessary utility functions, based on nodes in the flow.
1. **Call LLM** (`utils/call_llm.py`)
- *Input*: prompt (str)
- *Output*: response (str)
- Generally used by most nodes for LLM tasks
2. **Embedding** (`utils/get_embedding.py`)
- *Input*: str
- *Output*: a vector of 3072 floats
- Used by the second node to embed text
## Node Design
### Shared Store
> Notes for AI: Try to minimize data redundancy
The shared store structure is organized as follows:
```python
shared = {
"key": "value"
}
```
### Node Steps
> Notes for AI: Carefully decide whether to use Batch/Async Node/Flow.
1. First Node
- *Purpose*: Provide a short explanation of the node’s function
- *Type*: Decide between Regular, Batch, or Async
- *Steps*:
- *prep*: Read "key" from the shared store
- *exec*: Call the utility function
- *post*: Write "key" to the shared store
2. Second Node
...
~~~
- **`utils/`**: Contains all utility functions.
- It's recommended to dedicate one Python file to each API call, for example `call_llm.py` or `search_web.py`.
- Each file should also include a `main()` function to try that API call
```python
from google import genai
import os
def call_llm(prompt: str) -> str:
client = genai.Client(
api_key=os.getenv("GEMINI_API_KEY", ""),
)
model = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")
response = client.models.generate_content(model=model, contents=[prompt])
return response.text
if __name__ == "__main__":
test_prompt = "Hello, how are you?"
# First call - should hit the API
print("Making call...")
response1 = call_llm(test_prompt, use_cache=False)
print(f"Response: {response1}")
```
- **`nodes.py`**: Contains all the node definitions.
```python
# nodes.py
from pocketflow import Node
from utils.call_llm import call_llm
class GetQuestionNode(Node):
def exec(self, _):
# Get question directly from user input
user_question = input("Enter your question: ")
return user_question
def post(self, shared, prep_res, exec_res):
# Store the user's question
shared["question"] = exec_res
return "default" # Go to the next node
class AnswerNode(Node):
def prep(self, shared):
# Read question from shared
return shared["question"]
def exec(self, question):
# Call LLM to get the answer
return call_llm(question)
def post(self, shared, prep_res, exec_res):
# Store the answer in shared
shared["answer"] = exec_res
```
- **`flow.py`**: Implements functions that create flows by importing node definitions and connecting them.
```python
# flow.py
from pocketflow import Flow
from nodes import GetQuestionNode, AnswerNode
def create_qa_flow():
"""Create and return a question-answering flow."""
# Create nodes
get_question_node = GetQuestionNode()
answer_node = AnswerNode()
# Connect nodes in sequence
get_question_node >> answer_node
# Create flow starting with input node
return Flow(start=get_question_node)
```
- **`main.py`**: Serves as the project's entry point.
```python
# main.py
from flow import create_qa_flow
# Example main function
# Please replace this with your own main function
def main():
shared = {
"question": None, # Will be populated by GetQuestionNode from user input
"answer": None # Will be populated by AnswerNode
}
# Create the flow and run it
qa_flow = create_qa_flow()
qa_flow.run(shared)
print(f"Question: {shared['question']}")
print(f"Answer: {shared['answer']}")
if __name__ == "__main__":
main()
```
================================================
File: docs/index.md
================================================
---
layout: default
title: "Home"
nav_order: 1
---
# Pocket Flow
A [100-line](https://github.com/the-pocket/PocketFlow/blob/main/pocketflow/__init__.py) minimalist LLM framework for *Agents, Task Decomposition, RAG, etc*.
- **Lightweight**: Just the core graph abstraction in 100 lines. ZERO dependencies, and vendor lock-in.
- **Expressive**: Everything you love from larger frameworks—([Multi-](./design_pattern/multi_agent.html))[Agents](./design_pattern/agent.html), [Workflow](./design_pattern/workflow.html), [RAG](./design_pattern/rag.html), and more.
- **Agentic-Coding**: Intuitive enough for AI agents to help humans build complex LLM applications.
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/meme.jpg?raw=true" width="400"/>
</div>
## Core Abstraction
We model the LLM workflow as a **Graph + Shared Store**:
- [Node](./core_abstraction/node.md) handles simple (LLM) tasks.
- [Flow](./core_abstraction/flow.md) connects nodes through **Actions** (labeled edges).
- [Shared Store](./core_abstraction/communication.md) enables communication between nodes within flows.
- [Batch](./core_abstraction/batch.md) nodes/flows allow for data-intensive tasks.
- [Async](./core_abstraction/async.md) nodes/flows allow waiting for asynchronous tasks.
- [(Advanced) Parallel](./core_abstraction/parallel.md) nodes/flows handle I/O-bound tasks.
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/abstraction.png" width="500"/>
</div>
## Design Pattern
From there, it’s easy to implement popular design patterns:
- [Agent](./design_pattern/agent.md) autonomously makes decisions.
- [Workflow](./design_pattern/workflow.md) chains multiple tasks into pipelines.
- [RAG](./design_pattern/rag.md) integrates data retrieval with generation.
- [Map Reduce](./design_pattern/mapreduce.md) splits data tasks into Map and Reduce steps.
- [Structured Output](./design_pattern/structure.md) formats outputs consistently.
- [(Advanced) Multi-Agents](./design_pattern/multi_agent.md) coordinate multiple agents.
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/design.png" width="500"/>
</div>
## Utility Function
We **do not** provide built-in utilities. Instead, we offer *examples*—please *implement your own*:
- [LLM Wrapper](./utility_function/llm.md)
- [Viz and Debug](./utility_function/viz.md)
- [Web Search](./utility_function/websearch.md)
- [Chunking](./utility_function/chunking.md)
- [Embedding](./utility_function/embedding.md)
- [Vector Databases](./utility_function/vector.md)
- [Text-to-Speech](./utility_function/text_to_speech.md)
**Why not built-in?**: I believe it's a *bad practice* for vendor-specific APIs in a general framework:
- *API Volatility*: Frequent changes lead to heavy maintenance for hardcoded APIs.
- *Flexibility*: You may want to switch vendors, use fine-tuned models, or run them locally.
- *Optimizations*: Prompt caching, batching, and streaming are easier without vendor lock-in.
## Ready to build your Apps?
Check out [Agentic Coding Guidance](./guide.md), the fastest way to develop LLM projects with Pocket Flow!
================================================
File: docs/core_abstraction/async.md
================================================
---
layout: default
title: "(Advanced) Async"
parent: "Core Abstraction"
nav_order: 5
---
# (Advanced) Async
**Async** Nodes implement `prep_async()`, `exec_async()`, `exec_fallback_async()`, and/or `post_async()`. This is useful for:
1. **prep_async()**: For *fetching/reading data (files, APIs, DB)* in an I/O-friendly way.
2. **exec_async()**: Typically used for async LLM calls.
3. **post_async()**: For *awaiting user feedback*, *coordinating across multi-agents* or any additional async steps after `exec_async()`.
**Note**: `AsyncNode` must be wrapped in `AsyncFlow`. `AsyncFlow` can also include regular (sync) nodes.
### Example
```python
class SummarizeThenVerify(AsyncNode):
async def prep_async(self, shared):
# Example: read a file asynchronously
doc_text = await read_file_async(shared["doc_path"])
return doc_text
async def exec_async(self, prep_res):
# Example: async LLM call
summary = await call_llm_async(f"Summarize: {prep_res}")
return summary
async def post_async(self, shared, prep_res, exec_res):
# Example: wait for user feedback
decision = await gather_user_feedback(exec_res)
if decision == "approve":
shared["summary"] = exec_res
return "approve"
return "deny"
summarize_node = SummarizeThenVerify()
final_node = Finalize()
# Define transitions
summarize_node - "approve" >> final_node
summarize_node - "deny" >> summarize_node # retry
flow = AsyncFlow(start=summarize_node)
async def main():
shared = {"doc_path": "document.txt"}
await flow.run_async(shared)
print("Final Summary:", shared.get("summary"))
asyncio.run(main())
```
================================================
File: docs/core_abstraction/batch.md
================================================
---
layout: default
title: "Batch"
parent: "Core Abstraction"
nav_order: 4
---
# Batch
**Batch** makes it easier to handle large inputs in one Node or **rerun** a Flow multiple times. Example use cases:
- **Chunk-based** processing (e.g., splitting large texts).
- **Iterative** processing over lists of input items (e.g., user queries, files, URLs).
## 1. BatchNode
A **BatchNode** extends `Node` but changes `prep()` and `exec()`:
- **`prep(shared)`**: returns an **iterable** (e.g., list, generator).
- **`exec(item)`**: called **once** per item in that iterable.
- **`post(shared, prep_res, exec_res_list)`**: after all items are processed, receives a **list** of results (`exec_res_list`) and returns an **Action**.
### Example: Summarize a Large File
```python
class MapSummaries(BatchNode):
def prep(self, shared):
# Suppose we have a big file; chunk it
content = shared["data"]
chunk_size = 10000
chunks = [content[i:i+chunk_size] for i in range(0, len(content), chunk_size)]
return chunks
def exec(self, chunk):
prompt = f"Summarize this chunk in 10 words: {chunk}"
summary = call_llm(prompt)
return summary
def post(self, shared, prep_res, exec_res_list):
combined = "\n".join(exec_res_list)
shared["summary"] = combined
return "default"
map_summaries = MapSummaries()
flow = Flow(start=map_summaries)
flow.run(shared)
```
---
## 2. BatchFlow
A **BatchFlow** runs a **Flow** multiple times, each time with different `params`. Think of it as a loop that replays the Flow for each parameter set.
### Example: Summarize Many Files
```python
class SummarizeAllFiles(BatchFlow):
def prep(self, shared):
# Return a list of param dicts (one per file)
filenames = list(shared["data"].keys()) # e.g., ["file1.txt", "file2.txt", ...]
return [{"filename": fn} for fn in filenames]
# Suppose we have a per-file Flow (e.g., load_file >> summarize >> reduce):
summarize_file = SummarizeFile(start=load_file)
# Wrap that flow into a BatchFlow:
summarize_all_files = SummarizeAllFiles(start=summarize_file)
summarize_all_files.run(shared)
```
### Under the Hood
1. `prep(shared)` returns a list of param dicts—e.g., `[{filename: "file1.txt"}, {filename: "file2.txt"}, ...]`.
2. The **BatchFlow** loops through each dict. For each one:
- It merges the dict with the BatchFlow’s own `params`.
- It calls `flow.run(shared)` using the merged result.
3. This means the sub-Flow is run **repeatedly**, once for every param dict.
---
## 3. Nested or Multi-Level Batches
You can nest a **BatchFlow** in another **BatchFlow**. For instance:
- **Outer** batch: returns a list of diretory param dicts (e.g., `{"directory": "/pathA"}`, `{"directory": "/pathB"}`, ...).
- **Inner** batch: returning a list of per-file param dicts.
At each level, **BatchFlow** merges its own param dict with the parent’s. By the time you reach the **innermost** node, the final `params` is the merged result of **all** parents in the chain. This way, a nested structure can keep track of the entire context (e.g., directory + file name) at once.
```python
class FileBatchFlow(BatchFlow):
def prep(self, shared):
directory = self.params["directory"]
# e.g., files = ["file1.txt", "file2.txt", ...]
files = [f for f in os.listdir(directory) if f.endswith(".txt")]
return [{"filename": f} for f in files]
class DirectoryBatchFlow(BatchFlow):
def prep(self, shared):
directories = [ "/path/to/dirA", "/path/to/dirB"]
return [{"directory": d} for d in directories]
# MapSummaries have params like {"directory": "/path/to/dirA", "filename": "file1.txt"}
inner_flow = FileBatchFlow(start=MapSummaries())
outer_flow = DirectoryBatchFlow(start=inner_flow)
```
================================================
File: docs/core_abstraction/communication.md
================================================
---
layout: default
title: "Communication"
parent: "Core Abstraction"
nav_order: 3
---
# Communication
Nodes and Flows **communicate** in 2 ways:
1. **Shared Store (for almost all the cases)**
- A global data structure (often an in-mem dict) that all nodes can read ( `prep()`) and write (`post()`).
- Great for data results, large content, or anything multiple nodes need.
- You shall design the data structure and populate it ahead.
- > **Separation of Concerns:** Use `Shared Store` for almost all cases to separate *Data Schema* from *Compute Logic*! This approach is both flexible and easy to manage, resulting in more maintainable code. `Params` is more a syntax sugar for [Batch](./batch.md).
{: .best-practice }
2. **Params (only for [Batch](./batch.md))**
- Each node has a local, ephemeral `params` dict passed in by the **parent Flow**, used as an identifier for tasks. Parameter keys and values shall be **immutable**.
- Good for identifiers like filenames or numeric IDs, in Batch mode.
If you know memory management, think of the **Shared Store** like a **heap** (shared by all function calls), and **Params** like a **stack** (assigned by the caller).
---
## 1. Shared Store
### Overview
A shared store is typically an in-mem dictionary, like:
```python
shared = {"data": {}, "summary": {}, "config": {...}, ...}
```
It can also contain local file handlers, DB connections, or a combination for persistence. We recommend deciding the data structure or DB schema first based on your app requirements.
### Example
```python
class LoadData(Node):
def post(self, shared, prep_res, exec_res):
# We write data to shared store
shared["data"] = "Some text content"
return None
class Summarize(Node):
def prep(self, shared):
# We read data from shared store
return shared["data"]
def exec(self, prep_res):
# Call LLM to summarize
prompt = f"Summarize: {prep_res}"
summary = call_llm(prompt)
return summary
def post(self, shared, prep_res, exec_res):
# We write summary to shared store
shared["summary"] = exec_res
return "default"
load_data = LoadData()
summarize = Summarize()
load_data >> summarize
flow = Flow(start=load_data)
shared = {}
flow.run(shared)
```
Here:
- `LoadData` writes to `shared["data"]`.
- `Summarize` reads from `shared["data"]`, summarizes, and writes to `shared["summary"]`.
---
## 2. Params
**Params** let you store *per-Node* or *per-Flow* config that doesn't need to live in the shared store. They are:
- **Immutable** during a Node's run cycle (i.e., they don't change mid-`prep->exec->post`).
- **Set** via `set_params()`.
- **Cleared** and updated each time a parent Flow calls it.
> Only set the uppermost Flow params because others will be overwritten by the parent Flow.
>
> If you need to set child node params, see [Batch](./batch.md).
{: .warning }
Typically, **Params** are identifiers (e.g., file name, page number). Use them to fetch the task you assigned or write to a specific part of the shared store.
### Example
```python
# 1) Create a Node that uses params
class SummarizeFile(Node):
def prep(self, shared):
# Access the node's param
filename = self.params["filename"]
return shared["data"].get(filename, "")
def exec(self, prep_res):
prompt = f"Summarize: {prep_res}"
return call_llm(prompt)
def post(self, shared, prep_res, exec_res):
filename = self.params["filename"]
shared["summary"][filename] = exec_res
return "default"
# 2) Set params
node = SummarizeFile()
# 3) Set Node params directly (for testing)
node.set_params({"filename": "doc1.txt"})
node.run(shared)
# 4) Create Flow
flow = Flow(start=node)
# 5) Set Flow params (overwrites node params)
flow.set_params({"filename": "doc2.txt"})
flow.run(shared) # The node summarizes doc2, not doc1
```
================================================
File: docs/core_abstraction/flow.md
================================================
---
layout: default
title: "Flow"
parent: "Core Abstraction"
nav_order: 2
---
# Flow
A **Flow** orchestrates a graph of Nodes. You can chain Nodes in a sequence or create branching depending on the **Actions** returned from each Node's `post()`.
## 1. Action-based Transitions
Each Node's `post()` returns an **Action** string. By default, if `post()` doesn't return anything, we treat that as `"default"`.
You define transitions with the syntax:
1. **Basic default transition**: `node_a >> node_b`
This means if `node_a.post()` returns `"default"`, go to `node_b`.
(Equivalent to `node_a - "default" >> node_b`)
2. **Named action transition**: `node_a - "action_name" >> node_b`
This means if `node_a.post()` returns `"action_name"`, go to `node_b`.
It's possible to create loops, branching, or multi-step flows.
## 2. Creating a Flow
A **Flow** begins with a **start** node. You call `Flow(start=some_node)` to specify the entry point. When you call `flow.run(shared)`, it executes the start node, looks at its returned Action from `post()`, follows the transition, and continues until there's no next node.
### Example: Simple Sequence
Here's a minimal flow of two nodes in a chain:
```python
node_a >> node_b
flow = Flow(start=node_a)
flow.run(shared)
```
- When you run the flow, it executes `node_a`.
- Suppose `node_a.post()` returns `"default"`.
- The flow then sees `"default"` Action is linked to `node_b` and runs `node_b`.
- `node_b.post()` returns `"default"` but we didn't define `node_b >> something_else`. So the flow ends there.
### Example: Branching & Looping
Here's a simple expense approval flow that demonstrates branching and looping. The `ReviewExpense` node can return three possible Actions:
- `"approved"`: expense is approved, move to payment processing
- `"needs_revision"`: expense needs changes, send back for revision
- `"rejected"`: expense is denied, finish the process
We can wire them like this:
```python
# Define the flow connections
review - "approved" >> payment # If approved, process payment
review - "needs_revision" >> revise # If needs changes, go to revision
review - "rejected" >> finish # If rejected, finish the process
revise >> review # After revision, go back for another review
payment >> finish # After payment, finish the process
flow = Flow(start=review)
```
Let's see how it flows:
1. If `review.post()` returns `"approved"`, the expense moves to the `payment` node
2. If `review.post()` returns `"needs_revision"`, it goes to the `revise` node, which then loops back to `review`
3. If `review.post()` returns `"rejected"`, it moves to the `finish` node and stops
```mermaid
flowchart TD
review[Review Expense] -->|approved| payment[Process Payment]
review -->|needs_revision| revise[Revise Report]
review -->|rejected| finish[Finish Process]
revise --> review
payment --> finish
```
### Running Individual Nodes vs. Running a Flow
- `node.run(shared)`: Just runs that node alone (calls `prep->exec->post()`), returns an Action.
- `flow.run(shared)`: Executes from the start node, follows Actions to the next node, and so on until the flow can't continue.
> `node.run(shared)` **does not** proceed to the successor.
> This is mainly for debugging or testing a single node.
>
> Always use `flow.run(...)` in production to ensure the full pipeline runs correctly.
{: .warning }
## 3. Nested Flows
A **Flow** can act like a Node, which enables powerful composition patterns. This means you can:
1. Use a Flow as a Node within another Flow's transitions.
2. Combine multiple smaller Flows into a larger Flow for reuse.
3. Node `params` will be a merging of **all** parents' `params`.
### Flow's Node Methods
A **Flow** is also a **Node**, so it will run `prep()` and `post()`. However:
- It **won't** run `exec()`, as its main logic is to orchestrate its nodes.
- `post()` always receives `None` for `exec_res` and should instead get the flow execution results from the shared store.
### Basic Flow Nesting
Here's how to connect a flow to another node:
```python
# Create a sub-flow
node_a >> node_b
subflow = Flow(start=node_a)
# Connect it to another node
subflow >> node_c
# Create the parent flow
parent_flow = Flow(start=subflow)
```
When `parent_flow.run()` executes:
1. It starts `subflow`
2. `subflow` runs through its nodes (`node_a->node_b`)
3. After `subflow` completes, execution continues to `node_c`
### Example: Order Processing Pipeline
Here's a practical example that breaks down order processing into nested flows:
```python
# Payment processing sub-flow
validate_payment >> process_payment >> payment_confirmation
payment_flow = Flow(start=validate_payment)
# Inventory sub-flow
check_stock >> reserve_items >> update_inventory
inventory_flow = Flow(start=check_stock)
# Shipping sub-flow
create_label >> assign_carrier >> schedule_pickup
shipping_flow = Flow(start=create_label)
# Connect the flows into a main order pipeline
payment_flow >> inventory_flow >> shipping_flow
# Create the master flow
order_pipeline = Flow(start=payment_flow)
# Run the entire pipeline
order_pipeline.run(shared_data)
```
This creates a clean separation of concerns while maintaining a clear execution path:
```mermaid
flowchart LR
subgraph order_pipeline[Order Pipeline]
subgraph paymentFlow["Payment Flow"]
A[Validate Payment] --> B[Process Payment] --> C[Payment Confirmation]
end
subgraph inventoryFlow["Inventory Flow"]
D[Check Stock] --> E[Reserve Items] --> F[Update Inventory]
end
subgraph shippingFlow["Shipping Flow"]
G[Create Label] --> H[Assign Carrier] --> I[Schedule Pickup]
end
paymentFlow --> inventoryFlow
inventoryFlow --> shippingFlow
end
```
================================================
File: docs/core_abstraction/node.md
================================================
---
layout: default
title: "Node"
parent: "Core Abstraction"
nav_order: 1
---
# Node
A **Node** is the smallest building block. Each Node has 3 steps `prep->exec->post`:
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/node.png?raw=true" width="400"/>
</div>
1. `prep(shared)`
- **Read and preprocess data** from `shared` store.
- Examples: *query DB, read files, or serialize data into a string*.
- Return `prep_res`, which is used by `exec()` and `post()`.
2. `exec(prep_res)`
- **Execute compute logic**, with optional retries and error handling (below).
- Examples: *(mostly) LLM calls, remote APIs, tool use*.
- ⚠️ This shall be only for compute and **NOT** access `shared`.
- ⚠️ If retries enabled, ensure idempotent implementation.
- ⚠️ Defer exception handling to the Node's built-in retry mechanism.
- Return `exec_res`, which is passed to `post()`.
3. `post(shared, prep_res, exec_res)`
- **Postprocess and write data** back to `shared`.
- Examples: *update DB, change states, log results*.
- **Decide the next action** by returning a *string* (`action = "default"` if *None*).
> **Why 3 steps?** To enforce the principle of *separation of concerns*. The data storage and data processing are operated separately.
>
> All steps are *optional*. E.g., you can only implement `prep` and `post` if you just need to process data.
{: .note }
### Fault Tolerance & Retries
You can **retry** `exec()` if it raises an exception via two parameters when define the Node:
- `max_retries` (int): Max times to run `exec()`. The default is `1` (**no** retry).
- `wait` (int): The time to wait (in **seconds**) before next retry. By default, `wait=0` (no waiting).
`wait` is helpful when you encounter rate-limits or quota errors from your LLM provider and need to back off.
```python
my_node = SummarizeFile(max_retries=3, wait=10)
```
When an exception occurs in `exec()`, the Node automatically retries until:
- It either succeeds, or
- The Node has retried `max_retries - 1` times already and fails on the last attempt.
You can get the current retry times (0-based) from `self.cur_retry`.
```python
class RetryNode(Node):
def exec(self, prep_res):
print(f"Retry {self.cur_retry} times")
raise Exception("Failed")
```
### Graceful Fallback
To **gracefully handle** the exception (after all retries) rather than raising it, override:
```python
def exec_fallback(self, prep_res, exc):
raise exc
```
By default, it just re-raises exception. But you can return a fallback result instead, which becomes the `exec_res` passed to `post()`.
### Example: Summarize file
```python
class SummarizeFile(Node):
def prep(self, shared):
return shared["data"]
def exec(self, prep_res):
if not prep_res:
return "Empty file content"
prompt = f"Summarize this text in 10 words: {prep_res}"
summary = call_llm(prompt) # might fail
return summary
def exec_fallback(self, prep_res, exc):
# Provide a simple fallback instead of crashing
return "There was an error processing your request."
def post(self, shared, prep_res, exec_res):
shared["summary"] = exec_res
# Return "default" by not returning
summarize_node = SummarizeFile(max_retries=3)
# node.run() calls prep->exec->post
# If exec() fails, it retries up to 3 times before calling exec_fallback()
action_result = summarize_node.run(shared)
print("Action returned:", action_result) # "default"
print("Summary stored:", shared["summary"])
```
================================================
File: docs/core_abstraction/parallel.md
================================================
---
layout: default
title: "(Advanced) Parallel"
parent: "Core Abstraction"
nav_order: 6
---
# (Advanced) Parallel
**Parallel** Nodes and Flows let you run multiple **Async** Nodes and Flows **concurrently**—for example, summarizing multiple texts at once. This can improve performance by overlapping I/O and compute.
> Because of Python’s GIL, parallel nodes and flows can’t truly parallelize CPU-bound tasks (e.g., heavy numerical computations). However, they excel at overlapping I/O-bound work—like LLM calls, database queries, API requests, or file I/O.
{: .warning }
> - **Ensure Tasks Are Independent**: If each item depends on the output of a previous item, **do not** parallelize.
>
> - **Beware of Rate Limits**: Parallel calls can **quickly** trigger rate limits on LLM services. You may need a **throttling** mechanism (e.g., semaphores or sleep intervals).
>
> - **Consider Single-Node Batch APIs**: Some LLMs offer a **batch inference** API where you can send multiple prompts in a single call. This is more complex to implement but can be more efficient than launching many parallel requests and mitigates rate limits.
{: .best-practice }
## AsyncParallelBatchNode
Like **AsyncBatchNode**, but run `exec_async()` in **parallel**:
```python
class ParallelSummaries(AsyncParallelBatchNode):
async def prep_async(self, shared):
# e.g., multiple texts
return shared["texts"]
async def exec_async(self, text):
prompt = f"Summarize: {text}"
return await call_llm_async(prompt)
async def post_async(self, shared, prep_res, exec_res_list):
shared["summary"] = "\n\n".join(exec_res_list)
return "default"
node = ParallelSummaries()
flow = AsyncFlow(start=node)
```
## AsyncParallelBatchFlow
Parallel version of **BatchFlow**. Each iteration of the sub-flow runs **concurrently** using different parameters:
```python
class SummarizeMultipleFiles(AsyncParallelBatchFlow):
async def prep_async(self, shared):
return [{"filename": f} for f in shared["files"]]
sub_flow = AsyncFlow(start=LoadAndSummarizeFile())
parallel_flow = SummarizeMultipleFiles(start=sub_flow)
await parallel_flow.run_async(shared)
```
================================================
File: docs/design_pattern/agent.md
================================================
---
layout: default
title: "Agent"
parent: "Design Pattern"
nav_order: 1
---
# Agent
Agent is a powerful design pattern in which nodes can take dynamic actions based on the context.
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/agent.png?raw=true" width="350"/>
</div>
## Implement Agent with Graph
1. **Context and Action:** Implement nodes that supply context and perform actions.
2. **Branching:** Use branching to connect each action node to an agent node. Use action to allow the agent to direct the [flow](../core_abstraction/flow.md) between nodes—and potentially loop back for multi-step.
3. **Agent Node:** Provide a prompt to decide action—for example:
```python
f"""
### CONTEXT
Task: {task_description}
Previous Actions: {previous_actions}
Current State: {current_state}
### ACTION SPACE
[1] search
Description: Use web search to get results
Parameters:
- query (str): What to search for
[2] answer
Description: Conclude based on the results
Parameters:
- result (str): Final answer to provide
### NEXT ACTION
Decide the next action based on the current context and available action space.
Return your response in the following format:
```yaml
thinking: |
<your step-by-step reasoning process>
action: <action_name>
parameters:
<parameter_name>: <parameter_value>
```"""
```
The core of building **high-performance** and **reliable** agents boils down to:
1. **Context Management:** Provide *relevant, minimal context.* For example, rather than including an entire chat history, retrieve the most relevant via [RAG](./rag.md). Even with larger context windows, LLMs still fall victim to ["lost in the middle"](https://arxiv.org/abs/2307.03172), overlooking mid-prompt content.
2. **Action Space:** Provide *a well-structured and unambiguous* set of actions—avoiding overlap like separate `read_databases` or `read_csvs`. Instead, import CSVs into the database.
## Example Good Action Design
- **Incremental:** Feed content in manageable chunks (500 lines or 1 page) instead of all at once.
- **Overview-zoom-in:** First provide high-level structure (table of contents, summary), then allow drilling into details (raw texts).
- **Parameterized/Programmable:** Instead of fixed actions, enable parameterized (columns to select) or programmable (SQL queries) actions, for example, to read CSV files.
- **Backtracking:** Let the agent undo the last step instead of restarting entirely, preserving progress when encountering errors or dead ends.
## Example: Search Agent
This agent:
1. Decides whether to search or answer
2. If searches, loops back to decide if more search needed
3. Answers when enough context gathered
```python
class DecideAction(Node):
def prep(self, shared):
context = shared.get("context", "No previous search")
query = shared["query"]
return query, context
def exec(self, inputs):
query, context = inputs
prompt = f"""
Given input: {query}
Previous search results: {context}
Should I: 1) Search web for more info 2) Answer with current knowledge
Output in yaml:
```yaml
action: search/answer
reason: why this action
search_term: search phrase if action is search
```"""
resp = call_llm(prompt)
yaml_str = resp.split("```yaml")[1].split("```")[0].strip()
result = yaml.safe_load(yaml_str)
assert isinstance(result, dict)
assert "action" in result
assert "reason" in result
assert result["action"] in ["search", "answer"]
if result["action"] == "search":
assert "search_term" in result
return result
def post(self, shared, prep_res, exec_res):
if exec_res["action"] == "search":
shared["search_term"] = exec_res["search_term"]
return exec_res["action"]
class SearchWeb(Node):
def prep(self, shared):
return shared["search_term"]
def exec(self, search_term):
return search_web(search_term)
def post(self, shared, prep_res, exec_res):
prev_searches = shared.get("context", [])
shared["context"] = prev_searches + [
{"term": shared["search_term"], "result": exec_res}
]
return "decide"
class DirectAnswer(Node):
def prep(self, shared):
return shared["query"], shared.get("context", "")
def exec(self, inputs):
query, context = inputs
return call_llm(f"Context: {context}\nAnswer: {query}")
def post(self, shared, prep_res, exec_res):
print(f"Answer: {exec_res}")
shared["answer"] = exec_res
# Connect nodes
decide = DecideAction()
search = SearchWeb()
answer = DirectAnswer()
decide - "search" >> search
decide - "answer" >> answer
search - "decide" >> decide # Loop back
flow = Flow(start=decide)
flow.run({"query": "Who won the Nobel Prize in Physics 2024?"})
```
================================================
File: docs/design_pattern/mapreduce.md
================================================
---
layout: default
title: "Map Reduce"
parent: "Design Pattern"
nav_order: 4
---
# Map Reduce
MapReduce is a design pattern suitable when you have either:
- Large input data (e.g., multiple files to process), or
- Large output data (e.g., multiple forms to fill)
and there is a logical way to break the task into smaller, ideally independent parts.
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/mapreduce.png?raw=true" width="400"/>
</div>
You first break down the task using [BatchNode](../core_abstraction/batch.md) in the map phase, followed by aggregation in the reduce phase.
### Example: Document Summarization
```python
class SummarizeAllFiles(BatchNode):
def prep(self, shared):
files_dict = shared["files"] # e.g. 10 files
return list(files_dict.items()) # [("file1.txt", "aaa..."), ("file2.txt", "bbb..."), ...]
def exec(self, one_file):
filename, file_content = one_file
summary_text = call_llm(f"Summarize the following file:\n{file_content}")
return (filename, summary_text)
def post(self, shared, prep_res, exec_res_list):
shared["file_summaries"] = dict(exec_res_list)
class CombineSummaries(Node):
def prep(self, shared):
return shared["file_summaries"]
def exec(self, file_summaries):
# format as: "File1: summary\nFile2: summary...\n"
text_list = []
for fname, summ in file_summaries.items():
text_list.append(f"{fname} summary:\n{summ}\n")
big_text = "\n---\n".join(text_list)
return call_llm(f"Combine these file summaries into one final summary:\n{big_text}")
def post(self, shared, prep_res, final_summary):
shared["all_files_summary"] = final_summary
batch_node = SummarizeAllFiles()
combine_node = CombineSummaries()
batch_node >> combine_node
flow = Flow(start=batch_node)
shared = {
"files": {
"file1.txt": "Alice was beginning to get very tired of sitting by her sister...",
"file2.txt": "Some other interesting text ...",
# ...
}
}
flow.run(shared)
print("Individual Summaries:", shared["file_summaries"])
print("\nFinal Summary:\n", shared["all_files_summary"])
```
================================================
File: docs/design_pattern/rag.md
================================================
---
layout: default
title: "RAG"
parent: "Design Pattern"
nav_order: 3
---
# RAG (Retrieval Augmented Generation)
For certain LLM tasks like answering questions, providing relevant context is essential. One common architecture is a **two-stage** RAG pipeline:
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/rag.png?raw=true" width="400"/>
</div>
1. **Offline stage**: Preprocess and index documents ("building the index").
2. **Online stage**: Given a question, generate answers by retrieving the most relevant context.
---
## Stage 1: Offline Indexing
We create three Nodes:
1. `ChunkDocs` – [chunks](../utility_function/chunking.md) raw text.
2. `EmbedDocs` – [embeds](../utility_function/embedding.md) each chunk.
3. `StoreIndex` – stores embeddings into a [vector database](../utility_function/vector.md).
```python
class ChunkDocs(BatchNode):
def prep(self, shared):
# A list of file paths in shared["files"]. We process each file.
return shared["files"]
def exec(self, filepath):
# read file content. In real usage, do error handling.
with open(filepath, "r", encoding="utf-8") as f:
text = f.read()
# chunk by 100 chars each
chunks = []
size = 100
for i in range(0, len(text), size):
chunks.append(text[i : i + size])
return chunks
def post(self, shared, prep_res, exec_res_list):
# exec_res_list is a list of chunk-lists, one per file.
# flatten them all into a single list of chunks.
all_chunks = []
for chunk_list in exec_res_list:
all_chunks.extend(chunk_list)
shared["all_chunks"] = all_chunks
class EmbedDocs(BatchNode):
def prep(self, shared):
return shared["all_chunks"]
def exec(self, chunk):
return get_embedding(chunk)
def post(self, shared, prep_res, exec_res_list):
# Store the list of embeddings.
shared["all_embeds"] = exec_res_list
print(f"Total embeddings: {len(exec_res_list)}")
class StoreIndex(Node):
def prep(self, shared):
# We'll read all embeds from shared.
return shared["all_embeds"]
def exec(self, all_embeds):
# Create a vector index (faiss or other DB in real usage).
index = create_index(all_embeds)
return index
def post(self, shared, prep_res, index):
shared["index"] = index
# Wire them in sequence
chunk_node = ChunkDocs()
embed_node = EmbedDocs()
store_node = StoreIndex()
chunk_node >> embed_node >> store_node
OfflineFlow = Flow(start=chunk_node)
```
Usage example:
```python
shared = {
"files": ["doc1.txt", "doc2.txt"], # any text files
}
OfflineFlow.run(shared)
```
---
## Stage 2: Online Query & Answer
We have 3 nodes:
1. `EmbedQuery` – embeds the user’s question.
2. `RetrieveDocs` – retrieves top chunk from the index.
3. `GenerateAnswer` – calls the LLM with the question + chunk to produce the final answer.
```python
class EmbedQuery(Node):
def prep(self, shared):
return shared["question"]
def exec(self, question):
return get_embedding(question)
def post(self, shared, prep_res, q_emb):
shared["q_emb"] = q_emb
class RetrieveDocs(Node):
def prep(self, shared):
# We'll need the query embedding, plus the offline index/chunks
return shared["q_emb"], shared["index"], shared["all_chunks"]
def exec(self, inputs):
q_emb, index, chunks = inputs
I, D = search_index(index, q_emb, top_k=1)
best_id = I[0][0]
relevant_chunk = chunks[best_id]
return relevant_chunk
def post(self, shared, prep_res, relevant_chunk):
shared["retrieved_chunk"] = relevant_chunk
print("Retrieved chunk:", relevant_chunk[:60], "...")
class GenerateAnswer(Node):
def prep(self, shared):
return shared["question"], shared["retrieved_chunk"]
def exec(self, inputs):
question, chunk = inputs
prompt = f"Question: {question}\nContext: {chunk}\nAnswer:"
return call_llm(prompt)
def post(self, shared, prep_res, answer):
shared["answer"] = answer
print("Answer:", answer)
embed_qnode = EmbedQuery()
retrieve_node = RetrieveDocs()
generate_node = GenerateAnswer()
embed_qnode >> retrieve_node >> generate_node
OnlineFlow = Flow(start=embed_qnode)
```
Usage example:
```python
# Suppose we already ran OfflineFlow and have:
# shared["all_chunks"], shared["index"], etc.
shared["question"] = "Why do people like cats?"
OnlineFlow.run(shared)
# final answer in shared["answer"]
```
================================================
File: docs/design_pattern/structure.md
================================================
---
layout: default
title: "Structured Output"
parent: "Design Pattern"
nav_order: 5
---
# Structured Output
In many use cases, you may want the LLM to output a specific structure, such as a list or a dictionary with predefined keys.
There are several approaches to achieve a structured output:
- **Prompting** the LLM to strictly return a defined structure.
- Using LLMs that natively support **schema enforcement**.
- **Post-processing** the LLM's response to extract structured content.
In practice, **Prompting** is simple and reliable for modern LLMs.
### Example Use Cases
- Extracting Key Information
```yaml
product:
name: Widget Pro
price: 199.99
description: |
A high-quality widget designed for professionals.
Recommended for advanced users.
```
- Summarizing Documents into Bullet Points
```yaml
summary:
- This product is easy to use.
- It is cost-effective.
- Suitable for all skill levels.
```
- Generating Configuration Files
```yaml
server:
host: 127.0.0.1
port: 8080
ssl: true
```
## Prompt Engineering
When prompting the LLM to produce **structured** output:
1. **Wrap** the structure in code fences (e.g., `yaml`).
2. **Validate** that all required fields exist (and let `Node` handles retry).
### Example Text Summarization
```python
class SummarizeNode(Node):
def exec(self, prep_res):
# Suppose `prep_res` is the text to summarize.
prompt = f"""
Please summarize the following text as YAML, with exactly 3 bullet points
{prep_res}
Now, output:
```yaml
summary:
- bullet 1
- bullet 2
- bullet 3
```"""
response = call_llm(prompt)
yaml_str = response.split("```yaml")[1].split("```")[0].strip()
import yaml
structured_result = yaml.safe_load(yaml_str)
assert "summary" in structured_result
assert isinstance(structured_result["summary"], list)
return structured_result
```
> Besides using `assert` statements, another popular way to validate schemas is [Pydantic](https://github.com/pydantic/pydantic)
{: .note }
### Why YAML instead of JSON?
Current LLMs struggle with escaping. YAML is easier with strings since they don't always need quotes.
**In JSON**
```json
{
"dialogue": "Alice said: \"Hello Bob.\\nHow are you?\\nI am good.\""
}
```
- Every double quote inside the string must be escaped with `\"`.
- Each newline in the dialogue must be represented as `\n`.
**In YAML**
```yaml
dialogue: |
Alice said: "Hello Bob.
How are you?
I am good."
```
- No need to escape interior quotes—just place the entire text under a block literal (`|`).
- Newlines are naturally preserved without needing `\n`.
================================================
File: docs/design_pattern/workflow.md
================================================
---
layout: default
title: "Workflow"
parent: "Design Pattern"
nav_order: 2
---
# Workflow
Many real-world tasks are too complex for one LLM call. The solution is to **Task Decomposition**: decompose them into a [chain](../core_abstraction/flow.md) of multiple Nodes.
<div align="center">
<img src="https://github.com/the-pocket/.github/raw/main/assets/workflow.png?raw=true" width="400"/>
</div>
> - You don't want to make each task **too coarse**, because it may be *too complex for one LLM call*.
> - You don't want to make each task **too granular**, because then *the LLM call doesn't have enough context* and results are *not consistent across nodes*.
>
> You usually need multiple *iterations* to find the *sweet spot*. If the task has too many *edge cases*, consider using [Agents](./agent.md).
{: .best-practice }
### Example: Article Writing
```python
class GenerateOutline(Node):
def prep(self, shared): return shared["topic"]
def exec(self, topic): return call_llm(f"Create a detailed outline for an article about {topic}")
def post(self, shared, prep_res, exec_res): shared["outline"] = exec_res
class WriteSection(Node):
def prep(self, shared): return shared["outline"]
def exec(self, outline): return call_llm(f"Write content based on this outline: {outline}")
def post(self, shared, prep_res, exec_res): shared["draft"] = exec_res
class ReviewAndRefine(Node):
def prep(self, shared): return shared["draft"]
def exec(self, draft): return call_llm(f"Review and improve this draft: {draft}")
def post(self, shared, prep_res, exec_res): shared["final_article"] = exec_res
# Connect nodes
outline = GenerateOutline()
write = WriteSection()
review = ReviewAndRefine()
outline >> write >> review
# Create and run flow
writing_flow = Flow(start=outline)
shared = {"topic": "AI Safety"}
writing_flow.run(shared)
```
For *dynamic cases*, consider using [Agents](./agent.md).
================================================
File: docs/utility_function/llm.md
================================================
---
layout: default
title: "LLM Wrapper"
parent: "Utility Function"
nav_order: 1
---
# LLM Wrappers
Check out libraries like [litellm](https://github.com/BerriAI/litellm).
Here, we provide some minimal example implementations:
1. OpenAI
```python
def call_llm(prompt):
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY_HERE")
r = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
# Example usage
call_llm("How are you?")
```
> Store the API key in an environment variable like OPENAI_API_KEY for security.
{: .best-practice }
2. Claude (Anthropic)
```python
def call_llm(prompt):
from anthropic import Anthropic
client = Anthropic(api_key="YOUR_API_KEY_HERE")
r = client.messages.create(
model="claude-sonnet-4-0",
messages=[
{"role": "user", "content": prompt}
]
)
return r.content[0].text
```
3. Google (Generative AI Studio / PaLM API)
```python
def call_llm(prompt):
from google import genai
client = genai.Client(api_key='GEMINI_API_KEY')
response = client.models.generate_content(
model='gemini-2.5-pro',
contents=prompt
)
return response.text
```
4. Azure (Azure OpenAI)
```python
def call_llm(prompt):
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint="https://<YOUR_RESOURCE_NAME>.openai.azure.com/",
api_key="YOUR_API_KEY_HERE",
api_version="2023-05-15"
)
r = client.chat.completions.create(
model="<YOUR_DEPLOYMENT_NAME>",
messages=[{"role": "user", "content": prompt}]
)
return r.choices[0].message.content
```
5. Ollama (Local LLM)
```python
def call_llm(prompt):
from ollama import chat
response = chat(
model="llama2",
messages=[{"role": "user", "content": prompt}]
)
return response.message.content
```
## Improvements
Feel free to enhance your `call_llm` function as needed. Here are examples:
- Handle chat history:
```python
def call_llm(messages):
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY_HERE")
r = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
return r.choices[0].message.content
```
- Add in-memory caching
```python
from functools import lru_cache
@lru_cache(maxsize=1000)
def call_llm(prompt):
# Your implementation here
pass
```
> ⚠️ Caching conflicts with Node retries, as retries yield the same result.
>
> To address this, you could use cached results only if not retried.
{: .warning }
```python
from functools import lru_cache
@lru_cache(maxsize=1000)
def cached_call(prompt):
pass
def call_llm(prompt, use_cache):
if use_cache:
return cached_call(prompt)
# Call the underlying function directly
return cached_call.__wrapped__(prompt)
class SummarizeNode(Node):
def exec(self, text):
return call_llm(f"Summarize: {text}", self.cur_retry==0)
```
- Enable logging:
```python
def call_llm(prompt):
import logging
logging.info(f"Prompt: {prompt}")
response = ... # Your implementation here
logging.info(f"Response: {response}")
return response
```
================================================
FILE: .gitignore
================================================
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# IDE specific files
.idea/
.vscode/
*.swp
*.swo
*~
# Node
node_modules/
npm-debug.log
yarn-debug.log
yarn-error.log
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
venv/
ENV/
# Logs and databases
*.log
*.sql
*.sqlite
# Build output
dist/
build/
out/
# Coverage reports
coverage/
.coverage
.coverage.*
htmlcov/
# Misc
*.bak
*.tmp
*.temp
test.ipynb
.pytest_cache/
cookbook/pocketflow-multi-agent/.python-version
# local
uv.lock
.python-version
pyproject.toml
usage.md
cookbook/pocketflow-minimal-example/viz/flow_visualization.html
cookbook/pocketflow-minimal-example/viz/flow_visualization.json
.claude/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2024 Zachary Huang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<div align="center">
<img src="https://github.com/The-Pocket/.github/raw/main/assets/title.png" alt="Pocket Flow – 100-line minimalist LLM framework" width="600"/>
</div>
<!-- For translation, replace English with [English](https://github.com/The-Pocket/PocketFlow/blob/main/README.md), and remove the link for the target language. -->
English | [中文](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_CHINESE.md) | [Español](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_SPANISH.md) | [日本語](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_JAPANESE.md) | [Deutsch](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_GERMAN.md) | [Русский](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_RUSSIAN.md) | [Português](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_PORTUGUESE.md) | [Français](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_FRENCH.md) | [한국어](https://github.com/The-Pocket/PocketFlow/blob/main/cookbook/pocketflow-batch/translations/README_KOREAN.md)

[](https://the-pocket.github.io/PocketFlow/)
<a href="https://discord.gg/hUHHE9Sa6T">
<img src="https://img.shields.io/discord/1346833819172601907?logo=discord&style=flat">
</a>
Pocket Flow is a [100-line](https://github.com/The-Pocket/PocketFlow/blob/main/pocketflow/__init__.py) minimalist LLM framework
- **Lightweight**: Just 100 lines. Zero bloat, zero dependencies, zero vendor lock-in.
- **Expressive**: Everything you love—([Multi-](https://the-pocket.github.io/PocketFlow/design_pattern/multi_agent.html))[Agents](https://the-pocket.github.io/PocketFlow/design_pattern/agent.html), [Workflow](https://the-pocket.github.io/PocketFlow/design_pattern/workflow.html), [RAG](https://the-pocket.github.io/PocketFlow/design_pattern/rag.html), and more.
- **[Agentic Coding](https://zacharyhuang.substack.com/p/agentic-coding-the-most-fun-way-to)**: Let AI Agents (e.g., Cursor AI) build Agents—10x productivity boost!
Get started with Pocket Flow:
- To install, ```pip install pocketflow```or just copy the [source code](https://github.com/The-Pocket/PocketFlow/blob/main/pocketflow/__init__.py) (only 100 lines).
- To learn more, check out the [video tutorial](https://youtu.be/0Zr3NwcvpA0) and [documentation](https://the-pocket.github.io/PocketFlow/)
- 🎉 Join our [Discord](https://discord.gg/hUHHE9Sa6T) to connect with other developers building with Pocket Flow!
- 🎉 Pocket Flow now has [Typescript](https://github.com/The-Pocket/PocketFlow-Typescript), [Java](https://github.com/The-Pocket/PocketFlow-Java), [C++](https://github.com/The-Pocket/PocketFlow-CPP), [Go](https://github.com/The-Pocket/PocketFlow-Go), [Rust](https://github.com/The-Pocket/PocketFlow-Rust) and [PHP](https://github.com/The-Pocket/PocketFlow-PHP) versions!
## Why Pocket Flow?
Current LLM frameworks are bloated... You only need 100 lines for LLM Framework!
<div align="center">
<img src="https://github.com/The-Pocket/.github/raw/main/assets/meme.jpg" width="400"/>
| | **Abstraction** | **App-Specific Wrappers** | **Vendor-Specific Wrappers** | **Lines** | **Size** |
|----------------|:-----------------------------: |:-----------------------------------------------------------:|:------------------------------------------------------------:|:---------------:|:----------------------------:|
| LangChain | Agent, Chain | Many <br><sup><sub>(e.g., QA, Summarization)</sub></sup> | Many <br><sup><sub>(e.g., OpenAI, Pinecone, etc.)</sub></sup> | 405K | +166MB |
| CrewAI | Agent, Chain | Many <br><sup><sub>(e.g., FileReadTool, SerperDevTool)</sub></sup> | Many <br><sup><sub>(e.g., OpenAI, Anthropic, Pinecone, etc.)</sub></sup> | 18K | +173MB |
| SmolAgent | Agent | Some <br><sup><sub>(e.g., CodeAgent, VisitWebTool)</sub></sup> | Some <br><sup><sub>(e.g., DuckDuckGo, Hugging Face, etc.)</sub></sup> | 8K | +198MB |
| LangGraph | Agent, Graph | Some <br><sup><sub>(e.g., Semantic Search)</sub></sup> | Some <br><sup><sub>(e.g., PostgresStore, SqliteSaver, etc.) </sub></sup> | 37K | +51MB |
| AutoGen | Agent | Some <br><sup><sub>(e.g., Tool Agent, Chat Agent)</sub></sup> | Many <sup><sub>[Optional]<br> (e.g., OpenAI, Pinecone, etc.)</sub></sup> | 7K <br><sup><sub>(core-only)</sub></sup> | +26MB <br><sup><sub>(core-only)</sub></sup> |
| **PocketFlow** | **Graph** | **None** | **None** | **100** | **+56KB** |
</div>
## How does Pocket Flow work?
The [100 lines](https://github.com/The-Pocket/PocketFlow/blob/main/pocketflow/__init__.py) capture the core abstraction of LLM frameworks: Graph!
<br>
<div align="center">
<img src="https://github.com/The-Pocket/.github/raw/main/assets/abstraction.png" width="900"/>
</div>
<br>
From there, it's easy to implement popular design patterns like ([Multi-](https://the-pocket.github.io/PocketFlow/design_pattern/multi_agent.html))[Agents](https://the-pocket.github.io/PocketFlow/design_pattern/agent.html), [Workflow](https://the-pocket.github.io/PocketFlow/design_pattern/workflow.html), [RAG](https://the-pocket.github.io/PocketFlow/design_pattern/rag.html), etc.
<br>
<div align="center">
<img src="https://github.com/The-Pocket/.github/raw/main/assets/design.png" width="900"/>
</div>
<br>
✨ Below are basic tutorials:
<div align="center">
| Name | Difficulty | Description |
| :-------------: | :-------------: | :--------------------- |
| [Chat](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-chat) | ☆☆☆ <sup>*Dummy*</sup> | A basic chat bot with conversation history |
| [Structured Output](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-structured-output) | ☆☆☆ <sup>*Dummy*</sup> | Extracting structured data from resumes by prompting |
| [Workflow](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-workflow) | ☆☆☆ <sup>*Dummy*</sup> | A writing workflow that outlines, writes content, and applies styling |
| [Agent](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-agent) | ☆☆☆ <sup>*Dummy*</sup> | A research agent that can search the web and answer questions |
| [RAG](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-rag) | ☆☆☆ <sup>*Dummy*</sup> | A simple Retrieval-augmented Generation process |
| [Batch](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-batch) | ☆☆☆ <sup>*Dummy*</sup> | A batch processor that translates markdown into multiple languages |
| [Streaming](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-llm-streaming) | ☆☆☆ <sup>*Dummy*</sup> | A real-time LLM streaming demo with user interrupt capability |
| [Chat Guardrail](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-chat-guardrail) | ☆☆☆ <sup>*Dummy*</sup> | A travel advisor chatbot that only processes travel-related queries |
| [Majority Vote](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-majority-vote) | ☆☆☆ <sup>*Dummy*</sup> | Improve reasoning accuracy by aggregating multiple solution attempts |
| [Map-Reduce](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-map-reduce) | ☆☆☆ <sup>*Dummy*</sup> | Batch resume qualification using map-reduce pattern |
| [CLI HITL](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-cli-hitl) | ☆☆☆ <sup>*Dummy*</sup> | A command-line joke generator with human-in-the-loop feedback |
| [Multi-Agent](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-multi-agent) | ★☆☆ <sup>*Beginner*</sup> | A Taboo word game for async communication between 2 agents |
| [Supervisor](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-supervisor) | ★☆☆ <sup>*Beginner*</sup> | Research agent is getting unreliable... Let's build a supervision process|
| [Parallel](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-parallel-batch) | ★☆☆ <sup>*Beginner*</sup> | A parallel execution demo that shows 3x speedup |
| [Parallel Flow](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-parallel-batch-flow) | ★☆☆ <sup>*Beginner*</sup> | A parallel image processing showing 8x speedup |
| [Thinking](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-thinking) | ★☆☆ <sup>*Beginner*</sup> | Solve complex reasoning problems through Chain-of-Thought |
| [Memory](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-chat-memory) | ★☆☆ <sup>*Beginner*</sup> | A chat bot with short-term and long-term memory |
| [Text2SQL](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-text2sql) | ★☆☆ <sup>*Beginner*</sup> | Convert natural language to SQL queries with an auto-debug loop |
| [Code Generator](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-code-generator) | ★☆☆ <sup>*Beginner*</sup> | Generate test cases, implement solutions, and iteratively improve code |
| [MCP](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-mcp) | ★☆☆ <sup>*Beginner*</sup> | Agent using Model Context Protocol for numerical operations |
| [Agent Skills](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-agent-skills) | ★☆☆ <sup>*Beginner*</sup> | Route requests to reusable markdown skills and apply them in an agent flow |
| [A2A](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-a2a) | ★☆☆ <sup>*Beginner*</sup> | Agent wrapped with A2A protocol for inter-agent communication |
| [Streamlit FSM](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-streamlit-fsm) | ★☆☆ <sup>*Beginner*</sup> | Streamlit app with finite state machine for HITL image generation |
| [FastAPI WebSocket](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-fastapi-websocket) | ★☆☆ <sup>*Beginner*</sup> | Real-time chat interface with streaming LLM responses via WebSocket |
| [FastAPI Background](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-fastapi-background) | ★☆☆ <sup>*Beginner*</sup> | FastAPI app with background jobs and real-time progress via SSE |
| [Voice Chat](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-voice-chat) | ★☆☆ <sup>*Beginner*</sup> | An interactive voice chat application with VAD, STT, LLM, and TTS. |
</div>
👀 Want to see other tutorials for dummies? [Create an issue!](https://github.com/The-Pocket/PocketFlow/issues/new)
## How to Use Pocket Flow?
🚀 Through **Agentic Coding**—the fastest LLM App development paradigm-where *humans design* and *agents code*!
<br>
<div align="center">
<a href="https://zacharyhuang.substack.com/p/agentic-coding-the-most-fun-way-to" target="_blank">
<img src="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423a39af-49e8-483b-bc5a-88cc764350c6_1050x588.png" width="700" alt="IMAGE ALT TEXT" style="cursor: pointer;">
</a>
</div>
<br>
✨ Below are examples of more complex LLM Apps:
<div align="center">
| App Name | Difficulty | Topics | Human Design | Agent Code |
| :-------------: | :-------------: | :---------------------: | :---: | :---: |
| [Website Chatbot](https://github.com/The-Pocket/PocketFlow-Tutorial-Website-Chatbot) <br> <sup><sub>Turn your website into a 24/7 customer support genius</sup></sub> | ★★☆ <br> *Medium* | [Agent](https://the-pocket.github.io/PocketFlow/design_pattern/agent.html) <br> [RAG](https://the-pocket.github.io/PocketFlow/design_pattern/rag.html) | [Design Doc](https://github.com/The-Pocket/PocketFlow-Tutorial-Website-Chatbot/blob/main/docs/design.md) | [Flow Code](https://github.com/The-Pocket/PocketFlow-Tutorial-Website-Chatbot/blob/main/flow.py)
| [Danganronpa Simulator](https://github.com/The-Pocket/PocketFlow-Tutorial-Danganronpa-Simulator) <br> <sup><sub>Forget the Turing test. Danganronpa, the ultimate AI experiment!</sup></sub> | ★★★ <br> *Advanced* | [Workflow](https://the-pocket.github.io/PocketFlow/design_pattern/workflow.html) <br> [Agent](https://the-pocket.github.io/PocketFlow/design_pattern/agent.html) | [Design Doc](https://github.com/The-Pocket/PocketFlow-Tutorial-Danganronpa-Simulator/blob/main/docs/design.md) | [Flow Code](https://github.com/The-Pocket/PocketFlow-Tutorial-Danganronpa-Simulator/blob/main/flow.py)
| [Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge) <br> <sup><sub>Life's too short to stare at others' code in confusion</sup></sub> | ★★☆ <br> *Medium* | [Workflow](https://the-pocket.github.io/PocketFlow/design_pattern/workflow.html) | [Design Doc](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge/blob/main/docs/design.md) | [Flow Code](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge/blob/main/flow.py)
| [Build Cursor with Cursor](https://github.com/The-Pocket/Tutorial-Cursor) <br> <sup><sub>We'll reach the singularity soon ...</sup></sub> | ★★★ <br> *Advanced* | [Agent](https://the-pocket.github.io/PocketFlow/design_pattern/agent.html) | [Design Doc](https://github.com/The-Pocket/Tutorial-Cursor/blob/main/docs/design.md) | [Flow Code](https://github.com/The-Pocket/Tutorial-Cursor/blob/main/flow.py)
| [Ask AI Paul Graham](https://github.com/The-Pocket/Tutorial-YC-Partner) <br> <sup><sub>Ask AI Paul Graham, in case you don't get in</sup></sub> | ★★☆ <br> *Medium* | [RAG](https://the-pocket.github.io/PocketFlow/design_pattern/rag.html) <br> [Map Reduce](https://the-pocket.github.io/PocketFlow/design_pattern/mapreduce.html) <br> [TTS](https://the-pocket.github.io/PocketFlow/utility_function/text_to_speech.html) | [Design Doc](https://github.com/The-Pocket/Tutorial-AI-Paul-Graham/blob/main/docs/design.md) | [Flow Code](https://github.com/The-Pocket/Tutorial-AI-Paul-Graham/blob/main/flow.py)
| [Youtube Summarizer](https://github.com/The-Pocket/Tutorial-Youtube-Made-Simple) <br> <sup><sub> Explain YouTube Videos to you like you're 5 </sup></sub> | ★☆☆ <br> *Beginner* | [Map Reduce](https://the-pocket.github.io/PocketFlow/design_pattern/mapreduce.html) | [Design Doc](https://github.com/The-Pocket/Tutorial-Youtube-Made-Simple/blob/main/docs/design.md) | [Flow Code](https://github.com/The-Pocket/Tutorial-Youtube-Made-Simple/blob/main/flow.py)
| [Cold Opener Generator](https://github.com/The-Pocket/Tutorial-Cold-Email-Personalization) <br> <sup><sub> Instant icebreakers that turn cold leads hot </sup></sub> | ★☆☆ <br> *Beginner* | [Map Reduce](https://the-pocket.github.io/PocketFlow/design_pattern/mapreduce.html) <br> [Web Search](https://the-pocket.github.io/PocketFlow/utility_function/websearch.html) | [Design Doc](https://github.com/The-Pocket/Tutorial-Cold-Email-Personalization/blob/master/docs/design.md) | [Flow Code](https://github.com/The-Pocket/Tutorial-Cold-Email-Personalization/blob/master/flow.py)
</div>
- Want to learn **Agentic Coding**?
- Check out [my YouTube](https://www.youtube.com/@ZacharyLLM?sub_confirmation=1) for video tutorial on how some apps above are made!
- Want to build your own LLM App? Read this [post](https://zacharyhuang.substack.com/p/agentic-coding-the-most-fun-way-to)! Start with [this template](https://github.com/The-Pocket/PocketFlow-Template-Python)!
================================================
FILE: cookbook/README.md
================================================
# Pocket Flow Cookbook
<div align="center">
| Name | Difficulty | Description |
| :-------------: | :-------------: | :--------------------- |
| [Chat](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-chat) | ☆☆☆ <br> *Dummy* | A basic chat bot with conversation history |
| [Structured Output](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-structured-output) | ☆☆☆ <br> *Dummy* | Extracting structured data from resumes by prompting |
| [Workflow](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-workflow) | ☆☆☆ <br> *Dummy* | A writing workflow that outlines, writes content, and applies styling |
| [Agent](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-agent) | ☆☆☆ <br> *Dummy* | A research agent that can search the web and answer questions |
| [RAG](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-rag) | ☆☆☆ <br> *Dummy* | A simple Retrieval-augmented Generation process |
| [Map-Reduce](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-map-reduce) | ☆☆☆ <br> *Dummy* | A resume qualification processor using map-reduce pattern for batch evaluation |
| [Streaming](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-llm-streaming) | ☆☆☆ <br> *Dummy* | A real-time LLM streaming demo with user interrupt capability |
| [Chat Guardrail](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-chat-guardrail) | ☆☆☆ <br> *Dummy* | A travel advisor chatbot that only processes travel-related queries |
| [Multi-Agent](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-multi-agent) | ★☆☆ <br> *Beginner* | A Taboo word game for asynchronous communication between two agents |
| [Supervisor](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-supervisor) | ★☆☆ <br> *Beginner* | Research agent is getting unreliable... Let's build a supervision process|
| [Parallel](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-parallel-batch) | ★☆☆ <br> *Beginner* | A parallel execution demo that shows 3x speedup |
| [Parallel Flow](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-parallel-batch-flow) | ★☆☆ <br> *Beginner* | A parallel image processing demo showing 8x speedup with multiple filters |
| [Thinking](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-thinking) | ★☆☆ <br> *Beginner* | Solve complex reasoning problems through Chain-of-Thought |
| [Memory](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-chat-memory) | ★☆☆ <br> *Beginner* | A chat bot with short-term and long-term memory |
| [MCP](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-mcp) | ★☆☆ <br> *Beginner* | Agent using Model Context Protocol for numerical operations |
| [Tracing](https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-tracing) | ★☆☆ <br> *Beginner* | Trace and visualize the execution of your flow |
</div>
👀 Want to see other tutorials? [Create an issue!](https://github.com/The-Pocket/PocketFlow/issues/new)
================================================
FILE: cookbook/data/PaulGrahamEssaysLarge/addiction.txt
================================================
July 2010What hard liquor, cigarettes, heroin, and crack have in common is
that they're all more concentrated forms of less addictive predecessors.
Most if not all the things we describe as addictive are. And the
scary thing is, the process that created them is accelerating.We wouldn't want to stop it. It's the same process that cures
diseases: technological progress. Technological progress means
making things do more of what we want. When the thing we want is
something we want to want, we consider technological progress good.
If some new technique makes solar cells x% more efficient, that
seems strictly better. When progress concentrates something we
don't want to want—when it transforms opium into heroin—it seems
bad. But it's the same process at work.
[1]No one doubts this process is accelerating, which means increasing
numbers of things we like will be transformed into things we like
too much.
[2]As far as I know there's no word for something we like too much.
The closest is the colloquial sense of "addictive." That usage has
become increasingly common during my lifetime. And it's clear why:
there are an increasing number of things we need it for. At the
extreme end of the spectrum are crack and meth. Food has been
transformed by a combination of factory farming and innovations in
food processing into something with way more immediate bang for the
buck, and you can see the results in any town in America. Checkers
and solitaire have been replaced by World of Warcraft and FarmVille.
TV has become much more engaging, and even so it can't compete with Facebook.The world is more addictive than it was 40 years ago. And unless
the forms of technological progress that produced these things are
subject to different laws than technological progress in general,
the world will get more addictive in the next 40 years than it did
in the last 40.The next 40 years will bring us some wonderful things. I don't
mean to imply they're all to be avoided. Alcohol is a dangerous
drug, but I'd rather live in a world with wine than one without.
Most people can coexist with alcohol; but you have to be careful.
More things we like will mean more things we have to be careful
about.Most people won't, unfortunately. Which means that as the world
becomes more addictive, the two senses in which one can live a
normal life will be driven ever further apart. One sense of "normal"
is statistically normal: what everyone else does. The other is the
sense we mean when we talk about the normal operating range of a
piece of machinery: what works best.These two senses are already quite far apart. Already someone
trying to live well would seem eccentrically abstemious in most of
the US. That phenomenon is only going to become more pronounced.
You can probably take it as a rule of thumb from now on that if
people don't think you're weird, you're living badly.Societies eventually develop antibodies to addictive new things.
I've seen that happen with cigarettes. When cigarettes first
appeared, they spread the way an infectious disease spreads through
a previously isolated population. Smoking rapidly became a
(statistically) normal thing. There were ashtrays everywhere. We
had ashtrays in our house when I was a kid, even though neither of
my parents smoked. You had to for guests.As knowledge spread about the dangers of smoking, customs changed.
In the last 20 years, smoking has been transformed from something
that seemed totally normal into a rather seedy habit: from something
movie stars did in publicity shots to something small huddles of
addicts do outside the doors of office buildings. A lot of the
change was due to legislation, of course, but the legislation
couldn't have happened if customs hadn't already changed.It took a while though—on the order of 100 years. And unless the
rate at which social antibodies evolve can increase to match the
accelerating rate at which technological progress throws off new
addictions, we'll be increasingly unable to rely on customs to
protect us.
[3]
Unless we want to be canaries in the coal mine
of each new addiction—the people whose sad example becomes a
lesson to future generations—we'll have to figure out for ourselves
what to avoid and how. It will actually become a reasonable strategy
(or a more reasonable strategy) to suspect
everything new.In fact, even that won't be enough. We'll have to worry not just
about new things, but also about existing things becoming more
addictive. That's what bit me. I've avoided most addictions, but
the Internet got me because it became addictive while I was using
it.
[4]Most people I know have problems with Internet addiction. We're
all trying to figure out our own customs for getting free of it.
That's why I don't have an iPhone, for example; the last thing I
want is for the Internet to follow me out into the world.
[5]
My latest trick is taking long hikes. I used to think running was a
better form of exercise than hiking because it took less time. Now
the slowness of hiking seems an advantage, because the longer I
spend on the trail, the longer I have to think without interruption.Sounds pretty eccentric, doesn't it? It always will when you're
trying to solve problems where there are no customs yet to guide
you. Maybe I can't plead Occam's razor; maybe I'm simply eccentric.
But if I'm right about the acceleration of addictiveness, then this
kind of lonely squirming to avoid it will increasingly be the fate
of anyone who wants to get things done. We'll increasingly be
defined by what we say no to.
Notes[1]
Could you restrict technological progress to areas where you
wanted it? Only in a limited way, without becoming a police state.
And even then your restrictions would have undesirable side effects.
"Good" and "bad" technological progress aren't sharply differentiated,
so you'd find you couldn't slow the latter without also slowing the
former. And in any case, as Prohibition and the "war on drugs"
show, bans often do more harm than good.[2]
Technology has always been accelerating. By Paleolithic
standards, technology evolved at a blistering pace in the Neolithic
period.[3]
Unless we mass produce social customs. I suspect the recent
resurgence of evangelical Christianity in the US is partly a reaction
to drugs. In desperation people reach for the sledgehammer; if
their kids won't listen to them, maybe they'll listen to God. But
that solution has broader consequences than just getting kids to
say no to drugs. You end up saying no to
science as well.
I worry we may be heading for a future in which only a few people
plot their own itinerary through no-land, while everyone else books
a package tour. Or worse still, has one booked for them by the
government.[4]
People commonly use the word "procrastination" to describe
what they do on the Internet. It seems to me too mild to describe
what's happening as merely not-doing-work. We don't call it
procrastination when someone gets drunk instead of working.[5]
Several people have told me they like the iPad because it
lets them bring the Internet into situations where a laptop would
be too conspicuous. In other words, it's a hip flask. (This is
true of the iPhone too, of course, but this advantage isn't as
obvious because it reads as a phone, and everyone's used to those.)Thanks to Sam Altman, Patrick Collison, Jessica Livingston, and
Robert Morris for reading drafts of this.
================================================
FILE: cookbook/data/PaulGrahamEssaysLarge/aord.txt
================================================
October 2015When I talk to a startup that's been operating for more than 8 or
9 months, the first thing I want to know is almost always the same.
Assuming their expenses remain constant and their revenue growth
is what it has been over the last several months, do they make it to
profitability on the money they have left? Or to put it more
dramatically, by default do they live or die?The startling thing is how often the founders themselves don't know.
Half the founders I talk to don't know whether they're default alive
or default dead.If you're among that number, Trevor Blackwell has made a handy
calculator you can use to find out.The reason I want to know first whether a startup is default alive
or default dead is that the rest of the conversation depends on the
answer. If the company is default alive, we can talk about ambitious
new things they could do. If it's default dead, we probably need
to talk about how to save it. We know the current trajectory ends
badly. How can they get off that trajectory?Why do so few founders know whether they're default alive or default
dead? Mainly, I think, because they're not used to asking that.
It's not a question that makes sense to ask early on, any more than
it makes sense to ask a 3 year old how he plans to support
himself. But as the company grows older, the question switches from
meaningless to critical. That kind of switch often takes people
by surprise.I propose the following solution: instead of starting to ask too
late whether you're default alive or default dead, start asking too
early. It's hard to say precisely when the question switches
polarity. But it's probably not that dangerous to start worrying
too early that you're default dead, whereas it's very dangerous to
start worrying too late.The reason is a phenomenon I wrote about earlier: the
fatal pinch.
The fatal pinch is default dead + slow growth + not enough
time to fix it. And the way founders end up in it is by not realizing
that's where they're headed.There is another reason founders don't ask themselves whether they're
default alive or default dead: they assume it will be easy to raise
more money. But that assumption is often false, and worse still, the
more you depend on it, the falser it becomes.Maybe it will help to separate facts from hopes. Instead of thinking
of the future with vague optimism, explicitly separate the components.
Say "We're default dead, but we're counting on investors to save
us." Maybe as you say that, it will set off the same alarms in your
head that it does in mine. And if you set off the alarms sufficiently
early, you may be able to avoid the fatal pinch.It would be safe to be default dead if you could count on investors
saving you. As a rule their interest is a function of
growth. If you have steep revenue growth, say over 5x a year, you
can start to count on investors being interested even if you're not
profitable.
[1]
But investors are so fickle that you can never
do more than start to count on them. Sometimes something about your
business will spook investors even if your growth is great. So no
matter how good your growth is, you can never safely treat fundraising
as more than a plan A. You should always have a plan B as well: you
should know (as in write down) precisely what you'll need to do to
survive if you can't raise more money, and precisely when you'll
have to switch to plan B if plan A isn't working.In any case, growing fast versus operating cheaply is far from the
sharp dichotomy many founders assume it to be. In practice there
is surprisingly little connection between how much a startup spends
and how fast it grows. When a startup grows fast, it's usually
because the product hits a nerve, in the sense of hitting some big
need straight on. When a startup spends a lot, it's usually because
the product is expensive to develop or sell, or simply because
they're wasteful.If you're paying attention, you'll be asking at this point not just
how to avoid the fatal pinch, but how to avoid being default dead.
That one is easy: don't hire too fast. Hiring too fast is by far
the biggest killer of startups that raise money.
[2]Founders tell themselves they need to hire in order to grow. But
most err on the side of overestimating this need rather than
underestimating it. Why? Partly because there's so much work to
do. Naive founders think that if they can just hire enough
people, it will all get done. Partly because successful startups have
lots of employees, so it seems like that's what one does in order
to be successful. In fact the large staffs of successful startups
are probably more the effect of growth than the cause. And
partly because when founders have slow growth they don't want to
face what is usually the real reason: the product is not appealing
enough.Plus founders who've just raised money are often encouraged to
overhire by the VCs who funded them. Kill-or-cure strategies are
optimal for VCs because they're protected by the portfolio effect.
VCs want to blow you up, in one sense of the phrase or the other.
But as a founder your incentives are different. You want above all
to survive.
[3]Here's a common way startups die. They make something moderately
appealing and have decent initial growth. They raise their first
round fairly easily, because the founders seem smart and the idea
sounds plausible. But because the product is only moderately
appealing, growth is ok but not great. The founders convince
themselves that hiring a bunch of people is the way to boost growth.
Their investors agree. But (because the product is only moderately
appealing) the growth never comes. Now they're rapidly running out
of runway. They hope further investment will save them. But because
they have high expenses and slow growth, they're now unappealing
to investors. They're unable to raise more, and the company dies.What the company should have done is address the fundamental problem:
that the product is only moderately appealing. Hiring people is
rarely the way to fix that. More often than not it makes it harder.
At this early stage, the product needs to evolve more than to be
"built out," and that's usually easier with fewer people.
[4]Asking whether you're default alive or default dead may save you
from this. Maybe the alarm bells it sets off will counteract the
forces that push you to overhire. Instead you'll be compelled to
seek growth in other ways. For example, by doing
things that don't scale, or by redesigning the product in the
way only founders can.
And for many if not most startups, these paths to growth will be
the ones that actually work.Airbnb waited 4 months after raising money at the end of Y Combinator
before they hired their first employee. In the meantime the founders
were terribly overworked. But they were overworked evolving Airbnb
into the astonishingly successful organism it is now.Notes[1]
Steep usage growth will also interest investors. Revenue
will ultimately be a constant multiple of usage, so x% usage growth
predicts x% revenue growth. But in practice investors discount
merely predicted revenue, so if you're measuring usage you need a
higher growth rate to impress investors.[2]
Startups that don't raise money are saved from hiring too
fast because they can't afford to. But that doesn't mean you should
avoid raising money in order to avoid this problem, any more than
that total abstinence is the only way to avoid becoming an alcoholic.[3]
I would not be surprised if VCs' tendency to push founders
to overhire is not even in their own interest. They don't know how
many of the companies that get killed by overspending might have
done well if they'd survived. My guess is a significant number.[4]
After reading a draft, Sam Altman wrote:"I think you should make the hiring point more strongly. I think
it's roughly correct to say that YC's most successful companies
have never been the fastest to hire, and one of the marks of a great
founder is being able to resist this urge."Paul Buchheit adds:"A related problem that I see a lot is premature scaling—founders
take a small business that isn't really working (bad unit economics,
typically) and then scale it up because they want impressive growth
numbers. This is similar to over-hiring in that it makes the business
much harder to fix once it's big, plus they are bleeding cash really
fast."
Thanks to Sam Altman, Paul Buchheit, Joe Gebbia, Jessica Livingston,
and Geoff Ralston for reading drafts of this.
================================================
FILE: cookbook/data/PaulGrahamEssaysLarge/apple.txt
================================================
Want to start a startup? Get funded by
Y Combinator.
November 2009I don't think Apple realizes how badly the App Store approval process
is broken. Or rather, I don't think they realize how much it matters
that it's broken.The way Apple runs the App Store has harmed their reputation with
programmers more than anything else they've ever done.
Their reputation with programmers used to be great.
It used to be the most common complaint you heard
about Apple was that their fans admired them too uncritically.
The App Store has changed that. Now a lot of programmers
have started to see Apple as evil.How much of the goodwill Apple once had with programmers have they
lost over the App Store? A third? Half? And that's just so far.
The App Store is an ongoing karma leak.* * *How did Apple get into this mess? Their fundamental problem is
that they don't understand software.They treat iPhone apps the way they treat the music they sell through
iTunes. Apple is the channel; they own the user; if you want to
reach users, you do it on their terms. The record labels agreed,
reluctantly. But this model doesn't work for software. It doesn't
work for an intermediary to own the user. The software business
learned that in the early 1980s, when companies like VisiCorp showed
that although the words "software" and "publisher" fit together,
the underlying concepts don't. Software isn't like music or books.
It's too complicated for a third party to act as an intermediary
between developer and user. And yet that's what Apple is trying
to be with the App Store: a software publisher. And a particularly
overreaching one at that, with fussy tastes and a rigidly enforced
house style.If software publishing didn't work in 1980, it works even less now
that software development has evolved from a small number of big
releases to a constant stream of small ones. But Apple doesn't
understand that either. Their model of product development derives
from hardware. They work on something till they think it's finished,
then they release it. You have to do that with hardware, but because
software is so easy to change, its design can benefit from evolution.
The standard way to develop applications now is to launch fast and
iterate. Which means it's a disaster to have long, random delays
each time you release a new version.Apparently Apple's attitude is that developers should be more careful
when they submit a new version to the App Store. They would say
that. But powerful as they are, they're not powerful enough to
turn back the evolution of technology. Programmers don't use
launch-fast-and-iterate out of laziness. They use it because it
yields the best results. By obstructing that process, Apple is
making them do bad work, and programmers hate that as much as Apple
would.How would Apple like it if when they discovered a serious bug in
OS X, instead of releasing a software update immediately, they had
to submit their code to an intermediary who sat on it for a month
and then rejected it because it contained an icon they didn't like?By breaking software development, Apple gets the opposite of what
they intended: the version of an app currently available in the App
Store tends to be an old and buggy one. One developer told me:
As a result of their process, the App Store is full of half-baked
applications. I make a new version almost every day that I release
to beta users. The version on the App Store feels old and crappy.
I'm sure that a lot of developers feel this way: One emotion is
"I'm not really proud about what's in the App Store", and it's
combined with the emotion "Really, it's Apple's fault."
Another wrote:
I believe that they think their approval process helps users by
ensuring quality. In reality, bugs like ours get through all the
time and then it can take 4-8 weeks to get that bug fix approved,
leaving users to think that iPhone apps sometimes just don't work.
Worse for Apple, these apps work just fine on other platforms
that have immediate approval processes.
Actually I suppose Apple has a third misconception: that all the
complaints about App Store approvals are not a serious problem.
They must hear developers complaining. But partners and suppliers
are always complaining. It would be a bad sign if they weren't;
it would mean you were being too easy on them. Meanwhile the iPhone
is selling better than ever. So why do they need to fix anything?They get away with maltreating developers, in the short term, because
they make such great hardware. I just bought a new 27" iMac a
couple days ago. It's fabulous. The screen's too shiny, and the
disk is surprisingly loud, but it's so beautiful that you can't
make yourself care.So I bought it, but I bought it, for the first time, with misgivings.
I felt the way I'd feel buying something made in a country with a
bad human rights record. That was new. In the past when I bought
things from Apple it was an unalloyed pleasure. Oh boy! They make
such great stuff. This time it felt like a Faustian bargain. They
make such great stuff, but they're such assholes. Do I really want
to support this company?* * *Should Apple care what people like me think? What difference does
it make if they alienate a small minority of their users?There are a couple reasons they should care. One is that these
users are the people they want as employees. If your company seems
evil, the best programmers won't work for you. That hurt Microsoft
a lot starting in the 90s. Programmers started to feel sheepish
about working there. It seemed like selling out. When people from
Microsoft were talking to other programmers and they mentioned where
they worked, there were a lot of self-deprecating jokes about having
gone over to the dark side. But the real problem for Microsoft
wasn't the embarrassment of the people they hired. It was the
people they never got. And you know who got them? Google and
Apple. If Microsoft was the Empire, they were the Rebel Alliance.
And it's largely because they got more of the best people that
Google and Apple are doing so much better than Microsoft today.Why are programmers so fussy about their employers' morals? Partly
because they can afford to be. The best programmers can work
wherever they want. They don't have to work for a company they
have qualms about.But the other reason programmers are fussy, I think, is that evil
begets stupidity. An organization that wins by exercising power
starts to lose the ability to win by doing better work. And it's
not fun for a smart person to work in a place where the best ideas
aren't the ones that win. I think the reason Google embraced "Don't
be evil" so eagerly was not so much to impress the outside world
as to inoculate themselves against arrogance.
[1]That has worked for Google so far. They've become more
bureaucratic, but otherwise they seem to have held true to their
original principles. With Apple that seems less the case. When you
look at the famous
1984 ad
now, it's easier to imagine Apple as the
dictator on the screen than the woman with the hammer.
[2]
In fact, if you read the dictator's speech it sounds uncannily like a
prophecy of the App Store.
We have triumphed over the unprincipled dissemination of facts.We have created, for the first time in all history, a garden of
pure ideology, where each worker may bloom secure from the pests
of contradictory and confusing truths.
The other reason Apple should care what programmers think of them
is that when you sell a platform, developers make or break you. If
anyone should know this, Apple should. VisiCalc made the Apple II.And programmers build applications for the platforms they use. Most
applications—most startups, probably—grow out of personal projects.
Apple itself did. Apple made microcomputers because that's what
Steve Wozniak wanted for himself. He couldn't have afforded a
minicomputer.
[3]
Microsoft likewise started out making interpreters
for little microcomputers because
Bill Gates and Paul Allen were interested in using them. It's a
rare startup that doesn't build something the founders use.The main reason there are so many iPhone apps is that so many programmers
have iPhones. They may know, because they read it in an article,
that Blackberry has such and such market share. But in practice
it's as if RIM didn't exist. If they're going to build something,
they want to be able to use it themselves, and that means building
an iPhone app.So programmers continue to develop iPhone apps, even though Apple
continues to maltreat them. They're like someone stuck in an abusive
relationship. They're so attracted to the iPhone that they can't
leave. But they're looking for a way out. One wrote:
While I did enjoy developing for the iPhone, the control they
place on the App Store does not give me the drive to develop
applications as I would like. In fact I don't intend to make any
more iPhone applications unless absolutely necessary.
[4]
Can anything break this cycle? No device I've seen so far could.
Palm and RIM haven't a hope. The only credible contender is Android.
But Android is an orphan; Google doesn't really care about it, not
the way Apple cares about the iPhone. Apple cares about the iPhone
the way Google cares about search.* * *Is the future of handheld devices one locked down by Apple? It's
a worrying prospect. It would be a bummer to have another grim
monoculture like we had in the 1990s. In 1995, writing software
for end users was effectively identical with writing Windows
applications. Our horror at that prospect was the single biggest
thing that drove us to start building web apps.At least we know now what it would take to break Apple's lock.
You'd have to get iPhones out of programmers' hands. If programmers
used some other device for mobile web access, they'd start to develop
apps for that instead.How could you make a device programmers liked better than the iPhone?
It's unlikely you could make something better designed. Apple
leaves no room there. So this alternative device probably couldn't
win on general appeal. It would have to win by virtue of some
appeal it had to programmers specifically.One way to appeal to programmers is with software. If you
could think of an application programmers had to have, but that
would be impossible in the circumscribed world of the iPhone,
you could presumably get them to switch.That would definitely happen if programmers started to use handhelds
as development machines—if handhelds displaced laptops the
way laptops displaced desktops. You need more control of a development
machine than Apple will let you have over an iPhone.Could anyone make a device that you'd carry around in your pocket
like a phone, and yet would also work as a development machine?
It's hard to imagine what it would look like. But I've learned
never to say never about technology. A phone-sized device that
would work as a development machine is no more miraculous by present
standards than the iPhone itself would have seemed by the standards
of 1995.My current development machine is a MacBook Air, which I use with
an external monitor and keyboard in my office, and by itself when
traveling. If there was a version half the size I'd prefer it.
That still wouldn't be small enough to carry around everywhere like
a phone, but we're within a factor of 4 or so. Surely that gap is
bridgeable. In fact, let's make it an
RFS. Wanted:
Woman with hammer.Notes[1]
When Google adopted "Don't be evil," they were still so small
that no one would have expected them to be, yet.
[2]
The dictator in the 1984 ad isn't Microsoft, incidentally;
it's IBM. IBM seemed a lot more frightening in those days, but
they were friendlier to developers than Apple is now.[3]
He couldn't even afford a monitor. That's why the Apple
I used a TV as a monitor.[4]
Severa
gitextract_1kfwxukd/
├── .cursor/
│ └── rules/
│ ├── core_abstraction/
│ │ ├── async.mdc
│ │ ├── batch.mdc
│ │ ├── communication.mdc
│ │ ├── flow.mdc
│ │ ├── node.mdc
│ │ └── parallel.mdc
│ ├── design_pattern/
│ │ ├── agent.mdc
│ │ ├── mapreduce.mdc
│ │ ├── multi_agent.mdc
│ │ ├── rag.mdc
│ │ ├── structure.mdc
│ │ └── workflow.mdc
│ ├── guide_for_pocketflow.mdc
│ └── utility_function/
│ ├── chunking.mdc
│ ├── embedding.mdc
│ ├── llm.mdc
│ ├── text_to_speech.mdc
│ ├── vector.mdc
│ ├── viz.mdc
│ └── websearch.mdc
├── .cursorrules
├── .gitignore
├── LICENSE
├── README.md
├── cookbook/
│ ├── README.md
│ ├── data/
│ │ └── PaulGrahamEssaysLarge/
│ │ ├── addiction.txt
│ │ ├── aord.txt
│ │ ├── apple.txt
│ │ ├── avg.txt
│ │ └── before.txt
│ ├── pocketflow-a2a/
│ │ ├── README.md
│ │ ├── a2a_client.py
│ │ ├── a2a_server.py
│ │ ├── common/
│ │ │ ├── __init__.py
│ │ │ ├── client/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── card_resolver.py
│ │ │ │ └── client.py
│ │ │ ├── server/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── server.py
│ │ │ │ ├── task_manager.py
│ │ │ │ └── utils.py
│ │ │ ├── types.py
│ │ │ └── utils/
│ │ │ ├── in_memory_cache.py
│ │ │ └── push_notification_auth.py
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── task_manager.py
│ │ └── utils.py
│ ├── pocketflow-agent/
│ │ ├── README.md
│ │ ├── demo.ipynb
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-agent-skills/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── skills/
│ │ │ ├── checklist_writer.md
│ │ │ └── executive_brief.md
│ │ └── utils.py
│ ├── pocketflow-async-basic/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-batch/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── translations/
│ │ │ ├── README_CHINESE.md
│ │ │ ├── README_FRENCH.md
│ │ │ ├── README_GERMAN.md
│ │ │ ├── README_JAPANESE.md
│ │ │ ├── README_KOREAN.md
│ │ │ ├── README_PORTUGUESE.md
│ │ │ ├── README_RUSSIAN.md
│ │ │ └── README_SPANISH.md
│ │ └── utils.py
│ ├── pocketflow-batch-flow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-batch-node/
│ │ ├── README.md
│ │ ├── data/
│ │ │ └── sales.csv
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-chat/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-chat-guardrail/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-chat-memory/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── call_llm.py
│ │ ├── get_embedding.py
│ │ └── vector_index.py
│ ├── pocketflow-cli-hitl/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-code-generator/
│ │ ├── README.md
│ │ ├── doc/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── call_llm.py
│ │ └── code_executor.py
│ ├── pocketflow-communication/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-fastapi-background/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── static/
│ │ │ ├── index.html
│ │ │ └── progress.html
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-fastapi-hitl/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── server.py
│ │ ├── static/
│ │ │ └── style.css
│ │ ├── templates/
│ │ │ └── index.html
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── process_task.py
│ ├── pocketflow-fastapi-websocket/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── static/
│ │ │ └── index.html
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── stream_llm.py
│ ├── pocketflow-flow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ └── requirements.txt
│ ├── pocketflow-google-calendar/
│ │ ├── .gitignore
│ │ ├── Pipfile
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── google_calendar.py
│ ├── pocketflow-gradio-hitl/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── call_llm.py
│ │ ├── call_mock_api.py
│ │ ├── conversation.py
│ │ └── format_chat_history.py
│ ├── pocketflow-hello-world/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-llm-streaming/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-majority-vote/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-map-reduce/
│ │ ├── README.md
│ │ ├── data/
│ │ │ ├── resume1.txt
│ │ │ ├── resume2.txt
│ │ │ ├── resume3.txt
│ │ │ ├── resume4.txt
│ │ │ └── resume5.txt
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-mcp/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── simple_server.py
│ │ └── utils.py
│ ├── pocketflow-multi-agent/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-nested-batch/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── school/
│ │ ├── class_a/
│ │ │ ├── student1.txt
│ │ │ └── student2.txt
│ │ └── class_b/
│ │ ├── student3.txt
│ │ └── student4.txt
│ ├── pocketflow-node/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ └── call_llm.py
│ ├── pocketflow-parallel-batch/
│ │ ├── README.md
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── translations/
│ │ │ ├── README_CHINESE.md
│ │ │ ├── README_FRENCH.md
│ │ │ ├── README_GERMAN.md
│ │ │ ├── README_JAPANESE.md
│ │ │ ├── README_KOREAN.md
│ │ │ ├── README_PORTUGUESE.md
│ │ │ ├── README_RUSSIAN.md
│ │ │ └── README_SPANISH.md
│ │ └── utils.py
│ ├── pocketflow-parallel-batch-flow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── requirements.txt
│ ├── pocketflow-rag/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-streamlit-fsm/
│ │ ├── README.md
│ │ ├── app.py
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── generate_image.py
│ ├── pocketflow-structured-output/
│ │ ├── README.md
│ │ ├── data.txt
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-supervisor/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-tao/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ └── utils.py
│ ├── pocketflow-text2sql/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── populate_db.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ └── call_llm.py
│ ├── pocketflow-thinking/
│ │ ├── README.md
│ │ ├── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils.py
│ ├── pocketflow-tool-crawler/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ ├── crawler.py
│ │ │ └── parser.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tool-database/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ └── database.py
│ │ └── utils/
│ │ └── __init__.py
│ ├── pocketflow-tool-embeddings/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ └── embeddings.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tool-pdf-vision/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ ├── pdf.py
│ │ │ └── vision.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tool-search/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ ├── tools/
│ │ │ ├── parser.py
│ │ │ └── search.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── call_llm.py
│ ├── pocketflow-tracing/
│ │ ├── README.md
│ │ ├── examples/
│ │ │ ├── async_example.py
│ │ │ └── basic_example.py
│ │ ├── requirements.txt
│ │ ├── setup.py
│ │ ├── test_tracing.py
│ │ ├── tracing/
│ │ │ ├── __init__.py
│ │ │ ├── config.py
│ │ │ ├── core.py
│ │ │ └── decorator.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ └── setup.py
│ ├── pocketflow-visualization/
│ │ ├── README.md
│ │ ├── async_flow.py
│ │ ├── async_loop_flow.py
│ │ ├── visualize.py
│ │ └── viz/
│ │ ├── flow_visualization.html
│ │ └── flow_visualization.json
│ ├── pocketflow-voice-chat/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── design.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── audio_utils.py
│ │ ├── call_llm.py
│ │ ├── speech_to_text.py
│ │ └── text_to_speech.py
│ ├── pocketflow-workflow/
│ │ ├── README.md
│ │ ├── flow.py
│ │ ├── main.py
│ │ ├── nodes.py
│ │ ├── requirements.txt
│ │ └── utils/
│ │ └── call_llm.py
│ └── pocketflow_demo.ipynb
├── docs/
│ ├── _config.yml
│ ├── _includes/
│ │ └── footer_custom.html
│ ├── core_abstraction/
│ │ ├── async.md
│ │ ├── batch.md
│ │ ├── communication.md
│ │ ├── flow.md
│ │ ├── index.md
│ │ ├── node.md
│ │ └── parallel.md
│ ├── design_pattern/
│ │ ├── agent.md
│ │ ├── index.md
│ │ ├── mapreduce.md
│ │ ├── multi_agent.md
│ │ ├── rag.md
│ │ ├── structure.md
│ │ └── workflow.md
│ ├── guide.md
│ ├── index.md
│ └── utility_function/
│ ├── chunking.md
│ ├── embedding.md
│ ├── index.md
│ ├── llm.md
│ ├── text_to_speech.md
│ ├── vector.md
│ ├── viz.md
│ └── websearch.md
├── pocketflow/
│ ├── __init__.py
│ └── __init__.pyi
├── setup.py
├── tests/
│ ├── test_async_batch_flow.py
│ ├── test_async_batch_node.py
│ ├── test_async_flow.py
│ ├── test_async_parallel_batch_flow.py
│ ├── test_async_parallel_batch_node.py
│ ├── test_batch_flow.py
│ ├── test_batch_node.py
│ ├── test_fall_back.py
│ ├── test_flow_basic.py
│ └── test_flow_composition.py
└── utils/
└── update_pocketflow_mdc.py
SYMBOL INDEX (1175 symbols across 195 files)
FILE: cookbook/pocketflow-a2a/a2a_client.py
function colorize (line 42) | def colorize(color, text):
function cli (line 51) | async def cli(agent_url: str):
FILE: cookbook/pocketflow-a2a/a2a_server.py
function main (line 29) | def main(host, port):
FILE: cookbook/pocketflow-a2a/common/client/card_resolver.py
class A2ACardResolver (line 9) | class A2ACardResolver:
method __init__ (line 10) | def __init__(self, base_url, agent_card_path="/.well-known/agent.json"):
method get_agent_card (line 14) | def get_agent_card(self) -> AgentCard:
FILE: cookbook/pocketflow-a2a/common/client/client.py
class A2AClientError (line 34) | class A2AClientError(Exception):
method __init__ (line 36) | def __init__(self, message):
class RpcError (line 39) | class RpcError(Exception):
method __init__ (line 42) | def __init__(self, code: int, message: str, data: Any = None):
class A2AClient (line 48) | class A2AClient:
method __init__ (line 49) | def __init__(self, agent_card: AgentCard = None, url: str = None):
method _generateRequestId (line 58) | def _generateRequestId(self):
method _send_request (line 62) | async def _send_request(self, request: JSONRPCRequest) -> dict[str, Any]:
method send_task (line 106) | async def send_task(self, payload: dict[str, Any]) -> SendTaskResponse:
method send_task_streaming (line 111) | async def send_task_streaming(
method get_task (line 160) | async def get_task(self, payload: dict[str, Any]) -> GetTaskResponse:
method cancel_task (line 165) | async def cancel_task(self, payload: dict[str, Any]) -> CancelTaskResp...
method set_task_callback (line 170) | async def set_task_callback(
method get_task_callback (line 177) | async def get_task_callback(
FILE: cookbook/pocketflow-a2a/common/server/server.py
class A2AServer (line 32) | class A2AServer:
method __init__ (line 33) | def __init__(
method start (line 52) | def start(self):
method _get_agent_card (line 64) | def _get_agent_card(self, request: Request) -> JSONResponse:
method _process_request (line 68) | async def _process_request(self, request: Request):
method _handle_exception (line 115) | def _handle_exception(self, e: Exception, req_id=None) -> JSONResponse...
method _create_response (line 131) | def _create_response(self, result: Any) -> JSONResponse | EventSourceR...
FILE: cookbook/pocketflow-a2a/common/server/task_manager.py
class TaskManager (line 40) | class TaskManager(ABC):
method on_get_task (line 42) | async def on_get_task(self, request: GetTaskRequest) -> GetTaskResponse:
method on_cancel_task (line 46) | async def on_cancel_task(self, request: CancelTaskRequest) -> CancelTa...
method on_send_task (line 50) | async def on_send_task(self, request: SendTaskRequest) -> SendTaskResp...
method on_send_task_subscribe (line 54) | async def on_send_task_subscribe(
method on_set_task_push_notification (line 60) | async def on_set_task_push_notification(
method on_get_task_push_notification (line 66) | async def on_get_task_push_notification(
method on_resubscribe_to_task (line 72) | async def on_resubscribe_to_task(
class InMemoryTaskManager (line 78) | class InMemoryTaskManager(TaskManager):
method __init__ (line 79) | def __init__(self):
method on_get_task (line 86) | async def on_get_task(self, request: GetTaskRequest) -> GetTaskResponse:
method on_cancel_task (line 101) | async def on_cancel_task(self, request: CancelTaskRequest) -> CancelTa...
method on_send_task (line 113) | async def on_send_task(self, request: SendTaskRequest) -> SendTaskResp...
method on_send_task_subscribe (line 117) | async def on_send_task_subscribe(
method set_push_notification_info (line 122) | async def set_push_notification_info(self, task_id: str, notification_...
method get_push_notification_info (line 132) | async def get_push_notification_info(self, task_id: str) -> PushNotifi...
method has_push_notification_info (line 142) | async def has_push_notification_info(self, task_id: str) -> bool:
method on_set_task_push_notification (line 147) | async def on_set_task_push_notification(
method on_get_task_push_notification (line 166) | async def on_get_task_push_notification(
method upsert_task (line 185) | async def upsert_task(self, task_send_params: TaskSendParams) -> Task:
method on_resubscribe_to_task (line 203) | async def on_resubscribe_to_task(
method update_store (line 208) | async def update_store(
method append_task_history (line 230) | def append_task_history(self, task: Task, historyLength: int | None):
method setup_sse_consumer (line 239) | async def setup_sse_consumer(self, task_id: str, is_resubscribe: bool ...
method enqueue_events_for_sse (line 251) | async def enqueue_events_for_sse(self, task_id, task_update_event):
method dequeue_events_for_sse (line 260) | async def dequeue_events_for_sse(
FILE: cookbook/pocketflow-a2a/common/server/utils.py
function are_modalities_compatible (line 9) | def are_modalities_compatible(
function new_incompatible_types_error (line 23) | def new_incompatible_types_error(request_id):
function new_not_implemented_error (line 27) | def new_not_implemented_error(request_id):
FILE: cookbook/pocketflow-a2a/common/types.py
class TaskState (line 11) | class TaskState(str, Enum):
class TextPart (line 21) | class TextPart(BaseModel):
class FileContent (line 27) | class FileContent(BaseModel):
method check_content (line 34) | def check_content(self) -> Self:
class FilePart (line 44) | class FilePart(BaseModel):
class DataPart (line 50) | class DataPart(BaseModel):
class Message (line 59) | class Message(BaseModel):
class TaskStatus (line 65) | class TaskStatus(BaseModel):
method serialize_dt (line 71) | def serialize_dt(self, dt: datetime, _info):
class Artifact (line 75) | class Artifact(BaseModel):
class Task (line 85) | class Task(BaseModel):
class TaskStatusUpdateEvent (line 94) | class TaskStatusUpdateEvent(BaseModel):
class TaskArtifactUpdateEvent (line 101) | class TaskArtifactUpdateEvent(BaseModel):
class AuthenticationInfo (line 107) | class AuthenticationInfo(BaseModel):
class PushNotificationConfig (line 114) | class PushNotificationConfig(BaseModel):
class TaskIdParams (line 120) | class TaskIdParams(BaseModel):
class TaskQueryParams (line 125) | class TaskQueryParams(TaskIdParams):
class TaskSendParams (line 129) | class TaskSendParams(BaseModel):
class TaskPushNotificationConfig (line 139) | class TaskPushNotificationConfig(BaseModel):
class JSONRPCMessage (line 147) | class JSONRPCMessage(BaseModel):
class JSONRPCRequest (line 152) | class JSONRPCRequest(JSONRPCMessage):
class JSONRPCError (line 157) | class JSONRPCError(BaseModel):
class JSONRPCResponse (line 163) | class JSONRPCResponse(JSONRPCMessage):
class SendTaskRequest (line 168) | class SendTaskRequest(JSONRPCRequest):
class SendTaskResponse (line 173) | class SendTaskResponse(JSONRPCResponse):
class SendTaskStreamingRequest (line 177) | class SendTaskStreamingRequest(JSONRPCRequest):
class SendTaskStreamingResponse (line 182) | class SendTaskStreamingResponse(JSONRPCResponse):
class GetTaskRequest (line 186) | class GetTaskRequest(JSONRPCRequest):
class GetTaskResponse (line 191) | class GetTaskResponse(JSONRPCResponse):
class CancelTaskRequest (line 195) | class CancelTaskRequest(JSONRPCRequest):
class CancelTaskResponse (line 200) | class CancelTaskResponse(JSONRPCResponse):
class SetTaskPushNotificationRequest (line 204) | class SetTaskPushNotificationRequest(JSONRPCRequest):
class SetTaskPushNotificationResponse (line 209) | class SetTaskPushNotificationResponse(JSONRPCResponse):
class GetTaskPushNotificationRequest (line 213) | class GetTaskPushNotificationRequest(JSONRPCRequest):
class GetTaskPushNotificationResponse (line 218) | class GetTaskPushNotificationResponse(JSONRPCResponse):
class TaskResubscriptionRequest (line 222) | class TaskResubscriptionRequest(JSONRPCRequest):
class JSONParseError (line 245) | class JSONParseError(JSONRPCError):
class InvalidRequestError (line 251) | class InvalidRequestError(JSONRPCError):
class MethodNotFoundError (line 257) | class MethodNotFoundError(JSONRPCError):
class InvalidParamsError (line 263) | class InvalidParamsError(JSONRPCError):
class InternalError (line 269) | class InternalError(JSONRPCError):
class TaskNotFoundError (line 275) | class TaskNotFoundError(JSONRPCError):
class TaskNotCancelableError (line 281) | class TaskNotCancelableError(JSONRPCError):
class PushNotificationNotSupportedError (line 287) | class PushNotificationNotSupportedError(JSONRPCError):
class UnsupportedOperationError (line 293) | class UnsupportedOperationError(JSONRPCError):
class ContentTypeNotSupportedError (line 299) | class ContentTypeNotSupportedError(JSONRPCError):
class AgentProvider (line 305) | class AgentProvider(BaseModel):
class AgentCapabilities (line 310) | class AgentCapabilities(BaseModel):
class AgentAuthentication (line 316) | class AgentAuthentication(BaseModel):
class AgentSkill (line 321) | class AgentSkill(BaseModel):
class AgentCard (line 331) | class AgentCard(BaseModel):
class A2AClientError (line 345) | class A2AClientError(Exception):
class A2AClientHTTPError (line 349) | class A2AClientHTTPError(A2AClientError):
method __init__ (line 350) | def __init__(self, status_code: int, message: str):
class A2AClientJSONError (line 356) | class A2AClientJSONError(A2AClientError):
method __init__ (line 357) | def __init__(self, message: str):
class MissingAPIKeyError (line 362) | class MissingAPIKeyError(Exception):
FILE: cookbook/pocketflow-a2a/common/utils/in_memory_cache.py
class InMemoryCache (line 8) | class InMemoryCache:
method __new__ (line 18) | def __new__(cls):
method __init__ (line 32) | def __init__(self):
method set (line 47) | def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
method get (line 64) | def get(self, key: str, default: Any = None) -> Any:
method delete (line 81) | def delete(self, key: str) -> None:
method clear (line 99) | def clear(self) -> bool:
FILE: cookbook/pocketflow-a2a/common/utils/push_notification_auth.py
class PushNotificationAuth (line 19) | class PushNotificationAuth:
method _calculate_request_body_sha256 (line 20) | def _calculate_request_body_sha256(self, data: dict[str, Any]):
class PushNotificationSenderAuth (line 34) | class PushNotificationSenderAuth(PushNotificationAuth):
method __init__ (line 35) | def __init__(self):
method verify_push_notification_url (line 40) | async def verify_push_notification_url(url: str) -> bool:
method generate_jwk (line 58) | def generate_jwk(self):
method handle_jwks_endpoint (line 63) | def handle_jwks_endpoint(self, _request: Request):
method _generate_jwt (line 70) | def _generate_jwt(self, data: dict[str, Any]):
method send_push_notification (line 86) | async def send_push_notification(self, url: str, data: dict[str, Any]):
class PushNotificationReceiverAuth (line 101) | class PushNotificationReceiverAuth(PushNotificationAuth):
method __init__ (line 102) | def __init__(self):
method load_jwks (line 106) | async def load_jwks(self, jwks_url: str):
method verify_push_notification (line 109) | async def verify_push_notification(self, request: Request) -> bool:
FILE: cookbook/pocketflow-a2a/flow.py
function create_agent_flow (line 4) | def create_agent_flow():
FILE: cookbook/pocketflow-a2a/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-a2a/nodes.py
class DecideAction (line 5) | class DecideAction(Node):
method prep (line 6) | def prep(self, shared):
method exec (line 15) | def exec(self, inputs):
method post (line 66) | def post(self, shared, prep_res, exec_res):
class SearchWeb (line 79) | class SearchWeb(Node):
method prep (line 80) | def prep(self, shared):
method exec (line 84) | def exec(self, search_query):
method post (line 91) | def post(self, shared, prep_res, exec_res):
class AnswerQuestion (line 102) | class AnswerQuestion(Node):
method prep (line 103) | def prep(self, shared):
method exec (line 107) | def exec(self, inputs):
method post (line 127) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-a2a/task_manager.py
class PocketFlowTaskManager (line 22) | class PocketFlowTaskManager(InMemoryTaskManager):
method on_send_task (line 27) | async def on_send_task(self, request: SendTaskRequest) -> SendTaskResp...
method on_send_task_subscribe (line 94) | async def on_send_task_subscribe(
method _get_user_query (line 102) | def _get_user_query(self, task_send_params: TaskSendParams) -> str | N...
FILE: cookbook/pocketflow-a2a/utils.py
function call_llm (line 5) | def call_llm(prompt):
function search_web (line 13) | def search_web(query):
FILE: cookbook/pocketflow-agent-skills/flow.py
function create_flow (line 5) | def create_flow():
FILE: cookbook/pocketflow-agent-skills/main.py
function parse_task (line 5) | def parse_task(default_task: str) -> str:
function main (line 12) | def main():
FILE: cookbook/pocketflow-agent-skills/nodes.py
class SelectSkill (line 5) | class SelectSkill(Node):
method prep (line 6) | def prep(self, shared):
method exec (line 12) | def exec(self, prep_res):
method post (line 29) | def post(self, shared, prep_res, exec_res):
class ApplySkill (line 36) | class ApplySkill(Node):
method prep (line 37) | def prep(self, shared):
method exec (line 44) | def exec(self, prep_res):
method post (line 62) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-agent-skills/utils.py
function load_skills (line 6) | def load_skills(skills_dir: str) -> dict[str, str]:
function call_llm (line 16) | def call_llm(prompt: str) -> str:
FILE: cookbook/pocketflow-agent/flow.py
function create_agent_flow (line 4) | def create_agent_flow():
FILE: cookbook/pocketflow-agent/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-agent/nodes.py
class DecideAction (line 6) | class DecideAction(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 16) | def exec(self, inputs):
method post (line 97) | def post(self, shared, prep_res, exec_res):
class SearchWeb (line 110) | class SearchWeb(Node):
method prep (line 111) | def prep(self, shared):
method exec (line 115) | def exec(self, search_query):
method post (line 122) | def post(self, shared, prep_res, exec_res):
class AnswerQuestion (line 133) | class AnswerQuestion(Node):
method prep (line 134) | def prep(self, shared):
method exec (line 138) | def exec(self, inputs):
method post (line 158) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-agent/utils.py
function call_llm (line 6) | def call_llm(prompt):
function search_web_duckduckgo (line 14) | def search_web_duckduckgo(query):
function search_web_brave (line 20) | def search_web_brave(query):
FILE: cookbook/pocketflow-async-basic/flow.py
class NoOp (line 6) | class NoOp(Node):
function create_flow (line 10) | def create_flow():
FILE: cookbook/pocketflow-async-basic/main.py
function main (line 4) | async def main():
FILE: cookbook/pocketflow-async-basic/nodes.py
class FetchRecipes (line 4) | class FetchRecipes(AsyncNode):
method prep_async (line 7) | async def prep_async(self, shared):
method exec_async (line 12) | async def exec_async(self, ingredient):
method post_async (line 17) | async def post_async(self, shared, prep_res, recipes):
class SuggestRecipe (line 23) | class SuggestRecipe(AsyncNode):
method prep_async (line 26) | async def prep_async(self, shared):
method exec_async (line 30) | async def exec_async(self, recipes):
method post_async (line 37) | async def post_async(self, shared, prep_res, suggestion):
class GetApproval (line 42) | class GetApproval(AsyncNode):
method prep_async (line 45) | async def prep_async(self, shared):
method exec_async (line 49) | async def exec_async(self, suggestion):
method post_async (line 54) | async def post_async(self, shared, prep_res, answer):
FILE: cookbook/pocketflow-async-basic/utils.py
function fetch_recipes (line 5) | async def fetch_recipes(ingredient):
function call_llm_async (line 23) | async def call_llm_async(prompt):
function get_user_input (line 37) | async def get_user_input(prompt):
FILE: cookbook/pocketflow-batch-flow/flow.py
function create_base_flow (line 4) | def create_base_flow():
class ImageBatchFlow (line 18) | class ImageBatchFlow(BatchFlow):
method prep (line 21) | def prep(self, shared):
function create_flow (line 40) | def create_flow():
FILE: cookbook/pocketflow-batch-flow/main.py
function main (line 6) | def main():
FILE: cookbook/pocketflow-batch-flow/nodes.py
class LoadImage (line 7) | class LoadImage(Node):
method prep (line 10) | def prep(self, shared):
method exec (line 14) | def exec(self, image_path):
method post (line 18) | def post(self, shared, prep_res, exec_res):
class ApplyFilter (line 23) | class ApplyFilter(Node):
method prep (line 26) | def prep(self, shared):
method exec (line 30) | def exec(self, inputs):
method post (line 47) | def post(self, shared, prep_res, exec_res):
class SaveImage (line 52) | class SaveImage(Node):
method prep (line 55) | def prep(self, shared):
method exec (line 67) | def exec(self, inputs):
method post (line 73) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-batch-node/flow.py
class ShowStats (line 4) | class ShowStats(Node):
method prep (line 7) | def prep(self, shared):
method post (line 11) | def post(self, shared, prep_res, exec_res):
function create_flow (line 20) | def create_flow():
FILE: cookbook/pocketflow-batch-node/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-batch-node/nodes.py
class CSVProcessor (line 4) | class CSVProcessor(BatchNode):
method __init__ (line 7) | def __init__(self, chunk_size=1000):
method prep (line 12) | def prep(self, shared):
method exec (line 24) | def exec(self, chunk):
method post (line 39) | def post(self, shared, prep_res, exec_res_list):
FILE: cookbook/pocketflow-batch/main.py
class TranslateTextNode (line 6) | class TranslateTextNode(BatchNode):
method prep (line 7) | def prep(self, shared):
method exec (line 15) | def exec(self, data_tuple):
method post (line 32) | def post(self, shared, prep_res, exec_res_list):
FILE: cookbook/pocketflow-batch/utils.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-chat-guardrail/main.py
class UserInputNode (line 4) | class UserInputNode(Node):
method prep (line 5) | def prep(self, shared):
method exec (line 13) | def exec(self, _):
method post (line 18) | def post(self, shared, prep_res, exec_res):
class GuardrailNode (line 32) | class GuardrailNode(Node):
method prep (line 33) | def prep(self, shared):
method exec (line 38) | def exec(self, user_input):
method post (line 73) | def post(self, shared, prep_res, exec_res):
class LLMNode (line 87) | class LLMNode(Node):
method prep (line 88) | def prep(self, shared):
method exec (line 99) | def exec(self, messages):
method post (line 104) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-chat-guardrail/utils.py
function call_llm (line 4) | def call_llm(messages):
FILE: cookbook/pocketflow-chat-memory/flow.py
function create_chat_flow (line 4) | def create_chat_flow():
FILE: cookbook/pocketflow-chat-memory/main.py
function run_chat_memory_demo (line 3) | def run_chat_memory_demo():
FILE: cookbook/pocketflow-chat-memory/nodes.py
class GetUserQuestionNode (line 6) | class GetUserQuestionNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 15) | def exec(self, _):
method post (line 26) | def post(self, shared, prep_res, exec_res):
class AnswerNode (line 37) | class AnswerNode(Node):
method prep (line 38) | def prep(self, shared):
method exec (line 65) | def exec(self, messages):
method post (line 74) | def post(self, shared, prep_res, exec_res):
class EmbedNode (line 93) | class EmbedNode(Node):
method prep (line 94) | def prep(self, shared):
method exec (line 106) | def exec(self, conversation):
method post (line 124) | def post(self, shared, prep_res, exec_res):
class RetrieveNode (line 145) | class RetrieveNode(Node):
method prep (line 146) | def prep(self, shared):
method exec (line 167) | def exec(self, inputs):
method post (line 195) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-chat-memory/utils/call_llm.py
function call_llm (line 4) | def call_llm(messages):
FILE: cookbook/pocketflow-chat-memory/utils/get_embedding.py
function get_embedding (line 5) | def get_embedding(text):
FILE: cookbook/pocketflow-chat-memory/utils/vector_index.py
function create_index (line 4) | def create_index(dimension=1536):
function add_vector (line 7) | def add_vector(index, vector):
function search_vectors (line 17) | def search_vectors(index, query_vector, k=1):
FILE: cookbook/pocketflow-chat/main.py
class ChatNode (line 4) | class ChatNode(Node):
method prep (line 5) | def prep(self, shared):
method exec (line 24) | def exec(self, messages):
method post (line 32) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-chat/utils.py
function call_llm (line 4) | def call_llm(messages):
FILE: cookbook/pocketflow-cli-hitl/flow.py
function create_joke_flow (line 4) | def create_joke_flow() -> Flow:
FILE: cookbook/pocketflow-cli-hitl/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-cli-hitl/nodes.py
class GetTopicNode (line 4) | class GetTopicNode(Node):
method exec (line 6) | def exec(self, _shared):
method post (line 9) | def post(self, shared, _prep_res, exec_res):
class GenerateJokeNode (line 12) | class GenerateJokeNode(Node):
method prep (line 14) | def prep(self, shared):
method exec (line 24) | def exec(self, prep_res):
method post (line 27) | def post(self, shared, _prep_res, exec_res):
class GetFeedbackNode (line 31) | class GetFeedbackNode(Node):
method exec (line 33) | def exec(self, _prep_res):
method post (line 40) | def post(self, shared, _prep_res, exec_res):
FILE: cookbook/pocketflow-cli-hitl/utils/call_llm.py
function call_llm (line 4) | def call_llm(prompt: str) -> str:
FILE: cookbook/pocketflow-code-generator/flow.py
function create_code_generator_flow (line 4) | def create_code_generator_flow():
FILE: cookbook/pocketflow-code-generator/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-code-generator/nodes.py
class GenerateTestCases (line 6) | class GenerateTestCases(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 10) | def exec(self, problem):
method post (line 46) | def post(self, shared, prep_res, exec_res):
class ImplementFunction (line 56) | class ImplementFunction(Node):
method prep (line 57) | def prep(self, shared):
method exec (line 60) | def exec(self, inputs):
method post (line 100) | def post(self, shared, prep_res, exec_res):
class RunTests (line 107) | class RunTests(BatchNode):
method prep (line 108) | def prep(self, shared):
method exec (line 114) | def exec(self, test_data):
method post (line 136) | def post(self, shared, prep_res, exec_res_list):
class Revise (line 165) | class Revise(Node):
method prep (line 166) | def prep(self, shared):
method exec (line 175) | def exec(self, inputs):
method post (line 242) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-code-generator/utils/call_llm.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-code-generator/utils/code_executor.py
function execute_python (line 6) | def execute_python(function_code, input):
FILE: cookbook/pocketflow-communication/flow.py
function create_flow (line 6) | def create_flow():
FILE: cookbook/pocketflow-communication/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-communication/nodes.py
class EndNode (line 5) | class EndNode(Node):
class TextInput (line 9) | class TextInput(Node):
method prep (line 12) | def prep(self, shared):
method post (line 16) | def post(self, shared, prep_res, exec_res):
class WordCounter (line 34) | class WordCounter(Node):
method prep (line 37) | def prep(self, shared):
method exec (line 41) | def exec(self, text):
method post (line 45) | def post(self, shared, prep_res, exec_res):
class ShowStats (line 50) | class ShowStats(Node):
method prep (line 53) | def prep(self, shared):
method post (line 57) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-fastapi-background/flow.py
function create_article_flow (line 4) | def create_article_flow():
FILE: cookbook/pocketflow-fastapi-background/main.py
function run_article_workflow (line 18) | def run_article_workflow(job_id: str, topic: str):
function start_job (line 42) | async def start_job(background_tasks: BackgroundTasks, topic: str = Form...
function get_progress (line 56) | async def get_progress(job_id: str):
function get_index (line 100) | async def get_index():
function get_progress_page (line 105) | async def get_progress_page():
FILE: cookbook/pocketflow-fastapi-background/nodes.py
class GenerateOutline (line 5) | class GenerateOutline(Node):
method prep (line 6) | def prep(self, shared):
method exec (line 9) | def exec(self, topic):
method post (line 27) | def post(self, shared, prep_res, exec_res):
class WriteContent (line 37) | class WriteContent(BatchNode):
method prep (line 38) | def prep(self, shared):
method exec (line 44) | def exec(self, section):
method post (line 79) | def post(self, shared, prep_res, exec_res_list):
class ApplyStyle (line 84) | class ApplyStyle(Node):
method prep (line 85) | def prep(self, shared):
method exec (line 88) | def exec(self, draft):
method post (line 102) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-fastapi-background/utils/call_llm.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-fastapi-hitl/flow.py
function create_feedback_flow (line 4) | def create_feedback_flow():
FILE: cookbook/pocketflow-fastapi-hitl/nodes.py
class ProcessNode (line 4) | class ProcessNode(Node):
method prep (line 5) | def prep(self, shared):
method exec (line 10) | def exec(self, prep_res):
method post (line 13) | def post(self, shared, prep_res, exec_res):
class ReviewNode (line 18) | class ReviewNode(AsyncNode):
method prep_async (line 19) | async def prep_async(self, shared):
method exec_async (line 38) | async def exec_async(self, prep_res):
method post_async (line 47) | async def post_async(self, shared, prep_res, exec_res):
class ResultNode (line 65) | class ResultNode(Node):
method prep (line 66) | def prep(self, shared):
method exec (line 70) | def exec(self, prep_res):
method post (line 76) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-fastapi-hitl/server.py
function run_flow_background (line 39) | async def run_flow_background(task_id: str, flow, shared: Dict[str, Any]):
class SubmitRequest (line 97) | class SubmitRequest(BaseModel):
class SubmitResponse (line 100) | class SubmitResponse(BaseModel):
class FeedbackRequest (line 104) | class FeedbackRequest(BaseModel):
class FeedbackResponse (line 107) | class FeedbackResponse(BaseModel):
function get_index (line 112) | async def get_index(request: Request):
function submit_task (line 119) | async def submit_task(
function provide_feedback (line 164) | async def provide_feedback(task_id: str, feedback_request: FeedbackReque...
function stream_status (line 203) | async def stream_status(task_id: str):
FILE: cookbook/pocketflow-fastapi-hitl/utils/process_task.py
function process_task (line 3) | def process_task(input_data):
FILE: cookbook/pocketflow-fastapi-websocket/flow.py
function create_streaming_chat_flow (line 4) | def create_streaming_chat_flow():
FILE: cookbook/pocketflow-fastapi-websocket/main.py
function get_chat_interface (line 11) | async def get_chat_interface():
function websocket_endpoint (line 15) | async def websocket_endpoint(websocket: WebSocket):
FILE: cookbook/pocketflow-fastapi-websocket/nodes.py
class StreamingChatNode (line 6) | class StreamingChatNode(AsyncNode):
method prep_async (line 7) | async def prep_async(self, shared):
method exec_async (line 16) | async def exec_async(self, prep_res):
method post_async (line 33) | async def post_async(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-fastapi-websocket/utils/stream_llm.py
function stream_llm (line 4) | async def stream_llm(messages):
function test (line 21) | async def test():
FILE: cookbook/pocketflow-flow/flow.py
class TextInput (line 3) | class TextInput(Node):
method prep (line 4) | def prep(self, shared):
method post (line 11) | def post(self, shared, prep_res, exec_res):
class TextTransform (line 27) | class TextTransform(Node):
method prep (line 28) | def prep(self, shared):
method exec (line 31) | def exec(self, inputs):
method post (line 45) | def post(self, shared, prep_res, exec_res):
class EndNode (line 53) | class EndNode(Node):
FILE: cookbook/pocketflow-flow/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-google-calendar/main.py
function create_calendar_flow (line 5) | def create_calendar_flow():
function list_calendars_flow (line 18) | def list_calendars_flow():
function main (line 23) | def main():
FILE: cookbook/pocketflow-google-calendar/nodes.py
class CreateCalendarEventNode (line 5) | class CreateCalendarEventNode(Node):
method prep (line 6) | def prep(self, shared):
method exec (line 15) | def exec(self, event_data):
method post (line 28) | def post(self, shared, prep_res, exec_res):
class ListCalendarEventsNode (line 37) | class ListCalendarEventsNode(Node):
method prep (line 38) | def prep(self, shared):
method exec (line 44) | def exec(self, params):
method post (line 52) | def post(self, shared, prep_res, exec_res):
class ListCalendarsNode (line 61) | class ListCalendarsNode(Node):
method prep (line 62) | def prep(self, shared):
method exec (line 66) | def exec(self, params):
method post (line 74) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-google-calendar/utils/google_calendar.py
function get_calendar_service (line 19) | def get_calendar_service():
function create_event (line 38) | def create_event(summary, description, start_time, end_time, timezone=TI...
function list_events (line 58) | def list_events(days=7):
function create_custom_calendar (line 76) | def create_custom_calendar(calendar_name, description=""):
function list_calendar_lists (line 89) | def list_calendar_lists():
FILE: cookbook/pocketflow-gradio-hitl/flow.py
function create_flow (line 12) | def create_flow():
FILE: cookbook/pocketflow-gradio-hitl/main.py
function chat_fn (line 18) | def chat_fn(message, history, uuid):
function clear_fn (line 83) | def clear_fn():
FILE: cookbook/pocketflow-gradio-hitl/nodes.py
class DecideAction (line 13) | class DecideAction(Node):
method prep (line 14) | def prep(self, shared):
method exec (line 19) | def exec(self, prep_res):
method post (line 111) | def post(self, shared, prep_res, exec_res):
class CheckWeather (line 148) | class CheckWeather(Node):
method prep (line 149) | def prep(self, shared):
method exec (line 156) | def exec(self, prep_res):
method post (line 160) | def post(self, shared, prep_res, exec_res):
class BookHotel (line 171) | class BookHotel(Node):
method prep (line 172) | def prep(self, shared):
method exec (line 181) | def exec(self, prep_res):
method post (line 185) | def post(self, shared, prep_res, exec_res):
class FollowUp (line 196) | class FollowUp(Node):
method prep (line 197) | def prep(self, shared):
method exec (line 206) | def exec(self, prep_res):
method post (line 212) | def post(self, shared, prep_res, exec_res):
class ResultNotification (line 219) | class ResultNotification(Node):
method prep (line 220) | def prep(self, shared):
method exec (line 229) | def exec(self, prep_res):
method post (line 235) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-gradio-hitl/utils/call_llm.py
function call_llm (line 11) | def call_llm(message: str):
FILE: cookbook/pocketflow-gradio-hitl/utils/call_mock_api.py
function call_check_weather_api (line 5) | def call_check_weather_api(city: str, date: date | None):
function call_book_hotel_api (line 21) | def call_book_hotel_api(hotel: str, checkin_date: date, checkout_date: d...
FILE: cookbook/pocketflow-gradio-hitl/utils/conversation.py
function load_conversation (line 4) | def load_conversation(conversation_id: str):
function save_conversation (line 9) | def save_conversation(conversation_id: str, session: dict):
FILE: cookbook/pocketflow-gradio-hitl/utils/format_chat_history.py
function format_chat_history (line 1) | def format_chat_history(history):
FILE: cookbook/pocketflow-hello-world/flow.py
class AnswerNode (line 6) | class AnswerNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 11) | def exec(self, question):
method post (line 14) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-hello-world/main.py
function main (line 5) | def main():
FILE: cookbook/pocketflow-hello-world/utils/call_llm.py
function call_llm (line 3) | def call_llm(prompt):
FILE: cookbook/pocketflow-llm-streaming/main.py
class StreamNode (line 6) | class StreamNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 24) | def exec(self, prep_res):
method post (line 37) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-llm-streaming/utils.py
function stream_llm (line 4) | def stream_llm(prompt):
function fake_stream_llm (line 18) | def fake_stream_llm(prompt, predefined_text="This is a fake response. To...
FILE: cookbook/pocketflow-majority-vote/main.py
class MajorityVoteNode (line 7) | class MajorityVoteNode(BatchNode):
method prep (line 8) | def prep(self, shared):
method exec (line 13) | def exec(self, single_question: str):
method exec_fallback (line 35) | def exec_fallback(self, prep_res, exc):
method post (line 38) | def post(self, shared, prep_res, exec_res_list):
FILE: cookbook/pocketflow-majority-vote/utils.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-map-reduce/flow.py
function create_resume_processing_flow (line 4) | def create_resume_processing_flow():
FILE: cookbook/pocketflow-map-reduce/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-map-reduce/nodes.py
class ReadResumesNode (line 6) | class ReadResumesNode(Node):
method exec (line 9) | def exec(self, _):
method post (line 21) | def post(self, shared, prep_res, exec_res):
class EvaluateResumesNode (line 26) | class EvaluateResumesNode(BatchNode):
method prep (line 29) | def prep(self, shared):
method exec (line 32) | def exec(self, resume_item):
method post (line 63) | def post(self, shared, prep_res, exec_res_list):
class ReduceResultsNode (line 68) | class ReduceResultsNode(Node):
method prep (line 71) | def prep(self, shared):
method exec (line 74) | def exec(self, evaluations):
method post (line 93) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-map-reduce/utils.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-mcp/main.py
class GetToolsNode (line 6) | class GetToolsNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 13) | def exec(self, server_path):
method post (line 18) | def post(self, shared, prep_res, exec_res):
class DecideToolNode (line 40) | class DecideToolNode(Node):
method prep (line 41) | def prep(self, shared):
method exec (line 76) | def exec(self, prompt):
method post (line 82) | def post(self, shared, prep_res, exec_res):
class ExecuteToolNode (line 101) | class ExecuteToolNode(Node):
method prep (line 102) | def prep(self, shared):
method exec (line 106) | def exec(self, inputs):
method post (line 113) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-mcp/simple_server.py
function add (line 8) | def add(a: int, b: int) -> int:
function subtract (line 13) | def subtract(a: int, b: int) -> int:
function multiply (line 18) | def multiply(a: int, b: int) -> int:
function divide (line 23) | def divide(a: int, b: int) -> float:
FILE: cookbook/pocketflow-mcp/utils.py
function call_llm (line 10) | def call_llm(prompt):
function get_tools (line 18) | def get_tools(server_script_path=None):
function mcp_get_tools (line 25) | def mcp_get_tools(server_script_path):
function local_get_tools (line 42) | def local_get_tools(server_script_path=None):
function call_tool (line 109) | def call_tool(server_script_path=None, tool_name=None, arguments=None):
function mcp_call_tool (line 116) | def mcp_call_tool(server_script_path=None, tool_name=None, arguments=None):
function local_call_tool (line 133) | def local_call_tool(server_script_path=None, tool_name=None, arguments=N...
FILE: cookbook/pocketflow-multi-agent/main.py
class AsyncHinter (line 5) | class AsyncHinter(AsyncNode):
method prep_async (line 6) | async def prep_async(self, shared):
method exec_async (line 13) | async def exec_async(self, inputs):
method post_async (line 26) | async def post_async(self, shared, prep_res, exec_res):
class AsyncGuesser (line 33) | class AsyncGuesser(AsyncNode):
method prep_async (line 34) | async def prep_async(self, shared):
method exec_async (line 39) | async def exec_async(self, inputs):
method post_async (line 46) | async def post_async(self, shared, prep_res, exec_res):
function main (line 62) | async def main():
FILE: cookbook/pocketflow-multi-agent/utils.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-nested-batch/flow.py
function create_base_flow (line 5) | def create_base_flow():
class ClassBatchFlow (line 17) | class ClassBatchFlow(BatchFlow):
method prep (line 20) | def prep(self, shared):
method post (line 32) | def post(self, shared, prep_res, exec_res):
class SchoolBatchFlow (line 41) | class SchoolBatchFlow(BatchFlow):
method prep (line 44) | def prep(self, shared):
method post (line 52) | def post(self, shared, prep_res, exec_res):
function create_flow (line 62) | def create_flow():
FILE: cookbook/pocketflow-nested-batch/main.py
function create_sample_data (line 4) | def create_sample_data():
function main (line 30) | def main():
FILE: cookbook/pocketflow-nested-batch/nodes.py
class LoadGrades (line 4) | class LoadGrades(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 13) | def exec(self, file_path):
method post (line 20) | def post(self, shared, prep_res, grades):
class CalculateAverage (line 25) | class CalculateAverage(Node):
method prep (line 28) | def prep(self, shared):
method exec (line 32) | def exec(self, grades):
method post (line 36) | def post(self, shared, prep_res, average):
FILE: cookbook/pocketflow-node/flow.py
class Summarize (line 4) | class Summarize(Node):
method prep (line 5) | def prep(self, shared):
method exec (line 9) | def exec(self, prep_res):
method exec_fallback (line 17) | def exec_fallback(self, shared, prep_res, exc):
method post (line 21) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-node/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-node/utils/call_llm.py
function call_llm (line 3) | def call_llm(prompt):
FILE: cookbook/pocketflow-parallel-batch-flow/flow.py
function create_base_flow (line 6) | def create_base_flow():
class ImageBatchFlow (line 20) | class ImageBatchFlow(AsyncBatchFlow):
method prep_async (line 23) | async def prep_async(self, shared):
class ImageParallelBatchFlow (line 42) | class ImageParallelBatchFlow(AsyncParallelBatchFlow):
method prep_async (line 45) | async def prep_async(self, shared):
function create_flows (line 64) | def create_flows():
FILE: cookbook/pocketflow-parallel-batch-flow/main.py
function get_image_paths (line 6) | def get_image_paths():
function main (line 27) | async def main():
FILE: cookbook/pocketflow-parallel-batch-flow/nodes.py
class LoadImage (line 8) | class LoadImage(AsyncNode):
method prep_async (line 10) | async def prep_async(self, shared):
method exec_async (line 16) | async def exec_async(self, image_path):
method post_async (line 22) | async def post_async(self, shared, prep_res, exec_res):
class ApplyFilter (line 27) | class ApplyFilter(AsyncNode):
method prep_async (line 29) | async def prep_async(self, shared):
method exec_async (line 36) | async def exec_async(self, inputs):
method post_async (line 61) | async def post_async(self, shared, prep_res, exec_res):
class SaveImage (line 66) | class SaveImage(AsyncNode):
method prep_async (line 68) | async def prep_async(self, shared):
method exec_async (line 80) | async def exec_async(self, inputs):
method post_async (line 90) | async def post_async(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-parallel-batch/main.py
class TranslateTextNodeParallel (line 9) | class TranslateTextNodeParallel(AsyncParallelBatchNode):
method prep_async (line 11) | async def prep_async(self, shared):
method exec_async (line 17) | async def exec_async(self, data_tuple):
method post_async (line 35) | async def post_async(self, shared, prep_res, exec_res_list):
function create_parallel_translation_flow (line 63) | def create_parallel_translation_flow():
function main (line 70) | async def main():
FILE: cookbook/pocketflow-parallel-batch/utils.py
function call_llm (line 6) | async def call_llm(prompt):
function run_test (line 23) | async def run_test():
FILE: cookbook/pocketflow-rag/flow.py
function get_offline_flow (line 4) | def get_offline_flow():
function get_online_flow (line 16) | def get_online_flow():
FILE: cookbook/pocketflow-rag/main.py
function run_rag_demo (line 4) | def run_rag_demo():
FILE: cookbook/pocketflow-rag/nodes.py
class ChunkDocumentsNode (line 7) | class ChunkDocumentsNode(BatchNode):
method prep (line 8) | def prep(self, shared):
method exec (line 12) | def exec(self, text):
method post (line 16) | def post(self, shared, prep_res, exec_res_list):
class EmbedDocumentsNode (line 29) | class EmbedDocumentsNode(BatchNode):
method prep (line 30) | def prep(self, shared):
method exec (line 34) | def exec(self, text):
method post (line 38) | def post(self, shared, prep_res, exec_res_list):
class CreateIndexNode (line 45) | class CreateIndexNode(Node):
method prep (line 46) | def prep(self, shared):
method exec (line 50) | def exec(self, embeddings):
method post (line 63) | def post(self, shared, prep_res, exec_res):
class EmbedQueryNode (line 70) | class EmbedQueryNode(Node):
method prep (line 71) | def prep(self, shared):
method exec (line 75) | def exec(self, query):
method post (line 81) | def post(self, shared, prep_res, exec_res):
class RetrieveDocumentNode (line 86) | class RetrieveDocumentNode(Node):
method prep (line 87) | def prep(self, shared):
method exec (line 91) | def exec(self, inputs):
method post (line 112) | def post(self, shared, prep_res, exec_res):
class GenerateAnswerNode (line 119) | class GenerateAnswerNode(Node):
method prep (line 120) | def prep(self, shared):
method exec (line 124) | def exec(self, inputs):
method post (line 138) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-rag/utils.py
function call_llm (line 5) | def call_llm(prompt):
function get_embedding (line 13) | def get_embedding(text):
function fixed_size_chunk (line 27) | def fixed_size_chunk(text, chunk_size=2000):
FILE: cookbook/pocketflow-streamlit-fsm/flow.py
function create_generation_flow (line 4) | def create_generation_flow():
FILE: cookbook/pocketflow-streamlit-fsm/nodes.py
class GenerateImageNode (line 4) | class GenerateImageNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 10) | def exec(self, prompt):
method post (line 13) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-streamlit-fsm/utils/generate_image.py
function generate_image (line 5) | def generate_image(prompt: str) -> str:
FILE: cookbook/pocketflow-structured-output/main.py
class ResumeParserNode (line 6) | class ResumeParserNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 14) | def exec(self, prep_res):
method post (line 93) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-structured-output/utils.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-supervisor/flow.py
function create_agent_inner_flow (line 4) | def create_agent_inner_flow():
function create_agent_flow (line 34) | def create_agent_flow():
FILE: cookbook/pocketflow-supervisor/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-supervisor/nodes.py
class DecideAction (line 6) | class DecideAction(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 16) | def exec(self, inputs):
method post (line 61) | def post(self, shared, prep_res, exec_res):
class SearchWeb (line 73) | class SearchWeb(Node):
method prep (line 74) | def prep(self, shared):
method exec (line 78) | def exec(self, search_query):
method post (line 85) | def post(self, shared, prep_res, exec_res):
class UnreliableAnswerNode (line 96) | class UnreliableAnswerNode(Node):
method prep (line 97) | def prep(self, shared):
method exec (line 101) | def exec(self, inputs):
method post (line 126) | def post(self, shared, prep_res, exec_res):
class SupervisorNode (line 133) | class SupervisorNode(Node):
method prep (line 134) | def prep(self, shared):
method exec (line 138) | def exec(self, answer):
method post (line 159) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-supervisor/utils.py
function call_llm (line 5) | def call_llm(prompt):
function search_web (line 13) | def search_web(query):
FILE: cookbook/pocketflow-tao/flow.py
function create_tao_flow (line 6) | def create_tao_flow():
FILE: cookbook/pocketflow-tao/main.py
function main (line 5) | def main():
FILE: cookbook/pocketflow-tao/nodes.py
class ThinkNode (line 7) | class ThinkNode(Node):
method prep (line 8) | def prep(self, shared):
method exec (line 30) | def exec(self, prep_res):
method post (line 67) | def post(self, shared, prep_res, exec_res):
class ActionNode (line 88) | class ActionNode(Node):
method prep (line 89) | def prep(self, shared):
method exec (line 95) | def exec(self, inputs):
method post (line 117) | def post(self, shared, prep_res, exec_res):
method search_web (line 127) | def search_web(self, query):
method calculate (line 131) | def calculate(self, expression):
class ObserveNode (line 138) | class ObserveNode(Node):
method prep (line 139) | def prep(self, shared):
method exec (line 146) | def exec(self, inputs):
method post (line 167) | def post(self, shared, prep_res, exec_res):
class EndNode (line 179) | class EndNode(Node):
method prep (line 180) | def prep(self, shared):
method exec (line 184) | def exec(self, prep_res):
method post (line 188) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-tao/utils.py
function call_llm (line 6) | def call_llm(prompt):
FILE: cookbook/pocketflow-text2sql/flow.py
function create_text_to_sql_flow (line 4) | def create_text_to_sql_flow():
FILE: cookbook/pocketflow-text2sql/main.py
function run_text_to_sql (line 6) | def run_text_to_sql(natural_query, db_path=DB_FILE, max_debug_retries=3):
FILE: cookbook/pocketflow-text2sql/nodes.py
class GetSchema (line 7) | class GetSchema(Node):
method prep (line 8) | def prep(self, shared):
method exec (line 11) | def exec(self, db_path):
method post (line 28) | def post(self, shared, prep_res, exec_res):
class GenerateSQL (line 35) | class GenerateSQL(Node):
method prep (line 36) | def prep(self, shared):
method exec (line 39) | def exec(self, prep_res):
method post (line 58) | def post(self, shared, prep_res, exec_res):
class ExecuteSQL (line 68) | class ExecuteSQL(Node):
method prep (line 69) | def prep(self, shared):
method exec (line 72) | def exec(self, prep_res):
method post (line 101) | def post(self, shared, prep_res, exec_res):
class DebugSQL (line 135) | class DebugSQL(Node):
method prep (line 136) | def prep(self, shared):
method exec (line 144) | def exec(self, prep_res):
method post (line 170) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-text2sql/populate_db.py
function populate_database (line 8) | def populate_database(db_file=DB_FILE):
FILE: cookbook/pocketflow-text2sql/utils/call_llm.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-thinking/flow.py
function create_chain_of_thought_flow (line 4) | def create_chain_of_thought_flow():
FILE: cookbook/pocketflow-thinking/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-thinking/nodes.py
function format_plan (line 8) | def format_plan(plan_items, indent_level=0):
function format_plan_for_prompt (line 44) | def format_plan_for_prompt(plan_items, indent_level=0):
class ChainOfThoughtNode (line 66) | class ChainOfThoughtNode(Node):
method prep (line 67) | def prep(self, shared):
method exec (line 116) | def exec(self, prep_res):
method post (line 216) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-thinking/utils.py
function call_llm (line 4) | def call_llm(prompt):
FILE: cookbook/pocketflow-tool-crawler/flow.py
function create_flow (line 4) | def create_flow() -> Flow:
FILE: cookbook/pocketflow-tool-crawler/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-tool-crawler/nodes.py
class CrawlWebsiteNode (line 6) | class CrawlWebsiteNode(Node):
method prep (line 9) | def prep(self, shared):
method exec (line 12) | def exec(self, inputs):
method post (line 20) | def post(self, shared, prep_res, exec_res):
class AnalyzeContentBatchNode (line 24) | class AnalyzeContentBatchNode(BatchNode):
method prep (line 27) | def prep(self, shared):
method exec (line 33) | def exec(self, batch):
method post (line 36) | def post(self, shared, prep_res, exec_res_list):
class GenerateReportNode (line 45) | class GenerateReportNode(Node):
method prep (line 48) | def prep(self, shared):
method exec (line 51) | def exec(self, results):
method post (line 71) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-tool-crawler/tools/crawler.py
class WebCrawler (line 6) | class WebCrawler:
method __init__ (line 9) | def __init__(self, base_url: str, max_pages: int = 10):
method is_valid_url (line 14) | def is_valid_url(self, url: str) -> bool:
method extract_page_content (line 20) | def extract_page_content(self, url: str) -> Dict:
method crawl (line 50) | def crawl(self) -> List[Dict]:
FILE: cookbook/pocketflow-tool-crawler/tools/parser.py
function analyze_content (line 4) | def analyze_content(content: Dict) -> Dict:
function analyze_site (line 60) | def analyze_site(crawl_results: List[Dict]) -> List[Dict]:
FILE: cookbook/pocketflow-tool-crawler/utils/call_llm.py
function call_llm (line 7) | def call_llm(prompt: str) -> str:
FILE: cookbook/pocketflow-tool-database/flow.py
function create_database_flow (line 4) | def create_database_flow():
FILE: cookbook/pocketflow-tool-database/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-tool-database/nodes.py
class InitDatabaseNode (line 4) | class InitDatabaseNode(Node):
method exec (line 7) | def exec(self, _):
method post (line 11) | def post(self, shared, prep_res, exec_res):
class CreateTaskNode (line 15) | class CreateTaskNode(Node):
method prep (line 18) | def prep(self, shared):
method exec (line 24) | def exec(self, inputs):
method post (line 30) | def post(self, shared, prep_res, exec_res):
class ListTasksNode (line 34) | class ListTasksNode(Node):
method exec (line 37) | def exec(self, _):
method post (line 41) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-tool-database/tools/database.py
function execute_sql (line 4) | def execute_sql(query: str, params: Tuple = None) -> List[Tuple[Any, ...]]:
function init_db (line 27) | def init_db():
FILE: cookbook/pocketflow-tool-embeddings/flow.py
function create_embedding_flow (line 4) | def create_embedding_flow():
FILE: cookbook/pocketflow-tool-embeddings/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-tool-embeddings/nodes.py
class EmbeddingNode (line 4) | class EmbeddingNode(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 11) | def exec(self, text):
method post (line 15) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-tool-embeddings/tools/embeddings.py
function get_embedding (line 3) | def get_embedding(text):
FILE: cookbook/pocketflow-tool-embeddings/utils/call_llm.py
function call_llm (line 7) | def call_llm(prompt):
FILE: cookbook/pocketflow-tool-pdf-vision/flow.py
function create_vision_flow (line 4) | def create_vision_flow():
FILE: cookbook/pocketflow-tool-pdf-vision/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-tool-pdf-vision/nodes.py
class ProcessPDFBatchNode (line 8) | class ProcessPDFBatchNode(BatchNode):
method prep (line 11) | def prep(self, shared):
method exec (line 33) | def exec(self, item):
method post (line 50) | def post(self, shared, prep_res, exec_res_list):
class LoadPDFNode (line 54) | class LoadPDFNode(Node):
method prep (line 57) | def prep(self, shared):
method exec (line 60) | def exec(self, pdf_path):
method post (line 63) | def post(self, shared, prep_res, exec_res):
class ExtractTextNode (line 67) | class ExtractTextNode(Node):
method prep (line 70) | def prep(self, shared):
method exec (line 76) | def exec(self, inputs):
method post (line 89) | def post(self, shared, prep_res, exec_res):
class CombineResultsNode (line 93) | class CombineResultsNode(Node):
method prep (line 96) | def prep(self, shared):
method exec (line 99) | def exec(self, results):
method post (line 110) | def post(self, shared, prep_res, exec_res):
function create_single_pdf_flow (line 114) | def create_single_pdf_flow():
FILE: cookbook/pocketflow-tool-pdf-vision/tools/pdf.py
function pdf_to_images (line 7) | def pdf_to_images(pdf_path: str, max_size: int = 2000) -> List[Tuple[Ima...
function image_to_base64 (line 41) | def image_to_base64(image: Image.Image) -> str:
FILE: cookbook/pocketflow-tool-pdf-vision/tools/vision.py
function extract_text_from_image (line 5) | def extract_text_from_image(image: Image.Image, prompt: str = None) -> str:
FILE: cookbook/pocketflow-tool-search/flow.py
function create_flow (line 4) | def create_flow() -> Flow:
FILE: cookbook/pocketflow-tool-search/main.py
function main (line 4) | def main():
FILE: cookbook/pocketflow-tool-search/nodes.py
class SearchNode (line 6) | class SearchNode(Node):
method prep (line 9) | def prep(self, shared):
method exec (line 12) | def exec(self, inputs):
method post (line 20) | def post(self, shared, prep_res, exec_res):
class AnalyzeResultsNode (line 24) | class AnalyzeResultsNode(Node):
method prep (line 27) | def prep(self, shared):
method exec (line 30) | def exec(self, inputs):
method post (line 41) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-tool-search/tools/parser.py
function analyze_results (line 4) | def analyze_results(query: str, results: List[Dict]) -> Dict:
FILE: cookbook/pocketflow-tool-search/tools/search.py
class SearchTool (line 5) | class SearchTool:
method __init__ (line 8) | def __init__(self, api_key: Optional[str] = None):
method search (line 18) | def search(self, query: str, num_results: int = 5) -> List[Dict]:
FILE: cookbook/pocketflow-tool-search/utils/call_llm.py
function call_llm (line 11) | def call_llm(prompt: str) -> str:
FILE: cookbook/pocketflow-tracing/examples/async_example.py
class AsyncDataFetchNode (line 25) | class AsyncDataFetchNode(AsyncNode):
method prep_async (line 28) | async def prep_async(self, shared):
method exec_async (line 33) | async def exec_async(self, query):
method post_async (line 48) | async def post_async(self, shared, prep_res, exec_res):
class AsyncDataProcessNode (line 54) | class AsyncDataProcessNode(AsyncNode):
method prep_async (line 57) | async def prep_async(self, shared):
method exec_async (line 61) | async def exec_async(self, data):
method post_async (line 79) | async def post_async(self, shared, prep_res, exec_res):
class AsyncDataProcessingFlow (line 86) | class AsyncDataProcessingFlow(AsyncFlow):
method __init__ (line 89) | def __init__(self):
function main (line 101) | async def main():
FILE: cookbook/pocketflow-tracing/examples/basic_example.py
class GreetingNode (line 24) | class GreetingNode(Node):
method prep (line 27) | def prep(self, shared):
method exec (line 32) | def exec(self, name):
method post (line 37) | def post(self, shared, prep_res, exec_res):
class UppercaseNode (line 43) | class UppercaseNode(Node):
method prep (line 46) | def prep(self, shared):
method exec (line 50) | def exec(self, greeting):
method post (line 54) | def post(self, shared, prep_res, exec_res):
class BasicGreetingFlow (line 61) | class BasicGreetingFlow(Flow):
method __init__ (line 64) | def __init__(self):
function main (line 76) | def main():
FILE: cookbook/pocketflow-tracing/setup.py
function install_dependencies (line 13) | def install_dependencies():
function verify_setup (line 27) | def verify_setup():
function main (line 52) | def main():
FILE: cookbook/pocketflow-tracing/test_tracing.py
class TestNode (line 26) | class TestNode(Node):
method prep (line 29) | def prep(self, shared):
method exec (line 33) | def exec(self, prep_res):
method post (line 37) | def post(self, shared, prep_res, exec_res):
class TestAsyncNode (line 43) | class TestAsyncNode(AsyncNode):
method prep_async (line 46) | async def prep_async(self, shared):
method exec_async (line 51) | async def exec_async(self, prep_res):
method post_async (line 56) | async def post_async(self, shared, prep_res, exec_res):
class TestSyncFlow (line 63) | class TestSyncFlow(Flow):
method __init__ (line 66) | def __init__(self):
class TestAsyncFlow (line 71) | class TestAsyncFlow(AsyncFlow):
method __init__ (line 74) | def __init__(self):
function test_sync_flow (line 78) | def test_sync_flow():
function test_async_flow (line 96) | async def test_async_flow():
function test_configuration (line 114) | def test_configuration():
function test_error_handling (line 134) | def test_error_handling():
function main (line 159) | async def main():
FILE: cookbook/pocketflow-tracing/tracing/config.py
class TracingConfig (line 12) | class TracingConfig:
method from_env (line 34) | def from_env(cls, env_file: Optional[str] = None) -> "TracingConfig":
method validate (line 66) | def validate(self) -> bool:
method to_langfuse_kwargs (line 90) | def to_langfuse_kwargs(self) -> dict:
FILE: cookbook/pocketflow-tracing/tracing/core.py
class LangfuseTracer (line 22) | class LangfuseTracer:
method __init__ (line 27) | def __init__(self, config: TracingConfig):
method start_trace (line 65) | def start_trace(self, flow_name: str, input_data: Dict[str, Any]) -> O...
method end_trace (line 109) | def end_trace(self, output_data: Dict[str, Any], status: str = "succes...
method start_node_span (line 143) | def start_node_span(
method end_node_span (line 186) | def end_node_span(
method _serialize_data (line 253) | def _serialize_data(self, data: Any) -> Any:
method flush (line 278) | def flush(self) -> None:
FILE: cookbook/pocketflow-tracing/tracing/decorator.py
function trace_flow (line 14) | def trace_flow(
function _trace_flow_class (line 65) | def _trace_flow_class(flow_class, config, flow_name, session_id, user_id):
function _trace_flow_function (line 256) | def _trace_flow_function(flow_func, config, flow_name, session_id, user_...
FILE: cookbook/pocketflow-tracing/utils/setup.py
function setup_tracing (line 21) | def setup_tracing(env_file: Optional[str] = None) -> TracingConfig:
function test_langfuse_connection (line 71) | def test_langfuse_connection(config: TracingConfig) -> bool:
function print_configuration_help (line 103) | def print_configuration_help():
FILE: cookbook/pocketflow-visualization/async_flow.py
class ValidatePayment (line 6) | class ValidatePayment(AsyncNode):
method exec_async (line 7) | async def exec_async(self, prep_res):
method post_async (line 11) | async def post_async(self, shared, prep_res, exec_res):
class ProcessPayment (line 16) | class ProcessPayment(AsyncNode):
method exec_async (line 17) | async def exec_async(self, prep_res):
method post_async (line 21) | async def post_async(self, shared, prep_res, exec_res):
class PaymentConfirmation (line 26) | class PaymentConfirmation(AsyncNode):
method exec_async (line 27) | async def exec_async(self, prep_res):
method post_async (line 31) | async def post_async(self, shared, prep_res, exec_res):
class CheckStock (line 37) | class CheckStock(AsyncNode):
method exec_async (line 38) | async def exec_async(self, prep_res):
method post_async (line 42) | async def post_async(self, shared, prep_res, exec_res):
class ReserveItems (line 47) | class ReserveItems(AsyncNode):
method exec_async (line 48) | async def exec_async(self, prep_res):
method post_async (line 52) | async def post_async(self, shared, prep_res, exec_res):
class UpdateInventory (line 57) | class UpdateInventory(AsyncNode):
method exec_async (line 58) | async def exec_async(self, prep_res):
method post_async (line 62) | async def post_async(self, shared, prep_res, exec_res):
class CreateLabel (line 68) | class CreateLabel(AsyncNode):
method exec_async (line 69) | async def exec_async(self, prep_res):
method post_async (line 73) | async def post_async(self, shared, prep_res, exec_res):
class AssignCarrier (line 78) | class AssignCarrier(AsyncNode):
method exec_async (line 79) | async def exec_async(self, prep_res):
method post_async (line 83) | async def post_async(self, shared, prep_res, exec_res):
class SchedulePickup (line 88) | class SchedulePickup(AsyncNode):
method exec_async (line 89) | async def exec_async(self, prep_res):
method post_async (line 93) | async def post_async(self, shared, prep_res, exec_res):
class OrderFlow (line 130) | class OrderFlow(AsyncFlow):
function main (line 154) | async def main():
FILE: cookbook/pocketflow-visualization/async_loop_flow.py
class OrderFlow (line 39) | class OrderFlow(AsyncFlow):
function main (line 62) | async def main():
FILE: cookbook/pocketflow-visualization/visualize.py
function build_mermaid (line 21) | def build_mermaid(start):
function flow_to_json (line 61) | def flow_to_json(start):
function create_d3_visualization (line 210) | def create_d3_visualization(
function find_free_port (line 832) | def find_free_port():
function start_http_server (line 840) | def start_http_server(directory, port=None):
function serve_and_open_visualization (line 874) | def serve_and_open_visualization(html_path, auto_open=True):
function visualize_flow (line 904) | def visualize_flow(
function load_flow_from_module (line 953) | def load_flow_from_module(module_path: str, flow_variable: str) -> Flow:
FILE: cookbook/pocketflow-voice-chat/flow.py
function create_voice_chat_flow (line 4) | def create_voice_chat_flow() -> Flow:
FILE: cookbook/pocketflow-voice-chat/main.py
function main (line 3) | def main():
FILE: cookbook/pocketflow-voice-chat/nodes.py
class CaptureAudioNode (line 12) | class CaptureAudioNode(Node):
method exec (line 14) | def exec(self, _): # prep_res is not used as per design
method post (line 21) | def post(self, shared, prep_res, exec_res):
class SpeechToTextNode (line 33) | class SpeechToTextNode(Node):
method prep (line 35) | def prep(self, shared):
method exec (line 43) | def exec(self, prep_res):
method post (line 58) | def post(self, shared, prep_res, exec_res):
class QueryLLMNode (line 74) | class QueryLLMNode(Node):
method prep (line 76) | def prep(self, shared):
method exec (line 85) | def exec(self, prep_res):
method post (line 94) | def post(self, shared, prep_res, exec_res):
class TextToSpeechNode (line 105) | class TextToSpeechNode(Node):
method prep (line 107) | def prep(self, shared):
method exec (line 120) | def exec(self, prep_res):
method post (line 129) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-voice-chat/utils/audio_utils.py
function record_audio (line 12) | def record_audio(sample_rate = DEFAULT_SAMPLE_RATE,
function play_audio_data (line 84) | def play_audio_data(audio_data, sample_rate):
FILE: cookbook/pocketflow-voice-chat/utils/call_llm.py
function call_llm (line 4) | def call_llm(messages):
FILE: cookbook/pocketflow-voice-chat/utils/speech_to_text.py
function speech_to_text_api (line 5) | def speech_to_text_api(audio_data: bytes, sample_rate: int):
FILE: cookbook/pocketflow-voice-chat/utils/text_to_speech.py
function text_to_speech_api (line 4) | def text_to_speech_api(text_to_synthesize: str):
FILE: cookbook/pocketflow-workflow/flow.py
function create_article_flow (line 4) | def create_article_flow():
FILE: cookbook/pocketflow-workflow/main.py
function run_flow (line 3) | def run_flow(topic="AI Safety"):
FILE: cookbook/pocketflow-workflow/nodes.py
class GenerateOutline (line 6) | class GenerateOutline(Node):
method prep (line 7) | def prep(self, shared):
method exec (line 10) | def exec(self, topic):
method post (line 31) | def post(self, shared, prep_res, exec_res):
class WriteSimpleContent (line 52) | class WriteSimpleContent(BatchNode):
method prep (line 53) | def prep(self, shared):
method exec (line 58) | def exec(self, section):
method post (line 79) | def post(self, shared, prep_res, exec_res_list):
class ApplyStyle (line 103) | class ApplyStyle(Node):
method prep (line 104) | def prep(self, shared):
method exec (line 110) | def exec(self, draft):
method post (line 127) | def post(self, shared, prep_res, exec_res):
FILE: cookbook/pocketflow-workflow/utils/call_llm.py
function call_llm (line 4) | def call_llm(prompt):
FILE: pocketflow/__init__.py
class BaseNode (line 3) | class BaseNode:
method __init__ (line 4) | def __init__(self): self.params,self.successors={},{}
method set_params (line 5) | def set_params(self,params): self.params=params
method next (line 6) | def next(self,node,action="default"):
method prep (line 9) | def prep(self,shared): pass
method exec (line 10) | def exec(self,prep_res): pass
method post (line 11) | def post(self,shared,prep_res,exec_res): pass
method _exec (line 12) | def _exec(self,prep_res): return self.exec(prep_res)
method _run (line 13) | def _run(self,shared): p=self.prep(shared); e=self._exec(p); return se...
method run (line 14) | def run(self,shared):
method __rshift__ (line 17) | def __rshift__(self,other): return self.next(other)
method __sub__ (line 18) | def __sub__(self,action):
class _ConditionalTransition (line 22) | class _ConditionalTransition:
method __init__ (line 23) | def __init__(self,src,action): self.src,self.action=src,action
method __rshift__ (line 24) | def __rshift__(self,tgt): return self.src.next(tgt,self.action)
class Node (line 26) | class Node(BaseNode):
method __init__ (line 27) | def __init__(self,max_retries=1,wait=0): super().__init__(); self.max_...
method exec_fallback (line 28) | def exec_fallback(self,prep_res,exc): raise exc
method _exec (line 29) | def _exec(self,prep_res):
class BatchNode (line 36) | class BatchNode(Node):
method _exec (line 37) | def _exec(self,items): return [super(BatchNode,self)._exec(i) for i in...
class Flow (line 39) | class Flow(BaseNode):
method __init__ (line 40) | def __init__(self,start=None): super().__init__(); self.start_node=start
method start (line 41) | def start(self,start): self.start_node=start; return start
method get_next_node (line 42) | def get_next_node(self,curr,action):
method _orch (line 46) | def _orch(self,shared,params=None):
method _run (line 50) | def _run(self,shared): p=self.prep(shared); o=self._orch(shared); retu...
method post (line 51) | def post(self,shared,prep_res,exec_res): return exec_res
class BatchFlow (line 53) | class BatchFlow(Flow):
method _run (line 54) | def _run(self,shared):
class AsyncNode (line 59) | class AsyncNode(Node):
method prep_async (line 60) | async def prep_async(self,shared): pass
method exec_async (line 61) | async def exec_async(self,prep_res): pass
method exec_fallback_async (line 62) | async def exec_fallback_async(self,prep_res,exc): raise exc
method post_async (line 63) | async def post_async(self,shared,prep_res,exec_res): pass
method _exec (line 64) | async def _exec(self,prep_res):
method run_async (line 70) | async def run_async(self,shared):
method _run_async (line 73) | async def _run_async(self,shared): p=await self.prep_async(shared); e=...
method _run (line 74) | def _run(self,shared): raise RuntimeError("Use run_async.")
class AsyncBatchNode (line 76) | class AsyncBatchNode(AsyncNode,BatchNode):
method _exec (line 77) | async def _exec(self,items): return [await super(AsyncBatchNode,self)....
class AsyncParallelBatchNode (line 79) | class AsyncParallelBatchNode(AsyncNode,BatchNode):
method _exec (line 80) | async def _exec(self,items): return await asyncio.gather(*(super(Async...
class AsyncFlow (line 82) | class AsyncFlow(Flow,AsyncNode):
method _orch_async (line 83) | async def _orch_async(self,shared,params=None):
method _run_async (line 87) | async def _run_async(self,shared): p=await self.prep_async(shared); o=...
method post_async (line 88) | async def post_async(self,shared,prep_res,exec_res): return exec_res
class AsyncBatchFlow (line 90) | class AsyncBatchFlow(AsyncFlow,BatchFlow):
method _run_async (line 91) | async def _run_async(self,shared):
class AsyncParallelBatchFlow (line 96) | class AsyncParallelBatchFlow(AsyncFlow,BatchFlow):
method _run_async (line 97) | async def _run_async(self,shared):
FILE: pocketflow/__init__.pyi
class BaseNode (line 14) | class BaseNode(Generic[_PrepResult, _ExecResult, _PostResult]):
method __init__ (line 18) | def __init__(self) -> None: ...
method set_params (line 19) | def set_params(self, params: Params) -> None: ...
method next (line 20) | def next(self, node: BaseNode[Any, Any, Any], action: str = "default")...
method prep (line 21) | def prep(self, shared: SharedData) -> _PrepResult: ...
method exec (line 22) | def exec(self, prep_res: _PrepResult) -> _ExecResult: ...
method post (line 23) | def post(self, shared: SharedData, prep_res: _PrepResult, exec_res: _E...
method _exec (line 24) | def _exec(self, prep_res: _PrepResult) -> _ExecResult: ...
method _run (line 25) | def _run(self, shared: SharedData) -> _PostResult: ...
method run (line 26) | def run(self, shared: SharedData) -> _PostResult: ...
method __rshift__ (line 27) | def __rshift__(self, other: BaseNode[Any, Any, Any]) -> BaseNode[Any, ...
method __sub__ (line 28) | def __sub__(self, action: str) -> _ConditionalTransition: ...
class _ConditionalTransition (line 30) | class _ConditionalTransition:
method __init__ (line 34) | def __init__(self, src: BaseNode[Any, Any, Any], action: str) -> None:...
method __rshift__ (line 35) | def __rshift__(self, tgt: BaseNode[Any, Any, Any]) -> BaseNode[Any, An...
class Node (line 37) | class Node(BaseNode[_PrepResult, _ExecResult, _PostResult]):
method __init__ (line 42) | def __init__(self, max_retries: int = 1, wait: Union[int, float] = 0) ...
method exec_fallback (line 43) | def exec_fallback(self, prep_res: _PrepResult, exc: Exception) -> _Exe...
method _exec (line 44) | def _exec(self, prep_res: _PrepResult) -> _ExecResult: ...
class BatchNode (line 46) | class BatchNode(Node[Optional[List[_PrepResult]], List[_ExecResult], _Po...
method _exec (line 47) | def _exec(self, items: Optional[List[_PrepResult]]) -> List[_ExecResul...
class Flow (line 49) | class Flow(BaseNode[_PrepResult, Any, _PostResult]):
method __init__ (line 52) | def __init__(self, start: Optional[BaseNode[Any, Any, Any]] = None) ->...
method start (line 53) | def start(self, start: BaseNode[Any, Any, Any]) -> BaseNode[Any, Any, ...
method get_next_node (line 54) | def get_next_node(
method _orch (line 57) | def _orch(
method _run (line 60) | def _run(self, shared: SharedData) -> _PostResult: ...
method post (line 61) | def post(self, shared: SharedData, prep_res: _PrepResult, exec_res: An...
class BatchFlow (line 63) | class BatchFlow(Flow[Optional[List[Params]], Any, _PostResult]):
method _run (line 64) | def _run(self, shared: SharedData) -> _PostResult: ...
class AsyncNode (line 66) | class AsyncNode(Node[_PrepResult, _ExecResult, _PostResult]):
method prep_async (line 67) | async def prep_async(self, shared: SharedData) -> _PrepResult: ...
method exec_async (line 68) | async def exec_async(self, prep_res: _PrepResult) -> _ExecResult: ...
method exec_fallback_async (line 69) | async def exec_fallback_async(self, prep_res: _PrepResult, exc: Except...
method post_async (line 70) | async def post_async(
method _exec (line 73) | async def _exec(self, prep_res: _PrepResult) -> _ExecResult: ...
method run_async (line 74) | async def run_async(self, shared: SharedData) -> _PostResult: ...
method _run_async (line 75) | async def _run_async(self, shared: SharedData) -> _PostResult: ...
method _run (line 76) | def _run(self, shared: SharedData) -> _PostResult: ...
class AsyncBatchNode (line 78) | class AsyncBatchNode(AsyncNode[Optional[List[_PrepResult]], List[_ExecRe...
method _exec (line 79) | async def _exec(self, items: Optional[List[_PrepResult]]) -> List[_Exe...
class AsyncParallelBatchNode (line 81) | class AsyncParallelBatchNode(AsyncNode[Optional[List[_PrepResult]], List...
method _exec (line 82) | async def _exec(self, items: Optional[List[_PrepResult]]) -> List[_Exe...
class AsyncFlow (line 84) | class AsyncFlow(Flow[_PrepResult, Any, _PostResult], AsyncNode[_PrepResu...
method _orch_async (line 85) | async def _orch_async(
method _run_async (line 88) | async def _run_async(self, shared: SharedData) -> _PostResult: ...
method post_async (line 89) | async def post_async(
class AsyncBatchFlow (line 93) | class AsyncBatchFlow(AsyncFlow[Optional[List[Params]], Any, _PostResult]...
method _run_async (line 94) | async def _run_async(self, shared: SharedData) -> _PostResult: ...
class AsyncParallelBatchFlow (line 96) | class AsyncParallelBatchFlow(AsyncFlow[Optional[List[Params]], Any, _Pos...
method _run_async (line 97) | async def _run_async(self, shared: SharedData) -> _PostResult: ...
FILE: tests/test_async_batch_flow.py
class AsyncDataProcessNode (line 9) | class AsyncDataProcessNode(AsyncNode):
method prep_async (line 10) | async def prep_async(self, shared_storage):
method post_async (line 18) | async def post_async(self, shared_storage, prep_result, proc_result):
class AsyncErrorNode (line 24) | class AsyncErrorNode(AsyncNode):
method post_async (line 25) | async def post_async(self, shared_storage, prep_result, proc_result):
class TestAsyncBatchFlow (line 31) | class TestAsyncBatchFlow(unittest.TestCase):
method setUp (line 32) | def setUp(self):
method test_basic_async_batch_processing (line 35) | def test_basic_async_batch_processing(self):
method test_empty_async_batch (line 59) | def test_empty_async_batch(self):
method test_async_error_handling (line 74) | def test_async_error_handling(self):
method test_nested_async_flow (line 93) | def test_nested_async_flow(self):
method test_custom_async_parameters (line 138) | def test_custom_async_parameters(self):
FILE: tests/test_async_batch_node.py
class AsyncArrayChunkNode (line 9) | class AsyncArrayChunkNode(AsyncBatchNode):
method __init__ (line 10) | def __init__(self, chunk_size=10):
method prep_async (line 14) | async def prep_async(self, shared_storage):
method exec_async (line 23) | async def exec_async(self, chunk):
method post_async (line 28) | async def post_async(self, shared_storage, prep_result, proc_result):
class AsyncSumReduceNode (line 33) | class AsyncSumReduceNode(AsyncNode):
method prep_async (line 34) | async def prep_async(self, shared_storage):
class TestAsyncBatchNode (line 42) | class TestAsyncBatchNode(unittest.TestCase):
method test_array_chunking (line 43) | def test_array_chunking(self):
FILE: tests/test_async_flow.py
class AsyncNumberNode (line 9) | class AsyncNumberNode(AsyncNode):
method __init__ (line 15) | def __init__(self, number):
method prep_async (line 19) | async def prep_async(self, shared_storage):
method post_async (line 25) | async def post_async(self, shared_storage, prep_result, proc_result):
class AsyncIncrementNode (line 31) | class AsyncIncrementNode(AsyncNode):
method prep_async (line 35) | async def prep_async(self, shared_storage):
method post_async (line 39) | async def post_async(self, shared_storage, prep_result, proc_result):
class AsyncSignalNode (line 43) | class AsyncSignalNode(AsyncNode):
method __init__ (line 45) | def __init__(self, signal="default_async_signal"):
method prep_async (line 50) | async def prep_async(self, shared_storage):
method post_async (line 53) | async def post_async(self, shared_storage, prep_result, exec_result):
class AsyncPathNode (line 60) | class AsyncPathNode(AsyncNode):
method __init__ (line 62) | def __init__(self, path_id):
method prep_async (line 66) | async def prep_async(self, shared_storage):
method post_async (line 71) | async def post_async(self, shared_storage, prep_result, exec_result):
class TestAsyncNode (line 75) | class TestAsyncNode(unittest.TestCase):
method test_async_number_node_direct_call (line 79) | def test_async_number_node_direct_call(self):
method test_async_increment_node_direct_call (line 94) | def test_async_increment_node_direct_call(self):
class TestAsyncFlow (line 106) | class TestAsyncFlow(unittest.TestCase):
method test_simple_async_flow (line 110) | def test_simple_async_flow(self):
method test_async_flow_branching (line 133) | def test_async_flow_branching(self):
method test_async_composition_with_action_propagation (line 181) | def test_async_composition_with_action_propagation(self):
FILE: tests/test_async_parallel_batch_flow.py
class AsyncParallelNumberProcessor (line 9) | class AsyncParallelNumberProcessor(AsyncParallelBatchNode):
method __init__ (line 10) | def __init__(self, delay=0.1):
method prep_async (line 14) | async def prep_async(self, shared_storage):
method exec_async (line 18) | async def exec_async(self, number):
method post_async (line 22) | async def post_async(self, shared_storage, prep_result, exec_result):
class AsyncAggregatorNode (line 28) | class AsyncAggregatorNode(AsyncNode):
method prep_async (line 29) | async def prep_async(self, shared_storage):
method exec_async (line 37) | async def exec_async(self, prep_result):
method post_async (line 41) | async def post_async(self, shared_storage, prep_result, exec_result):
class TestAsyncParallelBatchFlow (line 45) | class TestAsyncParallelBatchFlow(unittest.TestCase):
method setUp (line 46) | def setUp(self):
method tearDown (line 50) | def tearDown(self):
method test_parallel_batch_flow (line 53) | def test_parallel_batch_flow(self):
method test_error_handling (line 94) | def test_error_handling(self):
method test_multiple_batch_sizes (line 121) | def test_multiple_batch_sizes(self):
class AsyncItemNode (line 159) | class AsyncItemNode(AsyncNode):
method prep_async (line 160) | async def prep_async(self, shared_storage):
method exec_async (line 162) | async def exec_async(self, prep_res):
method post_async (line 164) | async def post_async(self, shared_storage, prep_res, exec_res):
class InnerAsyncParallelBatchFlow (line 172) | class InnerAsyncParallelBatchFlow(AsyncParallelBatchFlow):
method prep_async (line 173) | async def prep_async(self, shared_storage):
class OuterAsyncParallelBatchFlow (line 177) | class OuterAsyncParallelBatchFlow(AsyncParallelBatchFlow):
method prep_async (line 178) | async def prep_async(self, shared_storage):
class TestNestedAsyncParallelBatchFlow (line 181) | class TestNestedAsyncParallelBatchFlow(unittest.TestCase):
method setUp (line 182) | def setUp(self):
method tearDown (line 186) | def tearDown(self):
method test_nested_parallel_batch_flow (line 189) | def test_nested_parallel_batch_flow(self):
FILE: tests/test_async_parallel_batch_node.py
class AsyncParallelNumberProcessor (line 9) | class AsyncParallelNumberProcessor(AsyncParallelBatchNode):
method __init__ (line 10) | def __init__(self, delay=0.1):
method prep_async (line 14) | async def prep_async(self, shared_storage):
method exec_async (line 18) | async def exec_async(self, number):
method post_async (line 22) | async def post_async(self, shared_storage, prep_result, exec_result):
class TestAsyncParallelBatchNode (line 26) | class TestAsyncParallelBatchNode(unittest.TestCase):
method setUp (line 27) | def setUp(self):
method tearDown (line 32) | def tearDown(self):
method test_parallel_processing (line 35) | def test_parallel_processing(self):
method test_empty_input (line 59) | def test_empty_input(self):
method test_single_item (line 72) | def test_single_item(self):
method test_large_batch (line 85) | def test_large_batch(self):
method test_error_handling (line 100) | def test_error_handling(self):
method test_concurrent_execution (line 118) | def test_concurrent_execution(self):
FILE: tests/test_batch_flow.py
class DataProcessNode (line 8) | class DataProcessNode(Node):
method prep (line 9) | def prep(self, shared_storage):
class ErrorProcessNode (line 16) | class ErrorProcessNode(Node):
method prep (line 17) | def prep(self, shared_storage):
class TestBatchFlow (line 25) | class TestBatchFlow(unittest.TestCase):
method setUp (line 26) | def setUp(self):
method test_basic_batch_processing (line 29) | def test_basic_batch_processing(self):
method test_empty_input (line 53) | def test_empty_input(self):
method test_single_item (line 68) | def test_single_item(self):
method test_error_handling (line 88) | def test_error_handling(self):
method test_nested_flow (line 107) | def test_nested_flow(self):
method test_custom_parameters (line 148) | def test_custom_parameters(self):
method test_nested_batch_flow (line 183) | def test_nested_batch_flow(self):
FILE: tests/test_batch_node.py
class ArrayChunkNode (line 8) | class ArrayChunkNode(BatchNode):
method __init__ (line 9) | def __init__(self, chunk_size=10):
method prep (line 13) | def prep(self, shared_storage):
method exec (line 22) | def exec(self, chunk):
method post (line 27) | def post(self, shared_storage, prep_result, proc_result):
class SumReduceNode (line 32) | class SumReduceNode(Node):
method prep (line 33) | def prep(self, shared_storage):
class TestBatchNode (line 39) | class TestBatchNode(unittest.TestCase):
method test_array_chunking (line 40) | def test_array_chunking(self):
method test_map_reduce_sum (line 53) | def test_map_reduce_sum(self):
method test_uneven_chunks (line 80) | def test_uneven_chunks(self):
method test_custom_chunk_size (line 101) | def test_custom_chunk_size(self):
method test_single_element_chunks (line 122) | def test_single_element_chunks(self):
method test_empty_array (line 142) | def test_empty_array(self):
FILE: tests/test_fall_back.py
class FallbackNode (line 9) | class FallbackNode(Node):
method __init__ (line 10) | def __init__(self, should_fail=True, max_retries=1):
method prep (line 15) | def prep(self, shared_storage):
method exec (line 20) | def exec(self, prep_result):
method exec_fallback (line 26) | def exec_fallback(self, prep_result, exc):
method post (line 29) | def post(self, shared_storage, prep_result, exec_result):
class AsyncFallbackNode (line 35) | class AsyncFallbackNode(AsyncNode):
method __init__ (line 36) | def __init__(self, should_fail=True, max_retries=1):
method prep_async (line 41) | async def prep_async(self, shared_storage):
method exec_async (line 46) | async def exec_async(self, prep_result):
method exec_fallback_async (line 52) | async def exec_fallback_async(self, prep_result, exc):
method post_async (line 56) | async def post_async(self, shared_storage, prep_result, exec_result):
class TestExecFallback (line 62) | class TestExecFallback(unittest.TestCase):
method test_successful_execution (line 63) | def test_successful_execution(self):
method test_fallback_after_failure (line 73) | def test_fallback_after_failure(self):
method test_fallback_in_flow (line 83) | def test_fallback_in_flow(self):
method test_no_fallback_implementation (line 108) | def test_no_fallback_implementation(self):
method test_retry_before_fallback (line 128) | def test_retry_before_fallback(self):
class TestAsyncExecFallback (line 138) | class TestAsyncExecFallback(unittest.TestCase):
method setUp (line 139) | def setUp(self):
method tearDown (line 143) | def tearDown(self):
method test_async_successful_execution (line 146) | def test_async_successful_execution(self):
method test_async_fallback_after_failure (line 159) | def test_async_fallback_after_failure(self):
method test_async_fallback_in_flow (line 173) | def test_async_fallback_in_flow(self):
method test_async_no_fallback_implementation (line 201) | def test_async_no_fallback_implementation(self):
method test_async_retry_before_fallback (line 224) | def test_async_retry_before_fallback(self):
FILE: tests/test_flow_basic.py
class NumberNode (line 15) | class NumberNode(Node):
method __init__ (line 16) | def __init__(self, number):
method prep (line 19) | def prep(self, shared_storage):
class AddNode (line 23) | class AddNode(Node):
method __init__ (line 24) | def __init__(self, number):
method prep (line 27) | def prep(self, shared_storage):
class MultiplyNode (line 31) | class MultiplyNode(Node):
method __init__ (line 32) | def __init__(self, number):
method prep (line 35) | def prep(self, shared_storage):
class CheckPositiveNode (line 39) | class CheckPositiveNode(Node):
method prep (line 41) | def prep(self, shared_storage):
method post (line 43) | def post(self, shared_storage, prep_result, proc_result):
class NoOpNode (line 50) | class NoOpNode(Node):
class EndSignalNode (line 54) | class EndSignalNode(Node):
method __init__ (line 56) | def __init__(self, signal="finished"):
method post (line 59) | def post(self, shared_storage, prep_result, exec_result):
class TestFlowBasic (line 63) | class TestFlowBasic(unittest.TestCase):
method test_start_method_initialization (line 65) | def test_start_method_initialization(self):
method test_start_method_chaining (line 76) | def test_start_method_chaining(self):
method test_sequence_with_rshift (line 88) | def test_sequence_with_rshift(self):
method test_branching_positive (line 104) | def test_branching_positive(self):
method test_branching_negative (line 124) | def test_branching_negative(self):
method test_cycle_until_negative_ends_with_signal (line 143) | def test_cycle_until_negative_ends_with_signal(self):
method test_flow_ends_warning_default_missing (line 165) | def test_flow_ends_warning_default_missing(self):
method test_flow_ends_warning_specific_missing (line 195) | def test_flow_ends_warning_specific_missing(self):
FILE: tests/test_flow_composition.py
class NumberNode (line 11) | class NumberNode(Node):
method __init__ (line 12) | def __init__(self, number):
method prep (line 15) | def prep(self, shared_storage):
class AddNode (line 19) | class AddNode(Node):
method __init__ (line 20) | def __init__(self, number):
method prep (line 23) | def prep(self, shared_storage):
class MultiplyNode (line 27) | class MultiplyNode(Node):
method __init__ (line 28) | def __init__(self, number):
method prep (line 31) | def prep(self, shared_storage):
class SignalNode (line 36) | class SignalNode(Node):
method __init__ (line 38) | def __init__(self, signal="default_signal"):
method post (line 42) | def post(self, shared_storage, prep_result, exec_result):
class PathNode (line 47) | class PathNode(Node):
method __init__ (line 49) | def __init__(self, path_id):
method prep (line 52) | def prep(self, shared_storage):
class TestFlowComposition (line 57) | class TestFlowComposition(unittest.TestCase):
method test_flow_as_node (line 60) | def test_flow_as_node(self):
method test_nested_flow (line 75) | def test_nested_flow(self):
method test_flow_chaining_flows (line 92) | def test_flow_chaining_flows(self):
method test_composition_with_action_propagation (line 110) | def test_composition_with_action_propagation(self):
FILE: utils/update_pocketflow_mdc.py
class HTMLTagStripper (line 16) | class HTMLTagStripper(html.parser.HTMLParser):
method __init__ (line 18) | def __init__(self):
method handle_data (line 25) | def handle_data(self, data):
method get_text (line 28) | def get_text(self):
function strip_html_tags (line 31) | def strip_html_tags(html_content):
function extract_frontmatter (line 37) | def extract_frontmatter(file_path):
function extract_first_heading (line 65) | def extract_first_heading(file_path):
function get_mdc_description (line 84) | def get_mdc_description(md_file, frontmatter, heading):
function process_markdown_content (line 118) | def process_markdown_content(content, remove_local_refs=False):
function get_documentation_first_policy (line 144) | def get_documentation_first_policy():
function generate_mdc_header (line 158) | def generate_mdc_header(md_file, description, always_apply=False):
function has_substantive_content (line 172) | def has_substantive_content(content):
function create_combined_guide (line 184) | def create_combined_guide(docs_dir, rules_dir):
function convert_md_to_mdc (line 230) | def convert_md_to_mdc(md_file, output_dir, docs_dir, special_treatment=F...
function generate_mdc_files (line 309) | def generate_mdc_files(docs_dir, rules_dir):
Condensed preview — 410 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,843K chars).
[
{
"path": ".cursor/rules/core_abstraction/async.mdc",
"chars": 1728,
"preview": "---\ndescription: Guidelines for using PocketFlow, Core Abstraction, (Advanced) Async\nglobs: \nalwaysApply: false\n---\n# (A"
},
{
"path": ".cursor/rules/core_abstraction/batch.mdc",
"chars": 6593,
"preview": "---\ndescription: Guidelines for using PocketFlow, Core Abstraction, Batch\nglobs: \nalwaysApply: false\n---\n# Batch\n\n**Batc"
},
{
"path": ".cursor/rules/core_abstraction/communication.mdc",
"chars": 4003,
"preview": "---\ndescription: Guidelines for using PocketFlow, Core Abstraction, Communication\nglobs: \nalwaysApply: false\n---\n# Commu"
},
{
"path": ".cursor/rules/core_abstraction/flow.mdc",
"chars": 5861,
"preview": "---\ndescription: Guidelines for using PocketFlow, Core Abstraction, Flow\nglobs: \nalwaysApply: false\n---\n# Flow\n\nA **Flow"
},
{
"path": ".cursor/rules/core_abstraction/node.mdc",
"chars": 3504,
"preview": "---\ndescription: Guidelines for using PocketFlow, Core Abstraction, Node\nglobs: \nalwaysApply: false\n---\n# Node\n\nA **Node"
},
{
"path": ".cursor/rules/core_abstraction/parallel.mdc",
"chars": 2225,
"preview": "---\ndescription: Guidelines for using PocketFlow, Core Abstraction, (Advanced) Parallel\nglobs: \nalwaysApply: false\n---\n#"
},
{
"path": ".cursor/rules/design_pattern/agent.mdc",
"chars": 4752,
"preview": "---\ndescription: Guidelines for using PocketFlow, Design Pattern, Agent\nglobs: \nalwaysApply: false\n---\n# Agent\n\nAgent is"
},
{
"path": ".cursor/rules/design_pattern/mapreduce.mdc",
"chars": 2329,
"preview": "---\ndescription: Guidelines for using PocketFlow, Design Pattern, Map Reduce\nglobs: \nalwaysApply: false\n---\n# Map Reduce"
},
{
"path": ".cursor/rules/design_pattern/multi_agent.mdc",
"chars": 5684,
"preview": "---\ndescription: Guidelines for using PocketFlow, Design Pattern, (Advanced) Multi-Agents\nglobs: \nalwaysApply: false\n---"
},
{
"path": ".cursor/rules/design_pattern/rag.mdc",
"chars": 4533,
"preview": "---\ndescription: Guidelines for using PocketFlow, Design Pattern, RAG\nglobs: \nalwaysApply: false\n---\n# RAG (Retrieval Au"
},
{
"path": ".cursor/rules/design_pattern/structure.mdc",
"chars": 2697,
"preview": "---\ndescription: Guidelines for using PocketFlow, Design Pattern, Structured Output\nglobs: \nalwaysApply: false\n---\n# Str"
},
{
"path": ".cursor/rules/design_pattern/workflow.mdc",
"chars": 1834,
"preview": "---\ndescription: Guidelines for using PocketFlow, Design Pattern, Workflow\nglobs: \nalwaysApply: false\n---\n# Workflow\n\nMa"
},
{
"path": ".cursor/rules/guide_for_pocketflow.mdc",
"chars": 14451,
"preview": "---\ndescription: Guidelines for using PocketFlow, Agentic Coding\nglobs: **/*.py\nalwaysApply: true\n---\n# DOCUMENTATION FI"
},
{
"path": ".cursor/rules/utility_function/chunking.mdc",
"chars": 1448,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, Text Chunking\nglobs: \nalwaysApply: false\n---\n# Text "
},
{
"path": ".cursor/rules/utility_function/embedding.mdc",
"chars": 3671,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, Embedding\nglobs: \nalwaysApply: false\n---\n# Embedding"
},
{
"path": ".cursor/rules/utility_function/llm.mdc",
"chars": 3909,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, LLM Wrapper\nglobs: \nalwaysApply: false\n---\n# LLM Wra"
},
{
"path": ".cursor/rules/utility_function/text_to_speech.mdc",
"chars": 3734,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, Text-to-Speech\nglobs: \nalwaysApply: false\n---\n# Text"
},
{
"path": ".cursor/rules/utility_function/vector.mdc",
"chars": 4973,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, Vector Databases\nglobs: \nalwaysApply: false\n---\n# Ve"
},
{
"path": ".cursor/rules/utility_function/viz.mdc",
"chars": 4771,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, Viz and Debug\nglobs: \nalwaysApply: false\n---\n# Visua"
},
{
"path": ".cursor/rules/utility_function/websearch.mdc",
"chars": 3356,
"preview": "---\ndescription: Guidelines for using PocketFlow, Utility Function, Web Search\nglobs: \nalwaysApply: false\n---\n# Web Sear"
},
{
"path": ".cursorrules",
"chars": 60670,
"preview": "---\nlayout: default\ntitle: \"Agentic Coding\"\n---\n\n# Agentic Coding: Humans Design, Agents code!\n\n> If you are an AI agent"
},
{
"path": ".gitignore",
"chars": 917,
"preview": "# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\n\n\n# IDE specific files\n.ide"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2024 Zachary Huang\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 16237,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/README.md",
"chars": 3185,
"preview": "# Pocket Flow Cookbook\n\n\n<div align=\"center\">\n \n| Name | Difficulty | Description | \n| :-------------: | :----"
},
{
"path": "cookbook/data/PaulGrahamEssaysLarge/addiction.txt",
"chars": 7436,
"preview": "July 2010What hard liquor, cigarettes, heroin, and crack have in common is\nthat they're all more concentrated forms of l"
},
{
"path": "cookbook/data/PaulGrahamEssaysLarge/aord.txt",
"chars": 8501,
"preview": "October 2015When I talk to a startup that's been operating for more than 8 or\n9 months, the first thing I want to know i"
},
{
"path": "cookbook/data/PaulGrahamEssaysLarge/apple.txt",
"chars": 12406,
"preview": "\n\nWant to start a startup? Get funded by\nY Combinator.\n\n\n\n\nNovember 2009I don't think Apple realizes how badly the App "
},
{
"path": "cookbook/data/PaulGrahamEssaysLarge/avg.txt",
"chars": 25387,
"preview": "\n\nWant to start a startup? Get funded by\nY Combinator.\n\n\n\n\nApril 2001, rev. April 2003(This article is derived from a t"
},
{
"path": "cookbook/data/PaulGrahamEssaysLarge/before.txt",
"chars": 25529,
"preview": "\n\nWant to start a startup? Get funded by\nY Combinator.\n\n\n\n\nOctober 2014(This essay is derived from a guest lecture in S"
},
{
"path": "cookbook/pocketflow-a2a/README.md",
"chars": 11371,
"preview": "# PocketFlow Agent with A2A Protocol\n\nThis project demonstrates how to take an existing agent built with the PocketFlow "
},
{
"path": "cookbook/pocketflow-a2a/a2a_client.py",
"chars": 6231,
"preview": "import asyncio\nimport asyncclick as click # Using asyncclick for async main\nfrom uuid import uuid4\nimport json # For pot"
},
{
"path": "cookbook/pocketflow-a2a/a2a_server.py",
"chars": 3552,
"preview": "import click\nimport logging\nimport os\n\n# Import from the common code you copied\nfrom common.server import A2AServer\nfrom"
},
{
"path": "cookbook/pocketflow-a2a/common/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-a2a/common/client/__init__.py",
"chars": 117,
"preview": "from .client import A2AClient\nfrom .card_resolver import A2ACardResolver\n\n__all__ = [\"A2AClient\", \"A2ACardResolver\"]\n"
},
{
"path": "cookbook/pocketflow-a2a/common/client/card_resolver.py",
"chars": 671,
"preview": "import httpx\nfrom common.types import (\n AgentCard,\n A2AClientJSONError,\n)\nimport json\n\n\nclass A2ACardResolver:\n "
},
{
"path": "cookbook/pocketflow-a2a/common/client/client.py",
"chars": 8086,
"preview": "import httpx\nfrom httpx_sse import connect_sse\nfrom typing import Any, AsyncIterable\nfrom common.types import (\n Agen"
},
{
"path": "cookbook/pocketflow-a2a/common/server/__init__.py",
"chars": 152,
"preview": "from .server import A2AServer\nfrom .task_manager import TaskManager, InMemoryTaskManager\n\n__all__ = [\"A2AServer\", \"TaskM"
},
{
"path": "cookbook/pocketflow-a2a/common/server/server.py",
"chars": 8032,
"preview": "from starlette.applications import Starlette\nfrom starlette.responses import JSONResponse\nfrom sse_starlette.sse import "
},
{
"path": "cookbook/pocketflow-a2a/common/server/task_manager.py",
"chars": 10197,
"preview": "from abc import ABC, abstractmethod\nfrom typing import Union, AsyncIterable, List\nfrom common.types import Task\nfrom com"
},
{
"path": "cookbook/pocketflow-a2a/common/server/utils.py",
"chars": 851,
"preview": "from common.types import (\n JSONRPCResponse,\n ContentTypeNotSupportedError,\n UnsupportedOperationError,\n)\nfrom "
},
{
"path": "cookbook/pocketflow-a2a/common/types.py",
"chars": 8792,
"preview": "from typing import Union, Any\nfrom pydantic import BaseModel, Field, TypeAdapter\nfrom typing import Literal, List, Annot"
},
{
"path": "cookbook/pocketflow-a2a/common/utils/in_memory_cache.py",
"chars": 3381,
"preview": "\"\"\"In Memory Cache utility.\"\"\"\n\nimport threading\nimport time\nfrom typing import Any, Dict, Optional\n\n\nclass InMemoryCach"
},
{
"path": "cookbook/pocketflow-a2a/common/utils/push_notification_auth.py",
"chars": 4915,
"preview": "from jwcrypto import jwk\nimport uuid\nfrom starlette.responses import JSONResponse\nfrom starlette.requests import Request"
},
{
"path": "cookbook/pocketflow-a2a/flow.py",
"chars": 1046,
"preview": "from pocketflow import Flow\nfrom nodes import DecideAction, SearchWeb, AnswerQuestion\n\ndef create_agent_flow():\n \"\"\"\n"
},
{
"path": "cookbook/pocketflow-a2a/main.py",
"chars": 735,
"preview": "import sys\nfrom flow import create_agent_flow\n\ndef main():\n \"\"\"Simple function to process a question.\"\"\"\n # Defaul"
},
{
"path": "cookbook/pocketflow-a2a/nodes.py",
"chars": 4708,
"preview": "from pocketflow import Node\nfrom utils import call_llm, search_web\nimport yaml\n\nclass DecideAction(Node):\n def prep(s"
},
{
"path": "cookbook/pocketflow-a2a/requirements.txt",
"chars": 537,
"preview": "# For PocketFlow Agent Logic\npocketflow>=0.0.1\nopenai>=1.0.0\nduckduckgo-search>=7.5.2\npyyaml>=5.1\n\n# For A2A Server Infr"
},
{
"path": "cookbook/pocketflow-a2a/task_manager.py",
"chars": 5837,
"preview": "# FILE: pocketflow_a2a_agent/task_manager.py\nimport logging\nfrom typing import AsyncIterable, Union\nimport asyncio\n\n# Im"
},
{
"path": "cookbook/pocketflow-a2a/utils.py",
"chars": 1002,
"preview": "from openai import OpenAI\nimport os\nfrom duckduckgo_search import DDGS\n\ndef call_llm(prompt): \n client = OpenAI(ap"
},
{
"path": "cookbook/pocketflow-agent/README.md",
"chars": 2119,
"preview": "# Research Agent\n\nThis project demonstrates a simple yet powerful LLM-powered research agent. This implementation is bas"
},
{
"path": "cookbook/pocketflow-agent/demo.ipynb",
"chars": 15940,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"vscode\": {\n "
},
{
"path": "cookbook/pocketflow-agent/flow.py",
"chars": 1046,
"preview": "from pocketflow import Flow\nfrom nodes import DecideAction, SearchWeb, AnswerQuestion\n\ndef create_agent_flow():\n \"\"\"\n"
},
{
"path": "cookbook/pocketflow-agent/main.py",
"chars": 735,
"preview": "import sys\nfrom flow import create_agent_flow\n\ndef main():\n \"\"\"Simple function to process a question.\"\"\"\n # Defaul"
},
{
"path": "cookbook/pocketflow-agent/nodes.py",
"chars": 6237,
"preview": "from pocketflow import Node\nfrom utils import call_llm, search_web_duckduckgo\nimport yaml\nimport re\n\nclass DecideAction("
},
{
"path": "cookbook/pocketflow-agent/requirements.txt",
"chars": 242,
"preview": "pocketflow>=0.0.1\nddgs>=7.5.2 # For web search\naiohttp>=3.8.0 # For HTTP requests\nopenai>=1.0.0 "
},
{
"path": "cookbook/pocketflow-agent/utils.py",
"chars": 1705,
"preview": "from openai import OpenAI\nimport os\nfrom ddgs import DDGS\nimport requests\n\ndef call_llm(prompt): \n client = OpenAI"
},
{
"path": "cookbook/pocketflow-agent-skills/README.md",
"chars": 1060,
"preview": "# Agent Skills with PocketFlow\n\nThis cookbook shows a lightweight pattern for using **Agent Skills** inside a PocketFlow"
},
{
"path": "cookbook/pocketflow-agent-skills/flow.py",
"chars": 225,
"preview": "from pocketflow import Flow\nfrom nodes import SelectSkill, ApplySkill\n\n\ndef create_flow():\n select_skill = SelectSkil"
},
{
"path": "cookbook/pocketflow-agent-skills/main.py",
"chars": 637,
"preview": "import sys\nfrom flow import create_flow\n\n\ndef parse_task(default_task: str) -> str:\n for arg in sys.argv[1:]:\n "
},
{
"path": "cookbook/pocketflow-agent-skills/nodes.py",
"chars": 1652,
"preview": "from pocketflow import Node\nfrom utils import call_llm, load_skills\n\n\nclass SelectSkill(Node):\n def prep(self, shared"
},
{
"path": "cookbook/pocketflow-agent-skills/requirements.txt",
"chars": 32,
"preview": "pocketflow>=0.0.1\nopenai>=1.0.0\n"
},
{
"path": "cookbook/pocketflow-agent-skills/skills/checklist_writer.md",
"chars": 231,
"preview": "# Checklist Writer Skill\n\nConvert requests into clear, actionable checklists.\n\n## Rules\n- Use numbered steps.\n- Keep eac"
},
{
"path": "cookbook/pocketflow-agent-skills/skills/executive_brief.md",
"chars": 248,
"preview": "# Executive Brief Skill\n\nYou are writing for senior leaders.\n\n## Rules\n- Keep it concise and decision-oriented.\n- Start "
},
{
"path": "cookbook/pocketflow-agent-skills/utils.py",
"chars": 654,
"preview": "from pathlib import Path\nimport os\nfrom openai import OpenAI\n\n\ndef load_skills(skills_dir: str) -> dict[str, str]:\n s"
},
{
"path": "cookbook/pocketflow-async-basic/README.md",
"chars": 2209,
"preview": "# PocketFlow Async Basic Example\n\nThis example demonstrates async operations using a simple Recipe Finder that:\n1. Fetch"
},
{
"path": "cookbook/pocketflow-async-basic/flow.py",
"chars": 749,
"preview": "\"\"\"AsyncFlow implementation for recipe finder.\"\"\"\n\nfrom pocketflow import AsyncFlow, Node\nfrom nodes import FetchRecipes"
},
{
"path": "cookbook/pocketflow-async-basic/main.py",
"chars": 456,
"preview": "import asyncio\nfrom flow import create_flow\n\nasync def main():\n \"\"\"Run the recipe finder flow.\"\"\"\n # Create flow\n "
},
{
"path": "cookbook/pocketflow-async-basic/nodes.py",
"chars": 2124,
"preview": "from pocketflow import AsyncNode\nfrom utils import fetch_recipes, call_llm_async, get_user_input\n\nclass FetchRecipes(Asy"
},
{
"path": "cookbook/pocketflow-async-basic/requirements.txt",
"chars": 91,
"preview": "pocketflow\naiohttp>=3.8.0 # For async HTTP requests\nopenai>=1.0.0 # For async LLM calls "
},
{
"path": "cookbook/pocketflow-async-basic/utils.py",
"chars": 1246,
"preview": "import asyncio\nimport aiohttp\nfrom openai import AsyncOpenAI\n\nasync def fetch_recipes(ingredient):\n \"\"\"Fetch recipes "
},
{
"path": "cookbook/pocketflow-batch/README.md",
"chars": 2293,
"preview": "# Batch Translation Process\n\nThis project demonstrates a batch processing implementation that enables LLMs to translate "
},
{
"path": "cookbook/pocketflow-batch/main.py",
"chars": 2657,
"preview": "import os\nimport time\nfrom pocketflow import BatchNode, Flow\nfrom utils import call_llm\n\nclass TranslateTextNode(BatchNo"
},
{
"path": "cookbook/pocketflow-batch/requirements.txt",
"chars": 47,
"preview": "pocketflow>=0.0.1\nanthropic>=0.15.0\npyyaml>=6.0"
},
{
"path": "cookbook/pocketflow-batch/translations/README_CHINESE.md",
"chars": 11492,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/translations/README_FRENCH.md",
"chars": 14906,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – fra"
},
{
"path": "cookbook/pocketflow-batch/translations/README_GERMAN.md",
"chars": 14574,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/translations/README_JAPANESE.md",
"chars": 12179,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/translations/README_KOREAN.md",
"chars": 12175,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/translations/README_PORTUGUESE.md",
"chars": 14626,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/translations/README_RUSSIAN.md",
"chars": 14711,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/translations/README_SPANISH.md",
"chars": 14899,
"preview": "<div align=\"center\">\n <img src=\"https://github.com/The-Pocket/.github/raw/main/assets/title.png\" alt=\"Pocket Flow – 100"
},
{
"path": "cookbook/pocketflow-batch/utils.py",
"chars": 697,
"preview": "from anthropic import Anthropic\nimport os\n\ndef call_llm(prompt):\n client = Anthropic(api_key=os.environ.get(\"ANTHROPI"
},
{
"path": "cookbook/pocketflow-batch-flow/README.md",
"chars": 2014,
"preview": "# PocketFlow BatchFlow Example\n\nThis example demonstrates the BatchFlow concept in PocketFlow by implementing an image p"
},
{
"path": "cookbook/pocketflow-batch-flow/flow.py",
"chars": 1382,
"preview": "from pocketflow import Flow, BatchFlow\nfrom nodes import LoadImage, ApplyFilter, SaveImage\n\ndef create_base_flow():\n "
},
{
"path": "cookbook/pocketflow-batch-flow/main.py",
"chars": 363,
"preview": "import os\nfrom PIL import Image\nimport numpy as np\nfrom flow import create_flow\n\ndef main():\n # Create and run flow\n "
},
{
"path": "cookbook/pocketflow-batch-flow/nodes.py",
"chars": 2507,
"preview": "\"\"\"Node implementations for image processing.\"\"\"\n\nimport os\nfrom PIL import Image, ImageEnhance, ImageFilter\nfrom pocket"
},
{
"path": "cookbook/pocketflow-batch-flow/requirements.txt",
"chars": 25,
"preview": "pocketflow\nPillow>=10.0.0"
},
{
"path": "cookbook/pocketflow-batch-node/README.md",
"chars": 1670,
"preview": "# PocketFlow BatchNode Example\n\nThis example demonstrates the BatchNode concept in PocketFlow by implementing a CSV proc"
},
{
"path": "cookbook/pocketflow-batch-node/data/sales.csv",
"chars": 193999,
"preview": "date,amount,product\n2024-01-01,114.9,B\n2024-01-02,95.85,A\n2024-01-03,119.43,C\n2024-01-04,145.69,A\n2024-01-05,92.98,B\n202"
},
{
"path": "cookbook/pocketflow-batch-node/flow.py",
"chars": 926,
"preview": "from pocketflow import Flow, Node\nfrom nodes import CSVProcessor\n\nclass ShowStats(Node):\n \"\"\"Node to display the fina"
},
{
"path": "cookbook/pocketflow-batch-node/main.py",
"chars": 1011,
"preview": "import os\nfrom flow import create_flow\n\ndef main():\n \"\"\"Run the batch processing example.\"\"\"\n # Create data direct"
},
{
"path": "cookbook/pocketflow-batch-node/nodes.py",
"chars": 1917,
"preview": "import pandas as pd\nfrom pocketflow import BatchNode\n\nclass CSVProcessor(BatchNode):\n \"\"\"BatchNode that processes a l"
},
{
"path": "cookbook/pocketflow-batch-node/requirements.txt",
"chars": 25,
"preview": "pocketflow\npandas>=2.0.0 "
},
{
"path": "cookbook/pocketflow-chat/README.md",
"chars": 1131,
"preview": "# Simple PocketFlow Chat\n\nA basic chat application using PocketFlow with OpenAI's GPT-4o model.\n\n## Features\n\n- Convers"
},
{
"path": "cookbook/pocketflow-chat/main.py",
"chars": 1648,
"preview": "from pocketflow import Node, Flow\nfrom utils import call_llm\n\nclass ChatNode(Node):\n def prep(self, shared):\n "
},
{
"path": "cookbook/pocketflow-chat/requirements.txt",
"chars": 31,
"preview": "pocketflow>=0.0.1\nopenai>=1.0.0"
},
{
"path": "cookbook/pocketflow-chat/utils.py",
"chars": 585,
"preview": "from openai import OpenAI\nimport os\n\ndef call_llm(messages):\n client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\""
},
{
"path": "cookbook/pocketflow-chat-guardrail/README.md",
"chars": 2815,
"preview": "# Travel Advisor Chat with Guardrails\n\nA travel-focused chat application using PocketFlow with OpenAI's GPT-4o model, e"
},
{
"path": "cookbook/pocketflow-chat-guardrail/main.py",
"chars": 4807,
"preview": "from pocketflow import Node, Flow\nfrom utils import call_llm\n\nclass UserInputNode(Node):\n def prep(self, shared):\n "
},
{
"path": "cookbook/pocketflow-chat-guardrail/requirements.txt",
"chars": 31,
"preview": "pocketflow>=0.0.1\nopenai>=1.0.0"
},
{
"path": "cookbook/pocketflow-chat-guardrail/utils.py",
"chars": 584,
"preview": "from openai import OpenAI\nimport os\n\ndef call_llm(messages):\n client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\""
},
{
"path": "cookbook/pocketflow-chat-memory/README.md",
"chars": 4844,
"preview": "# PocketFlow Chat with Memory\n\nA chat application with memory retrieval using PocketFlow. This example maintains a slidi"
},
{
"path": "cookbook/pocketflow-chat-memory/flow.py",
"chars": 994,
"preview": "from pocketflow import Flow\nfrom nodes import GetUserQuestionNode, RetrieveNode, AnswerNode, EmbedNode\n\ndef create_chat_"
},
{
"path": "cookbook/pocketflow-chat-memory/main.py",
"chars": 783,
"preview": "from flow import chat_flow\n\ndef run_chat_memory_demo():\n \"\"\"\n Run an interactive chat interface with memory retrie"
},
{
"path": "cookbook/pocketflow-chat-memory/nodes.py",
"chars": 7361,
"preview": "from pocketflow import Node\nfrom utils.vector_index import create_index, add_vector, search_vectors\nfrom utils.call_llm "
},
{
"path": "cookbook/pocketflow-chat-memory/requirements.txt",
"chars": 63,
"preview": "pocketflow>=0.0.2\nnumpy>=1.20.0\nfaiss-cpu>=1.7.0\nopenai>=1.0.0\n"
},
{
"path": "cookbook/pocketflow-chat-memory/utils/__init__.py",
"chars": 1,
"preview": "\n"
},
{
"path": "cookbook/pocketflow-chat-memory/utils/call_llm.py",
"chars": 584,
"preview": "import os\nfrom openai import OpenAI\n\ndef call_llm(messages):\n client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\""
},
{
"path": "cookbook/pocketflow-chat-memory/utils/get_embedding.py",
"chars": 1001,
"preview": "import os\nimport numpy as np\nfrom openai import OpenAI\n\ndef get_embedding(text):\n client = OpenAI(api_key=os.environ."
},
{
"path": "cookbook/pocketflow-chat-memory/utils/vector_index.py",
"chars": 2103,
"preview": "import numpy as np\nimport faiss\n\ndef create_index(dimension=1536):\n return faiss.IndexFlatL2(dimension)\n\ndef add_vect"
},
{
"path": "cookbook/pocketflow-cli-hitl/README.md",
"chars": 3345,
"preview": "# PocketFlow Command-Line Joke Generator (Human-in-the-Loop Example)\n\nA simple, interactive command-line application tha"
},
{
"path": "cookbook/pocketflow-cli-hitl/docs/design.md",
"chars": 5006,
"preview": "# Design Doc: Command-Line Joke Generator\n\n> Please DON'T remove notes for AI\n\n## Requirements\n\n> Notes for AI: Keep it "
},
{
"path": "cookbook/pocketflow-cli-hitl/flow.py",
"chars": 515,
"preview": "from pocketflow import Flow\nfrom nodes import GetTopicNode, GenerateJokeNode, GetFeedbackNode\n\ndef create_joke_flow() ->"
},
{
"path": "cookbook/pocketflow-cli-hitl/main.py",
"chars": 456,
"preview": "from flow import create_joke_flow\n\ndef main():\n \"\"\"Main function to run the joke generator application.\"\"\"\n print("
},
{
"path": "cookbook/pocketflow-cli-hitl/nodes.py",
"chars": 2085,
"preview": "from pocketflow import Node\nfrom utils.call_llm import call_llm\n\nclass GetTopicNode(Node):\n \"\"\"Prompts the user to en"
},
{
"path": "cookbook/pocketflow-cli-hitl/requirements.txt",
"chars": 57,
"preview": "pocketflow>=0.0.1\nanthropic>=0.20.0 # Or a recent version"
},
{
"path": "cookbook/pocketflow-cli-hitl/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-cli-hitl/utils/call_llm.py",
"chars": 912,
"preview": "from anthropic import Anthropic\nimport os\n\ndef call_llm(prompt: str) -> str:\n client = Anthropic(api_key=os.environ.g"
},
{
"path": "cookbook/pocketflow-code-generator/README.md",
"chars": 5943,
"preview": "# PocketFlow Code Generator\n\nAn intelligent AI system that takes LeetCode-style coding problems and automatically genera"
},
{
"path": "cookbook/pocketflow-code-generator/doc/design.md",
"chars": 5424,
"preview": "# Design Doc: PocketFlow Code Generator\n\n> Please DON'T remove notes for AI\n\n## Requirements\n\n> Notes for AI: Keep it si"
},
{
"path": "cookbook/pocketflow-code-generator/flow.py",
"chars": 611,
"preview": "from pocketflow import Flow\nfrom nodes import GenerateTestCases, ImplementFunction, RunTests, Revise\n\ndef create_code_ge"
},
{
"path": "cookbook/pocketflow-code-generator/main.py",
"chars": 1486,
"preview": "import sys\nfrom flow import create_code_generator_flow\n\ndef main():\n \"\"\"Runs the PocketFlow Code Generator applicatio"
},
{
"path": "cookbook/pocketflow-code-generator/nodes.py",
"chars": 10254,
"preview": "import yaml\nfrom pocketflow import Node, BatchNode\nfrom utils.call_llm import call_llm\nfrom utils.code_executor import e"
},
{
"path": "cookbook/pocketflow-code-generator/requirements.txt",
"chars": 28,
"preview": "anthropic\npocketflow\npyyaml "
},
{
"path": "cookbook/pocketflow-code-generator/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-code-generator/utils/call_llm.py",
"chars": 598,
"preview": "from anthropic import Anthropic\nimport os\n\ndef call_llm(prompt):\n client = Anthropic(api_key=os.environ.get(\"ANTHROPI"
},
{
"path": "cookbook/pocketflow-code-generator/utils/code_executor.py",
"chars": 1691,
"preview": "import sys\nimport io\nimport traceback\nfrom contextlib import redirect_stdout, redirect_stderr\n\ndef execute_python(functi"
},
{
"path": "cookbook/pocketflow-communication/README.md",
"chars": 1317,
"preview": "# PocketFlow Communication Example\n\nThis example demonstrates the [Communication](https://the-pocket.github.io/PocketFlo"
},
{
"path": "cookbook/pocketflow-communication/flow.py",
"chars": 617,
"preview": "\"\"\"Flow configuration for the communication example.\"\"\"\n\nfrom pocketflow import Flow\nfrom nodes import TextInput, WordCo"
},
{
"path": "cookbook/pocketflow-communication/main.py",
"chars": 184,
"preview": "from flow import create_flow\n\ndef main():\n \"\"\"Run the communication example.\"\"\"\n flow = create_flow()\n shared ="
},
{
"path": "cookbook/pocketflow-communication/nodes.py",
"chars": 1986,
"preview": "\"\"\"Node implementations for the communication example.\"\"\"\n\nfrom pocketflow import Node\n\nclass EndNode(Node):\n \"\"\"Node"
},
{
"path": "cookbook/pocketflow-communication/requirements.txt",
"chars": 18,
"preview": "pocketflow==0.1.0 "
},
{
"path": "cookbook/pocketflow-fastapi-background/README.md",
"chars": 2983,
"preview": "# PocketFlow FastAPI Background Jobs with Real-time Progress\n\nA web application demonstrating PocketFlow workflows runni"
},
{
"path": "cookbook/pocketflow-fastapi-background/docs/design.md",
"chars": 3728,
"preview": "# Design Doc: PocketFlow FastAPI Background Job with SSE Progress\n\n> Please DON'T remove notes for AI\n\n## Requirements\n\n"
},
{
"path": "cookbook/pocketflow-fastapi-background/flow.py",
"chars": 522,
"preview": "from pocketflow import Flow\nfrom nodes import GenerateOutline, WriteContent, ApplyStyle\n\ndef create_article_flow():\n "
},
{
"path": "cookbook/pocketflow-fastapi-background/main.py",
"chars": 3615,
"preview": "import asyncio\nimport json\nimport uuid\nfrom fastapi import FastAPI, BackgroundTasks, Form\nfrom fastapi.responses import "
},
{
"path": "cookbook/pocketflow-fastapi-background/nodes.py",
"chars": 3440,
"preview": "import yaml\nfrom pocketflow import Node, BatchNode\nfrom utils.call_llm import call_llm\n\nclass GenerateOutline(Node):\n "
},
{
"path": "cookbook/pocketflow-fastapi-background/requirements.txt",
"chars": 47,
"preview": "fastapi\nuvicorn\nopenai\npyyaml\npython-multipart "
},
{
"path": "cookbook/pocketflow-fastapi-background/static/index.html",
"chars": 6649,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width"
},
{
"path": "cookbook/pocketflow-fastapi-background/static/progress.html",
"chars": 14962,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width"
},
{
"path": "cookbook/pocketflow-fastapi-background/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-fastapi-background/utils/call_llm.py",
"chars": 378,
"preview": "import os\nfrom openai import OpenAI\n\ndef call_llm(prompt): \n client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KE"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/README.md",
"chars": 4187,
"preview": "# PocketFlow Web Human-in-the-Loop (HITL) Feedback Service\n\nThis project demonstrates a minimal web application for huma"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/docs/design.md",
"chars": 3311,
"preview": "# Human-in-the-Loop Web Service\n\n## 1. Requirements\n\n* **Goal:** Create a web service for task submission, processing"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/flow.py",
"chars": 547,
"preview": "from pocketflow import AsyncFlow\nfrom nodes import ProcessNode, ReviewNode, ResultNode\n\ndef create_feedback_flow():\n "
},
{
"path": "cookbook/pocketflow-fastapi-hitl/nodes.py",
"chars": 2738,
"preview": "from pocketflow import Node, AsyncNode\nfrom utils.process_task import process_task\n\nclass ProcessNode(Node):\n def pre"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/requirements.txt",
"chars": 98,
"preview": "pocketflow>=0.0.1\nfastapi\nuvicorn[standard] # ASGI server for FastAPI\njinja2 # For HTML templating"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/server.py",
"chars": 10856,
"preview": "import asyncio\nimport uuid\nimport json\nimport os\nfrom fastapi import FastAPI, Request, HTTPException, status, Background"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/static/style.css",
"chars": 3281,
"preview": "body {\n font-family: sans-serif;\n margin: 0; /* Remove default body margin */\n padding: 20px; /* Add some paddi"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/templates/index.html",
"chars": 8437,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width"
},
{
"path": "cookbook/pocketflow-fastapi-hitl/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-fastapi-hitl/utils/process_task.py",
"chars": 437,
"preview": "import time\n\ndef process_task(input_data):\n \"\"\"Minimal simulation of processing the input data.\"\"\"\n print(f\"Proces"
},
{
"path": "cookbook/pocketflow-fastapi-websocket/README.md",
"chars": 1740,
"preview": "# PocketFlow FastAPI WebSocket Chat\n\nReal-time chat interface with streaming LLM responses using PocketFlow, FastAPI, an"
},
{
"path": "cookbook/pocketflow-fastapi-websocket/docs/design.md",
"chars": 3036,
"preview": "# Design Doc: FastAPI WebSocket Chat Interface\n\n> Please DON'T remove notes for AI\n\n## Requirements\n\n> Notes for AI: Kee"
},
{
"path": "cookbook/pocketflow-fastapi-websocket/flow.py",
"chars": 178,
"preview": "from pocketflow import AsyncFlow\nfrom nodes import StreamingChatNode\n\ndef create_streaming_chat_flow():\n chat_node = "
},
{
"path": "cookbook/pocketflow-fastapi-websocket/main.py",
"chars": 1182,
"preview": "import json\nfrom fastapi import FastAPI, WebSocket, WebSocketDisconnect\nfrom fastapi.staticfiles import StaticFiles\nfrom"
},
{
"path": "cookbook/pocketflow-fastapi-websocket/nodes.py",
"chars": 1413,
"preview": "import asyncio\nimport json\nfrom pocketflow import AsyncNode\nfrom utils.stream_llm import stream_llm\n\nclass StreamingChat"
},
{
"path": "cookbook/pocketflow-fastapi-websocket/requirements.txt",
"chars": 68,
"preview": "fastapi==0.104.1\nuvicorn[standard]==0.24.0\nopenai==1.3.8\npocketflow "
},
{
"path": "cookbook/pocketflow-fastapi-websocket/static/index.html",
"chars": 7288,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <title>PocketFlow Chat</title>\n <meta name=\"viewport\" content=\"width=device-width, "
},
{
"path": "cookbook/pocketflow-fastapi-websocket/utils/__init__.py",
"chars": 53,
"preview": "# Utils package for FastAPI WebSocket Chat Interface "
},
{
"path": "cookbook/pocketflow-fastapi-websocket/utils/stream_llm.py",
"chars": 732,
"preview": "import os\nfrom openai import AsyncOpenAI\n\nasync def stream_llm(messages):\n client = AsyncOpenAI(api_key=os.environ.ge"
},
{
"path": "cookbook/pocketflow-flow/README.md",
"chars": 1549,
"preview": "# Text Converter Flow\n\nThis project demonstrates an interactive text transformation tool built with PocketFlow.\n\n## Feat"
},
{
"path": "cookbook/pocketflow-flow/flow.py",
"chars": 1792,
"preview": "from pocketflow import Node, Flow\n\nclass TextInput(Node):\n def prep(self, shared):\n \"\"\"Get text input from use"
},
{
"path": "cookbook/pocketflow-flow/main.py",
"chars": 307,
"preview": "from flow import flow\n\ndef main():\n print(\"\\nWelcome to Text Converter!\")\n print(\"=========================\")\n "
},
{
"path": "cookbook/pocketflow-flow/requirements.txt",
"chars": 18,
"preview": "pocketflow>=0.1.0 "
},
{
"path": "cookbook/pocketflow-google-calendar/.gitignore",
"chars": 47,
"preview": ".env\nPipfile.lock\ncredentials.json\ntoken.pickle"
},
{
"path": "cookbook/pocketflow-google-calendar/Pipfile",
"chars": 292,
"preview": "[[source]]\nurl = \"https://pypi.org/simple\"\nverify_ssl = true\nname = \"pypi\"\n\n[packages]\npython-dotenv = \">=0.19.0\"\npocket"
},
{
"path": "cookbook/pocketflow-google-calendar/README.md",
"chars": 2935,
"preview": "# Pocket Google Calendar\n\nAn application based on the Pocket Flow framework for Google Calendar integration.\n\n## 📋 Descr"
},
{
"path": "cookbook/pocketflow-google-calendar/main.py",
"chars": 1641,
"preview": "from pocketflow import Flow\nfrom nodes import CreateCalendarEventNode, ListCalendarEventsNode, ListCalendarsNode\nfrom da"
},
{
"path": "cookbook/pocketflow-google-calendar/nodes.py",
"chars": 2860,
"preview": "from pocketflow import Node\nfrom utils.google_calendar import create_event, list_events, list_calendar_lists\nfrom dateti"
},
{
"path": "cookbook/pocketflow-google-calendar/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-google-calendar/utils/google_calendar.py",
"chars": 2911,
"preview": "from google.oauth2.credentials import Credentials\nfrom google_auth_oauthlib.flow import InstalledAppFlow\nfrom google.aut"
},
{
"path": "cookbook/pocketflow-gradio-hitl/README.md",
"chars": 4001,
"preview": "# PocketFlow Gradio HITL Example\n\nA web-based application that demonstrates Human-in-the-Loop (HITL) workflow orchestrat"
},
{
"path": "cookbook/pocketflow-gradio-hitl/flow.py",
"chars": 730,
"preview": "from pocketflow import Flow\n\nfrom nodes import (\n DecideAction,\n CheckWeather,\n BookHotel,\n FollowUp,\n Re"
},
{
"path": "cookbook/pocketflow-gradio-hitl/main.py",
"chars": 2902,
"preview": "import time\nimport uuid\nfrom concurrent.futures import ThreadPoolExecutor\nfrom queue import Queue\n\nimport gradio as gr\nf"
},
{
"path": "cookbook/pocketflow-gradio-hitl/nodes.py",
"chars": 9312,
"preview": "from datetime import datetime\nfrom queue import Queue\n\nimport yaml\nfrom pocketflow import Node\n\nfrom utils.call_llm impo"
},
{
"path": "cookbook/pocketflow-gradio-hitl/requirements.txt",
"chars": 47,
"preview": "pocketflow>=0.0.2\ngradio>=5.29.1\nopenai>=1.78.1"
},
{
"path": "cookbook/pocketflow-gradio-hitl/utils/call_llm.py",
"chars": 588,
"preview": "import os\n\nfrom openai import OpenAI\nfrom openai.types.chat.chat_completion import ChatCompletion\n\napi_key = os.getenv(\""
},
{
"path": "cookbook/pocketflow-gradio-hitl/utils/call_mock_api.py",
"chars": 1498,
"preview": "import random\nfrom datetime import date, datetime\n\n\ndef call_check_weather_api(city: str, date: date | None):\n if dat"
},
{
"path": "cookbook/pocketflow-gradio-hitl/utils/conversation.py",
"chars": 335,
"preview": "conversation_cache = {}\n\n\ndef load_conversation(conversation_id: str):\n print(f\"Loading conversation {conversation_id"
},
{
"path": "cookbook/pocketflow-gradio-hitl/utils/format_chat_history.py",
"chars": 814,
"preview": "def format_chat_history(history):\n \"\"\"\n Format the chat history for LLM\n\n Args:\n history (list): The cha"
},
{
"path": "cookbook/pocketflow-hello-world/README.md",
"chars": 921,
"preview": "# PocketFlow Hello World\n\nYour first PocketFlow application! This simple example demonstrates how to create a basic Pock"
},
{
"path": "cookbook/pocketflow-hello-world/docs/design.md",
"chars": 734,
"preview": "# Your Project Title\n\n## Project Requirements\nA description of the project requirements. \n\n## Utility Functions\n\n1. **Ca"
},
{
"path": "cookbook/pocketflow-hello-world/flow.py",
"chars": 526,
"preview": "from pocketflow import Node, Flow\nfrom utils.call_llm import call_llm\n\n# An example node and flow\n# Please replace this "
},
{
"path": "cookbook/pocketflow-hello-world/main.py",
"chars": 369,
"preview": "from flow import qa_flow\n\n# Example main function\n# Please replace this with your own main function\ndef main():\n shar"
},
{
"path": "cookbook/pocketflow-hello-world/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "cookbook/pocketflow-hello-world/utils/call_llm.py",
"chars": 370,
"preview": "from openai import OpenAI\n\ndef call_llm(prompt): \n client = OpenAI(api_key=\"YOUR_API_KEY_HERE\")\n r = client.cha"
},
{
"path": "cookbook/pocketflow-llm-streaming/README.md",
"chars": 1047,
"preview": "# LLM Streaming and Interruption\n\nDemonstrates real-time LLM response streaming with user interrupt capability.\n\n- Chec"
},
{
"path": "cookbook/pocketflow-llm-streaming/main.py",
"chars": 1694,
"preview": "import time\nimport threading\nfrom pocketflow import Node, Flow\nfrom utils import fake_stream_llm, stream_llm\n\nclass Stre"
},
{
"path": "cookbook/pocketflow-llm-streaming/requirements.txt",
"chars": 31,
"preview": "pocketflow>=0.0.1\nopenai>=1.0.0"
},
{
"path": "cookbook/pocketflow-llm-streaming/utils.py",
"chars": 2399,
"preview": "from openai import OpenAI\nimport os\n\ndef stream_llm(prompt):\n client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\""
},
{
"path": "cookbook/pocketflow-majority-vote/README.md",
"chars": 2662,
"preview": "# Majority Vote Reasoning\n\nThis project demonstrates a majority vote implementation that enables LLMs to solve complex r"
},
{
"path": "cookbook/pocketflow-majority-vote/main.py",
"chars": 3095,
"preview": "import argparse\nfrom pocketflow import BatchNode, Flow\nimport collections\nfrom utils import call_llm\nimport yaml\n\nclass "
},
{
"path": "cookbook/pocketflow-majority-vote/requirements.txt",
"chars": 47,
"preview": "pocketflow>=0.0.1\nanthropic>=0.15.0\npyyaml>=6.0"
},
{
"path": "cookbook/pocketflow-majority-vote/utils.py",
"chars": 601,
"preview": "from anthropic import Anthropic\nimport os\n\ndef call_llm(prompt):\n client = Anthropic(api_key=os.environ.get(\"ANTHROPI"
},
{
"path": "cookbook/pocketflow-map-reduce/README.md",
"chars": 2321,
"preview": "# Resume Qualification - Map Reduce Example\n\nA PocketFlow example that demonstrates how to implement a Map-Reduce patter"
},
{
"path": "cookbook/pocketflow-map-reduce/data/resume1.txt",
"chars": 774,
"preview": "John Smith\nSoftware Engineer\n\nEducation:\n- Master of Computer Science, Stanford University, 2018\n- Bachelor of Computer "
},
{
"path": "cookbook/pocketflow-map-reduce/data/resume2.txt",
"chars": 854,
"preview": "Emily Johnson\nData Scientist\n\nEducation:\n- Ph.D. in Statistics, UC Berkeley, 2020\n- Master of Science in Mathematics, UC"
},
{
"path": "cookbook/pocketflow-map-reduce/data/resume3.txt",
"chars": 755,
"preview": "Michael Williams\nMarketing Manager\n\nEducation:\n- MBA, Harvard Business School, 2015\n- Bachelor of Arts in Communications"
}
]
// ... and 210 more files (download for full content)
About this extraction
This page contains the full source code of the The-Pocket/PocketFlow GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 410 files (1.7 MB), approximately 562.1k tokens, and a symbol index with 1175 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.