## File: README.md

# Julep

Julep — durable, composable AI agents. Flows that crash and resume, retry safely, and explain every step.

Julep builds agents as **composable, durable dataflows** instead of ad-hoc loops: flows can crash and resume, retry safely, explain every step through a derived projection, and deny any tool the model was not explicitly allowed to call. The primary authoring surface is define-by-construction `@flow`: ordinary Python names graph steps while registered tools, pures, reasoners, branches, fan-out, retries, and timeouts compile to the same frozen wire-format IR. The pure core stays dependency-free, while the Temporal layer is optional.

---

## Install

```bash
pip install --pre julep
```

Julep 3 currently ships as a release candidate, so the `--pre` flag is required; it drops once `3.0.0` is final.

---

## Quickstart

10 minutes, no API key. Install the base package and run this as a normal Python script:

```python
from typing import TypedDict

from julep import Reasoner, deploy, flow, pure, think, tool


class SupportReply(TypedDict):
    reply: str


@tool(effect="read", idempotent=True)
def lookup_ticket(ticket: str) -> dict[str, str]:
    return {
        "ticket": ticket,
        "queue": "billing",
        "summary": "Use the duplicate-charge runbook.",
    }


@pure("ticket_prompt")
def ticket_prompt(hit: dict[str, str]) -> dict[str, str]:
    return {"queue": hit["queue"], "context": hit["summary"]}


support_reply = Reasoner(
    name="support_reply",
    model="anthropic:claude-haiku-4-5-20251001",
    system="Draft one concise support reply as JSON.",
    reply=SupportReply,
)


@flow
def triage(ticket: str) -> dict[str, str]:
    hit = lookup_ticket(ticket, retries=2, timeout_s=5)
    prompt = ticket_prompt(hit)
    answer = think(support_reply, prompt, timeout_s=10)
    return hit | answer


def fake_support_reply(value: dict[str, str]) -> SupportReply:
    return {"reply": f"{value['queue']}: {value['context']}"}


deployment = deploy(triage, tools=[lookup_ticket], reasoners=[support_reply])
result = deployment.dry_run(
    "Customer was charged twice.",
    reasoners={"support_reply": fake_support_reply},
)

print(result.value)
```

`@flow` runs once at definition time with data handles. Registered tools, registered pures, `think(...)`, `cond(...)`, `switch(...)`, `each(...)`, and `reschedule(...)` append graph steps instead of doing runtime work; `|` merges records and `h["key"]` plucks fields. `deploy(..., tools=..., reasoners=...)` freezes the tool and reasoner surface, and `dry_run(...)` executes locally with in-memory tools and deterministic fake reasoners. See the larger `@flow` examples in `examples/episode_summary_flow.py` and `examples/cluster_labeling_flow.py`.

Use `mcp_tool(server, tool)` inside `@flow` for an MCP reference. Its schemas
and behavior contract come from the frozen MCP snapshot; handle-valued keyword
arguments build its input record directly. `examples/episode_summary_flow.py`
shows snapshot-backed MCP reads and writes with a local `mcp_call` fake.

## Production secrets and MCP safety

The self-hosted control plane includes a write-only operator vault whose values
are encrypted at rest. Callers can also bind short-lived, per-run credentials to
whole-string `secret://name` MCP header references; those values travel only in
encrypted Temporal payloads and are excluded from stored run data and
projections. Before user effects, worker-side MCP preflight checks the frozen,
transitively reachable tool surface. New releases default to exact `pin`
comparison, with explicit `names` and `off` escape hatches; mid-run tool removal
or post-validation schema rejection fails terminally as typed surface drift.

See the **[control-plane guide](docs-site/content/docs/deploy/control-plane.md)**
for vault configuration, run-secret limits and binding rules, MCP policy
behavior, and the administration API.

---

## The CLI

`julep` is the developer CLI for a whole **module of agents** — "dbt for agents, terminal-native." Point it at a directory; it discovers every `@flow`/`Agent(...)`, treats each as a node in a cross-agent graph, and gives you one selection grammar across every verb:

```bash
julep ls                                  # list agents (name · kind · tags)
julep show triage                         # one agent's kind, source location, tags, calls
julep graph                               # the cross-agent DAG as Graphviz DOT
julep run triage --input '"TICKET-42"'    # execute locally, stream the trace tree
julep lint +triage                        # validate an agent and everything it depends on
julep test triage                         # run pytest for the selected agents
julep trace <run-id>                      # render a cached run's trace tree + Langfuse link
julep doctor                              # preflight: discovery, secret refs, git, Langfuse, Temporal
julep deploy triage --env staging         # freeze → publish → record in the deploy ledger
julep serve api --migrate                 # run the self-hosted FastAPI control plane
```

Selectors compose: `tag:support`, `state:modified` (Slim-CI), `+agent`/`agent+`/`@agent` graph traversal, `a,b` intersection, `--exclude`. Full reference: **[docs-site/content/docs/guides/using-the-cli.md](docs-site/content/docs/guides/using-the-cli.md)**.

For production applications, declare an explicit object instead of adding a
second discovery convention:

```python
from collections.abc import Mapping

from julep import Application, CapabilityManifest, McpSnapshot, PipelineSpec


def load_live_memory_tools_snapshot(
    environment: Mapping[str, str],
) -> McpSnapshot:
    # Use the selected deployment environment to call tools/list.
    ...

application = Application("memory", [
    PipelineSpec(
        name="episode_summary",
        flow=summary_flow,
        reasoners=(summary_reasoner,),
        capabilities=CapabilityManifest.from_file("summary-capabilities.yaml"),
        lane="summary",
        eval_packages=("prompts/episode_summary.ctx",),
        snapshot=memory_tools_snapshot,
        snapshot_source=load_live_memory_tools_snapshot,
    ),
])
```

For `julep plan`, `apply`, and application-level `status`, each
`snapshot_source` receives a read-only mapping made from the selected
environment's `[vars]` followed by `[worker_environment]` (worker values win on
duplicate names). Secret-backed worker variables are intentionally absent:
`worker_secret_environment` contains Kubernetes Secret references, not values,
and those values exist only in the worker at runtime. The callback must return
an `McpSnapshot`; pass any credential needed for schema discovery through a
non-secret control-plane mechanism rather than expecting a Secret value here.

Point `[tool.julep].application` at that object with a `module:attribute` value.
Each deployable environment also names the worker's explicit context factory;
ordinary and Secret-backed worker environment can be reconciled with the lane:

```toml
[tool.julep.env.staging]
temporal_address = "temporal-frontend.temporal.svc.cluster.local:7233"
release_store = "s3://julep-releases/julep"
worker_image = "registry.example/memory@sha256:<digest>"
worker_context_factory = "memory.worker:build_context"
worker_service_account = "julep-worker"
worker_priority_class = "julep-model-worker"
payload_encryption_secret = "temporal-payload-codec"

[tool.julep.env.staging.worker_environment]
MEMORY_TOOLS_MCP_URL = "http://memory-tools/mcp-internal"
JULEP_BUNDLE_ALLOWED_SIGNERS = "<64-hex-ed25519-public-key>"

[tool.julep.env.staging.worker_secret_environment.MEMORY_TOOLS_JWT_PRIVATE_KEY]
secret_name = "memory-tools-jwt"
key = "private-key"
```

`payload_encryption_secret` is required for application releases and names an
existing Kubernetes Secret in `kubernetes_namespace` with `keyring` and
`active-key-id` entries. The PriorityClass is optional: set
`worker_priority_class` only when shared cluster infrastructure provisions it
(the EKS demo does); omit it on ordinary clusters.

`julep plan --env staging` reports artifact, MCP-schema, Helm/KEDA, and runtime
drift; `julep apply --env staging` publishes an immutable S3-artifact store release and
reconciles one digest-pinned Helm release per lane and immutable release on a
release-specific task queue, without changing traffic;
`julep status --env staging` aggregates the release and live lane state. That
application-level status path is selected only when `[tool.julep].application` is
configured and no selector or `--exclude` is supplied; selected status queries
continue to inspect the legacy per-agent deploy ledger.

Application publishing requires a 64-hex Ed25519 seed (or a file containing
one) in `JULEP_BUNDLE_SIGNING_KEY`. In production, set the corresponding 64-hex
public key in the non-secret `JULEP_BUNDLE_ALLOWED_SIGNERS` worker environment;
`apply` rejects a configured allow-list that does not contain the publishing
key. Read-only `plan` and application-level `status` need that public allow-list
(or the private key as a local fallback). Install `julep[store,temporal]` for
S3 publication and Temporal workers, plus any pipeline-specific extras. The
control-plane host also needs authenticated `helm`, `kubectl`, and `temporal`
CLIs; `apply --publish-only` skips Helm reconciliation.

`julep worker` runs continuously from its environment contract. A positive
`--smoke-test-seconds N` verifies Temporal connectivity, polls the configured
queue for `N` seconds, drains, and exits; the default `0` keeps serving.

---

## Extras

The base install is authoring + compile only (PyYAML). Optional extras add runtime surfaces:

