{{title}}
+ + {{#summary}} +{{summary}}
+ {{/summary}} +diff --git a/.cursorignore b/.agentignore
similarity index 98%
rename from .cursorignore
rename to .agentignore
index 4582f1fa2..458f85a8c 100644
--- a/.cursorignore
+++ b/.agentignore
@@ -1,6 +1,8 @@
# Git
.git/
+.codex/
+
# Build and distribution directories
**/dist/
**/build/
@@ -136,4 +138,4 @@ gateway/letsencrypt/
# Monitoring data
monitoring/grafana/dashboards/
monitoring/prometheus/data/
-monitoring/grafana/storage/
\ No newline at end of file
+monitoring/grafana/storage/
diff --git a/.codex/setup.sh b/.codex/setup.sh
new file mode 100644
index 000000000..25b5f7173
--- /dev/null
+++ b/.codex/setup.sh
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+#
+# setup-all.sh ─ one-shot bootstrap for the whole julep monorepo
+#
+# › run from repo root: ./setup-all.sh
+#
+# It will:
+# • ensure Poetry + TypeSpec compiler are available
+# • iterate over each top-level directory and install deps:
+# – pyproject.toml ➜ poetry install
+# – package.json ➜ npm install (uses pnpm if present)
+# – requirements.txt➜ pip install -r
+# • install root pre-commit hooks (if .pre-commit-config.yaml exists)
+# • stop on first error (set -e)
+
+set -euo pipefail
+
+### 1. Globals --------------------------------------------------------------
+
+IGNORE_DIRS_DEFAULT="sdks deploy scripts monitoring .git .venv node_modules"
+IGNORE_DIRS="${IGNORE_DIRS:-$IGNORE_DIRS_DEFAULT}"
+
+ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+# cd "$ROOT_DIR"
+
+RED="\033[0;31m"; GREEN="\033[0;32m"; CYAN="\033[0;36m"; NC="\033[0m"
+
+announce() { echo -e "${CYAN}==>$1${NC}"; }
+
+### 3. Ensure TypeSpec compiler --------------------------------------------
+
+if ! command -v tsp &> /dev/null; then
+ announce "Installing TypeSpec compiler globally (npm)…"
+ npm install -g @typespec/compiler > /dev/null
+else
+ announce "TypeSpec compiler present → $(tsp --version)"
+fi
+
+announce "Installing hasura-cli globally (npm)…"
+curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
+
+### 4. Walk directories -----------------------------------------------------
+curl -LsSf https://astral.sh/uv/install.sh | sh
+
+
+if [[ -f "pyproject.toml" ]]; then
+ announce "Installing root deps"
+ uv sync
+ echo -e "${GREEN}✓ root deps installed${NC}"
+fi
+
+
+OIFS=$IFS; IFS=$'\n'
+for dir in $(git ls-tree --name-only -d HEAD | sort); do
+ d="${dir#./}"
+ if [[ " $IGNORE_DIRS " =~ [[:space:]]"$d"[[:space:]] ]]; then
+ echo -e "· skipping $d (ignored)"
+ continue
+ fi
+
+ announce "Processing $d/"
+
+ # uv project?
+ if [[ -f "$d/pyproject.toml" ]]; then
+ pushd "$d" > /dev/null
+ announce "[uv] installing in $d …"
+ uv sync
+ uv pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
+ popd > /dev/null
+ echo -e "${GREEN}✓ uv install done for $d${NC}"
+ continue
+ fi
+
+ # Node project?
+ if [[ -f "$d/package.json" ]]; then
+ pushd "$d" > /dev/null
+ announce "[npm] installing in $d …"
+ if command -v pnpm &> /dev/null; then
+ pnpm install --silent
+ else
+ npm install --silent
+ fi
+ popd > /dev/null
+ echo -e "${GREEN}✓ npm install done for $d${NC}"
+ continue
+ fi
+
+ # Plain requirements.txt?
+ if [[ -f "$d/requirements.txt" ]]; then
+ pushd "$d" > /dev/null
+ announce "[pip] installing requirements in $d …"
+ pip install -r requirements.txt
+ pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
+ popd > /dev/null
+ echo -e "${GREEN}✓ pip install done for $d${NC}"
+ continue
+ fi
+
+ echo -e "· no recognised manifest in $d – nothing to install"
+done
+IFS=$OIFS
+
+### 5. Pre-commit -----------------------------------------------------------
+
+if [[ -f ".pre-commit-config.yaml" ]]; then
+ announce "Installing git pre-commit hooks…"
+ pip install --quiet pre-commit
+ pre-commit install
+ echo -e "${GREEN}✓ pre-commit hooks installed${NC}"
+fi
+
+echo -e "${GREEN}\nAll done – monorepo dependencies ready!${NC}"
diff --git a/.cursorindexignore b/.cursorindexignore
deleted file mode 100644
index 8ba194171..000000000
--- a/.cursorindexignore
+++ /dev/null
@@ -1,150 +0,0 @@
-# Git
-.git/
-.github/
-
-# Build and distribution directories
-**/dist/
-**/build/
-**/.ruff_cache/
-**/node_modules/
-**/__pycache__/
-**/.pytest_cache/
-**/.mypy_cache/
-**/.tox/
-**/.coverage/
-**/.venv/
-**/venv/
-**/.next/
-**/.nuxt/
-**/out/
-**/coverage/
-
-# Environment files (may contain sensitive information)
-**/.env
-**/.env.*
-**/*.pem
-**/*.key
-**/*.cert
-**/*.crt
-
-# Large data files and binaries (to avoid loading and indexing them)
-**/*.csv
-**/*.json
-**/*.parquet
-**/*.arrow
-**/*.pickle
-**/*.pkl
-**/*.db
-**/*.sqlite
-**/*.sqlite3
-**/*.so
-**/*.dll
-**/*.dylib
-**/*.exe
-**/*.whl
-**/*.tar.gz
-**/*.zip
-**/*.jar
-**/*.war
-**/*.ear
-
-# Lock files (usually don't need indexing)
-**/yarn.lock
-**/package-lock.json
-**/pnpm-lock.yaml
-**/poetry.lock
-**/Pipfile.lock
-**/requirements-frozen.txt
-**/uv.lock
-
-# Generated documentation or third-party code
-**/docs/_build/
-**/site/
-**/public/
-**/vendor/
-**/third_party/
-
-# Large media files
-**/*.mp4
-**/*.mp3
-**/*.wav
-**/*.avi
-**/*.mov
-**/*.png
-**/*.jpg
-**/*.jpeg
-**/*.gif
-**/*.svg
-**/*.ico
-**/*.pdf
-
-# Logs and temporary files
-**/logs/
-**/*.log
-**/tmp/
-**/temp/
-**/*.tmp
-**/*.temp
-
-# IDE and editor files
-**/.vscode/
-**/.idea/
-**/.DS_Store
-**/.ipynb_checkpoints/
-
-# Large generated files
-gaga.json
-openapi.yaml
-openapi*.yaml
-openapi*.yml
-openapi*.json
-
-# Julep-specific exclusions
-# TypeSpec generated outputs (avoid indexing auto-generated code)
-typespec/tsp-output/
-typespec/node_modules/
-
-# Memory-store migration files (SQL structure)
-memory-store/migrations/*.up.sql
-memory-store/migrations/*.down.sql
-
-# Large binary files in tests
-**/tests/sample_tasks/*.base64
-**/tests/sample_tasks/*.png
-**/tests/sample_tasks/screenshot.*
-
-# Auto-generated OpenAPI specs
-documentation/openapi.yaml
-sdks/**/api.md
-
-# Docker templates that don't need indexing
-**/*.template
-**/Dockerfile*
-**/docker-compose*.yml
-
-# Generated configuration files
-**/litellm-config.yaml
-scheduler/dynamicconfig/temporal-postgres.yaml
-
-# Exclude large notebooks in cookbooks
-cookbooks/*.ipynb
-
-# Browser automation screenshots and binary data
-**/browser_screenshots/
-**/downloads/
-
-# Certificate files
-scheduler/cert/
-gateway/letsencrypt/
-
-# Generated Python package files
-**/*.egg-info/
-**/*.pyc
-**/__pycache__/
-
-# Vector search training data
-**/embeddings/
-**/vectors/
-
-# Temporal workflow history (large and not needed for indexing)
-**/.temporal/
\ No newline at end of file
diff --git a/.cursorrules b/.cursorrules
deleted file mode 100644
index 797130215..000000000
--- a/.cursorrules
+++ /dev/null
@@ -1,158 +0,0 @@
-{
- "meta": {
- "description": "Julep project rules for LLMs",
- "version": "1.0"
- },
- "codeStyle": {
- "python": {
- "version": "3.12+",
- "framework": "fastAPI",
- "async": true,
- "lineLength": 96,
- "indentation": 4,
- "quotes": "double",
- "imports": "ruff",
- "typing": "strict",
- "naming": {
- "functions": "snake_case",
- "variables": "snake_case",
- "classes": "PascalCase"
- },
- "patterns": {
- "errors": "typed_exceptions",
- "resources": "context_managers",
- "docs": "docstrings_public"
- }
- }
- },
- "commands": {
- "format": "poe format",
- "lint": "poe lint",
- "typecheck": "poe typecheck",
- "test": "poe test",
- "testPattern": "poe test --search \"pattern_to_match\"",
- "testFile": "PYTHONPATH=$PWD python tests/test_file.py",
- "check": "poe check",
- "codegen": "poe codegen"
- },
- "architecture": {
- "components": {
- "agents-api": "Main service for agent and task functionality",
- "memory-store": "PostgreSQL with TimescaleDB for storage",
- "blob-store": "S3-compatible object storage",
- "scheduler": "Temporal workflow engine",
- "integrations-service": "External service integrations",
- "gateway": "API gateway and routing",
- "llm-proxy": "LiteLLM proxy for models",
- "monitoring": "Prometheus and Grafana",
- "typespec": "API specifications",
- "sdks": "Node.js and Python clients"
- },
- "patterns": {
- "api": "RESTful endpoints with consistent CRUD operations",
- "db": "PostgreSQL with pgvector, async queries",
- "workflow": "Temporal for durable execution",
- "expressions": "Python with simpleeval sandbox",
- "multitenancy": "Developer-scoped entities",
- "search": "Hybrid vector/text search"
- }
- },
- "domainModels": {
- "agents": "AI agent definitions with instructions and tools",
- "tasks": "Workflow definitions with steps",
- "tools": "Integrations and capabilities for agents",
- "sessions": "Conversation containers with context",
- "entries": "Message history tracking",
- "executions": "Task execution state tracking",
- "docs": "Document storage with vector search",
- "files": "File storage and management",
- "users": "User management and authentication"
- },
- "stepTypes": {
- "tool": ["ToolCallStep", "PromptStep", "EvaluateStep", "PgQueryStep"],
- "flow": ["IfElseStep", "SwitchStep", "ParallelStep", "ForeachStep", "MapReduceStep"],
- "data": ["GetStep", "SetStep", "LogStep"],
- "terminal": ["ReturnStep", "ErrorStep", "WaitForInputStep"]
- },
- "expressions": {
- "syntax": "$expression",
- "legacy": "{{variable}} → $f'''{{variable}}'''",
- "validation": "validate_py_expression() in base_evaluate.py",
- "context": "_ (current input), inputs, outputs, stdlibs",
- "security": "simpleeval sandbox, limited functions/modules"
- },
- "testing": {
- "framework": "ward",
- "syntax": "@test(\"Description\")",
- "search": "--search not -p",
- "limits": "--fail-limit 1",
- "env": "source .venv/bin/activate",
- "path": "PYTHONPATH=$PWD"
- },
- "databases": {
- "vectorSearch": {
- "implementation": "pgvector + OpenAI embeddings",
- "dimensions": 1024,
- "methods": ["text", "vector", "hybrid"],
- "indexing": "DiskANN for ANN search"
- },
- "textSearch": {
- "features": ["tsquery", "trigram", "unaccent"],
- "languages": "multi-language support"
- },
- "patterns": {
- "keys": "compound (developer_id, entity_id)",
- "metadata": "JSONB type",
- "timeseries": "hypertables for transitions"
- }
- },
- "errors": {
- "common": {
- "wardsyntax": "Using pytest fixtures/classes instead of @test()",
- "venv": "Forgetting to activate virtualenv",
- "paths": "Wrong PYTHONPATH or directory",
- "expressions": "Missing _ context or improper validation"
- }
- },
- "workflows": {
- "execution": {
- "steps": ["init", "wait", "error", "step", "cancelled", "init_branch", "finish"],
- "transitions": "tracked in database",
- "concurrency": "parallel for map/reduce",
- "timeouts": "configurable per activity",
- "heartbeats": "for long-running activities"
- },
- "activities": {
- "stepExecution": ["prompt_step", "tool_call_step", "get_value_step", "transition_step"],
- "external": ["execute_api_call", "execute_integration", "execute_system"],
- "data": ["sync_items_remote"]
- }
- },
- "cli": {
- "structure": {
- "config": "~/.config/julep/config.yml",
- "state": "~/.config/julep/julep_state.db",
- "project": "julep.yaml + julep-lock.json"
- },
- "commands": {
- "initialization": "julep init",
- "sync": "julep sync",
- "entities": "julep [agents|tasks|tools] [action]",
- "execution": "julep run --task
-
-
- 探索文档(正在开发中)
- ·
- 不和谐
- ·
- 𝕏
- ·
- LinkedIn
-
-
-
----
-
-> [!注意]
-> 从[此处](https://dashboard-dev.julep.ai)获取您的 API 密钥。
-
-
贡献🌟(点击展开)
-
-## 征集贡献者🌟
-
-我们很高兴欢迎新贡献者加入 Julep 项目!我们创建了几个“好的第一个问题”来帮助您入门。以下是您可以做出贡献的方式:
-
-1. 查看我们的 [CONTRIBUTING.md](https://github.com/julep-ai/julep/blob/dev/CONTRIBUTING.md) 文件以获取有关如何贡献的指南。
-2. 浏览我们的 [good first issues](https://github.com/julep-ai/julep/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 以找到您感兴趣的任务。
-3. 如果您有任何疑问或需要帮助,请随时通过我们的 [Discord](https://discord.com/invite/JTSBGRZrzj) 频道联系我们。
-
-您的贡献,无论大小,对我们来说都是宝贵的。让我们一起创造一些了不起的东西!🚀
+
+
+ ·
+
+
+ | Name | -About | -Syntax | -
|---|---|---|
| Prompt | -
-Send a message to the AI model and receive a response
- Note: The prompt step uses Jinja templates and you can access context variables in them. - |
-
-- -```yaml -- prompt: "分析以下数据:{{agent.name}}" # <-- 这是一个 jinja 模板 -``` - -```yaml -- 迅速的: -- 角色:系统 -内容:“您是 {{agent.name}}。 {{agent.about}}” -- 角色:用户 -内容:“分析以下数据:{{_.data}}” -``` - - | -
| Tool Call | -
-Execute an integrated tool or API that you have previously declared in the task.
- Note: The tool call step uses Python expressions inside the arguments. - - |
-
-- -```yaml -- 工具:web_search -参数: -查询:“最新的 AI 发展”#<- 这是一个 Python 表达式(注意引号) -num_results: len(_.topics) # <-- 用于访问列表长度的 Python 表达式 -``` - - | -
| Evaluate | -
-Perform calculations or manipulate data
- Note: The evaluate step uses Python expressions. - |
-
-- -```yaml -- 评价: -平均分数:总分(分数)/长度(分数) -``` - - | -
| Wait for Input | -
-Pause workflow until input is received. It accepts an `info` field that can be used by your application to collect input from the user.
-
- Note: The wait_for_input step is useful when you want to pause the workflow and wait for user input e.g. to collect a response to a prompt. - - |
-
-- -```yaml --等待输入: -信息: -消息:'“请提供有关 {_.required_info} 的其他信息。”' # <-- 用于访问上下文变量的 python 表达式 -``` - - | -
| Log | -
-Log a specified value or message.
-
- Note: The log step uses Jinja templates and you can access context variables in them. - - |
-
-- -```yaml -- log:“项目 {{_.item_id}} 的处理已完成”#<-- jinja 模板用于访问上下文变量 -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Get | --Retrieve a value from the execution's key-value store. - - | - -- -```yaml -- 获取:用户偏好 -``` - - | -
| Set | -
-Assign a value to a key in the execution's key-value store.
-
- Note: The set step uses Python expressions. - - |
-
-- -```yaml -- 放: -user_preference: '"dark_mode"' # <-- python 表达式 -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Foreach | --Iterate over a collection and perform steps for each item - - | - -- -```yaml -- foreach: -in: _.data_list # <-- 用于访问上下文变量的 python 表达式 -做: -- log: "处理项目 {{_.item}}" # <-- jinja 模板访问上下文变量 -``` - - | -
| Map-Reduce | --Map over a collection and reduce the results - - | -
+
-```yaml
-- 映射_减少:
-over: _.numbers # <-- 用于访问上下文变量的 python 表达式
-地图:
-- 评价:
-平方:“_ ** 2”
-reduce:results + [_] # <--(可选)python 表达式以减少结果。如果省略,则为默认值。
-```
+## 为什么选择Julep?
-```yaml
-- 映射_减少:
-结束:_.topics
-地图:
-- 提示:写一篇关于{{__}}的文章
-并行度:10
-```
+Julep是一个构建**基于智能代理的AI工作流**的开源平台,远超简单的提示链。它让你能够使用大型语言模型(LLM)和工具编排复杂的多步骤流程,**无需管理任何基础设施**。使用Julep,你可以创建**记住过往交互**并处理具有分支逻辑、循环、并行执行和外部API集成等复杂任务的AI代理。简而言之,Julep就像*"AI代理的Firebase"*,为规模化的智能工作流提供强大的后端。
- |
-
| Parallel | --Run multiple steps in parallel +**主要功能和优势:** - | +* **持久记忆:** 构建在对话中维持上下文和长期记忆的AI代理,让它们能够随时间学习和改进。 +* **模块化工作流:** 将复杂任务定义为模块化步骤(YAML或代码),具有条件逻辑、循环和错误处理。Julep的工作流引擎自动管理多步骤流程和决策。 +* **工具编排:** 轻松集成外部工具和API(网页搜索、数据库、第三方服务等)作为代理工具箱的一部分。Julep的代理可以调用这些工具来增强其能力,实现检索增强生成等功能。 +* **并行和可扩展:** 并行运行多个操作以提高效率,让Julep处理后台的扩展和并发。平台是无服务器的,因此可以无缝扩展工作流,无需额外的DevOps开销。 +* **可靠执行:** 不用担心故障 - Julep提供内置重试、自愈步骤和强大的错误处理,让长时间运行的任务保持正轨。你还能获得实时监控和日志记录来跟踪进展。 +* **易于集成:** 通过我们的**Python**和**Node.js** SDK快速开始,或使用Julep CLI进行脚本编写。如果你想直接集成到其他系统中,Julep的REST API也可以使用。 -
+*专注于你的AI逻辑和创意,而把繁重的工作交给Julep!*
- |
-
| Name | About | Syntax | -
|---|---|---|
| If-Else | --Conditional execution of steps - - | - -- -```yaml -- if: _.score > 0.8 # <-- python 表达式 -然后: -- 日志:取得高分 -别的: -- 错误:分数需要提高 -``` - - | -
| Switch | --Execute steps based on multiple conditions - - | - -- -```yaml -- 转变: -- 案例:_.category =='A' -然后: -- 日志:“A 类处理” -- 案例:_.category =='B' -然后: -- 日志:“B类处理” -- case: _ # 默认情况 -然后: -- 错误:未知类别 -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Sleep | --Pause the workflow for a specified duration - - | - -- -```yaml -- 睡觉: -秒:30 -# 分钟:1 -#小时数:1 -#天数:1 -``` - - | -
| Return | -
-Return a value from the workflow
-
- Note: The return step uses Python expressions. - - |
-
-- -```yaml -- 返回: -result: '“任务成功完成”' #<-- python 表达式 -时间:datetime.now().isoformat() # <-- python 表达式 -``` - - | -
| Yield | --Run a subworkflow and await its completion - - | - -- -```yaml -- 屈服: -工作流程:process_data -参数: -输入数据:_.raw_data # <-- python 表达式 -``` - - | -
| Error | --Handle errors by specifying an error message - - | - -- -```yaml -- 错误:“提供的输入无效”#<-- 仅限字符串 -``` - - | -
| Brave Search | -- -```yaml -设置: -api_key: string # Brave Search 的 API 密钥 - -参数: -query: string # 使用 Brave 搜索的搜索查询 - -输出: -result: list[dict] # 搜索结果列表,每个结果包含:标题、链接、摘要 -``` - - | - -- -**Example cookbook**: [cookbooks/02-sarcastic-news-headline-generator.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/02-sarcastic-news-headline-generator.ipynb) - - | -
| BrowserBase | -- -```yaml -设置: -api_key: string # BrowserBase 的 API 密钥 -project_id: string # BrowserBase 的项目 ID -session_id: string #(可选)BrowserBase 的会话 ID - -参数: -urls: list[string] # 使用 BrowserBase 加载的 URL - -输出: -documents: list # 从 URL 加载的文档 -``` - - | - -- -**Example cookbook**: [cookbooks/06-browser-use.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/06-browser-use.ipynb) - - | -
| - -```yaml -设置: -host: string # 电子邮件服务器的主机 -port: integer # 电子邮件服务器的端口 -用户:string#电子邮件服务器的用户名 -password: string # 邮件服务器的密码 - -参数: -to: string # 要发送电子邮件到的电子邮件地址 -from: string # 发送电子邮件的电子邮件地址 -subject: string # 电子邮件的主题 -body: string # 电子邮件正文 - -输出: -success: boolean # 邮件是否发送成功 -``` - - | - -- -**Example cookbook**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb) - - | -|
| Spider | -- -```yaml -设置: -spider_api_key: string # Spider 的 API 密钥 - -参数: -url: string # 获取数据的 URL -params: dict # (可选)Spider API 的参数 -content_type:字符串 #(可选)要返回的内容类型。默认为“application/json”。其他选项:“text/csv”、“application/xml”、“application/jsonl” - -输出: -result: list[dict] # 结果列表,每个结果包含:内容、错误、状态、费用、网址 -``` - - | - -- -**Example cookbook**: [cookbooks/01-website-crawler.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-website-crawler.ipynb) - - | -
| Weather | -- -```yaml -设置: -openweathermap_api_key: string # OpenWeatherMap 的 API 密钥 - -参数: -location: string # 获取天气数据的位置 - -输出: -result: string # 指定位置的天气数据 -``` - - | - -- -**Example cookbook**: [cookbooks/03-trip-planning-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-trip-planning-assistant.ipynb) - - | -
| Wikipedia | -- -```yaml -参数: -query: string # 搜索查询字符串 -load_max_docs:整数 #(可选)要加载的最大文档数。默认值为 2。 - -输出: -documents: list # 从 Wikipedia 搜索返回的文档 -``` - - | - -- -**Example cookbook**: [cookbooks/03-trip-planning-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-trip-planning-assistant.ipynb) - - | -
| FFmpeg | -- -```yaml -参数: -cmd: string # 要执行的 FFmpeg 命令 -file: string # 要处理的 base64 编码文件 - -输出: -fileoutput: string # FFmpeg 命令以 base64 编码输出的文件 -result: boolean # FFmpeg命令是否执行成功 -mime_type: string # 输出文件的 MIME 类型 -``` - - | - -|
| Llama Parse | -
-
-```yaml
-设置:
-llamaparse_api_key: string # Llama Parse 的 API 密钥
-params: dict #(可选)Llama Parse 集成的附加参数
-
-参数:
-文件:字符串 | 数组 |
-- -**Example cookbook**: [cookbooks/07-personalized-research-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/07-personalized-research-assistant.ipynb) - - | -
| Cloudinary | -- -```yaml - -方法:media_upload | media_edit # 用于 Cloudinary 集成的方法 - -设置: -cloudinary_cloud_name: string # 您的 Cloudinary 云名称 -cloudinary_api_key: string # 您的 Cloudinary API 密钥 -cloudinary_api_secret: string # 您的 Cloudinary API 密钥 -params: dict # (可选)Cloudinary 集成的附加参数 - -参数: -file: string # 文件上传的 URL。仅适用于 media_upload 方法。 -upload_params:dict #(可选)上传的附加参数。仅适用于 media_upload 方法。 -public_id:字符串 #(可选)文件的公共 ID。对于 media_edit 方法,它是必需的。对于 media_upload 方法,它是可选的。默认为随机 UUID。 -transformation:list[dict] # 应用于文件的转换。仅适用于 media_edit 方法。 -return_base64: boolean # 是否以 base64 编码返回文件。默认为 false。 - -输出: -url:string # 上传文件的 URL。仅适用于 media_upload 方法。 -meta_data: dict # 来自上传响应的附加元数据。仅适用于 media_upload 方法。 -public_id: string # 上传文件的公共 ID。仅适用于 media_upload 方法。 -经过转换的 URL:字符串 #(可选)转换后的 URL。仅适用于 media_edit 方法。 -base64:字符串#(可选)如果 return_base64 为真,则为 base64 编码的文件。 -``` - - | -- -**Example cookbook**: [cookbooks/05-video-processing-with-natural-language.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/05-video-processing-with-natural-language.ipynb) - - | -
| Arxiv | -- -```yaml -方法:搜索#用于 Arxiv 集成的方法 - -设置: -# Arxiv 不需要任何特殊设置参数 - -参数: -query: string # 使用 Arxiv 搜索的搜索查询 -id_list:list[string] | None # (可选)要搜索的 Arxiv ID 列表 -max_results: 整数 # 返回的最大结果数,必须介于 1 到 300000 之间 -download_pdf:boolean # 是否下载结果的 PDF。默认为 false。 -sort_by: string # 结果的排序标准,选项:relevance、lastUpdatedDate、submittedDate -sort_order: string # 结果的排序顺序,选项:升序、降序 - -输出: -result: list[dict] # 搜索结果列表,每个结果包含:entry_id、title、updated、published、authors、summary、comment、journal_ref、doi、primary_category、categories、links、pdf_url、pdf_downloaded -``` - - | - -- -**Example cookbook**: [cookbooks/07-personalized-research-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/07-personalized-research-assistant.ipynb) - - | -
+
+
-
-
-
----
-
-## Julep 和 LangChain 等有什么区别?
+## 文档和示例
-### 不同的用例
-可以将 LangChain 和 Julep 视为 AI 开发堆栈中具有不同重点的工具。
+想要深入了解?**[Julep文档](https://docs.julep.ai)**涵盖了掌握平台所需的一切 - 从核心概念(代理、任务、会话、工具)到高级主题如代理记忆管理和架构内部。关键资源包括:
-LangChain 非常适合创建提示序列和管理与 LLM 的交互。它拥有庞大的生态系统,包含大量预构建的集成,如果您想快速启动和运行某些功能,这会非常方便。LangChain 非常适合涉及线性提示链和 API 调用的简单用例。
+* **[概念指南](https://docs.julep.ai/concepts/):** 了解Julep的架构、会话和记忆的工作原理、工具使用、管理长对话等等。
+* **[API和SDK参考](https://docs.julep.ai/api-reference/):** 查找所有SDK方法和REST API端点的详细参考,以将Julep集成到你的应用程序中。
+* **[教程](https://docs.julep.ai/tutorials/):** 构建真实应用程序的分步指南(例如搜索网络的研究代理、旅行规划助手或具有自定义知识的聊天机器人)。
+* **[Cookbook食谱](https://github.com/julep-ai/julep/tree/dev/cookbooks):** 探索**Julep Cookbook**以获取现成的示例工作流和代理。这些食谱展示了常见模式和用例 - 通过示例学习的绝佳方式。*浏览此存储库中的 [`cookbooks/`](https://github.com/julep-ai/julep/tree/dev/cookbooks) 目录以获取示例代理定义。*
+* **[IDE集成](https://context7.com/julep-ai/julep):** 直接在IDE中访问Julep文档!在编码时获得即时答案的完美解决方案。
-另一方面,Julep 更侧重于构建持久的 AI 代理,这些代理可以在长期交互中保持上下文。当您需要涉及多步骤任务、条件逻辑以及在代理流程中直接与各种工具或 API 集成的复杂工作流时,它会大放异彩。它从头开始设计,以管理持久会话和复杂的工作流。
+
-如果您想构建一个需要执行以下操作的复杂 AI 助手,请使用 Julep:
+## 社区和贡献
-- 跟踪几天或几周内的用户互动。
-- 执行计划任务,例如发送每日摘要或监控数据源。
-- 根据之前的互动或存储的数据做出决策。
-- 作为其工作流程的一部分与多个外部服务进行交互。
+加入我们不断壮大的开发者和AI爱好者社区!以下是一些参与和获得支持的方式:
-然后 Julep 提供支持所有这些的基础设施,而无需您从头开始构建。
+* **Discord社区:** 有问题或想法?加入我们 [官方Discord服务器](https://discord.gg/7H5peSN9QP) 上的对话,与Julep团队和其他用户聊天。我们很乐意帮助故障排除或头脑风暴新的用例。
+* **GitHub讨论和问题:** 请随时使用GitHub报告错误、请求功能或讨论实现细节。如果你想贡献,请查看 [**good first issues**](https://github.com/julep-ai/julep/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) - 我们欢迎各种类型的贡献。
+* **贡献:** 如果你想贡献代码或改进,请查看我们的 [贡献指南](CONTRIBUTING.md) 了解如何开始。我们感谢所有的PR和反馈。通过协作,我们可以让Julep变得更好!
-### 不同的外形尺寸
+*专业提示:
-
- Explorer les documents (en cours)
- ·
- Discorde
- ·
- 𝕏
- ·
- LinkedIn
-
+ ·
+
+
+ | Name | -About | -Syntax | -
|---|---|---|
| Prompt | -
-Send a message to the AI model and receive a response
- Note: The prompt step uses Jinja templates and you can access context variables in them. - |
-
-- -```YAML -- invite : « Analyser les données suivantes : {{agent.name}} » # <-- ceci est un modèle jinja -``` - -```YAML -- rapide: -- rôle : système -contenu : « Vous êtes {{agent.name}}. {{agent.about}} » -- rôle : utilisateur -contenu : « Analysez les données suivantes : {{_.data}} » -``` - - | -
| Tool Call | -
-Execute an integrated tool or API that you have previously declared in the task.
- Note: The tool call step uses Python expressions inside the arguments. - - |
-
-- -```YAML -- outil : recherche sur le Web -Arguments: -requête : « Derniers développements de l'IA » # <-- il s'agit d'une expression Python (remarquez les guillemets) -num_results: len(_.topics) # <-- expression python pour accéder à la longueur d'une liste -``` - - | -
| Evaluate | -
-Perform calculations or manipulate data
- Note: The evaluate step uses Python expressions. - |
-
-- -```YAML -- évaluer: -average_score : somme(scores) / len(scores) -``` - - | -
| Wait for Input | -
-Pause workflow until input is received. It accepts an `info` field that can be used by your application to collect input from the user.
-
- Note: The wait_for_input step is useful when you want to pause the workflow and wait for user input e.g. to collect a response to a prompt. - - |
-
-- -```YAML -- attendre_la_saisie : -info: -message : « Veuillez fournir des informations supplémentaires sur {_.required_info}. » # <-- expression Python pour accéder à la variable de contexte -``` - - | -
| Log | -
-Log a specified value or message.
-
- Note: The log step uses Jinja templates and you can access context variables in them. - - |
-
-- -```YAML -- log : « Traitement terminé pour l'élément {{_.item_id}} » # <-- modèle jinja pour accéder à la variable de contexte -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Get | --Retrieve a value from the execution's key-value store. - - | - -- -```YAML -- obtenir : préférences_utilisateur -``` - - | -
| Set | -
-Assign a value to a key in the execution's key-value store.
-
- Note: The set step uses Python expressions. - - |
-
-- -```YAML -- ensemble: -préférence_utilisateur : '"dark_mode"' # <-- expression python -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Foreach | --Iterate over a collection and perform steps for each item - - | - -- -```YAML -- pour chaque : -dans : _.data_list # <-- expression python pour accéder à la variable de contexte -faire: -- log : « Traitement de l'élément {{_.item}} » # <-- modèle jinja pour accéder à la variable de contexte -``` - - | -
| Map-Reduce | --Map over a collection and reduce the results - - | -
+
-```YAML
-- map_reduce:
-over: _.numbers # <-- expression python pour accéder à la variable de contexte
-carte:
-- évaluer:
-au carré : "_ ** 2"
-réduire : résultats + [_] # <-- (facultatif) expression Python pour réduire les résultats. Il s'agit de la valeur par défaut si elle est omise.
-```
+## Pourquoi Julep ?
-```YAML
-- map_reduce:
-plus de: _.topics
-carte:
-- invite : Rédigez un essai sur {{_}}
-parallélisme : 10
-```
+Julep est une plateforme open-source pour construire des **flux de travail d'IA basés sur des agents** qui vont bien au-delà de simples chaînes de prompts. Elle vous permet d'orchestrer des processus complexes en plusieurs étapes avec des modèles de langage de grande taille (LLM) et des outils **sans gérer d'infrastructure**. Avec Julep, vous pouvez créer des agents d'IA qui **se souviennent des interactions passées** et gèrent des tâches sophistiquées avec une logique de branchement, des boucles, une exécution parallèle et l'intégration d'APIs externes. En bref, Julep agit comme un *"Firebase pour les agents d'IA,"* fournissant un backend robuste pour les flux de travail intelligents à grande échelle.
- |
-
| Parallel | --Run multiple steps in parallel +**Caractéristiques clés et avantages :** - | +* **Mémoire persistante :** Construisez des agents d'IA qui maintiennent le contexte et la mémoire à long terme à travers les conversations, afin qu'ils puissent apprendre et s'améliorer au fil du temps. +* **Flux de travail modulaires :** Définissez des tâches complexes comme des étapes modulaires (en YAML ou code) avec une logique conditionnelle, des boucles et la gestion d'erreurs. Le moteur de flux de travail de Julep gère automatiquement les processus multi-étapes et les décisions. +* **Orchestration d'outils :** Intégrez facilement des outils externes et des APIs (recherche web, bases de données, services tiers, etc.) dans la boîte à outils de votre agent. Les agents de Julep peuvent invoquer ces outils pour augmenter leurs capacités, permettant la génération augmentée par récupération et plus. +* **Parallèle et extensible :** Exécutez plusieurs opérations en parallèle pour l'efficacité, et laissez Julep gérer la mise à l'échelle et la concurrence en arrière-plan. La plateforme est sans serveur, donc elle met à l'échelle les flux de travail de manière transparente sans surcharge DevOps supplémentaire. +* **Exécution fiable :** Ne vous inquiétez pas des problèmes - Julep fournit des réessais intégrés, des étapes d'auto-guérison et une gestion d'erreurs robuste pour maintenir les tâches de longue durée sur la bonne voie. Vous obtenez également une surveillance et une journalisation en temps réel pour suivre les progrès. +* **Intégration facile :** Commencez rapidement avec nos SDKs pour **Python** et **Node.js**, ou utilisez le CLI Julep pour les scripts. L'API REST de Julep est disponible si vous voulez intégrer directement dans d'autres systèmes. -
+*Concentrez-vous sur votre logique et créativité d'IA, pendant que Julep s'occupe du gros travail !*
- |
-
| Name | About | Syntax | -
|---|---|---|
| If-Else | --Conditional execution of steps - - | - -- -```YAML -- si : _.score > 0.8 # <-- expression python -alors: -- log : score élevé atteint -autre: -- erreur : le score doit être amélioré -``` - - | -
| Switch | --Execute steps based on multiple conditions - - | - -- -```YAML -- changer: -- cas : _.category == 'A' -alors: -- log : « Traitement de catégorie A » -- cas : _.category == 'B' -alors: -- log : « Traitement de catégorie B » -- case: _ # Cas par défaut -alors: -- erreur : catégorie inconnue -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Sleep | --Pause the workflow for a specified duration - - | - -- -```YAML -- dormir: -secondes: 30 -# minutes: 1 -# heures: 1 -# jours: 1 -``` - - | -
| Return | -
-Return a value from the workflow
-
- Note: The return step uses Python expressions. - - |
-
-- -```YAML -- retour: -résultat : " Tâche terminée avec succès " # <-- expression python -heure : datetime.now().isoformat() # <-- expression python -``` - - | -
| Yield | --Run a subworkflow and await its completion - - | - -- -```YAML -- rendement: -flux de travail : données_de_processus -Arguments: -données d'entrée : _. données brutes # <-- expression Python -``` - - | -
| Error | --Handle errors by specifying an error message - - | - -- -```YAML -- erreur : « Entrée non valide fournie » # <-- Chaînes uniquement -``` - - | -
| Brave Search | -- -```YAML -installation: -api_key : chaîne # La clé API pour Brave Search - -Arguments: -requête : chaîne # La requête de recherche pour rechercher avec Brave - -sortir: -résultat : liste[dict] # Une liste de résultats de recherche, chacun contenant : titre, lien, extrait -``` - - | - -- -**Example cookbook**: [cookbooks/02-sarcastic-news-headline-generator.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/02-sarcastic-news-headline-generator.ipynb) - - | -
| BrowserBase | -- -```YAML -installation: -api_key : chaîne # La clé API pour BrowserBase -project_id : chaîne # L'ID de projet pour BrowserBase -session_id : chaîne # (facultatif) L'ID de session pour BrowserBase - -Arguments: -urls : liste[chaîne] # Les URL pour le chargement avec BrowserBase - -sortir: -documents : liste # Les documents chargés à partir des URL -``` - - | - -- -**Example cookbook**: [cookbooks/06-browser-use.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/06-browser-use.ipynb) - - | -
| - -```YAML -installation: -hôte : chaîne # L'hôte du serveur de messagerie -port : entier # Le port du serveur de messagerie -utilisateur : chaîne # Le nom d'utilisateur du serveur de messagerie -mot de passe : chaîne # Le mot de passe du serveur de messagerie - -Arguments: -à : chaîne # L'adresse e-mail à laquelle envoyer l'e-mail -de : chaîne # L'adresse e-mail à partir de laquelle envoyer l'e-mail -objet : chaîne # L'objet de l'e-mail -corps : chaîne # Le corps de l'e-mail - -sortir: -succès : booléen # Indique si l'e-mail a été envoyé avec succès -``` - - | - -- -**Example cookbook**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb) - - | -|
| Spider | -- -```YAML -installation: -spider_api_key : chaîne # La clé API pour Spider - -Arguments: -url : chaîne # L'URL pour laquelle récupérer les données -paramètres : dict # (facultatif) Les paramètres de l'API Spider -content_type : chaîne # (facultatif) Le type de contenu à renvoyer. La valeur par défaut est « application/json ». Autres options : « text/csv », « application/xml », « application/jsonl » - -sortir: -résultat : liste[dict] # Une liste de résultats, chacun contenant : contenu, erreur, statut, coûts, url -``` - - | - -- -**Example cookbook**: [cookbooks/01-website-crawler.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-website-crawler.ipynb) - - | -
| Weather | -- -```YAML -installation: -openweathermap_api_key : chaîne # La clé API pour OpenWeatherMap - -Arguments: -emplacement : chaîne # L'emplacement pour lequel récupérer les données météorologiques - -sortir: -résultat : chaîne # Les données météorologiques pour l'emplacement spécifié -``` - - | - -- -**Example cookbook**: [cookbooks/03-trip-planning-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-trip-planning-assistant.ipynb) - - | -
| Wikipedia | -- -```YAML -Arguments: -requête : chaîne # La chaîne de requête de recherche -load_max_docs : entier # (facultatif) Nombre maximal de documents à charger. La valeur par défaut est 2. - -sortir: -documents : liste # Les documents renvoyés par la recherche sur Wikipédia -``` - - | - -- -**Example cookbook**: [cookbooks/03-trip-planning-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-trip-planning-assistant.ipynb) - - | -
| FFmpeg | -- -```YAML -Arguments: -cmd : chaîne # La commande FFmpeg à exécuter -fichier : chaîne # Le fichier codé en base64 à traiter - -sortir: -fileoutput : chaîne # Le fichier de sortie de la commande FFmpeg en codage base64 -résultat : booléen # Si la commande FFmpeg a été exécutée avec succès -mime_type : chaîne # Le type MIME du fichier de sortie -``` - - | - -|
| Llama Parse | -
-
-```YAML
-installation:
-llamaparse_api_key: string # La clé API pour Llama Parse
-paramètres : dict # (facultatif) Paramètres supplémentaires pour l'intégration de Llama Parse
-
-Arguments:
-fichier : chaîne | tableau |
-- -**Example cookbook**: [cookbooks/07-personalized-research-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/07-personalized-research-assistant.ipynb) - - | -
| Cloudinary | -- -```YAML - -méthode : media_upload | media_edit # La méthode à utiliser pour l'intégration Cloudinary - -installation: -cloudinary_cloud_name : chaîne # Votre nom de cloud Cloudinary -cloudinary_api_key : chaîne # Votre clé API Cloudinary -cloudinary_api_secret : chaîne # Votre secret d'API Cloudinary -paramètres : dict # (facultatif) Paramètres supplémentaires pour l'intégration Cloudinary - -Arguments: -fichier : chaîne # L'URL du téléchargement du fichier. Disponible uniquement pour la méthode media_upload. -upload_params : dict # (facultatif) Paramètres supplémentaires pour le téléchargement. Disponible uniquement pour la méthode media_upload. -public_id : chaîne # (facultatif) L'ID public du fichier. Pour la méthode media_edit, il est OBLIGATOIRE. Pour la méthode media_upload, il est facultatif. La valeur par défaut est un UUID aléatoire. -transformation : list[dict] # Les transformations à appliquer au fichier. Disponible uniquement pour la méthode media_edit. -return_base64 : booléen # Indique si le fichier doit être renvoyé en codage base64. La valeur par défaut est false. - -sortir: -url : chaîne # L'URL du fichier téléchargé. Disponible uniquement pour la méthode media_upload. -meta_data : dict # Métadonnées supplémentaires provenant de la réponse de téléchargement. Disponible uniquement pour la méthode media_upload. -public_id : chaîne # L'ID public du fichier téléchargé. Disponible uniquement pour la méthode media_upload. -turned_url : chaîne # (facultatif) L'URL transformée. Disponible uniquement pour la méthode media_edit. -base64 : chaîne # (Facultatif) Le fichier codé en base64 si return_base64 est vrai. -``` - - | -- -**Example cookbook**: [cookbooks/05-video-processing-with-natural-language.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/05-video-processing-with-natural-language.ipynb) - - | -
| Arxiv | -- -```YAML -méthode : recherche # La méthode à utiliser pour l'intégration d'Arxiv - -installation: -# Aucun paramètre de configuration spécifique n'est requis pour Arxiv - -Arguments: -requête : chaîne # La requête de recherche pour la recherche avec Arxiv -id_list : liste[string] | None # (Facultatif) La liste des identifiants Arxiv à utiliser pour la recherche -max_results : entier # Le nombre maximal de résultats à renvoyer doit être compris entre 1 et 300 000 -download_pdf : booléen # S'il faut télécharger le PDF des résultats. La valeur par défaut est false. -sort_by : chaîne # Le critère de tri pour les résultats, options : relevance, lastUpdatedDate, submitDate -sort_order : chaîne # L'ordre de tri des résultats, options : croissant, décroissant - -sortir: -résultat : liste[dict] # Une liste de résultats de recherche, chacun contenant : entry_id, title, updated, published, authors, summary, comment, journal_ref, doi, primary_category, categories, links, pdf_url, pdf_downloaded -``` - - | - -- -**Example cookbook**: [cookbooks/07-personalized-research-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/07-personalized-research-assistant.ipynb) - - | -
-
-
----
-
-## Quelle est la différence entre Julep et LangChain etc ?
+## Documentation et exemples
-### Différents cas d'utilisation
-Considérez LangChain et Julep comme des outils avec des objectifs différents au sein de la pile de développement de l’IA.
+Vous voulez plonger plus profondément ? La **[Documentation Julep](https://docs.julep.ai)** couvre tout ce dont vous avez besoin pour maîtriser la plateforme - des concepts fondamentaux (Agents, Tâches, Sessions, Outils) aux sujets avancés comme la gestion de la mémoire des agents et les éléments internes de l'architecture. Les ressources clés incluent :
-LangChain est idéal pour créer des séquences d'invites et gérer les interactions avec les LLM. Il dispose d'un vaste écosystème avec de nombreuses intégrations prédéfinies, ce qui le rend pratique si vous souhaitez mettre en place quelque chose rapidement. LangChain s'adapte bien aux cas d'utilisation simples qui impliquent une chaîne linéaire d'invites et d'appels d'API.
+* **[Guides de concepts](https://docs.julep.ai/concepts/) :** Apprenez sur l'architecture de Julep, comment fonctionnent les sessions et la mémoire, l'utilisation d'outils, la gestion de longues conversations, et plus.
+* **[Référence API et SDK](https://docs.julep.ai/api-reference/) :** Trouvez une référence détaillée pour toutes les méthodes SDK et les points de terminaison de l'API REST pour intégrer Julep dans vos applications.
+* **[Tutoriels](https://docs.julep.ai/tutorials/) :** Guides étape par étape pour construire des applications réelles (ex. un agent de recherche qui parcourt le web, un assistant de planification de voyage, ou un chatbot avec des connaissances personnalisées).
+* **[Recettes de livre de cuisine](https://github.com/julep-ai/julep/tree/dev/cookbooks) :** Explorez le **Livre de cuisine Julep** pour des exemples de flux de travail et d'agents prêts à l'emploi. Ces recettes démontrent des modèles communs et des cas d'usage - un excellent moyen d'apprendre par l'exemple. *Parcourez le répertoire [`cookbooks/`](https://github.com/julep-ai/julep/tree/dev/cookbooks) dans ce dépôt pour des définitions d'agents d'exemple.*
+* **[Intégration IDE](https://context7.com/julep-ai/julep) :** Accédez à la documentation Julep directement dans votre IDE ! Parfait pour obtenir des réponses instantanées pendant que vous codez.
-Julep, en revanche, s'intéresse davantage à la création d'agents d'IA persistants capables de conserver le contexte lors d'interactions à long terme. Il est idéal lorsque vous avez besoin de flux de travail complexes impliquant des tâches en plusieurs étapes, une logique conditionnelle et une intégration avec divers outils ou API directement dans le processus de l'agent. Il est conçu dès le départ pour gérer les sessions persistantes et les flux de travail complexes.
+
-Utilisez Julep si vous imaginez créer un assistant IA complexe qui doit :
+## Communauté et contributions
-- Suivez les interactions des utilisateurs sur plusieurs jours ou semaines.
-- Exécutez des tâches planifiées, comme l'envoi de résumés quotidiens ou la surveillance de sources de données.
-- Prendre des décisions basées sur des interactions antérieures ou des données stockées.
-- Interagir avec plusieurs services externes dans le cadre de son flux de travail.
+Rejoignez notre communauté grandissante de développeurs et d'enthousiastes de l'IA ! Voici quelques façons de s'impliquer et d'obtenir du soutien :
-Ensuite, Julep fournit l’infrastructure pour prendre en charge tout cela sans que vous ayez à le construire à partir de zéro.
+* **Communauté Discord :** Vous avez des questions ou des idées ? Rejoignez la conversation sur notre [serveur Discord officiel](https://discord.gg/7H5peSN9QP) pour discuter avec l'équipe Julep et d'autres utilisateurs. Nous sommes heureux d'aider avec le dépannage ou de réfléchir à de nouveaux cas d'usage.
+* **Discussions et issues GitHub :** N'hésitez pas à utiliser GitHub pour signaler des bugs, demander des fonctionnalités, ou discuter des détails d'implémentation. Consultez les [**bonnes premières issues**](https://github.com/julep-ai/julep/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) si vous souhaitez contribuer - nous accueillons les contributions de toutes sortes.
+* **Contribuer :** Si vous voulez contribuer du code ou des améliorations, veuillez voir notre [Guide de contribution](CONTRIBUTING.md) pour comment commencer. Nous apprécions toutes les PR et les retours. En collaborant, nous pouvons rendre Julep encore meilleur !
-### Facteur de forme différent
+*Conseil de pro :
-
- ドキュメントを探索 (wip)
- ·
- 不和
- ·
- 𝕏
- ·
- リンクトイン
-
+ ·
+
+
+ | Name | -About | -Syntax | -
|---|---|---|
| Prompt | -
-Send a message to the AI model and receive a response
- Note: The prompt step uses Jinja templates and you can access context variables in them. - |
-
-- -```ヤム -- プロンプト: 「次のデータを分析してください: {{agent.name}}」 # <-- これは jinja テンプレートです -``` - -```ヤム -- プロンプト: -- 役割: システム -内容: 「あなたは {{agent.name}} です。 {{agent.about}}」 -- 役割: ユーザー -内容: 「次のデータを分析します: {{_.data}}」 -``` - - | -
| Tool Call | -
-Execute an integrated tool or API that you have previously declared in the task.
- Note: The tool call step uses Python expressions inside the arguments. - - |
-
-- -```ヤム -- ツール: web_search -引数: -クエリ: '"最新の AI 開発"' # <-- これは Python 式です (引用符に注意してください) -num_results: len(_.topics) # <-- リストの長さにアクセスするための Python 式 -``` - - | -
| Evaluate | -
-Perform calculations or manipulate data
- Note: The evaluate step uses Python expressions. - |
-
-- -```ヤム -- 評価する: -average_score: 合計(スコア) / 長さ(スコア) -``` - - | -
| Wait for Input | -
-Pause workflow until input is received. It accepts an `info` field that can be used by your application to collect input from the user.
-
- Note: The wait_for_input step is useful when you want to pause the workflow and wait for user input e.g. to collect a response to a prompt. - - |
-
-- -```ヤム -- 入力待ち: -情報: -メッセージ: '"{_.required_info} に関する追加情報を提供してください。"' # <-- コンテキスト変数にアクセスするための Python 式 -``` - - | -
| Log | -
-Log a specified value or message.
-
- Note: The log step uses Jinja templates and you can access context variables in them. - - |
-
-- -```ヤム -- ログ: "アイテム {{_.item_id}} の処理が完了しました" # <-- コンテキスト変数にアクセスするための jinja テンプレート -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Get | --Retrieve a value from the execution's key-value store. - - | - -- -```ヤム -- 取得: user_preference -``` - - | -
| Set | -
-Assign a value to a key in the execution's key-value store.
-
- Note: The set step uses Python expressions. - - |
-
-- -```ヤム -- セット: -user_preference: '"dark_mode"' # <-- python 式 -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Foreach | --Iterate over a collection and perform steps for each item - - | - -- -```ヤム -- 各: -in: _.data_list # <-- コンテキスト変数にアクセスするための Python 式 -する: -- ログ: "アイテム {{_.item}} を処理しています" # <-- コンテキスト変数にアクセスするための jinja テンプレート -``` - - | -
| Map-Reduce | --Map over a collection and reduce the results - - | -
+
-```ヤム
-- マップリデュース:
-over: _.numbers # <-- コンテキスト変数にアクセスするための Python 式
-地図:
-- 評価する:
-二乗: "_ ** 2"
-Reduce: 結果 + [_] # <-- (オプション) 結果を削減する Python 式。省略した場合、これがデフォルトになります。
-```
+## なぜJulepなのか?
-```ヤム
-- マップリデュース:
-以上: _.topics
-地図:
-- プロンプト: {{_}} に関するエッセイを書く
-並列度: 10
-```
+Julepは、単純なプロンプトのチェーンをはるかに超えた**エージェントベースのAIワークフロー**を構築するためのオープンソースプラットフォームです。大規模言語モデル(LLM)とツールを使用して複雑な多段階プロセスを**インフラストラクチャの管理なしに**オーケストレーションできます。Julepを使用すると、**過去のやり取りを記憶し**、分岐ロジック、ループ、並列実行、外部APIとの統合を備えた洗練されたタスクを処理するAIエージェントを作成できます。要するに、Julepは*「AIエージェントのためのFirebase」*として機能し、スケールでのインテリジェントワークフローのための堅牢なバックエンドを提供します。
- |
-
| Parallel | --Run multiple steps in parallel +**主要機能と利点:** - | +* **永続メモリ:** 会話を通じてコンテキストと長期記憶を維持するAIエージェントを構築し、時間をかけて学習と改善ができます。 +* **モジュラーワークフロー:** 条件ロジック、ループ、エラーハンドリングを備えたモジュラーステップとして複雑なタスクを定義します(YAMLまたはコード)。Julepのワークフローエンジンが多段階プロセスと決定を自動的に管理します。 +* **ツールオーケストレーション:** 外部ツールとAPI(Web検索、データベース、サードパーティサービスなど)をエージェントのツールキットの一部として簡単に統合します。Julepのエージェントはこれらのツールを呼び出して機能を拡張し、検索拡張生成などを可能にします。 +* **並列・スケーラブル:** 効率性のために複数の操作を並列で実行し、Julepにスケーリングと並行処理を任せます。プラットフォームはサーバーレスなので、追加のDevOpsオーバーヘッドなしにワークフローをシームレスにスケールします。 +* **信頼性のある実行:** 不具合を心配する必要はありません - Julepは組み込まれた再試行、自己修復ステップ、堅牢なエラーハンドリングを提供し、長時間実行タスクを軌道に乗せ続けます。また、進捗を追跡するためのリアルタイム監視とログも提供します。 +* **簡単な統合:** **Python**と**Node.js**向けのSDK、またはスクリプト用のJulep CLIですぐに始められます。他のシステムに直接統合したい場合は、JulepのREST APIが利用可能です。 -
+*AIロジックと創造性に集中し、重労働はJulepにお任せください!*
- |
-
| Name | About | Syntax | -
|---|---|---|
| If-Else | --Conditional execution of steps - - | - -- -```ヤム -- if: _.score > 0.8 # <-- Python 式 -それから: -- ログ: 高得点を達成 -それ以外: -- エラー: スコアの改善が必要です -``` - - | -
| Switch | --Execute steps based on multiple conditions - - | - -- -```ヤム -- スイッチ: -- ケース: _.category == 'A' -それから: -- ログ: 「カテゴリー A 処理」 -- ケース: _.category == 'B' -それから: -- ログ: 「カテゴリー B 処理」 -- case: _ # デフォルトのケース -それから: -- エラー: 不明なカテゴリ -``` - - | -
| Name | About | Syntax | -
|---|---|---|
| Sleep | --Pause the workflow for a specified duration - - | - -- -```ヤム -- 寝る: -秒: 30 -分数: 1 -時間数: 1 -日数: 1 -``` - - | -
| Return | -
-Return a value from the workflow
-
- Note: The return step uses Python expressions. - - |
-
-- -```ヤム -- 戻る: -結果: '"タスクは正常に完了しました"' # <-- Python 式 -time: datetime.now().isoformat() # <-- python 式 -``` - - | -
| Yield | --Run a subworkflow and await its completion - - | - -- -```ヤム -- 収率: -ワークフロー: process_data -引数: -input_data: _.raw_data # <-- Python式 -``` - - | -
| Error | --Handle errors by specifying an error message - - | - -- -```ヤム -- エラー:「無効な入力が提供されています」# <-- 文字列のみ -``` - - | -
| Brave Search | -- -```ヤム -設定: -api_key: 文字列 # Brave SearchのAPIキー - -引数: -query: 文字列 # Braveで検索するための検索クエリ - -出力: -result: list[dict] # 検索結果のリスト。それぞれにタイトル、リンク、スニペットが含まれます。 -``` - - | - -- -**Example cookbook**: [cookbooks/02-sarcastic-news-headline-generator.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/02-sarcastic-news-headline-generator.ipynb) - - | -
| BrowserBase | -- -```ヤム -設定: -api_key: 文字列 # BrowserBaseのAPIキー -project_id: 文字列 # BrowserBase のプロジェクト ID -session_id: 文字列 # (オプション) BrowserBaseのセッションID - -引数: -urls: list[string] # BrowserBaseで読み込むURL - -出力: -ドキュメント: リスト # URLから読み込まれたドキュメント -``` - - | - -- -**Example cookbook**: [cookbooks/06-browser-use.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/06-browser-use.ipynb) - - | -
| - -```ヤム -設定: -ホスト: 文字列 # メールサーバーのホスト -port: 整数 # メールサーバーのポート -user: 文字列 # メールサーバーのユーザー名 -パスワード: 文字列 # メールサーバーのパスワード - -引数: -to: 文字列 # メールを送信するメールアドレス -from: 文字列 # メールを送信するメールアドレス -subject: 文字列 # メールの件名 -body: 文字列 # メールの本文 - -出力: -success: boolean # メールが正常に送信されたかどうか -``` - - | - -- -**Example cookbook**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb) - - | -|
| Spider | -- -```ヤム -設定: -spider_api_key: 文字列 # SpiderのAPIキー - -引数: -url: 文字列 # データを取得するURL -params: dict # (オプション) Spider APIのパラメータ -content_type: 文字列 # (オプション) 返されるコンテンツ タイプ。デフォルトは「application/json」です。その他のオプション: 「text/csv」、「application/xml」、「application/jsonl」 - -出力: -result: list[dict] # 結果のリスト。それぞれにコンテンツ、エラー、ステータス、コスト、URLが含まれます。 -``` - - | - -- -**Example cookbook**: [cookbooks/01-website-crawler.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-website-crawler.ipynb) - - | -
| Weather | -- -```ヤム -設定: -openweathermap_api_key: 文字列 # OpenWeatherMapのAPIキー - -引数: -location: 文字列 # 気象データを取得する場所 - -出力: -結果: 文字列 # 指定された場所の天気データ -``` - - | - -- -**Example cookbook**: [cookbooks/03-trip-planning-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-trip-planning-assistant.ipynb) - - | -
| Wikipedia | -- -```ヤム -引数: -query: 文字列 # 検索クエリ文字列 -load_max_docs: 整数 # (オプション) ロードするドキュメントの最大数。デフォルトは 2 です。 - -出力: -ドキュメント: リスト # Wikipedia 検索から返されたドキュメント -``` - - | - -- -**Example cookbook**: [cookbooks/03-trip-planning-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-trip-planning-assistant.ipynb) - - | -
| FFmpeg | -- -```ヤム -引数: -cmd: 文字列 # 実行するFFmpegコマンド -file: 文字列 # 処理するbase64エンコードされたファイル - -出力: -fileoutput: 文字列 # FFmpeg コマンドからの出力ファイル(base64 エンコード) -結果: ブール値 # FFmpeg コマンドが正常に実行されたかどうか -mime_type: 文字列 # 出力ファイルのMIMEタイプ -``` - - | - -|
| Llama Parse | -
-
-```ヤム
-設定:
-llamaparse_api_key: string # Llama Parse の API キー
-params: dict # (オプション) Llama Parse 統合の追加パラメータ
-
-引数:
-ファイル: 文字列 | 配列 |
-- -**Example cookbook**: [cookbooks/07-personalized-research-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/07-personalized-research-assistant.ipynb) - - | -
| Cloudinary | -- -```ヤム - -method: media_upload | media_edit # Cloudinary統合に使用するメソッド - -設定: -cloudinary_cloud_name: 文字列 # Cloudinary クラウド名 -cloudinary_api_key: 文字列 # Cloudinary API キー -cloudinary_api_secret: 文字列 # Cloudinary API シークレット -params: dict # (オプション) Cloudinary統合の追加パラメータ - -引数: -file: 文字列 # ファイルのアップロード先の URL。media_upload メソッドでのみ使用できます。 -upload_params: dict # (オプション) アップロード用の追加パラメータ。media_upload メソッドでのみ使用できます。 -public_id: 文字列 # (オプション) ファイルのパブリック ID。media_edit メソッドの場合は必須です。media_upload メソッドの場合はオプションです。デフォルトはランダムな UUID です。 -transformation: list[dict] # ファイルに適用する変換。media_edit メソッドでのみ使用できます。 -return_base64: boolean # ファイルを base64 エンコードで返すかどうか。デフォルトは false です。 - -出力: -url: 文字列 # アップロードされたファイルの URL。media_upload メソッドでのみ使用できます。 -meta_data: dict # アップロード応答からの追加メタデータ。media_upload メソッドでのみ使用できます。 -public_id: 文字列 # アップロードされたファイルのパブリック ID。media_upload メソッドでのみ使用できます。 -transformed_url: 文字列 # (オプション) 変換された URL。media_edit メソッドでのみ使用できます。 -base64: 文字列 # (オプション) return_base64 が true の場合、base64 でエンコードされたファイル。 -``` - - | -- -**Example cookbook**: [cookbooks/05-video-processing-with-natural-language.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/05-video-processing-with-natural-language.ipynb) - - | -
| Arxiv | -- -```ヤム -method: search # Arxiv統合に使用するメソッド - -設定: -# Arxivには特別な設定パラメータは必要ありません - -引数: -query: 文字列 # Arxivで検索するための検索クエリ -id_list: list[string] | None # (オプション) 検索するArxiv IDのリスト -max_results: 整数 # 返される結果の最大数は 1 から 300000 の間でなければなりません -download_pdf: boolean # 結果の PDF をダウンロードするかどうか。デフォルトは false です。 -sort_by: 文字列 # 結果の並べ替え基準。オプション: 関連性、lastUpdatedDate、submittedDate -sort_order: 文字列 # 結果の並べ替え順序。オプション: 昇順、降順 - -出力: -result: list[dict] # 検索結果のリスト。それぞれに、entry_id、title、updated、published、authors、summary、comment、journal_ref、doi、primary_category、categories、links、pdf_url、pdf_downloaded が含まれます。 -``` - - | - -- -**Example cookbook**: [cookbooks/07-personalized-research-assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/07-personalized-research-assistant.ipynb) - - | -
+
+
-
-
-
----
-
-## Julep と LangChain などの違いは何ですか?
+## ドキュメントと例
-### さまざまなユースケース
-LangChain と Julep は、AI 開発スタック内で異なる重点を置いたツールと考えてください。
+さらに深く学びたいですか?**[Julepドキュメント](https://docs.julep.ai)**は、コアコンセプト(エージェント、タスク、セッション、ツール)から高度なトピック(エージェントメモリ管理やアーキテクチャの内部構造)まで、プラットフォームを習得するために必要なすべてをカバーしています。主要なリソースには以下があります:
-LangChain は、プロンプトのシーケンスを作成し、LLM とのやり取りを管理するのに最適です。多数の事前構築された統合を備えた大規模なエコシステムを備えているため、何かをすぐに起動して実行したい場合に便利です。LangChain は、プロンプトと API 呼び出しの線形チェーンを含む単純なユースケースに適しています。
+* **[コンセプトガイド](https://docs.julep.ai/concepts/):** Julepのアーキテクチャ、セッションとメモリの仕組み、ツールの使用、長い会話の管理などについて学びます。
+* **[API・SDK リファレンス](https://docs.julep.ai/api-reference/):** JulepをアプリケーションNに統合するためのすべてのSDKメソッドとREST APIエンドポイントの詳細なリファレンスを見つけます。
+* **[チュートリアル](https://docs.julep.ai/tutorials/):** 実際のアプリケーション構築のためのステップバイステップガイド(例:Webを検索するリサーチエージェント、旅行計画アシスタント、カスタム知識を持つチャットボット)。
+* **[クックブックレシピ](https://github.com/julep-ai/julep/tree/dev/cookbooks):** 既製のワークフローとエージェントの例については**Julep Cookbook**を探索してください。これらのレシピは一般的なパターンと使用例を示しています - 例から学ぶ素晴らしい方法です。*サンプルエージェント定義については、このリポジトリの[`cookbooks/`](https://github.com/julep-ai/julep/tree/dev/cookbooks)ディレクトリを参照してください。*
+* **[IDE統合](https://context7.com/julep-ai/julep):** IDE内でJulepドキュメントに直接アクセス!コーディング中に即座に答えを得るのに最適です。
-一方、Julep は、長期的なインタラクションでコンテキストを維持できる永続的な AI エージェントの構築に重点を置いています。複数ステップのタスク、条件付きロジック、エージェントのプロセス内で直接さまざまなツールや API との統合を伴う複雑なワークフローが必要な場合に効果を発揮します。永続的なセッションと複雑なワークフローを管理するために、ゼロから設計されています。
+
-以下のことが必要となる複雑な AI アシスタントの構築を考えている場合には、Julep を使用してください。
+## コミュニティと貢献
-- 数日または数週間にわたってユーザーのインタラクションを追跡します。
-- 毎日のサマリーの送信やデータ ソースの監視などのスケジュールされたタスクを実行します。
-- 以前のやり取りや保存されたデータに基づいて決定を下します。
-- ワークフローの一部として複数の外部サービスと対話します。
+成長する開発者とAI愛好家のコミュニティに参加しましょう!参加とサポートを得る方法をいくつか紹介します:
-そして、Julep は、ゼロから構築する必要なく、これらすべてをサポートするインフラストラクチャを提供します。
+* **Discordコミュニティ:** 質問やアイデアがありますか?[公式Discordサーバー](https://discord.gg/7H5peSN9QP)での会話に参加して、Julepチームや他のユーザーとチャットしましょう。トラブルシューティングのお手伝いや新しい使用例のブレインストーミングを喜んでサポートします。
+* **GitHub ディスカッションとイシュー:** バグ報告、機能要求、実装詳細の議論には、GitHubを自由にご利用ください。貢献したい場合は[**good first issues**](https://github.com/julep-ai/julep/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)をチェックしてください - あらゆる種類の貢献を歓迎します。
+* **貢献:** コードや改善を貢献したい場合は、始め方について[貢献ガイド](CONTRIBUTING.md)を参照してください。すべてのPRとフィードバックを感謝します。協力することで、Julepをさらに良くすることができます!
-### 異なるフォームファクタ
+*プロのヒント: | 🧠 | -Smart Memory | -Agents that remember context and learn from past interactions | -
| 🔄 | -Workflow Engine | -Build complex, multi-step processes with branching and loops | -
| ⚡ | -Parallel Processing | -Run multiple operations simultaneously for maximum efficiency | -
| 🛠️ | -Tool Integration | -Seamlessly connect with external APIs and services | -
| 🔌 | -Easy Setup | -Get started quickly with Python and Node.js SDKs | -
| 🔒 | -Reliable & Secure | -Built-in error handling, retries, and security features | -
| 📊 | -Monitoring | -Track task progress and performance in real-time | -
-Julep is made up of the following components: - -- **Julep Platform**: The Julep platform is a cloud service that runs your workflows. It includes a language for describing workflows, a server for running those workflows, and an SDK for interacting with the platform. -- **Julep SDKs**: Julep SDKs are a set of libraries for building workflows. There are SDKs for Python and JavaScript, with more on the way. -- **Julep CLI**: The Julep CLI is a command-line tool that allows you to interact with the Julep platform directly from your terminal. -- **Julep API**: The Julep API is a RESTful API that you can use to interact with the Julep platform. -
- --Think of Julep as a platform that combines both client-side and server-side components to help you build advanced AI agents. Here's how to visualize it: -1. **Your Application Code:** +## Why Julep? - - You can use the Julep SDK in your application to define agents, tasks, and workflows. - - The SDK provides functions and classes that make it easy to set up and manage these components. - - You can use the Julep CLI to interact with the Julep platform directly from your terminal. +Julep is an open-source platform for building **agent-based AI workflows** that go far beyond simple chains of prompts. It lets you orchestrate complex, multi-step processes with Large Language Models (LLMs) and tools **without managing any infrastructure**. With Julep, you can create AI agents that **remember past interactions** and handle sophisticated tasks with branching logic, loops, parallel execution, and integration of external APIs. In short, Julep acts like a *“Firebase for AI agents,”* providing a robust backend for intelligent workflows at scale. -2. **Julep Backend Service:** +**Key Features and Benefits:** - - The SDK communicates with the Julep backend over the network. - - The CLI communicates with the Julep backend via the SDK. - - The backend handles execution of tasks, maintains session state, stores documents, and orchestrates workflows. +* **Persistent Memory:** Build AI agents that maintain context and long-term memory across conversations, so they can learn and improve over time. +* **Modular Workflows:** Define complex tasks as modular steps (in YAML or code) with conditional logic, loops, and error handling. Julep’s workflow engine manages multi-step processes and decisions automatically. +* **Tool Orchestration:** Easily integrate external tools and APIs (web search, databases, third-party services, etc.) as part of your agent’s toolkit. Julep’s agents can invoke these tools to augment their capabilities, enabling Retrieval-Augmented Generation and more. +* **Parallel & Scalable:** Run multiple operations in parallel for efficiency, and let Julep handle scaling and concurrency under the hood. The platform is serverless, so it seamlessly scales workflows without extra devops overhead. +* **Reliable Execution:** Don’t worry about glitches – Julep provides built-in retries, self-healing steps, and robust error handling to keep long-running tasks on track. You also get real-time monitoring and logging to track progress. +* **Easy Integration:** Get started quickly with our SDKs for **Python** and **Node.js**, or use the Julep CLI for scripting. Julep’s REST API is available if you want to integrate directly into other systems. -3. **Integration with Tools and APIs:** - - Within your workflows, you can integrate external tools and services. - - The backend facilitates these integrations, so your agents can, for example, perform web searches, access databases, or call third-party APIs. -
+
----
-
-## 📦 Installation
-
--Julep CLI is a command-line tool that allows you to interact with the Julep platform directly from your terminal. It provides a convenient way to manage your AI workflows, tasks, and agents without needing to write code. -
-```bash -pip install julep-cli -``` - -For more details, check out the **[Julep CLI Documentation](https://docs.julep.ai/docs/julepcli/introduction)**. - -> [!NOTE] -> The CLI is currently in beta and available for Python only. Node.js support coming soon! - ---- - -## 🚀 Quick Start - -- -Imagine a Research AI agent that can do the following: - -1. **Take a topic**, -2. **Come up with 30 search queries** for that topic, -3. Perform those web **searches in parallel**, -4. **Summarize** the results, -5. Send the **summary to Discord**. - -
- -> [!NOTE] -> In Julep, this would be a single task under 80 lines of code and run fully managed all on its own. All of the steps are executed on Julep's own servers and you don't need to lift a finger. - -Here's a complete example of a task definition: - -```yaml -# yaml-language-server: $schema=https://raw.githubusercontent.com/julep-ai/julep/refs/heads/dev/schemas/create_task_request.json -name: Research Agent -description: A research assistant that can search the web and send the summary to Discord -######################################################## -####################### INPUT ########################## -######################################################## - -# Define the input schema for the task -input_schema: - type: object - properties: - topic: - type: string - description: The main topic to research - num_questions: - type: integer - description: The number of search queries to generate - -######################################################## -####################### TOOLS ########################## -######################################################## - -# Define the tools that the agent can use -tools: - - name: web_search - type: integration - integration: - provider: brave - setup: - api_key: "
-
- {{summary}}Research Summary for AI (Click to expand)
-
-> **Research Summary for AI**
->
-> ### Summary of Research Results on Artificial Intelligence (AI)
->
-> #### Introduction
->
-> The field of Artificial Intelligence (AI) has seen significant advancements in recent years, marked by the development of methods and technologies that enable machines to perceive their environment, learn from data, and make decisions. The primary focus of this summary is on the insights derived from various research findings related to AI.
->
-> #### Key Findings
->
-> 1. **Definition and Scope of AI**:
->
-> - AI is defined as a branch of computer science focused on creating systems that can perform tasks requiring human-like intelligence, including learning, reasoning, and problem-solving (Wikipedia).
-> - It encompasses various subfields, including machine learning, natural language processing, robotics, and computer vision.
->
-> 2. **Impact and Applications**:
->
-> - AI technologies are being integrated into numerous sectors, improving efficiency and productivity. Applications range from autonomous vehicles and healthcare diagnostics to customer service automation and financial forecasting (OpenAI).
-> - Google's commitment to making AI beneficial for everyone highlights its potential to significantly improve daily life by enhancing user experiences across various platforms (Google AI).
->
-> 3. **Ethical Considerations**:
->
-> - There is an ongoing discourse regarding the ethical implications of AI, including concerns about privacy, bias, and accountability in decision-making processes. The need for a framework that ensures the safe and responsible use of AI technologies is emphasized (OpenAI).
->
-> 4. **Learning Mechanisms**:
->
-> - AI systems utilize different learning mechanisms, such as supervised learning, unsupervised learning, and reinforcement learning. These methods allow AI to improve performance over time by learning from past experiences and data (Wikipedia).
-> - The distinction between supervised and unsupervised learning is critical; supervised learning relies on labeled data, while unsupervised learning identifies patterns without predefined labels (Unsupervised).
->
-> 5. **Future Directions**:
-> - Future AI developments are expected to focus on enhancing the interpretability and transparency of AI systems, ensuring that they can provide justifiable decisions and actions (OpenAI).
-> - There is also a push towards making AI systems more accessible and user-friendly, encouraging broader adoption across different demographics and industries (Google AI).
->
-> #### Conclusion
->
-> AI represents a transformative force across multiple domains, promising to reshape industries and improve quality of life. However, as its capabilities expand, it is crucial to address the ethical and societal implications that arise. Continued research and collaboration among technologists, ethicists, and policymakers will be essential in navigating the future landscape of AI.
-
-
**Python:** `pip install julep`
+ *
**Node.js:** `npm install @julep/sdk` (or `yarn add @julep/sdk`)
+3. **Define Your Agent:** Use the SDK or YAML to define an agent and its task workflow. For example, you can specify the agent’s memory, tools it can use, and a step-by-step task logic. (See the **[Quick Start](https://docs.julep.ai/introduction/quick-start)** in our docs for a detailed walkthrough.)
+4. **Run a Workflow:** Invoke your agent through the SDK to execute the task. The Julep platform will orchestrate the entire workflow in the cloud and manage the state, tool calls, and LLM interactions for you. You can check the agent’s output, monitor the execution on the dashboard, and iterate as needed.
-This command generates a JWT token that will be valid for 10 days.
+That’s it! Your first AI agent can be up and running in minutes. For a complete tutorial, check out the **[Quick Start Guide](https://docs.julep.ai/introduction/quick-start)** in the documentation.
-### 6. Interaction
+> **Note:** Julep also offers a command-line interface (CLI) (currently in beta for Python) to manage workflows and agents. If you prefer a no-code approach or want to script common tasks, see the [Julep CLI docs](https://docs.julep.ai/responses/quickstart#cli-installation) for details.
-- **Temporal UI**: You can access the Temporal UI through the specified port in your `.env` file.
-- **Julep SDK**: The Julep SDK is a Python/Node.js library that allows you to interact with the Julep API.
-```python
-from julep import Client
-client = Client(api_key="your_jwt_token")
-```
+## Documentation and Examples
-**Note:** SDK in Multi-Tenant mode, you need to generate a JWT token locally that acts as an API KEY to interact with the SDK. Furthermore, while initializing the client you will need to set the environment to `local_multi_tenant` and the api key to the JWT token you generated in the previous step. Whereas in Single-Tenant mode you can interact with the SDK directly without the need for the API KEY and set the environment to `local`.
-### 7. Troubleshooting
+Looking to dive deeper? The **[Julep Documentation](https://docs.julep.ai)** covers everything you need to master the platform – from core concepts (Agents, Tasks, Sessions, Tools) to advanced topics like agent memory management and architecture internals. Key resources include:
-- 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.
+* **[Concept Guides](https://docs.julep.ai/concepts/):** Learn about Julep’s architecture, how sessions and memory work, using tools, managing long conversations, and more.
+* **[API & SDK Reference](https://docs.julep.ai/api-reference/):** Find detailed reference for all SDK methods and REST API endpoints to integrate Julep into your applications.
+* **[Tutorials](https://docs.julep.ai/tutorials/):** Step-by-step guides for building real applications (e.g. a research agent that searches the web, a trip-planning assistant, or a chatbot with custom knowledge).
+* **[Cookbook Recipes](https://github.com/julep-ai/julep/tree/dev/cookbooks):** Explore the **Julep Cookbook** for ready-made example workflows and agents. These recipes demonstrate common patterns and use cases – a great way to learn by example. *Browse the [`cookbooks/`](https://github.com/julep-ai/julep/tree/dev/cookbooks) directory in this repository for sample agent definitions.*
+* **[IDE Integration](https://context7.com/julep-ai/julep):** Access Julep documentation directly in your IDE! Perfect for getting instant answers while coding.
----
-## 👥 Contributors
-Join Our Community! 🌟
+## Community and Contributions
-We're excited to welcome new contributors to the Julep project! We've created several "good first issues" to help you get started.
+Join our growing community of developers and AI enthusiasts! Here are some ways to get involved and get support:
-How to Contribute:
+* **Discord Community:** Have questions or ideas? Join the conversation on our [official Discord server](https://discord.gg/7H5peSN9QP) to chat with the Julep team and other users. We’re happy to help with troubleshooting or brainstorm new use cases.
+* **GitHub Discussions and Issues:** Feel free to use GitHub for reporting bugs, requesting features, or discussing implementation details. Check out the [**good first issues**](https://github.com/julep-ai/julep/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) if you’d like to contribute – we welcome contributions of all kinds.
+* **Contributing:** If you want to contribute code or improvements, please see our [Contributing Guide](.github/CONTRIBUTING.md) for how to get started. We appreciate all PRs and feedback. By collaborating, we can make Julep even better!
-1. 📖 Check out our [CONTRIBUTING.md](https://github.com/julep-ai/julep/blob/dev/CONTRIBUTING.md) file for guidelines
-2. 🔍 Browse our [good first issues](https://github.com/julep-ai/julep/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
-3. 💬 Join our [Discord](https://discord.com/invite/JTSBGRZrzj) for help and discussions
+*Pro tip: Star our repo to stay updated – we’re constantly adding new features and examples.*
-Your contributions, big or small, are valuable to us. Let's build something amazing together! 🚀
+Your contributions, big or small, are valuable to us. Let's build something amazing together!
+
Our Amazing Contributors:
@@ -649,12 +139,8 @@ Your contributions, big or small, are valuable to us. Let's build something amaz
----
-
-## 📄 License
-
-Julep is licensed under the [Apache License 2.0](LICENSE).
+
-See the LICENSE file for more details.
+## License
----
+Julep is offered under the **Apache 2.0 License**, which means it’s free to use in your own projects. See the [LICENSE](.github/LICENSE) file for details. Enjoy building with Julep!
diff --git a/agents-api/CLAUDE.md b/agents-api/CLAUDE.md
deleted file mode 100644
index 5577b7046..000000000
--- a/agents-api/CLAUDE.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Julep Agents API
-
-## Service Overview
-- FastAPI-based service for orchestrating agent workflows
-- Handles tasks, executions, sessions, and tools
-- Temporal-based workflow engine for task execution
-- PostgreSQL for data storage
-- S3 for remote object storage
-
-## Architecture
-- REST API (defined in routers/)
-- Database queries (queries/)
-- Workflow definitions (workflows/)
-- Task activities (activities/)
-- Background worker processing (worker/)
-- Common utilities and protocol definitions (common/)
-
-## Key Concepts
-- Tasks: Workflow specifications with steps and tools
-- Executions: Running instances of tasks
-- Sessions: User interaction contexts
-- Agents: LLM-based interfaces for users
-- Tools: Integrations and capabilities usable by agents
-
-## Runtime Flow
-- User defines tasks with step definitions
-- Task execution creates workflow in Temporal
-- Activities run individual steps (prompt, tool calls, etc.)
-- Transitions track execution state
-- Results stored in database, retrievable via API
-
-## Expression Evaluation
-- Task steps use Python expressions for logic/data flow
-- Expressions prefixed with '$' executed in sandbox
-- Backward compatibility: '{{variable}}' → '${variable}'
-- Input context: '_' holds current input, 'inputs' and 'outputs' for history
-
-## Validation
-- Expression validation checks syntax, undefined names, unsafe operations
-- Task validation checks all expressions in workflow steps
-- Security: Sandbox with limited function/module access
\ No newline at end of file
diff --git a/agents-api/agents_api/activities/task_steps/pg_query_step.py b/agents-api/agents_api/activities/task_steps/pg_query_step.py
deleted file mode 100644
index a681e05d4..000000000
--- a/agents-api/agents_api/activities/task_steps/pg_query_step.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from typing import Any
-
-from beartype import beartype
-from temporalio import activity
-
-from ... import queries
-from ...app import app
-from ...env import pg_dsn
-
-
-@activity.defn
-@beartype
-async def pg_query_step(
- query_name: str,
- values: dict[str, Any],
- dsn: str = pg_dsn,
-) -> Any:
- (module_name, name) = query_name.split(".")
-
- module = getattr(queries, module_name)
- query = getattr(module, name)
- return await query(**values, connection_pool=app.state.postgres_pool)
diff --git a/agents-api/agents_api/queries/agents/create_agent.py b/agents-api/agents_api/queries/agents/create_agent.py
deleted file mode 100644
index a7b4e49f1..000000000
--- a/agents-api/agents_api/queries/agents/create_agent.py
+++ /dev/null
@@ -1,102 +0,0 @@
-"""
-This module contains the functionality for creating agents in the PostgreSQL database.
-It includes functions to construct and execute SQL queries for inserting new agent records.
-"""
-
-from uuid import UUID
-
-from beartype import beartype
-from uuid_extensions import uuid7
-
-from ...autogen.openapi_model import Agent, CreateAgentRequest
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import generate_canonical_name, pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query
-agent_query = """
-INSERT INTO agents (
- developer_id,
- agent_id,
- canonical_name,
- name,
- about,
- instructions,
- model,
- metadata,
- default_settings,
- default_system_template
-)
-VALUES (
- $1,
- $2,
- $3,
- $4,
- $5,
- $6,
- $7,
- $8,
- $9,
- $10
-)
-RETURNING *;
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("agent", ["create"]))
-@wrap_in_class(
- Agent,
- one=True,
- transform=lambda d: {**d, "id": d["agent_id"]},
-)
-@query_metrics("create_agent")
-@pg_query
-@beartype
-async def create_agent(
- *,
- developer_id: UUID,
- agent_id: UUID | None = None,
- data: CreateAgentRequest,
-) -> tuple[str, list]:
- """
- Constructs and executes a SQL query to create a new agent in the database.
-
- Parameters:
- agent_id (UUID | None): The unique identifier for the agent.
- developer_id (UUID): The unique identifier for the developer creating the agent.
- data (CreateAgentRequest): The data for the new agent.
-
- Returns:
- tuple[str, dict]: SQL query and parameters for creating the agent.
- """
- agent_id = agent_id or uuid7()
-
- # Ensure instructions is a list
- data.instructions = (
- data.instructions if isinstance(data.instructions, list) else [data.instructions]
- )
-
- # Convert default_settings to dict if it exists
- default_settings = data.default_settings or {}
-
- # Set default values
- data.metadata = data.metadata or {}
- data.canonical_name = data.canonical_name or generate_canonical_name()
-
- params = [
- developer_id,
- agent_id,
- data.canonical_name,
- data.name,
- data.about,
- data.instructions,
- data.model,
- data.metadata,
- default_settings,
- data.default_system_template,
- ]
-
- return (
- agent_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/agents/create_or_update_agent.py b/agents-api/agents_api/queries/agents/create_or_update_agent.py
deleted file mode 100644
index 6be94e1b2..000000000
--- a/agents-api/agents_api/queries/agents/create_or_update_agent.py
+++ /dev/null
@@ -1,117 +0,0 @@
-"""
-This module contains the functionality for creating or updating agents in the PostgreSQL database.
-It constructs and executes SQL queries to insert a new agent or update an existing agent's details based on agent ID and developer ID.
-"""
-
-from uuid import UUID
-
-from beartype import beartype
-
-from ...autogen.openapi_model import Agent, CreateOrUpdateAgentRequest
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import generate_canonical_name, pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query
-agent_query = """
-WITH existing_agent AS (
- SELECT canonical_name
- FROM agents
- WHERE developer_id = $1 AND agent_id = $2
-)
-INSERT INTO agents (
- developer_id,
- agent_id,
- canonical_name,
- name,
- about,
- instructions,
- model,
- metadata,
- default_settings,
- default_system_template
-)
-VALUES (
- $1, -- developer_id
- $2, -- agent_id
- COALESCE( -- canonical_name
- (SELECT canonical_name FROM existing_agent),
- $3
- ),
- $4, -- name
- $5, -- about
- $6, -- instructions
- $7, -- model
- $8, -- metadata
- $9, -- default_settings
- $10 -- default_system_template
-)
-ON CONFLICT (developer_id, agent_id) DO UPDATE SET
- canonical_name = EXCLUDED.canonical_name,
- name = EXCLUDED.name,
- about = EXCLUDED.about,
- instructions = EXCLUDED.instructions,
- model = EXCLUDED.model,
- metadata = EXCLUDED.metadata,
- default_settings = EXCLUDED.default_settings,
- default_system_template = EXCLUDED.default_system_template
-RETURNING *;
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("agent", ["create", "update"]))
-@wrap_in_class(
- Agent,
- one=True,
- transform=lambda d: {**d, "id": d["agent_id"]},
-)
-@query_metrics("create_or_update_agent")
-@pg_query
-@beartype
-async def create_or_update_agent(
- *,
- agent_id: UUID,
- developer_id: UUID,
- data: CreateOrUpdateAgentRequest,
-) -> tuple[str, list]:
- """
- Constructs the SQL queries to create a new agent or update an existing agent's details.
-
- Args:
- agent_id (UUID): The UUID of the agent to create or update.
- developer_id (UUID): The UUID of the developer owning the agent.
- agent_data (Dict[str, Any]): A dictionary containing agent fields to insert or update.
-
- Returns:
- tuple[list[str], dict]: A tuple containing the list of SQL queries and their parameters.
- """
-
- # Ensure instructions is a list
- data.instructions = (
- data.instructions if isinstance(data.instructions, list) else [data.instructions]
- )
-
- # Convert default_settings to dict if it exists
- default_settings = data.default_settings or {}
-
- # Set default values
- data.metadata = data.metadata or {}
- data.canonical_name = data.canonical_name or generate_canonical_name()
-
- params = [
- developer_id,
- agent_id,
- data.canonical_name,
- data.name,
- data.about,
- data.instructions,
- data.model,
- data.metadata,
- default_settings,
- data.default_system_template,
- ]
-
- return (
- agent_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/agents/patch_agent.py b/agents-api/agents_api/queries/agents/patch_agent.py
deleted file mode 100644
index 940a2b34d..000000000
--- a/agents-api/agents_api/queries/agents/patch_agent.py
+++ /dev/null
@@ -1,98 +0,0 @@
-"""
-This module contains the functionality for partially updating an agent in the PostgreSQL database.
-It constructs and executes SQL queries to update specific fields of an agent based on agent ID and developer ID.
-"""
-
-from uuid import UUID
-
-from beartype import beartype
-
-from ...autogen.openapi_model import Agent, PatchAgentRequest
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query
-agent_query = """
-UPDATE agents
-SET
- name = CASE
- WHEN $3::text IS NOT NULL THEN $3
- ELSE name
- END,
- about = CASE
- WHEN $4::text IS NOT NULL THEN $4
- ELSE about
- END,
- metadata = CASE
- WHEN $5::jsonb IS NOT NULL THEN metadata || $5
- ELSE metadata
- END,
- model = CASE
- WHEN $6::text IS NOT NULL THEN $6
- ELSE model
- END,
- default_settings = CASE
- WHEN $7::jsonb IS NOT NULL THEN $7
- ELSE default_settings
- END,
- default_system_template = CASE
- WHEN $8::text IS NOT NULL THEN $8
- ELSE default_system_template
- END,
- instructions = CASE
- WHEN $9::text[] IS NOT NULL THEN $9
- ELSE instructions
- END,
- canonical_name = CASE
- WHEN $10::citext IS NOT NULL THEN $10
- ELSE canonical_name
- END
-WHERE agent_id = $2 AND developer_id = $1
-RETURNING *;
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("agent", ["patch"]))
-@wrap_in_class(
- Agent,
- one=True,
- transform=lambda d: {**d, "id": d["agent_id"]},
-)
-@query_metrics("patch_agent")
-@pg_query
-@beartype
-async def patch_agent(
- *,
- agent_id: UUID,
- developer_id: UUID,
- data: PatchAgentRequest,
-) -> tuple[str, list]:
- """
- Constructs the SQL query to partially update an agent's details.
-
- Args:
- agent_id (UUID): The UUID of the agent to update.
- developer_id (UUID): The UUID of the developer owning the agent.
- data (PatchAgentRequest): A dictionary of fields to update.
-
- Returns:
- tuple[str, list]: A tuple containing the SQL query and its parameters.
- """
- params = [
- developer_id,
- agent_id,
- data.name,
- data.about,
- data.metadata,
- data.model,
- data.default_settings,
- data.default_system_template,
- [data.instructions] if isinstance(data.instructions, str) else data.instructions,
- data.canonical_name,
- ]
-
- return (
- agent_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/agents/update_agent.py b/agents-api/agents_api/queries/agents/update_agent.py
deleted file mode 100644
index efc18fef7..000000000
--- a/agents-api/agents_api/queries/agents/update_agent.py
+++ /dev/null
@@ -1,70 +0,0 @@
-"""
-This module contains the functionality for fully updating an agent in the PostgreSQL database.
-It constructs and executes SQL queries to replace an agent's details based on agent ID and developer ID.
-"""
-
-from uuid import UUID
-
-from beartype import beartype
-
-from ...autogen.openapi_model import Agent, UpdateAgentRequest
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query
-agent_query = """
-UPDATE agents
-SET
- metadata = $3,
- name = $4,
- about = $5,
- model = $6,
- default_settings = $7::jsonb,
- default_system_template = $8
-WHERE agent_id = $2 AND developer_id = $1
-RETURNING *;
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("agent", ["update"]))
-@wrap_in_class(
- Agent,
- one=True,
- transform=lambda d: {**d, "id": d["agent_id"]},
-)
-@query_metrics("update_agent")
-@pg_query
-@beartype
-async def update_agent(
- *,
- agent_id: UUID,
- developer_id: UUID,
- data: UpdateAgentRequest,
-) -> tuple[str, list]:
- """
- Constructs the SQL query to fully update an agent's details.
-
- Args:
- agent_id (UUID): The UUID of the agent to update.
- developer_id (UUID): The UUID of the developer owning the agent.
- data (UpdateAgentRequest): A dictionary containing all agent fields to update.
-
- Returns:
- tuple[str, list]: A tuple containing the SQL query and its parameters.
- """
- params = [
- developer_id,
- agent_id,
- data.metadata or {},
- data.name,
- data.about,
- data.model,
- data.default_settings or {},
- data.default_system_template,
- ]
-
- return (
- agent_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/users/create_or_update_user.py b/agents-api/agents_api/queries/users/create_or_update_user.py
deleted file mode 100644
index 48c62af3a..000000000
--- a/agents-api/agents_api/queries/users/create_or_update_user.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from uuid import UUID
-
-from beartype import beartype
-
-from ...autogen.openapi_model import CreateOrUpdateUserRequest, User
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query for creating or updating a user
-user_query = """
-INSERT INTO users (
- developer_id,
- user_id,
- name,
- about,
- metadata
-)
-VALUES (
- $1, -- developer_id
- $2, -- user_id
- $3, -- name
- $4, -- about
- $5::jsonb -- metadata
-)
-ON CONFLICT (developer_id, user_id) DO UPDATE SET
- name = EXCLUDED.name,
- about = EXCLUDED.about,
- metadata = EXCLUDED.metadata
-RETURNING *;
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("user", ["create_or_update"]))
-@wrap_in_class(
- User,
- one=True,
- transform=lambda d: {
- **d,
- "id": d["user_id"],
- },
-)
-@query_metrics("create_or_update_user")
-@pg_query
-@beartype
-async def create_or_update_user(
- *,
- developer_id: UUID,
- user_id: UUID,
- data: CreateOrUpdateUserRequest,
-) -> tuple[str, list]:
- """
- Constructs an SQL query to create or update a user.
-
- Args:
- developer_id (UUID): The UUID of the developer.
- user_id (UUID): The UUID of the user.
- data (CreateOrUpdateUserRequest): The user data to insert or update.
-
- Returns:
- tuple[str, list]: SQL query and parameters.
-
- Raises:
- HTTPException: If developer doesn't exist (404) or on unique constraint violation (409)
- """
- params = [
- developer_id, # $1
- user_id, # $2
- data.name, # $3
- data.about, # $4
- data.metadata or {}, # $5
- ]
-
- return (
- user_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/users/create_user.py b/agents-api/agents_api/queries/users/create_user.py
deleted file mode 100644
index e8f3aa986..000000000
--- a/agents-api/agents_api/queries/users/create_user.py
+++ /dev/null
@@ -1,74 +0,0 @@
-from uuid import UUID
-
-from beartype import beartype
-from uuid_extensions import uuid7
-
-from ...autogen.openapi_model import CreateUserRequest, User
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query outside the function
-user_query = """
-INSERT INTO users (
- developer_id,
- user_id,
- name,
- about,
- metadata
-)
-VALUES (
- $1, -- developer_id
- $2, -- user_id
- $3, -- name
- $4, -- about
- $5::jsonb -- metadata
-)
-RETURNING *;
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("user", ["create"]))
-@wrap_in_class(
- User,
- one=True,
- transform=lambda d: {
- **d,
- "id": d["user_id"],
- },
-)
-@query_metrics("create_user")
-@pg_query
-@beartype
-async def create_user(
- *,
- developer_id: UUID,
- user_id: UUID | None = None,
- data: CreateUserRequest,
-) -> tuple[str, list]:
- """
- Constructs the SQL query to create a new user.
-
- Args:
- developer_id (UUID): The UUID of the developer creating the user.
- user_id (UUID, optional): The UUID for the new user. If None, one will be generated.
- data (CreateUserRequest): The user data to insert.
-
- Returns:
- tuple[str, list]: A tuple containing the SQL query and its parameters.
- """
- user_id = user_id or uuid7()
- metadata = data.metadata or {}
-
- params = [
- developer_id, # $1
- user_id, # $2
- data.name, # $3
- data.about, # $4
- metadata, # $5
- ]
-
- return (
- user_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/users/patch_user.py b/agents-api/agents_api/queries/users/patch_user.py
deleted file mode 100644
index 9bd0d3cea..000000000
--- a/agents-api/agents_api/queries/users/patch_user.py
+++ /dev/null
@@ -1,80 +0,0 @@
-from uuid import UUID
-
-from beartype import beartype
-
-from ...autogen.openapi_model import PatchUserRequest, User
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query outside the function
-user_query = """
-UPDATE users
-SET
- name = CASE
- WHEN $3::text IS NOT NULL THEN $3 -- name
- ELSE name
- END,
- about = CASE
- WHEN $4::text IS NOT NULL THEN $4 -- about
- ELSE about
- END,
- metadata = CASE
- WHEN $5::jsonb IS NOT NULL THEN metadata || $5 -- metadata
- ELSE metadata
- END
-WHERE developer_id = $1
-AND user_id = $2
-RETURNING
- user_id as id, -- user_id
- developer_id, -- developer_id
- name, -- name
- about, -- about
- metadata, -- metadata
- created_at, -- created_at
- updated_at; -- updated_at
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("user", ["patch"]))
-@wrap_in_class(
- User,
- one=True,
- transform=lambda d: {
- **d,
- "id": d["id"],
- },
-)
-@query_metrics("patch_user")
-@pg_query
-@beartype
-async def patch_user(
- *,
- developer_id: UUID,
- user_id: UUID,
- data: PatchUserRequest,
-) -> tuple[str, list]:
- """
- Constructs an optimized SQL query for partial user updates.
- Uses primary key for efficient update and jsonb_merge for metadata.
-
- Args:
- developer_id (UUID): The developer's UUID
- user_id (UUID): The user's UUID
- data (PatchUserRequest): Partial update data
-
- Returns:
- tuple[str, list]: SQL query and parameters
- """
- params = [
- developer_id, # $1
- user_id, # $2
- data.name, # $3. Will be NULL if not provided
- data.about, # $4. Will be NULL if not provided
- data.metadata, # $5. Will be NULL if not provided
- ]
-
- return (
- user_query,
- params,
- )
diff --git a/agents-api/agents_api/queries/users/update_user.py b/agents-api/agents_api/queries/users/update_user.py
deleted file mode 100644
index d84f99217..000000000
--- a/agents-api/agents_api/queries/users/update_user.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from uuid import UUID
-
-from beartype import beartype
-
-from ...autogen.openapi_model import UpdateUserRequest, User
-from ...common.utils.db_exceptions import common_db_exceptions
-from ...metrics.counters import query_metrics
-from ..utils import pg_query, rewrap_exceptions, wrap_in_class
-
-# Define the raw SQL query outside the function
-user_query = """
-UPDATE users
-SET
- name = $3, -- name
- about = $4, -- about
- metadata = $5 -- metadata
-WHERE developer_id = $1 -- developer_id
-AND user_id = $2 -- user_id
-RETURNING *
-"""
-
-
-@rewrap_exceptions(common_db_exceptions("user", ["update"]))
-@wrap_in_class(
- User,
- one=True,
- transform=lambda d: {
- **d,
- "id": d["user_id"],
- },
-)
-@query_metrics("update_user")
-@pg_query
-@beartype
-async def update_user(
- *,
- developer_id: UUID,
- user_id: UUID,
- data: UpdateUserRequest,
-) -> tuple[str, list]:
- """
- Constructs an optimized SQL query to update a user's details.
- Uses primary key for efficient update.
-
- Args:
- developer_id (UUID): The developer's UUID
- user_id (UUID): The user's UUID
- data (UpdateUserRequest): Updated user data
-
- Returns:
- tuple[str, list]: SQL query and parameters
- """
- params = [
- developer_id,
- user_id,
- data.name,
- data.about,
- data.metadata or {},
- ]
-
- return (
- user_query,
- params,
- )
diff --git a/agents-api/agents_api/routers/sessions/chat.py b/agents-api/agents_api/routers/sessions/chat.py
deleted file mode 100644
index 21f0de8f0..000000000
--- a/agents-api/agents_api/routers/sessions/chat.py
+++ /dev/null
@@ -1,132 +0,0 @@
-from typing import Annotated, Any
-from uuid import UUID
-
-from fastapi import BackgroundTasks, Depends, Header
-from starlette.status import HTTP_201_CREATED
-from uuid_extensions import uuid7
-
-from ...autogen.openapi_model import (
- ChatInput,
- ChatResponse,
- ChunkChatResponse,
- CreateEntryRequest,
- MessageChatResponse,
-)
-from ...clients import litellm
-from ...common.protocol.developers import Developer
-from ...common.utils.datetime import utcnow
-from ...dependencies.developer_id import get_developer_data
-from ...queries.entries.create_entries import create_entries
-from .metrics import total_tokens_per_user
-from .render import render_chat_input
-from .router import router
-
-COMPUTER_USE_BETA_FLAG = "computer-use-2024-10-22"
-
-
-@router.post(
- "/sessions/{session_id}/chat",
- status_code=HTTP_201_CREATED,
- tags=["sessions", "chat"],
-)
-async def chat(
- developer: Annotated[Developer, Depends(get_developer_data)],
- session_id: UUID,
- chat_input: ChatInput,
- background_tasks: BackgroundTasks,
- x_custom_api_key: str | None = Header(None, alias="X-Custom-Api-Key"),
- connection_pool: Any = None, # FIXME: Placeholder that should be removed
-) -> ChatResponse:
- """
- Initiates a chat session.
-
- Parameters:
- developer (Developer): The developer associated with the chat session.
- session_id (UUID): The unique identifier of the chat session.
- chat_input (ChatInput): The chat input data.
- background_tasks (BackgroundTasks): The background tasks to run.
- x_custom_api_key (Optional[str]): The custom API key.
-
- Returns:
- ChatResponse: The chat response.
- """
- (
- messages,
- doc_references,
- formatted_tools,
- settings,
- new_messages,
- chat_context,
- ) = await render_chat_input(
- developer=developer,
- session_id=session_id,
- chat_input=chat_input,
- )
-
- # Use litellm for other models
- params = {
- "messages": messages,
- "tools": formatted_tools or None,
- "user": str(developer.id),
- "tags": developer.tags,
- "custom_api_key": x_custom_api_key,
- }
- payload = {**settings, **params}
-
- model_response = await litellm.acompletion(**payload)
-
- # Save the input and the response to the session history
- if chat_input.save:
- new_entries = [
- CreateEntryRequest.from_model_input(
- model=settings["model"],
- **msg,
- source="api_request",
- )
- for msg in new_messages
- ]
-
- # Add the response to the new entries
- # FIXME: We need to save all the choices
- new_entries.append(
- CreateEntryRequest.from_model_input(
- model=settings["model"],
- **model_response.choices[0].model_dump()["message"],
- source="api_response",
- ),
- )
- background_tasks.add_task(
- create_entries,
- developer_id=developer.id,
- session_id=session_id,
- data=new_entries,
- )
-
- # Adaptive context handling
- jobs = []
- if chat_context.session.context_overflow == "adaptive":
- # FIXME: Start the adaptive context workflow
- # SCRUM-8
-
- # jobs = [await start_adaptive_context_workflow]
- msg = "Adaptive context is not yet implemented"
- raise NotImplementedError(msg)
-
- # Return the response
- # FIXME: Implement streaming for chat
- chat_response_class = ChunkChatResponse if chat_input.stream else MessageChatResponse
-
- chat_response: ChatResponse = chat_response_class(
- id=uuid7(),
- created_at=utcnow(),
- jobs=jobs,
- docs=doc_references,
- usage=model_response.usage.model_dump(),
- choices=[choice.model_dump() for choice in model_response.choices],
- )
-
- total_tokens_per_user.labels(str(developer.id)).inc(
- amount=chat_response.usage.total_tokens if chat_response.usage is not None else 0,
- )
-
- return chat_response
diff --git a/agents-api/agents_api/routers/utils/model_validation.py b/agents-api/agents_api/routers/utils/model_validation.py
deleted file mode 100644
index 5b5b56f46..000000000
--- a/agents-api/agents_api/routers/utils/model_validation.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from fastapi import HTTPException
-from starlette.status import HTTP_400_BAD_REQUEST
-
-from ...clients.litellm import get_model_list
-
-
-async def validate_model(model_name: str | None) -> None:
- """
- Validates if a given model name is available in LiteLLM.
- Raises HTTPException if model is not available.
- """
- models = await get_model_list()
- available_models = [model["id"] for model in models]
-
- if model_name not in available_models:
- raise HTTPException(
- status_code=HTTP_400_BAD_REQUEST,
- detail=f"Model {model_name} not available. Available models: {available_models}",
- )
diff --git a/agents-api/tests/test_agent_queries.py b/agents-api/tests/test_agent_queries.py
deleted file mode 100644
index a70a9778a..000000000
--- a/agents-api/tests/test_agent_queries.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# Tests for agent queries
-
-from agents_api.autogen.openapi_model import (
- Agent,
- CreateAgentRequest,
- CreateOrUpdateAgentRequest,
- PatchAgentRequest,
- ResourceDeletedResponse,
- UpdateAgentRequest,
-)
-from agents_api.clients.pg import create_db_pool
-from agents_api.queries.agents import (
- create_agent,
- create_or_update_agent,
- delete_agent,
- get_agent,
- list_agents,
- patch_agent,
- update_agent,
-)
-from fastapi import HTTPException
-from uuid_extensions import uuid7
-from ward import raises, test
-
-from tests.fixtures import pg_dsn, test_agent, test_developer_id
-
-
-@test("query: create agent sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id):
- """Test that an agent can be successfully created."""
-
- pool = await create_db_pool(dsn=dsn)
- await create_agent(
- developer_id=developer_id,
- data=CreateAgentRequest(
- name="test agent",
- about="test agent about",
- model="gpt-4o-mini",
- ),
- connection_pool=pool,
- ) # type: ignore[not-callable]
-
-
-@test("query: create or update agent sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id):
- """Test that an agent can be successfully created or updated."""
-
- pool = await create_db_pool(dsn=dsn)
- await create_or_update_agent(
- developer_id=developer_id,
- agent_id=uuid7(),
- data=CreateOrUpdateAgentRequest(
- name="test agent",
- canonical_name="test_agent2",
- about="test agent about",
- model="gpt-4o-mini",
- instructions=["test instruction"],
- ),
- connection_pool=pool,
- ) # type: ignore[not-callable]
-
-
-@test("query: update agent sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id, agent=test_agent):
- """Test that an existing agent's information can be successfully updated."""
-
- pool = await create_db_pool(dsn=dsn)
- result = await update_agent(
- agent_id=agent.id,
- developer_id=developer_id,
- data=UpdateAgentRequest(
- name="updated agent",
- about="updated agent about",
- model="gpt-4o-mini",
- default_settings={"temperature": 1.0},
- metadata={"hello": "world"},
- ),
- connection_pool=pool,
- ) # type: ignore[not-callable]
-
- assert result is not None
- assert isinstance(result, Agent)
- assert result.name == "updated agent"
- assert result.about == "updated agent about"
- assert result.model == "gpt-4o-mini"
- assert result.default_settings["temperature"] == 1.0
- assert result.metadata == {"hello": "world"}
-
-
-@test("query: get agent not exists sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id):
- """Test that retrieving a non-existent agent raises an exception."""
-
- agent_id = uuid7()
- pool = await create_db_pool(dsn=dsn)
-
- with raises(Exception):
- await get_agent(agent_id=agent_id, developer_id=developer_id, connection_pool=pool) # type: ignore[not-callable]
-
-
-@test("query: get agent exists sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id, agent=test_agent):
- """Test that retrieving an existing agent returns the correct agent information."""
-
- pool = await create_db_pool(dsn=dsn)
- result = await get_agent(
- agent_id=agent.id,
- developer_id=developer_id,
- connection_pool=pool,
- ) # type: ignore[not-callable]
-
- assert result is not None
- assert isinstance(result, Agent)
- assert result.id == agent.id
- assert result.name == agent.name
- assert result.about == agent.about
- assert result.model == agent.model
- assert result.default_settings == agent.default_settings
- assert result.metadata == agent.metadata
-
-
-@test("query: list agents sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id):
- """Test that listing agents returns a collection of agent information."""
-
- pool = await create_db_pool(dsn=dsn)
- result = await list_agents(developer_id=developer_id, connection_pool=pool) # type: ignore[not-callable]
-
- assert isinstance(result, list)
- assert all(isinstance(agent, Agent) for agent in result)
-
-
-@test("query: list agents sql, invalid sort direction")
-async def _(dsn=pg_dsn, developer_id=test_developer_id):
- """Test that listing agents with an invalid sort direction raises an exception."""
-
- pool = await create_db_pool(dsn=dsn)
- with raises(HTTPException) as exc:
- await list_agents(
- developer_id=developer_id,
- connection_pool=pool,
- direction="invalid",
- ) # type: ignore[not-callable]
-
- assert exc.raised.status_code == 400
- assert exc.raised.detail == "Invalid sort direction"
-
-
-@test("query: patch agent sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id, agent=test_agent):
- """Test that an agent can be successfully patched."""
-
- pool = await create_db_pool(dsn=dsn)
- result = await patch_agent(
- agent_id=agent.id,
- developer_id=developer_id,
- data=PatchAgentRequest(
- name="patched agent",
- about="patched agent about",
- default_settings={"temperature": 1.0},
- metadata={"something": "else"},
- ),
- connection_pool=pool,
- ) # type: ignore[not-callable]
-
- assert result is not None
- assert isinstance(result, Agent)
- assert result.name == "patched agent"
- assert result.about == "patched agent about"
- assert result.default_settings["temperature"] == 1.0
-
-
-@test("query: delete agent sql")
-async def _(dsn=pg_dsn, developer_id=test_developer_id):
- """Test that an agent can be successfully deleted."""
-
- pool = await create_db_pool(dsn=dsn)
- create_result = await create_agent(
- developer_id=developer_id,
- data=CreateAgentRequest(
- name="test agent",
- about="test agent about",
- model="gpt-4o-mini",
- ),
- connection_pool=pool,
- ) # type: ignore[not-callable]
- delete_result = await delete_agent(
- agent_id=create_result.id,
- developer_id=developer_id,
- connection_pool=pool,
- ) # type: ignore[not-callable]
-
- assert delete_result is not None
- assert isinstance(delete_result, ResourceDeletedResponse)
-
- with raises(Exception):
- await get_agent(
- developer_id=developer_id,
- agent_id=create_result.id,
- connection_pool=pool,
- ) # type: ignore[not-callable]
diff --git a/agents-api/tests/test_get_doc_search.py b/agents-api/tests/test_get_doc_search.py
deleted file mode 100644
index 9b507c8fe..000000000
--- a/agents-api/tests/test_get_doc_search.py
+++ /dev/null
@@ -1,180 +0,0 @@
-from agents_api.autogen.openapi_model import (
- HybridDocSearchRequest,
- TextOnlyDocSearchRequest,
- VectorDocSearchRequest,
-)
-from agents_api.common.utils.get_doc_search import get_language, get_search_fn_and_params
-from agents_api.queries.docs.search_docs_by_embedding import search_docs_by_embedding
-from agents_api.queries.docs.search_docs_by_text import search_docs_by_text
-from agents_api.queries.docs.search_docs_hybrid import search_docs_hybrid
-from fastapi import HTTPException
-from ward import raises, test
-
-
-@test("get_language: valid language code returns lowercase language name")
-def _():
- result = get_language("en")
- assert result == "english_unaccent"
-
- result = get_language("fr")
- assert result == "french"
-
-
-@test("get_language: empty language code raises HTTPException")
-def _():
- with raises(HTTPException) as exc:
- get_language("")
-
- assert exc.raised.status_code == 422
- assert exc.raised.detail == "Invalid ISO 639 language code."
-
-
-@test("get_search_fn_and_params: text-only search request")
-def _():
- request = TextOnlyDocSearchRequest(
- text="search query",
- limit=10,
- lang="en",
- metadata_filter={"field": "value"},
- trigram_similarity_threshold=0.4,
- )
-
- search_fn, params = get_search_fn_and_params(request)
-
- assert search_fn == search_docs_by_text
- assert params == {
- "query": "search query",
- "k": 10,
- "metadata_filter": {"field": "value"},
- "search_language": "english_unaccent",
- "extract_keywords": False,
- "trigram_similarity_threshold": 0.4,
- }
-
-
-@test("get_search_fn_and_params: vector search request without MMR")
-def _():
- request = VectorDocSearchRequest(
- vector=[0.1, 0.2, 0.3],
- limit=5,
- confidence=0.8,
- metadata_filter={"field": "value"},
- mmr_strength=0,
- )
-
- search_fn, params = get_search_fn_and_params(request)
-
- assert search_fn == search_docs_by_embedding
- assert params == {
- "embedding": [0.1, 0.2, 0.3],
- "k": 5,
- "confidence": 0.8,
- "metadata_filter": {"field": "value"},
- }
-
-
-@test("get_search_fn_and_params: vector search request with MMR")
-def _():
- request = VectorDocSearchRequest(
- vector=[0.1, 0.2, 0.3],
- limit=5,
- confidence=0.8,
- metadata_filter={"field": "value"},
- mmr_strength=0.5,
- )
-
- search_fn, params = get_search_fn_and_params(request)
-
- assert search_fn == search_docs_by_embedding
- assert params == {
- "embedding": [0.1, 0.2, 0.3],
- "k": 15, # 5 * 3 because MMR is enabled
- "confidence": 0.8,
- "metadata_filter": {"field": "value"},
- }
-
-
-@test("get_search_fn_and_params: hybrid search request")
-def _():
- request = HybridDocSearchRequest(
- text="search query",
- vector=[0.1, 0.2, 0.3],
- lang="en",
- limit=5,
- confidence=0.8,
- alpha=0.5,
- metadata_filter={"field": "value"},
- mmr_strength=0,
- trigram_similarity_threshold=0.4,
- k_multiplier=7,
- )
-
- search_fn, params = get_search_fn_and_params(request)
-
- assert search_fn == search_docs_hybrid
- assert params == {
- "text_query": "search query",
- "embedding": [0.1, 0.2, 0.3],
- "k": 5,
- "confidence": 0.8,
- "alpha": 0.5,
- "metadata_filter": {"field": "value"},
- "search_language": "english_unaccent",
- "extract_keywords": False,
- "trigram_similarity_threshold": 0.4,
- "k_multiplier": 7,
- }
-
-
-@test("get_search_fn_and_params: hybrid search request with MMR")
-def _():
- request = HybridDocSearchRequest(
- text="search query",
- vector=[0.1, 0.2, 0.3],
- lang="en",
- limit=5,
- confidence=0.8,
- alpha=0.5,
- metadata_filter={"field": "value"},
- mmr_strength=0.5,
- trigram_similarity_threshold=0.4,
- k_multiplier=7,
- )
-
- search_fn, params = get_search_fn_and_params(request)
-
- assert search_fn == search_docs_hybrid
- assert params == {
- "text_query": "search query",
- "embedding": [0.1, 0.2, 0.3],
- "k": 15, # 5 * 3 because MMR is enabled
- "confidence": 0.8,
- "alpha": 0.5,
- "metadata_filter": {"field": "value"},
- "search_language": "english_unaccent",
- "extract_keywords": False,
- "trigram_similarity_threshold": 0.4,
- "k_multiplier": 7,
- }
-
-
-@test("get_search_fn_and_params: hybrid search request with invalid language")
-def _():
- request = HybridDocSearchRequest(
- text="search query",
- vector=[0.1, 0.2, 0.3],
- lang="en-axzs", # Invalid language code
- limit=5,
- confidence=0.8,
- alpha=0.5,
- metadata_filter={"field": "value"},
- mmr_strength=0,
- trigram_similarity_threshold=0.4,
- k_multiplier=7,
- )
-
- with raises(HTTPException) as exc:
- _search_fn, _params = get_search_fn_and_params(request)
-
- assert exc.raised.status_code == 422
- assert exc.raised.detail == "Invalid ISO 639 language code."
diff --git a/agents-api/tests/test_litellm_utils.py b/agents-api/tests/test_litellm_utils.py
deleted file mode 100644
index dd075e674..000000000
--- a/agents-api/tests/test_litellm_utils.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from unittest.mock import patch
-
-from agents_api.clients.litellm import acompletion
-from litellm.types.utils import ModelResponse
-from ward import test
-
-
-@test("litellm_utils: acompletion - no tools")
-async def _():
- with patch("agents_api.clients.litellm._acompletion") as mock_acompletion:
- mock_acompletion.return_value = ModelResponse(
- id="test-id",
- choices=[{"message": {"content": "test"}}],
- model="gpt-4",
- usage={"total_tokens": 10},
- )
-
- messages = [{"role": "user", "content": "test", "tool_calls": []}]
-
- await acompletion(model="gpt-4", messages=messages)
-
- # Check that tool_calls was removed from the message
- mock_acompletion.assert_called_once()
- called_messages = mock_acompletion.call_args[1]["messages"]
- assert "tool_calls" not in called_messages[0]
diff --git a/agents-api/tests/test_pg_query_step.py b/agents-api/tests/test_pg_query_step.py
deleted file mode 100644
index 6416502cc..000000000
--- a/agents-api/tests/test_pg_query_step.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from unittest.mock import AsyncMock, MagicMock, patch
-
-from agents_api.activities.task_steps.pg_query_step import pg_query_step
-from ward import test
-
-
-@test("pg_query_step correctly calls the specified query")
-async def _():
- # Mock the database connection pool
- mock_pool = AsyncMock()
-
- # Create a mock query function that will be returned by getattr
- mock_query = AsyncMock(return_value={"result": "test"})
-
- # Mock the app state to provide the postgres_pool
- mock_app_state = MagicMock()
- mock_app_state.postgres_pool = mock_pool
-
- # Patch the relevant modules and functions
- with (
- patch("agents_api.activities.task_steps.pg_query_step.queries") as mock_queries,
- patch("agents_api.activities.task_steps.pg_query_step.app") as mock_app,
- ):
- # Set up the mock app state
- mock_app.state = mock_app_state
-
- # Set up module resolution
- mock_module = MagicMock()
- mock_module.test_query = mock_query
- mock_queries.test_module = mock_module
-
- # Call the function with a query in the format "module_name.query_name"
- result = await pg_query_step(
- query_name="test_module.test_query",
- values={"param1": "value1"},
- )
-
- # Verify the query was called with the expected arguments
- mock_query.assert_called_once_with(param1="value1", connection_pool=mock_pool)
-
- # Verify the function returns the result from the query
- assert result == {"result": "test"}
-
-
-@test("pg_query_step raises exception for invalid query name format")
-async def _():
- # Try with an invalid query name (no dot separator)
- try:
- await pg_query_step(query_name="invalid_query_name", values={})
- assert False, "Expected an exception but none was raised"
- except ValueError:
- # Expected behavior - ValueError should be raised
- pass
- except Exception as e:
- assert False, f"Expected ValueError but got {type(e).__name__}"
-
-
-@test("pg_query_step propagates exceptions from the underlying query")
-async def _():
- # Mock the database connection pool
- mock_pool = AsyncMock()
-
- # Create a mock query function that raises an exception
- mock_query = AsyncMock(side_effect=Exception("Test query error"))
-
- # Mock the app state to provide the postgres_pool
- mock_app_state = MagicMock()
- mock_app_state.postgres_pool = mock_pool
-
- # Patch the relevant modules and functions
- with (
- patch("agents_api.activities.task_steps.pg_query_step.queries") as mock_queries,
- patch("agents_api.activities.task_steps.pg_query_step.app") as mock_app,
- ):
- # Set up the mock app state
- mock_app.state = mock_app_state
-
- # Set up module resolution
- mock_module = MagicMock()
- mock_module.test_query = mock_query
- mock_queries.test_module = mock_module
-
- # Call the function and expect an exception
- try:
- await pg_query_step(
- query_name="test_module.test_query",
- values={},
- )
- assert False, "Expected an exception but none was raised"
- except Exception as e:
- # Verify the exception is propagated
- assert str(e) == "Test query error"
diff --git a/changelog/Templates/JulepCustom/entries.html b/changelog/Templates/JulepCustom/entries.html
new file mode 100644
index 000000000..44df3ea04
--- /dev/null
+++ b/changelog/Templates/JulepCustom/entries.html
@@ -0,0 +1,16 @@
+{{> head}}
+{{> header}}
+
+{{title}}
+
+ {{#summary}}
+ {{title}}
+
+ {{{html}}}
+ {{#tags}}
+ #{{.}}
+ {{/tags}}
+