diff --git a/.github/workflows/doctoc-on-push.yml b/.github/workflows/doctoc-on-push.yml index c0dfdf2c6..29d8cf800 100644 --- a/.github/workflows/doctoc-on-push.yml +++ b/.github/workflows/doctoc-on-push.yml @@ -11,4 +11,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MAX_HEADER_LEVEL: 3 TOC_TITLE: '

📖 Table of Contents

' - FOLDING: true + FOLDING: false diff --git a/.github/workflows/translate-readme.yml b/.github/workflows/translate-readme.yml index 57a7c8ade..f6b28b370 100644 --- a/.github/workflows/translate-readme.yml +++ b/.github/workflows/translate-readme.yml @@ -10,7 +10,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python v3.10.12 uses: actions/setup-python@v5 with: @@ -24,15 +26,15 @@ jobs: - name: Run translator script run: python scripts/readme_translator.py - - name: Commit changes - run: | - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - git add README-*.md - git commit -m "chore(readme): translate README.md" - - - name: Push changes - uses: ad-m/github-push-action@v0.6.0 + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: ${{ github.ref }} + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(readme): translate README.md" + title: "Translate README.md" + body: "This PR updates the translated versions of README.md" + branch: "translate-readme" + delete-branch: true + add-paths: | + README.md + README-*.md \ No newline at end of file diff --git a/README-CN.md b/README-CN.md index 8261307b3..24c488aef 100644 --- a/README-CN.md +++ b/README-CN.md @@ -6,7 +6,7 @@


- 探索文档 + 探索文档 · 不和谐 · @@ -62,40 +62,40 @@ -

-

📖 Table of Contents