| Extra | `pip install --pre 'julep[...]'` | Adds |
|---|---|---|
| `temporal` | `julep[temporal]` | durable execution on Temporal (workflows, activities, worker, client helpers) |
| `dbos` | `julep[dbos]` | durable execution on DBOS / Postgres (steps, flow workflow, chaining runner) |
| `http` | `julep[http]` | native HTTP tool calls from the `callTool` activity |
| `cma` | `julep[cma]` | httpx transport for the CMA HTTP adapter |
| `mcp` | `julep[mcp]` | official MCP SDK, httpx, PyJWT, and cryptography for MCP references, snapshots, calls, and auth |
| `server` | `julep[server]` | FastAPI/Uvicorn control plane, SSE, Postgres store, Temporal gateway, cryptography, and httpx |
| `dotctx` | `julep[dotctx]` | rich `.ctx` layout (Jinja2 templates compiled into registered renderers); native `!? $env.get(...)` settings support needs no extra |
| `providers` | `julep[providers]` | multi-provider `LlmCaller` via any-llm (pair with provider extras) |
| `otel` | `julep[otel]` | OpenTelemetry span export of the projection |
| `langfuse` | `julep[langfuse]` | Langfuse OTLP/HTTP export of the projection |
| `store` | `julep[store]` | artifact distribution stores + bundle signing primitives |
| `wasm` | `julep[wasm]` | sandboxed wasm execution of bundle-sourced pures (wasmtime host) |

`julep.HAVE_TEMPORAL` reports whether the runtime is available; the package imports and compiles flows either way.

---

## Looking for Julep v1?

Julep v1 (the agents API platform) is preserved on the [`v1` branch](https://github.com/julep-ai/julep/tree/v1) and its docs at v1.docs.julep.ai. Julep 3 is a ground-up rewrite; there is no migration path — v1 and v3 are different products.

---

## License

This project is licensed under Apache-2.0. See [LICENSE](LICENSE).

---

## File: cookbooks/README.md

# Julep AI - Notebook Overview

Welcome to the **Julep AI Notebook Collection**! This directory contains a set of Jupyter notebooks designed to showcase various AI and automation tasks using Julep's features.

Each notebook explores a unique use case, demonstrating different aspects of Julep's capabilities. Below is a quick overview of the notebooks, their purpose, and a link to run each of them on Google Colab.


## Basics Series

| **Notebook Name** | **Colab Link** | **Description** | **Implemented** |
|------------------ |--------------- |----------------- |----------------- |
| `01-Hello-Agent.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/basics/01-Hello-Agent.ipynb) | Create a simple agent and chat with it | Yes |
| `02-Simple-Task.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/basics/02-Simple-Task.ipynb) | Define and run a basic task | Yes |
| `03-Adding-Tools.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/basics/03-Adding-Tools.ipynb) | Attach a tool to the agent | Yes |
| `04-Parallel-Steps.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/basics/04-Parallel-Steps.ipynb) | Execute steps in parallel | Yes |
| `05-RAG-and-Docs.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/basics/05-RAG-and-Docs.ipynb) | Use documents for RAG style responses | Yes |

## Advanced Examples

| **Notebook Name** | **Colab Link** | **Description** | **Implemented** |
|------------------ |--------------- |----------------- |----------------- |
| `00-Devfest-Email-Assistant.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/00-Devfest-Email-Assistant.ipynb) | Email assistant for managing DevFest communications | Yes |
| `01-website-crawler.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/01-website-crawler.ipynb) | Implements a web crawler using a spider to extract website content | Yes |
| `02-sarcastic-news-headline-generator.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/02-sarcastic-news-headline-generator.ipynb) | Generates sarcastic news headlines using a Brave Search Tool | Yes |
| `03-trip-planning-assistant.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/03-trip-planning-assistant.ipynb) | Plans trips using weather data and location information | Yes |
| `04-hook-generator-trending-reels.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/04-hook-generator-trending-reels.ipynb) | Generates engaging hooks for trending social media reels | Yes |
| `05-video-processing-with-natural-language.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/05-video-processing-with-natural-language.ipynb) | Processes videos using natural language commands | Yes |
| `06-browser-use.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/06-browser-use.ipynb) | Demonstrates browser automation capabilities | Yes |
| `07-personalized-research-assistant.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/07-personalized-research-assistant.ipynb) | Demonstrates personalized research assistant capabilities | Yes |
| `08-rag-chatbot.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/08-rag-chatbot.ipynb) | Demonstrates RAG chatbot capabilities | Yes |
| `09-companion-agent.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/09-companion-agent.ipynb) | Demonstrates companion agent capabilities like story generation, user persona management, and more | Yes |
| `10-reel-generator.ipynb` | [Colab Link](https://colab.research.google.com/github/julep-ai/julep/blob/dev/cookbooks/advanced/10-reel-generator.ipynb) | Demonstrates reel generator capabilities | Yes |
## Potential Cookbooks for Contributors

We welcome contributions to expand our cookbook collection. Here are some ideas for new cookbooks that showcase various Julep features and use cases:

| **Potential Cookbook Name** | **Description** | **Key Features** |
|---------------------------- |----------------- |------------------|
| Daily News Aggregator | Collects and summarizes news articles, emails summaries to subscribers | Scheduled tasks, Email integration, Content summarization |
| Social Media Monitoring System | Monitors social platforms for keywords and sends alerts | API integration, Real-time monitoring, Alert system |
| Weather-Based Notification Service | Checks weather forecasts and notifies users of severe conditions | Weather API integration, Conditional alerts, Scheduling |
| Automated Financial Report Generator | Gathers financial data and generates reports for stakeholders | Data aggregation, Report generation, Scheduling |
| Task Management and Reminder System | Manages user tasks, sets reminders, and sends notifications | User management, Scheduling, Notifications |
| Interactive Story Generator | Creates stories based on user input with corresponding images | Natural language processing, Image generation, User interaction |
| Automated Meeting Scheduler | Finds optimal meeting times and manages calendar entries | Calendar integration, Conflict resolution, Invitations |
| Email Categorization and Response | Categorizes incoming emails and sends automated responses | Email processing, Content categorization, Automated responses |
| E-commerce Order Processing | Handles order placements, inventory, and shipment tracking | Workflow automation, Inventory management, Notifications |
| Content Moderation System | Reviews and classifies user-generated content | Content analysis, Classification, Moderation actions |
| Personalized Learning Assistant | Provides tailored learning materials and tracks progress | Personalization, Progress tracking, Content recommendation |
| Automated Backup and Recovery | Regularly backs up data and initiates recovery procedures | Scheduled tasks, Error handling, Data management |
| Smart Home Automation Workflow | Manages smart home devices based on user commands and conditions | IoT integration, Conditional logic, User interaction |
| Inventory Management System | Tracks inventory levels and automates reordering | Stock management, Predictive analysis, Automated ordering |
| Event-Driven Notification System | Triggers notifications based on specific events or thresholds | Event monitoring, Conditional alerts, Multi-channel notifications |
| Data Cleaning and Transformation | Cleans and transforms raw data for analysis | Data processing, ETL operations, Quality assurance |
| Project Management Assistant | Breaks down projects into tasks and tracks progress | Task decomposition, Progress monitoring, Reporting |
| Parallel Data Processing Pipeline | Processes large datasets in parallel and aggregates results | Parallel execution, Data aggregation, Scalable processing |
| Dynamic Content Recommendation | Analyzes user behavior and recommends personalized content | User profiling, Content analysis, Personalized recommendations |
| Compliance Monitoring System | Monitors activities for regulatory compliance and generates reports | Rule-based monitoring, Violation detection, Compliance reporting |
| Intelligent Resume Screening | Evaluates resumes based on criteria and forwards qualified candidates | Document analysis, Candidate scoring, Automated screening |
| Automated Code Review Pipeline | Reviews code commits, runs tests, and manages deployments | Code analysis, Automated testing, Deployment management |
| Personal Finance Tracker | Tracks expenses, analyzes patterns, and provides financial advice | Financial data analysis, Pattern recognition, Personalized advice |
| Automated Content Publishing | Schedules and publishes content across various platforms | Content management, Multi-platform publishing, Scheduling |
| AI-Powered Personal Assistant | Manages personal tasks, schedules, and provides information | Task management, Scheduling, Information retrieval |
| Bug Tracking and Reporting | Monitors repositories, categorizes issues, and assigns to developers | Issue tracking, Categorization, Automated assignment |
| Multi-Stage Data Validation | Validates data through multiple stages with different rules | Data validation, Multi-step processing, Error handling |
| Document Summarization and Archiving | Summarizes documents and archives them for easy retrieval | Text summarization, Document classification, Archiving |
| Real-Time Stock Market Analyzer | Analyzes market data and alerts users about significant changes | Real-time data processing, Financial analysis, Alert system |
| Webinar Management System | Schedules webinars, manages participants, and handles follow-ups | Event scheduling, Participant management, Automated follow-ups |
| Smart Content Filtering | Filters and recommends content based on user preferences | Content analysis, User profiling, Recommendation system |
| Automated Translation Workflow | Translates content into multiple languages and localizes it | Language translation, Localization, Content management |
| AI-Driven Survey Analysis | Analyzes survey responses and generates insight reports | Survey processing, Sentiment analysis, Report generation |
| Compliance Documentation Generator | Creates compliance documents based on regulatory standards | Document generation, Compliance checking, Template management |
| Task Prioritization and Allocation | Prioritizes tasks and allocates them to team members | Task analysis, Resource allocation, Team management |
| Webinar Feedback Analyzer | Collects and analyzes feedback from webinar participants | Feedback collection, Sentiment analysis, Improvement suggestions |
| Health and Fitness Tracker | Tracks health metrics and provides personalized fitness recommendations | Health data analysis, Personalized recommendations, Progress tracking |
| Incident Response System | Detects incidents, initiates response workflows, and notifies personnel | Incident detection, Workflow automation, Alert system |
| Content Optimization Workflow | Analyzes content performance and optimizes for better engagement | Performance analysis, Content optimization, A/B testing |
| Legal Document Processor | Extracts key information from legal documents and ensures compliance | Document analysis, Information extraction, Compliance checking |
| Job Application Tracker | Tracks job applications and provides application improvement suggestions | Application tracking, Status updates, Improvement recommendations |
| Content Rescheduling System | Monitors content performance and reschedules for better visibility | Performance monitoring, Content scheduling, Optimization |
| AI-Powered Investment Advisor | Analyzes financial data and suggests investment opportunities | Financial analysis, Risk assessment, Investment recommendations |
| Intelligent Document Version Control | Manages document versions and notifies users about updates | Version control, Change tracking, Notification system |
| Marketing Campaign Manager | Creates, schedules, and optimizes marketing campaigns | Campaign planning, Performance tracking, Optimization strategies |
| Competitive Analysis Workflow | Gathers data on competitors and generates analysis reports | Data collection, Comparative analysis, Report generation |
| Health Monitoring and Alerting | Monitors health metrics and alerts users and healthcare providers | Health data analysis, Anomaly detection, Alert system |
| Travel Itinerary Planner | Plans travel itineraries based on preferences and conditions | Trip planning, Preference matching, Dynamic scheduling |
| AI-Powered Personal Diary | Helps maintain a diary and provides insights into emotions and growth | Natural language processing, Sentiment analysis, Personal growth tracking |
| Language Learning Tutor | Provides exercises and personalized feedback for language learners | Language processing, Progress tracking, Personalized lessons |
| Knowledge Base Maintenance | Updates and maintains a knowledge base with new information | Information extraction, Knowledge management, Consistency checking |
| Feedback Loop for Improvement | Collects user feedback, analyzes it, and implements improvements | Feedback analysis, Improvement tracking, Stakeholder notifications |
| Grant Application Processor | Reviews grant applications, evaluates eligibility, and notifies applicants | Application processing, Eligibility checking, Automated notifications |
| AI-Powered Resume Builder | Assists in building resumes and provides improvement suggestions | Resume analysis, Content generation, Personalized recommendations |
| Vendor Management System | Manages vendor information, monitors performance, and handles communications | Vendor tracking, Performance monitoring, Communication automation |
| Meeting Minutes Recorder | Records meetings, transcribes audio, and distributes summaries | Audio transcription, Summary generation, Automated distribution |
| Personal Shopping Assistant | Finds products based on preferences and notifies about deals | Product matching, Price comparison, Deal notifications |
| Environmental Monitoring Reporter | Monitors environmental data and generates reports for stakeholders | Data monitoring, Anomaly detection, Report generation |
| Data Sync and Integration Workflow | Syncs data between platforms and handles conflicts | Data synchronization, Conflict resolution, Integration management |
| Competitive Pricing Strategy | Analyzes competitor pricing and adjusts prices dynamically | Price analysis, Dynamic pricing, Market monitoring |
| User Onboarding Workflow | Manages the user onboarding process and sets up accounts | User registration, Account setup, Welcome communications |
| Content Curation and Distribution | Curates content based on interests and tracks engagement | Content curation, Distribution scheduling, Engagement tracking |

We encourage contributors to choose from these ideas or propose their own to showcase Julep's capabilities in solving real-world problems.

## Julep Features Demonstrated

These notebooks showcase various features of Julep. Here's an overview of the key features you can explore:

1. **Agent Management**
   - Creating and updating agents
   - Configuring agent settings (name, model, about)

2. **Task Definition and Execution**
   - Creating multi-step tasks
   - Executing tasks with specific inputs
   - Various step types (Prompt, Tool Call, Evaluate, Conditional Logic, Loops, etc.)

3. **Tool Integration**
   - Adding custom tools to agents
   - Integrating external APIs (e.g., web search, image generation)

4. **Session Management**
   - Creating and managing persistent sessions
   - Handling context overflow

5. **User Management**
   - Creating and managing users
   - Associating users with sessions

6. **Document Management**
   - Uploading and managing documents
   - Document search functionality

7. **Chat Functionality**
   - Interacting with agents through chat sessions

8. **Execution Monitoring**
   - Streaming execution progress
   - Monitoring task lifecycle

9. **Authentication**
    - API Key authentication

We encourage contributors to create new notebooks that demonstrate these features in various combinations and use cases.

### Additional Information

For more details about the tasks or if you have any questions, please don't hesitate to contact the author:

**Author:** Julep AI  
**Contact:** [hey@julep.ai](mailto:hey@julep.ai) or [Discord](https://discord.com/invite/JTSBGRZrzj)

---

If you have feedback or would like to contribute to the notebooks, feel free to open an issue(s) in the [repository](https://github.com/julep-ai/julep).

---

## File: documentation/advanced/agentic-patterns.mdx

---
title: 'Agentic Patterns'
icon: 'sitemap'
---

## Overview

This guide covers common patterns and best practices for building effective Julep agents, inspired by a blog written by Anthropic on [Building effective agents](https://www.anthropic.com/research/building-effective-agents).

## Core Workflow Patterns

### 1. Prompt Chaining

Break tasks into sequential steps, where each step’s output feeds the next. Can be used for:
- Content generation and subsequent checks
- Translation/localization in multiple stages
- Ensuring quality between discrete transformations



**Example implementation:**
```yaml
main:
# Step 1: Generate initial content
- prompt:
   role: system
   content: >-
      $ f'''Generate marketing copy for product X based on the following:
      target_audience: {_.audience}
      product_features: {_.features}
      keywords: {_.seo_keywords}'''
   unwrap: true

