feat(cursor): add list artifacts and download artifact tools (#3970)

* feat(cursor): add list artifacts and download artifact tools

* fix(cursor): resolve build errors in cursor block and download artifact types

- Remove invalid wandConfig with unsupported generationType 'json-array' from promptImages subBlock
- Remove invalid 'optional' property from summary output definition
- Split DownloadArtifactResponse into v1 (content/metadata) and v2 (file) response types

* fix(cursor): address PR review feedback

- Remove redundant Array.isArray guards in list_artifacts.ts
- Pass through actual HTTP status on presigned URL download failure instead of hardcoded 400
This commit is contained in:
Waleed
2026-04-04 19:59:37 -07:00
committed by GitHub
parent f9a7c4538e
commit adfcb67dc2
15 changed files with 540 additions and 9 deletions

View File

@@ -45,6 +45,7 @@ List all cloud agents for the authenticated user with optional pagination. Retur
| `apiKey` | string | Yes | Cursor API key |
| `limit` | number | No | Number of agents to return \(default: 20, max: 100\) |
| `cursor` | string | No | Pagination cursor from previous response |
| `prUrl` | string | No | Filter agents by pull request URL |
#### Output
@@ -173,4 +174,41 @@ Permanently delete a cloud agent. Returns API-aligned fields only.
| --------- | ---- | ----------- |
| `id` | string | Agent ID |
### `cursor_list_artifacts`
List generated artifact files for a cloud agent. Returns API-aligned fields only.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Cursor API key |
| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `artifacts` | array | List of artifact files |
| ↳ `path` | string | Artifact file path |
| ↳ `size` | number | File size in bytes |
### `cursor_download_artifact`
Download a generated artifact file from a cloud agent. Returns the file for execution storage.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Cursor API key |
| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) |
| `path` | string | Yes | Absolute path of the artifact to download \(e.g., /src/index.ts\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `file` | file | Downloaded artifact file stored in execution files |

View File

@@ -2327,9 +2327,17 @@
{
"name": "Delete Agent",
"description": "Permanently delete a cloud agent. This action cannot be undone."
},
{
"name": "List Artifacts",
"description": "List generated artifact files for a cloud agent."
},
{
"name": "Download Artifact",
"description": "Download a generated artifact file from a cloud agent."
}
],
"operationCount": 7,
"operationCount": 9,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",

View File

