feat(library, executor): Make "Run Again" work with credentials (#10821)

- Resolves [OPEN-2549: Make "Run again" work with credentials in
`AgentRunDetailsView`](https://linear.app/autogpt/issue/OPEN-2549/make-run-again-work-with-credentials-in-agentrundetailsview)
- Resolves #10237

### Changes 🏗️

- feat(frontend/library): Make "Run Again" button work for runs with
credentials
- feat(backend/executor): Store passed-in credentials on
`GraphExecution`

### 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:
  - Go to `/library/agents/[id]` for an agent with credentials inputs
  - Run the agent manually
    - [x] -> runs successfully
- [x] -> "Run again" shows among the action buttons on the newly created
run
  - Click "Run again"
    - [x] -> runs successfully
This commit is contained in:
Reinier van der Leer
2025-09-02 19:34:56 +01:00
committed by GitHub
parent f669db4a10
commit e16e69ca55
14 changed files with 403 additions and 105 deletions

View File

@@ -1,5 +1,4 @@
"use client";
import { isEmpty } from "lodash";
import moment from "moment";
import React, { useCallback, useMemo } from "react";
@@ -92,7 +91,7 @@ export function AgentRunDetailsView({
}
>
| undefined = useMemo(() => {
if (!("inputs" in run)) return undefined;
if (!run.inputs) return undefined;
// TODO: show (link to) preset - https://github.com/Significant-Gravitas/AutoGPT/issues/9168
// Add type info from agent input schema
@@ -110,14 +109,16 @@ export function AgentRunDetailsView({
const runAgain = useCallback(
() =>
agentRunInputs &&
run.inputs &&
graph.credentials_input_schema.required.every(
(k) => k in (run.credential_inputs ?? {}),
) &&
api
.executeGraph(
graph.id,
graph.version,
Object.fromEntries(
Object.entries(agentRunInputs).map(([k, v]) => [k, v.value]),
),
run.inputs,
run.credential_inputs ?? undefined,
)
.then(({ graph_exec_id }) => onRun(graph_exec_id))
.catch(toastOnFail("execute agent")),
@@ -177,7 +178,9 @@ export function AgentRunDetailsView({
: []),
...(["success", "failed", "stopped"].includes(runStatus) &&
!graph.has_external_trigger &&
isEmpty(graph.credentials_input_schema.required) // TODO: enable re-run with credentials - https://linear.app/autogpt/issue/SECRT-1243
graph.credentials_input_schema.required.every(
(k) => k in (run.credential_inputs ?? {}),
)
? [
{
label: (

View File

@@ -5199,6 +5199,36 @@
"user_id": { "type": "string", "title": "User Id" },
"graph_id": { "type": "string", "title": "Graph Id" },
"graph_version": { "type": "integer", "title": "Graph Version" },
"inputs": {
"additionalProperties": true,
"type": "object",
"title": "Inputs"
},
"credential_inputs": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/CredentialsMetaInput"
},
"type": "object"
},
{ "type": "null" }
],
"title": "Credential Inputs"
},
"nodes_input_masks": {
"anyOf": [
{
"additionalProperties": {
"additionalProperties": true,
"type": "object"
},
"type": "object"
},
{ "type": "null" }
],
"title": "Nodes Input Masks"
},
"preset_id": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Preset Id"
@@ -5220,11 +5250,6 @@
{ "type": "null" }
]
},
"inputs": {
"additionalProperties": true,
"type": "object",
"title": "Inputs"
},
"outputs": {
"additionalProperties": { "items": {}, "type": "array" },
"type": "object",
@@ -5237,11 +5262,14 @@
"user_id",
"graph_id",
"graph_version",
"inputs",
"credential_inputs",
"nodes_input_masks",
"preset_id",
"status",
"started_at",
"ended_at",
"stats",
"inputs",
"outputs"
],
"title": "GraphExecution"
@@ -5287,6 +5315,38 @@
"user_id": { "type": "string", "title": "User Id" },
"graph_id": { "type": "string", "title": "Graph Id" },
"graph_version": { "type": "integer", "title": "Graph Version" },
"inputs": {
"anyOf": [
{ "additionalProperties": true, "type": "object" },
{ "type": "null" }
],
"title": "Inputs"
},
"credential_inputs": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/CredentialsMetaInput"
},
"type": "object"
},
{ "type": "null" }
],
"title": "Credential Inputs"
},
"nodes_input_masks": {
"anyOf": [
{
"additionalProperties": {
"additionalProperties": true,
"type": "object"
},
"type": "object"
},
{ "type": "null" }
],
"title": "Nodes Input Masks"
},
"preset_id": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Preset Id"
@@ -5315,6 +5375,10 @@
"user_id",
"graph_id",
"graph_version",
"inputs",
"credential_inputs",
"nodes_input_masks",
"preset_id",
"status",
"started_at",
"ended_at",
@@ -5328,6 +5392,36 @@
"user_id": { "type": "string", "title": "User Id" },
"graph_id": { "type": "string", "title": "Graph Id" },
"graph_version": { "type": "integer", "title": "Graph Version" },
"inputs": {
"additionalProperties": true,
"type": "object",
"title": "Inputs"
},
"credential_inputs": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/CredentialsMetaInput"
},
"type": "object"
},
{ "type": "null" }
],
"title": "Credential Inputs"
},
"nodes_input_masks": {
"anyOf": [
{
"additionalProperties": {
"additionalProperties": true,
"type": "object"
},
"type": "object"
},
{ "type": "null" }
],
"title": "Nodes Input Masks"
},
"preset_id": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Preset Id"
@@ -5349,11 +5443,6 @@
{ "type": "null" }
]
},
"inputs": {
"additionalProperties": true,
"type": "object",
"title": "Inputs"
},
"outputs": {
"additionalProperties": { "items": {}, "type": "array" },
"type": "object",
@@ -5371,11 +5460,14 @@
"user_id",
"graph_id",
"graph_version",
"inputs",
"credential_inputs",
"nodes_input_masks",
"preset_id",
"status",
"started_at",
"ended_at",
"stats",
"inputs",
"outputs",
"node_executions"
],

View File

@@ -250,6 +250,9 @@ export type GraphExecutionMeta = {
user_id: UserID;
graph_id: GraphID;
graph_version: number;
inputs: Record<string, any> | null;
credential_inputs: Record<string, CredentialsMetaInput> | null;
nodes_input_masks: Record<string, Record<string, any>> | null;
preset_id: LibraryAgentPresetID | null;
status:
| "QUEUED"
@@ -276,7 +279,7 @@ export type GraphExecutionMeta = {
export type GraphExecutionID = Brand<string, "GraphExecutionID">;
/* Mirror of backend/data/execution.py:GraphExecution */
export type GraphExecution = GraphExecutionMeta & {
export type GraphExecution = Omit<GraphExecutionMeta, "inputs"> & {
inputs: Record<string, any>;
outputs: Record<string, Array<any>>;
node_executions?: NodeExecutionResult[];
@@ -534,7 +537,7 @@ export type CredentialsDeleteNeedConfirmationResponse = {
export type CredentialsMetaInput = {
id: string;
type: CredentialsType;
title?: string;
title?: string | null;
provider: string;
};