# Step 2: Quality check gate
- evaluate:
   quality_check: $ _.content

# Step 3: Translation
- prompt:
   role: system
   content: Translate the approved content to Spanish
   unwrap: true
```

### 2. Routing Pattern

Act as a “traffic controller” by detecting request types and sending them to the correct handler. Ideal when inputs are diverse or require specialized expertise.

Steps generally include:
1. Classification of incoming data
2. Routing to handler modules
3. Specialized processing
4. (Optional) Aggregation of results



**Example implementation:**
```yaml [expandable]
main:
# Classification step
- prompt:
   role: system
   content: Classify the input query type
   unwrap: true

# Route based on classification
- switch:
   - case: $ _.classification == "technical_support"
      then:
         - tool: handle_technical
         arguments:
            ...
   - case: $ _.classification == "billing"
      then:
         - tool: handle_billing
         arguments:
            ...
   - case: $ _.classification == "general"
      then:
         - tool: handle_general
         arguments:
            ...
```

### 3. Parallelization Pattern

Execute subtasks concurrently by either dividing the workload (sectioning) or collecting multiple perspectives (voting).

Keys to consider:
• Parallel processes for performance or redundancy
• Syncing results and handling errors
• Aggregating diverse outputs



**Example implementations:**

1. Sectioning:
```yaml [expandable]
tools:
- name: aggregate_results
  type: ... # depends on the specific needs

# Custom workflow to run a subtask
run_subtask:
- ....

# Main workflow
main:
- prompt:
   role: system
   content: >
      $ f'''Break this task into multiple subtasks.
      Here is the task: {_.task}'''
   unwrap: true

- over: $ _.subtasks
   do:
      - workflow: run_subtask
      arguments:
         ...
- tool: aggregate_results
  arguments:
    results: $ _
```

2. Voting:
```yaml [expandable]
tools:
- name: perform_voting
  type: ... # depends on the specific needs

# Custom workflow to run a subtask
run_subtask:
- ....

# Main workflow
main:
- over: $ _.main_tasks
   do:
      - workflow: run_subtask # Run the same task multiple times (given that the `run_subtask` workflow is non-deterministic)
      arguments:
         ...
- tool: perform_voting
  arguments:
    results: $ _

- evaluate:
   final_result: $ _
```

### 4. Orchestrator-Workers Pattern

Use a central “orchestrator” that delegates subtasks to multiple “worker” agents and integrates their outputs. Best for:
- Large or dynamic multi-step tasks
- Coordinating various specialized capabilities
- Flexible task distribution



**Example implementation:**
```yaml
main:
# Orchestrator planning
- prompt:
   role: system
   content: $ f'''Break down the task into subtasks. Here is the task: {_.task}'''
   unwrap: true
# Worker delegation
- foreach:
   in: $ _.subtasks
   do:
      tool: assign_worker
      arguments:
         task: $ _