- -- [主要特点](#%E4%B8%BB%E8%A6%81%E7%89%B9%E7%82%B9) -- [Python 快速入门🐍](#python-%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) - - [步骤 1:创建代理](#%E6%AD%A5%E9%AA%A4-1%E5%88%9B%E5%BB%BA%E4%BB%A3%E7%90%86) - - [步骤 2:创建一个生成故事和漫画的任务](#%E6%AD%A5%E9%AA%A4-2%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%94%9F%E6%88%90%E6%95%85%E4%BA%8B%E5%92%8C%E6%BC%AB%E7%94%BB%E7%9A%84%E4%BB%BB%E5%8A%A1) - - [步骤 3:执行任务](#%E6%AD%A5%E9%AA%A4-3%E6%89%A7%E8%A1%8C%E4%BB%BB%E5%8A%A1) - - [步骤 4:与代理聊天](#%E6%AD%A5%E9%AA%A4-4%E4%B8%8E%E4%BB%A3%E7%90%86%E8%81%8A%E5%A4%A9) -- [Node.js 快速入门 🟩](#nodejs-%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8-) - - [步骤 1:创建代理](#%E6%AD%A5%E9%AA%A4-1%E5%88%9B%E5%BB%BA%E4%BB%A3%E7%90%86-1) - - [步骤 2:创建一个生成故事和漫画的任务](#%E6%AD%A5%E9%AA%A4-2%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%94%9F%E6%88%90%E6%95%85%E4%BA%8B%E5%92%8C%E6%BC%AB%E7%94%BB%E7%9A%84%E4%BB%BB%E5%8A%A1-1) - - [步骤 3:执行任务](#%E6%AD%A5%E9%AA%A4-3%E6%89%A7%E8%A1%8C%E4%BB%BB%E5%8A%A1-1) - - [步骤 4:与代理聊天](#%E6%AD%A5%E9%AA%A4-4%E4%B8%8E%E4%BB%A3%E7%90%86%E8%81%8A%E5%A4%A9-1) - - [心智模型](#%E5%BF%83%E6%99%BA%E6%A8%A1%E5%9E%8B) -- [概念](#%E6%A6%82%E5%BF%B5) -- [理解任务](#%E7%90%86%E8%A7%A3%E4%BB%BB%E5%8A%A1) - - [工作流步骤的类型](#%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AD%A5%E9%AA%A4%E7%9A%84%E7%B1%BB%E5%9E%8B) -- [工具类型](#%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%9E%8B) - - [用户定义的函数](#%E7%94%A8%E6%88%B7%E5%AE%9A%E4%B9%89%E7%9A%84%E5%87%BD%E6%95%B0) - - [`系统` 工具](#%E7%B3%BB%E7%BB%9F-%E5%B7%A5%E5%85%B7) - - [内置“集成”](#%E5%86%85%E7%BD%AE%E9%9B%86%E6%88%90) - - [直接 `api_calls`](#%E7%9B%B4%E6%8E%A5-api_calls) -- [集成](#%E9%9B%86%E6%88%90) - - [向代理添加工具](#%E5%90%91%E4%BB%A3%E7%90%86%E6%B7%BB%E5%8A%A0%E5%B7%A5%E5%85%B7) - - [管理会话和用户](#%E7%AE%A1%E7%90%86%E4%BC%9A%E8%AF%9D%E5%92%8C%E7%94%A8%E6%88%B7) - - [文档集成与搜索](#%E6%96%87%E6%A1%A3%E9%9B%86%E6%88%90%E4%B8%8E%E6%90%9C%E7%B4%A2) -- [本地快速启动](#%E6%9C%AC%E5%9C%B0%E5%BF%AB%E9%80%9F%E5%90%AF%E5%8A%A8) -- [SDK 参考](#sdk-%E5%8F%82%E8%80%83) -- [为什么选择 Julep 而不是 LangChain?](#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-julep-%E8%80%8C%E4%B8%8D%E6%98%AF-langchain) - - [不同的用例](#%E4%B8%8D%E5%90%8C%E7%9A%84%E7%94%A8%E4%BE%8B) - - [不同的外形尺寸](#%E4%B8%8D%E5%90%8C%E7%9A%84%E5%A4%96%E5%BD%A2%E5%B0%BA%E5%AF%B8) +

📖 目录

+ +- [简介](#introduction) +- [主要特点](#key-features) +- [快速示例](#quick-example) +- [安装](#安装) +- [Python 快速入门 🐍](#python-quick-start-) +- [Node.js 快速入门🟩](#nodejs-quick-start-) +- [步骤 1:创建代理](#step-1-create-an-agent) +- [组件](#components) +- [心智模型](#mental-model) +- [概念](#concepts) +- [理解任务](#understanding-tasks) +- [任务的生命周期](#lifecycle-of-a-task) +- [工作流步骤的类型](#types-of-workflow-steps) +- [工具类型](#tool-types) +- [用户定义的`函数`](#user-defined-functions) +- [`系统` 工具](#system-tools) +- [内置 `integrations`](#built-in-integrations) +-[直接`api_calls`](#direct-api_calls) +- [集成](#integrations) +- [其他功能](#other-features) +- [向代理添加工具](#adding-tools-to-agents) +- [管理会话和用户](#managing-sessions-and-users) +- [文档集成与搜索](#document-integration-and-search) +- [参考](#reference) +- [SDK 参考](#sdk-reference) +- [API 参考](#api-reference) +- [本地快速启动](#local-quickstart) +- [Julep 和 LangChain 等有什么区别?](#julep 和 langchain 等之间有什么区别) +- [不同用例](#different-use-cases) +- [不同的外形尺寸](#different-form-factor) +- [总结](#in-summary) -
## 介绍 @@ -104,40 +104,46 @@ Julep 是一个用于创建 AI 代理的平台,这些代理可以记住过去 Julep 支持创建多步骤任务,包括决策、循环、并行处理以及与众多外部工具和 API 的集成。 -虽然许多人工智能应用程序仅限于简单、线性的提示链和 API 调用,并且分支很少,但 Julep 可以处理更复杂的场景。 - -它支持: +尽管许多 AI 应用程序仅限于简单、线性的提示和 API 调用链,并且分支很少,但 Julep 可以处理更复杂的场景,这些场景包括: -- 复杂、多步骤的流程 -- 动态决策 -- 并行执行 +- 有多个步骤, +- 根据模型输出做出决策, +- 产生并行分支, +- 使用多种工具,并且 +- 长时间运行。 > [!提示] -> 想象一下,您想要构建一个 AI 代理,它不仅可以回答简单的问题,还可以处理复杂的任务,记住过去的交互,甚至可能使用其他工具或 API。这就是 Julep 的作用所在。 +> 想象一下,您想要构建一个 AI 代理,它不仅可以回答简单的问题,还可以处理复杂的任务、记住过去的交互,甚至可能使用其他工具或 API。这就是 Julep 的作用所在。阅读 [了解任务](#understanding-tasks) 了解更多信息。 ## 主要特点 1. 🧠 **持久 AI 代理**:在长期交互​​中记住上下文和信息。 2. 💾 **状态会话**:跟踪过去的互动以获得个性化回应。 -3. 🔄 **多步骤任务**:使用循环和决策构建复杂的多步骤流程。 +3. 🔄 **多步骤任务**:通过循环和决策构建复杂的多步骤流程。 4. ⏳ **任务管理**:处理可以无限期运行的长时间运行的任务。 5.🛠️**内置工具**:在您的任务中使用内置工具和外部 API。 6. 🔧 **自我修复**:Julep 将自动重试失败的步骤、重新发送消息,并确保您的任务顺利运行。 7. 📚 **RAG**:使用 Julep 的文档存储构建一个用于检索和使用您自己的数据的系统。 -Julep 非常适合需要超越简单的提示响应模型的 AI 用例的应用程序。 +![功能](https://github.com/user-attachments/assets/4355cbae-fcbd-4510-ac0d-f8f77b73af70) + +> [!提示] +> Julep 非常适合需要超越简单的提示响应模型的 AI 用例的应用程序。 快速示例 想象一下一个可以执行以下操作的研究 AI 代理: -1. 选择一个主题, +1. **选择一个主题**, 2. 针对该主题提出 100 个搜索查询, 3. 同时进行网页搜索, -4. 总结结果, -5. 将摘要发送至 Discord +4. **总结**结果, +5. 将**摘要发送至 Discord**。 + +> [!注意] +> 在 Julep 中,这将是一项单独的任务80行代码然后运行完全托管全部独立完成。所有步骤都在 Julep 自己的服务器上执行,您无需动手。 -在 Julep 中,这将是一个单一的任务80行代码然后运行完全托管一切都是独立的。所有步骤都在 Julep 自己的服务器上执行,您无需动手。这是一个工作示例: +这是一个有效的例子: ```yaml name: Research Agent @@ -157,12 +163,12 @@ tools: integration: provider: brave setup: - api_key: "YOUR_BRAVE_API_KEY" + api_key: BSAqES7dj9d... # dummy key - name: discord_webhook type: api_call api_call: - url: "YOUR_DISCORD_WEBHOOK_URL" + url: https://eobuxj02se0n.m.pipedream.net # dummy requestbin method: POST headers: Content-Type: application/json @@ -194,7 +200,7 @@ main: tool: web_search arguments: query: "_" - parallelism: 100 + parallelism: 10 # Collect the results from the web search - evaluate: @@ -208,28 +214,74 @@ main: The summary should be well-structured, informative, and highlight key findings and insights: {{_.results}} unwrap: true + settings: + model: gpt-4o-mini # Send the summary to Discord - tool: discord_webhook arguments: - content: > - **Research Summary for {{inputs[0].topic}}** + content: |- + f''' + **Research Summary for {inputs[0].topic}** - {{_}} + {_} + ''' ``` 在这个例子中,Julep 将自动管理并行执行,重试失败的步骤,重新发送 API 请求,并保持任务可靠运行直到完成。 +> 这在 30 秒内运行并返回以下输出: + +
+人工智能研究摘要 (点击展开) + +> **人工智能研究摘要** +> +>###人工智能(AI)研究成果摘要 +> +> #### 简介 +> 近年来,人工智能 (AI) 领域取得了重大进展,其特点是方法和技术的发展,使机器能够感知环境、从数据中学习并做出决策。本摘要主要关注从与 AI 相关的各种研究成果中获得的见解。 +> +> #### 主要发现 +> +> 1. **人工智能的定义和范围**: +> - 人工智能被定义为计算机科学的一个分支,专注于创建能够执行需要类似人类智能的任务的系统,包括学习、推理和解决问题(维基百科)。 +>——它涵盖了各种子领域,包括机器学习、自然语言处理、机器人和计算机视觉。 +> +> 2. **影响与应用**: +> - AI 技术正在融入众多领域,提高效率和生产力。应用范围从自动驾驶汽车和医疗诊断到客户服务自动化和财务预测(OpenAI)。 +> - 谷歌致力于让人工智能造福每个人,这凸显了其通过增强各个平台的用户体验(谷歌人工智能)显著改善日常生活的潜力。 +> +> 3. **道德考虑**: +> - 关于人工智能的伦理影响的讨论一直在进行中,包括对隐私、偏见和决策过程中的责任的担忧。强调需要一个确保安全和负责任地使用人工智能技术的框架(OpenAI)。 +> +> 4. **学习机制**: +> - AI 系统利用不同的学习机制,例如监督学习、无监督学习和强化学习。这些方法允许 AI 通过从过去的经验和数据中学习来提高性能(维基百科)。 +> - 监督学习和无监督学习之间的区别至关重要;监督学习依赖于标记数据,而无监督学习则识别没有预定义标签的模式(无监督)。 +> +> 5. **未来方向**: +> - 未来人工智能的发展预计将专注于增强人工智能系统的可解释性和透明度,确保它们能够提供合理的决策和行动(OpenAI)。 +> - 人们还在努力使人工智能系统更易于访问和用户友好,鼓励不同人群和行业更广泛地采用它(谷歌人工智能)。 +> +> #### 结论 +> 人工智能代表着跨多个领域的变革力量,有望重塑行业并改善生活质量。然而,随着其能力的扩展,解决随之而来的伦理和社会影响至关重要。技术专家、伦理学家和政策制定者之间的持续研究和合作对于驾驭人工智能的未来格局至关重要。 + +
+ ## 安装 要开始使用 Julep,请使用 [npm](https://www.npmjs.com/package/@julep/sdk) 或 [pip](https://pypi.org/project/julep/) 安装它: +**Node.js**: ```bash npm install @julep/sdk -``` -或者 +# or + +bun add @julep/sdk +``` +**Python**: ```bash pip install julep ``` @@ -246,997 +298,1219 @@ pip install julep ## Python 快速入门🐍 -### 步骤 1:创建代理 - ```python +### Step 0: Setup + +import time import yaml from julep import Julep # or AsyncJulep client = Julep(api_key="your_julep_api_key") +### Step 1: Create an Agent + agent = client.agents.create( name="Storytelling Agent", - model="gpt-4o", - about="You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", + model="claude-3.5-sonnet", + about="You are a creative storyteller that crafts engaging stories on a myriad of topics.", ) -# 🛠️ Add an image generation tool (DALL·E) to the agent -client.agents.tools.create( - agent_id=agent.id, - name="image_generator", - description="Use this tool to generate images based on descriptions.", - integration={ - "provider": "dalle", - "method": "generate_image", - "setup": { - "api_key": "your_openai_api_key", - }, - }, -) -``` - -### 步骤 2:创建一个生成故事和漫画的任务 +### Step 2: Create a Task that generates a story and comic strip -让我们定义一个多步骤任务来创建一个故事并根据输入的想法生成面板漫画: - -```python -# 📋 Task -# Create a task that takes an idea and creates a story and a 4-panel comic strip task_yaml = """ -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside ```yaml 标签位于您的回复末尾。 +展开:true + +- 评价: +情节想法:load_yaml(_.split('```yaml')[1].split('```')[0].strip()) + +# 第二步:从情节思路中提取研究领域 +- 迅速的: +- 角色:系统 +内容:您是 {{agent.name}}。{{agent.about}} +- 角色:用户 +内容: > +以下是一些故事情节的想法: +{% 表示 _.plot_ideas 中的想法 %} +- {{主意}} +{% 结束 %} + +为了发展故事情节,我们需要研究情节思路。 +我们应该研究什么?写下你认为有趣的情节想法的维基百科搜索查询。 +将输出作为 yaml 列表返回```yaml tags at the end of your response. unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].strip() - panels: re.findall(r'\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)', _) + research_queries: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) - # Step 3: Generate images for each panel using the image generator tool + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ + + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' - # Step 4: Generate a catchy title for the story + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} - unwrap: true - - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: "[output.image.url for output in outputs[2]]" + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside ```yaml 标签位于响应末尾。yaml 对象应具有以下结构: + + ```yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""``` + +确保 yaml 有效,且角色和场景不为空。还要注意分号和编写 yaml 的其他问题。 +展开:true + +- 评价: +情节:“load_yaml(_.split('```yaml')[1].split('```')[0].strip())” """ -task = client.tasks.create( - agent_id=agent.id, - **yaml.safe_load(task_yaml) +任务 = 客户端.任务.创建( +agent_id=代理.id, +**yaml.safe_load(任务_yaml) ) -``` ### 步骤 3:执行任务 -```python -# 🚀 Execute the task with an input idea -execution = client.executions.create( - task_id=task.id, - input={"idea": "A cat who learns to fly"} +执行 = 客户端.执行.创建( +任务ID=任务ID, +输入={“idea”:“一只学飞的猫”} ) -# 🎉 Watch as the story and comic panels are generated -for transition in client.executions.transitions.stream(execution_id=execution.id): - print(transition) +# 🎉 观看故事和漫画面板的生成 +while (result := client.executions.get(execution.id)).status 不在 ['成功', '失败'] 中: +打印(结果.状态,结果.输出) +时间.睡眠(1) -# 📦 Once the execution is finished, retrieve the results -result = client.executions.get(execution_id=execution.id) +# 📦执行完成后,检索结果 +如果 result.status ==“成功”: +打印(结果.输出) +别的: +引发异常(结果.错误) ``` -### 步骤 4:与代理聊天 - -开始与代理进行交互式聊天会话: +You can find the full python example [here](example.py). -```python -session = client.sessions.create(agent_id=agent.id) - -# 💬 Send messages to the agent -while (message := input("Enter a message: ")) != "quit": - response = client.sessions.chat( - session_id=session.id, - message=message, - ) - - print(response) -``` +
+ + Back to Top +  |  + + Table of Contents + +
-您可以在[这里](example.py)找到完整的python示例。 +## Node.js Quick Start 🟩 -## Node.js 快速入门 🟩 +### Step 1: Create an Agent -### 步骤 1:创建代理 +```JavaScript的 +// 步骤 0:设置 +const dotenv = require('dotenv'); +const { Julep } = require('@julep/sdk'); +const yaml = require('yaml'); -```javascript -import { Julep } from "@julep/sdk"; -import yaml from "js-yaml"; +dotenv.配置(); -const client = new Julep({ apiKey: "your_julep_api_key" }); +const 客户端 = new Julep({ apiKey:process.env.JULEP_API_KEY, 环境:process.env.JULEP_ENVIRONMENT || “生产” }); -async function createAgent() { - const agent = await client.agents.create({ - name: "Storytelling Agent", - model: "gpt-4", - about: - "You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", - }); +/* 步骤 1:创建代理 */ - // 🛠️ Add an image generation tool (DALL·E) to the agent - await client.agents.tools.create(agent.id, { - name: "image_generator", - description: "Use this tool to generate images based on descriptions.", - integration: { - provider: "dalle", - method: "generate_image", - setup: { - api_key: "your_openai_api_key", - }, - }, +异步函数 createAgent() { +const 代理 = 等待客户端.代理.创建({ +名称:“讲故事特工”, +模型:“claude-3.5-sonnet”, +关于:“您是一位富有创意的讲故事者,能够就无数主题创作引人入胜的故事。”, }); - - return agent; +回報代理; } -``` -### 步骤 2:创建一个生成故事和漫画的任务 +/* 步骤 2:创建一个生成故事和漫画的任务 */ -```javascript const taskYaml = ` -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. - -main: - # Step 1: Generate a story and outline into 4 panels - - prompt: - - role: system - content: You are {{agent.name}}. {{agent.about}} - - role: user - content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. - unwrap: true - - # Step 2: Extract the panel descriptions and story - - evaluate: - story: _.split('1. ')[0].trim() - panels: _.match(/\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)/g) - - # Step 3: Generate images for each panel using the image generator tool - - foreach: - in: _.panels - do: - tool: image_generator - arguments: - description: _ - - # Step 4: Generate a catchy title for the story - - prompt: - - role: system - content: You are {{agent.name}}. {{agent.about}} - - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} - unwrap: true - - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: outputs[2].map(output => output.image.url) +名称:讲故事的人 +描述:根据一个想法创建一个故事。 + +工具: +- 名称:research_wikipedia +一体化: +提供者:维基百科 +方法:搜索 + +主要的: +# 步骤 1:产生情节想法 +- 迅速的: +- 角色:系统 +内容:您是 {{agent.name}}。{{agent.about}} +- 角色:用户 +内容: > +根据想法“{{_.idea}}”,生成 5 个情节想法的列表。尽情发挥你的想象力和创造力。将输出作为响应末尾的 \`\`\`yaml 标签内的长字符串列表返回。 +展开:true + +- 评价: +plot_ideas:load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + +# 第二步:从情节思路中提取研究领域 +- 迅速的: +- 角色:系统 +内容:您是 {{agent.name}}。{{agent.about}} +- 角色:用户 +内容: > +以下是一些故事情节的想法: +{% 表示 _.plot_ideas 中的想法 %} +- {{主意}} +{% 结束 %} + +为了发展故事情节,我们需要研究情节思路。 +我们应该研究什么?写下你认为有趣的情节想法的维基百科搜索查询。 +将您的输出作为 yaml 列表返回到响应末尾的 \`\`\`yaml 标签内。 +展开:true +设置: +型号:gpt-4o-mini +温度:0.7 + +- 评价: +research_queries:load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + +# 步骤 3:研究每个情节构思 +- foreach: +在:_.research_queries +做: +工具:research_wikipedia +参数: +询问: _ + +- 评价: +wikipedia_results:'NEWLINE.join([f“- {doc.metadata.title}:{doc.metadata.summary}”用于 item in _ for doc in item.documents])' + +# 第 4 步:思考和深思 +- 迅速的: +- 角色:系统 +内容:您是 {{agent.name}}。{{agent.about}} +- 角色:用户 +内容:|- +在写故事之前,让我们先思考一下。以下是一些情节构思: +{% for idea in output[1].plot_ideas %} +- {{主意}} +{% 结束 %} + +以下是在维基百科上研究情节思路的结果: +{{_.wikipedia_results}} + +认真思考故事情节。将故事情节与维基百科搜索结果相结合,为故事创建详细情节。 +写下你所有的笔记和想法。 +最后,将图表作为 yaml 对象写入响应末尾的 \`\`\`yaml 标签内。yaml 对象应具有以下结构: + +\`\`\`yaml +标题: ”" +人物: +- 姓名: ”" +关于: ”" +概要:”" +场景: +- 标题: ”" +描述: ”" +人物: +- 姓名: ”" +角色: ”" +故事情节: +-”“\`\`\` + +确保 yaml 有效,且角色和场景不为空。还要注意分号和编写 yaml 的其他问题。 +展开:true + +- 评价: +情节:“load_yaml(_。split('\`\`\`yaml')[1].split('\`\`\`')[0].strip())” `; -async function createTask(agent) { - const task = await client.tasks.create(agent.id, yaml.load(taskYaml)); - return task; +异步函数 createTask(agentId){ +const task = await 客户端.tasks.create( +代理人编号, +yaml.解析(taskYaml) +(英文): +返回任务; } -``` - -### 步骤 3:执行任务 - -```javascript -async function executeTask(task) { - const execution = await client.executions.create(task.id, { - input: { idea: "A cat who learns to fly" }, - }); - - // 🎉 Watch as the story and comic panels are generated - for await (const transition of client.executions.transitions.stream( - execution.id - )) { - console.log(transition); - } - - // 📦 Once the execution is finished, retrieve the results - const result = await client.executions.get(execution.id); - return result; -} -``` - -### 步骤 4:与代理聊天 -```javascript -async function chatWithAgent(agent) { - const session = await client.sessions.create({ agent_id: agent.id }); +/* 步骤 3:执行任务 */ - // 💬 Send messages to the agent - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, +异步函数 executeTask (taskId) { +const 执行 = 等待客户端.执行.创建(taskId,{ +输入:{ 想法:“一只学飞的猫” } }); - const chat = async () => { - rl.question("Enter a message (or 'quit' to exit): ", async (message) => { - if (message.toLowerCase() === "quit") { - rl.close(); - return; +// 🎉 观看故事和漫画面板的生成 +while (真) { +const result = 等待客户端.executions.get(execution.id); +控制台.log(结果.状态,结果.输出); + +if (result.status === '成功' || result.status === '失败') { +// 📦执行完成后,检索结果 +如果 (result.status === "成功") { +控制台.log(结果.输出); +} 别的 { +抛出新的错误(result.error); } +休息; + } - const response = await client.sessions.chat(session.id, { message }); - console.log(response); - chat(); - }); - }; - - chat(); +等待新的 Promise(resolve => setTimeout(resolve,1000)); + } } -// Run the example -async function runExample() { - const agent = await createAgent(); - const task = await createTask(agent); - const result = await executeTask(task); - console.log("Task Result:", result); - await chatWithAgent(agent); +// 运行示例的主函数 +异步函数 main() { +尝试 { +const agent = await createAgent(); +const task = await createTask(agent.id); +等待执行任务(任务id); +} 捕获 (错误) { +console.error("发生错误:", error); + } } -runExample().catch(console.error); +main().then(() => console.log("完成")).catch(console.error); ``` -您可以在[这里](example.js)找到完整的 Node.js 示例。 +You can find the full Node.js example [here](example.js). -## 成分 +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Components -Julep 由以下成分组成: +Julep is made up of the following components: -- **Julep 平台**:Julep 平台是运行您的工作流程的云服务。它包括用于描述工作流程的语言、用于运行这些工作流程的服务器以及用于与平台交互的 SDK。 -- **Julep SDKs**:Julep SDKs 是一组用于构建工作流的库。目前有适用于 Python 和 JavaScript 的 SDKs,还有更多 SDKs 正在开发中。 -- **Julep API**:Julep API 是一个 RESTful API,您可以使用它与 Julep 平台进行交互。 +- **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 API**: The Julep API is a RESTful API that you can use to interact with the Julep platform. -### 心智模型 +### Mental Model
-您可以将 Julep 视为一个结合了客户端和服务器端组件的平台,以帮助您构建高级 AI 代理。以下是它的可视化方法: +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. **您的申请代码:** +1. **Your Application Code:** -- 您可以在应用程序中使用 Julep SDK 来定义代理、任务和工作流。 -- SDK 提供的函数和类使得设置和管理这些组件变得容易。 + - 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. -2. **Julep 后端服务:** +2. **Julep Backend Service:** -- SDK 通过网络与 Julep 后端通信。 -- 后端处理任务的执行,维护会话状态,存储文档并协调工作流程。 + - The SDK communicates with the Julep backend over the network. + - The backend handles execution of tasks, maintains session state, stores documents, and orchestrates workflows. -3. **与工具和 API 集成:** -- 在您的工作流程中,您可以集成外部工具和服务。 -- 后端促进这些集成,因此您的代理可以执行网络搜索、访问数据库或调用第三方 API。 +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. -## 概念 +## Concepts -Julep 基于几个关键技术组件构建,这些组件共同协作以创建强大的 AI 工作流程: +Julep is built on several key technical components that work together to create powerful AI workflows: -```mermaid -graph TD - User[User] ==> Session[Session] - Session --> Agent[Agent] - Agent --> Tasks[Tasks] - Agent --> LLM[Large Language Model] - Tasks --> Tools[Tools] - Agent --> Documents[Documents] - Documents --> VectorDB[Vector Database] - Tasks --> Executions[Executions] +```美人鱼 +图 TD +用户[用户] ==> 会话[会话] +会话-->代理[代理] +代理-->任务[任务] +代理——> LLM[大型语言模型] +任务 --> 工具[工具] +代理人 --> 文件[文件] +文档 --> VectorDB[矢量数据库] +任务 --> 执行[执行] - classDef client fill:#9ff,stroke:#333,stroke-width:1px; - class User client; +classDef 客户端填充:#9ff,描边:#333,描边宽度:1px; +用户客户端类; - classDef core fill:#f9f,stroke:#333,stroke-width:2px; - class Agent,Tasks,Session core; +classDef 核心填充:#f9f,描边:#333,描边宽度:2px; +类代理、任务、会话核心; ``` -- **代理**:由大型语言模型(LLM)支持的人工智能实体,可执行任务并与用户交互。 -- **用户**:通过会话与代理交互的实体。 -- **会话**:代理和用户之间的状态交互,在多个交换之间维护上下文。 -- **任务**:代理可以执行的多步骤、程序化工作流,包括提示、工具调用和条件逻辑等各种类型的步骤。 -- **工具**:扩展代理功能的集成,包括用户定义的函数、系统工具或第三方 API 集成。 -- **文档**:与代理或用户相关的文本或数据对象,矢量化并存储以用于语义搜索和检索。 -- **执行**:通过特定输入启动的任务实例,具有自己的生命周期和状态机。 +- **Agents**: AI-powered entities backed by large language models (LLMs) that execute tasks and interact with users. +- **Users**: Entities that interact with agents through sessions. +- **Sessions**: Stateful interactions between agents and users, maintaining context across multiple exchanges. +- **Tasks**: Multi-step, programmatic workflows that agents can execute, including various types of steps like prompts, tool calls, and conditional logic. +- **Tools**: Integrations that extend an agent's capabilities, including user-defined functions, system tools, or third-party API integrations. +- **Documents**: Text or data objects associated with agents or users, vectorized and stored for semantic search and retrieval. +- **Executions**: Instances of tasks that have been initiated with specific inputs, with their own lifecycle and state machine. + + +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Understanding Tasks + +Tasks are the core of Julep's workflow system. They allow you to define complex, multi-step AI workflows that your agents can execute. Here's a brief overview of task components: -有关更详细的解释,请参阅我们的[概念文档](https://github.com/julep-ai/julep/blob/dev/docs/julep-concepts.md)。 +- **Name, Description and Input Schema**: Each task has a unique name and description for easy identification. An input schema (optional) that is used to validate the input to the task. +- **Main Steps**: The core of a task, defining the sequence of actions to be performed. Each step can be a prompt, tool call, evaluate, wait_for_input, log, get, set, foreach, map_reduce, if-else, switch, sleep, or return. (See [Types of Workflow Steps](#types-of-workflow-steps) for more details) +- **Tools**: Optional integrations that extend the capabilities of your agent during task execution. -## 理解任务 +### Lifecycle of a Task -任务是 Julep 工作流系统的核心。它们允许您定义代理可以执行的复杂、多步骤 AI 工作流。以下是任务组件的简要概述: +You create a task using the Julep SDK and specify the main steps that the agent will execute. When you execute a task, the following lifecycle happens: -- **名称和描述**:每个任务都有唯一的名称和描述,以便于识别。 -- **主要步骤**:任务的核心,定义要执行的操作顺序。 -- **工具**:可选集成,可在任务执行期间扩展代理的功能。 +```美人鱼 +顺序图 +参与者 D 作为您的代码 +参与者 C 作为 Julep 客户 +参与者 S 担任 Julep 服务器 -### 工作流步骤的类型 +D->>C:创建任务 +C->>S:提交执行 +注意 S:执行任务 +S 注释:管理状态 +S-->>C:执行事件 +C-->>D:进度更新 +S->>C:执行完成 +C->>D:最终结果 +``` + +### Types of Workflow Steps -Julep 中的任务可以包含各种类型的步骤,让您可以创建复杂而强大的工作流程。以下是可用步骤类型的概述: +Tasks in Julep can include various types of steps, allowing you to create complex and powerful workflows. Here's an overview of the available step types: -#### 常见步骤 +#### Common Steps - + + + - + - + - + - + - +
姓名 关于句法NameAboutSyntax
迅速的 Prompt -向 AI 模型发送消息并接收响应 - +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: "Analyze the following data: {{data}}" +- prompt: "分析以下数据:{{agent.name}}" # <-- 这是一个 jinja 模板 +``` + +```yaml +- 迅速的: +- 角色:系统 +内容:“您是 {{agent.name}}。 {{agent.about}}” +- 角色:用户 +内容:“分析以下数据:{{_.data}}” ```
工具调用 Tool Call -执行集成工具或 API +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 -- tool: web_search - arguments: - query: "Latest AI developments" +- 工具:web_search +参数: +查询:“最新的 AI 发展”#<- 这是一个 Python 表达式(注意引号) +num_results: len(_.topics) # <-- 用于访问列表长度的 Python 表达式 ```
评价 Evaluate -执行计算或处理数据 - +Perform calculations or manipulate data +

Note: The evaluate step uses Python expressions.
```yaml -- evaluate: - average_score: "sum(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 -- wait_for_input: - info: - message: "Please provide additional information." +-等待输入: +信息: +消息:'“请提供有关 {_.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: "Processing completed for item {{item_id}}" +- log:“项目 {{_.item_id}} 的处理已完成”#<-- jinja 模板用于访问上下文变量 ```
-#### 键值步骤 +#### Key-Value Steps - + - + - +
姓名 关于句法 Name About Syntax
得到 Get -从键值存储中检索值 +Retrieve a value from the execution's key-value store. ```yaml -- get: "user_preference" +- 获取:用户偏好 ```
Set -为键值存储中的键分配值 +Assign a value to a key in the execution's key-value store. +

Note: The set step uses Python expressions.
```yaml -- set: - user_preference: "dark_mode" +- 放: +user_preference: '"dark_mode"' # <-- python 表达式 ```
-#### 迭代步骤 +#### Iteration Steps - + - + - + - +
姓名 关于句法 Name About Syntax
Foreach Foreach -遍历集合并对每个项目执行步骤 +Iterate over a collection and perform steps for each item ```yaml -- foreach: - in: "data_list" - do: - - log: "Processing item {{_}}" +- foreach: +in: _.data_list # <-- 用于访问上下文变量的 python 表达式 +做: +- log: "处理项目 {{_.item}}" # <-- jinja 模板访问上下文变量 ```
Map-Reduce Map-Reduce -对集合进行映射并减少结果 +Map over a collection and reduce the results ```yaml -- map_reduce: - over: "numbers" - map: - - evaluate: - squared: "_ ** 2" - reduce: "sum(results)" +- 映射_减少: +over: _.numbers # <-- 用于访问上下文变量的 python 表达式 +地图: +- 评价: +平方:“_ ** 2” +reduce:results + [_] # <--(可选)python 表达式以减少结果。如果省略,则为默认值。 +``` + +```yaml +- 映射_减少: +结束:_.topics +地图: +- 提示:写一篇关于{{__}}的文章 +并行度:10 ```
平行线 Parallel -并行运行多个步骤 +Run multiple steps in parallel ```yaml -- parallel: - - tool: web_search - arguments: - query: "AI news" - - tool: weather_check - arguments: - location: "New York" +- 平行线: +- 工具:web_search +参数: +查询:“AI 新闻” +- 工具:weather_check +参数: +地点:“纽约” ```
-#### 条件步骤 +#### Conditional Steps - + - + - +
姓名 关于句法 Name About Syntax
如果-否则 If-Else -有条件地执行步骤 +Conditional execution of steps ```yaml -- if: "score > 0.8" - then: - - log: "High score achieved" - else: - - log: "Score needs improvement" +- if: _.score > 0.8 # <-- python 表达式 +然后: +- 日志:取得高分 +别的: +- 错误:分数需要提高 ```
转变 Switch -根据多个条件执行步骤 +Execute steps based on multiple conditions ```yaml -- switch: - - case: "category == 'A'" - then: - - log: "Category A processing" - - case: "category == 'B'" - then: - - log: "Category B processing" - - case: "_" # Default case - then: - - log: "Unknown category" +- 转变: +- 案例:_.category =='A' +然后: +- 日志:“A 类处理” +- 案例:_.category =='B' +然后: +- 日志:“B类处理” +- case: _ # 默认情况 +然后: +- 错误:未知类别 ```
-#### 其他控制流 +#### Other Control Flow - + - + - + - + - +
姓名 关于句法 Name About Syntax
睡觉 Sleep -暂停工作流一段指定的时间 +Pause the workflow for a specified duration ```yaml -- sleep: - seconds: 30 +- 睡觉: +秒:30 +# 分钟:1 +#小时数:1 +#天数:1 ```
返回 Return -从工作流返回值 +Return a value from the workflow + +

Note: The return step uses Python expressions.
```yaml -- return: - result: "Task completed successfully" +- 返回: +result: '“任务成功完成”' #<-- python 表达式 +时间:datetime.now().isoformat() # <-- python 表达式 ```
屈服 Yield -运行子工作流并等待其完成 +Run a subworkflow and await its completion ```yaml -- yield: - workflow: "data_processing_subflow" - arguments: - input_data: "{{raw_data}}" +- 屈服: +工作流程:process_data +参数: +输入数据:_.raw_data # <-- python 表达式 ```
错误 Error -通过指定错误消息来处理错误 +Handle errors by specifying an error message ```yaml -- error: "Invalid input provided" +- 错误:“提供的输入无效”#<-- 仅限字符串 ```
-每种步骤类型在构建复杂的 AI 工作流中都有特定的用途。此分类有助于理解 Julep 任务中可用的各种控制流程和操作。 - -## 工具类型 +Each step type serves a specific purpose in building sophisticated AI workflows. This categorization helps in understanding the various control flows and operations available in Julep tasks. -代理可以访问许多“工具”——基础模型可以使用一组输入“调用”的任何编程接口来实现目标。例如,它可以使用“web_search(query)”工具在互联网上搜索一些信息。 +
+ + Back to Top +  |  + + Table of Contents + +
-与代理框架不同,julep 是管理代理执行的后端。客户端可以使用我们的 SDK 与代理进行交互。julep 负责执行任务和运行集成。 +## Tool Types -julep 中的工具可以是以下之一: +Agents can be given access to a number of "tools" -- any programmatic interface that a foundation model can "call" with a set of inputs to achieve a goal. For example, it might use a `web_search(query)` tool to search the Internet for some information. -### 用户定义的函数 +Unlike agent frameworks, julep is a _backend_ that manages agent execution. Clients can interact with agents using our SDKs. julep takes care of executing tasks and running integrations. -这些是您可以为模型提供的函数签名,类似于 [openai] 的函数调用工作方式。例如: +Tools in julep can be one of: +1. **User-defined `functions`**: These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. They need to be handled by the client. The workflow will pause until the client calls the function and gives the results back to julep. +2. **`system` tools**: Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. +3. **`integrations`**: Built-in third party tools that can be used to extend the capabilities of your agents. +4. **`api_calls`**: Direct api calls during workflow executions as tool calls. -```yaml -name: Example system tool task -description: List agents using system call +### User-defined `functions` -tools: - - name: send_notification - description: Send a notification to the user - type: function - function: - parameters: - type: object - properties: - text: - type: string - description: Content of the notification +These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. An example: -main: - - tool: send_notification - arguments: - content: hi +```yaml +名称:示例系统工具任务 +描述:使用系统调用列出代理 + +工具: +- 名称:send_notification +描述:向用户发送通知 +类型:函数 +功能: +参数: +类型:对象 +特性: +文本: +类型:字符串 +描述:通知内容 + +主要的: +- 工具:send_notification +参数: +内容:'“hi”'#<--python 表达式 ``` -每当 julep 遇到_用户定义函数_时,它就会暂停,将控制权交还给客户端,并等待客户端运行函数调用并将结果返回给 julep。 +Whenever julep encounters a _user-defined function_, it pauses, giving control back to the client and waits for the client to run the function call and give the results back to julep. -> [!提示] -> **示例食谱**:[cookbooks/13-Error_Handling_and_Recovery.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/13-Error_Handling_and_Recovery.py) +> [!TIP] +> **Example cookbook**: [cookbooks/13-Error_Handling_and_Recovery.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/13-Error_Handling_and_Recovery.py) -### `系统` 工具 +### `system` tools -内置工具可用于调用 julep API 本身,例如触发任务执行、附加到元数据字段等。 -“系统”工具内置于后端。它们会在需要时自动执行。它们不需要客户端的任何操作。 +Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. -例如, +`system` tools are built into the backend. They get executed automatically when needed. They do _not_ require any action from the client-side. -```yaml -name: Example system tool task -description: List agents using system call +For example, -tools: - - name: list_agents - description: List all agents - type: system - system: - resource: agent - operation: list -main: - - tool: list_agents - arguments: - limit: 10 +```yaml +名称:示例系统工具任务 +描述:使用系统调用列出代理 + +工具: +- 名称:list_agent_docs +描述:列出给定代理的所有文档 +类型:系统 +系统: +资源:代理 +子资源:doc +操作:列表 + +主要的: +- 工具:list_agents +参数: +限制:10 #<-- python 表达式 ``` -> [!提示] -> **示例食谱**:[cookbooks/10-Document_Management_and_Search.py​​](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py​​) +#### Available `system` resources and operations -### 内置“集成” +- `agent`: + - `list`: List all agents. + - `get`: Get a single agent by id. + - `create`: Create a new agent. + - `update`: Update an existing agent. + - `delete`: Delete an existing agent. -Julep 带有许多内置集成(如下节所述)。`集成` 工具直接在 julep 后端执行。它们在运行时所需的任何其他参数都可以在代理/会话/用户的 `元数据` 字段中设置。 +- `user`: + - `list`: List all users. + - `get`: Get a single user by id. + - `create`: Create a new user. + - `update`: Update an existing user. + - `delete`: Delete an existing user. -> [!提示] -> **示例食谱**:[cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) +- `session`: + - `list`: List all sessions. + - `get`: Get a single session by id. + - `create`: Create a new session. + - `update`: Update an existing session. + - `delete`: Delete an existing session. + - `chat`: Chat with a session. + - `history`: Get the chat history with a session. + +- `task`: + - `list`: List all tasks. + - `get`: Get a single task by id. + - `create`: Create a new task. + - `update`: Update an existing task. + - `delete`: Delete an existing task. + +- `doc` (subresource for `agent` and `user`): + - `list`: List all documents. + - `create`: Create a new document. + - `delete`: Delete an existing document. + - `search`: Search for documents. + +Additional operations available for some resources: +- `embed`: Embed a resource (specific resources not specified in the provided code). +- `change_status`: Change the status of a resource (specific resources not specified in the provided code). +- `chat`: Chat with a resource (specific resources not specified in the provided code). +- `history`: Get the chat history with a resource (specific resources not specified in the provided code). +- `create_or_update`: Create a new resource or update an existing one (specific resources not specified in the provided code). + +Note: The availability of these operations may vary depending on the specific resource and implementation details. + +> [!TIP] +> **Example cookbook**: [cookbooks/10-Document_Management_and_Search.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py) -julep 后端附带来自以下提供商的集成第三方工具: +### Built-in `integrations` -- [合成](https://composio.dev) -- [匿名](https://anon.com) -- [langchain 工具包](https://python.langchain.com/v0.2/docs/integrations/toolkits/) +Julep comes with a number of built-in integrations (as described in the section below). `integration` tools are directly executed on the julep backend. Any additional parameters needed by them at runtime can be set in the agent/session/user's `metadata` fields. -计划支持_Github、Gitlab、Gmail、Jira、MultiOn、Slack_工具包。 +See [Integrations](#integrations) for details on the available integrations. -由于_composio_和_anon_是第三方提供商,因此他们的工具需要设置帐户链接。 +> [!TIP] +> **Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) -### 直接 `api_calls` -julep 还可以在工作流执行期间直接以工具调用的形式进行 api 调用。与“集成”相同,其他运行时参数从“元数据”字段加载。 +### Direct `api_calls` -例如, +julep can also directly make api calls during workflow executions as tool calls. Same as `integration`s, additional runtime parameters are loaded from `metadata` fields. + +For example, ```yaml -name: Example api_call task -tools: - - type: api_call - name: hello - api_call: - method: GET - url: https://httpbin.org/get -main: - - tool: hello - arguments: - params: - test: _.input +名称:示例 api_call 任务 +工具: +- 类型:api_call +名字:你好 +API调用: +方法:GET +网址:https://httpbin.org/get + +主要的: +- 工具:你好 +参数: +json: +测试:_.input#<--python 表达式 ``` -## 集成 +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Integrations -Julep 支持各种集成,可以扩展您的 AI 代理的功能。以下是可用集成及其支持的参数的列表: +Julep supports various integrations that extend the capabilities of your AI agents. Here's a list of available integrations and their supported arguments: - + - + - + - + - + - +
勇敢搜索 Brave Search ```yaml -setup: - api_key: string # The API key for Brave Search +设置: +api_key: string # Brave Search 的 API 密钥 -arguments: - query: string # The search query for searching with Brave +参数: +query: string # 使用 Brave 搜索的搜索查询 -output: - result: string # The result of the Brave Search +输出: +result: string # Brave Search 的结果 ``` -**示例食谱**:[cookbooks/03-SmartResearcher_With_WebSearch.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-SmartResearcher_With_WebSearch.ipynb) +**Example cookbook**: [cookbooks/03-SmartResearcher_With_WebSearch.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-SmartResearcher_With_WebSearch.ipynb)
浏览器基础 BrowserBase ```yaml -setup: - api_key: string # The API key for BrowserBase - project_id: string # The project ID for BrowserBase - session_id: string # (Optional) The session ID for BrowserBase +设置: +api_key: string # BrowserBase 的 API 密钥 +project_id: string # BrowserBase 的项目 ID +session_id: string #(可选)BrowserBase 的会话 ID -arguments: - urls: list[string] # The URLs for loading with BrowserBase +参数: +urls: list[string] # 使用 BrowserBase 加载的 URL -output: - documents: list # The documents loaded from the URLs +输出: +documents: list # 从 URL 加载的文档 ```
电子邮件 Email ```yaml -setup: - host: string # The host of the email server - port: integer # The port of the email server - user: string # The username of the email server - password: string # The password of the email server - -arguments: - to: string # The email address to send the email to - from: string # The email address to send the email from - subject: string # The subject of the email - body: string # The body of the email - -output: - success: boolean # Whether the email was sent successfully +设置: +host: string # 电子邮件服务器的主机 +port: integer # 电子邮件服务器的端口 +用户:string#电子邮件服务器的用户名 +password: string # 邮件服务器的密码 + +参数: +to: string # 要发送电子邮件到的电子邮件地址 +from: string # 发送电子邮件的电子邮件地址 +subject: string # 电子邮件的主题 +body: string # 电子邮件正文 + +输出: +success: boolean # 邮件是否发送成功 ``` -**示例食谱**:[cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb) +**Example cookbook**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb)
蜘蛛 Spider ```yaml -setup: - spider_api_key: string # The API key for Spider +设置: +spider_api_key: string # Spider 的 API 密钥 -arguments: - url: string # The URL for which to fetch data - mode: string # The type of crawlers (default: "scrape") - params: dict # (Optional) The parameters for the Spider API +参数: +url: string # 获取数据的 URL +mode: string # 爬虫的类型(默认值:“scrape”) +params: dict # (可选)Spider API 的参数 -output: - documents: list # The documents returned from the spider +输出: +documents: list # 蜘蛛返回的文档 ``` -**示例食谱**:[cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) +**Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb)
天气 Weather ```yaml -setup: - openweathermap_api_key: string # The API key for OpenWeatherMap +设置: +openweathermap_api_key: string # OpenWeatherMap 的 API 密钥 -arguments: - location: string # The location for which to fetch weather data +参数: +location: string # 获取天气数据的位置 -output: - result: string # The weather data for the specified location +输出: +result: string # 指定位置的天气数据 ``` -**示例食谱**:[cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb) +**Example cookbook**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb)
维基百科 Wikipedia ```yaml -arguments: - query: string # The search query string - load_max_docs: integer # Maximum number of documents to load (default: 2) +参数: +query: string # 搜索查询字符串 +load_max_docs:整数#要加载的最大文档数(默认值:2) -output: - documents: list # The documents returned from the Wikipedia search +输出: +documents: list # 从 Wikipedia 搜索返回的文档 ``` -**示例食谱**:[cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb) +**Example cookbook**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb)
-有关更多详细信息,请参阅我们的 [集成文档](https://docs.julep.ai/integrations)。 +For more details, refer to our [Integrations Documentation](#integrations). -其他功能 +
+ + Back to Top +  |  + + Table of Contents + +
-Julep 提供一系列高级功能来增强您的 AI 工作流程: +## Other Features -### 向代理添加工具 +Julep offers a range of advanced features to enhance your AI workflows: -通过集成外部工具和 API 来扩展代理的功能: +### Adding Tools to Agents -```python -client.agents.tools.create( - agent_id=agent.id, - name="web_search", - description="Search the web for information.", - integration={ - "provider": "brave", - "method": "search", - "setup": {"api_key": "your_brave_api_key"}, - }, +Extend your agent's capabilities by integrating external tools and APIs: + +```Python +客户端.代理.工具.创建( +agent_id=代理.id, +名称="web_search", +description="在网络上搜索信息。", +积分={ +“提供者”:“勇敢”, +“方法”:“搜索”, +“设置”:{“api_key”:“你的brave_api_key”}, +}, ) ``` -### 管理会话和用户 +### Managing Sessions and Users -Julep 为持久交互提供了强大的会话管理: +Julep provides robust session management for persistent interactions: -```python -session = client.sessions.create( - agent_id=agent.id, - user_id=user.id, - context_overflow="adaptive" +```Python +会话 = 客户端.会话.创建( +agent_id=代理.id, +用户 ID=用户 ID, +context_overflow="自适应" ) -# Continue conversation in the same session -response = client.sessions.chat( - session_id=session.id, - messages=[ +# 在同一会话中继续对话 +响应 = 客户端.会话.聊天( +session_id=会话id, +消息=[ { - "role": "user", - "content": "Follow up on the previous conversation." +“角色”:“用户”, +"content": "跟进之前的对话。" } ] ) ``` -### 文档集成与搜索 +### Document Integration and Search -轻松管理和搜索代理的文档: +Easily manage and search through documents for your agents: -```python -# Upload a document -document = client.agents.docs.create( - title="AI advancements", - content="AI is changing the world...", - metadata={"category": "research_paper"} +```Python +# 上传文档 +文档 = 客户端.代理.docs.创建( +title="人工智能进步", +content="人工智能正在改变世界...", +元数据={“category”:“research_paper”} ) -# Search documents -results = client.agents.docs.search( - text="AI advancements", - metadata_filter={"category": "research_paper"} +# 搜索文档 +结果 = 客户端.代理.docs.搜索( +text="AI 进步", +metadata_filter={“category”:“research_paper”} ) ``` +
+ + Back to Top +  |  + + Table of Contents + +
+ +## 参考 + +### SDK 参考 + +- **Node.js** [SDK 参考](https://github.com/julep-ai/node-sdk/blob/main/api.md) | [NPM 包](https://www.npmjs.com/package/@julep/sdk) +- **Python** [SDK 参考](https://github.com/julep-ai/python-sdk/blob/main/api.md) | [PyPI 包](https://pypi.org/project/julep/) + +### API 参考 + +浏览我们的 API 文档以了解有关代理、任务和执行的更多信息: + +- [代理 API](https://dev.julep.ai/api/docs#tag/agents) +- [任务 API](https://dev.julep.ai/api/docs#tag/tasks) +- [执行 API](https://dev.julep.ai/api/docs#tag/executions) + +
+ + Back to Top +  |  + + Table of Contents + +
+ ## 本地快速启动 **要求**: @@ -1252,22 +1526,19 @@ results = client.agents.docs.search( 5. `cp .env.example .env # <-- 编辑此文件` 6. `docker compose --env-file .env --profile temporary-ui --profile single-tenant --profile self-hosted-db up --build` -## SDK 参考 - -- [Node.js SDK](https://github.com/julep-ai/node-sdk/blob/main/api.md) -- [Python SDK](https://github.com/julep-ai/python-sdk/blob/main/api.md) - -API 参考 - -浏览我们全面的 API 文档,了解有关代理、任务和执行的更多信息: +
+ + Back to Top +  |  + + Table of Contents + +
-- [代理 API](https://api.julep.ai/api/docs#tag/agents) -- [任务 API](https://api.julep.ai/api/docs#tag/tasks) -- [执行 API](https://api.julep.ai/api/docs#tag/executions) ***** -## 为什么选择 Julep 而不是 LangChain? +## Julep 和 LangChain 等有什么区别? ### 不同的用例 @@ -1305,5 +1576,8 @@ LangChain 是一个**库**,其中包含一些工具和一个用于构建线性
Back to Top +  |  + + Table of Contents
diff --git a/README-FR.md b/README-FR.md index 9fb786006..ca96b9ebd 100644 --- a/README-FR.md +++ b/README-FR.md @@ -6,7 +6,7 @@


- Explorer les documents + Explorer les documents · Discorde · @@ -62,47 +62,40 @@ Des nouvelles passionnantes ! Nous participons au DevFest.AI tout au long du moi -

-

📖 Table of Contents

+

📖 Table des matières

-- [Introduction](#introduction) -- [Principales caractéristiques](#principales-caract%C3%A9ristiques) -- [Exemple rapide](#exemple-rapide) +- [Présentation](#introduction) +- [Caractéristiques principales](#key-features) +- [Exemple rapide](#quick-example) - [Installation](#installation) -- [Démarrage rapide de Python 🐍](#d%C3%A9marrage-rapide-de-python-) - - [Étape 1 : Créer un agent](#%C3%89tape-1%C2%A0-cr%C3%A9er-un-agent) - - [Étape 2 : Créer une tâche qui génère une histoire et une bande dessinée](#%C3%89tape-2%C2%A0-cr%C3%A9er-une-t%C3%A2che-qui-g%C3%A9n%C3%A8re-une-histoire-et-une-bande-dessin%C3%A9e) - - [Étape 3 : Exécuter la tâche](#%C3%89tape-3%C2%A0-ex%C3%A9cuter-la-t%C3%A2che) - - [Étape 4 : Discuter avec l'agent](#%C3%89tape-4%C2%A0-discuter-avec-lagent) -- [Démarrage rapide de Node.js 🟩](#d%C3%A9marrage-rapide-de-nodejs-) - - [Étape 1 : Créer un agent](#%C3%89tape-1%C2%A0-cr%C3%A9er-un-agent-1) - - [Étape 2 : Créer une tâche qui génère une histoire et une bande dessinée](#%C3%89tape-2%C2%A0-cr%C3%A9er-une-t%C3%A2che-qui-g%C3%A9n%C3%A8re-une-histoire-et-une-bande-dessin%C3%A9e-1) - - [Étape 3 : Exécuter la tâche](#%C3%89tape-3%C2%A0-ex%C3%A9cuter-la-t%C3%A2che-1) - - [Étape 4 : Discuter avec l'agent](#%C3%89tape-4%C2%A0-discuter-avec-lagent-1) +- [Démarrage rapide de Python 🐍](#python-quick-start-) +- [Démarrage rapide de Node.js 🟩](#nodejs-quick-start-) +- [Étape 1 : Créer un agent](#step-1-create-an-agent) - [Composants](#composants) - - [Modèle mental](#mod%C3%A8le-mental) +- [Modèle mental](#mental-model) - [Concepts](#concepts) -- [Comprendre les tâches](#comprendre-les-t%C3%A2ches) - - [Types d'étapes de flux de travail](#types-d%C3%A9tapes-de-flux-de-travail) -- [Types d'outils](#types-doutils) - - [Fonctions définies par l'utilisateur](#fonctions-d%C3%A9finies-par-lutilisateur) - - [outils `système`](#outils-syst%C3%A8me) - - [« Intégrations » intégrées](#%C2%AB%C2%A0int%C3%A9grations%C2%A0%C2%BB-int%C3%A9gr%C3%A9es) - - [Appels directs `api_calls`](#appels-directs-api_calls) -- [Intégrations](#int%C3%A9grations) -- [Autres fonctionnalités](#autres-fonctionnalit%C3%A9s) - - [Ajout d'outils aux agents](#ajout-doutils-aux-agents) - - [Gestion des sessions et des utilisateurs](#gestion-des-sessions-et-des-utilisateurs) - - [Intégration et recherche de documents](#int%C3%A9gration-et-recherche-de-documents) -- [Démarrage rapide local](#d%C3%A9marrage-rapide-local) -- [Référence du SDK](#r%C3%A9f%C3%A9rence-du-sdk) -- [Référence API](#r%C3%A9f%C3%A9rence-api) -- [Pourquoi Julep vs. LangChain ?](#pourquoi-julep-vs-langchain%C2%A0) - - [Différents cas d'utilisation](#diff%C3%A9rents-cas-dutilisation) - - [Facteur de forme différent](#facteur-de-forme-diff%C3%A9rent) - - [En résumé](#en-r%C3%A9sum%C3%A9) +- [Comprendre les tâches](#understanding-tasks) +- [Cycle de vie d'une tâche](#cycle-de-vie-d-une-tâche) +- [Types d'étapes de flux de travail](#types-of-workflow-steps) +- [Types d'outils](#types-d'outils) +- [`Fonctions` définies par l'utilisateur](#user-defined-functions) +- [outils système](#outils-système) +- [`Intégrations` intégrées](#integrations-integrées) +- [Appels directs `api_calls`](#appels directs-api_calls) +- [Intégrations](#intégrations) +- [Autres fonctionnalités](#other-features) +- [Ajout d'outils aux agents](#adding-tools-to-agents) +- [Gestion des sessions et des utilisateurs](#managing-sessions-and-users) +- [Intégration et recherche de documents](#document-integration-and-search) +- [Référence](#référence) +- [Référence SDK](#sdk-reference) +- [Référence API](#api-reference) +- [Démarrage rapide local](#local-quickstart) +- [Quelle est la différence entre Julep et LangChain etc ?](#quelle-est-la-différence-entre-julep-et-langchain-etc) +- [Différents cas d'utilisation](#different-use-cases) +- [Facteur de forme différent](#different-form-factor) +- [En résumé](#en-resumé) -
## Introduction @@ -111,16 +104,16 @@ Julep est une plateforme permettant de créer des agents IA qui se souviennent d Julep permet la création de tâches en plusieurs étapes intégrant la prise de décision, les boucles, le traitement parallèle et l'intégration avec de nombreux outils et API externes. -Alors que de nombreuses applications d’IA se limitent à des chaînes simples et linéaires d’invites et d’appels d’API avec une ramification minimale, Julep est conçu pour gérer des scénarios plus complexes. +Alors que de nombreuses applications d'IA se limitent à des chaînes simples et linéaires d'invites et d'appels d'API avec une ramification minimale, Julep est conçu pour gérer des scénarios plus complexes qui : -Il prend en charge : - -- Processus complexes en plusieurs étapes -- Prise de décision dynamique -- Exécution parallèle +- comporter plusieurs étapes, +- prendre des décisions basées sur les résultats du modèle, +- générer des branches parallèles, +- utiliser beaucoup d'outils, et +- courir pendant une longue période. > [!TIP] -> Imaginez que vous souhaitiez créer un agent d'IA capable de faire plus que simplement répondre à des questions simples : il doit gérer des tâches complexes, se souvenir des interactions passées et peut-être même utiliser d'autres outils ou API. C'est là qu'intervient Julep. +> Imaginez que vous souhaitiez créer un agent d'IA capable de faire plus que simplement répondre à des questions simples : il doit gérer des tâches complexes, mémoriser des interactions passées et peut-être même utiliser d'autres outils ou API. C'est là qu'intervient Julep. Lisez [Comprendre les tâches](#understanding-tasks) pour en savoir plus. ## Principales caractéristiques @@ -132,19 +125,25 @@ Il prend en charge : 6. 🔧 **Auto-réparation** : Julep réessaiera automatiquement les étapes ayant échoué, renverra les messages et assurera généralement le bon déroulement de vos tâches. 7. 📚 **RAG** ​​: Utilisez le magasin de documents de Julep pour créer un système permettant de récupérer et d'utiliser vos propres données. -Julep est idéal pour les applications qui nécessitent des cas d’utilisation de l’IA au-delà des simples modèles de réponse rapide. +![fonctionnalités](https://github.com/user-attachments/assets/4355cbae-fcbd-4510-ac0d-f8f77b73af70) + +> [!TIP] +> Julep est idéal pour les applications qui nécessitent des cas d’utilisation de l’IA au-delà des simples modèles de réponse rapide. ## Exemple rapide Imaginez un agent d’IA de recherche capable d’effectuer les opérations suivantes : -1. Prenez un sujet, -2. Proposez 100 requêtes de recherche pour ce sujet, -3. Effectuez ces recherches sur le Web en parallèle, -4. Résumez les résultats, -5. Envoyez le résumé sur Discord +1. **Prenez un sujet**, +2. **Proposez 100 requêtes de recherche** pour ce sujet, +3. Effectuez ces **recherches Web en parallèle**, +4. **Résumez** les résultats, +5. Envoyez le **résumé à Discord**. + +> [!REMARQUE] +> Dans Julep, ce serait une tâche unique sous80 lignes de codeet courirentièrement gérétout seul. Toutes les étapes sont exécutées sur les propres serveurs de Julep et vous n'avez pas besoin de lever le petit doigt. -Dans Julep, ce serait une tâche unique sous80 lignes de codeet courirentièrement gérétout seul. Toutes les étapes sont exécutées sur les propres serveurs de Julep et vous n'avez pas besoin de lever le petit doigt. Voici un exemple fonctionnel : +Voici un exemple fonctionnel : ```yaml name: Research Agent @@ -164,12 +163,12 @@ tools: integration: provider: brave setup: - api_key: "YOUR_BRAVE_API_KEY" + api_key: BSAqES7dj9d... # dummy key - name: discord_webhook type: api_call api_call: - url: "YOUR_DISCORD_WEBHOOK_URL" + url: https://eobuxj02se0n.m.pipedream.net # dummy requestbin method: POST headers: Content-Type: application/json @@ -201,7 +200,7 @@ main: tool: web_search arguments: query: "_" - parallelism: 100 + parallelism: 10 # Collect the results from the web search - evaluate: @@ -215,28 +214,74 @@ main: The summary should be well-structured, informative, and highlight key findings and insights: {{_.results}} unwrap: true + settings: + model: gpt-4o-mini # Send the summary to Discord - tool: discord_webhook arguments: - content: > - **Research Summary for {{inputs[0].topic}}** + content: |- + f''' + **Research Summary for {inputs[0].topic}** - {{_}} + {_} + ''' ``` Dans cet exemple, Julep gérera automatiquement les exécutions parallèles, réessayera les étapes ayant échoué, renverra les requêtes API et maintiendra les tâches en cours d'exécution de manière fiable jusqu'à leur achèvement. +> Cela s'exécute en moins de 30 secondes et renvoie le résultat suivant : + +
+Résumé de la recherche sur l'IA (Cliquez pour agrandir) + +> **Résumé de la recherche sur l'IA** +> +> ### Résumé des résultats de recherche sur l'intelligence artificielle (IA) +> +> #### Présentation +> Le domaine de l’intelligence artificielle (IA) a connu des avancées significatives ces dernières années, marquées par le développement de méthodes et de technologies permettant aux machines de percevoir leur environnement, d’apprendre à partir de données et de prendre des décisions. L’objectif principal de ce résumé est de présenter les enseignements tirés de divers résultats de recherche liés à l’IA. +> +> #### Principales conclusions +> +> 1. **Définition et portée de l’IA** : +> - L'IA est définie comme une branche de l'informatique axée sur la création de systèmes capables d'effectuer des tâches nécessitant une intelligence humaine, notamment l'apprentissage, le raisonnement et la résolution de problèmes (Wikipedia). +> - Il englobe divers sous-domaines, notamment l’apprentissage automatique, le traitement du langage naturel, la robotique et la vision par ordinateur. +> +> 2. **Impact et applications** : +> - Les technologies d'IA sont intégrées dans de nombreux secteurs, améliorant l'efficacité et la productivité. Les applications vont des véhicules autonomes et des diagnostics de santé à l'automatisation du service client et aux prévisions financières (OpenAI). +> - L'engagement de Google à rendre l'IA bénéfique pour tous met en évidence son potentiel à améliorer considérablement la vie quotidienne en améliorant l'expérience utilisateur sur diverses plateformes (Google AI). +> +> 3. **Considérations éthiques** : +> - Un débat est en cours sur les implications éthiques de l'IA, notamment sur les préoccupations relatives à la confidentialité, aux préjugés et à la responsabilité dans les processus de prise de décision. La nécessité d'un cadre garantissant l'utilisation sûre et responsable des technologies de l'IA est soulignée (OpenAI). +> +> 4. **Mécanismes d’apprentissage** : +> - Les systèmes d'IA utilisent différents mécanismes d'apprentissage, tels que l'apprentissage supervisé, l'apprentissage non supervisé et l'apprentissage par renforcement. Ces méthodes permettent à l'IA d'améliorer ses performances au fil du temps en apprenant des expériences et des données passées (Wikipedia). +> - La distinction entre l’apprentissage supervisé et non supervisé est essentielle ; l’apprentissage supervisé s’appuie sur des données étiquetées, tandis que l’apprentissage non supervisé identifie des modèles sans étiquettes prédéfinies (non supervisé). +> +> 5. **Orientations futures**: +> - Les futurs développements de l’IA devraient se concentrer sur l’amélioration de l’interprétabilité et de la transparence des systèmes d’IA, garantissant qu’ils peuvent fournir des décisions et des actions justifiables (OpenAI). +> - On observe également une volonté de rendre les systèmes d’IA plus accessibles et plus conviviaux, encourageant une adoption plus large dans différents groupes démographiques et secteurs (Google AI). +> +> #### Conclusion +> L’IA représente une force de transformation dans de nombreux domaines, promettant de remodeler les industries et d’améliorer la qualité de vie. Cependant, à mesure que ses capacités se développent, il est essentiel de tenir compte des implications éthiques et sociétales qui en découlent. La poursuite des recherches et de la collaboration entre les technologues, les éthiciens et les décideurs politiques sera essentielle pour s’orienter dans le futur paysage de l’IA. + +
+ ## Installation Pour commencer à utiliser Julep, installez-le en utilisant [npm](https://www.npmjs.com/package/@julep/sdk) ou [pip](https://pypi.org/project/julep/) : +**Node.js**: ```bash npm install @julep/sdk -``` -ou +# or +bun add @julep/sdk +``` + +**Python**: ```bash pip install julep ``` @@ -253,997 +298,1219 @@ pip install julep ## Démarrage rapide de Python 🐍 -### Étape 1 : Créer un agent - ```python +### Step 0: Setup + +import time import yaml from julep import Julep # or AsyncJulep client = Julep(api_key="your_julep_api_key") +### Step 1: Create an Agent + agent = client.agents.create( name="Storytelling Agent", - model="gpt-4o", - about="You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", + model="claude-3.5-sonnet", + about="You are a creative storyteller that crafts engaging stories on a myriad of topics.", ) -# 🛠️ Add an image generation tool (DALL·E) to the agent -client.agents.tools.create( - agent_id=agent.id, - name="image_generator", - description="Use this tool to generate images based on descriptions.", - integration={ - "provider": "dalle", - "method": "generate_image", - "setup": { - "api_key": "your_openai_api_key", - }, - }, -) -``` - -### Étape 2 : Créer une tâche qui génère une histoire et une bande dessinée - -Définissons une tâche en plusieurs étapes pour créer une histoire et générer une bande dessinée à panneaux basée sur une idée d'entrée : +### Step 2: Create a Task that generates a story and comic strip -```python -# 📋 Task -# Create a task that takes an idea and creates a story and a 4-panel comic strip task_yaml = """ -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside ```balises yaml à la fin de votre réponse. +déballer : vrai + +- évaluer: +plot_ideas : load_yaml(_.split('```yaml')[1].split('```')[0].strip()) + +# Étape 2 : Extraire les domaines de recherche des idées de l'intrigue +- rapide: +- rôle : système +contenu : Vous êtes {{agent.name}}. {{agent.about}} +- rôle : utilisateur +contenu : > +Voici quelques idées d’intrigue pour une histoire : +{% pour l'idée dans _.plot_ideas %} +- {{idée}} +{% fin de %} + +Pour développer l’histoire, nous devons rechercher les idées d’intrigue. +Sur quoi devrions-nous faire des recherches ? Notez les requêtes de recherche Wikipédia pour les idées d'intrigue que vous trouvez intéressantes. +Renvoyez votre sortie sous forme de liste yaml à l'intérieur```yaml tags at the end of your response. unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].strip() - panels: re.findall(r'\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)', _) + research_queries: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) - # Step 3: Generate images for each panel using the image generator tool + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ + + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' - # Step 4: Generate a catchy title for the story + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} - unwrap: true - - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: "[output.image.url for output in outputs[2]]" + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside ```balises yaml à la fin de votre réponse. L'objet yaml doit avoir la structure suivante : + + ```yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""``` + +Assurez-vous que le fichier YAML est valide et que les caractères et les scènes ne sont pas vides. Faites également attention aux points-virgules et autres problèmes liés à l'écriture du fichier YAML. +déballer : vrai + +- évaluer: +intrigue : « load_yaml(_.split('```yaml')[1].split('```')[0].strip())" """ -task = client.tasks.create( - agent_id=agent.id, - **yaml.safe_load(task_yaml) +tâche = client.tasks.create( +agent_id=agent.id, +**yaml.safe_load(tâche_yaml) ) -``` ### Étape 3 : Exécuter la tâche -```python -# 🚀 Execute the task with an input idea -execution = client.executions.create( - task_id=task.id, - input={"idea": "A cat who learns to fly"} +exécution = client.executions.create( +task_id=task.id, +input={"idea": "Un chat qui apprend à voler"} ) -# 🎉 Watch as the story and comic panels are generated -for transition in client.executions.transitions.stream(execution_id=execution.id): - print(transition) +# 🎉 Regardez l'histoire et les panneaux de bande dessinée se générer +while (result := client.executions.get(execution.id)).status n'est pas dans ['réussi', 'échec'] : +print(résultat.statut, résultat.sortie) +heure.sommeil(1) -# 📦 Once the execution is finished, retrieve the results -result = client.executions.get(execution_id=execution.id) +# 📦 Une fois l'exécution terminée, récupérez les résultats +si result.status == "réussi" : +imprimer(résultat.sortie) +autre: +déclencher une exception (résultat.erreur) ``` -### Étape 4 : Discuter avec l'agent - -Démarrez une session de chat interactive avec l'agent : - -```python -session = client.sessions.create(agent_id=agent.id) - -# 💬 Send messages to the agent -while (message := input("Enter a message: ")) != "quit": - response = client.sessions.chat( - session_id=session.id, - message=message, - ) +You can find the full python example [here](example.py). - print(response) -``` - -Vous pouvez trouver l'exemple Python complet [ici](example.py). +
+ + Back to Top +  |  + + Table of Contents + +
-## Démarrage rapide de Node.js 🟩 +## Node.js Quick Start 🟩 -### Étape 1 : Créer un agent +### Step 1: Create an Agent ```javascript -import { Julep } from "@julep/sdk"; -import yaml from "js-yaml"; +// Étape 0 : Configuration +const dotenv = require('dotenv'); +const { Julep } = require('@julep/sdk'); +const yaml = require('yaml'); -const client = new Julep({ apiKey: "your_julep_api_key" }); +dotenv.config(); -async function createAgent() { - const agent = await client.agents.create({ - name: "Storytelling Agent", - model: "gpt-4", - about: - "You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", - }); +const client = new Julep({ apiKey: process.env.JULEP_API_KEY, environnement: process.env.JULEP_ENVIRONMENT || "production" }); - // 🛠️ Add an image generation tool (DALL·E) to the agent - await client.agents.tools.create(agent.id, { - name: "image_generator", - description: "Use this tool to generate images based on descriptions.", - integration: { - provider: "dalle", - method: "generate_image", - setup: { - api_key: "your_openai_api_key", - }, - }, - }); +/* Étape 1 : Créer un agent */ - return agent; +fonction asynchrone createAgent() { +agent constant = attendez que le client.agents.create({ +nom : « Agent de narration », +modèle : "claude-3.5-sonnet", +à propos de : « Vous êtes un conteur créatif qui crée des histoires captivantes sur une myriade de sujets. », + }); +agent de retour; } -``` - -### Étape 2 : Créer une tâche qui génère une histoire et une bande dessinée -```javascript -const taskYaml = ` -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. - -main: - # Step 1: Generate a story and outline into 4 panels - - prompt: - - role: system - content: You are {{agent.name}}. {{agent.about}} - - role: user - content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. - unwrap: true - - # Step 2: Extract the panel descriptions and story - - evaluate: - story: _.split('1. ')[0].trim() - panels: _.match(/\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)/g) - - # Step 3: Generate images for each panel using the image generator tool - - foreach: - in: _.panels - do: - tool: image_generator - arguments: - description: _ - - # Step 4: Generate a catchy title for the story - - prompt: - - role: system - content: You are {{agent.name}}. {{agent.about}} - - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} - unwrap: true - - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: outputs[2].map(output => output.image.url) +/* Étape 2 : Créer une tâche qui génère une histoire et une bande dessinée */ + +const tâcheYaml = ` +nom : Conteur +description : Créez une histoire basée sur une idée. + +outils: +- nom : research_wikipedia +intégration: +fournisseur : wikipedia +méthode : recherche + +principal: +# Étape 1 : Générer une idée d'intrigue +- rapide: +- rôle : système +contenu : Vous êtes {{agent.name}}. {{agent.about}} +- rôle : utilisateur +contenu : > +En vous basant sur l'idée « {{_.idea}} », générez une liste de 5 idées d'intrigue. Laissez libre cours à votre créativité. Renvoyez votre résultat sous forme de liste de longues chaînes à l'intérieur des balises \`\`\`yaml à la fin de votre réponse. +déballer : vrai + +- évaluer: +plot_ideas: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + +# Étape 2 : Extraire les domaines de recherche des idées de l'intrigue +- rapide: +- rôle : système +contenu : Vous êtes {{agent.name}}. {{agent.about}} +- rôle : utilisateur +contenu : > +Voici quelques idées d’intrigue pour une histoire : +{% pour l'idée dans _.plot_ideas %} +- {{idée}} +{% fin de %} + +Pour développer l’histoire, nous devons rechercher les idées d’intrigue. +Sur quoi devrions-nous faire des recherches ? Notez les requêtes de recherche Wikipédia pour les idées d'intrigue que vous trouvez intéressantes. +Renvoyez votre sortie sous forme de liste yaml à l'intérieur des balises \`\`\`yaml à la fin de votre réponse. +déballer : vrai +paramètres: +modèle: gpt-4o-mini +température: 0,7 + +- évaluer: +requêtes de recherche : load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + +# Étape 3 : Recherchez chaque idée d'intrigue +- pour chaque : +dans : _.research_queries +faire: +outil : research_wikipedia +Arguments: +requête: _ + +- évaluer: +wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" pour l'élément dans _ pour le document dans l'élément.documents])' + +# Étape 4 : Réfléchir et délibérer +- rapide: +- rôle : système +contenu : Vous êtes {{agent.name}}. {{agent.about}} +- rôle : utilisateur +contenu: |- +Avant d'écrire l'histoire, réfléchissons et délibérons. Voici quelques idées d'intrigue : +{% pour l'idée dans les sorties[1].plot_ideas %} +- {{idée}} +{% fin de %} + +Voici les résultats de la recherche d'idées d'intrigue sur Wikipédia : +{{_.wikipedia_results}} + +Réfléchissez aux idées de l'intrigue de manière critique. Combinez les idées de l'intrigue avec les résultats de Wikipédia pour créer une intrigue détaillée pour une histoire. +Écrivez toutes vos notes et vos pensées. +Ensuite, écrivez enfin le tracé sous forme d'objet yaml à l'intérieur des balises \`\`\`yaml à la fin de votre réponse. L'objet yaml doit avoir la structure suivante : + +\`\`\`yaml +titre: "" +personnages: +- nom: "" +à propos de: "" +résumé: "" +scènes: +- titre: "" +description: "" +personnages: +- nom: "" +rôle: "" +intrigues: + - ""\`\`\` + +Assurez-vous que le fichier YAML est valide et que les caractères et les scènes ne sont pas vides. Faites également attention aux points-virgules et autres problèmes liés à l'écriture du fichier YAML. +déballer : vrai + +- évaluer: +tracé : « load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) » `; -async function createTask(agent) { - const task = await client.tasks.create(agent.id, yaml.load(taskYaml)); - return task; -} -``` - -### Étape 3 : Exécuter la tâche - -```javascript -async function executeTask(task) { - const execution = await client.executions.create(task.id, { - input: { idea: "A cat who learns to fly" }, - }); - - // 🎉 Watch as the story and comic panels are generated - for await (const transition of client.executions.transitions.stream( - execution.id - )) { - console.log(transition); - } - - // 📦 Once the execution is finished, retrieve the results - const result = await client.executions.get(execution.id); - return result; +fonction asynchrone createTask(agentId) { +const tâche = attendre client.tasks.create( +identifiant de l'agent, +yaml.parse(tâcheYaml) + ); +tâche de retour; } -``` - -### Étape 4 : Discuter avec l'agent -```javascript -async function chatWithAgent(agent) { - const session = await client.sessions.create({ agent_id: agent.id }); +/* Étape 3 : Exécuter la tâche */ - // 💬 Send messages to the agent - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, +fonction asynchrone executeTask(taskId) { +const exécution = attendre client.executions.create(taskId, { +entrée : { idée : "Un chat qui apprend à voler" } }); - const chat = async () => { - rl.question("Enter a message (or 'quit' to exit): ", async (message) => { - if (message.toLowerCase() === "quit") { - rl.close(); - return; +// 🎉 Regardez comment l'histoire et les panneaux de bande dessinée sont générés +tandis que (vrai) { +const résultat = wait client.executions.get(execution.id); +console.log(résultat.status, résultat.output); + +si (résultat.status === 'réussi' || résultat.status === 'échec') { +// 📦 Une fois l'exécution terminée, récupérez les résultats +si (résultat.status === "réussi") { +console.log(résultat.sortie); +} autre { +lancer une nouvelle erreur (résultat.erreur); } +casser; + } - const response = await client.sessions.chat(session.id, { message }); - console.log(response); - chat(); - }); - }; - - chat(); +attendre une nouvelle promesse (résolution => setTimeout (résolution, 1000)); + } } -// Run the example -async function runExample() { - const agent = await createAgent(); - const task = await createTask(agent); - const result = await executeTask(task); - console.log("Task Result:", result); - await chatWithAgent(agent); +// Fonction principale pour exécuter l'exemple +fonction asynchrone main() { +essayer { +agent constant = wait createAgent(); +const tâche = wait createTask(agent.id); +attendre executeTask(task.id); +} catch (erreur) { +console.error("Une erreur s'est produite :", error); + } } -runExample().catch(console.error); +main().then(() => console.log("Terminé")).catch(console.error); ``` -Vous pouvez trouver l'exemple complet de Node.js [ici](example.js). +You can find the full Node.js example [here](example.js). + +
+ + Back to Top +  |  + + Table of Contents + +
-## Composants +## Components -Julep est composé des éléments suivants : +Julep is made up of the following components: -- **Plateforme Julep** : la plateforme Julep est un service cloud qui exécute vos workflows. Elle comprend un langage pour décrire les workflows, un serveur pour exécuter ces workflows et un SDK pour interagir avec la plateforme. -- **SDK Julep** : les SDK Julep sont un ensemble de bibliothèques permettant de créer des workflows. Il existe des SDK pour Python et JavaScript, et d'autres sont en cours de développement. -- **API Julep** : L'API Julep est une API RESTful que vous pouvez utiliser pour interagir avec la plateforme Julep. +- **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 API**: The Julep API is a RESTful API that you can use to interact with the Julep platform. -### Modèle mental +### Mental Model
-Considérez Julep comme une plateforme qui combine des composants côté client et côté serveur pour vous aider à créer des agents d'IA avancés. Voici comment le visualiser : +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. **Votre code d'application :** +1. **Your Application Code:** -- Vous pouvez utiliser le SDK Julep dans votre application pour définir des agents, des tâches et des workflows. -- Le SDK fournit des fonctions et des classes qui facilitent la configuration et la gestion de ces composants. + - 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. -2. **Service back-end Julep :** +2. **Julep Backend Service:** -- Le SDK communique avec le backend Julep via le réseau. -- Le backend gère l'exécution des tâches, maintient l'état de la session, stocke les documents et orchestre les flux de travail. + - The SDK communicates with the Julep backend over the network. + - The backend handles execution of tasks, maintains session state, stores documents, and orchestrates workflows. -3. **Intégration avec les outils et les API :** -- Au sein de vos workflows, vous pouvez intégrer des outils et services externes. -- Le backend facilite ces intégrations, afin que vos agents puissent, par exemple, effectuer des recherches sur le Web, accéder à des bases de données ou appeler des API tierces. +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. ## Concepts -Julep s'appuie sur plusieurs composants techniques clés qui fonctionnent ensemble pour créer de puissants flux de travail d'IA : +Julep is built on several key technical components that work together to create powerful AI workflows: -```mermaid -graph TD - User[User] ==> Session[Session] - Session --> Agent[Agent] - Agent --> Tasks[Tasks] - Agent --> LLM[Large Language Model] - Tasks --> Tools[Tools] - Agent --> Documents[Documents] - Documents --> VectorDB[Vector Database] - Tasks --> Executions[Executions] +```sirène +graphique TD +Utilisateur[Utilisateur] ==> Session[Session] +Session --> Agent[Agent] +Agent --> Tâches[Tâches] +Agent --> LLM [Modèle de langage étendu] +Tâches --> Outils[Outils] +Agent --> Documents[Documents] +Documents --> VectorDB[Base de données vectorielles] +Tâches --> Exécutions[Exécutions] - classDef client fill:#9ff,stroke:#333,stroke-width:1px; - class User client; +client classDef fill:#9ff,trait:#333,largeur-trait:1px; +classe Utilisateur client ; - classDef core fill:#f9f,stroke:#333,stroke-width:2px; - class Agent,Tasks,Session core; +classDef core fill:#f9f,trait:#333,largeur-trait:2px; +classe Agent,Tâches,Session core; ``` -- **Agents** : entités alimentées par l'IA et soutenues par de grands modèles linguistiques (LLM) qui exécutent des tâches et interagissent avec les utilisateurs. -- **Utilisateurs** : entités qui interagissent avec les agents via des sessions. -- **Sessions** : interactions avec état entre agents et utilisateurs, maintenant le contexte sur plusieurs échanges. -- **Tâches** : flux de travail programmatiques en plusieurs étapes que les agents peuvent exécuter, y compris différents types d'étapes telles que des invites, des appels d'outils et une logique conditionnelle. -- **Outils** : intégrations qui étendent les capacités d'un agent, y compris les fonctions définies par l'utilisateur, les outils système ou les intégrations d'API tierces. -- **Documents** : Objets textes ou données associés à des agents ou utilisateurs, vectorisés et stockés pour la recherche et la récupération sémantiques. -- **Exécutions** : instances de tâches qui ont été initiées avec des entrées spécifiques, avec leur propre cycle de vie et leur propre machine d'état. +- **Agents**: AI-powered entities backed by large language models (LLMs) that execute tasks and interact with users. +- **Users**: Entities that interact with agents through sessions. +- **Sessions**: Stateful interactions between agents and users, maintaining context across multiple exchanges. +- **Tasks**: Multi-step, programmatic workflows that agents can execute, including various types of steps like prompts, tool calls, and conditional logic. +- **Tools**: Integrations that extend an agent's capabilities, including user-defined functions, system tools, or third-party API integrations. +- **Documents**: Text or data objects associated with agents or users, vectorized and stored for semantic search and retrieval. +- **Executions**: Instances of tasks that have been initiated with specific inputs, with their own lifecycle and state machine. + + +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Understanding Tasks -Pour une explication plus détaillée, reportez-vous à notre [Documentation des concepts](https://github.com/julep-ai/julep/blob/dev/docs/julep-concepts.md). +Tasks are the core of Julep's workflow system. They allow you to define complex, multi-step AI workflows that your agents can execute. Here's a brief overview of task components: -## Comprendre les tâches +- **Name, Description and Input Schema**: Each task has a unique name and description for easy identification. An input schema (optional) that is used to validate the input to the task. +- **Main Steps**: The core of a task, defining the sequence of actions to be performed. Each step can be a prompt, tool call, evaluate, wait_for_input, log, get, set, foreach, map_reduce, if-else, switch, sleep, or return. (See [Types of Workflow Steps](#types-of-workflow-steps) for more details) +- **Tools**: Optional integrations that extend the capabilities of your agent during task execution. -Les tâches sont au cœur du système de workflow de Julep. Elles vous permettent de définir des workflows IA complexes en plusieurs étapes que vos agents peuvent exécuter. Voici un bref aperçu des composants des tâches : +### Lifecycle of a Task -- **Nom et description** : Chaque tâche a un nom et une description uniques pour une identification facile. -- **Étapes principales** : Le cœur d’une tâche, définissant la séquence d’actions à effectuer. -- **Outils** : intégrations facultatives qui étendent les capacités de votre agent pendant l'exécution des tâches. +You create a task using the Julep SDK and specify the main steps that the agent will execute. When you execute a task, the following lifecycle happens: -### Types d'étapes de flux de travail +```sirène +Diagramme de séquence +participant D comme votre code +participant C en tant que client Julep +participant S en tant que serveur Julep + +D->>C : Créer une tâche +C->>S : Soumettre l'exécution +Remarque sur S : Exécuter la tâche +Remarque sur S : Gérer l'état +S-->>C : Événements d'exécution +C-->>D : Mises à jour de la progression +S->>C : Fin de l'exécution +C->>D : Résultat final +``` -Les tâches dans Julep peuvent inclure différents types d'étapes, ce qui vous permet de créer des flux de travail complexes et puissants. Voici un aperçu des types d'étapes disponibles : +### Types of Workflow Steps -#### Étapes courantes +Tasks in Julep can include various types of steps, allowing you to create complex and powerful workflows. Here's an overview of the available step types: + +#### Common Steps - + + + - + - + - + - + - +
Nom À proposSyntaxeNameAboutSyntax
Rapide Prompt -Envoyez un message au modèle d'IA et recevez une réponse - +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: "Analyze the following data: {{data}}" +```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}} » ```
Appel d'outil Tool Call -Exécuter un outil intégré ou une API +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 -- tool: web_search - arguments: - query: "Latest AI developments" +```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 ```
Évaluer Evaluate -Effectuer des calculs ou manipuler des données - +Perform calculations or manipulate data +

Note: The evaluate step uses Python expressions.
-```yaml -- evaluate: - average_score: "sum(scores) / len(scores)" +```YAML +- évaluer: +average_score : somme(scores) / len(scores) ```
Attendre l'entrée Wait for Input -Suspendre le flux de travail jusqu'à ce que les données soient reçues +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 -- wait_for_input: - info: - message: "Please provide additional information." +```YAML +- attendre_la_saisie : +info: +message : « Veuillez fournir des informations supplémentaires sur {_.required_info}. » # <-- expression Python pour accéder à la variable de contexte ```
Enregistrer Log -Enregistrer une valeur ou un message spécifié +Log a specified value or message. + +

Note: The log step uses Jinja templates and you can access context variables in them.
-```yaml -- log: "Processing completed for item {{item_id}}" +```YAML +- log : « Traitement terminé pour l'élément {{_.item_id}} » # <-- modèle jinja pour accéder à la variable de contexte ```
-#### Étapes clé-valeur +#### Key-Value Steps - + - + - +
Nom À proposSyntaxe Name About Syntax
Obtenir Get -Récupérer une valeur d'un magasin clé-valeur +Retrieve a value from the execution's key-value store. -```yaml -- get: "user_preference" +```YAML +- obtenir : préférences_utilisateur ```
Ensemble Set -Attribuer une valeur à une clé dans un magasin clé-valeur +Assign a value to a key in the execution's key-value store. +

Note: The set step uses Python expressions.
-```yaml -- set: - user_preference: "dark_mode" +```YAML +- ensemble: +préférence_utilisateur : '"dark_mode"' # <-- expression python ```
-#### Étapes d'itération +#### Iteration Steps - + - + - + - +
Nom À proposSyntaxe Name About Syntax
Pour chaque Foreach -Itérer sur une collection et effectuer des étapes pour chaque élément +Iterate over a collection and perform steps for each item -```yaml -- foreach: - in: "data_list" - do: - - log: "Processing 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 ```
Carte-Réduction Map-Reduce -Cartographier une collection et réduire les résultats +Map over a collection and reduce the results -```yaml +```YAML - map_reduce: - over: "numbers" - map: - - evaluate: - squared: "_ ** 2" - reduce: "sum(results)" +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. +``` + +```YAML +- map_reduce: +plus de: _.topics +carte: +- invite : Rédigez un essai sur {{_}} +parallélisme : 10 ```
Parallèle Parallel -Exécuter plusieurs étapes en parallèle +Run multiple steps in parallel -```yaml -- parallel: - - tool: web_search - arguments: - query: "AI news" - - tool: weather_check - arguments: - location: "New York" +```YAML +- parallèle: +- outil : recherche_sur_le_web +Arguments: +requête : « Actualités sur l'IA » +- outil : weather_check +Arguments: +Lieu : « New York » ```
-#### Étapes conditionnelles +#### Conditional Steps - + - + - +
Nom À proposSyntaxe Name About Syntax
Si-Sinon If-Else -Exécution conditionnelle des étapes +Conditional execution of steps -```yaml -- if: "score > 0.8" - then: - - log: "High score achieved" - else: - - log: "Score needs improvement" +```YAML +- si : _.score > 0.8 # <-- expression python +alors: +- log : score élevé atteint +autre: +- erreur : le score doit être amélioré ```
Changer Switch -Exécuter des étapes en fonction de plusieurs conditions +Execute steps based on multiple conditions -```yaml -- switch: - - case: "category == 'A'" - then: - - log: "Category A processing" - - case: "category == 'B'" - then: - - log: "Category B processing" - - case: "_" # Default case - then: - - log: "Unknown category" +```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 ```
-#### Autre flux de contrôle +#### Other Control Flow - + - + - + - + - +
Nom À proposSyntaxe Name About Syntax
Dormir Sleep -Suspendre le flux de travail pendant une durée spécifiée +Pause the workflow for a specified duration -```yaml -- sleep: - seconds: 30 +```YAML +- dormir: +secondes: 30 +# minutes: 1 +# heures: 1 +# jours: 1 ```
Retour Return -Renvoyer une valeur du workflow +Return a value from the workflow + +

Note: The return step uses Python expressions.
-```yaml -- return: - result: "Task completed successfully" +```YAML +- retour: +résultat : " Tâche terminée avec succès " # <-- expression python +heure : datetime.now().isoformat() # <-- expression python ```
Rendement Yield -Exécuter un sous-workflow et attendre sa fin +Run a subworkflow and await its completion -```yaml -- yield: - workflow: "data_processing_subflow" - arguments: - input_data: "{{raw_data}}" +```YAML +- rendement: +flux de travail : données_de_processus +Arguments: +données d'entrée : _. données brutes # <-- expression Python ```
Erreur Error -Gérer les erreurs en spécifiant un message d'erreur +Handle errors by specifying an error message -```yaml -- error: "Invalid input provided" +```YAML +- erreur : « Entrée non valide fournie » # <-- Chaînes uniquement ```
-Chaque type d'étape remplit un objectif spécifique dans la création de workflows d'IA sophistiqués. Cette catégorisation permet de comprendre les différents flux de contrôle et opérations disponibles dans les tâches Julep. +Each step type serves a specific purpose in building sophisticated AI workflows. This categorization helps in understanding the various control flows and operations available in Julep tasks. + +
+ + Back to Top +  |  + + Table of Contents + +
-## Types d'outils +## Tool Types -Les agents peuvent avoir accès à un certain nombre d'« outils » : toute interface de programmation qu'un modèle de base peut « appeler » avec un ensemble d'entrées pour atteindre un objectif. Par exemple, il peut utiliser un outil « web_search(query) » pour rechercher des informations sur Internet. +Agents can be given access to a number of "tools" -- any programmatic interface that a foundation model can "call" with a set of inputs to achieve a goal. For example, it might use a `web_search(query)` tool to search the Internet for some information. -Contrairement aux frameworks d'agents, Julep est un backend qui gère l'exécution des agents. Les clients peuvent interagir avec les agents à l'aide de nos SDK. Julep s'occupe de l'exécution des tâches et de l'exécution des intégrations. +Unlike agent frameworks, julep is a _backend_ that manages agent execution. Clients can interact with agents using our SDKs. julep takes care of executing tasks and running integrations. -Les outils du julep peuvent être l’un des suivants : +Tools in julep can be one of: +1. **User-defined `functions`**: These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. They need to be handled by the client. The workflow will pause until the client calls the function and gives the results back to julep. +2. **`system` tools**: Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. +3. **`integrations`**: Built-in third party tools that can be used to extend the capabilities of your agents. +4. **`api_calls`**: Direct api calls during workflow executions as tool calls. -### Fonctions définies par l'utilisateur +### User-defined `functions` -Il s'agit de signatures de fonctions que vous pouvez attribuer au modèle pour qu'il puisse choisir, de la même manière que fonctionne l'appel de fonctions d'[openai]. Un exemple : +These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. An example: -```yaml -name: Example system tool task -description: List agents using system call +```YAML +nom : Exemple de tâche d'outil système +description : Lister les agents à l'aide d'un appel système -tools: - - name: send_notification - description: Send a notification to the user - type: function - function: - parameters: - type: object - properties: - text: - type: string - description: Content of the notification +outils: +- nom : send_notification +description : Envoyer une notification à l'utilisateur +type : fonction +fonction: +paramètres: +type: objet +propriétés: +texte: +type : chaîne +description : Contenu de la notification -main: - - tool: send_notification - arguments: - content: hi +principal: +- outil : send_notification +Arguments: +contenu : '"salut"' # <-- expression python ``` -Chaque fois que julep rencontre une _fonction définie par l'utilisateur_, il s'arrête, rend le contrôle au client et attend que le client exécute l'appel de fonction et renvoie les résultats à julep. +Whenever julep encounters a _user-defined function_, it pauses, giving control back to the client and waits for the client to run the function call and give the results back to julep. > [!TIP] -> **Exemple de livre de recettes** : [cookbooks/13-Error_Handling_and_Recovery.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/13-Error_Handling_and_Recovery.py) +> **Example cookbook**: [cookbooks/13-Error_Handling_and_Recovery.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/13-Error_Handling_and_Recovery.py) -### outils `système` +### `system` tools -Outils intégrés qui peuvent être utilisés pour appeler les API julep elles-mêmes, comme déclencher l'exécution d'une tâche, ajouter à un champ de métadonnées, etc. -Les outils « système » sont intégrés au backend. Ils sont exécutés automatiquement lorsque cela est nécessaire. Ils ne nécessitent aucune action du côté client. +Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. -Par exemple, +`system` tools are built into the backend. They get executed automatically when needed. They do _not_ require any action from the client-side. -```yaml -name: Example system tool task -description: List agents using system call +For example, -tools: - - name: list_agents - description: List all agents - type: system - system: - resource: agent - operation: list -main: - - tool: list_agents - arguments: - limit: 10 -``` +```YAML +nom : Exemple de tâche d'outil système +description : Lister les agents à l'aide d'un appel système -> [!TIP] -> **Exemple de livre de recettes** : [cookbooks/10-Document_Management_and_Search.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py) +outils: +- nom : list_agent_docs +description : Liste tous les documents pour l'agent donné +type : système +système: +ressource : agent +sous-ressource : doc +opération : liste -### « Intégrations » intégrées +principal: +- outil : list_agents +Arguments: +limite : 10 # <-- expression python +``` -Julep est livré avec un certain nombre d'intégrations intégrées (comme décrit dans la section ci-dessous). Les outils « d'intégration » sont directement exécutés sur le backend de Julep. Tous les paramètres supplémentaires dont ils ont besoin au moment de l'exécution peuvent être définis dans les champs « métadonnées » de l'agent/session/utilisateur. +#### Available `system` resources and operations + +- `agent`: + - `list`: List all agents. + - `get`: Get a single agent by id. + - `create`: Create a new agent. + - `update`: Update an existing agent. + - `delete`: Delete an existing agent. + +- `user`: + - `list`: List all users. + - `get`: Get a single user by id. + - `create`: Create a new user. + - `update`: Update an existing user. + - `delete`: Delete an existing user. + +- `session`: + - `list`: List all sessions. + - `get`: Get a single session by id. + - `create`: Create a new session. + - `update`: Update an existing session. + - `delete`: Delete an existing session. + - `chat`: Chat with a session. + - `history`: Get the chat history with a session. + +- `task`: + - `list`: List all tasks. + - `get`: Get a single task by id. + - `create`: Create a new task. + - `update`: Update an existing task. + - `delete`: Delete an existing task. + +- `doc` (subresource for `agent` and `user`): + - `list`: List all documents. + - `create`: Create a new document. + - `delete`: Delete an existing document. + - `search`: Search for documents. + +Additional operations available for some resources: +- `embed`: Embed a resource (specific resources not specified in the provided code). +- `change_status`: Change the status of a resource (specific resources not specified in the provided code). +- `chat`: Chat with a resource (specific resources not specified in the provided code). +- `history`: Get the chat history with a resource (specific resources not specified in the provided code). +- `create_or_update`: Create a new resource or update an existing one (specific resources not specified in the provided code). + +Note: The availability of these operations may vary depending on the specific resource and implementation details. > [!TIP] -> **Exemple de livre de recettes** : [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) +> **Example cookbook**: [cookbooks/10-Document_Management_and_Search.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py) -Le backend Julep est livré avec des outils tiers intégrés provenant des fournisseurs suivants : +### Built-in `integrations` -- [composio](https://composio.dev) -- [anonyme](https://anon.com) -- [boîtes à outils langchain](https://python.langchain.com/v0.2/docs/integrations/toolkits/) +Julep comes with a number of built-in integrations (as described in the section below). `integration` tools are directly executed on the julep backend. Any additional parameters needed by them at runtime can be set in the agent/session/user's `metadata` fields. -La prise en charge des boîtes à outils _Github, Gitlab, Gmail, Jira, MultiOn, Slack_ est prévue. +See [Integrations](#integrations) for details on the available integrations. -Étant donné que _composio_ et _anon_ sont des fournisseurs tiers, leurs outils nécessitent la configuration d'une liaison de compte. +> [!TIP] +> **Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) -### Appels directs `api_calls` -julep peut également effectuer directement des appels d'API lors des exécutions de workflows sous forme d'appels d'outils. Comme pour `integration`, des paramètres d'exécution supplémentaires sont chargés à partir des champs `metadata`. +### Direct `api_calls` -Par exemple, +julep can also directly make api calls during workflow executions as tool calls. Same as `integration`s, additional runtime parameters are loaded from `metadata` fields. -```yaml -name: Example api_call task -tools: - - type: api_call - name: hello - api_call: - method: GET - url: https://httpbin.org/get -main: - - tool: hello - arguments: - params: - test: _.input +For example, + +```YAML +nom : Exemple de tâche api_call +outils: +- type : api_call +nom : bonjour +appel_API : +méthode : GET +URL: https://httpbin.org/get + +principal: +- outil : bonjour +Arguments: +json: +test: _.input # <-- expression python ``` -## Intégrations +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Integrations -Julep prend en charge diverses intégrations qui étendent les capacités de vos agents IA. Voici une liste des intégrations disponibles et de leurs arguments pris en charge : +Julep supports various integrations that extend the capabilities of your AI agents. Here's a list of available integrations and their supported arguments: - + - + - + - + - + - +
Recherche courageuse Brave Search -```yaml -setup: - api_key: string # The API key for Brave Search +```YAML +installation: +api_key : chaîne # La clé API pour Brave Search -arguments: - query: string # The search query for searching with Brave +Arguments: +requête : chaîne # La requête de recherche pour rechercher avec Brave -output: - result: string # The result of the Brave Search +sortir: +résultat : chaîne # Le résultat de la recherche Brave ``` -**Exemple de livre de recettes** : [cookbooks/03-SmartResearcher_With_WebSearch.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-SmartResearcher_With_WebSearch.ipynb) +**Example cookbook**: [cookbooks/03-SmartResearcher_With_WebSearch.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-SmartResearcher_With_WebSearch.ipynb)
Base de navigateur BrowserBase -```yaml -setup: - api_key: string # The API key for BrowserBase - project_id: string # The project ID for BrowserBase - session_id: string # (Optional) The session ID for 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: list[string] # The URLs for loading with BrowserBase +Arguments: +urls : liste[chaîne] # Les URL pour le chargement avec BrowserBase -output: - documents: list # The documents loaded from the URLs +sortir: +documents : liste # Les documents chargés à partir des URL ```
E-mail Email -```yaml -setup: - host: string # The host of the email server - port: integer # The port of the email server - user: string # The username of the email server - password: string # The password of the email server - -arguments: - to: string # The email address to send the email to - from: string # The email address to send the email from - subject: string # The subject of the email - body: string # The body of the email - -output: - success: boolean # Whether the email was sent successfully +```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 ``` -**Exemple de livre de recettes** : [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb) +**Example cookbook**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb)
Araignée Spider -```yaml -setup: - spider_api_key: string # The API key for Spider +```YAML +installation: +spider_api_key : chaîne # La clé API pour Spider -arguments: - url: string # The URL for which to fetch data - mode: string # The type of crawlers (default: "scrape") - params: dict # (Optional) The parameters for the Spider API +Arguments: +url : chaîne # L'URL pour laquelle récupérer les données +mode : chaîne # Le type de robots d'exploration (par défaut : « scrape ») +paramètres : dict # (facultatif) Les paramètres de l'API Spider -output: - documents: list # The documents returned from the spider +sortir: +documents : liste # Les documents renvoyés par l'araignée ``` -**Exemple de livre de recettes** : [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) +**Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb)
Météo Weather -```yaml -setup: - openweathermap_api_key: string # The API key for OpenWeatherMap +```YAML +installation: +openweathermap_api_key : chaîne # La clé API pour OpenWeatherMap -arguments: - location: string # The location for which to fetch weather data +Arguments: +emplacement : chaîne # L'emplacement pour lequel récupérer les données météorologiques -output: - result: string # The weather data for the specified location +sortir: +résultat : chaîne # Les données météorologiques pour l'emplacement spécifié ``` -**Exemple de livre de recettes** : [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb) +**Example cookbook**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb)
Wikipédia Wikipedia -```yaml -arguments: - query: string # The search query string - load_max_docs: integer # Maximum number of documents to load (default: 2) +```YAML +Arguments: +requête : chaîne # La chaîne de requête de recherche +load_max_docs : entier # Nombre maximal de documents à charger (par défaut : 2) -output: - documents: list # The documents returned from the Wikipedia search +sortir: +documents : liste # Les documents renvoyés par la recherche sur Wikipédia ``` -**Exemple de livre de recettes** : [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb) +**Example cookbook**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb)
-Pour plus de détails, reportez-vous à notre [Documentation sur les intégrations](https://docs.julep.ai/integrations). +For more details, refer to our [Integrations Documentation](#integrations). + +
+ + Back to Top +  |  + + Table of Contents + +
-## Autres fonctionnalités +## Other Features -Julep propose une gamme de fonctionnalités avancées pour améliorer vos flux de travail d'IA : +Julep offers a range of advanced features to enhance your AI workflows: -### Ajout d'outils aux agents +### Adding Tools to Agents -Étendez les capacités de votre agent en intégrant des outils et des API externes : +Extend your agent's capabilities by integrating external tools and APIs: ```python -client.agents.tools.create( - agent_id=agent.id, - name="web_search", - description="Search the web for information.", - integration={ - "provider": "brave", - "method": "search", - "setup": {"api_key": "your_brave_api_key"}, +client.agents.outils.créer( +agent_id=agent.id, +nom="recherche_sur_le_web", +description="Rechercher des informations sur le Web.", +intégration={ +"fournisseur": "courageux", +"méthode": "recherche", +"setup": {"api_key": "votre_brave_api_key"}, }, ) ``` -### Gestion des sessions et des utilisateurs +### Managing Sessions and Users -Julep fournit une gestion de session robuste pour les interactions persistantes : +Julep provides robust session management for persistent interactions: ```python session = client.sessions.create( - agent_id=agent.id, - user_id=user.id, - context_overflow="adaptive" +agent_id=agent.id, +user_id=utilisateur.id, +context_overflow="adaptatif" ) -# Continue conversation in the same session -response = client.sessions.chat( - session_id=session.id, - messages=[ +# Poursuivre la conversation dans la même session +réponse = client.sessions.chat( +session_id=session.id, +messages=[ { - "role": "user", - "content": "Follow up on the previous conversation." +"rôle": "utilisateur", +« contenu » : « Suivi de la conversation précédente. » } ] ) ``` -### Intégration et recherche de documents +### Document Integration and Search -Gérez et recherchez facilement des documents pour vos agents : +Easily manage and search through documents for your agents: ```python -# Upload a document +# Télécharger un document document = client.agents.docs.create( - title="AI advancements", - content="AI is changing the world...", - metadata={"category": "research_paper"} +titre="Progrès de l'IA", +content="L'IA change le monde...", +métadonnées={"category": "article_de_recherche"} ) -# Search documents -results = client.agents.docs.search( - text="AI advancements", - metadata_filter={"category": "research_paper"} +# Rechercher des documents +résultats = client.agents.docs.search( +texte="Progrès de l'IA", +metadata_filter={"category": "article_de_recherche"} ) ``` +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Référence + +### Référence du SDK + +- **Node.js** [Référence SDK](https://github.com/julep-ai/node-sdk/blob/main/api.md) | [Package NPM](https://www.npmjs.com/package/@julep/sdk) +- **Python** [Référence SDK](https://github.com/julep-ai/python-sdk/blob/main/api.md) | [Package PyPI](https://pypi.org/project/julep/) + +### Référence API + +Explorez notre documentation API pour en savoir plus sur les agents, les tâches et les exécutions : + +- [API des agents](https://dev.julep.ai/api/docs#tag/agents) +- [API des tâches](https://dev.julep.ai/api/docs#tag/tasks) +- [API d'exécution](https://dev.julep.ai/api/docs#tag/executions) + +
+ + Back to Top +  |  + + Table of Contents + +
+ ## Démarrage rapide local **Exigences**: @@ -1259,22 +1526,19 @@ results = client.agents.docs.search( 5. `cp .env.example .env # <-- Modifier ce fichier` 6. `docker compose --env-file .env --profile temporal-ui --profile single-tenant --profile self-hosted-db up --build` -## Référence du SDK - -- [Kit de développement logiciel Node.js](https://github.com/julep-ai/node-sdk/blob/main/api.md) -- [SDK Python](https://github.com/julep-ai/python-sdk/blob/main/api.md) - -## Référence API - -Explorez notre documentation API complète pour en savoir plus sur les agents, les tâches et les exécutions : +
+ + Back to Top +  |  + + Table of Contents + +
-- [API des agents](https://api.julep.ai/api/docs#tag/agents) -- [API des tâches](https://api.julep.ai/api/docs#tag/tasks) -- [API d'exécution](https://api.julep.ai/api/docs#tag/executions) ***** -## Pourquoi Julep vs. LangChain ? +## Quelle est la différence entre Julep et LangChain etc ? ### Différents cas d'utilisation @@ -1312,5 +1576,8 @@ Choisissez Julep lorsque vous avez besoin d'un framework robuste pour les agents
Back to Top +  |  + + Table of Contents
diff --git a/README-JA.md b/README-JA.md index 1a3b1682e..a9aebe72a 100644 --- a/README-JA.md +++ b/README-JA.md @@ -6,7 +6,7 @@


- ドキュメントを見る + ドキュメントを見る · 不和 · @@ -62,45 +62,40 @@ Julep プロジェクトに新しい貢献者を迎えられることを嬉し -

-

📖 Table of Contents

- -- [主な特徴](#%E4%B8%BB%E3%81%AA%E7%89%B9%E5%BE%B4) -- [簡単な例](#%E7%B0%A1%E5%8D%98%E3%81%AA%E4%BE%8B) -- [インストール](#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) -- [Python クイックスタート 🐍](#python-%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88-) - - [ステップ 1: エージェントを作成する](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%97-1-%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B) - - [ステップ2: ストーリーと漫画を生成するタスクを作成する](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%972-%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AA%E3%83%BC%E3%81%A8%E6%BC%AB%E7%94%BB%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B) - - [ステップ3: タスクを実行する](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%973-%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B) - - [ステップ4: エージェントとチャットする](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%974-%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%81%A8%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E3%81%99%E3%82%8B) -- [Node.js クイックスタート 🟩](#nodejs-%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88-) - - [ステップ 1: エージェントを作成する](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%97-1-%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B-1) - - [ステップ2: ストーリーと漫画を生成するタスクを作成する](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%972-%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AA%E3%83%BC%E3%81%A8%E6%BC%AB%E7%94%BB%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B-1) - - [ステップ3: タスクを実行する](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%973-%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B-1) - - [ステップ4: エージェントとチャットする](#%E3%82%B9%E3%83%86%E3%83%83%E3%83%974-%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%81%A8%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E3%81%99%E3%82%8B-1) -- [コンポーネント](#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88) - - [メンタルモデル](#%E3%83%A1%E3%83%B3%E3%82%BF%E3%83%AB%E3%83%A2%E3%83%87%E3%83%AB) -- [コンセプト](#%E3%82%B3%E3%83%B3%E3%82%BB%E3%83%97%E3%83%88) -- [タスクを理解する](#%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B) - - [ワークフローステップの種類](#%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%81%AE%E7%A8%AE%E9%A1%9E) -- [ツールの種類](#%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AE%E7%A8%AE%E9%A1%9E) - - [ユーザー定義の `functions`](#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E5%AE%9A%E7%BE%A9%E3%81%AE-functions) - - [`システム` ツール](#%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-%E3%83%84%E3%83%BC%E3%83%AB) - - [組み込みの `integrations`](#%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AE-integrations) - - [直接の `api_calls`](#%E7%9B%B4%E6%8E%A5%E3%81%AE-api_calls) -- [統合](#%E7%B5%B1%E5%90%88) -- [その他の機能](#%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E6%A9%9F%E8%83%BD) - - [エージェントへのツールの追加](#%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%81%B8%E3%81%AE%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AE%E8%BF%BD%E5%8A%A0) - - [セッションとユーザーの管理](#%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E7%AE%A1%E7%90%86) - - [ドキュメントの統合と検索](#%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E7%B5%B1%E5%90%88%E3%81%A8%E6%A4%9C%E7%B4%A2) -- [ローカルクイックスタート](#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88) -- [SDK リファレンス](#sdk-%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9) -- [APIリファレンス](#api%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9) -- [Julep と LangChain を比較する理由](#julep-%E3%81%A8-langchain-%E3%82%92%E6%AF%94%E8%BC%83%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1) - - [さまざまなユースケース](#%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9) - - [異なるフォームファクタ](#%E7%95%B0%E3%81%AA%E3%82%8B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF) +

📖 目次

+ +- [はじめに](#introduction) +- [主な特徴](#key-features) +- [簡単な例](#quick-example) +- [インストール](#installation) +- [Python クイックスタート 🐍](#python-quick-start-) +- [Node.js クイック スタート 🟩](#nodejs-quick-start-) +- [ステップ 1: エージェントを作成する](#step-1-create-an-agent) +- [コンポーネント](#components) +- [メンタルモデル](#mental-model) +- [コンセプト](#concepts) +- [タスクの理解](#understanding-tasks) +- [タスクのライフサイクル](#lifecycle-of-a-task) +- [ワークフロー ステップの種類](#types-of-workflow-steps) +- [ツールの種類](#tool-types) +- [ユーザー定義の `functions`](#user-defined-functions) +- [`システム` ツール](#system-tools) +- [組み込みの `integrations`](#built-in-integrations) +- [直接の `api_calls`](#direct-api_calls) +- [統合](#integrations) +- [その他の機能](#other-features) +- [エージェントへのツールの追加](#adding-tools-to-agents) +- [セッションとユーザーの管理](#managing-sessions-and-users) +- [ドキュメントの統合と検索](#document-integration-and-search) +- [参考](#reference) +- [SDKリファレンス](#sdk-reference) +- [APIリファレンス](#api-reference) +- [ローカルクイックスタート](#local-quickstart) +- [Julep と LangChain などの違いは何ですか?](#whats-the-difference-between-julep-and-langchain-etc) +- [さまざまなユースケース](#different-use-cases) +- [異なるフォームファクター](#different-form-factor) +- [要約](#in-summary) -
## 導入 @@ -109,40 +104,46 @@ Julep は、過去のやり取りを記憶し、複雑なタスクを実行で Julep を使用すると、意思決定、ループ、並列処理、多数の外部ツールや API との統合を組み込んだ複数ステップのタスクを作成できます。 -多くの AI アプリケーションは、分岐が最小限の、プロンプトと API 呼び出しの単純な線形チェーンに制限されていますが、Julep はより複雑なシナリオを処理できるように構築されています。 +多くの AI アプリケーションは、最小限の分岐によるプロンプトと API 呼び出しの単純な線形チェーンに制限されていますが、Julep は次のようなより複雑なシナリオを処理できるように構築されています。 -サポート対象: - -- 複雑で多段階のプロセス -- ダイナミックな意思決定 -- 並列実行 +- 複数のステップがある、 +- モデルの出力に基づいて意思決定を行う +- 平行枝を生成し、 +- たくさんのツールを使い、 +- 長時間走る。 > [!ヒント] -> 単純な質問に答えるだけでなく、複雑なタスクを処理し、過去のやり取りを記憶し、場合によっては他のツールや API も使用できる AI エージェントを構築したいとします。そこで Julep の出番です。 +> 単純な質問に答えるだけでなく、複雑なタスクを処理し、過去のやり取りを記憶し、場合によっては他のツールや API も使用できる AI エージェントを構築したいとします。そこで Julep の出番です。詳細については、[タスクの理解](#understanding-tasks) をお読みください。 ## 主な特徴 1. 🧠 **永続的な AI エージェント**: 長期にわたるやり取りを通じてコン​​テキストと情報を記憶します。 2. 💾 **ステートフル セッション**: 過去のやり取りを追跡して、パーソナライズされた応答を提供します。 -3. 🔄 **複数ステップのタスク**: ループと意思決定を使用して、複雑な複数ステップのプロセスを構築します。 +3. 🔄 **複数ステップのタスク**: ループと意思決定を含む複雑な複数ステップのプロセスを構築します。 4. ⏳ **タスク管理**: 無期限に実行される可能性のある長時間実行タスクを処理します。 5. 🛠️ **組み込みツール**: タスクで組み込みツールと外部 API を使用します。 6. 🔧 **自己修復**: Julep は失敗したステップを自動的に再試行し、メッセージを再送信し、一般的にタスクがスムーズに実行されるようにします。 7. 📚 **RAG**: Julep のドキュメント ストアを使用して、独自のデータを取得して使用するためのシステムを構築します。 -Julep は、単純なプロンプト応答モデルを超えた AI ユースケースを必要とするアプリケーションに最適です。 +![機能](https://github.com/user-attachments/assets/4355cbae-fcbd-4510-ac0d-f8f77b73af70) + +> [!ヒント] +> Julep は、単純なプロンプト応答モデルを超えた AI ユースケースを必要とするアプリケーションに最適です。 ## 簡単な例 次のことができる研究 AI エージェントを想像してください。 -1. トピックを取り上げ、 -2. そのトピックについて100個の検索クエリを考えます。 +1. **トピックを選ぶ**、 +2. そのトピックについて**100個の検索クエリを考え出す** 3. ウェブ検索を並行して実行する -4. 結果をまとめる -5.要約をDiscordに送信する +4. 結果を**要約**します。 +5. **要約を Discord に送信**します。 + +> [!注意] +> Julepでは、これは単一のタスクになります80行のコードそして走る完全に管理されたすべて自動的に行われます。すべての手順は Julep の独自のサーバー上で実行されるため、何もする必要はありません。 -Julepでは、これは単一のタスクになります80行のコードそして走る完全に管理されたすべては Julep のサーバー上で実行されます。すべての手順は Julep のサーバー上で実行されるため、何もする必要はありません。次に動作例を示します。 +実際の例を次に示します。 ```yaml name: Research Agent @@ -162,12 +163,12 @@ tools: integration: provider: brave setup: - api_key: "YOUR_BRAVE_API_KEY" + api_key: BSAqES7dj9d... # dummy key - name: discord_webhook type: api_call api_call: - url: "YOUR_DISCORD_WEBHOOK_URL" + url: https://eobuxj02se0n.m.pipedream.net # dummy requestbin method: POST headers: Content-Type: application/json @@ -199,7 +200,7 @@ main: tool: web_search arguments: query: "_" - parallelism: 100 + parallelism: 10 # Collect the results from the web search - evaluate: @@ -213,28 +214,74 @@ main: The summary should be well-structured, informative, and highlight key findings and insights: {{_.results}} unwrap: true + settings: + model: gpt-4o-mini # Send the summary to Discord - tool: discord_webhook arguments: - content: > - **Research Summary for {{inputs[0].topic}}** + content: |- + f''' + **Research Summary for {inputs[0].topic}** - {{_}} + {_} + ''' ``` この例では、Julep は並列実行を自動的に管理し、失敗したステップを再試行し、API リクエストを再送信し、タスクが完了するまで確実に実行し続けます。 +> これは 30 秒以内に実行され、次の出力を返します。 + +
+AIに関する研究概要 (クリックして拡大) + +> **AIに関する研究概要** +> +> ### 人工知能(AI)に関する研究成果の概要 +> +> #### はじめに +> 人工知能 (AI) の分野は近年、機械が環境を認識し、データから学習し、意思決定を行える方法とテクノロジーの開発により、大きな進歩を遂げています。この概要では、AI に関連するさまざまな研究結果から得られた洞察に主に焦点を当てています。 +> +> #### 主な調査結果 +> +> 1. **AIの定義と範囲**: +> - AI は、学習、推論、問題解決など、人間のような知能を必要とするタスクを実行できるシステムの作成に重点を置いたコンピューター サイエンスの分野として定義されています (Wikipedia)。 +> - 機械学習、自然言語処理、ロボット工学、コンピュータービジョンなど、さまざまなサブフィールドを網羅しています。 +> +> 2. **影響と応用**: +> - AI テクノロジーはさまざまな分野に統合され、効率性と生産性を向上させています。その応用範囲は、自律走行車やヘルスケア診断から顧客サービスの自動化や財務予測まで多岐にわたります (OpenAI)。 +> - AI をすべての人にとって有益なものにするという Google の取り組みは、さまざまなプラットフォームでユーザー エクスペリエンスを強化することで日常生活を大幅に改善する可能性を強調しています (Google AI)。 +> +> 3. **倫理的配慮**: +> - プライバシー、偏見、意思決定プロセスの説明責任に関する懸念など、AI の倫理的影響に関する議論が続いています。AI 技術の安全で責任ある使用を保証するフレームワークの必要性が強調されています (OpenAI)。 +> +> 4. **学習メカニズム**: +> - AI システムは、教師あり学習、教師なし学習、強化学習などのさまざまな学習メカニズムを活用します。これらの方法により、AI は過去の経験やデータから学習することで、時間の経過とともにパフォーマンスを向上させることができます (Wikipedia)。 +> - 教師あり学習と教師なし学習の区別は重要です。教師あり学習はラベル付きデータに依存しますが、教師なし学習は事前定義されたラベルなしでパターンを識別します (教師なし)。 +> +> 5. **今後の方向性**: +> - 今後の AI 開発では、AI システムの解釈可能性と透明性を高め、正当な判断と行動を提供できるようにすることに重点が置かれると予想されます (OpenAI)。 +> - AI システムをよりアクセスしやすく、ユーザーフレンドリーなものにし、さまざまな人口統計や業界での幅広い導入を促進する動きもあります (Google AI)。 +> +> #### 結論 +> AI は複数の領域に変革をもたらす力を持ち、産業の再構築や生活の質の向上が期待されています。しかし、AI の機能が拡大するにつれて、倫理的および社会的影響に対処することが極めて重要になります。AI の将来像を見据えるには、技術者、倫理学者、政策立案者による継続的な研究と協力が不可欠です。 + +
+ ## インストール Julep を使い始めるには、[npm](https://www.npmjs.com/package/@julep/sdk) または [pip](https://pypi.org/project/julep/) を使用してインストールします。 +**Node.js**: ```bash npm install @julep/sdk -``` -または +# or +bun add @julep/sdk +``` + +**Python**: ```bash pip install julep ``` @@ -251,997 +298,1219 @@ pip install julep ## Python クイックスタート 🐍 -### ステップ 1: エージェントを作成する - ```python +### Step 0: Setup + +import time import yaml from julep import Julep # or AsyncJulep client = Julep(api_key="your_julep_api_key") +### Step 1: Create an Agent + agent = client.agents.create( name="Storytelling Agent", - model="gpt-4o", - about="You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", + model="claude-3.5-sonnet", + about="You are a creative storyteller that crafts engaging stories on a myriad of topics.", ) -# 🛠️ Add an image generation tool (DALL·E) to the agent -client.agents.tools.create( - agent_id=agent.id, - name="image_generator", - description="Use this tool to generate images based on descriptions.", - integration={ - "provider": "dalle", - "method": "generate_image", - "setup": { - "api_key": "your_openai_api_key", - }, - }, -) -``` +### Step 2: Create a Task that generates a story and comic strip -### ステップ2: ストーリーと漫画を生成するタスクを作成する - -入力されたアイデアに基づいてストーリーを作成し、パネル化された漫画を生成するためのマルチステップタスクを定義しましょう。 - -```python -# 📋 Task -# Create a task that takes an idea and creates a story and a 4-panel comic strip task_yaml = """ -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside ```応答の最後に yaml タグを追加します。 +アンラップ: true + +- 評価する: +plot_ideas: load_yaml(_.split('```yaml')[1].split('```')[0].ストリップ()) + +# ステップ2: プロットのアイデアから研究分野を抽出する +- プロンプト: +- 役割: システム +内容: あなたは {{agent.name}} です。 {{agent.about}} +- 役割: ユーザー +内容: > +ストーリーのプロットのアイデアをいくつか紹介します。 +{% for idea in _.plot_ideas %} +- {{アイデア}} +{% endfor %} + +ストーリーを展開するには、プロットのアイデアをリサーチする必要があります。 +何を研究すべきでしょうか? 興味深いと思うプロットのアイデアについて、Wikipedia の検索クエリを書き留めてください。 +出力をyamlリストとして返します```yaml tags at the end of your response. unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].strip() - panels: re.findall(r'\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)', _) + research_queries: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) - # Step 3: Generate images for each panel using the image generator tool + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ - # Step 4: Generate a catchy title for the story + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' + + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} - unwrap: true - - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: "[output.image.url for output in outputs[2]]" + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside ```応答の最後に yaml タグを追加します。yaml オブジェクトの構造は次のようになります。 + + ```yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""``` + +yaml が有効であり、文字とシーンが空でないことを確認してください。また、セミコロンや yaml の記述に関するその他の注意点にも注意してください。 +アンラップ: true + +- 評価する: +プロット: "load_yaml(_.split('```yaml')[1].split('```')[0].strip())" """ -task = client.tasks.create( - agent_id=agent.id, - **yaml.safe_load(task_yaml) +タスク = client.tasks.create( +エージェントID=エージェントID、 +**yaml.safe_load(タスクyaml) ) -``` ### ステップ3: タスクを実行する -```python -# 🚀 Execute the task with an input idea -execution = client.executions.create( - task_id=task.id, - input={"idea": "A cat who learns to fly"} +実行 = client.executions.create( +タスクID=タスクID、 +input={"idea": "飛ぶことを学ぶ猫"} ) -# 🎉 Watch as the story and comic panels are generated -for transition in client.executions.transitions.stream(execution_id=execution.id): - print(transition) +# 🎉 ストーリーと漫画パネルが生成される様子をご覧ください +while (result := client.executions.get(execution.id)).status が ['succeeded', 'failed'] の範囲外です: +print(結果.ステータス、結果.出力) +時間.睡眠(1) -# 📦 Once the execution is finished, retrieve the results -result = client.executions.get(execution_id=execution.id) +# 📦 実行が完了したら、結果を取得します +result.status == "成功"の場合: +print(結果.出力) +それ以外: +例外(結果.エラー)を発生させる ``` -### ステップ4: エージェントとチャットする - -エージェントとの対話型チャット セッションを開始します。 - -```python -session = client.sessions.create(agent_id=agent.id) - -# 💬 Send messages to the agent -while (message := input("Enter a message: ")) != "quit": - response = client.sessions.chat( - session_id=session.id, - message=message, - ) +You can find the full python example [here](example.py). - print(response) -``` +
+ + Back to Top +  |  + + Table of Contents + +
-完全な Python の例は [ここ](example.py) にあります。 +## Node.js Quick Start 🟩 -## Node.js クイックスタート 🟩 +### Step 1: Create an Agent -### ステップ 1: エージェントを作成する +```ジャバスクリプト +// ステップ 0: セットアップ +定数dotenv = require('dotenv'); +Julep のクラスを '@julep/sdk' として定義します。 +yaml を require('yaml'); -```javascript -import { Julep } from "@julep/sdk"; -import yaml from "js-yaml"; +config() を呼び出します。 -const client = new Julep({ apiKey: "your_julep_api_key" }); +const client = new Julep({ apiKey: process.env.JULEP_API_KEY, 環境: process.env.JULEP_ENVIRONMENT || "production" }); -async function createAgent() { - const agent = await client.agents.create({ - name: "Storytelling Agent", - model: "gpt-4", - about: - "You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", - }); +/* ステップ 1: エージェントを作成する */ - // 🛠️ Add an image generation tool (DALL·E) to the agent - await client.agents.tools.create(agent.id, { - name: "image_generator", - description: "Use this tool to generate images based on descriptions.", - integration: { - provider: "dalle", - method: "generate_image", - setup: { - api_key: "your_openai_api_key", - }, - }, +非同期関数createAgent() { +const エージェント = クライアント.エージェント.作成を待機します({ +名前: 「ストーリーテリングエージェント」 +モデル: "claude-3.5-sonnet", +概要: 「あなたは、さまざまなトピックについて魅力的なストーリーを作り上げることができるクリエイティブなストーリーテラーです。」 }); - - return agent; +返品エージェント; } -``` - -### ステップ2: ストーリーと漫画を生成するタスクを作成する - -```javascript -const taskYaml = ` -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. - -main: - # Step 1: Generate a story and outline into 4 panels - - prompt: - - role: system - content: You are {{agent.name}}. {{agent.about}} - - role: user - content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. - unwrap: true - - # Step 2: Extract the panel descriptions and story - - evaluate: - story: _.split('1. ')[0].trim() - panels: _.match(/\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)/g) - # Step 3: Generate images for each panel using the image generator tool - - foreach: - in: _.panels - do: - tool: image_generator - arguments: - description: _ - - # Step 4: Generate a catchy title for the story - - prompt: - - role: system - content: You are {{agent.name}}. {{agent.about}} - - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} - unwrap: true - - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: outputs[2].map(output => output.image.url) +/* ステップ 2: ストーリーと漫画を生成するタスクを作成する */ + +const タスクYaml = ` +名前: ストーリーテラー +説明: アイデアに基づいてストーリーを作成します。 + +ツール: +- 名前: research_wikipedia +統合: +提供元: wikipedia +方法: 検索 + +主要: +# ステップ1: プロットのアイデアを生み出す +- プロンプト: +- 役割: システム +内容: あなたは {{agent.name}} です。 {{agent.about}} +- 役割: ユーザー +内容: > +アイデア「{{_.idea}}」に基づいて、5 つのプロット アイデアのリストを生成します。自由に創造的に考えてください。出力は、応答の最後に \`\`\`yaml タグ内の長い文字列のリストとして返されます。 +アンラップ: true + +- 評価する: +plot_ideas: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + +# ステップ2: プロットのアイデアから研究分野を抽出する +- プロンプト: +- 役割: システム +内容: あなたは {{agent.name}} です。 {{agent.about}} +- 役割: ユーザー +内容: > +ストーリーのプロットのアイデアをいくつか紹介します。 +{% for idea in _.plot_ideas %} +- {{アイデア}} +{% endfor %} + +ストーリーを展開するには、プロットのアイデアをリサーチする必要があります。 +何を研究すべきでしょうか? 興味深いと思うプロットのアイデアについて、Wikipedia の検索クエリを書き留めてください。 +応答の最後に、\`\`\`yaml タグ内の yaml リストとして出力を返します。 +アンラップ: true +設定: +モデル: gpt-4o-mini +温度: 0.7 + +- 評価する: +リサーチクエリ: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + +# ステップ3: 各プロットのアイデアをリサーチする +- 各: +in: _.research_queries +する: +ツール: research_wikipedia +引数: +クエリ: _ + +- 評価する: +wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' + +# ステップ4: 考えて熟考する +- プロンプト: +- 役割: システム +内容: あなたは {{agent.name}} です。 {{agent.about}} +- 役割: ユーザー +内容: |- +物語を書く前に、考え、熟考してみましょう。ここにいくつかのプロットのアイデアがあります: +{% 出力[1].plot_ideas のアイデア %} +- {{アイデア}} +{% endfor %} + +Wikipedia でプロットのアイデアを調査した結果は次のとおりです。 +{{_.wikipedia_results}} + +プロットのアイデアを批判的に考えます。プロットのアイデアと Wikipedia の結果を組み合わせて、ストーリーの詳細なプロットを作成します。 +メモや考えをすべて書き留めてください。 +最後に、レスポンスの最後にある \`\`\`yaml タグ内に yaml オブジェクトとしてプロットを記述します。yaml オブジェクトの構造は次のようになります。 + +\`\`\`yaml +タイトル: "" +文字: +- 名前: "" +について: "" +概要: "" +シーン: +- タイトル: "" +説明: "" +文字: +- 名前: "" +役割: "" +ストーリーライン: + - "「\`\`\` + +yaml が有効であり、文字とシーンが空でないことを確認してください。また、セミコロンや yaml の記述に関するその他の注意点にも注意してください。 +アンラップ: true + +- 評価する: +プロット: "load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip())" `; -async function createTask(agent) { - const task = await client.tasks.create(agent.id, yaml.load(taskYaml)); - return task; +非同期関数createTask(agentId) { +const タスク = クライアント.タスク.作成を待機します( +エージェントID、 +yaml.parse(タスクYaml) + ); +タスクを返す。 } -``` -### ステップ3: タスクを実行する +/* ステップ 3: タスクを実行する */ -```javascript -async function executeTask(task) { - const execution = await client.executions.create(task.id, { - input: { idea: "A cat who learns to fly" }, +非同期関数executeTask(taskId) { +const 実行 = クライアント.実行.作成(taskId, { +入力: { アイデア: 「飛ぶことを学ぶ猫」 } }); - // 🎉 Watch as the story and comic panels are generated - for await (const transition of client.executions.transitions.stream( - execution.id - )) { - console.log(transition); - } - - // 📦 Once the execution is finished, retrieve the results - const result = await client.executions.get(execution.id); - return result; -} -``` - -### ステップ4: エージェントとチャットする - -```javascript -async function chatWithAgent(agent) { - const session = await client.sessions.create({ agent_id: agent.id }); - - // 💬 Send messages to the agent - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - - const chat = async () => { - rl.question("Enter a message (or 'quit' to exit): ", async (message) => { - if (message.toLowerCase() === "quit") { - rl.close(); - return; +// 🎉 ストーリーと漫画パネルが生成される様子をご覧ください +(真)の間{ +const 結果 = client.executions.get(execution.id); を待機します。 +console.log(結果のステータス、結果の出力); + +if (result.status === '成功' || result.status === '失敗') { +// 📦 実行が終了したら、結果を取得します +if (result.status === "成功") { +console.log(結果の出力); +} それ以外 { +新しいエラーをスローします(result.error); } +壊す; + } - const response = await client.sessions.chat(session.id, { message }); - console.log(response); - chat(); - }); - }; - - chat(); +新しい Promise(resolve => setTimeout(resolve, 1000)) を待機します。 + } } -// Run the example -async function runExample() { - const agent = await createAgent(); - const task = await createTask(agent); - const result = await executeTask(task); - console.log("Task Result:", result); - await chatWithAgent(agent); +// 例を実行するためのメイン関数 +非同期関数main() { +試す { +const エージェント = createAgent() を待機します。 +const タスク = createTask(agent.id); +タスクの実行を待機します(task.id); +} キャッチ(エラー){ +console.error("エラーが発生しました:", error); + } } -runExample().catch(console.error); +main().then(() => console.log("完了")).catch(console.error); ``` -完全な Node.js の例は [ここ](example.js) にあります。 +You can find the full Node.js example [here](example.js). + +
+ + Back to Top +  |  + + Table of Contents + +
-## コンポーネント +## Components -Julep は次のコンポーネントで構成されています。 +Julep is made up of the following components: -- **Julep プラットフォーム**: Julep プラットフォームは、ワークフローを実行するクラウド サービスです。ワークフローを記述するための言語、ワークフローを実行するためのサーバー、プラットフォームと対話するための SDK が含まれています。 -- **Julep SDK**: Julep SDK は、ワークフローを構築するためのライブラリのセットです。Python 用と JavaScript 用の SDK があり、今後さらに追加される予定です。 -- **Julep API**: Julep API は、Julep プラットフォームと対話するために使用できる RESTful API です。 +- **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 API**: The Julep API is a RESTful API that you can use to interact with the Julep platform. -### メンタルモデル +### Mental Model
-Julep は、クライアント側とサーバー側の両方のコンポーネントを組み合わせて、高度な AI エージェントの構築を支援するプラットフォームと考えてください。これを視覚化する方法は次のとおりです。 +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. **アプリケーションコード:** +1. **Your Application Code:** -- アプリケーションで Julep SDK を使用して、エージェント、タスク、ワークフローを定義できます。 -- SDK は、これらのコンポーネントのセットアップと管理を容易にする関数とクラスを提供します。 + - 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. -2. **Julep バックエンド サービス:** +2. **Julep Backend Service:** -- SDK はネットワーク経由で Julep バックエンドと通信します。 -- バックエンドは、タスクの実行を処理し、セッション状態を維持し、ドキュメントを保存し、ワークフローを調整します。 + - The SDK communicates with the Julep backend over the network. + - The backend handles execution of tasks, maintains session state, stores documents, and orchestrates workflows. -3. **ツールとAPIとの統合:** -- ワークフロー内で、外部ツールやサービスを統合できます。 -- バックエンドはこれらの統合を容易にするため、エージェントは、たとえば、Web 検索を実行したり、データベースにアクセスしたり、サードパーティの API を呼び出したりすることができます。 +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. -## コンセプト +## Concepts -Julep は、強力な AI ワークフローを作成するために連携するいくつかの主要な技術コンポーネントに基づいて構築されています。 +Julep is built on several key technical components that work together to create powerful AI workflows: -```mermaid -graph TD - User[User] ==> Session[Session] - Session --> Agent[Agent] - Agent --> Tasks[Tasks] - Agent --> LLM[Large Language Model] - Tasks --> Tools[Tools] - Agent --> Documents[Documents] - Documents --> VectorDB[Vector Database] - Tasks --> Executions[Executions] +```マーメイド +グラフTD +ユーザー[ユーザー] ==> セッション[セッション] +セッション --> エージェント[エージェント] +エージェント --> タスク[タスク] +エージェント --> LLM[大規模言語モデル] +タスク --> ツール[ツール] +エージェント --> ドキュメント[ドキュメント] +ドキュメント --> VectorDB[ベクターデータベース] +タスク --> 実行[実行] - classDef client fill:#9ff,stroke:#333,stroke-width:1px; - class User client; +classDef client fill:#9ff、stroke:#333、stroke-width:1px; +クラス User クライアント; - classDef core fill:#f9f,stroke:#333,stroke-width:2px; - class Agent,Tasks,Session core; +classDef core fill:#f9f、stroke:#333、stroke-width:2px; +クラス Agent、Tasks、Session コア; ``` -- **エージェント**: タスクを実行し、ユーザーと対話する大規模言語モデル (LLM) を搭載した AI 搭載エンティティ。 -- **ユーザー**: セッションを通じてエージェントと対話するエンティティ。 -- **セッション**: エージェントとユーザー間のステートフルなやり取り。複数のやり取りにわたってコンテキストを維持します。 -- **タスク**: プロンプト、ツール呼び出し、条件付きロジックなどのさまざまな種類のステップを含む、エージェントが実行できる複数ステップのプログラム ワークフロー。 -- **ツール**: ユーザー定義関数、システム ツール、サードパーティ API 統合など、エージェントの機能を拡張する統合。 -- **ドキュメント**: エージェントまたはユーザーに関連付けられたテキストまたはデータ オブジェクト。セマンティック検索と取得のためにベクトル化され、保存されます。 -- **実行**: 特定の入力で開始され、独自のライフサイクルとステート マシンを持つタスクのインスタンス。 +- **Agents**: AI-powered entities backed by large language models (LLMs) that execute tasks and interact with users. +- **Users**: Entities that interact with agents through sessions. +- **Sessions**: Stateful interactions between agents and users, maintaining context across multiple exchanges. +- **Tasks**: Multi-step, programmatic workflows that agents can execute, including various types of steps like prompts, tool calls, and conditional logic. +- **Tools**: Integrations that extend an agent's capabilities, including user-defined functions, system tools, or third-party API integrations. +- **Documents**: Text or data objects associated with agents or users, vectorized and stored for semantic search and retrieval. +- **Executions**: Instances of tasks that have been initiated with specific inputs, with their own lifecycle and state machine. -より詳細な説明については、[コンセプトのドキュメント](https://github.com/julep-ai/julep/blob/dev/docs/julep-concepts.md)を参照してください。 -## タスクを理解する +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Understanding Tasks -タスクは Julep のワークフロー システムの中核です。タスクを使用すると、エージェントが実行できる複雑な複数ステップの AI ワークフローを定義できます。タスク コンポーネントの概要は次のとおりです。 +Tasks are the core of Julep's workflow system. They allow you to define complex, multi-step AI workflows that your agents can execute. Here's a brief overview of task components: -- **名前と説明**: 各タスクには、簡単に識別できるように一意の名前と説明が付いています。 -- **メインステップ**: タスクの中核であり、実行されるアクションのシーケンスを定義します。 -- **ツール**: タスク実行中にエージェントの機能を拡張するオプションの統合。 +- **Name, Description and Input Schema**: Each task has a unique name and description for easy identification. An input schema (optional) that is used to validate the input to the task. +- **Main Steps**: The core of a task, defining the sequence of actions to be performed. Each step can be a prompt, tool call, evaluate, wait_for_input, log, get, set, foreach, map_reduce, if-else, switch, sleep, or return. (See [Types of Workflow Steps](#types-of-workflow-steps) for more details) +- **Tools**: Optional integrations that extend the capabilities of your agent during task execution. -### ワークフローステップの種類 +### Lifecycle of a Task -Julep のタスクにはさまざまな種類のステップを含めることができるため、複雑で強力なワークフローを作成できます。利用可能なステップの種類の概要は次のとおりです。 +You create a task using the Julep SDK and specify the main steps that the agent will execute. When you execute a task, the following lifecycle happens: -#### 一般的な手順 +```マーメイド +シーケンス図 +参加者Dをあなたのコードとして +参加者C(ジュレップクライアント) +参加者Sはジュレップサーバーとして + +D->>C: タスクの作成 +C->>S: 実行を送信 +Sの上のメモ: タスクの実行 +Sに関する注意: 状態の管理 +S-->>C: 実行イベント +C-->>D: 進捗状況の更新 +S->>C: 実行完了 +C->>D: 最終結果 +``` + +### Types of Workflow Steps + +Tasks in Julep can include various types of steps, allowing you to create complex and powerful workflows. Here's an overview of the available step types: + +#### Common Steps - + + + - + - + - + - + - +
名前 について構文NameAboutSyntax
プロンプト Prompt -AIモデルにメッセージを送信し、応答を受け取る - +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: "Analyze the following data: {{data}}" +```ヤム +- プロンプト: 「次のデータを分析してください: {{agent.name}}」 # <-- これは jinja テンプレートです +``` + +```ヤム +- プロンプト: +- 役割: システム +内容: 「あなたは {{agent.name}} です。 {{agent.about}}」 +- 役割: ユーザー +内容: 「次のデータを分析します: {{_.data}}」 ```
ツールコール Tool Call -統合ツールまたはAPIを実行する +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 -- tool: web_search - arguments: - query: "Latest AI developments" +```ヤム +- ツール: web_search +引数: +クエリ: '"最新の AI 開発"' # <-- これは Python 式です (引用符に注意してください) +num_results: len(_.topics) # <-- リストの長さにアクセスするための Python 式 ```
評価する Evaluate -計算を実行したりデータを操作したりする - +Perform calculations or manipulate data +

Note: The evaluate step uses Python expressions.
-```yaml -- evaluate: - average_score: "sum(scores) / len(scores)" +```ヤム +- 評価する: +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.
-```yaml -- wait_for_input: - info: - message: "Please provide additional information." +```ヤム +- 入力待ち: +情報: +メッセージ: '"{_.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: "Processing completed for item {{item_id}}" +```ヤム +- ログ: "アイテム {{_.item_id}} の処理が完了しました" # <-- コンテキスト変数にアクセスするための jinja テンプレート ```
-#### キー値ステップ +#### Key-Value Steps - + - + - +
名前 について構文 Name About Syntax
得る Get -キーバリューストアから値を取得する +Retrieve a value from the execution's key-value store. -```yaml -- get: "user_preference" +```ヤム +- 取得: user_preference ```
セット Set -キーバリューストア内のキーに値を割り当てる +Assign a value to a key in the execution's key-value store. +

Note: The set step uses Python expressions.
-```yaml -- set: - user_preference: "dark_mode" +```ヤム +- セット: +user_preference: '"dark_mode"' # <-- python 式 ```
-#### 反復ステップ +#### Iteration Steps - + - + - + - +
名前 について構文 Name About Syntax
フォア Foreach -コレクションを反復処理し、各アイテムに対して手順を実行します。 +Iterate over a collection and perform steps for each item -```yaml -- foreach: - in: "data_list" - do: - - log: "Processing item {{_}}" +```ヤム +- 各: +in: _.data_list # <-- コンテキスト変数にアクセスするための Python 式 +する: +- ログ: "アイテム {{_.item}} を処理しています" # <-- コンテキスト変数にアクセスするための jinja テンプレート ```
マップリデュース Map-Reduce -コレクションをマップして結果を減らす +Map over a collection and reduce the results -```yaml -- map_reduce: - over: "numbers" - map: - - evaluate: - squared: "_ ** 2" - reduce: "sum(results)" +```ヤム +- マップリデュース: +over: _.numbers # <-- コンテキスト変数にアクセスするための Python 式 +地図: +- 評価する: +二乗: "_ ** 2" +Reduce: 結果 + [_] # <-- (オプション) 結果を削減する Python 式。省略した場合、これがデフォルトになります。 +``` + +```ヤム +- マップリデュース: +以上: _.topics +地図: +- プロンプト: {{_}} に関するエッセイを書く +並列度: 10 ```
平行 Parallel -複数のステップを並行して実行する +Run multiple steps in parallel -```yaml -- parallel: - - tool: web_search - arguments: - query: "AI news" - - tool: weather_check - arguments: - location: "New York" +```ヤム +- 平行: +- ツール: web_search +引数: +クエリ: 「AI ニュース」 +- ツール: weather_check +引数: +場所: '"ニューヨーク"' ```
-#### 条件付きステップ +#### Conditional Steps - + - + - +
名前 について構文 Name About Syntax
If-Else If-Else -ステップの条件付き実行 +Conditional execution of steps -```yaml -- if: "score > 0.8" - then: - - log: "High score achieved" - else: - - log: "Score needs improvement" +```ヤム +- if: _.score > 0.8 # <-- Python 式 +それから: +- ログ: 高得点を達成 +それ以外: +- エラー: スコアの改善が必要です ```
スイッチ Switch -複数の条件に基づいてステップを実行する +Execute steps based on multiple conditions -```yaml -- switch: - - case: "category == 'A'" - then: - - log: "Category A processing" - - case: "category == 'B'" - then: - - log: "Category B processing" - - case: "_" # Default case - then: - - log: "Unknown category" +```ヤム +- スイッチ: +- ケース: _.category == 'A' +それから: +- ログ: 「カテゴリー A 処理」 +- ケース: _.category == 'B' +それから: +- ログ: 「カテゴリー B 処理」 +- case: _ # デフォルトのケース +それから: +- エラー: 不明なカテゴリ ```
-#### その他の制御フロー +#### Other Control Flow - + - + - + - + - +
名前 について構文 Name About Syntax
寝る Sleep -指定した期間ワークフローを一時停止する +Pause the workflow for a specified duration -```yaml -- sleep: - seconds: 30 +```ヤム +- 寝る: +秒: 30 +分数: 1 +時間数: 1 +日数: 1 ```
戻る Return -ワークフローから値を返す +Return a value from the workflow + +

Note: The return step uses Python expressions.
-```yaml -- return: - result: "Task completed successfully" +```ヤム +- 戻る: +結果: '"タスクは正常に完了しました"' # <-- Python 式 +time: datetime.now().isoformat() # <-- python 式 ```
収率 Yield -サブワークフローを実行し、完了を待ちます +Run a subworkflow and await its completion -```yaml -- yield: - workflow: "data_processing_subflow" - arguments: - input_data: "{{raw_data}}" +```ヤム +- 収率: +ワークフロー: process_data +引数: +input_data: _.raw_data # <-- Python式 ```
エラー Error -エラーメッセージを指定してエラーを処理する +Handle errors by specifying an error message -```yaml -- error: "Invalid input provided" +```ヤム +- エラー:「無効な入力が提供されています」# <-- 文字列のみ ```
-各ステップ タイプは、高度な AI ワークフローを構築する上で特定の目的を果たします。この分類は、Julep タスクで使用できるさまざまな制御フローと操作を理解するのに役立ちます。 +Each step type serves a specific purpose in building sophisticated AI workflows. This categorization helps in understanding the various control flows and operations available in Julep tasks. -## ツールの種類 - -エージェントには、さまざまな「ツール」へのアクセスを許可できます。これは、基盤モデルが一連の入力を使用して「呼び出す」ことができるプログラム インターフェイスです。たとえば、インターネットで何らかの情報を検索するには、`web_search(query)` ツールを使用します。 - -エージェント フレームワークとは異なり、julep はエージェントの実行を管理する _バックエンド_ です。クライアントは SDK を使用してエージェントと対話できます。julep はタスクの実行と統合の実行を担当します。 - -julep のツールは次のいずれかになります。 - -### ユーザー定義の `functions` - -これらは、[openai] の関数呼び出しの仕組みと同様に、モデルに選択させることができる関数シグネチャです。例: - -```yaml -name: Example system tool task -description: List agents using system call +
+ + Back to Top +  |  + + Table of Contents + +
-tools: - - name: send_notification - description: Send a notification to the user - type: function - function: - parameters: - type: object - properties: - text: - type: string - description: Content of the notification +## Tool Types -main: - - tool: send_notification - arguments: - content: hi -``` +Agents can be given access to a number of "tools" -- any programmatic interface that a foundation model can "call" with a set of inputs to achieve a goal. For example, it might use a `web_search(query)` tool to search the Internet for some information. -julep は、_ユーザー定義関数_ に遭遇するたびに一時停止し、クライアントに制御を戻し、クライアントが関数呼び出しを実行して結果を julep に返すのを待ちます。 +Unlike agent frameworks, julep is a _backend_ that manages agent execution. Clients can interact with agents using our SDKs. julep takes care of executing tasks and running integrations. -> [!ヒント] -> **サンプルクックブック**: [cookbooks/13-Error_Handling_and_Recovery.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/13-Error_Handling_and_Recovery.py) +Tools in julep can be one of: +1. **User-defined `functions`**: These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. They need to be handled by the client. The workflow will pause until the client calls the function and gives the results back to julep. +2. **`system` tools**: Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. +3. **`integrations`**: Built-in third party tools that can be used to extend the capabilities of your agents. +4. **`api_calls`**: Direct api calls during workflow executions as tool calls. -### `システム` ツール +### User-defined `functions` -タスク実行のトリガー、メタデータ フィールドへの追加など、julep API 自体を呼び出すために使用できる組み込みツール。 -`system` ツールはバックエンドに組み込まれています。必要に応じて自動的に実行されます。クライアント側からのアクションは必要ありません。 +These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. An example: -例えば、 +```ヤム +名前: システムツールタスクの例 +説明: システムコールを使用してエージェントを一覧表示する -```yaml -name: Example system tool task -description: List agents using system call +ツール: +- 名前: send_notification +説明: ユーザーに通知を送信する +タイプ: 関数 +関数: +パラメータ: +タイプ: オブジェクト +プロパティ: +文章: +タイプ: 文字列 +説明: 通知の内容 -tools: - - name: list_agents - description: List all agents - type: system - system: - resource: agent - operation: list -main: - - tool: list_agents - arguments: - limit: 10 +主要: +- ツール: send_notification +引数: +内容: '"hi"' # <-- Python 式 ``` -> [!ヒント] -> **サンプルクックブック**: [cookbooks/10-Document_Management_and_Search.py​​](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py​​) - -### 組み込みの `integrations` +Whenever julep encounters a _user-defined function_, it pauses, giving control back to the client and waits for the client to run the function call and give the results back to julep. -Julep には、いくつかの組み込み統合が付属しています (以下のセクションで説明)。`integration` ツールは、julep バックエンドで直接実行されます。実行時に必要な追加パラメータは、エージェント/セッション/ユーザーの `metadata` フィールドで設定できます。 +> [!TIP] +> **Example cookbook**: [cookbooks/13-Error_Handling_and_Recovery.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/13-Error_Handling_and_Recovery.py) -> [!ヒント] -> **サンプルクックブック**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) - -julep バックエンドには、次のプロバイダーからの統合サードパーティ ツールが付属しています。 +### `system` tools -- [composio](https://composio.dev) -- [匿名](https://anon.com) -- [langchain ツールキット](https://python.langchain.com/v0.2/docs/integrations/toolkits/) +Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. -_Github、Gitlab、Gmail、Jira、MultiOn、Slack_ ツールキットのサポートが計画されています。 +`system` tools are built into the backend. They get executed automatically when needed. They do _not_ require any action from the client-side. -_composio_ と _anon_ はサードパーティプロバイダーであるため、それらのツールではアカウントリンクを設定する必要があります。 +For example, -### 直接の `api_calls` +```ヤム +名前: システムツールタスクの例 +説明: システムコールを使用してエージェントを一覧表示する -julep は、ワークフロー実行中にツール呼び出しとして直接 API 呼び出しを行うこともできます。`integration` と同様に、追加のランタイム パラメータは `metadata` フィールドから読み込まれます。 +ツール: +- 名前: list_agent_docs +説明: 指定されたエージェントのすべてのドキュメントを一覧表示します +タイプ: システム +システム: +リソース: エージェント +サブリソース: doc +操作: リスト -例えば、 +主要: +- ツール: list_agents +引数: +制限: 10 # <-- Python式 +``` -```yaml -name: Example api_call task -tools: - - type: api_call - name: hello - api_call: - method: GET - url: https://httpbin.org/get -main: - - tool: hello - arguments: - params: - test: _.input +#### Available `system` resources and operations + +- `agent`: + - `list`: List all agents. + - `get`: Get a single agent by id. + - `create`: Create a new agent. + - `update`: Update an existing agent. + - `delete`: Delete an existing agent. + +- `user`: + - `list`: List all users. + - `get`: Get a single user by id. + - `create`: Create a new user. + - `update`: Update an existing user. + - `delete`: Delete an existing user. + +- `session`: + - `list`: List all sessions. + - `get`: Get a single session by id. + - `create`: Create a new session. + - `update`: Update an existing session. + - `delete`: Delete an existing session. + - `chat`: Chat with a session. + - `history`: Get the chat history with a session. + +- `task`: + - `list`: List all tasks. + - `get`: Get a single task by id. + - `create`: Create a new task. + - `update`: Update an existing task. + - `delete`: Delete an existing task. + +- `doc` (subresource for `agent` and `user`): + - `list`: List all documents. + - `create`: Create a new document. + - `delete`: Delete an existing document. + - `search`: Search for documents. + +Additional operations available for some resources: +- `embed`: Embed a resource (specific resources not specified in the provided code). +- `change_status`: Change the status of a resource (specific resources not specified in the provided code). +- `chat`: Chat with a resource (specific resources not specified in the provided code). +- `history`: Get the chat history with a resource (specific resources not specified in the provided code). +- `create_or_update`: Create a new resource or update an existing one (specific resources not specified in the provided code). + +Note: The availability of these operations may vary depending on the specific resource and implementation details. + +> [!TIP] +> **Example cookbook**: [cookbooks/10-Document_Management_and_Search.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py) + +### Built-in `integrations` + +Julep comes with a number of built-in integrations (as described in the section below). `integration` tools are directly executed on the julep backend. Any additional parameters needed by them at runtime can be set in the agent/session/user's `metadata` fields. + +See [Integrations](#integrations) for details on the available integrations. + +> [!TIP] +> **Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) + + +### Direct `api_calls` + +julep can also directly make api calls during workflow executions as tool calls. Same as `integration`s, additional runtime parameters are loaded from `metadata` fields. + +For example, + +```ヤム +名前: api_callタスクの例 +ツール: +- タイプ: api_call +名前: こんにちは +API呼び出し: +メソッド: GET +URL: https://httpbin.org/get + +主要: +- ツール: こんにちは +引数: +書式: +test: _.input # <-- Python式 ``` -## 統合 +
+ + Back to Top +  |  + + Table of Contents + +
-Julep は、AI エージェントの機能を拡張するさまざまな統合をサポートしています。利用可能な統合とサポートされている引数のリストは次のとおりです。 +## Integrations + +Julep supports various integrations that extend the capabilities of your AI agents. Here's a list of available integrations and their supported arguments: - + - + - + - + - + - +
勇敢な検索 Brave Search -```yaml -setup: - api_key: string # The API key for Brave Search +```ヤム +設定: +api_key: 文字列 # Brave SearchのAPIキー -arguments: - query: string # The search query for searching with Brave +引数: +query: 文字列 # Braveで検索するための検索クエリ -output: - result: string # The result of the Brave Search +出力: +result: 文字列 # Brave Searchの結果 ``` -**サンプルクックブック**: [cookbooks/03-SmartResearcher_With_WebSearch.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-SmartResearcher_With_WebSearch.ipynb) +**Example cookbook**: [cookbooks/03-SmartResearcher_With_WebSearch.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/03-SmartResearcher_With_WebSearch.ipynb)
ブラウザベース BrowserBase -```yaml -setup: - api_key: string # The API key for BrowserBase - project_id: string # The project ID for BrowserBase - session_id: string # (Optional) The session ID for BrowserBase +```ヤム +設定: +api_key: 文字列 # BrowserBaseのAPIキー +project_id: 文字列 # BrowserBase のプロジェクト ID +session_id: 文字列 # (オプション) BrowserBaseのセッションID -arguments: - urls: list[string] # The URLs for loading with BrowserBase +引数: +urls: list[string] # BrowserBaseで読み込むURL -output: - documents: list # The documents loaded from the URLs +出力: +documents: list # URLから読み込まれたドキュメント ```
メール Email -```yaml -setup: - host: string # The host of the email server - port: integer # The port of the email server - user: string # The username of the email server - password: string # The password of the email server - -arguments: - to: string # The email address to send the email to - from: string # The email address to send the email from - subject: string # The subject of the email - body: string # The body of the email - -output: - success: boolean # Whether the email was sent successfully +```ヤム +設定: +ホスト: 文字列 # メールサーバーのホスト +port: 整数 # メールサーバーのポート +user: 文字列 # メールサーバーのユーザー名 +パスワード: 文字列 # メールサーバーのパスワード + +引数: +to: 文字列 # メールを送信するメールアドレス +from: 文字列 # メールを送信するメールアドレス +subject: 文字列 # メールの件名 +body: 文字列 # メールの本文 + +出力: +success: boolean # メールが正常に送信されたかどうか ``` -**サンプルクックブック**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb) +**Example cookbook**: [cookbooks/00-Devfest-Email-Assistant.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/00-Devfest-Email-Assistant.ipynb)
スパイダー Spider -```yaml -setup: - spider_api_key: string # The API key for Spider +```ヤム +設定: +spider_api_key: 文字列 # SpiderのAPIキー -arguments: - url: string # The URL for which to fetch data - mode: string # The type of crawlers (default: "scrape") - params: dict # (Optional) The parameters for the Spider API +引数: +url: 文字列 # データを取得するURL +mode: 文字列 # クローラーのタイプ (デフォルト: "scrape") +params: dict # (オプション) Spider APIのパラメータ -output: - documents: list # The documents returned from the spider +出力: +ドキュメント: リスト # スパイダーから返されたドキュメント ``` -**サンプルクックブック**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) +**Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb)
天気 Weather -```yaml -setup: - openweathermap_api_key: string # The API key for OpenWeatherMap +```ヤム +設定: +openweathermap_api_key: 文字列 # OpenWeatherMapのAPIキー -arguments: - location: string # The location for which to fetch weather data +引数: +location: 文字列 # 気象データを取得する場所 -output: - result: string # The weather data for the specified location +出力: +結果: 文字列 # 指定された場所の天気データ ``` -**サンプルクックブック**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb) +**Example cookbook**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb)
ウィキペディア Wikipedia -```yaml -arguments: - query: string # The search query string - load_max_docs: integer # Maximum number of documents to load (default: 2) +```ヤム +引数: +query: 文字列 # 検索クエリ文字列 +load_max_docs: 整数 # 読み込むドキュメントの最大数 (デフォルト: 2) -output: - documents: list # The documents returned from the Wikipedia search +出力: +ドキュメント: リスト # Wikipedia 検索から返されたドキュメント ``` -**サンプルクックブック**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb) +**Example cookbook**: [cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/04-TripPlanner_With_Weather_And_WikiInfo.ipynb)
-詳細については、[統合ドキュメント](https://docs.julep.ai/integrations)を参照してください。 +For more details, refer to our [Integrations Documentation](#integrations). -## その他の機能 +
+ + Back to Top +  |  + + Table of Contents + +
-Julep は、AI ワークフローを強化するためのさまざまな高度な機能を提供します。 +## Other Features -### エージェントへのツールの追加 +Julep offers a range of advanced features to enhance your AI workflows: -外部ツールと API を統合してエージェントの機能を拡張します。 +### Adding Tools to Agents -```python -client.agents.tools.create( - agent_id=agent.id, - name="web_search", - description="Search the web for information.", - integration={ - "provider": "brave", - "method": "search", - "setup": {"api_key": "your_brave_api_key"}, +Extend your agent's capabilities by integrating external tools and APIs: + +```パイソン +クライアント.エージェント.ツール.作成( +エージェントID=エージェントID、 +名前="ウェブ検索", +description="Web で情報を検索します。", +統合={ +「プロバイダー」:「勇敢な」、 +"メソッド": "検索", +"セットアップ": {"api_key": "your_brave_api_key"}, }, ) ``` -### セッションとユーザーの管理 +### Managing Sessions and Users -Julep は、永続的なインタラクションのための堅牢なセッション管理を提供します。 +Julep provides robust session management for persistent interactions: -```python -session = client.sessions.create( - agent_id=agent.id, - user_id=user.id, - context_overflow="adaptive" +```パイソン +セッション = client.sessions.create( +エージェントID=エージェントID、 +user_id=ユーザーID、 +context_overflow="適応型" ) -# Continue conversation in the same session -response = client.sessions.chat( - session_id=session.id, - messages=[ +# 同じセッションで会話を続ける +レスポンス = client.sessions.chat( +session_id=セッションID、 +メッセージ=[ { - "role": "user", - "content": "Follow up on the previous conversation." +「役割」: 「ユーザー」、 +"content": "前回の会話をフォローアップします。" } ] ) ``` -### ドキュメントの統合と検索 +### Document Integration and Search -エージェントのドキュメントを簡単に管理および検索できます。 +Easily manage and search through documents for your agents: -```python -# Upload a document -document = client.agents.docs.create( - title="AI advancements", - content="AI is changing the world...", - metadata={"category": "research_paper"} +```パイソン +# ドキュメントをアップロードする +ドキュメント = client.agents.docs.create( +title="AIの進歩", +content="AI は世界を変えています...", +メタデータ = {"カテゴリ": "研究論文"} ) -# Search documents -results = client.agents.docs.search( - text="AI advancements", - metadata_filter={"category": "research_paper"} +# ドキュメントを検索 +結果 = client.agents.docs.search( +text="AIの進歩", +metadata_filter={"category": "研究論文"} ) ``` +
+ + Back to Top +  |  + + Table of Contents + +
+ +## 参照 + +### SDK リファレンス + +- **Node.js** [SDK リファレンス](https://github.com/julep-ai/node-sdk/blob/main/api.md) | [NPM パッケージ](https://www.npmjs.com/package/@julep/sdk) +- **Python** [SDK リファレンス](https://github.com/julep-ai/python-sdk/blob/main/api.md) | [PyPI パッケージ](https://pypi.org/project/julep/) + +### API リファレンス + +エージェント、タスク、実行の詳細については、API ドキュメントをご覧ください。 + +- [エージェント API](https://dev.julep.ai/api/docs#tag/agents) +- [タスク API](https://dev.julep.ai/api/docs#tag/tasks) +- [実行API](https://dev.julep.ai/api/docs#tag/executions) + +
+ + Back to Top +  |  + + Table of Contents + +
+ ## ローカルクイックスタート **要件**: @@ -1253,26 +1522,23 @@ results = client.agents.docs.search( 1. `git clone https://github.com/julep-ai/julep.git` 2. `cd ジュレップ` 3. `docker volume create cozo_backup` -4. `docker volume create cozo_data` +4. docker ボリュームを作成します cozo_data 5. `cp .env.example .env # <-- このファイルを編集します` 6. `docker compose --env-file .env --profile temporal-ui --profile single-tenant --profile self-hosted-db up --build` -## SDK リファレンス - -- [Node.js SDK](https://github.com/julep-ai/node-sdk/blob/main/api.md) -- [Python SDK](https://github.com/julep-ai/python-sdk/blob/main/api.md) - -## APIリファレンス - -エージェント、タスク、実行の詳細については、包括的な API ドキュメントをご覧ください。 +
+ + Back to Top +  |  + + Table of Contents + +
-- [エージェント API](https://api.julep.ai/api/docs#tag/agents) -- [タスク API](https://api.julep.ai/api/docs#tag/tasks) -- [実行API](https://api.julep.ai/api/docs#tag/executions) ***** -## Julep と LangChain を比較する理由 +## Julep と LangChain などの違いは何ですか? ### さまざまなユースケース @@ -1310,5 +1576,8 @@ LangChain は、プロンプトと API 呼び出しの線形チェーンを含
Back to Top +  |  + + Table of Contents
diff --git a/README.md b/README.md index b20361db6..a79b313db 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@


- Explore Docs + Explore Docs · Discord · @@ -62,27 +62,20 @@ Exciting news! We're participating in DevFest.AI throughout October 2024! 🗓 -

-

📖 Table of Contents

+

📖 Table of Contents

- [Introduction](#introduction) - [Key Features](#key-features) - [Quick Example](#quick-example) - [Installation](#installation) - [Python Quick Start 🐍](#python-quick-start-) - - [Step 1: Create an Agent](#step-1-create-an-agent) - - [Step 2: Create a Task that generates a story and comic strip](#step-2-create-a-task-that-generates-a-story-and-comic-strip) - - [Step 3: Execute the Task](#step-3-execute-the-task) - - [Step 4: Chat with the Agent](#step-4-chat-with-the-agent) - [Node.js Quick Start 🟩](#nodejs-quick-start-) - - [Step 1: Create an Agent](#step-1-create-an-agent-1) - - [Step 2: Create a Task that generates a story and comic strip](#step-2-create-a-task-that-generates-a-story-and-comic-strip-1) - - [Step 3: Execute the Task](#step-3-execute-the-task-1) - - [Step 4: Chat with the Agent](#step-4-chat-with-the-agent-1) + - [Step 1: Create an Agent](#step-1-create-an-agent) - [Components](#components) - [Mental Model](#mental-model) - [Concepts](#concepts) - [Understanding Tasks](#understanding-tasks) + - [Lifecycle of a Task](#lifecycle-of-a-task) - [Types of Workflow Steps](#types-of-workflow-steps) - [Tool Types](#tool-types) - [User-defined `functions`](#user-defined-functions) @@ -94,15 +87,15 @@ Exciting news! We're participating in DevFest.AI throughout October 2024! 🗓 - [Adding Tools to Agents](#adding-tools-to-agents) - [Managing Sessions and Users](#managing-sessions-and-users) - [Document Integration and Search](#document-integration-and-search) +- [Reference](#reference) + - [SDK Reference](#sdk-reference) + - [API Reference](#api-reference) - [Local Quickstart](#local-quickstart) -- [SDK Reference](#sdk-reference) -- [API Reference](#api-reference) -- [Why Julep vs. LangChain?](#why-julep-vs-langchain) +- [What's the difference between Julep and LangChain etc?](#whats-the-difference-between-julep-and-langchain-etc) - [Different Use Cases](#different-use-cases) - [Different Form Factor](#different-form-factor) - [In Summary](#in-summary) -
## Introduction @@ -111,16 +104,16 @@ Julep is a platform for creating AI agents that remember past interactions and c Julep enables the creation of multi-step tasks incorporating decision-making, loops, parallel processing, and integration with numerous external tools and APIs. -While many AI applications are limited to simple, linear chains of prompts and API calls with minimal branching, Julep is built to handle more complex scenarios. - -It supports: +While many AI applications are limited to simple, linear chains of prompts and API calls with minimal branching, Julep is built to handle more complex scenarios which: -- Intricate, multi-step processes -- Dynamic decision-making -- Parallel execution +- have multiple steps, +- make decisions based on model outputs, +- spawn parallel branches, +- use lots of tools, and +- run for a long time. > [!TIP] -> Imagine you want to build an AI agent that can do more than just answer simple questions—it needs to handle complex tasks, remember past interactions, and maybe even use other tools or APIs. That's where Julep comes in. +> Imagine you want to build an AI agent that can do more than just answer simple questions—it needs to handle complex tasks, remember past interactions, and maybe even use other tools or APIs. That's where Julep comes in. Read [Understanding Tasks](#understanding-tasks) to learn more. ## Key Features @@ -132,19 +125,25 @@ It supports: 6. 🔧 **Self-Healing**: Julep will automatically retry failed steps, resend messages, and generally keep your tasks running smoothly. 7. 📚 **RAG**: Use Julep's document store to build a system for retrieving and using your own data. -Julep is ideal for applications that require AI use cases beyond simple prompt-response models. +![features](https://github.com/user-attachments/assets/4355cbae-fcbd-4510-ac0d-f8f77b73af70) + +> [!TIP] +> Julep is ideal for applications that require AI use cases beyond simple prompt-response models. ## Quick Example Imagine a Research AI agent that can do the following: -1. Take a topic, -2. Come up with 100 search queries for that topic, -3. Perform those web searches in parallel, -4. Summarize the results, -5. Send the summary to Discord +1. **Take a topic**, +2. **Come up with 100 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. -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 working example: +Here's a working example: ```yaml name: Research Agent @@ -164,12 +163,12 @@ tools: integration: provider: brave setup: - api_key: "YOUR_BRAVE_API_KEY" + api_key: BSAqES7dj9d... # dummy key - name: discord_webhook type: api_call api_call: - url: "YOUR_DISCORD_WEBHOOK_URL" + url: https://eobuxj02se0n.m.pipedream.net # dummy requestbin method: POST headers: Content-Type: application/json @@ -201,7 +200,7 @@ main: tool: web_search arguments: query: "_" - parallelism: 100 + parallelism: 10 # Collect the results from the web search - evaluate: @@ -215,28 +214,74 @@ main: The summary should be well-structured, informative, and highlight key findings and insights: {{_.results}} unwrap: true + settings: + model: gpt-4o-mini # Send the summary to Discord - tool: discord_webhook arguments: - content: > - **Research Summary for {{inputs[0].topic}}** + content: |- + f''' + **Research Summary for {inputs[0].topic}** - {{_}} + {_} + ''' ``` In this example, Julep will automatically manage parallel executions, retry failed steps, resend API requests, and keep the tasks running reliably until completion. +> This runs in under 30 seconds and returns the following output: + +
+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. + +
+ ## Installation To get started with Julep, install it using [npm](https://www.npmjs.com/package/@julep/sdk) or [pip](https://pypi.org/project/julep/): +**Node.js**: ```bash npm install @julep/sdk -``` -or +# or +bun add @julep/sdk +``` + +**Python**: ```bash pip install julep ``` @@ -253,283 +298,338 @@ pip install julep ## Python Quick Start 🐍 -### Step 1: Create an Agent - ```python +### Step 0: Setup + +import time import yaml from julep import Julep # or AsyncJulep client = Julep(api_key="your_julep_api_key") +### Step 1: Create an Agent + agent = client.agents.create( name="Storytelling Agent", - model="gpt-4o", - about="You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", + model="claude-3.5-sonnet", + about="You are a creative storyteller that crafts engaging stories on a myriad of topics.", ) -# 🛠️ Add an image generation tool (DALL·E) to the agent -client.agents.tools.create( - agent_id=agent.id, - name="image_generator", - description="Use this tool to generate images based on descriptions.", - integration={ - "provider": "dalle", - "method": "generate_image", - "setup": { - "api_key": "your_openai_api_key", - }, - }, -) -``` - ### Step 2: Create a Task that generates a story and comic strip -Let's define a multi-step task to create a story and generate a paneled comic strip based on an input idea: - -```python -# 📋 Task -# Create a task that takes an idea and creates a story and a 4-panel comic strip task_yaml = """ -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside ```yaml tags at the end of your response. unwrap: true - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].strip() - panels: re.findall(r'\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)', _) + plot_ideas: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) - # Step 3: Generate images for each panel using the image generator tool + # Step 2: Extract research fields from the plot ideas + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: > + Here are some plot ideas for a story: + {% for idea in _.plot_ideas %} + - {{idea}} + {% endfor %} + + To develop the story, we need to research for the plot ideas. + What should we research? Write down wikipedia search queries for the plot ideas you think are interesting. + Return your output as a yaml list inside ```yaml tags at the end of your response. + unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 + + - evaluate: + research_queries: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) + + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ + + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' - # Step 4: Generate a catchy title for the story + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside ```yaml tags at the end of your response. The yaml object should have the following structure: + + ```yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""``` + + Make sure the yaml is valid and the characters and scenes are not empty. Also take care of semicolons and other gotchas of writing yaml. unwrap: true - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: "[output.image.url for output in outputs[2]]" + - evaluate: + plot: "load_yaml(_.split('```yaml')[1].split('```')[0].strip())" """ task = client.tasks.create( agent_id=agent.id, **yaml.safe_load(task_yaml) ) -``` ### Step 3: Execute the Task -```python -# 🚀 Execute the task with an input idea execution = client.executions.create( task_id=task.id, input={"idea": "A cat who learns to fly"} ) # 🎉 Watch as the story and comic panels are generated -for transition in client.executions.transitions.stream(execution_id=execution.id): - print(transition) +while (result := client.executions.get(execution.id)).status not in ['succeeded', 'failed']: + print(result.status, result.output) + time.sleep(1) # 📦 Once the execution is finished, retrieve the results -result = client.executions.get(execution_id=execution.id) -``` - -### Step 4: Chat with the Agent - -Start an interactive chat session with the agent: - -```python -session = client.sessions.create(agent_id=agent.id) - -# 💬 Send messages to the agent -while (message := input("Enter a message: ")) != "quit": - response = client.sessions.chat( - session_id=session.id, - message=message, - ) - - print(response) +if result.status == "succeeded": + print(result.output) +else: + raise Exception(result.error) ``` You can find the full python example [here](example.py). +
+ + Back to Top +  |  + + Table of Contents + +
+ ## Node.js Quick Start 🟩 ### Step 1: Create an Agent ```javascript -import { Julep } from "@julep/sdk"; -import yaml from "js-yaml"; +// Step 0: Setup +const dotenv = require('dotenv'); +const { Julep } = require('@julep/sdk'); +const yaml = require('yaml'); + +dotenv.config(); + +const client = new Julep({ apiKey: process.env.JULEP_API_KEY, environment: process.env.JULEP_ENVIRONMENT || "production" }); -const client = new Julep({ apiKey: "your_julep_api_key" }); +/* Step 1: Create an Agent */ async function createAgent() { const agent = await client.agents.create({ name: "Storytelling Agent", - model: "gpt-4", - about: - "You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", + model: "claude-3.5-sonnet", + about: "You are a creative storyteller that crafts engaging stories on a myriad of topics.", }); - - // 🛠️ Add an image generation tool (DALL·E) to the agent - await client.agents.tools.create(agent.id, { - name: "image_generator", - description: "Use this tool to generate images based on descriptions.", - integration: { - provider: "dalle", - method: "generate_image", - setup: { - api_key: "your_openai_api_key", - }, - }, - }); - return agent; } -``` -### Step 2: Create a Task that generates a story and comic strip +/* Step 2: Create a Task that generates a story and comic strip */ -```javascript const taskYaml = ` -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside \`\`\`yaml tags at the end of your response. unwrap: true - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].trim() - panels: _.match(/\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)/g) + plot_ideas: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + + # Step 2: Extract research fields from the plot ideas + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: > + Here are some plot ideas for a story: + {% for idea in _.plot_ideas %} + - {{idea}} + {% endfor %} + + To develop the story, we need to research for the plot ideas. + What should we research? Write down wikipedia search queries for the plot ideas you think are interesting. + Return your output as a yaml list inside \`\`\`yaml tags at the end of your response. + unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 - # Step 3: Generate images for each panel using the image generator tool + - evaluate: + research_queries: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ + + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' - # Step 4: Generate a catchy title for the story + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside \`\`\`yaml tags at the end of your response. The yaml object should have the following structure: + + \`\`\`yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""\`\`\` + + Make sure the yaml is valid and the characters and scenes are not empty. Also take care of semicolons and other gotchas of writing yaml. unwrap: true - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: outputs[2].map(output => output.image.url) + - evaluate: + plot: "load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip())" `; -async function createTask(agent) { - const task = await client.tasks.create(agent.id, yaml.load(taskYaml)); +async function createTask(agentId) { + const task = await client.tasks.create( + agentId, + yaml.parse(taskYaml) + ); return task; } -``` -### Step 3: Execute the Task +/* Step 3: Execute the Task */ -```javascript -async function executeTask(task) { - const execution = await client.executions.create(task.id, { - input: { idea: "A cat who learns to fly" }, +async function executeTask(taskId) { + const execution = await client.executions.create(taskId, { + input: { idea: "A cat who learns to fly" } }); // 🎉 Watch as the story and comic panels are generated - for await (const transition of client.executions.transitions.stream( - execution.id - )) { - console.log(transition); - } - - // 📦 Once the execution is finished, retrieve the results - const result = await client.executions.get(execution.id); - return result; -} -``` - -### Step 4: Chat with the Agent - -```javascript -async function chatWithAgent(agent) { - const session = await client.sessions.create({ agent_id: agent.id }); - - // 💬 Send messages to the agent - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - - const chat = async () => { - rl.question("Enter a message (or 'quit' to exit): ", async (message) => { - if (message.toLowerCase() === "quit") { - rl.close(); - return; + while (true) { + const result = await client.executions.get(execution.id); + console.log(result.status, result.output); + + if (result.status === 'succeeded' || result.status === 'failed') { + // 📦 Once the execution is finished, retrieve the results + if (result.status === "succeeded") { + console.log(result.output); + } else { + throw new Error(result.error); } + break; + } - const response = await client.sessions.chat(session.id, { message }); - console.log(response); - chat(); - }); - }; - - chat(); + await new Promise(resolve => setTimeout(resolve, 1000)); + } } -// Run the example -async function runExample() { - const agent = await createAgent(); - const task = await createTask(agent); - const result = await executeTask(task); - console.log("Task Result:", result); - await chatWithAgent(agent); +// Main function to run the example +async function main() { + try { + const agent = await createAgent(); + const task = await createTask(agent.id); + await executeTask(task.id); + } catch (error) { + console.error("An error occurred:", error); + } } -runExample().catch(console.error); +main().then(() => console.log("Done")).catch(console.error); ``` You can find the full Node.js example [here](example.js). +
+ + Back to Top +  |  + + Table of Contents + +
+ ## Components Julep is made up of the following components: @@ -590,16 +690,44 @@ graph TD - **Documents**: Text or data objects associated with agents or users, vectorized and stored for semantic search and retrieval. - **Executions**: Instances of tasks that have been initiated with specific inputs, with their own lifecycle and state machine. -For a more detailed explanation, refer to our [Concepts Documentation](https://github.com/julep-ai/julep/blob/dev/docs/julep-concepts.md). + +
+ + Back to Top +  |  + + Table of Contents + +
## Understanding Tasks Tasks are the core of Julep's workflow system. They allow you to define complex, multi-step AI workflows that your agents can execute. Here's a brief overview of task components: -- **Name and Description**: Each task has a unique name and description for easy identification. -- **Main Steps**: The core of a task, defining the sequence of actions to be performed. +- **Name, Description and Input Schema**: Each task has a unique name and description for easy identification. An input schema (optional) that is used to validate the input to the task. +- **Main Steps**: The core of a task, defining the sequence of actions to be performed. Each step can be a prompt, tool call, evaluate, wait_for_input, log, get, set, foreach, map_reduce, if-else, switch, sleep, or return. (See [Types of Workflow Steps](#types-of-workflow-steps) for more details) - **Tools**: Optional integrations that extend the capabilities of your agent during task execution. +### Lifecycle of a Task + +You create a task using the Julep SDK and specify the main steps that the agent will execute. When you execute a task, the following lifecycle happens: + +```mermaid +sequenceDiagram + participant D as Your Code + participant C as Julep Client + participant S as Julep Server + + D->>C: Create Task + C->>S: Submit Execution + Note over S: Execute Task + Note over S: Manage State + S-->>C: Execution Events + C-->>D: Progress Updates + S->>C: Execution Completion + C->>D: Final Result +``` + ### Types of Workflow Steps Tasks in Julep can include various types of steps, allowing you to create complex and powerful workflows. Here's an overview of the available step types: @@ -608,27 +736,38 @@ Tasks in Julep can include various types of steps, allowing you to create comple - + + + - + - + @@ -637,31 +776,34 @@ Execute an integrated tool or API ```yaml - tool: web_search arguments: - query: "Latest AI developments" + query: '"Latest AI developments"' # <-- this is a python expression (notice the quotes) + num_results: len(_.topics) # <-- python expression to access the length of a list ``` - + - + @@ -670,22 +812,24 @@ Pause workflow until input is received ```yaml - wait_for_input: info: - message: "Please provide additional information." + message: '"Please provide additional information about {_.required_info}."' # <-- python expression to access the context variable ``` - + @@ -696,35 +840,36 @@ Log a specified value or message
Name About SyntaxNameAboutSyntax
Prompt 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: "Analyze the following data: {{data}}" +- prompt: "Analyze the following data: {{agent.name}}" # <-- this is a jinja template +``` + +```yaml +- prompt: + - role: system + content: "You are {{agent.name}}. {{agent.about}}" + - role: user + content: "Analyze the following data: {{_.data}}" ```
Tool Call Tool Call -Execute an integrated tool or API +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.
Evaluate Evaluate Perform calculations or manipulate data - +

Note: The evaluate step uses Python expressions.
```yaml - evaluate: - average_score: "sum(scores) / len(scores)" + average_score: sum(scores) / len(scores) ```
Wait for Input Wait for Input -Pause workflow until input is received +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.
Log Log -Log a specified value or message +Log a specified value or message. + +

Note: The log step uses Jinja templates and you can access context variables in them.
```yaml -- log: "Processing completed for item {{item_id}}" +- log: "Processing completed for item {{_.item_id}}" # <-- jinja template to access the context variable ```
- + - + - + @@ -735,10 +880,10 @@ Assign a value to a key in a key-value store
Name About Syntax Name About Syntax
Get Get -Retrieve a value from a key-value store +Retrieve a value from the execution's key-value store. ```yaml -- get: "user_preference" +- get: user_preference ```
Set Set -Assign a value to a key in a key-value store +Assign a value to a key in the execution's key-value store. +

Note: The set step uses Python expressions.
```yaml - set: - user_preference: "dark_mode" + user_preference: '"dark_mode"' # <-- python expression ```
- + - + - + - + @@ -802,10 +955,10 @@ Run multiple steps in parallel
Name About Syntax Name About Syntax
Foreach Foreach Iterate over a collection and perform steps for each item @@ -748,15 +893,15 @@ Iterate over a collection and perform steps for each item ```yaml - foreach: - in: "data_list" + in: _.data_list # <-- python expression to access the context variable do: - - log: "Processing item {{_}}" + - log: "Processing item {{_.item}}" # <-- jinja template to access the context variable ```
Map-Reduce Map-Reduce Map over a collection and reduce the results @@ -766,17 +911,25 @@ Map over a collection and reduce the results ```yaml - map_reduce: - over: "numbers" + over: _.numbers # <-- python expression to access the context variable map: - evaluate: squared: "_ ** 2" - reduce: "sum(results)" + reduce: results + [_] # <-- (optional) python expression to reduce the results. This is the default if omitted. +``` + +```yaml +- map_reduce: + over: _.topics + map: + - prompt: Write an essay on {{_}} + parallelism: 10 ```
Parallel Parallel Run multiple steps in parallel @@ -788,10 +941,10 @@ Run multiple steps in parallel - parallel: - tool: web_search arguments: - query: "AI news" + query: '"AI news"' - tool: weather_check arguments: - location: "New York" + location: '"New York"' ```
- + - + - + @@ -853,10 +1006,10 @@ Execute steps based on multiple conditions
Name About Syntax Name About Syntax
If-Else If-Else Conditional execution of steps @@ -814,17 +967,17 @@ Conditional execution of steps ```yaml -- if: "score > 0.8" +- if: _.score > 0.8 # <-- python expression then: - - log: "High score achieved" + - log: High score achieved else: - - log: "Score needs improvement" + - error: Score needs improvement ```
Switch Switch Execute steps based on multiple conditions @@ -834,15 +987,15 @@ Execute steps based on multiple conditions ```yaml - switch: - - case: "category == 'A'" + - case: _.category == 'A' then: - log: "Category A processing" - - case: "category == 'B'" + - case: _.category == 'B' then: - log: "Category B processing" - - case: "_" # Default case + - case: _ # Default case then: - - log: "Unknown category" + - error: Unknown category ```
- + - + - + - + - + @@ -925,6 +1084,15 @@ Handle errors by specifying an error message Each step type serves a specific purpose in building sophisticated AI workflows. This categorization helps in understanding the various control flows and operations available in Julep tasks. +
+ + Back to Top +  |  + + Table of Contents + +
+ ## Tool Types Agents can be given access to a number of "tools" -- any programmatic interface that a foundation model can "call" with a set of inputs to achieve a goal. For example, it might use a `web_search(query)` tool to search the Internet for some information. @@ -932,6 +1100,10 @@ Agents can be given access to a number of "tools" -- any programmatic interface Unlike agent frameworks, julep is a _backend_ that manages agent execution. Clients can interact with agents using our SDKs. julep takes care of executing tasks and running integrations. Tools in julep can be one of: +1. **User-defined `functions`**: These are function signatures that you can give the model to choose from, similar to how [openai]'s function-calling works. They need to be handled by the client. The workflow will pause until the client calls the function and gives the results back to julep. +2. **`system` tools**: Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. +3. **`integrations`**: Built-in third party tools that can be used to extend the capabilities of your agents. +4. **`api_calls`**: Direct api calls during workflow executions as tool calls. ### User-defined `functions` @@ -956,7 +1128,7 @@ tools: main: - tool: send_notification arguments: - content: hi + content: '"hi"' # <-- python expression ``` Whenever julep encounters a _user-defined function_, it pauses, giving control back to the client and waits for the client to run the function call and give the results back to julep. @@ -967,6 +1139,7 @@ Whenever julep encounters a _user-defined function_, it pauses, giving control b ### `system` tools Built-in tools that can be used to call the julep APIs themselves, like triggering a task execution, appending to a metadata field, etc. + `system` tools are built into the backend. They get executed automatically when needed. They do _not_ require any action from the client-side. For example, @@ -976,18 +1149,67 @@ name: Example system tool task description: List agents using system call tools: - - name: list_agents - description: List all agents + - name: list_agent_docs + description: List all docs for the given agent type: system system: resource: agent + subresource: doc operation: list + main: - tool: list_agents arguments: - limit: 10 + limit: 10 # <-- python expression ``` +#### Available `system` resources and operations + +- `agent`: + - `list`: List all agents. + - `get`: Get a single agent by id. + - `create`: Create a new agent. + - `update`: Update an existing agent. + - `delete`: Delete an existing agent. + +- `user`: + - `list`: List all users. + - `get`: Get a single user by id. + - `create`: Create a new user. + - `update`: Update an existing user. + - `delete`: Delete an existing user. + +- `session`: + - `list`: List all sessions. + - `get`: Get a single session by id. + - `create`: Create a new session. + - `update`: Update an existing session. + - `delete`: Delete an existing session. + - `chat`: Chat with a session. + - `history`: Get the chat history with a session. + +- `task`: + - `list`: List all tasks. + - `get`: Get a single task by id. + - `create`: Create a new task. + - `update`: Update an existing task. + - `delete`: Delete an existing task. + +- `doc` (subresource for `agent` and `user`): + - `list`: List all documents. + - `create`: Create a new document. + - `delete`: Delete an existing document. + - `search`: Search for documents. + +Additional operations available for some resources: +- `embed`: Embed a resource (specific resources not specified in the provided code). +- `change_status`: Change the status of a resource (specific resources not specified in the provided code). +- `chat`: Chat with a resource (specific resources not specified in the provided code). +- `history`: Get the chat history with a resource (specific resources not specified in the provided code). +- `create_or_update`: Create a new resource or update an existing one (specific resources not specified in the provided code). + +Note: The availability of these operations may vary depending on the specific resource and implementation details. + > [!TIP] > **Example cookbook**: [cookbooks/10-Document_Management_and_Search.py](https://github.com/julep-ai/julep/blob/dev/cookbooks/10-Document_Management_and_Search.py) @@ -995,18 +1217,11 @@ main: Julep comes with a number of built-in integrations (as described in the section below). `integration` tools are directly executed on the julep backend. Any additional parameters needed by them at runtime can be set in the agent/session/user's `metadata` fields. +See [Integrations](#integrations) for details on the available integrations. + > [!TIP] > **Example cookbook**: [cookbooks/01-Website_Crawler_using_Spider.ipynb](https://github.com/julep-ai/julep/blob/dev/cookbooks/01-Website_Crawler_using_Spider.ipynb) -julep backend ships with integrated third party tools from the following providers: - -- [composio](https://composio.dev) -- [anon](https://anon.com) -- [langchain toolkits](https://python.langchain.com/v0.2/docs/integrations/toolkits/) - -Support for _Github, Gitlab, Gmail, Jira, MultiOn, Slack_ toolkits is planned. - -Since _composio_ and _anon_ are third-party providers, their tools require setting up account linking. ### Direct `api_calls` @@ -1022,13 +1237,23 @@ tools: api_call: method: GET url: https://httpbin.org/get + main: - tool: hello arguments: - params: - test: _.input + json: + test: _.input # <-- python expression ``` +
+ + Back to Top +  |  + + Table of Contents + +
+ ## Integrations Julep supports various integrations that extend the capabilities of your AI agents. Here's a list of available integrations and their supported arguments: @@ -1036,7 +1261,7 @@ Julep supports various integrations that extend the capabilities of your AI agen
Name About Syntax Name About Syntax
Sleep Sleep Pause the workflow for a specified duration @@ -867,28 +1020,34 @@ Pause the workflow for a specified duration ```yaml - sleep: seconds: 30 + # minutes: 1 + # hours: 1 + # days: 1 ```
Return Return Return a value from the workflow +

Note: The return step uses Python expressions. +
```yaml - return: - result: "Task completed successfully" + result: '"Task completed successfully"' # <-- python expression + time: datetime.now().isoformat() # <-- python expression ```
Yield Yield Run a subworkflow and await its completion @@ -898,16 +1057,16 @@ Run a subworkflow and await its completion ```yaml - yield: - workflow: "data_processing_subflow" + workflow: process_data arguments: - input_data: "{{raw_data}}" + input_data: _.raw_data # <-- python expression ```
Error Error Handle errors by specifying an error message @@ -916,7 +1075,7 @@ Handle errors by specifying an error message ```yaml -- error: "Invalid input provided" +- error: "Invalid input provided" # <-- Strings only ```
- + - + - + - + - + - +
Brave Search Brave Search ```yaml @@ -1059,7 +1284,7 @@ output:
BrowserBase BrowserBase ```yaml @@ -1079,7 +1304,7 @@ output:
Email Email ```yaml @@ -1108,7 +1333,7 @@ output:
Spider Spider ```yaml @@ -1133,7 +1358,7 @@ output:
Weather Weather ```yaml @@ -1157,7 +1382,7 @@ output:
Wikipedia Wikipedia ```yaml @@ -1179,7 +1404,16 @@ output:
-For more details, refer to our [Integrations Documentation](https://docs.julep.ai/integrations). +For more details, refer to our [Integrations Documentation](#integrations). + +
+ + Back to Top +  |  + + Table of Contents + +
## Other Features @@ -1244,6 +1478,39 @@ results = client.agents.docs.search( ) ``` +
+ + Back to Top +  |  + + Table of Contents + +
+ +## Reference + +### SDK Reference + +- **Node.js** [SDK Reference](https://github.com/julep-ai/node-sdk/blob/main/api.md) | [NPM Package](https://www.npmjs.com/package/@julep/sdk) +- **Python** [SDK Reference](https://github.com/julep-ai/python-sdk/blob/main/api.md) | [PyPI Package](https://pypi.org/project/julep/) + +### API Reference + +Explore our API documentation to learn more about agents, tasks, and executions: + +- [Agents API](https://dev.julep.ai/api/docs#tag/agents) +- [Tasks API](https://dev.julep.ai/api/docs#tag/tasks) +- [Executions API](https://dev.julep.ai/api/docs#tag/executions) + +
+ + Back to Top +  |  + + Table of Contents + +
+ ## Local Quickstart **Requirements**: @@ -1259,22 +1526,19 @@ results = client.agents.docs.search( 5. `cp .env.example .env # <-- Edit this file` 6. `docker compose --env-file .env --profile temporal-ui --profile single-tenant --profile self-hosted-db up --build` -## SDK Reference - -- [Node.js SDK](https://github.com/julep-ai/node-sdk/blob/main/api.md) -- [Python SDK](https://github.com/julep-ai/python-sdk/blob/main/api.md) - -## API Reference - -Explore our comprehensive API documentation to learn more about agents, tasks, and executions: +
+ + Back to Top +  |  + + Table of Contents + +
-- [Agents API](https://api.julep.ai/api/docs#tag/agents) -- [Tasks API](https://api.julep.ai/api/docs#tag/tasks) -- [Executions API](https://api.julep.ai/api/docs#tag/executions) ***** -## Why Julep vs. LangChain? +## What's the difference between Julep and LangChain etc? ### Different Use Cases @@ -1312,5 +1576,8 @@ Choose Julep when you need a robust framework for stateful agents with advanced
Back to Top +  |  + + Table of Contents
diff --git a/agents-api/.gitignore b/agents-api/.gitignore index 0011e41de..33217a796 100644 --- a/agents-api/.gitignore +++ b/agents-api/.gitignore @@ -6,6 +6,7 @@ temporal.db *.dir # jupyterlab stuff +notebooks/Untitled*.ipynb .virtual_documents/ # Byte-compiled / optimized / DLL files diff --git a/agents-api/agents_api/activities/execute_system.py b/agents-api/agents_api/activities/execute_system.py index 780d4c0fb..cc92ece9e 100644 --- a/agents-api/agents_api/activities/execute_system.py +++ b/agents-api/agents_api/activities/execute_system.py @@ -41,6 +41,8 @@ from ..routers.docs.create_doc import create_agent_doc, create_user_doc from ..routers.docs.search_docs import search_agent_docs, search_user_docs +# FIXME: This is a total mess. Should be refactored. + @auto_blob_store @beartype @@ -48,7 +50,7 @@ async def execute_system( context: StepContext, system: SystemDef, ) -> Any: - arguments = system.arguments + arguments: dict[str, Any] = system.arguments or {} arguments["developer_id"] = context.execution_input.developer_id # Unbox all the arguments diff --git a/agents-api/agents_api/activities/task_steps/evaluate_step.py b/agents-api/agents_api/activities/task_steps/evaluate_step.py index dcdbfe592..76031c8e3 100644 --- a/agents-api/agents_api/activities/task_steps/evaluate_step.py +++ b/agents-api/agents_api/activities/task_steps/evaluate_step.py @@ -23,7 +23,8 @@ async def evaluate_step( else context.current_step.evaluate ) - values = context.model_dump() | additional_values + values = context.model_dump(include_remote=True) | additional_values + output = simple_eval_dict(expr, values) result = StepOutcome(output=output) diff --git a/agents-api/agents_api/activities/task_steps/log_step.py b/agents-api/agents_api/activities/task_steps/log_step.py index b57c624b5..80a61089f 100644 --- a/agents-api/agents_api/activities/task_steps/log_step.py +++ b/agents-api/agents_api/activities/task_steps/log_step.py @@ -21,7 +21,9 @@ async def log_step(context: StepContext) -> StepOutcome: template: str = context.current_step.log output = await render_template( - template, context.model_dump(), skip_vars=["developer_id"] + template, + context.model_dump(include_remote=True), + skip_vars=["developer_id"], ) result = StepOutcome(output=output) diff --git a/agents-api/agents_api/activities/task_steps/transition_step.py b/agents-api/agents_api/activities/task_steps/transition_step.py index 04ce6e8fd..9c903a645 100644 --- a/agents-api/agents_api/activities/task_steps/transition_step.py +++ b/agents-api/agents_api/activities/task_steps/transition_step.py @@ -3,6 +3,7 @@ from ...autogen.openapi_model import CreateTransitionRequest, Transition from ...common.protocol.tasks import StepContext +from ...common.storage_handler import load_from_blob_store_if_remote from ...env import testing from ...models.execution.create_execution_transition import create_execution_transition @@ -12,6 +13,9 @@ async def transition_step( context: StepContext, transition_info: CreateTransitionRequest, ) -> Transition: + # Load output from blob store if it is a remote object + transition_info.output = load_from_blob_store_if_remote(transition_info.output) + # Create transition transition = create_execution_transition( developer_id=context.execution_input.developer_id, diff --git a/agents-api/agents_api/activities/utils.py b/agents-api/agents_api/activities/utils.py index 1fcc6266c..45a264437 100644 --- a/agents-api/agents_api/activities/utils.py +++ b/agents-api/agents_api/activities/utils.py @@ -201,13 +201,18 @@ class stdlib_statistics: "statistics": stdlib_statistics, } +constants = { + "NEWLINE": "\n", +} + @beartype def get_evaluator( names: dict[str, Any], extra_functions: dict[str, Callable] | None = None ) -> SimpleEval: evaluator = EvalWithCompoundTypes( - names=names | stdlib, functions=ALLOWED_FUNCTIONS | (extra_functions or {}) + names=names | stdlib | constants, + functions=ALLOWED_FUNCTIONS | (extra_functions or {}), ) return evaluator diff --git a/agents-api/agents_api/autogen/Sessions.py b/agents-api/agents_api/autogen/Sessions.py index 75e5252cd..858c8a5a3 100644 --- a/agents-api/agents_api/autogen/Sessions.py +++ b/agents-api/agents_api/autogen/Sessions.py @@ -27,7 +27,7 @@ class CreateSessionRequest(BaseModel): Agent ID of agent associated with this session """ agents: list[UUID] | None = None - situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' + situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.about}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' """ A specific situation that sets the background for this session """ @@ -64,7 +64,7 @@ class PatchSessionRequest(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' + situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.about}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' """ A specific situation that sets the background for this session """ @@ -97,7 +97,7 @@ class Session(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' + situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.about}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' """ A specific situation that sets the background for this session """ @@ -174,7 +174,7 @@ class UpdateSessionRequest(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' + situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.about}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' """ A specific situation that sets the background for this session """ @@ -218,7 +218,7 @@ class CreateOrUpdateSessionRequest(CreateSessionRequest): Agent ID of agent associated with this session """ agents: list[UUID] | None = None - situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' + situation: str = '{%- if agent.name -%}\nYou are {{agent.name}}.{{" "}}\n{%- endif -%}\n\n{%- if agent.about -%}\nAbout you: {{agent.about}}.{{" "}}\n{%- endif -%}\n\n{%- if user -%}\nYou are talking to a user\n {%- if user.name -%}{{" "}} and their name is {{user.name}}\n {%- if user.about -%}. About the user: {{user.about}}.{%- else -%}.{%- endif -%}\n {%- endif -%}\n{%- endif -%}\n\n{{"\n\n"}}\n\n{%- if agent.instructions -%}\nInstructions:{{"\n"}}\n {%- if agent.instructions is string -%}\n {{agent.instructions}}{{"\n"}}\n {%- else -%}\n {%- for instruction in agent.instructions -%}\n - {{instruction}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"\n"}}\n{%- endif -%}\n\n{%- if tools -%}\nTools:{{"\n"}}\n {%- for tool in tools -%}\n {%- if tool.type == "function" -%}\n - {{tool.function.name}}\n {%- if tool.function.description -%}: {{tool.function.description}}{%- endif -%}{{"\n"}}\n {%- else -%}\n - {{ 0/0 }} {# Error: Other tool types aren\'t supported yet. #}\n {%- endif -%}\n {%- endfor -%}\n{{"\n\n"}}\n{%- endif -%}\n\n{%- if docs -%}\nRelevant documents:{{"\n"}}\n {%- for doc in docs -%}\n {{doc.title}}{{"\n"}}\n {%- if doc.content is string -%}\n {{doc.content}}{{"\n"}}\n {%- else -%}\n {%- for snippet in doc.content -%}\n {{snippet}}{{"\n"}}\n {%- endfor -%}\n {%- endif -%}\n {{"---"}}\n {%- endfor -%}\n{%- endif -%}' """ A specific situation that sets the background for this session """ diff --git a/agents-api/agents_api/common/interceptors.py b/agents-api/agents_api/common/interceptors.py index b10c5ac42..408005da5 100644 --- a/agents-api/agents_api/common/interceptors.py +++ b/agents-api/agents_api/common/interceptors.py @@ -6,6 +6,7 @@ from typing import Optional, Type +from temporalio.activity import _CompleteAsyncError as CompleteAsyncError from temporalio.exceptions import ApplicationError, FailureError, TemporalError from temporalio.service import RPCError from temporalio.worker import ( @@ -42,8 +43,10 @@ async def execute_activity(self, input: ExecuteActivityInput): ReadOnlyContextError, NondeterminismError, RPCError, + CompleteAsyncError, TemporalError, FailureError, + ApplicationError, ): raise except BaseException as e: @@ -73,8 +76,10 @@ async def execute_workflow(self, input: ExecuteWorkflowInput): ReadOnlyContextError, NondeterminismError, RPCError, + CompleteAsyncError, TemporalError, FailureError, + ApplicationError, ): raise except BaseException as e: diff --git a/agents-api/agents_api/common/nlp.py b/agents-api/agents_api/common/nlp.py index bc4d33383..a2f2f17ea 100644 --- a/agents-api/agents_api/common/nlp.py +++ b/agents-api/agents_api/common/nlp.py @@ -41,7 +41,7 @@ def extract_keywords(text: str, top_n: int = 10, clean: bool = True) -> list[str combined = entities + nouns # Normalize and count frequency - normalized = [re.sub(r"\s+", " ", kw).strip().lower() for kw in combined] + normalized = [re.sub(r"\s+", " ", kw).strip() for kw in combined] freq = Counter(normalized) # Get top_n keywords diff --git a/agents-api/agents_api/common/protocol/remote.py b/agents-api/agents_api/common/protocol/remote.py index 6ec3e3a5a..9905e437a 100644 --- a/agents-api/agents_api/common/protocol/remote.py +++ b/agents-api/agents_api/common/protocol/remote.py @@ -75,6 +75,18 @@ def __setattr__(self, name: str, value: Any) -> None: cache = self.__dict__.get("_remote_cache", {}) cache.pop(name, None) + def load_all(self) -> None: + for name in self.model_fields_set: + self.__getattribute__(name) + + def model_dump( + self, *args, include_remote: bool = False, **kwargs + ) -> dict[str, Any]: + if include_remote: + self.load_all() + + return super().model_dump(*args, **kwargs) + def unload_attribute(self, name: str) -> None: if name in self._remote_cache: data = self._remote_cache.pop(name) @@ -112,7 +124,9 @@ def __save_item(self, item: Any) -> Any: return store_in_blob_store_if_large(item) - def __getitem__(self, index: int | slice) -> Any: + def __getitem__( + self, index: int | slice + ) -> Any: # pytype: disable=signature-mismatch if isinstance(index, slice): # Obtain the slice without triggering __getitem__ recursively sliced_items = super().__getitem__( @@ -150,7 +164,9 @@ def _extend_without_processing(self, items: list[Any]) -> None: """ super().extend(items) - def __setitem__(self, index: int | slice, value: Any) -> None: + def __setitem__( + self, index: int | slice, value: Any + ) -> None: # pytype: disable=signature-mismatch if isinstance(index, slice): # Handle slice assignment without processing existing RemoteObjects processed_values = [self.__save_item(v) for v in value] @@ -219,7 +235,7 @@ def extend(self, iterable: list[Any]) -> None: for item in iterable: self.append(item) - def __iter__(self) -> Iterator[Any]: + def __iter__(self) -> Iterator[Any]: # pytype: disable=signature-mismatch for index in range(len(self)): yield self.__getitem__(index) diff --git a/agents-api/agents_api/common/protocol/tasks.py b/agents-api/agents_api/common/protocol/tasks.py index ad7a08ada..d3fb957be 100644 --- a/agents-api/agents_api/common/protocol/tasks.py +++ b/agents-api/agents_api/common/protocol/tasks.py @@ -1,7 +1,7 @@ from typing import Annotated, Any from uuid import UUID -from temporalio import workflow +from temporalio import activity, workflow with workflow.unsafe.imports_passed_through(): from pydantic import BaseModel, Field, computed_field @@ -28,6 +28,7 @@ Workflow, WorkflowStep, ) + from ...common.storage_handler import load_from_blob_store_if_remote from .remote import BaseRemoteModel, RemoteObject # TODO: Maybe we should use a library for this @@ -199,11 +200,14 @@ def is_main(self) -> Annotated[bool, Field(exclude=True)]: return self.cursor.workflow == "main" def model_dump(self, *args, **kwargs) -> dict[str, Any]: + current_input = self.current_input + if activity.in_activity(): + current_input = load_from_blob_store_if_remote(current_input) + dump = super().model_dump(*args, **kwargs) # Merge execution inputs into the dump dict execution_input: dict = dump.pop("execution_input") - current_input: Any = dump.pop("current_input") dump = { **dump, **execution_input, diff --git a/agents-api/agents_api/common/storage_handler.py b/agents-api/agents_api/common/storage_handler.py index 50b9e58f3..4e543700e 100644 --- a/agents-api/agents_api/common/storage_handler.py +++ b/agents-api/agents_api/common/storage_handler.py @@ -15,6 +15,9 @@ def store_in_blob_store_if_large(x: Any) -> RemoteObject | Any: + if not use_blob_store_for_temporal: + return x + s3.setup() serialized = serialize(x) @@ -28,6 +31,9 @@ def store_in_blob_store_if_large(x: Any) -> RemoteObject | Any: def load_from_blob_store_if_remote(x: Any | RemoteObject) -> Any: + if not use_blob_store_for_temporal: + return x + s3.setup() if isinstance(x, RemoteObject): @@ -42,42 +48,85 @@ def load_from_blob_store_if_remote(x: Any | RemoteObject) -> Any: # 2. load from blob store if the input is a RemoteObject -def auto_blob_store(f: Callable) -> Callable: - def load_args( - args: list[Any], kwargs: dict[str, Any] - ) -> tuple[list[Any], dict[str, Any]]: - new_args = [load_from_blob_store_if_remote(arg) for arg in args] - new_kwargs = {k: load_from_blob_store_if_remote(v) for k, v in kwargs.items()} +def auto_blob_store(f: Callable | None = None, *, deep: bool = False) -> Callable: + def auto_blob_store_decorator(f: Callable) -> Callable: + def load_args( + args: list | tuple, kwargs: dict[str, Any] + ) -> tuple[list | tuple, dict[str, Any]]: + new_args = [load_from_blob_store_if_remote(arg) for arg in args] + new_kwargs = { + k: load_from_blob_store_if_remote(v) for k, v in kwargs.items() + } + + if deep: + args = new_args + kwargs = new_kwargs + + new_args = [] + + for arg in args: + if isinstance(arg, list): + new_args.append( + [load_from_blob_store_if_remote(item) for item in arg] + ) + elif isinstance(arg, dict): + new_args.append( + { + key: load_from_blob_store_if_remote(value) + for key, value in arg.items() + } + ) + else: + new_args.append(arg) + + new_kwargs = {} + + for k, v in kwargs.items(): + if isinstance(v, list): + new_kwargs[k] = [ + load_from_blob_store_if_remote(item) for item in v + ] + + elif isinstance(v, dict): + new_kwargs[k] = { + key: load_from_blob_store_if_remote(value) + for key, value in v.items() + } + + else: + new_kwargs[k] = v + + return new_args, new_kwargs - return new_args, new_kwargs + def unload_return_value(x: Any | BaseRemoteModel | RemoteList) -> Any: + if isinstance(x, (BaseRemoteModel, RemoteList)): + x.unload_all() - def unload_return_value(x: Any | BaseRemoteModel | RemoteList) -> Any: - if isinstance(x, (BaseRemoteModel, RemoteList)): - x.unload_all() + return store_in_blob_store_if_large(x) - return store_in_blob_store_if_large(x) + if inspect.iscoroutinefunction(f): - if inspect.iscoroutinefunction(f): + @wraps(f) + async def async_wrapper(*args, **kwargs) -> Any: + new_args, new_kwargs = load_args(args, kwargs) + output = await f(*new_args, **new_kwargs) - @wraps(f) - async def async_wrapper(*args, **kwargs) -> Any: - new_args, new_kwargs = load_args(args, kwargs) - output = await f(*new_args, **new_kwargs) + return unload_return_value(output) - return unload_return_value(output) + return async_wrapper if use_blob_store_for_temporal else f - return async_wrapper if use_blob_store_for_temporal else f + else: - else: + @wraps(f) + def wrapper(*args, **kwargs) -> Any: + new_args, new_kwargs = load_args(args, kwargs) + output = f(*new_args, **new_kwargs) - @wraps(f) - def wrapper(*args, **kwargs) -> Any: - new_args, new_kwargs = load_args(args, kwargs) - output = f(*new_args, **new_kwargs) + return unload_return_value(output) - return unload_return_value(output) + return wrapper if use_blob_store_for_temporal else f - return wrapper if use_blob_store_for_temporal else f + return auto_blob_store_decorator(f) if f else auto_blob_store_decorator def auto_blob_store_workflow(f: Callable) -> Callable: @@ -100,4 +149,4 @@ async def wrapper(*args, **kwargs) -> Any: return result - return wrapper + return wrapper if use_blob_store_for_temporal else f diff --git a/agents-api/agents_api/common/utils/template.py b/agents-api/agents_api/common/utils/template.py index 2f614fb4f..5a39f6304 100644 --- a/agents-api/agents_api/common/utils/template.py +++ b/agents-api/agents_api/common/utils/template.py @@ -37,7 +37,7 @@ jinja_env.globals["true"] = True jinja_env.globals["false"] = False jinja_env.globals["null"] = None - +jinja_env.globals["NEWLINE"] = "\n" simple_jinja_regex = re.compile(r"{{|{%.+}}|%}", re.DOTALL) diff --git a/agents-api/agents_api/env.py b/agents-api/agents_api/env.py index a0470acba..371b6230c 100644 --- a/agents-api/agents_api/env.py +++ b/agents-api/agents_api/env.py @@ -118,6 +118,12 @@ temporal_worker_url=temporal_worker_url, temporal_namespace=temporal_namespace, embedding_model_id=embedding_model_id, + use_blob_store_for_temporal=use_blob_store_for_temporal, + blob_store_bucket=blob_store_bucket, + blob_store_cutoff_kb=blob_store_cutoff_kb, + s3_endpoint=s3_endpoint, + s3_access_key=s3_access_key, + s3_secret_key=s3_secret_key, testing=testing, ) diff --git a/agents-api/agents_api/models/docs/get_doc.py b/agents-api/agents_api/models/docs/get_doc.py index e81084985..d47cc80a8 100644 --- a/agents-api/agents_api/models/docs/get_doc.py +++ b/agents-api/agents_api/models/docs/get_doc.py @@ -37,7 +37,11 @@ one=True, transform=lambda d: { "content": [s[1] for s in sorted(d["snippet_data"], key=lambda x: x[0])], - "embeddings": [s[2] for s in sorted(d["snippet_data"], key=lambda x: x[0])], + "embeddings": [ + s[2] + for s in sorted(d["snippet_data"], key=lambda x: x[0]) + if s[2] is not None + ], **d, }, ) diff --git a/agents-api/agents_api/models/docs/list_docs.py b/agents-api/agents_api/models/docs/list_docs.py index 8f8d8c7a0..302b2154f 100644 --- a/agents-api/agents_api/models/docs/list_docs.py +++ b/agents-api/agents_api/models/docs/list_docs.py @@ -34,7 +34,11 @@ Doc, transform=lambda d: { "content": [s[1] for s in sorted(d["snippet_data"], key=lambda x: x[0])], - "embeddings": [s[2] for s in sorted(d["snippet_data"], key=lambda x: x[0])], + "embeddings": [ + s[2] + for s in sorted(d["snippet_data"], key=lambda x: x[0]) + if s[2] is not None + ], **d, }, ) diff --git a/agents-api/agents_api/models/docs/search_docs_by_text.py b/agents-api/agents_api/models/docs/search_docs_by_text.py index 1df34a5e2..34ee8cb00 100644 --- a/agents-api/agents_api/models/docs/search_docs_by_text.py +++ b/agents-api/agents_api/models/docs/search_docs_by_text.py @@ -1,5 +1,6 @@ """This module contains functions for searching documents in the CozoDB based on embedding queries.""" +import re from typing import Any, Literal, TypeVar from uuid import UUID @@ -62,9 +63,10 @@ def search_docs_by_text( [owner_type, str(owner_id)] for owner_type, owner_id in owners ] - # Need to use NEAR/3($query) to search for arbitrary text within 3 words of each other # See: https://docs.cozodb.org/en/latest/vector.html#full-text-search-fts - fts_queries = paragraph_to_custom_queries(query) + fts_queries = paragraph_to_custom_queries(query) or [ + re.sub(r"[^\w\s\-_]+", "", query) + ] # Construct the datalog query for searching document snippets search_query = f""" diff --git a/agents-api/agents_api/models/execution/create_execution_transition.py b/agents-api/agents_api/models/execution/create_execution_transition.py index b4a06d389..5a5304ddd 100644 --- a/agents-api/agents_api/models/execution/create_execution_transition.py +++ b/agents-api/agents_api/models/execution/create_execution_transition.py @@ -95,6 +95,16 @@ def create_execution_transition( data.metadata = data.metadata or {} data.execution_id = execution_id + # Dump to json + if isinstance(data.output, list): + data.output = [ + item.model_dump(mode="json") if hasattr(item, "model_dump") else item + for item in data.output + ] + + elif hasattr(data.output, "model_dump"): + data.output = data.output.model_dump(mode="json") + # TODO: This is a hack to make sure the transition is valid # (parallel transitions are whack, we should do something better) is_parallel = data.current.workflow.startswith("PAR:") diff --git a/agents-api/agents_api/models/execution/get_execution.py b/agents-api/agents_api/models/execution/get_execution.py index da76701f4..db0279b1f 100644 --- a/agents-api/agents_api/models/execution/get_execution.py +++ b/agents-api/agents_api/models/execution/get_execution.py @@ -33,7 +33,7 @@ transform=lambda d: { **d, "output": d["output"][OUTPUT_UNNEST_KEY] - if OUTPUT_UNNEST_KEY in d["output"] + if isinstance(d["output"], dict) and OUTPUT_UNNEST_KEY in d["output"] else d["output"], }, ) diff --git a/agents-api/agents_api/models/execution/list_executions.py b/agents-api/agents_api/models/execution/list_executions.py index 6bd7f5303..64add074f 100644 --- a/agents-api/agents_api/models/execution/list_executions.py +++ b/agents-api/agents_api/models/execution/list_executions.py @@ -33,8 +33,8 @@ transform=lambda d: { **d, "output": d["output"][OUTPUT_UNNEST_KEY] - if OUTPUT_UNNEST_KEY in d["output"] - else d["output"], + if isinstance(d.get("output"), dict) and OUTPUT_UNNEST_KEY in d["output"] + else d.get("output"), }, ) @cozo_query @@ -58,6 +58,7 @@ def list_executions( task_id, status, input, + output, session_id, metadata, created_at, @@ -68,6 +69,7 @@ def list_executions( execution_id: id, status, input, + output, session_id, metadata, created_at, diff --git a/agents-api/agents_api/models/utils.py b/agents-api/agents_api/models/utils.py index 0b0c41edd..e182de077 100644 --- a/agents-api/agents_api/models/utils.py +++ b/agents-api/agents_api/models/utils.py @@ -8,7 +8,7 @@ from pydantic import BaseModel from ..common.utils.cozo import uuid_int_list_to_uuid4 -from ..env import debug, do_verify_developer, do_verify_developer_owns_resource +from ..env import do_verify_developer, do_verify_developer_owns_resource P = ParamSpec("P") T = TypeVar("T") @@ -185,8 +185,8 @@ def make_cozo_json_query(fields): def cozo_query( func: Callable[P, tuple[str | list[str | None], dict]] | None = None, - debug: bool | None = debug, - only_on_error: bool = True, + debug: bool | None = None, + only_on_error: bool = False, ): def cozo_query_dec(func: Callable[P, tuple[str | list[Any], dict]]): """ diff --git a/agents-api/agents_api/routers/sessions/chat.py b/agents-api/agents_api/routers/sessions/chat.py index 25550a517..b3dd1605b 100644 --- a/agents-api/agents_api/routers/sessions/chat.py +++ b/agents-api/agents_api/routers/sessions/chat.py @@ -168,7 +168,9 @@ async def chat( ) total_tokens_per_user.labels(str(developer.id)).inc( - amount=chat_response.usage.total_tokens or 0 + 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/tasks/create_or_update_task.py b/agents-api/agents_api/routers/tasks/create_or_update_task.py index 50dbf19d9..d7e22f66a 100644 --- a/agents-api/agents_api/routers/tasks/create_or_update_task.py +++ b/agents-api/agents_api/routers/tasks/create_or_update_task.py @@ -29,10 +29,6 @@ async def create_or_update_task( # TODO: Do thorough validation of the task spec # SCRUM-10 - # FIXME: There is also some subtle bug here that prevents us from - # starting executions from tasks created via this endpoint - # SCRUM-9 - # Validate the input schema try: if data.input_schema is not None: diff --git a/agents-api/agents_api/routers/tasks/create_task.py b/agents-api/agents_api/routers/tasks/create_task.py index d92bd4a4d..a12a60d83 100644 --- a/agents-api/agents_api/routers/tasks/create_task.py +++ b/agents-api/agents_api/routers/tasks/create_task.py @@ -23,7 +23,6 @@ async def create_task( ) -> ResourceCreatedResponse: # TODO: Do thorough validation of the task spec # SCRUM-10 - # TODO: Validate the jinja templates # Validate the input schema try: diff --git a/agents-api/agents_api/routers/tasks/router.py b/agents-api/agents_api/routers/tasks/router.py index ea25228bd..101dcb228 100644 --- a/agents-api/agents_api/routers/tasks/router.py +++ b/agents-api/agents_api/routers/tasks/router.py @@ -16,7 +16,7 @@ async def body(self) -> bytes: "application/yaml", "text/yaml", ]: - body = yaml.load(body, yaml.CSafeLoader) + body = yaml.load(body) self._body = body diff --git a/agents-api/agents_api/workflows/task_execution/__init__.py b/agents-api/agents_api/workflows/task_execution/__init__.py index 252f48537..294f5d9f3 100644 --- a/agents-api/agents_api/workflows/task_execution/__init__.py +++ b/agents-api/agents_api/workflows/task_execution/__init__.py @@ -532,14 +532,7 @@ async def run( ), ) - # FIXME: This is a hack to make the output of the system call match - # the expected output format (convert uuid/datetime to strings) - def model_dump(obj): - if isinstance(obj, list): - return [model_dump(item) for item in obj] - return obj.model_dump(mode="json") - - state = PartialTransition(output=model_dump(tool_call_response)) + state = PartialTransition(output=tool_call_response) case _: workflow.logger.error( diff --git a/agents-api/agents_api/workflows/task_execution/transition.py b/agents-api/agents_api/workflows/task_execution/transition.py index 035322dad..150be6720 100644 --- a/agents-api/agents_api/workflows/task_execution/transition.py +++ b/agents-api/agents_api/workflows/task_execution/transition.py @@ -26,6 +26,7 @@ async def transition( state.type = "finish_branch" case _, _: state.type = "step" + transition_request = CreateTransitionRequest( current=context.cursor, **{ @@ -35,7 +36,8 @@ async def transition( workflow=context.cursor.workflow, step=context.cursor.step + 1 ), "metadata": {"step_type": type(context.current_step).__name__}, - **state.model_dump(exclude_unset=True), + "output": state.output, + **state.model_dump(exclude_unset=True, exclude={"output"}), **kwargs, # Override with any additional kwargs }, ) diff --git a/agents-api/poetry.lock b/agents-api/poetry.lock index d2bb2fb2d..c6507586a 100644 --- a/agents-api/poetry.lock +++ b/agents-api/poetry.lock @@ -474,17 +474,17 @@ numpy = ">=2.0.0,<3.0.0" [[package]] name = "boto3" -version = "1.35.42" +version = "1.35.44" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.42-py3-none-any.whl", hash = "sha256:e1f36f8be453505cebcc3da178ea081b2a06c0e5e1cdee774f1067599b8d9c3e"}, - {file = "boto3-1.35.42.tar.gz", hash = "sha256:a5b00f8b82dce62870759f04861747944da834d64a64355970120c475efdafc0"}, + {file = "boto3-1.35.44-py3-none-any.whl", hash = "sha256:18416d07b41e6094101a44f8b881047dcec6b846dad0b9f83b9bbf2f0cd93d07"}, + {file = "boto3-1.35.44.tar.gz", hash = "sha256:7f8e8a252458d584d8cf7877c372c4f74ec103356eedf43d2dd9e479f47f3639"}, ] [package.dependencies] -botocore = ">=1.35.42,<1.36.0" +botocore = ">=1.35.44,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -493,13 +493,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.35.42" +version = "1.35.44" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.42-py3-none-any.whl", hash = "sha256:05af0bb8b9cea7ce7bc589c332348d338a21b784e9d088a588fd10ec145007ff"}, - {file = "botocore-1.35.42.tar.gz", hash = "sha256:af348636f73dc24b7e2dc760a34d08c8f2f94366e9b4c78d877307b128abecef"}, + {file = "botocore-1.35.44-py3-none-any.whl", hash = "sha256:55388e80624401d017a9a2b8109afd94814f7e666b53e28fce51375cfa8d9326"}, + {file = "botocore-1.35.44.tar.gz", hash = "sha256:1fcd97b966ad8a88de4106fe1bd3bbd6d8dadabe99bbd4a6aadcf11cb6c66b39"}, ] [package.dependencies] @@ -774,13 +774,13 @@ test = ["pytest"] [[package]] name = "cloudpathlib" -version = "0.19.0" +version = "0.20.0" description = "pathlib-style classes for cloud storage services." optional = false python-versions = ">=3.8" files = [ - {file = "cloudpathlib-0.19.0-py3-none-any.whl", hash = "sha256:eb7758648812d5906af44f14cf9a6a64f687342a6f547a1c20deb7241d769dcb"}, - {file = "cloudpathlib-0.19.0.tar.gz", hash = "sha256:919edbfd9a4e935d2423da210b143df89cb0ec6d378366a0dffa2e9fd0664fe8"}, + {file = "cloudpathlib-0.20.0-py3-none-any.whl", hash = "sha256:7af3bcefbf73392ae7f31c08b3660ec31607f8c01b7f6262d4d73469a845f641"}, + {file = "cloudpathlib-0.20.0.tar.gz", hash = "sha256:f6ef7ca409a510f7ba4639ba50ab3fc5b6dee82d6dff0d7f5715fd0c9ab35891"}, ] [package.extras] @@ -1432,13 +1432,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "huggingface-hub" -version = "0.25.2" +version = "0.26.0" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.25.2-py3-none-any.whl", hash = "sha256:1897caf88ce7f97fe0110603d8f66ac264e3ba6accdf30cd66cc0fed5282ad25"}, - {file = "huggingface_hub-0.25.2.tar.gz", hash = "sha256:a1014ea111a5f40ccd23f7f7ba8ac46e20fa3b658ced1f86a00c75c06ec6423c"}, + {file = "huggingface_hub-0.26.0-py3-none-any.whl", hash = "sha256:e43b8f36042b2103b48dea822535e08f5f089c4aa7013a067fca7b4ebf7f85a3"}, + {file = "huggingface_hub-0.26.0.tar.gz", hash = "sha256:524fe9281b015b76aa73ff1a83bf1cbe8cab851c9ac5ae5fcd2a25d5173ce629"}, ] [package.dependencies] @@ -1451,16 +1451,16 @@ tqdm = ">=4.42.1" typing-extensions = ">=3.7.4.3" [package.extras] -all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio (>=4.0.0)", "jedi", "libcst (==1.4.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] cli = ["InquirerPy (==0.3.4)"] -dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio (>=4.0.0)", "jedi", "libcst (==1.4.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] hf-transfer = ["hf-transfer (>=0.1.4)"] -inference = ["aiohttp", "minijinja (>=1.0)"] -quality = ["mypy (==1.5.1)", "ruff (>=0.5.0)"] +inference = ["aiohttp"] +quality = ["libcst (==1.4.0)", "mypy (==1.5.1)", "ruff (>=0.5.0)"] tensorflow = ["graphviz", "pydot", "tensorflow"] tensorflow-testing = ["keras (<3.0)", "tensorflow"] -testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio (>=4.0.0)", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] torch = ["safetensors[torch]", "torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] @@ -1868,13 +1868,13 @@ referencing = ">=0.31.0" [[package]] name = "julep" -version = "1.16.0" +version = "1.18.0" description = "The official Python library for the julep API" optional = false python-versions = ">=3.7" files = [ - {file = "julep-1.16.0-py3-none-any.whl", hash = "sha256:db84751b45b618bb3793809da87b745c05ee2a2330e819c394427d8a68d1f26b"}, - {file = "julep-1.16.0.tar.gz", hash = "sha256:776f8b86f8672bc98ade814ca89a505a566897297bc4dd0292ecfd35bfd67ca7"}, + {file = "julep-1.18.0-py3-none-any.whl", hash = "sha256:6eabb83a1f411cafa0faa674552137881fb56ff4257bfbf7c8a0f077b1d329db"}, + {file = "julep-1.18.0.tar.gz", hash = "sha256:d4dab1ef2052529fc373e0165a8c09051ad160a40494452a39a9fe3eef233844"}, ] [package.dependencies] @@ -1882,6 +1882,8 @@ anyio = ">=3.5.0,<5" distro = ">=1.7.0,<2" httpx = ">=0.23.0,<1" pydantic = ">=1.9.0,<3" +python-dotenv = ">=1.0,<1.1" +ruamel-yaml = ">=0.18.6,<0.19" sniffio = "*" typing-extensions = ">=4.7,<5" @@ -2185,13 +2187,13 @@ dev = ["Sphinx (>=5.1.1)", "black (==24.8.0)", "build (>=0.10.0)", "coverage[tom [[package]] name = "litellm" -version = "1.49.5" +version = "1.49.7" description = "Library to easily interface with LLM API providers" optional = false python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" files = [ - {file = "litellm-1.49.5-py3-none-any.whl", hash = "sha256:9cd246221c1d922edb7614f29b5b5618b9da588f0ac04612965dbd8afeaa130f"}, - {file = "litellm-1.49.5.tar.gz", hash = "sha256:f45667d723d77d235dc3cc3b056338012eb2ffbfd46d7beb7abea927f49358e0"}, + {file = "litellm-1.49.7-py3-none-any.whl", hash = "sha256:30f0c5b1b0a1466ae29006f3d3b29dd8a3836387375cc2efbde9a5d76bc92673"}, + {file = "litellm-1.49.7.tar.gz", hash = "sha256:9442b5c0922580ce3d536030247800c0112c64c0f123aad1a4a87872e51f0e09"}, ] [package.dependencies] @@ -2378,92 +2380,92 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "3.0.1" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" files = [ - {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-win32.whl", hash = "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-win32.whl", hash = "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-win32.whl", hash = "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-win32.whl", hash = "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-win32.whl", hash = "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-win32.whl", hash = "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b"}, - {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "marshmallow" -version = "3.22.0" +version = "3.23.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"}, - {file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"}, + {file = "marshmallow-3.23.0-py3-none-any.whl", hash = "sha256:82f20a2397834fe6d9611b241f2f7e7b680ed89c49f84728a1ad937be6b4bdf4"}, + {file = "marshmallow-3.23.0.tar.gz", hash = "sha256:98d8827a9f10c03d44ead298d2e99c6aea8197df18ccfad360dae7f89a50da2e"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] -tests = ["pytest", "pytz", "simplejson"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-version-warning (==1.1.2)"] +tests = ["pytest", "simplejson"] [[package]] name = "matplotlib-inline" @@ -2990,13 +2992,13 @@ files = [ [[package]] name = "openai" -version = "1.51.2" +version = "1.52.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.51.2-py3-none-any.whl", hash = "sha256:5c5954711cba931423e471c37ff22ae0fd3892be9b083eee36459865fbbb83fa"}, - {file = "openai-1.51.2.tar.gz", hash = "sha256:c6a51fac62a1ca9df85a522e462918f6bb6bc51a8897032217e453a0730123a6"}, + {file = "openai-1.52.0-py3-none-any.whl", hash = "sha256:0c249f20920183b0a2ca4f7dba7b0452df3ecd0fa7985eb1d91ad884bc3ced9c"}, + {file = "openai-1.52.0.tar.gz", hash = "sha256:95c65a5f77559641ab8f3e4c3a050804f7b51d278870e2ec1f7444080bfe565a"}, ] [package.dependencies] @@ -3456,32 +3458,33 @@ files = [ [[package]] name = "psutil" -version = "6.0.0" +version = "6.1.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, - {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, - {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, - {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, - {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, - {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, - {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, - {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, - {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, - {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, - {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, - {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, - {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, - {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, + {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"}, + {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"}, + {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"}, + {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"}, + {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"}, + {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"}, + {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, + {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"}, + {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"}, + {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, + {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, + {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, ] [package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"] +test = ["pytest", "pytest-xdist", "setuptools"] [[package]] name = "ptyprocess" @@ -3897,17 +3900,17 @@ files = [ [[package]] name = "pywinpty" -version = "2.0.13" +version = "2.0.14" description = "Pseudo terminal support for Windows from Python." optional = false python-versions = ">=3.8" files = [ - {file = "pywinpty-2.0.13-cp310-none-win_amd64.whl", hash = "sha256:697bff211fb5a6508fee2dc6ff174ce03f34a9a233df9d8b5fe9c8ce4d5eaf56"}, - {file = "pywinpty-2.0.13-cp311-none-win_amd64.whl", hash = "sha256:b96fb14698db1284db84ca38c79f15b4cfdc3172065b5137383910567591fa99"}, - {file = "pywinpty-2.0.13-cp312-none-win_amd64.whl", hash = "sha256:2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4"}, - {file = "pywinpty-2.0.13-cp38-none-win_amd64.whl", hash = "sha256:61d420c2116c0212808d31625611b51caf621fe67f8a6377e2e8b617ea1c1f7d"}, - {file = "pywinpty-2.0.13-cp39-none-win_amd64.whl", hash = "sha256:71cb613a9ee24174730ac7ae439fd179ca34ccb8c5349e8d7b72ab5dea2c6f4b"}, - {file = "pywinpty-2.0.13.tar.gz", hash = "sha256:c34e32351a3313ddd0d7da23d27f835c860d32fe4ac814d372a3ea9594f41dde"}, + {file = "pywinpty-2.0.14-cp310-none-win_amd64.whl", hash = "sha256:0b149c2918c7974f575ba79f5a4aad58bd859a52fa9eb1296cc22aa412aa411f"}, + {file = "pywinpty-2.0.14-cp311-none-win_amd64.whl", hash = "sha256:cf2a43ac7065b3e0dc8510f8c1f13a75fb8fde805efa3b8cff7599a1ef497bc7"}, + {file = "pywinpty-2.0.14-cp312-none-win_amd64.whl", hash = "sha256:55dad362ef3e9408ade68fd173e4f9032b3ce08f68cfe7eacb2c263ea1179737"}, + {file = "pywinpty-2.0.14-cp313-none-win_amd64.whl", hash = "sha256:074fb988a56ec79ca90ed03a896d40707131897cefb8f76f926e3834227f2819"}, + {file = "pywinpty-2.0.14-cp39-none-win_amd64.whl", hash = "sha256:5725fd56f73c0531ec218663bd8c8ff5acc43c78962fab28564871b5fce053fd"}, + {file = "pywinpty-2.0.14.tar.gz", hash = "sha256:18bd9529e4a5daf2d9719aa17788ba6013e594ae94c5a0c27e83df3278b0660e"}, ] [[package]] @@ -4387,6 +4390,83 @@ files = [ {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, ] +[[package]] +name = "ruamel-yaml" +version = "0.18.6" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = false +python-versions = ">=3.6" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + [[package]] name = "ruff" version = "0.5.7" @@ -4460,13 +4540,13 @@ win32 = ["pywin32"] [[package]] name = "sentry-sdk" -version = "2.16.0" +version = "2.17.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.16.0-py2.py3-none-any.whl", hash = "sha256:49139c31ebcd398f4f6396b18910610a0c1602f6e67083240c33019d1f6aa30c"}, - {file = "sentry_sdk-2.16.0.tar.gz", hash = "sha256:90f733b32e15dfc1999e6b7aca67a38688a567329de4d6e184154a73f96c6892"}, + {file = "sentry_sdk-2.17.0-py2.py3-none-any.whl", hash = "sha256:625955884b862cc58748920f9e21efdfb8e0d4f98cca4ab0d3918576d5b606ad"}, + {file = "sentry_sdk-2.17.0.tar.gz", hash = "sha256:dd0a05352b78ffeacced73a94e86f38b32e2eae15fff5f30ca5abb568a72eacf"}, ] [package.dependencies] @@ -5689,93 +5769,93 @@ files = [ [[package]] name = "yarl" -version = "1.15.4" +version = "1.15.5" description = "Yet another URL library" optional = false python-versions = ">=3.9" files = [ - {file = "yarl-1.15.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:551205388d1da18a9975302c9a274ba24788f53bb9bb86187496ebf9e938916e"}, - {file = "yarl-1.15.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eee724176b5bc50ee64905f559345448119b860a30b9489bd7a073f61baf925f"}, - {file = "yarl-1.15.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db818e33599f7b2e4c6507f2b2c24f45ff539a1b6e4e09163bb6f3cfb4616ca7"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07019a9de859c5a29916defd1e8c7557de6491a10bf50c49ff5284e6aedf5313"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db64a20e78969fc66665d2e5fc96cb4f4dc80f2137d8fed4b5a650ad569bb60f"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4076bfd8f1621449b19b9826848ed51bf0f2d1d38e82647c312c0730d8778903"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c23a442973dba3646811c284fce3dddd7fe5c2bd674ac73a122198e8218d6115"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2bdb038b3f5c284e3919218c580dedc95f592c417a358361450b9519b22f7a8"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:59db8e6888d5302b8dbca0c1026ddabe99d81d67cdc101941519e13ffc9050fe"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f3294ce265011547630a59c20085fcb6af8cc5fa1fa44a203251f7d86cd5d913"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4851618679ca70b863ba2e7109be5f09f8fd7715ec505bd42e5a947dcfde3a45"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:dce1c56beef74d9c799a6ed94001693232a1402138292353a8ce302b64f457d9"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1e7468f31de61a82817f918743e5229fce774f73fad58487cdf88eef4f06d864"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:527c68f48a91d953691291d3bce0209293aa5ad13ff05286ddb506791c331818"}, - {file = "yarl-1.15.4-cp310-cp310-win32.whl", hash = "sha256:c30115cecaf25fdcb67cc71c669d08425207f62d7a2f6d5416057c1460529216"}, - {file = "yarl-1.15.4-cp310-cp310-win_amd64.whl", hash = "sha256:df09c80f4bc2bc2efde309af383c3fe8fd8c51fe0519edb350b9c9e0af43ffa4"}, - {file = "yarl-1.15.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:76259901cf1ac3db65e7e6dff04775b626d0715f9b51d92b447351144c756a82"}, - {file = "yarl-1.15.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98d8dc1e8133f86d916125deca9780d791b22645f0d62bafe1452d1cd5eac631"}, - {file = "yarl-1.15.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d0f16c87c62b7a94b389ddf6a8c9d081265d788875c39f3a80108c4856eea7b"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8de5328d91859b461899497980d4cc8269e84e2d18640f6ac643886fda9000bf"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84937d00e2ea03616c40977de20189fa13a9213e5744a3c6afa0e7dd9141d69c"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:691a3b498fdebef63308e8967bb598cfd326c56d628da82b799dd181bace4503"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a706db0c3b7e4578ff34ed2b1d2507b08fd491346ffc64468786fdf1151d938"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:adb6b5d07d17c32f9d34c9dd4a693637a72323cfcb1f8a52d57033ab2dd21e99"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e100c6c7d9e9d469009fd55cc4d7ad168d67d40758865c50da713f7ada491e5"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6b254e55c8ac2362afaa651e3e53453aa19a095570792346245773b434176e"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8721f8bedaa722c3c483cc06a1399cbfdb280eadf443aa5d324b0203cef2a75f"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1005921b30f4f39bf893946df6173567ff650307babb5ec04bbf64342a1f62c1"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ab79cc13307065a0b3ef087f09f0509996fc605d35d6642bb28e5d85b2648e1e"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f337486742c700b102d640830aab3faf2848bed966b479a39e6783edd4ab1c6c"}, - {file = "yarl-1.15.4-cp311-cp311-win32.whl", hash = "sha256:20acf84bd1ce530065f8e957e4a5878fda4bc5f18cb02659828210e1519de54e"}, - {file = "yarl-1.15.4-cp311-cp311-win_amd64.whl", hash = "sha256:ab9ccf26cb3fa32747ba2a637a189d2d42386a2fc4afc10dbc7f85922dd23b0f"}, - {file = "yarl-1.15.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f923e94e93a37fd990e8336e0b9bedea533e7cbed14e0c572bf9357ef2a70681"}, - {file = "yarl-1.15.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3198da7d7c34e29fc8c823e0c3ce6c7274aac35760de557c2017489c7d98fc5a"}, - {file = "yarl-1.15.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d886de2ea81f513ba2d6820451d33b767a97c37867ba688d42e164b2dbca1362"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ac85e760543129a1912a82438fc8075223e35eaa2d457d61cd83c27d00d17be"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e58c5d07b1f78dd4cb180c5b3b82465cd281aaeee8aafea0e5d72a4b97922cb1"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9060589d0acad1fca048861fa9ee3e8ed060f67894fa885969648ab6e9e99a54"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccd6774aa7bebdf9ca608bb0839318757a71b8e0d2cf7b10c002bc8790bd343e"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7694f109867ee428c21b85ae19fd31d164c691eb45cc95c561cfdeba237a12e3"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:83e7154aa0d17f5c93d27ac01088fd9ab6673e7bab1acbd07cd7a865b980c045"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f16d1940c0cbc342f1d29d6212a006d172be616d2942c5c41966e8a3ce4c3be1"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7d5226c70af3ad9569ccc4ccc04ab65be79eeb22c87d7ae789c89e62ef76bbd6"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f25906e4a72d9833e81717c39a39dee7297ff5cb44957d06d177a2ab8ef2ef7f"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e07e4b17b648c880e8e42bf1ac0a730bde114961646ae1c2ec4433f0c11ca94"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f8136bde8dfa4477c6a85c79a366581b4a505b51a52b669318fb631d3f4f638"}, - {file = "yarl-1.15.4-cp312-cp312-win32.whl", hash = "sha256:ccbeaf5b18b173b9d78e332e017b30ba8bedcf03cdce1d13490b82a3f421bc98"}, - {file = "yarl-1.15.4-cp312-cp312-win_amd64.whl", hash = "sha256:f74f6ffdc633aefecbc80282242a5395058db9d1247fa7dd2f070ef84dc82583"}, - {file = "yarl-1.15.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4f66a0eda48844508736e47ed476d8fdd7cdbf16a4053b5d439509a25f708504"}, - {file = "yarl-1.15.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fd2bb86f40962d53a91def15a2f7684c62e081a7b96ec74ed0259c34b15973b9"}, - {file = "yarl-1.15.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f864b412557e69a6b953d62c01a0ed0ee342666298aa7f2a29af526bfa80f6e9"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a79c0a8bbb046add85663af85e9993b691bf20c2a109518bd35e0ce77edfe42"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de479e30abd2dfd49fdad3bd6953f2d930a45380be5143c0c9f7a1215cffc8cc"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21fabe58042f3e567b4edc75b2cf44cea02f228e41ac09d73de126bf685fe883"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77390496f2f32437a721c854897f889abefae0f3009daf90a2f703508d96c920"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3896bf15284dd23acab1f2e7fceb350d8da6f6f2436b922f7ec6b3de685d34ca"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:590e2d733a82ecf004c5c531cbef0d6be328e93adec960024eb213f10cb9503e"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:1ceb677fb583971351627eac70eec6763fbc889761828da7a276681b5e39742d"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69f628d2da1489b27959f4d63fdb326781fe484944dce94abbf919e416c54abe"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:35a6b69cc44bda002705d6138346bf0a0234cbb7c26c3bf192513eb946aee6f9"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:49f886e8dcf591275c6e20915b516fd81647857566b0c0158c52df1e468849c9"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:49190eb2ece70313742b0ea51520340288a059674da1f39eefb589d598d9453e"}, - {file = "yarl-1.15.4-cp313-cp313-win32.whl", hash = "sha256:48334a6c8afee93097eb17c0a094234dac2d88da076c8cf372e09e2a5dcc4b66"}, - {file = "yarl-1.15.4-cp313-cp313-win_amd64.whl", hash = "sha256:f68025d6ba1816428b7de615c80f61cb03d5b7061158d4ced7696657a64aa59c"}, - {file = "yarl-1.15.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b569f4f511b59518ba6719feb5b8bf0a5d4115e6ac903c89e10a8a9ac656017"}, - {file = "yarl-1.15.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fe17744d60fc404ac61f824118e1e15ce3c2e92eced9b8e22f3c7847acafbf2"}, - {file = "yarl-1.15.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:115346433fad2084ee3a1a925ccc0659990aa42e208ca54c278830a150a3caf3"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60165b8bc260f453321004b193770a66cc1b1a5c57c07d4b8dcc96839e7ad578"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65a0168691373e08d869d48b62c8bed0af0cdaef19c76e11ad73b43901bbdb5a"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:787532f00543a21b8f4ec3050b4e01b8fe437797903c0156a0b03dfca5e1ba6c"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c9d173e5fa4b12d06ddca09a41cabbdeb660471dbe55432423eec095709ab"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c96eaa30030e1cfafe533f3da8983812281235b7c50ef2a6c78ceca7aea1a0b"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4feab2dcb725eb5b4835207ecf3d370ff7ce930b253cba5e681646cb80d64c2c"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:de38b0b5b86e57efb129d179854e78b65cb8e294a8c75560877869c43aa2415a"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:65e0467f90f2acf3bc83bbfeedece8f1fd84df8add1a54e9600ed7b7b5debdb0"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:40c18f96696549e73b92dc12619f07019cbf5faefc1612608f967c144816e493"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:46491b3e058de7b484e1c9fb20aa8441f06d6c9a18395d711c1c2a9ad6707d6a"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:faa3dd7f4620ab5e5da7a0789d0aac78a9ad0376f102409d442ec5a4179e200a"}, - {file = "yarl-1.15.4-cp39-cp39-win32.whl", hash = "sha256:c33ea7c55a73be343f02361795caf52a187357ea07708fb1cae6661ee1d689c8"}, - {file = "yarl-1.15.4-cp39-cp39-win_amd64.whl", hash = "sha256:11b207061f28b4b6d980239b22ab0ecfadc47846b5a3b8e79f27fcc019d02cf9"}, - {file = "yarl-1.15.4-py3-none-any.whl", hash = "sha256:e5cc288111c450c0a54a74475591b206d3b1cb47dc71bb6200f6be8b1337184c"}, - {file = "yarl-1.15.4.tar.gz", hash = "sha256:a0c5e271058d148d730219ca4f33c5d841c6bd46e05b0da60fea7b516906ccd3"}, + {file = "yarl-1.15.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6c57972a406ea0f61e3f28f2b3a780fb71fbe1d82d267afe5a2f889a83ee7e7"}, + {file = "yarl-1.15.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c3ac5bdcc1375c8ee52784adf94edbce37c471dd2100a117cfef56fe8dbc2b4"}, + {file = "yarl-1.15.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:68d21d0563d82aaf46163eac529adac301b20be3181b8a2811f7bd5615466055"}, + {file = "yarl-1.15.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7d317fb80bc17ed4b34a9aad8b80cef34bea0993654f3e8566daf323def7ef9"}, + {file = "yarl-1.15.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed9c72d5361cfd5af5ccadffa8f8077f4929640e1f938aa0f4b92c5a24996ac5"}, + {file = "yarl-1.15.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bb707859218e8335447b210f41a755e7b1367c33e87add884128bba144694a7f"}, + {file = "yarl-1.15.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6563394492c96cb57f4dff0c69c63d2b28b5469c59c66f35a1e6451583cd0ab4"}, + {file = "yarl-1.15.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c2d1109c8d92059314cc34dd8f0a31f74b720dc140744923ed7ca228bf9b491"}, + {file = "yarl-1.15.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8fc727f0fb388debc771eaa7091c092bd2e8b6b4741b73354b8efadcf96d6031"}, + {file = "yarl-1.15.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:94189746c5ad62e1014a16298130e696fe593d031d442ef135fb7787b7a1f820"}, + {file = "yarl-1.15.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b06d8b05d0fafef204d635a4711283ddbf19c7c0facdc61b4b775f6e47e2d4be"}, + {file = "yarl-1.15.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:de6917946dc6bc237d4b354e38aa13a232e0c7948fdbdb160edee3862e9d735f"}, + {file = "yarl-1.15.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:34816f1d833433a16c4832562a050b0a60eac53dcb71b2032e6ebff82d74b6a7"}, + {file = "yarl-1.15.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:19e2a4b2935f95fad0949f420514c5d862f5f18058fbbfd8854f496a97d9fd87"}, + {file = "yarl-1.15.5-cp310-cp310-win32.whl", hash = "sha256:30ca64521f1a96b72886dd9e8652f16eab11891b4572dcfcfc1ad6d6ccb27abd"}, + {file = "yarl-1.15.5-cp310-cp310-win_amd64.whl", hash = "sha256:86648c53b10c53db8b967a75fb41e0c89dbec7398f6525e34af2b6c456bb0ac0"}, + {file = "yarl-1.15.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e652aa9f8dfa808bc5b2da4d1f4e286cf1d640570fdfa72ffc0c1d16ba114651"}, + {file = "yarl-1.15.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21050b6cd569980fe20ceeab4baeb900d3f7247270475e42bafe117416a5496c"}, + {file = "yarl-1.15.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:18940191ec9a83bbfe63eea61c3e9d12474bb910d5613bce8fa46e84a80b75b2"}, + {file = "yarl-1.15.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a082dc948045606f62dca0228ab24f13737180b253378d6443f5b2b9ef8beefe"}, + {file = "yarl-1.15.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a843e692f9d5402b3455653f4607dc521de2385f01c5cad7ba4a87c46e2ea8d"}, + {file = "yarl-1.15.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5093a453176a4fad4f9c3006f507cf300546190bb3e27944275a37cfd6323a65"}, + {file = "yarl-1.15.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2597a589859b94d0a5e2f5d30fee95081867926e57cb751f8b44a7dd92da4e79"}, + {file = "yarl-1.15.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f5a1ca6eaabfe62718b87eac06d9a47b30cf92ffa065fee9196d3ecd24a3cf1"}, + {file = "yarl-1.15.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4ac83b307cc4b8907345b52994055c6c3c2601ceb6fcb94c5ed6a93c6b4e8257"}, + {file = "yarl-1.15.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:325e2beb2cd8654b276e7686a3cd203628dd3fe32d5c616e632bc35a2901fb16"}, + {file = "yarl-1.15.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:75d04ba8ed335042328086e643e01165e0c24598216f72da709b375930ae3bdb"}, + {file = "yarl-1.15.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7abd7d15aedb3961a967cc65f8144dbbca42e3626a21c5f4f29919cf43eeafb9"}, + {file = "yarl-1.15.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:294c742a273f44511f14b03a9e06b66094dcdf4bbb75a5e23fead548fd5310ae"}, + {file = "yarl-1.15.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:63d46606b20f80a6476f1044bab78e1a69c2e0747f174583e2f12fc70bad2170"}, + {file = "yarl-1.15.5-cp311-cp311-win32.whl", hash = "sha256:b1217102a455e3ac9ac293081093f21f0183e978c7692171ff669fee5296fa28"}, + {file = "yarl-1.15.5-cp311-cp311-win_amd64.whl", hash = "sha256:5848500b6a01497560969e8c3a7eb1b2570853c74a0ca6f67ebaf6064106c49b"}, + {file = "yarl-1.15.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d3309ee667f2d9c7ac9ecf44620d6b274bfdd8065b8c5019ff6795dd887b8fed"}, + {file = "yarl-1.15.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:96ce879799fee124d241ea3b84448378f638e290c49493d00b706f3fd57ec22b"}, + {file = "yarl-1.15.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c884dfa56b050f718ea3cbbfd972e29a6f07f63a7449b10d9a20d64f7eec92e2"}, + {file = "yarl-1.15.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0327081978fe186c3390dd4f73f95f825d0bb9c74967e22c2a1a87735974d8f5"}, + {file = "yarl-1.15.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:524b3bb7dff320e305bc979c65eddc0342548c56ea9241502f907853fe53c408"}, + {file = "yarl-1.15.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd56de8b645421ff09c993fdb0ee9c5a3b50d290a8f55793b500d99b34d0c1ce"}, + {file = "yarl-1.15.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c166ad987265bb343be58cdf4fbc4478cc1d81f2246d2be9a15f94393b269faa"}, + {file = "yarl-1.15.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d56980374a10c74255fcea6ebcfb0aeca7166d212ee9fd7e823ddef35fb62ad0"}, + {file = "yarl-1.15.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cbf36099a9b407e1456dbf55844743a98603fcba32d2a46fb3a698d926facf1b"}, + {file = "yarl-1.15.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d7fa4b033e2f267e37aabcc36949fa89f9f1716a723395912147f9cf3fb437c7"}, + {file = "yarl-1.15.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bb129f77ddaea2d8e6e00417b8d907448de3407af4eddacca0a515574ad71493"}, + {file = "yarl-1.15.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:68e837b3edfcd037f9706157e7cb8efda832de6248c7d9e893e2638356dfae5d"}, + {file = "yarl-1.15.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5b8af4165e097ff84d9bbb97bb4f4d7f71b9c1c9565a2d0e27d93e5f92dae220"}, + {file = "yarl-1.15.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:70d074d5a96e0954fe6db81ff356f4361397da1cda3f7c127fc0902f671a087e"}, + {file = "yarl-1.15.5-cp312-cp312-win32.whl", hash = "sha256:362da97ad4360e4ef1dd24ccdd3bceb18332da7f40026a42f49b7edd686e31c3"}, + {file = "yarl-1.15.5-cp312-cp312-win_amd64.whl", hash = "sha256:9aa054d97033beac9cb9b19b7c0b8784b85b12cd17879087ca6bffba57884e02"}, + {file = "yarl-1.15.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5fadcf532fd9f6cbad71485ef8c2462dd9a91d3efc72ca01eb0970792c92552a"}, + {file = "yarl-1.15.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8b7dd6983c81523f9de0ae6334c3b7a3cb33283936e0525f80c4f713f54a9bb6"}, + {file = "yarl-1.15.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fcfd663dc88465ebe41c7c938bdc91c4b01cda96a0d64bf38fd66c1877323771"}, + {file = "yarl-1.15.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd529e637cd23204bd82072f6637cff7af2516ad2c132e8f3342cbc84871f7d1"}, + {file = "yarl-1.15.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b30f13fac56598474071a4f1ecd66c78fdaf2f8619042d7ca135f72dbb348cf"}, + {file = "yarl-1.15.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44088ec0be82fba118ed29b6b429f80bf295297727adae4c257ac297e01e8bcd"}, + {file = "yarl-1.15.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607683991bab8607e5158cd290dd8fdaa613442aeab802fe1c237d3a3eee7358"}, + {file = "yarl-1.15.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da48cdff56b01ea4282a6d04b83b07a2088351a4a3ff7aacc1e7e9b6b04b90b9"}, + {file = "yarl-1.15.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9162ea117ce8bad8ebc95b7376b4135988acd888d2cf4702f8281e3c11f8b81f"}, + {file = "yarl-1.15.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:e8aa19c39cb20bfb16f0266df175a6004943122cf20707fbf0cacc21f6468a25"}, + {file = "yarl-1.15.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d6be369488d503c8edc14e2f63d71ab2a607041ad216a8ad444fa18e8dea792"}, + {file = "yarl-1.15.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6e2c674cfe4c03ad7a4d536b1f808221f0d11a360486b4b032d2557c0bd633ad"}, + {file = "yarl-1.15.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:041bafaa82b77fd4ec2826d42a55461ec86d999adf7ed9644eef7e8a9febb366"}, + {file = "yarl-1.15.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2eeb9ba53c055740cd282ae9d34eb7970d65e73a46f15adec4b0c1b0f2e55cc2"}, + {file = "yarl-1.15.5-cp313-cp313-win32.whl", hash = "sha256:73143dd279e641543da52c55652ad7b4c7c5f79e797f124f58f04cc060f14271"}, + {file = "yarl-1.15.5-cp313-cp313-win_amd64.whl", hash = "sha256:94ab1185900f43760d5487c8e49f5f1a66f864e36092f282f1813597479b9dfa"}, + {file = "yarl-1.15.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6b3d2767bd64c62909ea33525b954ba05c8f9726bfdf2141d175da4e344f19ae"}, + {file = "yarl-1.15.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:44359c52af9c383e5107f3b6301446fc8269599721fa42fafb2afb5f31a42dcb"}, + {file = "yarl-1.15.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6493da9ba5c551978c679ab04856c2cf8f79c316e8ec8c503460a135705edc3b"}, + {file = "yarl-1.15.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a6b6e95bc621c11cf9ff21012173337e789f2461ebc3b4e5bf65c74ef69adb8"}, + {file = "yarl-1.15.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7983290ede3aaa2c9620879530849532529b4dcbf5b12a0b6a91163a773eadb9"}, + {file = "yarl-1.15.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07a4b53abe85813c538b9cdbb02909ebe3734e3af466a587df516e960d500cc8"}, + {file = "yarl-1.15.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5882faa2a6e684f65ee44f18c701768749a950cbd5e72db452fc07805f6bdec0"}, + {file = "yarl-1.15.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e27861251d9c094f641d39a8a78dd2371fb9a252ea2f689d1ad353a31d46a0bc"}, + {file = "yarl-1.15.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8669a110f655c9eb22f16fb68a7d4942020aeaa09f1def584a80183e3e89953c"}, + {file = "yarl-1.15.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:10bfe0bef4cf5ea0383886beda004071faadedf2647048b9f876664284c5b60d"}, + {file = "yarl-1.15.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f7de0d4b6b4d8a77e422eb54d765255c0ec6883ee03b8fd537101633948619d7"}, + {file = "yarl-1.15.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:00bb3a559d7bd006a5302ecd7e409916939106a8cdbe31f4eb5e5b9ffcca57ea"}, + {file = "yarl-1.15.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:06ec070a2d71415f90dbe9d70af3158e7da97a128519dba2d1581156ee27fb92"}, + {file = "yarl-1.15.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b997a806846c00d1f41d6a251803732837771b2091bead7566f68820e317bfe7"}, + {file = "yarl-1.15.5-cp39-cp39-win32.whl", hash = "sha256:7825506fbee4055265528ec3532a8197ff26fc53d4978917a4c8ddbb4c1667d7"}, + {file = "yarl-1.15.5-cp39-cp39-win_amd64.whl", hash = "sha256:71730658be0b5de7c570a9795d7404c577b2313c1db370407092c66f70e04ccb"}, + {file = "yarl-1.15.5-py3-none-any.whl", hash = "sha256:625f31d6650829fba4030b4e7bdb2d69e41510dddfa29a1da27076c199521757"}, + {file = "yarl-1.15.5.tar.gz", hash = "sha256:8249147ee81c1cf4d1dc6f26ba28a1b9d92751529f83c308ad02164bb93abd0d"}, ] [package.dependencies] @@ -5805,4 +5885,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "29d8c62c96da59b2b1dc59b534ff5300ec0d18b0f526ffc815bfe0f8658c22f1" +content-hash = "0b75ce61bf1e1338e08e99482083f7d1238216f11f9a07edfc29f61d9b620f6f" diff --git a/agents-api/pyproject.toml b/agents-api/pyproject.toml index d0cf7f3b3..47c709286 100644 --- a/agents-api/pyproject.toml +++ b/agents-api/pyproject.toml @@ -51,7 +51,7 @@ ruff = "^0.5.5" datamodel-code-generator = "^0.25.9" cozo-migrate = "^0.2.0" poethepoet = "^0.25.1" -pytype = ">=2024.9.13" +pytype = ">=2024.10.11" pyjwt = "^2.8.0" ward = "^0.68.0b0" jupyterlab = "^4.2.4" diff --git a/agents-api/tests/fixtures.py b/agents-api/tests/fixtures.py index 9ae198c78..c4856112f 100644 --- a/agents-api/tests/fixtures.py +++ b/agents-api/tests/fixtures.py @@ -1,3 +1,4 @@ +import time from uuid import UUID, uuid4 from cozo_migrate.api import apply, init @@ -177,6 +178,8 @@ def test_doc( client=client, ) + time.sleep(0.5) + yield doc delete_doc( diff --git a/agents-api/tests/test_docs_queries.py b/agents-api/tests/test_docs_queries.py index c5826df43..96cf7618e 100644 --- a/agents-api/tests/test_docs_queries.py +++ b/agents-api/tests/test_docs_queries.py @@ -1,6 +1,6 @@ # Tests for entry queries -from ward import skip, test +from ward import test from agents_api.autogen.openapi_model import CreateDocRequest from agents_api.models.docs.create_doc import create_doc @@ -41,7 +41,6 @@ def _( ) -@skip("Execute embedding workflow to fix this test and other docs tests") @test("model: get docs") def _(client=cozo_client, doc=test_doc, developer_id=test_developer_id): get_doc( @@ -79,6 +78,7 @@ def _( owner_type="agent", owner_id=agent.id, client=client, + include_without_embeddings=True, ) assert len(result) >= 1 diff --git a/agents-api/tests/test_execution_workflow.py b/agents-api/tests/test_execution_workflow.py index f4fe00b0e..7ed4492d3 100644 --- a/agents-api/tests/test_execution_workflow.py +++ b/agents-api/tests/test_execution_workflow.py @@ -7,7 +7,7 @@ import yaml from google.protobuf.json_format import MessageToDict from litellm.types.utils import Choices, ModelResponse -from ward import raises, test +from ward import raises, skip, test from agents_api.autogen.openapi_model import ( CreateExecutionRequest, @@ -686,6 +686,7 @@ async def _( assert result["test"] == data.input["test"] +@skip("integration service patch not working") @test("workflow: tool call integration mocked weather") async def _( client=cozo_client, diff --git a/agents-api/tests/test_workflow_routes.py b/agents-api/tests/test_workflow_routes.py index d1538535d..2ffc73173 100644 --- a/agents-api/tests/test_workflow_routes.py +++ b/agents-api/tests/test_workflow_routes.py @@ -46,6 +46,54 @@ async def _( @test("workflow route: evaluate step single with yaml") +async def _( + cozo_client=cozo_client, + developer_id=test_developer_id, + agent=test_agent, +): + agent_id = str(agent.id) + + async with patch_http_client_with_temporal( + cozo_client=cozo_client, developer_id=developer_id + ) as ( + make_request, + client, + ): + task_data = """ +name: test task +description: test task about +input_schema: + type: object + additionalProperties: true + +main: + - evaluate: + hello: '"world"' +""" + + result = ( + make_request( + method="POST", + url=f"/agents/{agent_id}/tasks", + content=task_data.encode("utf-8"), + headers={"Content-Type": "text/yaml"}, + ) + .raise_for_status() + .json() + ) + + task_id = result["id"] + + execution_data = dict(input={"test": "input"}) + + make_request( + method="POST", + url=f"/tasks/{task_id}/executions", + json=execution_data, + ).raise_for_status() + + +@test("workflow route: create or update: evaluate step single with yaml") async def _( cozo_client=cozo_client, developer_id=test_developer_id, diff --git a/cookbooks/05-Basic_Agent_Creation_and_Interaction.py b/cookbooks/05-Basic_Agent_Creation_and_Interaction.py index 05b16f7bd..e57a38560 100644 --- a/cookbooks/05-Basic_Agent_Creation_and_Interaction.py +++ b/cookbooks/05-Basic_Agent_Creation_and_Interaction.py @@ -1,4 +1,4 @@ -# UNDER CONSTRUCTION - NOT WORKING YET +# BASIC AGENT CREATION AND INTERACTION import uuid from julep import Client @@ -35,8 +35,7 @@ # Create a session for interaction session = client.sessions.create( - agent=agent.id, - context_overflow="adaptive" + agent=agent.id ) print(f"Session created with ID: {session.id}") @@ -47,7 +46,6 @@ def chat_with_agent(message): "role": "user", "content": message, } - # TODO: message validation error response = client.sessions.chat( session_id=session.id, messages=[message], @@ -67,7 +65,6 @@ def chat_with_agent(message): print(f"Agent: {response}") # Optional: Retrieve chat history -history = client.sessions.messages.list(session_id=session.id) +history = client.sessions.get(session_id=session.id) print("\nChat History:") -for message in history.items: - print(f"{message.role}: {message.content}") \ No newline at end of file +print(history) \ No newline at end of file diff --git a/cookbooks/10-Document_Management_and_Search.py b/cookbooks/10-Document_Management_and_Search.py index 10f44117d..2df493f8b 100644 --- a/cookbooks/10-Document_Management_and_Search.py +++ b/cookbooks/10-Document_Management_and_Search.py @@ -10,8 +10,6 @@ # 7. Execute the document search task # 8. Display the search results -# UNDER CONSTRUCTION - YAML is working but the flow is not correct yet - import uuid import yaml,time from julep import Client @@ -93,8 +91,6 @@ properties: query: type: string - filters: - type: object tools: - name: document_search @@ -108,18 +104,16 @@ arguments: agent_id: "'{agent.id}'" text: inputs[0].query - metadata_filters: inputs[0].filters - prompt: - role: system content: >- Based on the search results, provide a summary of the most relevant documents found. - Search query: {{inputs[0].query}} + Search query: {{{{inputs[0].query}}}} Number of results: {{len(outputs[0])}} Results: - {{outputs[0]}} - unwrap: true + {{{{outputs[0]}}}} """) # Creating the search task @@ -166,8 +160,7 @@ search_execution = client.executions.create( task_id=SEARCH_TASK_UUID, input={ - "query": "impact of technology on society", - "filters": {"category": "technology"} + "query": "technology" } ) @@ -178,10 +171,14 @@ # Display the search results print("\nSearch Results:") for transition in client.executions.transitions.list(execution_id=search_execution.id).items: - if transition.type == "tool_call" and transition.tool == "document_search": - for doc in transition.output: - print(f"- {doc['content']} (Score: {doc['score']})") + if transition.type == "step" and transition.metadata['step_type'] == "ToolCallStep": + doc_output = transition.output['docs'] + for doc in doc_output: + print(f"Owner: {doc['owner']}") + print(f"Title: {doc['title']}") + print(f"Distance: {doc['distance']}") + print(f"Content: {doc['snippets']}") print("\nSearch Summary:") -search_response = client.executions.transitions.list(search_result.id).items[0].output +search_response = client.executions.transitions.list(search_result.id).items[0].output['choices'][0]['message']['content'] print(search_response) \ No newline at end of file diff --git a/cookbooks/11-Advanced_Chat_Interactions.py b/cookbooks/11-Advanced_Chat_Interactions.py index 1a6b13026..1cfa71555 100644 --- a/cookbooks/11-Advanced_Chat_Interactions.py +++ b/cookbooks/11-Advanced_Chat_Interactions.py @@ -12,7 +12,7 @@ # d. Integrating external information during the conversation # 6. Display the chat history and any relevant metrics -# UNDER CONSTRUCTION - YAML is working but the flow is not correct yet +# UNDER CONSTRUCTION - Dynamic weather integration is not yet implemented, rest of the code is functional import uuid import yaml @@ -75,49 +75,51 @@ integration: provider: weather setup: - api_key: "API_KEY" + api_key: "YOUR_WEATHER_API_KEY" main: -- evaluate: - context_length: len(inputs[0].chat_history) - -- if: "_.context_length > '10'" +- if: "len(inputs[0].chat_history) > 5" + then: + evaluate: + summarized_history: str(inputs[0].chat_history[-5:]) + else: + evaluate: + summarized_history: str(inputs[0].chat_history) + +- if: "search_regex('weather', inputs[0].user_input)" then: + tool: weather_api + arguments: + location: "'NEW YORK'" + else: evaluate: - summarized_history: str(inputs[0].chat_history[-10:]) + weather: "'No weather information requested'" + +- evaluate: + weather: outputs[1] + +- if: "search_regex('weather', inputs[0].user_input)" + then: prompt: - role: system - content: >- + content: >- You are an advanced chat assistant. Here's a summary of the recent conversation: - {{outputs[1].summarized_history}} - + {{outputs[0].summarized_history}} + + The user mentioned weather. Here's the current weather information for NEW YORK + Incorporate this information into your response. + + {{_.weather}} + Now, respond to the user's latest input: {{inputs[0].user_input}} - unwrap: true else: prompt: - role: system content: >- - You are an advanced chat assistant. Here's the conversation history: - {{inputs[0].chat_history}} - + You are an advanced chat assistant. Here's a summary of the recent conversation: + {{outputs[0].summarized_history}} + Now, respond to the user's latest input: {{inputs[0].user_input}} - unwrap: true - -- if: "'weather' in inputs[0].user_input.lower()" - then: - tool: weather_api - arguments: - location: inputs[0].user_input.lower.split('weather')[1].strip() - prompt: - - role: system - content: >- - The user mentioned weather. Here's the current weather information for {{inputs[0].user_input.lower.split('weather')[1].strip()}} - - Incorporate this information into your response. - unwrap: true - -- return: - summary: _ """) # Creating the chat task @@ -141,8 +143,6 @@ def run_chat_session(): chat_history = [] print("Starting advanced chat session. Type 'exit' to end the conversation.") - session = client.sessions.create(agent=AGENT_UUID) - while True: user_input = get_user_input() if user_input.lower() == 'exit': @@ -158,17 +158,17 @@ def run_chat_session(): } ) # Wait for the execution to complete - time.sleep(3) + time.sleep(5) result = client.executions.get(execution.id) print(client.executions.transitions.list(execution.id).items) print(f"Execution result: {result.output}") - assistant_response = result.output + assistant_response = result.output['choices'][0]['message']['content'] chat_history.append({"role": "assistant", "content": assistant_response}) - print(f"Assistant: {assistant_response}") + print(f"Assistant: { assistant_response}") # Simulate a delay for a more natural conversation flow - time.sleep(1) + print("----------------------") print("\nChat session ended. Here's the complete chat history:") display_chat_history(chat_history) diff --git a/cookbooks/14_Automated_Webinar_Scheduling_Workflow.ipynb b/cookbooks/14-Automated_Webinar_Scheduling_Workflow.ipynb similarity index 100% rename from cookbooks/14_Automated_Webinar_Scheduling_Workflow.ipynb rename to cookbooks/14-Automated_Webinar_Scheduling_Workflow.ipynb diff --git a/cookbooks/14_automated_webinar_scheduling_workflow.py b/cookbooks/14-Automated_Webinar_Scheduling_Workflow.py similarity index 100% rename from cookbooks/14_automated_webinar_scheduling_workflow.py rename to cookbooks/14-Automated_Webinar_Scheduling_Workflow.py diff --git a/cookbooks/15_Personal_Finance_Tracker.ipynb b/cookbooks/15-Personal_Finance_Tracker.ipynb similarity index 100% rename from cookbooks/15_Personal_Finance_Tracker.ipynb rename to cookbooks/15-Personal_Finance_Tracker.ipynb diff --git a/cookbooks/15_personal_finance_tracker.py b/cookbooks/15-Personal_Finance_Tracker.py similarity index 100% rename from cookbooks/15_personal_finance_tracker.py rename to cookbooks/15-Personal_Finance_Tracker.py diff --git a/cookbooks/E_commerce_Order_Processing_Workflow.ipynb b/cookbooks/16-E_commerce_Order_Processing_Workflow.ipynb similarity index 100% rename from cookbooks/E_commerce_Order_Processing_Workflow.ipynb rename to cookbooks/16-E_commerce_Order_Processing_Workflow.ipynb diff --git a/cookbooks/e_commerce_order_processing_workflow.py b/cookbooks/16-E_commerce_Order_Processing_Workflow.py similarity index 100% rename from cookbooks/e_commerce_order_processing_workflow.py rename to cookbooks/16-E_commerce_Order_Processing_Workflow.py diff --git a/docs/explanation/default_system_template.md b/docs/explanation/default_system_template.md index 4ba74b2a9..c9885669d 100644 --- a/docs/explanation/default_system_template.md +++ b/docs/explanation/default_system_template.md @@ -15,7 +15,7 @@ You are {{agent.name}}.{{" "}} {%- endif -%} {%- if agent.about -%} -About you: {{agent.name}}.{{" "}} +About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} diff --git a/docs/julep-concepts.md b/docs/julep-concepts.md index b6fc945d7..477e6accf 100644 --- a/docs/julep-concepts.md +++ b/docs/julep-concepts.md @@ -391,7 +391,7 @@ You are {{agent.name}}.{{" "}} {%- endif -%} {%- if agent.about -%} -About you: {{agent.name}}.{{" "}} +About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} diff --git a/example.js b/example.js index df2bf0af8..6bbc083a2 100644 --- a/example.js +++ b/example.js @@ -1,130 +1,161 @@ +// Step 0: Setup +const dotenv = require('dotenv'); const { Julep } = require('@julep/sdk'); -const yaml = require('js-yaml'); -const readline = require('readline'); +const yaml = require('yaml'); -const client = new Julep({ apiKey: 'your_julep_api_key' }); +dotenv.config(); +const client = new Julep({ apiKey: process.env.JULEP_API_KEY, environment: process.env.JULEP_ENVIRONMENT || "production" }); + +// Step 1: Create an Agent async function createAgent() { const agent = await client.agents.create({ name: "Storytelling Agent", - model: "gpt-4", - about: "You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", - }); - - // 🛠️ Add an image generation tool (DALL·E) to the agent - await client.agents.tools.create(agent.id, { - name: "image_generator", - description: "Use this tool to generate images based on descriptions.", - integration: { - provider: "dalle", - method: "generate_image", - setup: { - api_key: "your_openai_api_key", - }, - }, + model: "claude-3.5-sonnet", + about: "You are a creative storyteller that crafts engaging stories on a myriad of topics.", }); - return agent; } +// Step 2: Create a Task that generates a story and comic strip const taskYaml = ` -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside \`\`\`yaml tags at the end of your response. unwrap: true - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].trim() - panels: _.match(/\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)/g) + plot_ideas: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) - # Step 3: Generate images for each panel using the image generator tool + # Step 2: Extract research fields from the plot ideas + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: > + Here are some plot ideas for a story: + {% for idea in _.plot_ideas %} + - {{idea}} + {% endfor %} + + To develop the story, we need to research for the plot ideas. + What should we research? Write down wikipedia search queries for the plot ideas you think are interesting. + Return your output as a yaml list inside \`\`\`yaml tags at the end of your response. + unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 + + - evaluate: + research_queries: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ - # Step 4: Generate a catchy title for the story + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' + + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside \`\`\`yaml tags at the end of your response. The yaml object should have the following structure: + + \`\`\`yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""\`\`\` + + Make sure the yaml is valid and the characters and scenes are not empty. Also take care of semicolons and other gotchas of writing yaml. unwrap: true - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: outputs[2].map(output => output.image.url) + - evaluate: + plot: "load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip())" `; -async function createTask(agent) { - const task = await client.tasks.create(agent.id, yaml.load(taskYaml)); +async function createTask(agentId) { + const task = await client.tasks.create( + agentId, + yaml.parse(taskYaml) + ); return task; } -async function executeTask(task) { - const execution = await client.executions.create(task.id, { +// Step 3: Execute the Task +async function executeTask(taskId) { + const execution = await client.executions.create(taskId, { input: { idea: "A cat who learns to fly" } }); // 🎉 Watch as the story and comic panels are generated - for await (const transition of client.executions.transitions.stream(execution.id)) { - console.log(transition); - } - - // 📦 Once the execution is finished, retrieve the results - const result = await client.executions.get(execution.id); - return result; -} - -async function chatWithAgent(agent) { - const session = await client.sessions.create({ agent_id: agent.id }); - - // 💬 Send messages to the agent - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - const chat = async () => { - rl.question("Enter a message (or 'quit' to exit): ", async (message) => { - if (message.toLowerCase() === 'quit') { - rl.close(); - return; + while (true) { + const result = await client.executions.get(execution.id); + console.log(result.status, result.output); + + if (result.status === 'succeeded' || result.status === 'failed') { + // 📦 Once the execution is finished, retrieve the results + if (result.status === "succeeded") { + console.log(result.output); + } else { + throw new Error(result.error); } + break; + } - const response = await client.sessions.chat(session.id, { message }); - console.log(response); - chat(); - }); - }; - - chat(); + await new Promise(resolve => setTimeout(resolve, 1000)); + } } -// Run the example -async function runExample() { - const agent = await createAgent(); - const task = await createTask(agent); - const result = await executeTask(task); - console.log("Task Result:", result); - await chatWithAgent(agent); +// Main function to run the example +async function main() { + try { + const agent = await createAgent(); + const task = await createTask(agent.id); + await executeTask(task.id); + } catch (error) { + console.error("An error occurred:", error); + } } -runExample().catch(console.error); \ No newline at end of file +main().then(() => console.log("Done")).catch(console.error); diff --git a/example.mjs b/example.mjs new file mode 100644 index 000000000..2fec89dfd --- /dev/null +++ b/example.mjs @@ -0,0 +1,161 @@ +// Step 0: Setup +import dotenv from 'dotenv'; +import { Julep } from '@julep/sdk'; +import yaml from 'yaml'; + +dotenv.config(); + +const client = new Julep({ apiKey: process.env.JULEP_API_KEY, environment: process.env.JULEP_ENVIRONMENT || "production" }); + +// Step 1: Create an Agent +async function createAgent() { + const agent = await client.agents.create({ + name: "Storytelling Agent", + model: "claude-3.5-sonnet", + about: "You are a creative storyteller that crafts engaging stories on a myriad of topics.", + }); + return agent; +} + +// Step 2: Create a Task that generates a story and comic strip +const taskYaml = ` +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search + +main: + # Step 1: Generate plot idea + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: > + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside \`\`\`yaml tags at the end of your response. + unwrap: true + + - evaluate: + plot_ideas: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + + # Step 2: Extract research fields from the plot ideas + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: > + Here are some plot ideas for a story: + {% for idea in _.plot_ideas %} + - {{idea}} + {% endfor %} + + To develop the story, we need to research for the plot ideas. + What should we research? Write down wikipedia search queries for the plot ideas you think are interesting. + Return your output as a yaml list inside \`\`\`yaml tags at the end of your response. + unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 + + - evaluate: + research_queries: load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip()) + + # Step 3: Research each plot idea + - foreach: + in: _.research_queries + do: + tool: research_wikipedia + arguments: + query: _ + + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' + + # Step 4: Think and deliberate + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside \`\`\`yaml tags at the end of your response. The yaml object should have the following structure: + + \`\`\`yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""\`\`\` + + Make sure the yaml is valid and the characters and scenes are not empty. Also take care of semicolons and other gotchas of writing yaml. + unwrap: true + + - evaluate: + plot: "load_yaml(_.split('\`\`\`yaml')[1].split('\`\`\`')[0].strip())" +`; + +async function createTask(agentId) { + const task = await client.tasks.create( + agentId, + yaml.parse(taskYaml) + ); + return task; +} + +// Step 3: Execute the Task +async function executeTask(taskId) { + const execution = await client.executions.create(taskId, { + input: { idea: "A cat who learns to fly" } + }); + + // 🎉 Watch as the story and comic panels are generated + while (true) { + const result = await client.executions.get(execution.id); + console.log(result.status, result.output); + + if (result.status === 'succeeded' || result.status === 'failed') { + // 📦 Once the execution is finished, retrieve the results + if (result.status === "succeeded") { + console.log(result.output); + } else { + throw new Error(result.error); + } + break; + } + + await new Promise(resolve => setTimeout(resolve, 1000)); + } +} + +// Main function to run the example +async function main() { + try { + const agent = await createAgent(); + const task = await createTask(agent.id); + await executeTask(task.id); + } catch (error) { + console.error("An error occurred:", error); + } +} + +main().then(() => console.log("Done")).catch(console.error); diff --git a/example.py b/example.py index 1d0e7deda..cc7982523 100644 --- a/example.py +++ b/example.py @@ -1,75 +1,116 @@ +### Step 0: Setup + +import os +import time import yaml -from julep import Julep +from julep import Julep # or AsyncJulep + +client = Julep(api_key=os.environ["JULEP_API_KEY"]) -# Initialize the Julep client -client = Julep(api_key="your_julep_api_key") +### Step 1: Create an Agent -# Step 1: Create an Agent agent = client.agents.create( name="Storytelling Agent", - model="gpt-4", - about="You are a creative storytelling agent that can craft engaging stories and generate comic panels based on ideas.", + model="claude-3.5-sonnet", + about="You are a creative storyteller that crafts engaging stories on a myriad of topics.", ) -# Add an image generation tool (DALL·E) to the agent -client.agents.tools.create( - agent_id=agent.id, - name="image_generator", - description="Use this tool to generate images based on descriptions.", - integration={ - "provider": "dalle", - "method": "generate_image", - "setup": { - "api_key": "your_openai_api_key", - }, - }, -) +### Step 2: Create a Task that generates a story and comic strip -# Step 2: Create a Task that generates a story and comic strip task_yaml = """ -name: Story and Comic Creator -description: Create a story based on an idea and generate a 4-panel comic strip illustrating the story. +name: Storyteller +description: Create a story based on an idea. + +tools: + - name: research_wikipedia + integration: + provider: wikipedia + method: search main: - # Step 1: Generate a story and outline into 4 panels + # Step 1: Generate plot idea - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user content: > - Based on the idea '{{_.idea}}', write a short story suitable for a 4-panel comic strip. - Provide the story and a numbered list of 4 brief descriptions for each panel illustrating key moments in the story. + Based on the idea '{{_.idea}}', generate a list of 5 plot ideas. Go crazy and be as creative as possible. Return your output as a list of long strings inside ```yaml tags at the end of your response. unwrap: true - # Step 2: Extract the panel descriptions and story - evaluate: - story: _.split('1. ')[0].strip() - panels: re.findall(r'\\d+\\.\\s*(.*?)(?=\\d+\\.\\s*|$)', _) + plot_ideas: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) - # Step 3: Generate images for each panel using the image generator tool + # Step 2: Extract research fields from the plot ideas + - prompt: + - role: system + content: You are {{agent.name}}. {{agent.about}} + - role: user + content: > + Here are some plot ideas for a story: + {% for idea in _.plot_ideas %} + - {{idea}} + {% endfor %} + + To develop the story, we need to research for the plot ideas. + What should we research? Write down wikipedia search queries for the plot ideas you think are interesting. + Return your output as a yaml list inside ```yaml tags at the end of your response. + unwrap: true + settings: + model: gpt-4o-mini + temperature: 0.7 + + - evaluate: + research_queries: load_yaml(_.split('```yaml')[1].split('```')[0].strip()) + + # Step 3: Research each plot idea - foreach: - in: _.panels + in: _.research_queries do: - tool: image_generator + tool: research_wikipedia arguments: - description: _ + query: _ + + - evaluate: + wikipedia_results: 'NEWLINE.join([f"- {doc.metadata.title}: {doc.metadata.summary}" for item in _ for doc in item.documents])' - # Step 4: Generate a catchy title for the story + # Step 4: Think and deliberate - prompt: - role: system content: You are {{agent.name}}. {{agent.about}} - role: user - content: > - Based on the story below, generate a catchy title. - - Story: {{outputs[1].story}} + content: |- + Before we write the story, let's think and deliberate. Here are some plot ideas: + {% for idea in outputs[1].plot_ideas %} + - {{idea}} + {% endfor %} + + Here are the results from researching the plot ideas on Wikipedia: + {{_.wikipedia_results}} + + Think about the plot ideas critically. Combine the plot ideas with the results from Wikipedia to create a detailed plot for a story. + Write down all your notes and thoughts. + Then finally write the plot as a yaml object inside ```yaml tags at the end of your response. The yaml object should have the following structure: + + ```yaml + title: "" + characters: + - name: "" + about: "" + synopsis: "" + scenes: + - title: "" + description: "" + characters: + - name: "" + role: "" + plotlines: + - ""``` + + Make sure the yaml is valid and the characters and scenes are not empty. Also take care of semicolons and other gotchas of writing yaml. unwrap: true - # Step 5: Return the story, the generated images, and the title - - return: - title: outputs[3] - story: outputs[1].story - comic_panels: "[output.image.url for output in outputs[2]]" + - evaluate: + plot: "load_yaml(_.split('```yaml')[1].split('```')[0].strip())" """ task = client.tasks.create( @@ -77,33 +118,20 @@ **yaml.safe_load(task_yaml) ) -# Step 3: Execute the Task +### Step 3: Execute the Task + execution = client.executions.create( task_id=task.id, input={"idea": "A cat who learns to fly"} ) -# Watch as the story and comic panels are generated -for transition in client.executions.transitions.stream(execution_id=execution.id): - print(transition) - -# Once the execution is finished, retrieve the results -result = client.executions.get(execution_id=execution.id) -print("Task Result:", result) - -# Step 4: Chat with the Agent -session = client.sessions.create(agent_id=agent.id) - -# Send messages to the agent -while True: - message = input("Enter a message (or 'quit' to exit): ") - if message.lower() == 'quit': - break - - response = client.sessions.chat( - session_id=session.id, - message=message, - ) - print("Agent:", response.choices[0].message.content) - -print("Chat session ended.") +# 🎉 Watch as the story and comic panels are generated +while (result := client.executions.get(execution.id)).status not in ['succeeded', 'failed']: + print(result.status, result.output) + time.sleep(1) + +# 📦 Once the execution is finished, retrieve the results +if result.status == "succeeded": + print(result.output) +else: + raise Exception(result.error) \ No newline at end of file diff --git a/integrations-service/integrations/models/base_models.py b/integrations-service/integrations/models/base_models.py index 9f119d460..55b614a2a 100644 --- a/integrations-service/integrations/models/base_models.py +++ b/integrations-service/integrations/models/base_models.py @@ -1,6 +1,6 @@ -from typing import Annotated, Any, Optional +from typing import Annotated, Optional -from pydantic import BaseModel, Field, RootModel +from pydantic import BaseModel, Field from pydantic_core import Url IdentifierName = Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")] diff --git a/integrations-service/integrations/models/email.py b/integrations-service/integrations/models/email.py index cab794a7d..11943968d 100644 --- a/integrations-service/integrations/models/email.py +++ b/integrations-service/integrations/models/email.py @@ -16,7 +16,9 @@ class EmailSetup(BaseSetup): class EmailArguments(BaseArguments): to: EmailStr = Field(..., description="The email address to send the email to") - from_: EmailStr = Field(..., alias="from", description="The email address to send the email from") + from_: EmailStr = Field( + ..., alias="from", description="The email address to send the email from" + ) subject: str = Field(..., description="The subject of the email") body: str = Field(..., description="The body of the email") diff --git a/integrations-service/integrations/models/wikipedia.py b/integrations-service/integrations/models/wikipedia.py index 8c8e4f623..36a2108ce 100644 --- a/integrations-service/integrations/models/wikipedia.py +++ b/integrations-service/integrations/models/wikipedia.py @@ -1,5 +1,3 @@ -from typing import Literal - from langchain_core.documents import Document from pydantic import Field diff --git a/integrations-service/integrations/providers.py b/integrations-service/integrations/providers.py index 41b5bf757..76ede47af 100644 --- a/integrations-service/integrations/providers.py +++ b/integrations-service/integrations/providers.py @@ -10,8 +10,6 @@ EmailArguments, EmailOutput, EmailSetup, - HackerNewsFetchArguments, - HackerNewsFetchOutput, ProviderInfo, SpiderFetchArguments, SpiderFetchOutput, @@ -61,25 +59,6 @@ ), ) -hacker_news = BaseProvider( - provider="hacker_news", - setup=None, - methods=[ - BaseProviderMethod( - method="fetch", - description="Get the top stories from Hacker News", - arguments=HackerNewsFetchArguments, - output=HackerNewsFetchOutput, - ), - ], - info=ProviderInfo( - url="https://news.ycombinator.com/", - docs="https://news.ycombinator.com/newsguidelines.html", - icon="https://news.ycombinator.com/favicon.ico", - friendly_name="Hacker News", - ), -) - spider = BaseProvider( provider="spider", setup=SpiderSetup, @@ -156,7 +135,6 @@ providers = { "wikipedia": wikipedia, "weather": weather, - "hacker_news": hacker_news, "spider": spider, "brave": brave, "browserbase": browserbase, diff --git a/integrations-service/integrations/routers/execution/execute.py b/integrations-service/integrations/routers/execution/execute.py index df4bf913a..3097c6c99 100644 --- a/integrations-service/integrations/routers/execution/execute.py +++ b/integrations-service/integrations/routers/execution/execute.py @@ -20,13 +20,13 @@ async def execute( @router.post("/execute/{provider}/{method}", tags=["execution"]) -def execute( +async def execute( provider: IdentifierName, method: IdentifierName, data: ExecutionRequest, ) -> ExecutionResponse: try: - return execute_integration( + return await execute_integration( provider=provider, arguments=data.arguments, setup=data.setup, method=method ) except ValueError as e: diff --git a/integrations-service/integrations/routers/integrations/get_integration.py b/integrations-service/integrations/routers/integrations/get_integration.py index 2a9b34595..7b45c8190 100644 --- a/integrations-service/integrations/routers/integrations/get_integration.py +++ b/integrations-service/integrations/routers/integrations/get_integration.py @@ -1,5 +1,3 @@ -from typing import List - from ...providers import providers from .router import router diff --git a/integrations-service/integrations/utils/execute_integration.py b/integrations-service/integrations/utils/execute_integration.py index ab1907885..f1dd1965a 100644 --- a/integrations-service/integrations/utils/execute_integration.py +++ b/integrations-service/integrations/utils/execute_integration.py @@ -30,7 +30,7 @@ async def execute_integration( setup = setup_class(**setup.model_dump()) arguments_class = next(m for m in provider.methods if m.method == method).arguments - + if not isinstance(arguments, arguments_class): parsed_arguments = arguments_class(**arguments.model_dump()) else: diff --git a/integrations-service/integrations/utils/integrations/__init__.py b/integrations-service/integrations/utils/integrations/__init__.py index 238dacfd3..ce5ed0e83 100644 --- a/integrations-service/integrations/utils/integrations/__init__.py +++ b/integrations-service/integrations/utils/integrations/__init__.py @@ -1,7 +1,6 @@ from .brave import search from .browserbase import load from .email import send -from .hacker_news import fetch from .spider import crawl from .weather import get from .wikipedia import search diff --git a/integrations-service/integrations/utils/integrations/brave.py b/integrations-service/integrations/utils/integrations/brave.py index 10bfe8084..3723f80d7 100644 --- a/integrations-service/integrations/utils/integrations/brave.py +++ b/integrations-service/integrations/utils/integrations/brave.py @@ -1,8 +1,14 @@ from langchain_community.tools import BraveSearch +from tenacity import retry, stop_after_attempt, wait_exponential from ...models import BraveSearchArguments, BraveSearchOutput, BraveSearchSetup +@retry( + wait=wait_exponential(multiplier=1, min=4, max=10), + reraise=True, + stop=stop_after_attempt(4), +) async def search( setup: BraveSearchSetup, arguments: BraveSearchArguments ) -> BraveSearchOutput: diff --git a/integrations-service/integrations/utils/integrations/browserbase.py b/integrations-service/integrations/utils/integrations/browserbase.py index 7cc672662..87e7c8cac 100644 --- a/integrations-service/integrations/utils/integrations/browserbase.py +++ b/integrations-service/integrations/utils/integrations/browserbase.py @@ -1,8 +1,14 @@ from langchain_community.document_loaders import BrowserbaseLoader +from tenacity import retry, stop_after_attempt, wait_exponential from ...models import BrowserBaseLoadArguments, BrowserBaseLoadOutput, BrowserBaseSetup +@retry( + wait=wait_exponential(multiplier=1, min=4, max=10), + reraise=True, + stop=stop_after_attempt(3), +) async def load( setup: BrowserBaseSetup, arguments: BrowserBaseLoadArguments ) -> BrowserBaseLoadOutput: diff --git a/integrations-service/integrations/utils/integrations/dalle_image_generator.py b/integrations-service/integrations/utils/integrations/dalle_image_generator.py deleted file mode 100644 index e0a6496b8..000000000 --- a/integrations-service/integrations/utils/integrations/dalle_image_generator.py +++ /dev/null @@ -1,22 +0,0 @@ -from langchain_community.utilities.dalle_image_generator import DallEAPIWrapper - -from ...models import DalleImageGeneratorArguments, DalleImageGeneratorSetup - - -async def dalle_image_generator( - setup: DalleImageGeneratorSetup, arguments: DalleImageGeneratorArguments -) -> str: - """ - Generates an image using DALL-E based on a provided prompt. - """ - - assert isinstance(setup, DalleImageGeneratorSetup), "Invalid setup" - assert isinstance(arguments, DalleImageGeneratorArguments), "Invalid arguments" - - # FIXME: Fix OpenAI API Key error - - dalle = DallEAPIWrapper(api_key=setup.api_key) - prompt = arguments.prompt - if not prompt: - raise ValueError("Prompt parameter is required for DALL-E image generation") - return dalle.run(prompt) diff --git a/integrations-service/integrations/utils/integrations/duckduckgo_search.py b/integrations-service/integrations/utils/integrations/duckduckgo_search.py deleted file mode 100644 index a8ea38f56..000000000 --- a/integrations-service/integrations/utils/integrations/duckduckgo_search.py +++ /dev/null @@ -1,15 +0,0 @@ -from langchain_community.tools import DuckDuckGoSearchRun - -from ...models import DuckDuckGoSearchExecutionArguments - - -async def duckduckgo_search(arguments: DuckDuckGoSearchExecutionArguments) -> str: - """ - Performs a web search using DuckDuckGo and returns the results. - """ - - search = DuckDuckGoSearchRun() - query = arguments.query - if not query: - raise ValueError("Query parameter is required for DuckDuckGo search") - return search.run(query) diff --git a/integrations-service/integrations/utils/integrations/email.py b/integrations-service/integrations/utils/integrations/email.py index b0ced9ff5..5913beb73 100644 --- a/integrations-service/integrations/utils/integrations/email.py +++ b/integrations-service/integrations/utils/integrations/email.py @@ -1,15 +1,17 @@ from email.message import EmailMessage from smtplib import SMTP -from beartype import beartype +from tenacity import retry, stop_after_attempt, wait_exponential from ...models import EmailArguments, EmailOutput, EmailSetup -# @beartype -async def send( - setup: EmailSetup, arguments: EmailArguments -) -> EmailOutput: +@retry( + wait=wait_exponential(multiplier=1, min=4, max=10), + reraise=True, + stop=stop_after_attempt(4), +) +async def send(setup: EmailSetup, arguments: EmailArguments) -> EmailOutput: """ Sends an email with the provided details. """ diff --git a/integrations-service/integrations/utils/integrations/gmail/send_mail.py b/integrations-service/integrations/utils/integrations/gmail/send_mail.py deleted file mode 100644 index e1863f280..000000000 --- a/integrations-service/integrations/utils/integrations/gmail/send_mail.py +++ /dev/null @@ -1,6 +0,0 @@ -async def send_mail(arguments: dict) -> str: - """ - Dummy integration for sending an email to a specified recipient with a given subject and message. - """ - - return "Mail sent" diff --git a/integrations-service/integrations/utils/integrations/hacker_news.py b/integrations-service/integrations/utils/integrations/hacker_news.py deleted file mode 100644 index 526024c72..000000000 --- a/integrations-service/integrations/utils/integrations/hacker_news.py +++ /dev/null @@ -1,22 +0,0 @@ -from langchain_community.document_loaders import HNLoader - -from ...models import HackerNewsFetchArguments, HackerNewsFetchOutput - - -async def fetch(arguments: HackerNewsFetchArguments) -> HackerNewsFetchOutput: - """ - Fetches and formats content from a Hacker News thread using the provided URL. - """ - - assert isinstance(arguments, HackerNewsFetchArguments), "Invalid arguments" - - url = arguments.url - if not url: - raise ValueError("URL parameter is required for Hacker News search") - loader = HNLoader(str(url)) - documents = loader.load() - - if not documents: - raise ValueError("No data found for the given URL") - - return HackerNewsFetchOutput(documents=documents) diff --git a/integrations-service/integrations/utils/integrations/request.py b/integrations-service/integrations/utils/integrations/request.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/integrations-service/integrations/utils/integrations/spider.py b/integrations-service/integrations/utils/integrations/spider.py index a355e2347..7ff06a46d 100644 --- a/integrations-service/integrations/utils/integrations/spider.py +++ b/integrations-service/integrations/utils/integrations/spider.py @@ -1,9 +1,17 @@ from langchain_community.document_loaders import SpiderLoader +from tenacity import retry, stop_after_attempt, wait_exponential from ...models import SpiderFetchArguments, SpiderFetchOutput, SpiderSetup -async def crawl(setup: SpiderSetup, arguments: SpiderFetchArguments) -> SpiderFetchOutput: +@retry( + wait=wait_exponential(multiplier=1, min=4, max=10), + reraise=True, + stop=stop_after_attempt(4), +) +async def crawl( + setup: SpiderSetup, arguments: SpiderFetchArguments +) -> SpiderFetchOutput: """ Fetches data from a specified URL. """ diff --git a/integrations-service/integrations/utils/integrations/weather.py b/integrations-service/integrations/utils/integrations/weather.py index e9393bc09..0266aca4b 100644 --- a/integrations-service/integrations/utils/integrations/weather.py +++ b/integrations-service/integrations/utils/integrations/weather.py @@ -1,8 +1,14 @@ from langchain_community.utilities import OpenWeatherMapAPIWrapper +from tenacity import retry, stop_after_attempt, wait_exponential from ...models import WeatherGetArguments, WeatherGetOutput, WeatherSetup +@retry( + wait=wait_exponential(multiplier=1, min=4, max=10), + reraise=True, + stop=stop_after_attempt(4), +) async def get(setup: WeatherSetup, arguments: WeatherGetArguments) -> WeatherGetOutput: """ Fetches weather data for a specified location using OpenWeatherMap API. @@ -20,4 +26,3 @@ async def get(setup: WeatherSetup, arguments: WeatherGetArguments) -> WeatherGet weather = OpenWeatherMapAPIWrapper(openweathermap_api_key=openweathermap_api_key) result = weather.run(location) return WeatherGetOutput(result=result) - diff --git a/integrations-service/integrations/utils/integrations/wikipedia.py b/integrations-service/integrations/utils/integrations/wikipedia.py index aa53b5515..d4b212d7b 100644 --- a/integrations-service/integrations/utils/integrations/wikipedia.py +++ b/integrations-service/integrations/utils/integrations/wikipedia.py @@ -1,8 +1,14 @@ from langchain_community.document_loaders import WikipediaLoader +from tenacity import retry, stop_after_attempt, wait_exponential from ...models import WikipediaSearchArguments, WikipediaSearchOutput +@retry( + wait=wait_exponential(multiplier=1, min=4, max=10), + reraise=True, + stop=stop_after_attempt(4), +) def search(arguments: WikipediaSearchArguments) -> WikipediaSearchOutput: """ Searches Wikipedia for a given query and returns formatted results. diff --git a/integrations-service/poetry.lock b/integrations-service/poetry.lock index bc294a56f..83a500a29 100644 --- a/integrations-service/poetry.lock +++ b/integrations-service/poetry.lock @@ -889,18 +889,18 @@ files = [ [[package]] name = "langchain" -version = "0.3.2" +version = "0.3.4" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain-0.3.2-py3-none-any.whl", hash = "sha256:cf005dcba132e46fb5e8d3dfaf7f8751bffd2d73e738c36be58f41edc7e3a4b8"}, - {file = "langchain-0.3.2.tar.gz", hash = "sha256:dc330e6eb10d81d23ba0305d18358702c73cc59e95c410eca6c6779aab4ddc9b"}, + {file = "langchain-0.3.4-py3-none-any.whl", hash = "sha256:7a1241d9429510d2083c62df0da998a7b2b05c730cd4255b89da9d47c57f48fd"}, + {file = "langchain-0.3.4.tar.gz", hash = "sha256:3596515fcd0157dece6ec96e0240d29f4cf542d91ecffc815d32e35198dfff37"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" -langchain-core = ">=0.3.8,<0.4.0" +langchain-core = ">=0.3.12,<0.4.0" langchain-text-splitters = ">=0.3.0,<0.4.0" langsmith = ">=0.1.17,<0.2.0" numpy = {version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""} @@ -908,41 +908,41 @@ pydantic = ">=2.7.4,<3.0.0" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [[package]] name = "langchain-community" -version = "0.3.1" +version = "0.3.3" description = "Community contributed LangChain integrations." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_community-0.3.1-py3-none-any.whl", hash = "sha256:627eb26c16417764762ac47dd0d3005109f750f40242a88bb8f2958b798bcf90"}, - {file = "langchain_community-0.3.1.tar.gz", hash = "sha256:c964a70628f266a61647e58f2f0434db633d4287a729f100a81dd8b0654aec93"}, + {file = "langchain_community-0.3.3-py3-none-any.whl", hash = "sha256:319cfc2f923a066c91fbb8e02decd7814018af952b6b98298b8ac9d30ea1da56"}, + {file = "langchain_community-0.3.3.tar.gz", hash = "sha256:bfb3f2b219aed21087e0ecb7d2ebd1c81401c02b92239e11645c822d5be63f80"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain = ">=0.3.1,<0.4.0" -langchain-core = ">=0.3.6,<0.4.0" +langchain = ">=0.3.4,<0.4.0" +langchain-core = ">=0.3.12,<0.4.0" langsmith = ">=0.1.125,<0.2.0" numpy = {version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""} pydantic-settings = ">=2.4.0,<3.0.0" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [[package]] name = "langchain-core" -version = "0.3.9" +version = "0.3.12" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.9-py3-none-any.whl", hash = "sha256:26efa048666c7de56d0ab311de2c0778b04cbb2ffe95bff76139118f13815d01"}, - {file = "langchain_core-0.3.9.tar.gz", hash = "sha256:7a6ac988d24d0ddce5874b28f538cd95f69f502b7f50581de22aca0dc58199a8"}, + {file = "langchain_core-0.3.12-py3-none-any.whl", hash = "sha256:46050d34f5fa36dc57dca971c6a26f505643dd05ee0492c7ac286d0a78a82037"}, + {file = "langchain_core-0.3.12.tar.gz", hash = "sha256:98a3c078e375786aa84939bfd1111263af2f3bc402bbe2cac9fa18a387459cf2"}, ] [package.dependencies] @@ -954,7 +954,7 @@ pydantic = [ {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, ] PyYAML = ">=5.3" -tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" typing-extensions = ">=4.7" [[package]] @@ -2198,13 +2198,13 @@ widechars = ["wcwidth"] [[package]] name = "tenacity" -version = "8.5.0" +version = "9.0.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"}, - {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"}, + {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, + {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, ] [package.extras] @@ -2462,4 +2462,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "4f933143b7f17beaa1c4e8bdc117978de07df01f9b8b0eb4eb11f88182230ee5" +content-hash = "6ea8ddd02f0921f3edb5527dce0abc6d174124516d4b7348ba4083e3737957fc" diff --git a/integrations-service/pyproject.toml b/integrations-service/pyproject.toml index 33173f2c2..592206fc6 100644 --- a/integrations-service/pyproject.toml +++ b/integrations-service/pyproject.toml @@ -21,6 +21,7 @@ spider-client = "^0.0.70" browserbase = "^0.3.0" setuptools = "^75.1.0" beartype = "^0.19.0" +tenacity = "^9.0.0" [tool.poe.tasks] format = "ruff format" diff --git a/typespec/common/constants.tsp b/typespec/common/constants.tsp index e60329752..524a2c14c 100644 --- a/typespec/common/constants.tsp +++ b/typespec/common/constants.tsp @@ -10,7 +10,7 @@ You are {{agent.name}}.{{" "}} {%- endif -%} {%- if agent.about -%} -About you: {{agent.name}}.{{" "}} +About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} diff --git a/typespec/tsp-output/@typespec/openapi3/openapi-0.4.0.yaml b/typespec/tsp-output/@typespec/openapi3/openapi-0.4.0.yaml index 63ce86ae1..597c61513 100644 --- a/typespec/tsp-output/@typespec/openapi3/openapi-0.4.0.yaml +++ b/typespec/tsp-output/@typespec/openapi3/openapi-0.4.0.yaml @@ -3196,7 +3196,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3328,7 +3328,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3482,7 +3482,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3601,7 +3601,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3783,7 +3783,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} diff --git a/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml b/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml index 5bcbdb1b8..ffdc05a26 100644 --- a/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml +++ b/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml @@ -3196,7 +3196,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3328,7 +3328,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3482,7 +3482,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3601,7 +3601,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%} @@ -3783,7 +3783,7 @@ components: {%- endif -%} {%- if agent.about -%} - About you: {{agent.name}}.{{" "}} + About you: {{agent.about}}.{{" "}} {%- endif -%} {%- if user -%}