Compare commits

..

15 Commits

Author SHA1 Message Date
Nicholas Tindle
4b4207760f Update test.py 2025-01-27 14:11:46 +00:00
Aarushi
fe84cbe566 Revert "feature(backend): Add ability to execute store agents without agent ownership" (#9263)
Reverts Significant-Gravitas/AutoGPT#9179

This PR is preventing the running of agents in dev.
2025-01-13 18:34:17 +00:00
Aarushi
5618072375 fix(blocks/Exa): Fix exa contents block advanced toggle (#9255)
Toggling the advanced option on Exa Contents Block isn't working. It
throws a frontend error.

### Changes 🏗️

Remove Optional from ContentRetrievalSettings in exa/contents.py

### Checklist 📋

#### For code changes:
- [x ] I have clearly listed my changes in the PR description
- [ x] I have made a test plan
- [ x] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - Add an ExaContentsBlock
  - Hit advanced


#### For configuration changes:
N/A
2025-01-13 16:35:14 +00:00
Reinier van der Leer
95b79abcfe Revert broken Library v2 DB stuff of #9218, #9211 (#9256)
- **Revert "feature(platform): Implement library add, update, remove,
archive functionality (#9218)"**
- **Revert "feat(backend): Add Support for Managing Agent Presets with
Pagination and Soft Delete (#9211)"**

These PRs contain untested changes to DB functions and cause issues in
production.
2025-01-13 16:08:58 +01:00
Swifty
fd6f28fa57 feature(platform): Implement library add, update, remove, archive functionality (#9218)
### Changes 🏗️

1. **Core Features**:
   - Add agents to the user's library.
   - Update library agents (auto-update, favorite, archive, delete).
   - Paginate library agents and presets.
   - Execute graphs using presets.

2. **Refactoring**:
   - Replaced `UserAgent` with `LibraryAgent`.
   - Separated routes for agents and presets.

3. **Schema Changes**:
- Added `LibraryAgent` table with fields like `isArchived`, `isDeleted`,
etc.
   - Soft delete functionality for `AgentPreset`.

4. **Testing**:
   - Updated tests for `LibraryAgent` operations.
   - Added edge case tests for deletion, archiving, and pagination.

5. **Database Migrations**:
   - Migration to drop `UserAgent` and add `LibraryAgent`.
   - Added fields for soft deletion and auto-update.


Note this includes the changes from the following PR's to avoid merge
conflicts with them:

#9179 
#9211

---------

Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
2025-01-10 13:02:53 +01:00
Swifty
4b17cc9963 feat(backend): Add Support for Managing Agent Presets with Pagination and Soft Delete (#9211)
#### Summary
- **New Models**: Added `LibraryAgentPreset`,
`LibraryAgentPresetResponse`, `Pagination`, and
`CreateLibraryAgentPresetRequest`.
- **Database Changes**:
  - Added `isDeleted` column in `AgentPreset` for soft delete.
  - CRUD operations for `AgentPreset`:
    - `get_presets` with pagination.
    - `get_preset` by ID.
    - `create_or_update_preset` for upsert.
    - `delete_preset` to soft delete.
- **API Routes**:
  - `GET /presets`: Fetch paginated presets.
  - `GET /presets/{preset_id}`: Fetch a single preset.
  - `POST /presets`: Create a preset.
  - `PUT /presets/{preset_id}`: Update a preset.
  - `DELETE /presets/{preset_id}`: Soft delete a preset.
- **Tests**:
  - Coverage for models, CRUD operations, and pagination.
- **Migration**:
  - Added `isDeleted` field to support soft delete.

#### Review Notes
- Validate migration scripts and test coverage.
- Ensure API aligns with project standards.

---------

Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
2025-01-10 12:57:35 +01:00
Swifty
00bb7c67b3 feature(backend): Add ability to execute store agents without agent ownership (#9179)
### Description

This PR enables the execution of store agents even if they are not owned
by the user. Key changes include handling store-listed agents in the
`get_graph` logic, improving execution flow, and ensuring
version-specific handling. These updates support more flexible agent
execution.

### Changes 🏗️

- **Graph Retrieval:** Updated `get_graph` to check store listings for
agents not owned by the user.
- **Version Handling:** Added `graph_version` to execution methods for
consistent version-specific execution.
- **Execution Flow:** Refactored `scheduler.py`, `rest_api.py`, and
other modules for clearer logic and better maintainability.
- **Testing:** Updated `test_manager.py` and other test cases to
validate execution of store-listed agents added test for accessing graph

---------

Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
Co-authored-by: Zamil Majdy <zamil.majdy@agpt.co>
2025-01-10 12:39:06 +01:00
Zamil Majdy
9d1bc25ffa hotfix(backend): Increase statement timeout for the double brace migration (#9245)
### Changes 🏗️


https://github.com/Significant-Gravitas/AutoGPT/actions/runs/12696734339/job/35391431786

### Checklist 📋

#### For code changes:
- [ ] I have clearly listed my changes in the PR description
- [ ] I have made a test plan
- [ ] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - [ ] ...

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:
- [ ] `.env.example` is updated or already compatible with my changes
- [ ] `docker-compose.yml` is updated or already compatible with my
changes
- [ ] I have included a list of my configuration changes in the PR
description (under **Changes**)

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>
2025-01-09 21:59:22 +00:00
Zamil Majdy
3a3ee994c2 hotfix(backend): Increase statement timeout for the double brace migration (#9244)
### Changes 🏗️


https://github.com/Significant-Gravitas/AutoGPT/actions/runs/12696734339/job/35391431786

### Checklist 📋

#### For code changes:
- [ ] I have clearly listed my changes in the PR description
- [ ] I have made a test plan
- [ ] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - [ ] ...

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:
- [ ] `.env.example` is updated or already compatible with my changes
- [ ] `docker-compose.yml` is updated or already compatible with my
changes
- [ ] I have included a list of my configuration changes in the PR
description (under **Changes**)

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>
2025-01-09 19:44:37 +00:00
Aarushi
0d44f5be13 feat(backend/blocks/nvidia): Provide Nvidia by default (#9235)
We want to allow users to use Nvidia without their own keys

### Changes 🏗️

Added nvidia api key to credentials store.

### Checklist 📋

#### For code changes:
- [ ] I have clearly listed my changes in the PR description
- [ ] I have made a test plan
- [ ] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - [ ] ...

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:
- [x] `.env.example` is updated or already compatible with my changes

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>
2025-01-09 18:12:05 +00:00
Zamil Majdy
1670579a61 fix(block): Remove Python.format & Jinja templating format backward compatibility (#9229)
Python format uses `{Variable}` as the variable placeholder, while Jinja
uses `{{Variable}}` as its default.
Jinja is used as the main templating engine on the system, but the
Python format version is still maintained for backward compatibility.

However, the backward compatibility support can cause a side effect
while passing JSON string value into the block that uses it:
https://github.com/Significant-Gravitas/AutoGPT/issues/9194

### Changes 🏗️

* Use `{{Variable}}` place holder format and removed `{Variable}`
support in these blocks:
 - '363ae599-353e-4804-937e-b2ee3cef3da4', -- AgentOutputBlock
 - 'db7d8f02-2f44-4c55-ab7a-eae0941f0c30', -- FillTextTemplateBlock
 - '1f292d4a-41a4-4977-9684-7c8d560b9f91', -- AITextGeneratorBlock
- 'ed55ac19-356e-4243-a6cb-bc599e9b716f' --
AIStructuredResponseGeneratorBlock
* Add Jinja templating support on `AITextGeneratorBlock` &
`AIStructuredResponseGeneratorBlock`
* Migrated the existing database content to prevent breaking changes.

### Checklist 📋

#### For code changes:
- [ ] I have clearly listed my changes in the PR description
- [ ] I have made a test plan
- [ ] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - [ ] ...

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:
- [ ] `.env.example` is updated or already compatible with my changes
- [ ] `docker-compose.yml` is updated or already compatible with my
changes
- [ ] I have included a list of my configuration changes in the PR
description (under **Changes**)

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>
2025-01-09 16:29:16 +00:00
Bently
a1889e6212 docs(Ollama): Update Ollama docs (#9234)
The Ollama docs where very out of date and needed updating so I have
updated them and added some screenshots so its easier to follow.

I have also added a new Ollama model to the platform, "llama3.2" as that
is what i based the tutorial off and its name is easy to find in the
list of models

I also added a new folder in the "imgs" dir to store the Ollama related
photo just to keep things tidy
2025-01-09 15:19:37 +00:00
Abhimanyu Yadav
9c702516fd feat(platform): fix carousel on store page (#9230)
- resolves #8973 

Adding smooth scrolling and solving some weird interaction on carousal

### Changes

- Update `CarouselPrevious`, `CarouselPrevious` and add
`CarouselIndicator` in `carousel.tsx`
- Add `CarouselPrevious`, `CarouselPrevious` and `CarouselIndicator`
support in `FeaturedSection.tsx`

### Demo 


https://github.com/user-attachments/assets/ba9a22fa-ddf2-469f-ba8a-aee1a7fc5f78
2025-01-09 13:48:53 +00:00
Aarushi
32c908ae13 fix(backend): Add default credentials for Fal, Exa, E2B (#9233)
We want to provide certain providers by default on our platform. These
three were not added previously, so fixing that.

### Changes 🏗️

If api keys for Fal Exa or E2B exist in environment variables, load them
by default as credentials that are usable by our users.

### Checklist 📋

#### For code changes:
- [ ] I have clearly listed my changes in the PR description
- [ ] I have made a test plan
- [ ] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - [ ] ...

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:
- [x] `.env.example` is updated or already compatible with my changes

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>
2025-01-09 13:47:54 +00:00
Abhimanyu Yadav
b4a0100c22 feat(platform): Add Twitter integration (#8754)
- Resolves #8326  

Create a Twitter integration with some small frontend changes.

### Changes
1. Add Twitter OAuth 2.0 with PKCE support for authentication.
2. Add a way to multi-select from a list of enums by creating a
multi-select on the frontend.
3. Add blocks for Twitter integration.
4. `_types.py` for repetitive enums and input types.
5. `_builders.py` for creating parameters without repeating the same
logic.
6. `_serializer.py` to serialize the Tweepy enums into dictionaries so
they can travel easily from Pyro5.
7. `_mappers.py` to map the frontend values to the correct request
values.

> I have added a new multi-select feature because my list contains many
items, and selecting all of them makes the block cluttered. This new
block displays only the first two items and then show something like "2
more" . It works only for list of enums.


### Blocks

Block Name | What It Does | Error Reason | Manual Testing
-- | -- | -- | --
`TwitterBookmarkTweetBlock` | Bookmark a tweet on Twitter | No error | 
`TwitterGetBookmarkedTweetsBlock` | Get all your bookmarked tweets from
Twitter | No error | 
`TwitterRemoveBookmarkTweetBlock` | Remove a bookmark for a tweet on
Twitter | No error | 
`TwitterHideReplyBlock` | Hides a reply of one of your tweets | No error
| 
`TwitterUnhideReplyBlock` | Unhides a reply to a tweet | No error | 
`TwitterLikeTweetBlock` | Likes a tweet | No error | 
`TwitterGetLikingUsersBlock` | Gets information about users who liked
one of your tweets | No error | 
`TwitterGetLikedTweetsBlock` | Gets information about tweets liked by
you | No error | 
`TwitterUnlikeTweetBlock` | Unlikes a tweet that was previously liked |
No error | 
`TwitterPostTweetBlock` | Create a tweet on Twitter with the option to
include one additional element such as media, quote, or deep link. | No
error | 
`TwitterDeleteTweetBlock` | Deletes a tweet on Twitter using Twitter ID
| No error | 
`TwitterSearchRecentTweetsBlock` | Searches all public Tweets in Twitter
history | No error | 
`TwitterGetQuoteTweetsBlock` | Gets quote tweets for a specified tweet
ID | No error | 
`TwitterRetweetBlock` | Retweets a tweet on Twitter | No error | 
`TwitterRemoveRetweetBlock` | Removes a retweet on Twitter | No error |

`TwitterGetRetweetersBlock` | Gets information about who has retweeted a
tweet | No error | 
`TwitterGetUserMentionsBlock` | Returns Tweets where a single user is
mentioned, just put that user ID | No error | 
`TwitterGetHomeTimelineBlock` | Returns a collection of the most recent
Tweets and Retweets posted by you and users you follow | No error | 
`TwitterGetUserTweetsBlock` | Returns Tweets composed by a single user,
specified by the requested user ID | No error | 
`TwitterGetTweetBlock` | Returns information about a single Tweet
specified by the requested ID | No error | 
`TwitterGetTweetsBlock` | Returns information about multiple Tweets
specified by the requested IDs | No error | 
`TwitterUnblockUserBlock` | Unblock a specific user on Twitter | No
error | 
`TwitterGetBlockedUsersBlock` | Get a list of users who are blocked by
the authenticating user | No error | 
`TwitterBlockUserBlock` | Block a specific user on Twitter | No error |

`TwitterUnfollowUserBlock` | Allows a user to unfollow another user
specified by target user ID | No error | 
`TwitterFollowUserBlock` | Allows a user to follow another user
specified by target user ID | No error | 
`TwitterGetFollowersBlock` | Retrieves a list of followers for a
specified Twitter user ID | Need Enterprise level access | 
`TwitterGetFollowingBlock` | Retrieves a list of users that a specified
Twitter user ID is following | Need Enterprise level access | 
`TwitterUnmuteUserBlock` | Allows a user to unmute another user
specified by target user ID | No error | 
`TwitterGetMutedUsersBlock` | Returns a list of users who are muted by
the authenticating user | No error | 
`TwitterMuteUserBlock` | Allows a user to mute another user specified by
target user ID | No error | 
`TwitterGetUserBlock` | Gets information about a single Twitter user
specified by ID or username | No error | 
`TwitterGetUsersBlock` | Gets information about multiple Twitter users
specified by IDs or usernames | No error | 
`TwitterSearchSpacesBlock` | Returns live or scheduled Spaces matching
specified search terms [for a week only] | No error | 
`TwitterGetSpacesBlock` | Gets information about multiple Twitter Spaces
specified by Space IDs or creator user IDs | No error | 
`TwitterGetSpaceByIdBlock` | Gets information about a single Twitter
Space specified by Space ID | No error | 
`TwitterGetSpaceBuyersBlock` | Gets list of users who purchased a ticket
to the requested Space | I do not have a monetized account for this | 
`TwitterGetSpaceTweetsBlock` | Gets list of Tweets shared in the
requested Space | No error | 
`TwitterUnfollowListBlock` | Unfollows a Twitter list for the
authenticated user | No error | 
`TwitterFollowListBlock` | Follows a Twitter list for the authenticated
user | No error | 
`TwitterListGetFollowersBlock` | Gets followers of a specified Twitter
list | Enterprise level access | 
`TwitterGetFollowedListsBlock` | Gets lists followed by a specified
Twitter user | Enterprise level access | 
`TwitterGetListBlock` | Gets information about a Twitter List specified
by ID | No error | 
`TwitterGetOwnedListsBlock` | Gets all Lists owned by the specified user
| No error | 
`TwitterRemoveListMemberBlock` | Removes a member from a Twitter List
that the authenticated user owns | No error | 
`TwitterAddListMemberBlock` | Adds a member to a Twitter List that the
authenticated user owns | No error | 
`TwitterGetListMembersBlock` | Gets the members of a specified Twitter
List | No error | 
`TwitterGetListMembershipsBlock` | Gets all Lists that a specified user
is a member of | No error | 
`TwitterGetListTweetsBlock` | Gets tweets from a specified Twitter list
| No error | 
`TwitterDeleteListBlock` | Deletes a Twitter List owned by the
authenticated user | No error | 
`TwitterUpdateListBlock` | Updates a Twitter List owned by the
authenticated user | No error | 
`TwitterCreateListBlock` | Creates a Twitter List owned by the
authenticated user | No error | 
`TwitterUnpinListBlock` | Enables the authenticated user to unpin a
List. | No error | 
`TwitterPinListBlock` | Enables the authenticated user to pin a List. |
No error | 
`TwitterGetPinnedListsBlock` | Returns the Lists pinned by the
authenticated user. | No error | 
`TwitterGetDMEventsBlock` | Gets a list of Direct Message events for the
authenticated user | Need Enterprise level access | 
`TwitterSendDirectMessageBlock` | Sends a direct message to a Twitter
user | Need Enterprise level access | 
`TwitterCreateDMConversationBlock` | Creates a new group direct message
| Need Enterprise level access | 

### Need to add more stuff
1. A normal input to select date and time.
2. Some more enterprise-level blocks, especially webhook triggers.

Supported triggers 


Event Name | Description
-- | --
Posts (by user) | User creates a new post.
Post deletes (by user) | User deletes an existing post.
@mentions (of user) | User is mentioned in a post.
Replies (to or from user) | User replies to a post or receives a reply
from another user.
Retweets (by user or of user) | User retweets a post or someone retweets
the user's post.
Quote Tweets (by user or of user) | User quote tweets a post or someone
quote tweets the user's post.
Retweets of Quoted Tweets (by user or of user) | Retweets of quote
tweets by the user or of the user.
Likes (by user or of user) | User likes a post or someone likes the
user's post.
Follows (by user or of user) | User follows another user or another user
follows the user.
Unfollows (by user) | User unfollows another user.
Blocks (by user) | User blocks another user.
Unblocks (by user) | User unblocks a previously blocked user.
Mutes (by user) | User mutes another user.
Unmutes (by user) | User unmutes a previously muted user.
Direct Messages sent (by user) | User sends direct messages to other
users.
Direct Messages received (by user) | User receives direct messages from
other users.
Typing indicators (to user) | Indicators showing when someone is typing
a message to the user.
Read receipts (to user) | Indicators showing when the user has read a
message.
Subscription revokes (by user) | User revokes a subscription to a
service or content.

---------

Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co>
Co-authored-by: Nicholas Tindle <nicktindle@outlook.com>
2025-01-08 19:47:00 +00:00
25 changed files with 1170 additions and 989 deletions

View File

@@ -121,6 +121,18 @@ REPLICATE_API_KEY=
# Ideogram
IDEOGRAM_API_KEY=
# Fal
FAL_API_KEY=
# Exa
EXA_API_KEY=
# E2B
E2B_API_KEY=
# Nvidia
NVIDIA_API_KEY=
# Logging Configuration
LOG_LEVEL=INFO
ENABLE_CLOUD_LOGGING=false

View File

@@ -241,7 +241,7 @@ class AgentOutputBlock(Block):
advanced=True,
)
format: str = SchemaField(
description="The format string to be used to format the recorded_value.",
description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
default="",
advanced=True,
)

View File

@@ -13,12 +13,12 @@ from backend.util.request import requests
class ContentRetrievalSettings(BaseModel):
text: Optional[dict] = SchemaField(
text: dict = SchemaField(
description="Text content settings",
default={"maxCharacters": 1000, "includeHtmlTags": False},
advanced=True,
)
highlights: Optional[dict] = SchemaField(
highlights: dict = SchemaField(
description="Highlight settings",
default={
"numSentences": 3,
@@ -27,7 +27,7 @@ class ContentRetrievalSettings(BaseModel):
},
advanced=True,
)
summary: Optional[dict] = SchemaField(
summary: dict = SchemaField(
description="Summary settings",
default={"query": ""},
advanced=True,

View File

@@ -26,8 +26,10 @@ from backend.data.model import (
)
from backend.util import json
from backend.util.settings import BehaveAs, Settings
from backend.util.text import TextFormatter
logger = logging.getLogger(__name__)
fmt = TextFormatter()
LLMProviderName = Literal[
ProviderName.ANTHROPIC,
@@ -109,6 +111,7 @@ class LlmModel(str, Enum, metaclass=LlmModelMeta):
LLAMA3_1_70B = "llama-3.1-70b-versatile"
LLAMA3_1_8B = "llama-3.1-8b-instant"
# Ollama models
OLLAMA_LLAMA3_2 = "llama3.2"
OLLAMA_LLAMA3_8B = "llama3"
OLLAMA_LLAMA3_405B = "llama3.1:405b"
OLLAMA_DOLPHIN = "dolphin-mistral:latest"
@@ -163,6 +166,7 @@ MODEL_METADATA = {
# Limited to 16k during preview
LlmModel.LLAMA3_1_70B: ModelMetadata("groq", 131072),
LlmModel.LLAMA3_1_8B: ModelMetadata("groq", 131072),
LlmModel.OLLAMA_LLAMA3_2: ModelMetadata("ollama", 8192),
LlmModel.OLLAMA_LLAMA3_8B: ModelMetadata("ollama", 8192),
LlmModel.OLLAMA_LLAMA3_405B: ModelMetadata("ollama", 8192),
LlmModel.OLLAMA_DOLPHIN: ModelMetadata("ollama", 32768),
@@ -234,7 +238,9 @@ class AIStructuredResponseGeneratorBlock(Block):
description="Number of times to retry the LLM call if the response does not match the expected format.",
)
prompt_values: dict[str, str] = SchemaField(
advanced=False, default={}, description="Values used to fill in the prompt."
advanced=False,
default={},
description="Values used to fill in the prompt. The values can be used in the prompt by putting them in a double curly braces, e.g. {{variable_name}}.",
)
max_tokens: int | None = SchemaField(
advanced=True,
@@ -448,8 +454,8 @@ class AIStructuredResponseGeneratorBlock(Block):
values = input_data.prompt_values
if values:
input_data.prompt = input_data.prompt.format(**values)
input_data.sys_prompt = input_data.sys_prompt.format(**values)
input_data.prompt = fmt.format_string(input_data.prompt, values)
input_data.sys_prompt = fmt.format_string(input_data.sys_prompt, values)
if input_data.sys_prompt:
prompt.append({"role": "system", "content": input_data.sys_prompt})
@@ -576,7 +582,9 @@ class AITextGeneratorBlock(Block):
description="Number of times to retry the LLM call if the response does not match the expected format.",
)
prompt_values: dict[str, str] = SchemaField(
advanced=False, default={}, description="Values used to fill in the prompt."
advanced=False,
default={},
description="Values used to fill in the prompt. The values can be used in the prompt by putting them in a double curly braces, e.g. {{variable_name}}.",
)
ollama_host: str = SchemaField(
advanced=True,

View File

@@ -141,10 +141,10 @@ class ExtractTextInformationBlock(Block):
class FillTextTemplateBlock(Block):
class Input(BlockSchema):
values: dict[str, Any] = SchemaField(
description="Values (dict) to be used in format"
description="Values (dict) to be used in format. These values can be used by putting them in double curly braces in the format template. e.g. {{value_name}}.",
)
format: str = SchemaField(
description="Template to format the text using `values`"
description="Template to format the text using `values`. Use Jinja2 syntax."
)
class Output(BlockSchema):
@@ -160,7 +160,7 @@ class FillTextTemplateBlock(Block):
test_input=[
{
"values": {"name": "Alice", "hello": "Hello", "world": "World!"},
"format": "{hello}, {world} {{name}}",
"format": "{{hello}}, {{ world }} {{name}}",
},
{
"values": {"list": ["Hello", " World!"]},

View File

@@ -51,6 +51,7 @@ MODEL_COST: dict[LlmModel, int] = {
LlmModel.LLAMA3_1_405B: 1,
LlmModel.LLAMA3_1_70B: 1,
LlmModel.LLAMA3_1_8B: 1,
LlmModel.OLLAMA_LLAMA3_2: 1,
LlmModel.OLLAMA_LLAMA3_8B: 1,
LlmModel.OLLAMA_LLAMA3_405B: 1,
LlmModel.OLLAMA_DOLPHIN: 1,

View File

@@ -93,6 +93,34 @@ open_router_credentials = APIKeyCredentials(
title="Use Credits for Open Router",
expires_at=None,
)
fal_credentials = APIKeyCredentials(
id="6c0f5bd0-9008-4638-9d79-4b40b631803e",
provider="fal",
api_key=SecretStr(settings.secrets.fal_api_key),
title="Use Credits for FAL",
expires_at=None,
)
exa_credentials = APIKeyCredentials(
id="96153e04-9c6c-4486-895f-5bb683b1ecec",
provider="exa",
api_key=SecretStr(settings.secrets.exa_api_key),
title="Use Credits for Exa search",
expires_at=None,
)
e2b_credentials = APIKeyCredentials(
id="78d19fd7-4d59-4a16-8277-3ce310acf2b7",
provider="e2b",
api_key=SecretStr(settings.secrets.e2b_api_key),
title="Use Credits for E2B",
expires_at=None,
)
nvidia_credentials = APIKeyCredentials(
id="96b83908-2789-4dec-9968-18f0ece4ceb3",
provider="nvidia",
api_key=SecretStr(settings.secrets.nvidia_api_key),
title="Use Credits for Nvidia",
expires_at=None,
)
DEFAULT_CREDENTIALS = [
@@ -106,6 +134,10 @@ DEFAULT_CREDENTIALS = [
jina_credentials,
unreal_credentials,
open_router_credentials,
fal_credentials,
exa_credentials,
e2b_credentials,
nvidia_credentials,
]
@@ -157,6 +189,14 @@ class IntegrationCredentialsStore:
all_credentials.append(unreal_credentials)
if settings.secrets.open_router_api_key:
all_credentials.append(open_router_credentials)
if settings.secrets.fal_api_key:
all_credentials.append(fal_credentials)
if settings.secrets.exa_api_key:
all_credentials.append(exa_credentials)
if settings.secrets.e2b_api_key:
all_credentials.append(e2b_credentials)
if settings.secrets.nvidia_api_key:
all_credentials.append(nvidia_credentials)
return all_credentials
def get_creds_by_id(self, user_id: str, credentials_id: str) -> Credentials | None:

View File

@@ -38,7 +38,7 @@ def create_test_graph() -> graph.Graph:
graph.Node(
block_id=FillTextTemplateBlock().id,
input_default={
"format": "{a}, {b}{c}",
"format": "{{a}}, {{b}}{{c}}",
"values_#_c": "!!!",
},
),

View File

@@ -304,7 +304,10 @@ class Secrets(UpdateTrackingModel["Secrets"], BaseSettings):
jina_api_key: str = Field(default="", description="Jina API Key")
unreal_speech_api_key: str = Field(default="", description="Unreal Speech API Key")
fal_key: str = Field(default="", description="FAL API key")
fal_api_key: str = Field(default="", description="FAL API key")
exa_api_key: str = Field(default="", description="Exa API key")
e2b_api_key: str = Field(default="", description="E2B API key")
nvidia_api_key: str = Field(default="", description="Nvidia API key")
# Add more secret fields as needed

View File

@@ -57,7 +57,7 @@ async def wait_execution(
user_id: str,
graph_id: str,
graph_exec_id: str,
timeout: int = 20,
timeout: int = 30,
) -> Sequence[ExecutionResult]:
async def is_execution_completed():
status = await AgentServer().test_get_graph_run_status(graph_exec_id, user_id)

View File

@@ -1,5 +1,3 @@
import re
from jinja2 import BaseLoader
from jinja2.sandbox import SandboxedEnvironment
@@ -15,8 +13,5 @@ class TextFormatter:
self.env.globals.clear()
def format_string(self, template_str: str, values=None, **kwargs) -> str:
# For python.format compatibility: replace all {...} with {{..}}.
# But avoid replacing {{...}} to {{{...}}}.
template_str = re.sub(r"(?<!{){[ a-zA-Z0-9_]+}", r"{\g<0>}", template_str)
template = self.env.from_string(template_str)
return template.render(values or {}, **kwargs)

View File

@@ -0,0 +1,86 @@
/*
Warnings:
- You are about replace a single brace string input format for the following blocks:
- AgentOutputBlock
- FillTextTemplateBlock
- AITextGeneratorBlock
- AIStructuredResponseGeneratorBlock
with a double brace format.
- This migration can be slow for a large updated AgentNode tables.
*/
BEGIN;
SET LOCAL statement_timeout = '10min';
WITH to_update AS (
SELECT
"id",
"agentBlockId",
"constantInput"::jsonb AS j
FROM "AgentNode"
WHERE
"agentBlockId" IN (
'363ae599-353e-4804-937e-b2ee3cef3da4', -- AgentOutputBlock
'db7d8f02-2f44-4c55-ab7a-eae0941f0c30', -- FillTextTemplateBlock
'1f292d4a-41a4-4977-9684-7c8d560b9f91', -- AITextGeneratorBlock
'ed55ac19-356e-4243-a6cb-bc599e9b716f' -- AIStructuredResponseGeneratorBlock
)
AND (
"constantInput"::jsonb->>'format' ~ '(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})'
OR "constantInput"::jsonb->>'prompt' ~ '(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})'
OR "constantInput"::jsonb->>'sys_prompt' ~ '(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})'
)
),
updated_rows AS (
SELECT
"id",
"agentBlockId",
(
j
-- Update "format" if it has a single-brace placeholder
|| CASE WHEN j->>'format' ~ '(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})'
THEN jsonb_build_object(
'format',
regexp_replace(
j->>'format',
'(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})',
'{{\1}}',
'g'
)
)
ELSE '{}'::jsonb
END
-- Update "prompt" if it has a single-brace placeholder
|| CASE WHEN j->>'prompt' ~ '(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})'
THEN jsonb_build_object(
'prompt',
regexp_replace(
j->>'prompt',
'(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})',
'{{\1}}',
'g'
)
)
ELSE '{}'::jsonb
END
-- Update "sys_prompt" if it has a single-brace placeholder
|| CASE WHEN j->>'sys_prompt' ~ '(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})'
THEN jsonb_build_object(
'sys_prompt',
regexp_replace(
j->>'sys_prompt',
'(?<!\{)\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}(?!\})',
'{{\1}}',
'g'
)
)
ELSE '{}'::jsonb
END
)::text AS "newConstantInput"
FROM to_update
)
UPDATE "AgentNode" AS an
SET "constantInput" = ur."newConstantInput"
FROM updated_rows ur
WHERE an."id" = ur."id";
COMMIT;

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,7 @@ python-dotenv = "^1.0.1"
redis = "^5.2.0"
sentry-sdk = "2.19.2"
strenum = "^0.4.9"
supabase = "^2.10.0"
supabase = "2.11.0"
tenacity = "^9.0.0"
tweepy = "^4.14.0"
uvicorn = { extras = ["standard"], version = "^0.34.0" }

View File

@@ -102,7 +102,7 @@ async def assert_sample_graph_executions(
assert exec.graph_exec_id == graph_exec_id
assert exec.output_data == {"output": ["Hello, World!!!"]}
assert exec.input_data == {
"format": "{a}, {b}{c}",
"format": "{{a}}, {{b}}{{c}}",
"values": {"a": "Hello", "b": "World", "c": "!!!"},
"values_#_a": "Hello",
"values_#_b": "World",

View File

@@ -6,9 +6,11 @@ import {
Carousel,
CarouselContent,
CarouselItem,
CarouselPrevious,
CarouselNext,
CarouselIndicator,
} from "@/components/ui/carousel";
import { useCallback, useState } from "react";
import { IconLeftArrow, IconRightArrow } from "@/components/ui/icons";
import { useRouter } from "next/navigation";
const BACKGROUND_COLORS = [
@@ -63,27 +65,24 @@ export const FeaturedSection: React.FC<FeaturedSectionProps> = ({
return (
<div className="flex w-full flex-col items-center justify-center">
<div className="w-full">
<h2 className="font-poppins mb-8 text-2xl font-semibold leading-7 text-neutral-800 dark:text-neutral-200">
<div className="w-[99vw]">
<h2 className="font-poppins mx-auto mb-8 max-w-[1360px] px-4 text-2xl font-semibold leading-7 text-neutral-800 dark:text-neutral-200">
Featured agents
</h2>
<div>
<div className="w-[99vw] pb-[60px]">
<Carousel
className="mx-auto pb-10"
opts={{
loop: true,
startIndex: currentSlide,
duration: 500,
align: "start",
align: "center",
containScroll: "trimSnaps",
}}
className="w-full overflow-x-hidden"
>
<CarouselContent className="transition-transform duration-500">
<CarouselContent className="ml-[calc(50vw-690px)]">
{featuredAgents.map((agent, index) => (
<CarouselItem
key={index}
className="max-w-[460px] flex-[0_0_auto] pr-8"
className="max-w-[460px] flex-[0_0_auto]"
>
<FeaturedStoreCard
agentName={agent.agent_name}
@@ -99,37 +98,13 @@ export const FeaturedSection: React.FC<FeaturedSectionProps> = ({
</CarouselItem>
))}
</CarouselContent>
<div className="relative mx-auto w-full max-w-[1360px] pl-4">
<CarouselIndicator />
<CarouselPrevious afterClick={handlePrevSlide} />
<CarouselNext afterClick={handleNextSlide} />
</div>
</Carousel>
</div>
<div className="mt-8 flex w-full items-center justify-between">
<div className="flex h-3 items-center gap-2">
{featuredAgents.map((_, index) => (
<div
key={index}
className={`${
currentSlide === index
? "h-3 w-[52px] rounded-[39px] bg-neutral-800 transition-all duration-500 dark:bg-neutral-200"
: "h-3 w-3 rounded-full bg-neutral-300 transition-all duration-500 dark:bg-neutral-600"
}`}
/>
))}
</div>
<div className="mb-[60px] flex items-center gap-3">
<button
onClick={handlePrevSlide}
className="mb:h-12 mb:w-12 flex h-10 w-10 items-center justify-center rounded-full border border-neutral-400 bg-white dark:border-neutral-600 dark:bg-neutral-800"
>
<IconLeftArrow className="h-8 w-8 text-neutral-800 dark:text-neutral-200" />
</button>
<button
onClick={handleNextSlide}
className="mb:h-12 mb:w-12 flex h-10 w-10 items-center justify-center rounded-full border border-neutral-900 bg-white dark:border-neutral-600 dark:bg-neutral-800"
>
<IconRightArrow className="h-8 w-8 text-neutral-800 dark:text-neutral-200" />
</button>
</div>
</div>
</div>
</div>
);

View File

@@ -1,10 +1,11 @@
// This file has been updated for the Store's "Featured Agent Section". If you want to add Carousel, keep these components in mind: CarouselIndicator, CarouselPrevious, and CarouselNext.
"use client";
import * as React from "react";
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react";
import { ArrowLeft, ArrowRight } from "lucide-react";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
@@ -196,67 +197,137 @@ CarouselItem.displayName = "CarouselItem";
const CarouselPrevious = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
React.ComponentProps<typeof Button> & { afterClick?: () => void }
>(
(
{ className, afterClick, variant = "outline", size = "icon", ...props },
ref,
) => {
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-8 w-8 rounded-full",
orientation === "horizontal"
? "-left-12 top-1/2 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
className,
)}
disabled={!canScrollPrev}
onClick={scrollPrev}
{...props}
>
<ArrowLeft className="h-4 w-4" />
<span className="sr-only">Previous slide</span>
</Button>
);
});
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-[52px] w-[52px] rounded-full",
orientation === "horizontal"
? "-bottom-20 right-24 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
className,
)}
disabled={!canScrollPrev}
onClick={() => {
scrollPrev();
if (afterClick) {
afterClick();
}
}}
{...props}
>
<ChevronLeft className="h-8 w-8" strokeWidth={1.25} />
<span className="sr-only">Previous slide</span>
</Button>
);
},
);
CarouselPrevious.displayName = "CarouselPrevious";
const CarouselNext = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollNext, canScrollNext } = useCarousel();
React.ComponentProps<typeof Button> & { afterClick?: () => void }
>(
(
{ className, afterClick, variant = "outline", size = "icon", ...props },
ref,
) => {
const { orientation, scrollNext, canScrollNext } = useCarousel();
const handleClick = () => {
scrollNext();
if (afterClick) {
afterClick();
}
};
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-[52px] w-[52px] rounded-full",
orientation === "horizontal"
? "-bottom-20 right-4 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
className,
)}
disabled={!canScrollNext}
onClick={handleClick}
{...props}
>
<ChevronRight className="h-8 w-8" strokeWidth={1.25} />
<span className="sr-only">Next slide</span>
</Button>
);
},
);
CarouselNext.displayName = "CarouselNext";
const CarouselIndicator = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const { api } = useCarousel();
const [selectedIndex, setSelectedIndex] = React.useState(0);
const [scrollSnaps, setScrollSnaps] = React.useState<number[]>([]);
const scrollTo = React.useCallback(
(index: number) => {
api?.scrollTo(index);
},
[api],
);
React.useEffect(() => {
if (!api) return;
setScrollSnaps(api.scrollSnapList());
api.on("select", () => {
setSelectedIndex(api.selectedScrollSnap());
});
}, [api]);
return (
<Button
<div
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-8 w-8 rounded-full",
orientation === "horizontal"
? "-right-12 top-1/2 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
className,
)}
disabled={!canScrollNext}
onClick={scrollNext}
className={cn("relative top-10 flex h-3 items-center gap-2", className)}
{...props}
>
<ArrowRight className="h-4 w-4" />
<span className="sr-only">Next slide</span>
</Button>
{scrollSnaps.map((_, index) => (
<div
key={index}
onClick={() => scrollTo(index)}
className={cn(
selectedIndex === index
? "h-3 w-[52px] rounded-[39px] bg-neutral-800 transition-all duration-500 dark:bg-neutral-200"
: "h-3 w-3 rounded-full bg-neutral-300 transition-all duration-500 dark:bg-neutral-600",
"cursor-pointer",
)}
/>
))}
</div>
);
});
CarouselNext.displayName = "CarouselNext";
CarouselIndicator.displayName = "CarouselIndicator";
export {
type CarouselApi,
Carousel,
CarouselContent,
CarouselItem,
CarouselIndicator,
CarouselPrevious,
CarouselNext,
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@@ -1,37 +1,78 @@
# Running Ollama with AutoGPT
Follow these steps to set up and run Ollama and your AutoGPT project:
> **Important**: Ollama integration is only available when self-hosting the AutoGPT platform. It cannot be used with the cloud-hosted version.
1. **Run Ollama**
- Open a terminal
- Execute the following command:
```
ollama run llama3
```
- Leave this terminal running
Follow these steps to set up and run Ollama with the AutoGPT platform.
2. **Run the Backend**
- Open a new terminal
- Navigate to the backend directory in the AutoGPT project:
```
cd autogpt_platform/backend/
```
- Start the backend using Poetry:
```
poetry run app
```
## Prerequisites
3. **Run the Frontend**
- Open another terminal
- Navigate to the frontend directory in the AutoGPT project:
```
cd autogpt_platform/frontend/
```
- Start the frontend development server:
```
npm run dev
```
1. Make sure you have gone through and completed the [AutoGPT Setup](/platform/getting-started) steps, if not please do so before continuing with this guide.
2. Before starting, ensure you have [Ollama installed](https://ollama.com/download) on your machine.
4. **Choose the Ollama Model**
- Add LLMBlock in the UI
- Choose the last option in the model selection dropdown
## Setup Steps
### 1. Launch Ollama
Open a new terminal and execute:
```bash
ollama run llama3.2
```
> **Note**: This will download the [llama3.2](https://ollama.com/library/llama3.2) model and start the service. Keep this terminal running in the background.
### 2. Start the Backend
Open a new terminal and navigate to the autogpt_platform directory:
```bash
cd autogpt_platform
docker compose up -d --build
```
### 3. Start the Frontend
Open a new terminal and navigate to the frontend directory:
```bash
cd autogpt_platform/frontend
npm run dev
```
Then visit [http://localhost:3000](http://localhost:3000) to see the frontend running, after registering an account/logging in, navigate to the build page at [http://localhost:3000/build](http://localhost:3000/build)
### 4. Using Ollama with AutoGPT
Now that both Ollama and the AutoGPT platform are running we can move onto using Ollama with AutoGPT:
1. Add an AI Text Generator block to your workspace (it can work with any AI LLM block but for this example will be using the AI Text Generator block):
![Add AI Text Generator Block](../imgs/ollama/Select-AI-block.png)
2. In the "LLM Model" dropdown, select "llama3.2" (This is the model we downloaded earlier)
![Select Ollama Model](../imgs/ollama/Ollama-Select-Llama32.png)
3. You will see it ask for "Ollama Credentials", simply press "Enter API key"
![Ollama Credentials](../imgs/ollama/Ollama-Enter-API-key.png)
And you will see "Add new API key for Ollama", In the API key field you can enter anything you want as Ollama does not require an API key, I usually just enter a space, for the Name call it "Ollama" then press "Save & use this API key"
![Ollama Credentials](../imgs/ollama/Ollama-Credentials.png)
4. After that you will now see the block again, add your prompts then save and then run the graph:
![Add Prompt](../imgs/ollama/Ollama-Add-Prompts.png)
That's it! You've successfully setup the AutoGPT platform and made a LLM call to Ollama.
![Ollama Output](../imgs/ollama/Ollama-Output.png)
### Using Ollama on a Remote Server with AutoGPT
For running Ollama on a remote server, simply make sure the Ollama server is running and is accessible from other devices on your network/remotely through the port 11434, then you can use the same steps above but you need to add the Ollama servers IP address to the "Ollama Host" field in the block settings like so:
![Ollama Remote Host](../imgs/ollama/Ollama-Remote-Host.png)
## Troubleshooting
If you encounter any issues, verify that:
- Ollama is properly installed and running
- All terminals remain open during operation
- Docker is running before starting the backend
For common errors:
1. **Connection Refused**: Make sure Ollama is running and the host address is correct (also make sure the port is correct, its default is 11434)
2. **Model Not Found**: Try running `ollama pull llama3.2` manually first
3. **Docker Issues**: Ensure Docker daemon is running with `docker ps`