```

### 5. Evaluator-Optimizer Pattern

Create iterative feedback loops to refine outputs until they meet preset criteria. Suitable for:
• Content refinement
• Code reviews
• Detailed document enhancements

General flow:
1. Generate an initial result
2. Evaluate against criteria
3. Provide improvement feedback
4. Optimize/retry until goals are met



**Example implementation:**
```yaml [expandable]
tools:
- name: score_content
  type: function
  function:
    parameters:
      type: object
      properties:
        content:
          type: string
# Subworkflow to evaluate content
evaluate_content:
- tool: score_content
  arguments:
    content: $ _.content
- if: $ _.score < 0.5 # If the content does not meet the criteria, improve it
  then:
    - workflow: improve_content
      arguments:
        content: $ steps[0].input.content # steps[0].input is the main input of this workflow
        feedback: $ _.feedback # _ is the output of the score_content tool call
  else:
    evaluate:
      final_content: $ steps[0].input.content

# Subworkflow to improve content
improve_content:
- prompt:
    role: system
    content: $ f'''Improve the content based on the feedback. Here is the feedback: {_.feedback}'''
  unwrap: true
- workflow: evaluate_content
  arguments:
    content: $ _


main:
# Initial generation
- prompt:
   role: system
   content: $ f'''Generate initial content. Here is the task: {_.task}'''
   unwrap: true

# Evaluation loop
- loop:
   while: $ not _.meets_criteria
   do:
      - tool: evaluate_content
      - tool: improve_content