@@ -0,0 +1,146 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
secureFetchWithPinnedIP,
validateUrlWithDNS,
} from '@/lib/core/security/input-validation.server'
import { generateRequestId } from '@/lib/core/utils/request'
export const dynamic = 'force-dynamic'
const logger = createLogger('CursorDownloadArtifactAPI')
const DownloadArtifactSchema = z.object({
apiKey: z.string().min(1, 'API key is required'),
agentId: z.string().min(1, 'Agent ID is required'),
path: z.string().min(1, 'Artifact path is required'),
})
export async function POST(request: NextRequest) {
const requestId = generateRequestId()
try {
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.warn(
`[${requestId}] Unauthorized Cursor download artifact attempt: ${authResult.error}`
)
return NextResponse.json(
{ success: false, error: authResult.error || 'Authentication required' },
{ status: 401 }
)
}
logger.info(
`[${requestId}] Authenticated Cursor download artifact request via ${authResult.authType}`,
{
userId: authResult.userId,
}
)
const body = await request.json()
const { apiKey, agentId, path } = DownloadArtifactSchema.parse(body)
const authHeader = `Basic ${Buffer.from(`${apiKey}:`).toString('base64')}`
logger.info(`[${requestId}] Requesting presigned URL for artifact`, { agentId, path })
const artifactResponse = await fetch(
`https://api.cursor.com/v0/agents/${encodeURIComponent(agentId)}/artifacts/download?path=${encodeURIComponent(path)}`,
{
method: 'GET',
headers: {
Authorization: authHeader,
},
}
)
if (!artifactResponse.ok) {
const errorText = await artifactResponse.text().catch(() => '')
logger.error(`[${requestId}] Failed to get artifact presigned URL`, {
status: artifactResponse.status,
error: errorText,
})
return NextResponse.json(
{
success: false,
error: errorText || `Failed to get artifact URL (${artifactResponse.status})`,
},
{ status: artifactResponse.status }
)
}
const artifactData = await artifactResponse.json()
const downloadUrl = artifactData.url || artifactData.downloadUrl || artifactData.presignedUrl
if (!downloadUrl) {
logger.error(`[${requestId}] No download URL in artifact response`, { artifactData })
return NextResponse.json(
{ success: false, error: 'No download URL returned for artifact' },
{ status: 400 }
)
}
const urlValidation = await validateUrlWithDNS(downloadUrl, 'downloadUrl')
if (!urlValidation.isValid) {
return NextResponse.json({ success: false, error: urlValidation.error }, { status: 400 })
}
logger.info(`[${requestId}] Downloading artifact from presigned URL`, { agentId, path })
const downloadResponse = await secureFetchWithPinnedIP(
downloadUrl,
urlValidation.resolvedIP!,
{}
)
if (!downloadResponse.ok) {
logger.error(`[${requestId}] Failed to download artifact content`, {
status: downloadResponse.status,
statusText: downloadResponse.statusText,
})
return NextResponse.json(
{
success: false,
error: `Failed to download artifact content (${downloadResponse.status}: ${downloadResponse.statusText})`,
},
{ status: downloadResponse.status }
)
}
const contentType = downloadResponse.headers.get('content-type') || 'application/octet-stream'
const arrayBuffer = await downloadResponse.arrayBuffer()
const fileBuffer = Buffer.from(arrayBuffer)
const fileName = path.split('/').pop() || 'artifact'
logger.info(`[${requestId}] Artifact downloaded successfully`, {
agentId,
path,
name: fileName,
size: fileBuffer.length,
mimeType: contentType,
})
return NextResponse.json({
success: true,
output: {
file: {
name: fileName,
mimeType: contentType,
data: fileBuffer.toString('base64'),
size: fileBuffer.length,
},
},
})
} catch (error) {
logger.error(`[${requestId}] Error downloading Cursor artifact:`, error)
return NextResponse.json(
{ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred' },
{ status: 500 }
)
}
}

View File

@@ -31,6 +31,8 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
{ label: 'List Agents', id: 'cursor_list_agents' },
{ label: 'Stop Agent', id: 'cursor_stop_agent' },
{ label: 'Delete Agent', id: 'cursor_delete_agent' },
{ label: 'List Artifacts', id: 'cursor_list_artifacts' },
{ label: 'Download Artifact', id: 'cursor_download_artifact' },
],
value: () => 'cursor_launch_agent',
},
@@ -48,6 +50,7 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
type: 'short-input',
placeholder: 'main (optional)',
condition: { field: 'operation', value: 'cursor_launch_agent' },
mode: 'advanced',
},
{
id: 'promptText',
@@ -57,12 +60,21 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
condition: { field: 'operation', value: 'cursor_launch_agent' },
required: true,
},
{
id: 'promptImages',
title: 'Prompt Images',
type: 'long-input',
placeholder: '[{"data": "base64...", "dimension": {"width": 1024, "height": 768}}]',
condition: { field: 'operation', value: ['cursor_launch_agent', 'cursor_add_followup'] },
mode: 'advanced',
},
{
id: 'model',
title: 'Model',
type: 'short-input',
placeholder: 'Auto-selection by default',
condition: { field: 'operation', value: 'cursor_launch_agent' },
mode: 'advanced',
},
{
id: 'branchName',
@@ -70,6 +82,7 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
type: 'short-input',
placeholder: 'Custom branch name (optional)',
condition: { field: 'operation', value: 'cursor_launch_agent' },
mode: 'advanced',
},
{
id: 'autoCreatePr',
@@ -82,12 +95,14 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
title: 'Open as Cursor GitHub App',
type: 'switch',
condition: { field: 'operation', value: 'cursor_launch_agent' },
mode: 'advanced',
},
{
id: 'skipReviewerRequest',
title: 'Skip Reviewer Request',
type: 'switch',
condition: { field: 'operation', value: 'cursor_launch_agent' },
mode: 'advanced',
},
{
id: 'agentId',
@@ -102,10 +117,20 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
'cursor_add_followup',
'cursor_stop_agent',
'cursor_delete_agent',
'cursor_list_artifacts',
'cursor_download_artifact',
],
},
required: true,
},
{
id: 'path',
title: 'Artifact Path',
type: 'short-input',
placeholder: '/opt/cursor/artifacts/screenshot.png',
condition: { field: 'operation', value: 'cursor_download_artifact' },
required: true,
},
{
id: 'followupPromptText',
title: 'Follow-up Prompt',
@@ -114,12 +139,21 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
condition: { field: 'operation', value: 'cursor_add_followup' },
required: true,
},
{
id: 'prUrl',
title: 'PR URL Filter',
type: 'short-input',
placeholder: 'Filter by pull request URL (optional)',
condition: { field: 'operation', value: 'cursor_list_agents' },
mode: 'advanced',
},
{
id: 'limit',
title: 'Limit',
type: 'short-input',
placeholder: '20 (default, max 100)',
condition: { field: 'operation', value: 'cursor_list_agents' },
mode: 'advanced',
},
{
id: 'cursor',
@@ -127,6 +161,7 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
type: 'short-input',
placeholder: 'Cursor from previous response',
condition: { field: 'operation', value: 'cursor_list_agents' },
mode: 'advanced',
},
{
id: 'apiKey',
@@ -146,6 +181,8 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
'cursor_add_followup',
'cursor_stop_agent',
'cursor_delete_agent',
'cursor_list_artifacts',
'cursor_download_artifact',
],
config: {
tool: (params) => params.operation || 'cursor_launch_agent',
@@ -157,15 +194,20 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
ref: { type: 'string', description: 'Branch, tag, or commit reference' },
promptText: { type: 'string', description: 'Instruction text for the agent' },
followupPromptText: { type: 'string', description: 'Follow-up instruction text for the agent' },
promptImages: { type: 'string', description: 'JSON array of image objects' },
promptImages: {
type: 'string',
description: 'JSON array of image objects with base64 data and dimensions',
},
model: { type: 'string', description: 'Model to use (empty for auto-selection)' },
branchName: { type: 'string', description: 'Custom branch name' },
autoCreatePr: { type: 'boolean', description: 'Auto-create PR when done' },
openAsCursorGithubApp: { type: 'boolean', description: 'Open PR as Cursor GitHub App' },
skipReviewerRequest: { type: 'boolean', description: 'Skip reviewer request' },
agentId: { type: 'string', description: 'Agent identifier' },
prUrl: { type: 'string', description: 'Filter agents by pull request URL' },
limit: { type: 'number', description: 'Number of results to return' },
cursor: { type: 'string', description: 'Pagination cursor' },
path: { type: 'string', description: 'Absolute path of the artifact to download' },
apiKey: { type: 'string', description: 'Cursor API key' },
},
outputs: {
@@ -192,6 +234,8 @@ export const CursorV2Block: BlockConfig<CursorResponse> = {
'cursor_add_followup_v2',
'cursor_stop_agent_v2',
'cursor_delete_agent_v2',
'cursor_list_artifacts_v2',
'cursor_download_artifact_v2',
],
config: {
tool: createVersionedToolSelector({
@@ -213,5 +257,7 @@ export const CursorV2Block: BlockConfig<CursorResponse> = {
agents: { type: 'json', description: 'Array of agent objects (list operation)' },
nextCursor: { type: 'string', description: 'Pagination cursor (list operation)' },
messages: { type: 'json', description: 'Conversation messages (get conversation operation)' },
artifacts: { type: 'json', description: 'List of artifact files (list artifacts operation)' },
file: { type: 'file', description: 'Downloaded artifact file (download artifact operation)' },
},
}

View File

@@ -30,7 +30,7 @@ const addFollowupBase = {
},
request: {
url: (params: AddFollowupParams) =>
`https://api.cursor.com/v0/agents/${params.agentId}/followup`,
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/followup`,
method: 'POST',
headers: (params: AddFollowupParams) => ({
'Content-Type': 'application/json',

View File

@@ -17,7 +17,7 @@ const deleteAgentBase = {
},
},
request: {
url: (params: DeleteAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId}`,
url: (params: DeleteAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId.trim()}`,
method: 'DELETE',
headers: (params: DeleteAgentParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,

View File

@@ -0,0 +1,113 @@
import type {
DownloadArtifactParams,
DownloadArtifactResponse,
DownloadArtifactV2Response,
} from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const downloadArtifactBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Absolute path of the artifact to download (e.g., /src/index.ts)',
},
},
request: {
url: '/api/tools/cursor/download-artifact',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params: DownloadArtifactParams) => ({
apiKey: params.apiKey,
agentId: params.agentId?.trim(),
path: params.path?.trim(),
}),
},
} satisfies Pick<ToolConfig<DownloadArtifactParams, any>, 'params' | 'request'>
export const downloadArtifactTool: ToolConfig<DownloadArtifactParams, DownloadArtifactResponse> = {
id: 'cursor_download_artifact',
name: 'Cursor Download Artifact',
description: 'Download a generated artifact file from a cloud agent.',
version: '1.0.0',
...downloadArtifactBase,
transformResponse: async (response) => {
const data = await response.json()
if (!data.success) {
throw new Error(data.error || 'Failed to download artifact')
}
return {
success: true,
output: {
content: `Downloaded artifact: ${data.output.file.name}`,
metadata: data.output.file,
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable download result' },
metadata: {
type: 'object',
description: 'Downloaded file metadata',
properties: {
name: { type: 'string', description: 'File name' },
mimeType: { type: 'string', description: 'MIME type' },
size: { type: 'number', description: 'File size in bytes' },
},
},
},
}
export const downloadArtifactV2Tool: ToolConfig<
DownloadArtifactParams,
DownloadArtifactV2Response
> = {
...downloadArtifactBase,
id: 'cursor_download_artifact_v2',
name: 'Cursor Download Artifact',
description:
'Download a generated artifact file from a cloud agent. Returns the file for execution storage.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
if (!data.success) {
throw new Error(data.error || 'Failed to download artifact')
}
return {
success: true,
output: {
file: data.output.file,
},
}
},
outputs: {
file: {
type: 'file',
description: 'Downloaded artifact file stored in execution files',
},
},
}

View File

@@ -17,7 +17,7 @@ const getAgentBase = {
},
},
request: {
url: (params: GetAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId}`,
url: (params: GetAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId.trim()}`,
method: 'GET',
headers: (params: GetAgentParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,

View File

@@ -18,7 +18,7 @@ const getConversationBase = {
},
request: {
url: (params: GetConversationParams) =>
`https://api.cursor.com/v0/agents/${params.agentId}/conversation`,
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/conversation`,
method: 'GET',
headers: (params: GetConversationParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,

View File

@@ -1,9 +1,11 @@
import { addFollowupTool, addFollowupV2Tool } from '@/tools/cursor/add_followup'
import { deleteAgentTool, deleteAgentV2Tool } from '@/tools/cursor/delete_agent'
import { downloadArtifactTool, downloadArtifactV2Tool } from '@/tools/cursor/download_artifact'
import { getAgentTool, getAgentV2Tool } from '@/tools/cursor/get_agent'
import { getConversationTool, getConversationV2Tool } from '@/tools/cursor/get_conversation'
import { launchAgentTool, launchAgentV2Tool } from '@/tools/cursor/launch_agent'
import { listAgentsTool, listAgentsV2Tool } from '@/tools/cursor/list_agents'
import { listArtifactsTool, listArtifactsV2Tool } from '@/tools/cursor/list_artifacts'
import { stopAgentTool, stopAgentV2Tool } from '@/tools/cursor/stop_agent'
export const cursorListAgentsTool = listAgentsTool
@@ -13,6 +15,8 @@ export const cursorLaunchAgentTool = launchAgentTool
export const cursorAddFollowupTool = addFollowupTool
export const cursorStopAgentTool = stopAgentTool
export const cursorDeleteAgentTool = deleteAgentTool
export const cursorDownloadArtifactTool = downloadArtifactTool
export const cursorListArtifactsTool = listArtifactsTool
export const cursorListAgentsV2Tool = listAgentsV2Tool
export const cursorGetAgentV2Tool = getAgentV2Tool
@@ -21,3 +25,5 @@ export const cursorLaunchAgentV2Tool = launchAgentV2Tool
export const cursorAddFollowupV2Tool = addFollowupV2Tool
export const cursorStopAgentV2Tool = stopAgentV2Tool
export const cursorDeleteAgentV2Tool = deleteAgentV2Tool
export const cursorDownloadArtifactV2Tool = downloadArtifactV2Tool
export const cursorListArtifactsV2Tool = listArtifactsV2Tool

View File

@@ -21,12 +21,19 @@ const listAgentsBase = {
visibility: 'user-or-llm',
description: 'Pagination cursor from previous response',
},
prUrl: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter agents by pull request URL',
},
},
request: {
url: (params: ListAgentsParams) => {
const url = new URL('https://api.cursor.com/v0/agents')
if (params.limit) url.searchParams.set('limit', String(params.limit))
if (params.cursor) url.searchParams.set('cursor', params.cursor)
if (params.prUrl) url.searchParams.set('prUrl', params.prUrl)
return url.toString()
},
method: 'GET',
@@ -53,7 +60,7 @@ export const listAgentsTool: ToolConfig<ListAgentsParams, ListAgentsResponse> =
content: `Found ${data.agents.length} agents`,
metadata: {
agents: data.agents,
nextCursor: data.nextCursor,
nextCursor: data.nextCursor ?? null,
},
},
}

View File

@@ -0,0 +1,113 @@
import type { ListArtifactsParams, ListArtifactsResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listArtifactsBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: ListArtifactsParams) =>
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/artifacts`,
method: 'GET',
headers: (params: ListArtifactsParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListArtifactsParams, any>, 'params' | 'request'>
export const listArtifactsTool: ToolConfig<ListArtifactsParams, ListArtifactsResponse> = {
id: 'cursor_list_artifacts',
name: 'Cursor List Artifacts',
description: 'List generated artifact files for a cloud agent.',
version: '1.0.0',
...listArtifactsBase,
transformResponse: async (response) => {
const data = await response.json()
const artifacts = data.artifacts ?? []
return {
success: true,
output: {
content: `Found ${artifacts.length} artifact(s)`,
metadata: {
artifacts,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable artifact count' },
metadata: {
type: 'object',
description: 'Artifacts metadata',
properties: {
artifacts: {
type: 'array',
description: 'List of artifacts',
items: {
type: 'object',
properties: {
path: { type: 'string', description: 'Artifact file path' },
size: { type: 'number', description: 'File size in bytes', optional: true },
},
},
},
},
},
},
}
interface ListArtifactsV2Response {
success: boolean
output: {
artifacts: Array<{ path: string; size?: number }>
}
}
export const listArtifactsV2Tool: ToolConfig<ListArtifactsParams, ListArtifactsV2Response> = {
...listArtifactsBase,
id: 'cursor_list_artifacts_v2',
name: 'Cursor List Artifacts',
description: 'List generated artifact files for a cloud agent. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
const artifacts = data.artifacts ?? []
return {
success: true,
output: {
artifacts: Array.isArray(artifacts) ? artifacts : [],
},
}
},
outputs: {
artifacts: {
type: 'array',
description: 'List of artifact files',
items: {
type: 'object',
properties: {
path: { type: 'string', description: 'Artifact file path' },
size: { type: 'number', description: 'File size in bytes', optional: true },
},
},
},
},
}

View File

@@ -17,7 +17,8 @@ const stopAgentBase = {
},
},
request: {
url: (params: StopAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId}/stop`,
url: (params: StopAgentParams) =>
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/stop`,
method: 'POST',
headers: (params: StopAgentParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,

View File

@@ -7,6 +7,7 @@ export interface BaseCursorParams {
export interface ListAgentsParams extends BaseCursorParams {
limit?: number
cursor?: string
prUrl?: string
}
export interface GetAgentParams extends BaseCursorParams {
@@ -60,7 +61,7 @@ interface AgentTarget {
interface AgentMetadata {
id: string
name: string
status: 'RUNNING' | 'FINISHED' | 'STOPPED' | 'FAILED'
status: 'CREATING' | 'RUNNING' | 'FINISHED' | 'STOPPED' | 'FAILED'
source: AgentSource
target: AgentTarget
summary?: string
@@ -174,6 +175,47 @@ export interface ListRepositoriesResponse extends ToolResponse {
}
}
export interface ListArtifactsParams extends BaseCursorParams {
agentId: string
}
export interface ArtifactMetadata {
path: string
size?: number
}
export interface ListArtifactsResponse extends ToolResponse {
output: {
content: string
metadata: {
artifacts: ArtifactMetadata[]
}
}
}
export interface DownloadArtifactParams extends BaseCursorParams {
agentId: string
path: string
}
export interface DownloadArtifactResponse extends ToolResponse {
output: {
content: string
metadata: Record<string, unknown>
}
}
export interface DownloadArtifactV2Response extends ToolResponse {
output: {
file: {
name: string
mimeType: string
data: string
size: number
}
}
}
export type CursorResponse =
| ListAgentsResponse
| GetAgentResponse
@@ -185,3 +227,6 @@ export type CursorResponse =
| GetApiKeyInfoResponse
| ListModelsResponse
| ListRepositoriesResponse
| ListArtifactsResponse
| DownloadArtifactResponse
| DownloadArtifactV2Response

View File

@@ -346,6 +346,8 @@ import {
cursorAddFollowupV2Tool,
cursorDeleteAgentTool,
cursorDeleteAgentV2Tool,
cursorDownloadArtifactTool,
cursorDownloadArtifactV2Tool,
cursorGetAgentTool,
cursorGetAgentV2Tool,
cursorGetConversationTool,
@@ -354,6 +356,8 @@ import {
cursorLaunchAgentV2Tool,
cursorListAgentsTool,
cursorListAgentsV2Tool,
cursorListArtifactsTool,
cursorListArtifactsV2Tool,
cursorStopAgentTool,
cursorStopAgentV2Tool,
} from '@/tools/cursor'
@@ -4123,6 +4127,10 @@ export const tools: Record<string, ToolConfig> = {
cursor_stop_agent_v2: cursorStopAgentV2Tool,
cursor_delete_agent: cursorDeleteAgentTool,
cursor_delete_agent_v2: cursorDeleteAgentV2Tool,
cursor_download_artifact: cursorDownloadArtifactTool,
cursor_download_artifact_v2: cursorDownloadArtifactV2Tool,
cursor_list_artifacts: cursorListArtifactsTool,
cursor_list_artifacts_v2: cursorListArtifactsV2Tool,
trello_list_lists: trelloListListsTool,
trello_list_cards: trelloListCardsTool,
trello_create_card: trelloCreateCardTool,