```

**Explanation:**

1. The `evaluate_content` subworkflow:
   - Takes content as input and scores it using a scoring tool
   - If the score is below 0.5, it triggers the improvement workflow
   - Uses a special variable (`_`) to manage content and feedback between workflows
   - Returns the final content once quality criteria are met

2. The `improve_content` subworkflow:
   - Receives content and feedback from the evaluation
   - Uses an LLM to improve the content based on specific feedback
   - Automatically triggers another evaluation cycle by calling evaluate_content

The main workflow ties these together by:
- Generating initial content from a task description
- Running a continuous loop that alternates between evaluation and improvement
- Only completing when content meets the defined quality criteria

This creates a powerful feedback loop where content is repeatedly refined based on specific feedback until it reaches the desired quality level. The pattern is particularly useful for tasks requiring high accuracy or quality, such as content generation, code review, or document analysis.

## Best Practices

<CardGroup cols={3}>
    <Card title="Start Simple" icon="minimize">
        
            <li>**1. Minimal Steps**: Use minimal steps and only add complexity when it clearly improves results.</li>
        
    </Card>
    <Card title="Thoughtful Tool Design" icon="wrench">
        
            <li>**1. Documentation**: Provide clear documentation, examples, and usage guidelines for each tool.</li>
        
    </Card>
    <Card title="Error Handling" icon="shield-check">
        
            <li>**1. Guardrails**: Include feedback loops, define stopping conditions, and surface potential issues.</li>
        
    </Card>
    <Card title="Testing" icon="vial">
        
            <li>**1. Validation**: Thoroughly test in controlled environments and measure against success criteria.</li>
        
    </Card>
    <Card title="Human Oversight" icon="user-check">
        
            <li>**1. Checkpoints**: Establish checkpoints for approval, ensure transparency, and maintain easy-to-audit workflows.</li>
        
    </Card>
</CardGroup>

## Conclusion

These patterns represent proven approaches from production implementations. Choose and adapt them based on your specific use case requirements and complexity needs.

## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/architecture-deep-dive.mdx

---
title: 'Architecture Deep Dive'
icon: 'brain'
---

## Overview

Think of Julep as a platform that combines both client-side and server-side components to help you build advanced AI agents. Here's a mental model to help you understand it:

1. Your Application Code
   - Use the Julep SDK in your application to define agents, tasks, and workflows
   - SDK provides functions and classes for easy setup and management of components

2. Julep Backend Service
   - SDK communicates with Julep backend over the network
   - Backend handles task execution, session state, document storage, and workflow orchestration

3. Integration with Tools and APIs
   - Integrate external tools and services within your workflows
   - Backend facilitates integrations for web searches, database access, third-party API calls, and more

To help you visualize this, here's a diagram:
<Frame caption="Julep Architecture Overview">
  
</Frame>
<Frame caption="System Architecture">
  
</Frame>


## Core Components

<CardGroup cols={2}>
  <Card title="Agent" icon="robot">
    The main orchestrator of your application, backed by foundation models like GPT4 or Claude.
  </Card>

  <Card title="User" icon="user">
    Users can be associated with sessions and are used to scope memories formed by agents.
  </Card>

  <Card title="Session" icon="messages">
    The main workhorse for Julep apps.
  </Card>

  <Card title="Tool" icon="wrench">
    Programmatic interfaces that foundation models can "call" with inputs.
  </Card>

  <Card title="Doc" icon="file-lines">
    Collections of text snippets indexed into a vector database.
  </Card>

  <Card title="Task & Execution" icon="list-check">
    Github Actions-style workflows for complex operations.
  </Card>

  <Card title="Secret" icon="key">
    Encrypted key-value pairs for securely storing sensitive information like API keys and credentials.
  </Card>
</CardGroup>

## Infrastructure Components

<CardGroup cols={4}>
  <Card title="Document Store" icon="database">
    The document store provides a vector database for semantic search along with a document management system. It supports various file types and handles automatic indexing and retrieval of documents.
  </Card>

  <Card title="Task Execution Engine" icon="gears">
    The task execution engine handles distributed task processing, state management, error handling with retries, and supports parallel execution of tasks.
  </Card>

  <Card title="Secrets Store" icon="key">
    The secrets store provides encrypted storage for sensitive information like API keys, credentials, and tokens. It uses AES-256 encryption and developer-scoped access controls to securely manage confidential data.
  </Card>

  <Card title="API Layer" icon="code">
    The API layer provides RESTful API endpoints, SDK support, authentication and authorization capabilities, and handles rate limiting and quotas.
  </Card>
</CardGroup>

## Data Flow

<Frame caption="Data Flow Overview">
  
</Frame>


  The data flow in Julep is divided into three main components, each handling specific aspects of request processing and response generation.


<Steps>
  <Step title="Client Interaction" icon="arrow-right-to-bracket">
    - SDK or API calls initiate requests
    - Authentication and validation
    - Request routing
  </Step>

  <Step title="Task Processing" icon="gears">
    - Task decomposition
    - Step execution
    - State management
    - Tool integration
  </Step>

  <Step title="Response Handling" icon="arrow-right-from-bracket">
    
    - Result aggregation
    - Error handling
    - Client notification
    - State persistence
  </Step>
</Steps>

## Security

<CardGroup cols={3}>
  <Card title="Authentication" icon="lock">
    <ol>
      <li>**1.** API key-based access</li>
      <li>**2.** Role-based permissions</li>
      <li>**3.** Session management</li>
      <li>**4.** Token validation</li>
    </ol>
  </Card>

  <Card title="Data Protection" icon="shield">
    <ol>
      <li>**1.** Encryption at rest</li>
      <li>**2.** Secure communication</li>
      <li>**3.** Data isolation</li>
      <li>**4.** Access controls</li>
      <li>**5.** Encrypted secrets</li>
    </ol>
  </Card>

  <Card title="Monitoring" icon="chart-line">
    <ol>
      <li>**1.** Audit logging</li>
      <li>**2.** Performance metrics</li>
      <li>**3.** Error tracking</li>
      <li>**4.** Usage analytics</li>
    </ol>
  </Card>
</CardGroup>

## Conclusion

The modular design enables you to customize and extend functionality as needed, while the security-first approach ensures your data and operations remain protected. Whether you're building a simple chatbot or a complex AI workflow, this architecture provides the foundation you need.

## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/chat.mdx

---
title: 'Chat Features in Julep'
icon: 'message-dots'
---

## Overview

Julep provides a robust chat system with various features for dynamic interaction with agents. Here's an overview of the key components and functionalities.

## Features

<Steps>
  <Step title="Tool Integration">
    The chat API allows for the use of tools, enabling the agent to perform actions or retrieve information during the conversation.
  </Step>
  <Step title="Multi-agent Sessions">
    You can specify different agents within the same session using the `agent` parameter in the chat settings.
  </Step>
  <Step title="Response Formatting">
    Control the output format, including options for JSON responses with specific schemas.
  </Step>
  <Step title="Memory and Recall">
    Configure how the session accesses and stores conversation history and memories.
  </Step>
  <Step title="Document References">
    The API returns information about documents referenced during the interaction, useful for providing citations or sources.
  </Step>
</Steps>


  <h4>Prerequisites for Using Chat API</h4>
  
  
    <li>**Session Creation**: Before using the chat API, you must create a session first. Learn more about the session object on the [Session](/concepts/sessions) page.</li>
    <li>**Document (RAG) Integration**: To use Document (RAG) capabilities with the chat API, create a session with the `recall_options` parameter configured with appropriate search parameters. For details on configuring `recall_options`, see the [Session: Recall Options](/concepts/sessions#recall-options-rag-search) documentation.</li>
  


## Input Structure

- **Messages**: An array of input messages representing the conversation so far.
- **Tools**: (Advanced) Additional tools provided for this specific interaction.
- **Tool Choice**: Specifies which tool the agent should use.
- **Memory Access**: Controls how the session accesses history and memories.(`recall` parameter)
- **Additional Parameters**: Various parameters to control the behavior of the chat. You can find more details in the [Additional Parameters](#additional-parameters) section.

Here's an example of how a typical message object might be structured in a chat interaction:

<Accordion title="Message Object Structure">
  ```python Python
    """
    Attributes for the Message object:
        role (Literal["user", "assistant", "system", "tool"]): The role of the message sender.
        tool_call_id (str | None): Optional identifier for a tool call associated with this message.
        content (Annotated[str | list[str] | list[Content | ContentModel7 | ContentModel] | None, Field(...)]): The main content of the message, which can be a string, a list of strings, or a list of content models.
        name (str | None): Optional name associated with the message.
        continue_ (Annotated[StrictBool | None, Field(alias="continue")]): Flag to indicate whether to continue the conversation without interruption.
        tool_calls (list[ChosenFunctionCall | ChosenComputer20241022 | ChosenTextEditor20241022 | ChosenBash20241022] | None): List of tool calls generated during the message creation, if any.
    """
    # Example of a simple message structure
    messages = [{"role": "user", "content": "Your query here"}]
  ```
  This object represents a message in the chat system, detailing the structure and types of data it can hold.
</Accordion>

## Additional Parameters

| Parameter           | Type    | Description                                      | Default  |
|---------------------|---------|--------------------------------------------------|----------|
| `stream`            | `bool`  | Indicates if the server should stream the response as it's generated. | `False` |
| `stop`              | `list[str]` | Up to 4 sequences where the API will stop generating further tokens. | `[]` |
| `seed`              | `int`   | If specified, the system will make a best effort to sample deterministically for that particular seed value. | `None` |
| `max_tokens`        | `int`   | The maximum number of tokens to generate in the chat completion. | `None` |
| `logit_bias`        | `dict[str, float]`  | Modify the likelihood of specified tokens appearing in the completion. | `None` |
| `response_format`   | `str`   | Response format (set to `json_object` to restrict output to JSON). | `None` |
| `agent`             | `UUID`  | Agent ID of the agent to use for this interaction. (Only applicable for multi-agent sessions) | `None` |
| `repetition_penalty`| `float` | Number between 0 and 2.0. 1.0 is neutral and values larger than that penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. | `None` |
| `length_penalty`    | `float` | Number between 0 and 2.0. 1.0 is neutral and values larger than that penalize number of tokens generated. | `None` |
| `min_p`             | `float` | Minimum probability compared to leading token to be considered. | `None` |
| `frequency_penalty` | `float` | Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. | `None` |
| `presence_penalty`  | `float` | Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. | `None` |
| `temperature`       | `float` | What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. | `None` |
| `top_p`             | `float` | An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. | `1.0` |
| `recall`            | `bool` | Whether to use the document (RAG) search or not | `True` |
| `save`              | `bool` | Whether this interaction should be stored in the session history or not | `True` |
| `remember`          | `bool` | DISABLED: Whether this interaction should form new memories or not (will be enabled in a future release) | `False` |
| `model`             | `str` | The model to use for the chat completion. | `None` |

## Usage

Here's an example of how to use the chat API in Julep using the SDKs:


  To use the Chat endpint, you always have to create a session first.


<CodeGroup>
    ```python Python [expandable]
    # Create a session with custom recall options
    client.sessions.create(
        agent=agent.id,
        user=user.id,
        recall=True,
        recall_options={
            "mode": "hybrid", # or "vector", "text"
            "num_search_messages": 4, # number of messages to search for documents
            "max_query_length": 1000, # maximum query length
            "alpha": 0.7, # weight to apply to BM25 vs Vector search results (ranges from 0 to 1)
            "confidence": 0.6, # confidence cutoff level (ranges from -1 to 1)
            "limit": 10, # limit of documents to return
            "lang": "en-US", # language to be used for text-only search
            "metadata_filter": {}, # metadata filter to apply to the search
            "mmr_strength": 0, # MMR Strength (ranges from 0 to 1)
        }
    )

    # Chat in the session
    response = client.sessions.chat(
        session_id=session.id,
        messages=[
            {
                "role": "user",
                "content": "Tell me about Julep"
            }
        ],
        recall=True
    )
    print("Agent's response:", response.choices[0].message.content)
    print("Searched Documents:", response.docs)
    ```

    ```javascript Node.js [expandable]
    client.sessions.create({
        agent: agent.id,
        user: user.id,
        recall: true,
        recall_options: {
            mode: "hybrid", // or "vector", "text"
            num_search_messages: 4, // number of messages to search for documents
            max_query_length: 1000, // maximum query length
            alpha: 0.7, // weight to apply to BM25 vs Vector search results (ranges from 0 to 1)
            confidence: 0.6, // confidence cutoff level (ranges from -1 to 1)
            limit: 10, // limit of documents to return
            lang: "en-US", // language to be used for text-only search
            metadata_filter: {}, // metadata filter to apply to the search
            mmr_strength: 0, // MMR Strength (ranges from 0 to 1)
        }
    });

    // Chat in the session
    const response = await client.sessions.chat({
        session_id: session.id,
        messages: [
            {
                role: "user",
                content: "Tell me about Julep"
            }
        ],
        recall: true
    });
    ```
</CodeGroup>

To learn more about the Session object, check out the [Session](/concepts/sessions) page.

<Tip>
    Check out the [API reference](/api-reference/sessions/chat) or SDK reference ([Python](/sdks/python/reference#sessions) or [JavaScript](/sdks/nodejs/reference#sessions)) for more details on different operations you can perform on sessions.
</Tip>

## Response

<Tabs>
  <Tab title="Complete Response">
    - **Content-Type**: `application/json`
    - **Body**: A `MessageChatResponse` object containing the full generated message(s)
  </Tab>
  <Tab title="Streamed Response">
    - **Content-Type**: `text/event-stream`
    - **Body**: A stream of `ChatOutputChunk` objects
    <Warning>
      This feature is not implemented yet.
    </Warning>
  </Tab>
</Tabs>

Both types of responses include the following fields:

- `id`: The unique identifier for the chat response
- `choices`: An object of generated message completions containing:
    - `role`: The role of the message (e.g. "assistant", "user", etc.)
    - `id`: Unique identifier for the message
    - `content`: list of actual message content
    - `created_at`: Timestamp when the message was created
    - `name`: Optional name associated with the message
    - `tool_call_id`: Optional ID referencing a tool call
    - `tool_calls`: Optional list of tool calls made during message generation
  - `created_at`: When this resource was created as UTC date-time
  - `docs`: List of document references used for this request, intended for citation purposes
  - `jobs`: List of UUIDs for background jobs that may have been initiated as a result of this interaction
  - `usage`: Statistics on token usage for the completion request


## Finish Reasons

<CardGroup cols={2}>
  <Card title="stop" icon="stop">
    Natural stop point or provided stop sequence reached
  </Card>
  <Card title="length" icon="ruler">
    Maximum number of tokens specified in the request was reached
  </Card>
  <Card title="content_filter" icon="filter">
    Content was omitted due to a flag from content filters
  </Card>
  <Card title="tool_calls" icon="wrench">
    The model called a tool
  </Card>
</CardGroup>

## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/files.mdx

---
title: 'Files (Multimedia)'
icon: 'file-circle-plus'
---

## Overview

Julep’s Files feature supports uploading, storing, retrieving, and integrating files across Julep components. It handles various file types and formats.

## File Properties

Each file in Julep has the following properties:

```typescript
id: string; // Unique identifier
name: string; // Name of the file
content: string; // Base64 encoded content
created_at: string; // Creation timestamp
size: number; // File size in bytes
hash: string; // File hash for verification
description?: string; // Optional description
mime_type?: string; // Optional MIME type
```

## Basic Operations

### Creating Files

Here's how you can create files using the SDKs:

<CodeGroup>
    ```python Python
    from julep import Julep

    client = Julep()

    file = client.files.create(
        name="example.pdf",
        content="base64_encoded_content",
        description="Sample document",
        mime_type="application/pdf"
    )
    ```

    ```javascript Node.js
    import Julep from '@julep/sdk';
    const client = new Julep();
    const file = await client.files.create({
        name: "example.pdf",
        content: "base64_encoded_content",
        mime_type: "application/pdf"
    });
    ```
</CodeGroup>

### Retrieving Files

Here's how you can retrieve files using the SDKs:

<CodeGroup>
    ```python Python
    file = client.files.get("file_id")
    ```

    ```javascript Node.js
    const file = await client.files.get("file_id");
    ```
</CodeGroup>

### Deleting Files

<CodeGroup>
    ```python Python
    client.files.delete("file_id")
    ```

    ```javascript Node.js
    await client.files.delete("file_id");
    ```
</CodeGroup>

## API Reference

For complete API documentation, see [Files API Reference](https://dev.julep.ai/api/docs#tag/files).

## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/lifecycle.mdx

---
title: 'Execution Lifecycle'
icon: 'arrows-spin'
---

## Overview

Understanding the lifecycle of a Julep task is crucial for building effective workflows. 
Let's explore this through the lens of a [Trip Plan task](/tutorials/trip-planning) - a practical example that showcases key aspects of task execution.

The Trip Plan task is an ideal example because it demonstrates:
1. Parallel execution of workflow steps
2. Integration with multiple external APIs:
   - [Weather API](/integrations/communicationdata/weather) for current conditions
   - [Brave Search API](/integrations/search/brave) for attractions
3. Data aggregation from various sources
4. AI-powered personalization of results

Below is a visual representation of how this task flows through Julep's execution lifecycle:

<Frame caption="Lifecycle of the Trip Plan Task">
  
</Frame>

Let's examine each phase of the execution lifecycle using this task as our guide.


  This is a simplified representation of the execution lifecycle. In practice, Julep handles many more details and edge cases to ensure robust and efficient task execution.


<Note>
  Out here in this section, we will be focusing on the main workflow steps of the Trip Plan task and how these steps are executed in Julep.
</Note>

### 1. Input Schema

First, we define what inputs our task expects:

```yaml

input_schema:
    type: object
    properties:
        locations:
            type: array
            items:
                type: string
```


This schema specifies that our task expects an array of location strings (e.g., `["New York", "London", "Paris"]`).

### 2. Tools Configuration

Next, we define the external tools our task will use:

```yaml
- name: weather
  type: integration
  integration:
    provider: weather
    setup:
      openweathermap_api_key: {openweathermap_api_key}

- name: internet_search
  type: integration
  integration:
    provider: brave
    setup:
      brave_api_key: {brave_api_key}
```

We're using two integrations:
- The `weather` integration to fetch current weather conditions
- The `brave` search integration to find tourist attractions

### 3. Main Workflow Steps

#### Step 1: Fetch Weather Data

```yaml
- over: $ steps[0].input.locations
  map:
    tool: weather
    arguments:
      location: $ _
```

This step:
- Iterates over each location in the input array
- Calls the weather API for each location
- The `_` represents the current location in the iteration

#### Step 2: Search for Tourist Attractions

```yaml
- over: $ steps[0].input.locations
  map:
    tool: internet_search
    arguments:
      query: $ 'tourist attractions in ' + _
```


This step:
- Iterates over the locations again
- Searches for tourist attractions in each location
- Constructs a search query by concatenating "tourist attractions in " with the location

#### Step 3: Combine Data

```yaml
- evaluate:
    zipped: |-
      $ list(
        zip(
          steps[0].input.locations,
          [output['result'] for output in steps[0].output],
          steps[1].output
        )
      )
```


This step:
- Combines the data from previous steps into tuples
- Each tuple contains: (location, weather_data, attractions_data)
- Uses Python's `zip` function to align the data

#### Step 4: Generate Itineraries

```yaml [expandable]
- over: $ _['zipped']
  parallelism: 3
  # Inside the map step, each `_` represents the current element in the list
  # which is a tuple of (location, weather, attractions)
  map:
    prompt:
    - role: system
      content: >-
        $ f'''You are {agent.name}. Your task is to create a detailed itinerary
        for visiting tourist attractions in some locations.
        The user will give you the following information for each location:

        - The location
        - The current weather condition
        - The top tourist attractions'''
    - role: user
      content: >-
        $ f'''Location: {_[0]}
        Weather: {_[1]}
        Attractions: {_[2]}'''
    unwrap: true
```


This step:
- Processes up to 3 locations in parallel
- For each location tuple:
  - Sends a prompt to the AI model
  - Includes location, weather, and attraction data
  - Generates a personalized itinerary

#### Step 5: Format Final Output

```yaml
- evaluate:
    final_plan: |-
      $ '\\n---------------\\n'.join(activity for activity in _)
```


This step:
- Combines all itineraries into a single output
- Separates each itinerary with a divider

## Example Output

An example output when running this task with an input of `["New York", "London", "Paris", "Tokyo", "Sydney"]`:


Here's a detailed itinerary for visiting top tourist attractions in New York, considering the current weather conditions. 

### Day 1: Iconic Landmarks and Observation Decks
- **Morning:**
  - **Top of the Rock Observation Deck:** Start your day with a visit to the Top of the Rock Observation Deck at Rockefeller Plaza. The panoramic 360-degree views from the 70th floor are a must-see. Dress warmly as it feels like 5.2°C outside, and it’s quite windy.
  - **Link for more info:** [Tripadvisor - Top of the Rock](https://www.tripadvisor.com/Attractions-g60763-Activities-New_York_City_New_York.html)

- **Afternoon:**
  - **St. Patrick’s Cathedral:** Just a short walk from Rockefeller Plaza, explore the stunning architecture of St. Patrick’s Cathedral. The overcast skies will provide a dramatic backdrop for photos.
  - **Fifth Avenue:** Enjoy a leisurely stroll along Fifth Avenue, visiting iconic stores and landmarks.

- **Evening:**
  - **Times Square:** Experience the vibrant lights and energy of Times Square. The overcast clouds might enhance the brightness of the neon lights.

### Day 2: Culture and History
- **Morning:**
  - **The Museum of Modern Art (MoMA):** Spend your morning exploring MoMA’s vast collection of modern and contemporary art. This indoor activity is perfect for a cloudy day.

- **Afternoon:**
  - **Central Park:** Head to Central Park for a refreshing walk. With 100% cloud cover, it's a great day to explore the park without the harsh sun. Consider visiting the Central Park Zoo or taking a guided tour.

- **Evening:**
  - **Broadway Show:** End your day with a Broadway show. It’s an ideal indoor activity to avoid the chilly weather outside. Book tickets in advance for popular shows.

### Day 3: Historical and Educational
- **Morning:**
  - **Statue of Liberty and Ellis Island:** Take a ferry to visit these iconic sites. Dress warmly for the ferry ride. The cloud cover will provide a unique perspective for photos.

- **Afternoon:**
  - **9/11 Memorial and Museum:** Spend your afternoon reflecting at the 9/11 Memorial and exploring the museum exhibits.

- **Evening:**
  - **Brooklyn Bridge:** Walk across the Brooklyn Bridge and enjoy the city skyline. With the wind speed at 5.81 m/s, be prepared for breezy conditions.

### Additional Tips:
- **Clothing:** Wear layers to keep warm, as the temperature feels colder than it actually is.
- **Dining:** New York offers a plethora of dining options. Consider trying some local favorites like a classic New York bagel or pizza.
- **Transportation:** Utilize the subway for efficient travel across the city. Taxis and ride-sharing services are also readily available.

For more details on attractions and guided tours, you can visit [USA Guided Tours](https://usaguidedtours.com/nyc/attraction/) and [I Love NY](https://www.iloveny.com/places-to-go/new-york-city/attractions/). 

Enjoy your trip to New York City!
---------------
**Day 1: Exploring Iconic London Landmarks**

**Morning:**
1. **Buckingham Palace**
   - Start your day early with a visit to Buckingham Palace. Arrive by 9:30 AM to catch the Changing of the Guard ceremony, which typically starts at 11:00 AM. Enjoy the majestic architecture and the surrounding gardens.
   - Weather Tip: With the overcast clouds, it might feel chilly, so dress warmly and bring an umbrella just in case.

**Midday:**
2. **Westminster Abbey**
   - Head towards Westminster Abbey, a short walk from Buckingham Palace. This historic church has been the site of many significant events, including royal weddings and coronations. Spend about 1.5 hours exploring.

3. **Lunch at Borough Market**
   - Take a tube or walk to Borough Market for a variety of food options. It's a great place to warm up with some hot street food and explore the diverse culinary offerings.

**Afternoon:**
4. **London Eye**
   - After lunch, head to the London Eye. The overcast sky might not offer the clearest views, but the experience is still worthwhile. Pre-book your tickets to avoid long lines and enjoy a 30-minute ride on this iconic Ferris wheel.

**Evening:**
5. **The Globe Theatre**
   - As the day winds down, visit Shakespeare's Globe Theatre. If there's a performance, consider attending or simply take a guided tour to learn about the history of this famous theater.

**Day 2: Museums and Cultural Exploration**

**Morning:**
1. **The British Museum**
   - Start your second day at the British Museum. Spend a few hours exploring the vast collection of art and antiquities. Highlights include the Rosetta Stone and the Elgin Marbles.

**Midday:**
2. **Lunch near Covent Garden**
   - Head to Covent Garden for lunch. This area is bustling with restaurants and cafes, perfect for a cozy indoor meal.

**Afternoon:**
3. **The Tower of London**
   - After lunch, make your way to the Tower of London. Delve into England's rich history and see the Crown Jewels. Allocate about 2-3 hours for this visit.

**Evening:**
4. **Tower Bridge**
   - Conclude your day with a walk across Tower Bridge. The views of the Thames River and the cityscape are beautiful, even on a cloudy evening.

**Day 3: Leisure and Local Experiences**

**Morning:**
1. **Natural History Museum**
   - Begin your last day at the Natural History Museum. It's a family-friendly museum with fascinating exhibits, including dinosaur skeletons and a model of a blue whale.

**Midday:**
2. **Lunch at South Kensington**
   - Enjoy a relaxed lunch in South Kensington. There are plenty of options, from casual cafes to high-end dining.

**Afternoon:**
3. **Hyde Park**
   - Spend your afternoon strolling through Hyde Park. Visit the Serpentine Galleries if you're interested in contemporary art. The park's natural beauty is a peaceful retreat amidst the city hustle.

**Evening:**
4. **Dinner and a Show in the West End**
   - End your London adventure with a memorable dinner followed by a theater show in the West End. Book your tickets in advance for popular shows.

**Additional Tips:**
- Always check the attraction websites for any specific COVID-19 guidelines or changes in operating hours.
- London’s public transport system is efficient; consider getting an Oyster card for convenient travel.
- Don't forget to dress in layers to adapt to the chilly weather, and always have your camera ready to capture memories.
---------------
Here’s a detailed itinerary for your visit to Paris, considering the current snowy weather conditions and top attractions:

### Day 1: Embrace the Iconic Landmarks

**Morning: Eiffel Tower**
- **Time:** 9:00 AM
- **Details:** Begin your day with a visit to the Eiffel Tower. Even in the snow, the tower offers stunning views of Paris. Dress warmly and enjoy hot chocolate from nearby cafes.
- **Link for more info:** [Tripadvisor - Things to Do in Paris](https://www.tripadvisor.com/Attractions-g187147-Activities-Paris_Ile_de_France.html)

**Afternoon: Louvre Museum**
- **Time:** 1:00 PM
- **Details:** Spend your afternoon indoors at the Louvre Museum. With its vast collection of art and history, it's a perfect way to escape the cold. Consider taking a guided tour to make the most of your visit.
- **Link for more info:** [U.S. News Travel - Things To Do](https://travel.usnews.com/Paris_France/Things_To_Do/)

**Evening: Seine River Cruise**
- **Time:** 6:00 PM
- **Details:** End your day with a magical Seine River cruise. The snow adds a picturesque touch to the illuminated landmarks. Ensure to book a heated cruise for comfort.

### Day 2: Explore Cultural and Historical Treasures

**Morning: Notre-Dame Cathedral**
- **Time:** 9:30 AM
- **Details:** Visit the iconic Notre-Dame Cathedral. Although some areas may be under restoration, its architecture and history are worth experiencing. Warm clothing is essential as the interior can be chilly.

**Afternoon: Musée d'Orsay**
- **Time:** 1:30 PM
- **Details:** Head to the Musée d'Orsay, renowned for its Impressionist masterpieces. This indoor activity is ideal for escaping the cold and enjoying world-class art.

**Evening: Montmartre and Sacré-Cœur**
- **Time:** 5:00 PM
- **Details:** Wander through the charming streets of Montmartre and visit the Sacré-Cœur Basilica. The view of Paris in the snow is breathtaking. Enjoy a cozy dinner at a local bistro in Montmartre.

### Day 3: Discover Hidden Gems and Local Flavors

**Morning: Le Marais District**
- **Time:** 10:00 AM
- **Details:** Explore Le Marais, known for its vibrant street art, boutiques, and cafes. Enjoy a leisurely breakfast and shop for unique souvenirs.

**Afternoon: Palais Garnier (Opera House)**
- **Time:** 2:00 PM
- **Details:** Tour the opulent Palais Garnier. Its stunning interiors are a must-see, especially when it's snowy outside.

**Evening: Moulin Rouge Show**
- **Time:** 8:00 PM
- **Details:** Conclude your trip with a classic Parisian experience at the Moulin Rouge. Book in advance to secure a good seat and enjoy the legendary cabaret performance.

### Additional Tips:
- **Weather Preparation:** Wear layers, waterproof boots, and carry an umbrella. The snow and cold wind can be intense.
- **Dining:** Indulge in warm, hearty French cuisine at local cafes and restaurants. Try dishes like French onion soup, coq au vin, and tarte Tatin.
- **Transport:** Use public transportation to avoid the snowy streets, and consider purchasing a Paris Visite pass for unlimited travel.

Enjoy your snowy adventure in Paris!
---------------
**Tokyo Itinerary**

**Day 1: Arrival and Exploration of Historical and Cultural Sites**

- **Morning:**
  - **Asakusa District**: Begin your day with a visit to the historic Asakusa district. Explore the iconic Senso-ji Temple, Tokyo's oldest temple. Enjoy the traditional market streets like Nakamise Street for some shopping and snacks.

- **Afternoon:**
  - **Tokyo National Museum**: Head to Ueno Park and visit the Tokyo National Museum. Discover Japan’s extensive collection of art and antiquities. This is a great spot to dive into Japanese history and culture.

- **Evening:**
  - **Dinner in Ueno**: Explore the local dining options around Ueno and enjoy a traditional Japanese dinner.

**Day 2: Modern Tokyo and Unique Experiences**

- **Morning:**
  - **Ghibli Museum**: Start your day with a magical visit to the Ghibli Museum in Mitaka. Perfect for fans of Studio Ghibli's animated films, this museum offers a whimsical look into the creative world of Hayao Miyazaki.

- **Afternoon:**
  - **Shibuya and Harajuku**: Head towards the bustling areas of Shibuya and Harajuku. Witness the famous Shibuya Crossing and explore the trendy shops of Harajuku, especially Takeshita Street.

- **Evening:**
  - **Golden Gai**: Conclude your day in the vibrant Golden Gai district. This area is renowned for its narrow alleys filled with small bars and eateries. Experience the unique nightlife of Tokyo here.

**Day 3: Relax and Explore Green Spaces**

- **Morning:**
  - **Shinjuku Gyoen National Garden**: Spend a peaceful morning strolling through the beautiful Shinjuku Gyoen, one of Tokyo's largest and most beautiful parks. It's a perfect spot for relaxation and enjoying nature.

- **Afternoon:**
  - **Meiji Shrine**: Visit the Meiji Shrine, located in a forested area near Harajuku and Shibuya. It's a serene place to learn about Shinto traditions and enjoy the tranquil setting.

- **Evening:**
  - **Tokyo Tower or Skytree**: End your trip with a visit to either Tokyo Tower or Tokyo Skytree for a panoramic view of the city. It's an unforgettable way to see Tokyo illuminated at night.

**Weather Considerations:**
- With the current weather of few clouds and a mild temperature around 10.32°C, it is advisable to wear layers and carry a light jacket for comfort during outdoor activities.
- Humidity is high (92%), so be prepared for a slightly damp feeling and consider moisture-wicking clothing.

**Additional Tips:**
- Always check the opening hours of attractions and book tickets in advance where necessary.
- Use Tokyo’s efficient public transport to move around easily.
- Consider visiting the websites linked in the attraction descriptions for more detailed information and current updates.
---------------
Here's a detailed itinerary for exploring some of Sydney's top tourist attractions with the current weather conditions in mind. With clear skies and pleasant temperatures, it's a perfect day to explore the outdoors and enjoy what Sydney has to offer.

### Morning

**9:00 AM - Sydney Opera House**
- Begin your day with a visit to the iconic Sydney Opera House. Take a guided tour to learn about its history and architecture. Tours are available in multiple languages.
- **Link:** [Top attractions in Sydney | Sydney.com](https://www.sydney.com/things-to-do/attractions)

**11:00 AM - Royal Botanic Garden Sydney**
- Just a short walk from the Opera House, enjoy a leisurely stroll through the Royal Botanic Garden. The clear skies will offer beautiful views of the diverse plant life and the Sydney Harbour.

### Afternoon

**12:30 PM - Lunch at Opera Bar**
- Head back to Opera Bar for lunch. Enjoy a refreshing cocktail with stunning views of the Sydney Harbour Bridge and the waterfront.
- **Link:** [Top attractions in Sydney | Sydney.com](https://www.sydney.com/things-to-do/attractions)

**2:00 PM - Sydney Harbour Bridge**
- After lunch, take a scenic walk across the Sydney Harbour Bridge. If you're up for it, consider the BridgeClimb for breathtaking panoramic views of the city.

**4:00 PM - The Rocks**
- Explore The Rocks, one of Sydney's most historic areas. Wander through the cobbled streets, visit the local markets, and perhaps enjoy a cup of coffee at a nearby café.

### Evening

**6:00 PM - Darling Harbour**
- Make your way to Darling Harbour for the evening. Here you can visit attractions such as the SEA LIFE Sydney Aquarium or simply enjoy the lively atmosphere by the waterfront.

**8:00 PM - Dinner at a Local Restaurant**
- Conclude your day with dinner at one of Darling Harbour's many restaurants. Choose from a variety of cuisines while enjoying the vibrant night scene.

### Additional Suggestions

- If you're interested in more unique experiences, consider visiting some of the attractions listed on [Time Out Sydney](https://www.timeout.com/sydney/attractions/tourist-attractions-that-dont-suck), which includes thrilling adventures and scenic tours.

With clear skies and mild temperatures, this itinerary offers a balanced mix of cultural, historical, and scenic experiences. Enjoy your visit to Sydney!


## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/localsetup.mdx

---
title: 'Local Setup'
icon: 'code'
---
## Overview

Juelp is designed to be run locally with the help of Docker. This guide will help you set up Julep locally.

## Prerequisites

- [Docker](https://docs.docker.com/get-docker/)

## Setup Instructions

### 1. Clone the Repository
Clone the repository from your preferred source:

```bash
git clone <repository_url>
```

### 2. Navigate to the Root Directory
Change to the root directory of the project:

```bash
cd <repository_root>
```

### 3. Set Up Environment Variables
- Create a `.env` file in the root directory.
- Refer to the [`.env.example`](https://github.com/julep-ai/julep/blob/dev/.env.example) file for a list of required variables.
- Ensure that all necessary variables are set in the `.env` file.

### 4. Create a Docker Volume for Backup
Create a Docker volume named `grafana_data`, `memory_store_data`, `temporal-db-data`, `prometheus_data` and `seadweedfs_data`:

```bash
docker volume create grafana_data
docker volume create memory_store_data
docker volume create temporal-db-data
docker volume create prometheus_data
docker volume create seaweedfs_data
```

The volumes are used to store the data for the Grafana, Memory Store (Timescale DB), Temporal DB, Prometheus, and SeadweedFS, and Memories respectively.


### 5. Run the Project using Docker Compose
You can run the project in two different modes: **Single Tenant** or **Multi-Tenant**. Choose one of the following commands based on your requirement:

#### Single-Tenant Mode
Run the project in single-tenant mode:

```bash
docker compose --env-file .env --profile temporal-ui --profile single-tenant --profile self-hosted-db --profile blob-store --profile temporal-ui-public up --build --force-recreate --watch
```

> **Note:** In single-tenant mode, you can interact with the SDK directly without the need for the API KEY.

#### Multi-Tenant Mode
Run the project in multi-tenant mode:

```bash
docker compose --env-file .env --profile temporal-ui --profile multi-tenant --profile self-hosted-db --profile blob-store --profile temporal-ui-public up --build --force-recreate --watch
```

> **Note:** In multi-tenant mode, you need to generate a JWT token locally that act as an API KEY to interact with the SDK.

### 6. Generate a JWT Token (Only for Multi-Tenant Mode)
Replace `JWT_SHARED_KEY` with the corresponding key from your `.env` file to generate a JWT token
<Tabs>
  <Tab title="Linux">
  
  1. **Install** the JWT CLI from apt:
     ```bash
     sudo apt install jwt
     ```
  2. **Export** your `JWT_SHARED_KEY`:
     ```bash
     export JWT_SHARED_KEY="your-shared-key"
     ```
  3. **Generate** the token:
     ```bash
     jwt -alg HS512 -sign + -claim exp=$(date -d '+10 days' +%s) -claim iat=$(date +%s) -claim sub=00000000-0000-0000-0000-000000000000 -key <(printf '%s' "$JWT_SHARED_SECRET")
     ```
  </Tab>

  <Tab title="macOS">
  
  1. **Install** the Mike-Engel JWT-CLI:
     ```bash
     brew install mike-engel/jwt-cli/jwt-cli
     ```
  2. **Export** your `JWT_SHARED_KEY`:
     ```bash
     export JWT_SHARED_KEY="your-shared-key"
     ```

  3. **Generate** the token:
     ```bash
     jwt encode --secret "$JWT_SHARED_KEY" --alg HS512 --exp $(date -v +10d +%s) --sub '00000000-0000-0000-0000-000000000000' '{}'
     ```
  </Tab>
</Tabs>

> **Note:** This command generates a JWT token that will be valid for 10 days.

### 7. Access and Interact
- **Temporal UI**: You can access the Temporal UI through the specified port in your `.env` file.
- **API Interactions**: Depending on the chosen mode, interact with the setup using the provided endpoints.

### Troubleshooting
- Ensure that all required Docker images are available.
- Check for missing environment variables in the `.env` file.
- Use the `docker compose logs` command to view detailed logs for debugging.

## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/multi-agent-multi-user-sessions.mdx

---
title: 'Multi-Agent Multi-User Sessions'
icon: 'sitemap'
---

## Overview

Julep supports different types of sessions based on the number of agents and users involved. This flexibility allows for complex interactions and use cases.

## Types of Sessions

<CardGroup cols={2}>
  <Card title="Single Agent" icon="user">
    <ol>
      <li>No user</li>
      <li>Single user</li>
      <li>Multiple users</li>
    </ol>
  </Card>
  <Card title="Multiple Agents" icon="users">
    <ol>
      <li>No user</li>
      <li>Single user</li>
      <li>Multiple users</li>
    </ol>
  </Card>
</CardGroup>

## Behavior in Multi-Agent/User Sessions

### User Behavior

<AccordionGroup>
  <Accordion title="No User" icon="user" defaultOpen={true}>
    <ol>
      <li>No user data is retrieved</li>
      <li>(Upcoming) Memories are not mined from the session</li>
    </ol>
  </Accordion>

  <Accordion title="One or More Users" icon="users" defaultOpen={true}>
    <ol>
      <li>Docs, metadata, memories, etc. are retrieved for all users in the session</li>
      <li>Messages can be added for each user by referencing them by name in the `ChatML` messages</li>
      <li>(Upcoming) Memories mined in the background are added to the corresponding user's scope</li>
    </ol>
  </Accordion>
</AccordionGroup>

### Agent Behavior

<AccordionGroup>
  <Accordion title="One Agent" icon="lightbulb" defaultOpen={true}>
    <ol>
      <li>Works as expected</li>
    </ol>
  </Accordion>

  <Accordion title="Multiple Agents" icon="lightbulb" defaultOpen={true}>
    <ol>
      <li>When a message is received by the session, each agent is called one after another in the order they were defined in the session</li>
      <li>You can specify which `agent` to use in a request, in which case, only that agent will be used</li>
    </ol>
  </Accordion>
</AccordionGroup>

<Note>
  This multi-agent/user capability allows for sophisticated scenarios such as:
  - Collaborative problem-solving with multiple AI agents
  - Group conversations with multiple users and agents
  - Specialized agents working together on complex tasks
</Note>

## Conclusion

By supporting these various configurations, Julep provides a flexible framework for building diverse and powerful AI applications.

## Support

If you need help with further questions in Julep:

- Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
- Check the [GitHub repository](https://github.com/julep-ai/julep)
- Contact support at [hey@julep.ai](mailto:hey@julep.ai)

---

## File: documentation/advanced/new-syntax.mdx

---
title: 'New Syntax (Important)'
icon: 'code'
---

## Overview

We've updated our workflow syntax to make data flow more explicit and consistent. 
These changes improve readability and make workflows more maintainable. 
While this update requires modifications to existing workflows, it provides a more robust foundation for workflow development.


## 1. Input/Output Data References

The most significant change is how we reference input and output data between workflow steps. The new syntax makes the data flow more explicit by using the `steps` keyword.

### Old Syntax:
- `inputs[x]` - Referenced input data from step x
- `outputs[x]` - Referenced output data from step x
- `_x` - Shorthand for input data from step x

### New Syntax:
- `steps[x].input` - References input data from step x
- `steps[x].output` - References output data from step x
- `_x` -  Has been removed

### Example

#### Old Syntax
```yaml
- evaluate:
    input_data: inputs[0].a
    output_data: outputs[0].b
    shorthand: _0.c
```

#### New Syntax
```yaml
- evaluate:
    input: $ steps[0].input.a
    output: $ steps[0].output.b
    shorthand: $ steps[0].input.c
```

<Note>
Notice the addition of the `$` prefix in the new syntax. This indicates that the value should be treated as a Python expression. We'll cover this in detail in the next section.
</Note>

### Key Changes:
- `inputs[0]` becomes `steps[0].input`
- `outputs[0]` becomes `steps[0].output`
- `_0` becomes `steps[0].input`
- Added `$` prefix to indicate Python expressions

## 2. Template Syntax Changes Inside `prompt` Steps

Another significant change is the removal of Jinja templates (`{{ }}`) in `log` steps and `prompt` steps. Instead, we now use Python f-strings with the `$` prefix for dynamic content.

### Old Syntax (Using Jinja):
```yaml
- prompt:
    - role: user
      content: Write me an article about the topic: {{inputs[0].topic}}
```

### New Syntax (Using f-strings):
```yaml
- prompt:
    - role: user
      content: $ f"Write me an article about the topic: {steps[0].input.topic}"
    - role: user
      content: this is only text, no need for dollar sign prefix
```

For multiple lines, you can use a multiline f-string:

```yaml
- prompt:
    - role: user
      content: |-
        $ f"""
        Write me an article about the topic: {steps[0].input.topic}.
        The article should be {steps[0].input.article_length} words long.
        """
```

<Note>
The `$` prefix is only needed when the value contains a Python expression or f-string. Plain text content doesn't require the prefix.
</Note>

## 3. When to Use the $ Prefix

The `$` prefix should be used in two scenarios:
1. When referencing step data (inputs/outputs)
2. When using Python expressions or f-strings

#### Examples:

```yaml
steps:
  - prompt:
      # Needs $ because it uses an f-string
      - role: user
        content: $ f"The temperature is {steps[0].input.temp}°C"
      
      # No $ needed - plain text
      - role: user
        content: Tell me about the weather

  - evaluate:
      # Needs $ because it references step data
      input: $ steps[0].output
      
      # Needs $ because it's a Python expression
      condition: $ len(steps[0].input.text) > 100
```