improvement(integrations): validate and expand devin, cursor, and greptile (#4820)

* improvement(integrations): validate and expand devin, cursor, and greptile

- devin: fix missing org_id path segment on all session endpoints, add 7 session sub-resource tools (list messages/attachments, get/append/replace tags, archive, terminate), pagination, and is_archived output
- cursor: add get_api_key_info, list_models, list_repositories tools
- greptile: align block and docs
- normalize array outputs to default [] and tighten types

* refactor(cursor): simplify list_repositories v2 array normalization

Collapse the redundant `?? []` + `Array.isArray` double-guard into a
single Array.isArray check, per PR review feedback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(devin): scope session-tag mapping to tag ops and normalize array tag inputs

- Only map sessionTags into the tools tags param for append/replace operations,
  preventing stale sessionTags state from clobbering create_session tags
- Fall back to a wired tags value when sessionTags is empty for tag operations
- Normalize tag inputs (string or wired string[]) via normalizeTags so array
  values from other blocks no longer throw on .split

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cursor): restore base64 file data in legacy download_artifact metadata

The legacy CursorBlock exposes only content + metadata (no v2 file
output), so metadata.data was the only way legacy-block workflows could
access downloaded artifact bytes. Restore the base64 data field and
document it in the outputs/type instead of dropping it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(devin): coerce terminateArchive to archive flag for boolean-wired input

* docs(integrations): regenerate tool docs for new devin and cursor operations

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Waleed
2026-05-30 18:53:29 -07:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 911586ad5a
commit 20a8d85e15
29 changed files with 1646 additions and 99 deletions
@@ -211,4 +211,57 @@ Download a generated artifact file from a cloud agent. Returns the file for exec
| --------- | ---- | ----------- |
| `file` | file | Downloaded artifact file stored in execution files |
### `cursor_list_models`
List the models available for launching cloud agents. Returns API-aligned fields only.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Cursor API key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `models` | array | Array of available model names |
### `cursor_list_repositories`
List the GitHub repositories accessible to the authenticated user. Returns API-aligned fields only.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Cursor API key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `repositories` | array | Array of accessible repositories |
| ↳ `owner` | string | Repository owner |
| ↳ `name` | string | Repository name |
| ↳ `repository` | string | Repository URL |
### `cursor_get_api_key_info`
Retrieve details about the API key currently in use. Returns API-aligned fields only.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Cursor API key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `apiKeyName` | string | Name of the API key |
| `createdAt` | string | API key creation timestamp |
| `userEmail` | string | Email of the key owner |
+189 -7
View File
@@ -50,6 +50,7 @@ Create a new Devin session with a prompt. Devin will autonomously work on the ta
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `prompt` | string | Yes | The task prompt for Devin to work on |
| `playbookId` | string | No | Optional playbook ID to guide the session |
| `maxAcuLimit` | number | No | Maximum ACU limit for the session |
@@ -67,10 +68,11 @@ Create a new Devin session with a prompt. Devin will autonomously work on the ta
| `createdAt` | number | Unix timestamp when the session was created |
| `updatedAt` | number | Unix timestamp when the session was last updated |
| `acusConsumed` | number | ACUs consumed by the session |
| `tags` | json | Tags associated with the session |
| `pullRequests` | json | Pull requests created during the session |
| `tags` | json | Tags associated with the session \(array of strings\) |
| `pullRequests` | json | Pull requests created during the session \(\[\{pr_url, pr_state\}\]\) |
| `structuredOutput` | json | Structured output from the session |
| `playbookId` | string | Associated playbook ID |
| `isArchived` | boolean | Whether the session is archived |
### `devin_get_session`
@@ -81,6 +83,7 @@ Retrieve details of an existing Devin session including status, tags, pull reque
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to retrieve |
#### Output
@@ -95,10 +98,11 @@ Retrieve details of an existing Devin session including status, tags, pull reque
| `createdAt` | number | Unix timestamp when the session was created |
| `updatedAt` | number | Unix timestamp when the session was last updated |
| `acusConsumed` | number | ACUs consumed by the session |
| `tags` | json | Tags associated with the session |
| `pullRequests` | json | Pull requests created during the session |
| `tags` | json | Tags associated with the session \(array of strings\) |
| `pullRequests` | json | Pull requests created during the session \(\[\{pr_url, pr_state\}\]\) |
| `structuredOutput` | json | Structured output from the session |
| `playbookId` | string | Associated playbook ID |
| `isArchived` | boolean | Whether the session is archived |
### `devin_list_sessions`
@@ -109,7 +113,9 @@ List Devin sessions in the organization. Returns up to 100 sessions by default.
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `limit` | number | No | Maximum number of sessions to return \(1-200, default: 100\) |
| `after` | string | No | Pagination cursor \(endCursor from a previous response\) to fetch the next page |
#### Output
@@ -123,7 +129,14 @@ List Devin sessions in the organization. Returns up to 100 sessions by default.
| ↳ `title` | string | Session title |
| ↳ `createdAt` | number | Creation timestamp \(Unix\) |
| ↳ `updatedAt` | number | Last updated timestamp \(Unix\) |
| ↳ `tags` | json | Session tags |
| ↳ `tags` | json | Session tags \(array of strings\) |
| ↳ `acusConsumed` | number | ACUs consumed by the session |
| ↳ `pullRequests` | json | Pull requests created during the session \(\[\{pr_url, pr_state\}\]\) |
| ↳ `playbookId` | string | Associated playbook ID |
| ↳ `isArchived` | boolean | Whether the session is archived |
| `endCursor` | string | Pagination cursor for the next page, or null if last page |
| `hasNextPage` | boolean | Whether more sessions are available |
| `total` | number | Total number of sessions, if provided |
### `devin_send_message`
@@ -134,6 +147,7 @@ Send a message to a Devin session. If the session is suspended, it will be autom
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to send the message to |
| `message` | string | Yes | The message to send to Devin |
@@ -149,9 +163,177 @@ Send a message to a Devin session. If the session is suspended, it will be autom
| `createdAt` | number | Unix timestamp when the session was created |
| `updatedAt` | number | Unix timestamp when the session was last updated |
| `acusConsumed` | number | ACUs consumed by the session |
| `tags` | json | Tags associated with the session |
| `pullRequests` | json | Pull requests created during the session |
| `tags` | json | Tags associated with the session \(array of strings\) |
| `pullRequests` | json | Pull requests created during the session \(\[\{pr_url, pr_state\}\]\) |
| `structuredOutput` | json | Structured output from the session |
| `playbookId` | string | Associated playbook ID |
| `isArchived` | boolean | Whether the session is archived |
### `devin_list_session_messages`
List the messages exchanged in a Devin session, including messages from both the user and Devin.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to list messages for |
| `limit` | number | No | Maximum number of messages to return \(1-200, default: 100\) |
| `after` | string | No | Pagination cursor \(endCursor from a previous response\) to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `messages` | array | Messages exchanged in the session |
| ↳ `eventId` | string | Unique identifier for the message event |
| ↳ `source` | string | Origin of the message \(devin or user\) |
| ↳ `message` | string | The message content |
| ↳ `createdAt` | number | Unix timestamp when the message was created |
| `endCursor` | string | Pagination cursor for the next page, or null if last page |
| `hasNextPage` | boolean | Whether more messages are available |
| `total` | number | Total number of messages, if provided |
### `devin_list_session_attachments`
List the files uploaded to or produced by a Devin session.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to list attachments for |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `attachments` | array | Attachments associated with the session |
| ↳ `attachmentId` | string | Unique identifier for the attachment |
| ↳ `name` | string | Attachment file name |
| ↳ `url` | string | URL to download the attachment |
| ↳ `source` | string | Origin of the attachment \(devin or user\) |
| ↳ `contentType` | string | MIME type of the attachment |
### `devin_get_session_tags`
Retrieve the tags currently applied to a Devin session.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to retrieve tags for |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tags` | json | Tags applied to the session \(array of strings\) |
### `devin_append_session_tags`
Add tags to a Devin session without removing existing tags (max 50 tags total).
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to add tags to |
| `tags` | string | Yes | Tags to append to the session \(comma-separated string or array of strings\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tags` | json | Updated list of tags on the session \(array of strings\) |
### `devin_replace_session_tags`
Replace all tags on a Devin session with a new set of tags (max 50 tags).
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to replace tags on |
| `tags` | string | Yes | Tags that will overwrite the existing tags \(comma-separated string or array of strings\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tags` | json | Updated list of tags on the session \(array of strings\) |
### `devin_archive_session`
Archive a Devin session. Archived sessions can still be viewed but cannot be modified or resumed.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to archive |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | Unique identifier for the session |
| `url` | string | URL to view the session in the Devin UI |
| `status` | string | Session status \(new, claimed, running, exit, error, suspended, resuming\) |
| `statusDetail` | string | Detailed status \(working, waiting_for_user, waiting_for_approval, finished, inactivity, etc.\) |
| `title` | string | Session title |
| `createdAt` | number | Unix timestamp when the session was created |
| `updatedAt` | number | Unix timestamp when the session was last updated |
| `acusConsumed` | number | ACUs consumed by the session |
| `tags` | json | Tags associated with the session \(array of strings\) |
| `pullRequests` | json | Pull requests created during the session \(\[\{pr_url, pr_state\}\]\) |
| `structuredOutput` | json | Structured output from the session |
| `playbookId` | string | Associated playbook ID |
| `isArchived` | boolean | Whether the session is archived |
### `devin_terminate_session`
Terminate a Devin session. Optionally archive the session instead of permanently terminating it.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Devin API key \(service user credential starting with cog_\) |
| `orgId` | string | Yes | Devin organization ID \(prefixed with org-\) |
| `sessionId` | string | Yes | The session ID to terminate |
| `archive` | boolean | No | Archive the session instead of permanently terminating it \(default: false\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | Unique identifier for the session |
| `url` | string | URL to view the session in the Devin UI |
| `status` | string | Session status \(new, claimed, running, exit, error, suspended, resuming\) |
| `statusDetail` | string | Detailed status \(working, waiting_for_user, waiting_for_approval, finished, inactivity, etc.\) |
| `title` | string | Session title |
| `createdAt` | number | Unix timestamp when the session was created |
| `updatedAt` | number | Unix timestamp when the session was last updated |
| `acusConsumed` | number | ACUs consumed by the session |
| `tags` | json | Tags associated with the session \(array of strings\) |
| `pullRequests` | json | Pull requests created during the session \(\[\{pr_url, pr_state\}\]\) |
| `structuredOutput` | json | Structured output from the session |
| `playbookId` | string | Associated playbook ID |
| `isArchived` | boolean | Whether the session is archived |
+1 -1
View File
@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="greptile"
color="#e5e5e5"
color="#5DE195"
/>
{/* MANUAL-CONTENT-START:intro */}
@@ -3052,9 +3052,21 @@
{
"name": "Download Artifact",
"description": "Download a generated artifact file from a cloud agent."
},
{
"name": "List Models",
"description": "List the models available for launching cloud agents."
},
{
"name": "List Repositories",
"description": "List the GitHub repositories accessible to the authenticated user."
},
{
"name": "Get API Key Info",
"description": "Retrieve details about the API key currently in use."
}
],
"operationCount": 9,
"operationCount": 12,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",
@@ -3298,9 +3310,37 @@
{
"name": "Send Message",
"description": "Send a message to a Devin session. If the session is suspended, it will be automatically resumed. Returns the updated session state."
},
{
"name": "List Session Messages",
"description": "List the messages exchanged in a Devin session, including messages from both the user and Devin."
},
{
"name": "List Session Attachments",
"description": "List the files uploaded to or produced by a Devin session."
},
{
"name": "Get Session Tags",
"description": "Retrieve the tags currently applied to a Devin session."
},
{
"name": "Append Session Tags",
"description": "Add tags to a Devin session without removing existing tags (max 50 tags total)."
},
{
"name": "Replace Session Tags",
"description": "Replace all tags on a Devin session with a new set of tags (max 50 tags)."
},
{
"name": "Archive Session",
"description": "Archive a Devin session. Archived sessions can still be viewed but cannot be modified or resumed."
},
{
"name": "Terminate Session",
"description": "Terminate a Devin session. Optionally archive the session instead of permanently terminating it."
}
],
"operationCount": 4,
"operationCount": 11,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",
@@ -6470,7 +6510,7 @@
"name": "Greptile",
"description": "AI-powered codebase search and Q&A",
"longDescription": "Query and search codebases using natural language with Greptile. Get AI-generated answers about your code, find relevant files, and understand complex codebases.",
"bgColor": "#e5e5e5",
"bgColor": "#5DE195",
"iconName": "GreptileIcon",
"docsUrl": "https://docs.sim.ai/tools/greptile",
"operations": [
+18 -1
View File
@@ -33,6 +33,9 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
{ label: 'Delete Agent', id: 'cursor_delete_agent' },
{ label: 'List Artifacts', id: 'cursor_list_artifacts' },
{ label: 'Download Artifact', id: 'cursor_download_artifact' },
{ label: 'List Models', id: 'cursor_list_models' },
{ label: 'List Repositories', id: 'cursor_list_repositories' },
{ label: 'Get API Key Info', id: 'cursor_get_api_key_info' },
],
value: () => 'cursor_launch_agent',
},
@@ -183,6 +186,9 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
'cursor_delete_agent',
'cursor_list_artifacts',
'cursor_download_artifact',
'cursor_list_models',
'cursor_list_repositories',
'cursor_get_api_key_info',
],
config: {
tool: (params) => params.operation || 'cursor_launch_agent',
@@ -236,6 +242,9 @@ export const CursorV2Block: BlockConfig<CursorResponse> = {
'cursor_delete_agent_v2',
'cursor_list_artifacts_v2',
'cursor_download_artifact_v2',
'cursor_list_models_v2',
'cursor_list_repositories_v2',
'cursor_get_api_key_info_v2',
],
config: {
tool: createVersionedToolSelector({
@@ -253,11 +262,19 @@ export const CursorV2Block: BlockConfig<CursorResponse> = {
source: { type: 'json', description: 'Agent source repository info' },
target: { type: 'json', description: 'Agent target branch/PR info' },
summary: { type: 'string', description: 'Agent summary' },
createdAt: { type: 'string', description: 'Agent creation timestamp' },
createdAt: { type: 'string', description: 'Creation timestamp (agent or API key)' },
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)' },
models: { type: 'json', description: 'Available model names (list models operation)' },
repositories: {
type: 'json',
description:
'Accessible repositories [{owner, name, repository}] (list repositories operation)',
},
apiKeyName: { type: 'string', description: 'API key name (api key info operation)' },
userEmail: { type: 'string', description: 'Key owner email (api key info operation)' },
},
}
+153 -23
View File
@@ -2,6 +2,14 @@ import { DevinIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode, IntegrationType } from '@/blocks/types'
const SESSION_OBJECT_OPERATIONS = [
'create_session',
'get_session',
'send_message',
'archive_session',
'terminate_session',
] as const
export const DevinBlock: BlockConfig = {
type: 'devin',
name: 'Devin',
@@ -32,6 +40,13 @@ export const DevinBlock: BlockConfig = {
{ label: 'Get Session', id: 'get_session' },
{ label: 'List Sessions', id: 'list_sessions' },
{ label: 'Send Message', id: 'send_message' },
{ label: 'List Session Messages', id: 'list_session_messages' },
{ label: 'List Session Attachments', id: 'list_session_attachments' },
{ label: 'Get Session Tags', id: 'get_session_tags' },
{ label: 'Append Session Tags', id: 'append_session_tags' },
{ label: 'Replace Session Tags', id: 'replace_session_tags' },
{ label: 'Archive Session', id: 'archive_session' },
{ label: 'Terminate Session', id: 'terminate_session' },
],
value: () => 'create_session',
},
@@ -43,6 +58,13 @@ export const DevinBlock: BlockConfig = {
password: true,
required: true,
},
{
id: 'orgId',
title: 'Organization ID',
type: 'short-input',
placeholder: 'Enter your Devin organization ID (org-...)',
required: true,
},
{
id: 'prompt',
title: 'Prompt',
@@ -86,16 +108,19 @@ RULES:
title: 'Tags',
type: 'short-input',
placeholder: 'Comma-separated tags',
condition: { field: 'operation', value: 'create_session' },
mode: 'advanced',
required: { field: 'operation', value: ['append_session_tags', 'replace_session_tags'] },
condition: {
field: 'operation',
value: ['create_session', 'append_session_tags', 'replace_session_tags'],
},
},
{
id: 'sessionId',
title: 'Session ID',
type: 'short-input',
placeholder: 'Enter session ID',
required: { field: 'operation', value: ['get_session', 'send_message'] },
condition: { field: 'operation', value: ['get_session', 'send_message'] },
required: { field: 'operation', value: ['create_session', 'list_sessions'], not: true },
condition: { field: 'operation', value: ['create_session', 'list_sessions'], not: true },
},
{
id: 'message',
@@ -109,8 +134,28 @@ RULES:
id: 'limit',
title: 'Limit',
type: 'short-input',
placeholder: 'Number of sessions (1-200, default: 100)',
condition: { field: 'operation', value: 'list_sessions' },
placeholder: 'Max results (1-200, default: 100)',
condition: { field: 'operation', value: ['list_sessions', 'list_session_messages'] },
mode: 'advanced',
},
{
id: 'after',
title: 'After Cursor',
type: 'short-input',
placeholder: 'Pagination cursor from a previous response',
condition: { field: 'operation', value: ['list_sessions', 'list_session_messages'] },
mode: 'advanced',
},
{
id: 'terminateArchive',
title: 'Archive Instead of Terminate',
type: 'dropdown',
options: [
{ label: 'No', id: 'false' },
{ label: 'Yes', id: 'true' },
],
value: () => 'false',
condition: { field: 'operation', value: 'terminate_session' },
mode: 'advanced',
},
],
@@ -120,15 +165,30 @@ RULES:
'devin_get_session',
'devin_list_sessions',
'devin_send_message',
'devin_list_session_messages',
'devin_list_session_attachments',
'devin_get_session_tags',
'devin_append_session_tags',
'devin_replace_session_tags',
'devin_archive_session',
'devin_terminate_session',
],
config: {
tool: (params) => `devin_${params.operation}`,
params: (params) => {
if (params.maxAcuLimit != null && params.maxAcuLimit !== '') {
params.maxAcuLimit = Number(params.maxAcuLimit)
const parsed = Number(params.maxAcuLimit)
params.maxAcuLimit = Number.isFinite(parsed) ? parsed : undefined
}
if (params.limit != null && params.limit !== '') {
params.limit = Number(params.limit)
const parsed = Number(params.limit)
params.limit = Number.isFinite(parsed) ? parsed : undefined
}
if (params.terminateArchive != null && params.terminateArchive !== '') {
params.archive =
typeof params.terminateArchive === 'boolean'
? params.terminateArchive
: params.terminateArchive === 'true'
}
return params
},
@@ -139,51 +199,121 @@ RULES:
sessionId: { type: 'string', description: 'Session ID' },
message: { type: 'string', description: 'Message to send to the session' },
apiKey: { type: 'string', description: 'Devin API key' },
orgId: { type: 'string', description: 'Devin organization ID' },
playbookId: { type: 'string', description: 'Playbook ID to guide the session' },
maxAcuLimit: { type: 'number', description: 'Maximum ACU limit' },
tags: { type: 'string', description: 'Comma-separated tags' },
limit: { type: 'number', description: 'Number of sessions to return' },
tags: { type: 'string', description: 'Tags (comma-separated string or array of strings)' },
limit: { type: 'number', description: 'Maximum number of results to return' },
after: { type: 'string', description: 'Pagination cursor for the next page' },
terminateArchive: {
type: 'string',
description: 'Whether to archive instead of terminate the session',
},
},
outputs: {
sessionId: { type: 'string', description: 'Session identifier' },
url: { type: 'string', description: 'URL to view the session in Devin UI' },
sessionId: {
type: 'string',
description: 'Session identifier',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
url: {
type: 'string',
description: 'URL to view the session in Devin UI',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
status: {
type: 'string',
description: 'Session status (new, claimed, running, exit, error, suspended, resuming)',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
statusDetail: {
type: 'string',
description: 'Detailed status (working, waiting_for_user, finished, etc.)',
condition: { field: 'operation', value: 'list_sessions', not: true },
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
title: {
type: 'string',
description: 'Session title',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
createdAt: {
type: 'number',
description: 'Creation timestamp (Unix)',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
updatedAt: {
type: 'number',
description: 'Last updated timestamp (Unix)',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
title: { type: 'string', description: 'Session title' },
createdAt: { type: 'number', description: 'Creation timestamp (Unix)' },
updatedAt: { type: 'number', description: 'Last updated timestamp (Unix)' },
acusConsumed: {
type: 'number',
description: 'ACUs consumed',
condition: { field: 'operation', value: 'list_sessions', not: true },
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
tags: {
type: 'json',
description: 'Session tags (array of strings)',
condition: {
field: 'operation',
value: [
...SESSION_OBJECT_OPERATIONS,
'get_session_tags',
'append_session_tags',
'replace_session_tags',
],
},
},
tags: { type: 'json', description: 'Session tags' },
pullRequests: {
type: 'json',
description: 'Pull requests created during the session',
condition: { field: 'operation', value: 'list_sessions', not: true },
description: 'Pull requests created during the session ([{pr_url, pr_state}])',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
structuredOutput: {
type: 'json',
description: 'Structured output from the session',
condition: { field: 'operation', value: 'list_sessions', not: true },
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
playbookId: {
type: 'string',
description: 'Associated playbook ID',
condition: { field: 'operation', value: 'list_sessions', not: true },
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
isArchived: {
type: 'boolean',
description: 'Whether the session is archived',
condition: { field: 'operation', value: [...SESSION_OBJECT_OPERATIONS] },
},
sessions: {
type: 'json',
description: 'List of sessions',
description:
'List of sessions ([{sessionId, url, status, statusDetail, title, tags, acusConsumed, pullRequests, playbookId, isArchived, ...}])',
condition: { field: 'operation', value: 'list_sessions' },
},
messages: {
type: 'json',
description: 'Messages in the session ([{eventId, source, message, createdAt}])',
condition: { field: 'operation', value: 'list_session_messages' },
},
attachments: {
type: 'json',
description: 'Session attachments ([{attachmentId, name, url, source, contentType}])',
condition: { field: 'operation', value: 'list_session_attachments' },
},
endCursor: {
type: 'string',
description: 'Pagination cursor for the next page, or null if last page',
condition: { field: 'operation', value: ['list_sessions', 'list_session_messages'] },
},
hasNextPage: {
type: 'boolean',
description: 'Whether more results are available',
condition: { field: 'operation', value: ['list_sessions', 'list_session_messages'] },
},
total: {
type: 'number',
description: 'Total number of results, if provided',
condition: { field: 'operation', value: ['list_sessions', 'list_session_messages'] },
},
},
}
+6 -33
View File
@@ -14,7 +14,7 @@ export const GreptileBlock: BlockConfig<GreptileResponse> = {
category: 'tools',
integrationType: IntegrationType.DeveloperTools,
tags: ['version-control', 'knowledge-base'],
bgColor: '#e5e5e5',
bgColor: '#5DE195',
icon: GreptileIcon,
subBlocks: [
{
@@ -89,7 +89,7 @@ export const GreptileBlock: BlockConfig<GreptileResponse> = {
// type: 'switch',
// condition: { field: 'operation', value: 'greptile_search' },
// },
// Index operation inputs
// Index & Status shared inputs
{
id: 'remote',
title: 'Git Remote',
@@ -99,14 +99,14 @@ export const GreptileBlock: BlockConfig<GreptileResponse> = {
{ label: 'GitLab', id: 'gitlab' },
],
value: () => 'github',
condition: { field: 'operation', value: 'greptile_index_repo' },
condition: { field: 'operation', value: ['greptile_index_repo', 'greptile_status'] },
},
{
id: 'repository',
title: 'Repository',
type: 'short-input',
placeholder: 'owner/repo',
condition: { field: 'operation', value: 'greptile_index_repo' },
condition: { field: 'operation', value: ['greptile_index_repo', 'greptile_status'] },
required: true,
},
{
@@ -114,9 +114,10 @@ export const GreptileBlock: BlockConfig<GreptileResponse> = {
title: 'Branch',
type: 'short-input',
placeholder: 'main',
condition: { field: 'operation', value: 'greptile_index_repo' },
condition: { field: 'operation', value: ['greptile_index_repo', 'greptile_status'] },
required: true,
},
// Index-only inputs
{
id: 'reload',
title: 'Force Re-index',
@@ -129,34 +130,6 @@ export const GreptileBlock: BlockConfig<GreptileResponse> = {
type: 'switch',
condition: { field: 'operation', value: 'greptile_index_repo' },
},
// Status operation inputs
{
id: 'remote',
title: 'Git Remote',
type: 'dropdown',
options: [
{ label: 'GitHub', id: 'github' },
{ label: 'GitLab', id: 'gitlab' },
],
value: () => 'github',
condition: { field: 'operation', value: 'greptile_status' },
},
{
id: 'repository',
title: 'Repository',
type: 'short-input',
placeholder: 'owner/repo',
condition: { field: 'operation', value: 'greptile_status' },
required: true,
},
{
id: 'branch',
title: 'Branch',
type: 'short-input',
placeholder: 'main',
condition: { field: 'operation', value: 'greptile_status' },
required: true,
},
// API Keys (common)
{
id: 'apiKey',
+7 -1
View File
@@ -59,7 +59,12 @@ export const downloadArtifactTool: ToolConfig<DownloadArtifactParams, DownloadAr
success: true,
output: {
content: `Downloaded artifact: ${data.output.file.name}`,
metadata: data.output.file,
metadata: {
name: data.output.file.name,
mimeType: data.output.file.mimeType,
data: data.output.file.data,
size: data.output.file.size,
},
},
}
},
@@ -72,6 +77,7 @@ export const downloadArtifactTool: ToolConfig<DownloadArtifactParams, DownloadAr
properties: {
name: { type: 'string', description: 'File name' },
mimeType: { type: 'string', description: 'MIME type' },
data: { type: 'string', description: 'Base64-encoded file contents' },
size: { type: 'number', description: 'File size in bytes' },
},
},
+93
View File
@@ -0,0 +1,93 @@
import type { GetApiKeyInfoParams, GetApiKeyInfoResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const getApiKeyInfoBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
},
request: {
url: () => 'https://api.cursor.com/v0/me',
method: 'GET',
headers: (params: GetApiKeyInfoParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<GetApiKeyInfoParams, any>, 'params' | 'request'>
export const getApiKeyInfoTool: ToolConfig<GetApiKeyInfoParams, GetApiKeyInfoResponse> = {
id: 'cursor_get_api_key_info',
name: 'Cursor Get API Key Info',
description: 'Retrieve details about the API key currently in use.',
version: '1.0.0',
...getApiKeyInfoBase,
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
content: `API key "${data.apiKeyName}" for ${data.userEmail}`,
metadata: {
apiKeyName: data.apiKeyName,
createdAt: data.createdAt,
userEmail: data.userEmail,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable API key summary' },
metadata: {
type: 'object',
description: 'API key metadata',
properties: {
apiKeyName: { type: 'string', description: 'Name of the API key' },
createdAt: { type: 'string', description: 'API key creation timestamp' },
userEmail: { type: 'string', description: 'Email of the key owner' },
},
},
},
}
interface GetApiKeyInfoV2Response {
success: boolean
output: {
apiKeyName: string
createdAt: string
userEmail: string
}
}
export const getApiKeyInfoV2Tool: ToolConfig<GetApiKeyInfoParams, GetApiKeyInfoV2Response> = {
...getApiKeyInfoBase,
id: 'cursor_get_api_key_info_v2',
name: 'Cursor Get API Key Info',
description:
'Retrieve details about the API key currently in use. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
apiKeyName: data.apiKeyName,
createdAt: data.createdAt,
userEmail: data.userEmail,
},
}
},
outputs: {
apiKeyName: { type: 'string', description: 'Name of the API key' },
createdAt: { type: 'string', description: 'API key creation timestamp' },
userEmail: { type: 'string', description: 'Email of the key owner' },
},
}
+9
View File
@@ -2,10 +2,13 @@ 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 { getApiKeyInfoTool, getApiKeyInfoV2Tool } from '@/tools/cursor/get_api_key_info'
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 { listModelsTool, listModelsV2Tool } from '@/tools/cursor/list_models'
import { listRepositoriesTool, listRepositoriesV2Tool } from '@/tools/cursor/list_repositories'
import { stopAgentTool, stopAgentV2Tool } from '@/tools/cursor/stop_agent'
export const cursorListAgentsTool = listAgentsTool
@@ -17,6 +20,9 @@ export const cursorStopAgentTool = stopAgentTool
export const cursorDeleteAgentTool = deleteAgentTool
export const cursorDownloadArtifactTool = downloadArtifactTool
export const cursorListArtifactsTool = listArtifactsTool
export const cursorListModelsTool = listModelsTool
export const cursorListRepositoriesTool = listRepositoriesTool
export const cursorGetApiKeyInfoTool = getApiKeyInfoTool
export const cursorListAgentsV2Tool = listAgentsV2Tool
export const cursorGetAgentV2Tool = getAgentV2Tool
@@ -27,3 +33,6 @@ export const cursorStopAgentV2Tool = stopAgentV2Tool
export const cursorDeleteAgentV2Tool = deleteAgentV2Tool
export const cursorDownloadArtifactV2Tool = downloadArtifactV2Tool
export const cursorListArtifactsV2Tool = listArtifactsV2Tool
export const cursorListModelsV2Tool = listModelsV2Tool
export const cursorListRepositoriesV2Tool = listRepositoriesV2Tool
export const cursorGetApiKeyInfoV2Tool = getApiKeyInfoV2Tool
+92
View File
@@ -0,0 +1,92 @@
import type { ListModelsParams, ListModelsResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listModelsBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
},
request: {
url: () => 'https://api.cursor.com/v0/models',
method: 'GET',
headers: (params: ListModelsParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListModelsParams, any>, 'params' | 'request'>
export const listModelsTool: ToolConfig<ListModelsParams, ListModelsResponse> = {
id: 'cursor_list_models',
name: 'Cursor List Models',
description: 'List the models available for launching cloud agents.',
version: '1.0.0',
...listModelsBase,
transformResponse: async (response) => {
const data = await response.json()
const models = data.models ?? []
return {
success: true,
output: {
content: `Found ${models.length} model(s)`,
metadata: {
models,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable model count' },
metadata: {
type: 'object',
description: 'Models metadata',
properties: {
models: {
type: 'array',
description: 'Array of available model names',
items: { type: 'string', description: 'Model name' },
},
},
},
},
}
interface ListModelsV2Response {
success: boolean
output: {
models: string[]
}
}
export const listModelsV2Tool: ToolConfig<ListModelsParams, ListModelsV2Response> = {
...listModelsBase,
id: 'cursor_list_models_v2',
name: 'Cursor List Models',
description:
'List the models available for launching cloud agents. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
models: Array.isArray(data.models) ? data.models : [],
},
}
},
outputs: {
models: {
type: 'array',
description: 'Array of available model names',
items: { type: 'string', description: 'Model name' },
},
},
}
+109
View File
@@ -0,0 +1,109 @@
import type { ListRepositoriesParams, ListRepositoriesResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listRepositoriesBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
},
request: {
url: () => 'https://api.cursor.com/v0/repositories',
method: 'GET',
headers: (params: ListRepositoriesParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListRepositoriesParams, any>, 'params' | 'request'>
export const listRepositoriesTool: ToolConfig<ListRepositoriesParams, ListRepositoriesResponse> = {
id: 'cursor_list_repositories',
name: 'Cursor List Repositories',
description: 'List the GitHub repositories accessible to the authenticated user.',
version: '1.0.0',
...listRepositoriesBase,
transformResponse: async (response) => {
const data = await response.json()
const repositories = data.repositories ?? []
return {
success: true,
output: {
content: `Found ${repositories.length} repository(ies)`,
metadata: {
repositories,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable repository count' },
metadata: {
type: 'object',
description: 'Repositories metadata',
properties: {
repositories: {
type: 'array',
description: 'Array of accessible repositories',
items: {
type: 'object',
properties: {
owner: { type: 'string', description: 'Repository owner' },
name: { type: 'string', description: 'Repository name' },
repository: { type: 'string', description: 'Repository URL' },
},
},
},
},
},
},
}
interface ListRepositoriesV2Response {
success: boolean
output: {
repositories: Array<{ owner: string; name: string; repository: string }>
}
}
export const listRepositoriesV2Tool: ToolConfig<
ListRepositoriesParams,
ListRepositoriesV2Response
> = {
...listRepositoriesBase,
id: 'cursor_list_repositories_v2',
name: 'Cursor List Repositories',
description:
'List the GitHub repositories accessible to the authenticated user. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
repositories: Array.isArray(data.repositories) ? data.repositories : [],
},
}
},
outputs: {
repositories: {
type: 'array',
description: 'Array of accessible repositories',
items: {
type: 'object',
properties: {
owner: { type: 'string', description: 'Repository owner' },
name: { type: 'string', description: 'Repository name' },
repository: { type: 'string', description: 'Repository URL' },
},
},
},
},
}
+18 -7
View File
@@ -44,6 +44,12 @@ export interface DeleteAgentParams extends BaseCursorParams {
agentId: string
}
export type ListModelsParams = BaseCursorParams
export type ListRepositoriesParams = BaseCursorParams
export type GetApiKeyInfoParams = BaseCursorParams
interface AgentSource {
repository: string
ref: string
@@ -54,14 +60,14 @@ interface AgentTarget {
url: string
prUrl?: string
autoCreatePr: boolean
openAsCursorGithubApp: boolean
skipReviewerRequest: boolean
openAsCursorGithubApp?: boolean
skipReviewerRequest?: boolean
}
interface AgentMetadata {
id: string
name: string
status: 'CREATING' | 'RUNNING' | 'FINISHED' | 'STOPPED' | 'FAILED'
status: string
source: AgentSource
target: AgentTarget
summary?: string
@@ -150,14 +156,14 @@ export interface DeleteAgentResponse extends ToolResponse {
}
}
interface GetApiKeyInfoResponse extends ToolResponse {
export interface GetApiKeyInfoResponse extends ToolResponse {
output: {
content: string
metadata: ApiKeyInfoMetadata
}
}
interface ListModelsResponse extends ToolResponse {
export interface ListModelsResponse extends ToolResponse {
output: {
content: string
metadata: {
@@ -166,7 +172,7 @@ interface ListModelsResponse extends ToolResponse {
}
}
interface ListRepositoriesResponse extends ToolResponse {
export interface ListRepositoriesResponse extends ToolResponse {
output: {
content: string
metadata: {
@@ -201,7 +207,12 @@ export interface DownloadArtifactParams extends BaseCursorParams {
export interface DownloadArtifactResponse extends ToolResponse {
output: {
content: string
metadata: Record<string, unknown>
metadata: {
name: string
mimeType: string
data: string
size: number
}
}
}
@@ -0,0 +1,70 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinAppendSessionTagsParams, DevinSessionTagsResponse } from './types'
import { normalizeTags } from './utils'
export const devinAppendSessionTagsTool: ToolConfig<
DevinAppendSessionTagsParams,
DevinSessionTagsResponse
> = {
id: 'devin_append_session_tags',
name: 'append_session_tags',
description: 'Add tags to a Devin session without removing existing tags (max 50 tags total).',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to add tags to',
},
tags: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Tags to append to the session (comma-separated string or array of strings)',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/tags`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => ({
tags: normalizeTags(params.tags),
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
tags: data.tags ?? [],
},
}
},
outputs: {
tags: {
type: 'json',
description: 'Updated list of tags on the session (array of strings)',
},
},
}
+82
View File
@@ -0,0 +1,82 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinArchiveSessionParams, DevinArchiveSessionResponse } from './types'
import { DEVIN_SESSION_OUTPUT_PROPERTIES } from './types'
export const devinArchiveSessionTool: ToolConfig<
DevinArchiveSessionParams,
DevinArchiveSessionResponse
> = {
id: 'devin_archive_session',
name: 'archive_session',
description:
'Archive a Devin session. Archived sessions can still be viewed but cannot be modified or resumed.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to archive',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/archive`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
sessionId: data.session_id ?? null,
url: data.url ?? null,
status: data.status ?? null,
statusDetail: data.status_detail ?? null,
title: data.title ?? null,
createdAt: data.created_at ?? null,
updatedAt: data.updated_at ?? null,
acusConsumed: data.acus_consumed ?? null,
tags: data.tags ?? [],
pullRequests: data.pull_requests ?? [],
structuredOutput: data.structured_output ?? null,
playbookId: data.playbook_id ?? null,
isArchived: data.is_archived ?? false,
},
}
},
outputs: {
sessionId: DEVIN_SESSION_OUTPUT_PROPERTIES.sessionId,
url: DEVIN_SESSION_OUTPUT_PROPERTIES.url,
status: DEVIN_SESSION_OUTPUT_PROPERTIES.status,
statusDetail: DEVIN_SESSION_OUTPUT_PROPERTIES.statusDetail,
title: DEVIN_SESSION_OUTPUT_PROPERTIES.title,
createdAt: DEVIN_SESSION_OUTPUT_PROPERTIES.createdAt,
updatedAt: DEVIN_SESSION_OUTPUT_PROPERTIES.updatedAt,
acusConsumed: DEVIN_SESSION_OUTPUT_PROPERTIES.acusConsumed,
tags: DEVIN_SESSION_OUTPUT_PROPERTIES.tags,
pullRequests: DEVIN_SESSION_OUTPUT_PROPERTIES.pullRequests,
structuredOutput: DEVIN_SESSION_OUTPUT_PROPERTIES.structuredOutput,
playbookId: DEVIN_SESSION_OUTPUT_PROPERTIES.playbookId,
isArchived: DEVIN_SESSION_OUTPUT_PROPERTIES.isArchived,
},
}
+14 -6
View File
@@ -1,6 +1,7 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinCreateSessionParams, DevinCreateSessionResponse } from './types'
import { DEVIN_SESSION_OUTPUT_PROPERTIES } from './types'
import { normalizeTags } from './utils'
export const devinCreateSessionTool: ToolConfig<
DevinCreateSessionParams,
@@ -19,6 +20,12 @@ export const devinCreateSessionTool: ToolConfig<
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
prompt: {
type: 'string',
required: true,
@@ -46,7 +53,7 @@ export const devinCreateSessionTool: ToolConfig<
},
request: {
url: 'https://api.devin.ai/v3/organizations/sessions',
url: (params) => `https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
@@ -60,9 +67,8 @@ export const devinCreateSessionTool: ToolConfig<
if (params.maxAcuLimit != null) {
body.max_acu_limit = params.maxAcuLimit
}
if (params.tags) {
body.tags = params.tags.split(',').map((t: string) => t.trim())
}
const tags = normalizeTags(params.tags)
if (tags.length > 0) body.tags = tags
return body
},
},
@@ -80,10 +86,11 @@ export const devinCreateSessionTool: ToolConfig<
createdAt: data.created_at ?? null,
updatedAt: data.updated_at ?? null,
acusConsumed: data.acus_consumed ?? null,
tags: data.tags ?? null,
pullRequests: data.pull_requests ?? null,
tags: data.tags ?? [],
pullRequests: data.pull_requests ?? [],
structuredOutput: data.structured_output ?? null,
playbookId: data.playbook_id ?? null,
isArchived: data.is_archived ?? false,
},
}
},
@@ -101,5 +108,6 @@ export const devinCreateSessionTool: ToolConfig<
pullRequests: DEVIN_SESSION_OUTPUT_PROPERTIES.pullRequests,
structuredOutput: DEVIN_SESSION_OUTPUT_PROPERTIES.structuredOutput,
playbookId: DEVIN_SESSION_OUTPUT_PROPERTIES.playbookId,
isArchived: DEVIN_SESSION_OUTPUT_PROPERTIES.isArchived,
},
}
+12 -3
View File
@@ -16,6 +16,12 @@ export const devinGetSessionTool: ToolConfig<DevinGetSessionParams, DevinGetSess
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
@@ -25,7 +31,8 @@ export const devinGetSessionTool: ToolConfig<DevinGetSessionParams, DevinGetSess
},
request: {
url: (params) => `https://api.devin.ai/v3/organizations/sessions/${params.sessionId}`,
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
@@ -45,10 +52,11 @@ export const devinGetSessionTool: ToolConfig<DevinGetSessionParams, DevinGetSess
createdAt: data.created_at ?? null,
updatedAt: data.updated_at ?? null,
acusConsumed: data.acus_consumed ?? null,
tags: data.tags ?? null,
pullRequests: data.pull_requests ?? null,
tags: data.tags ?? [],
pullRequests: data.pull_requests ?? [],
structuredOutput: data.structured_output ?? null,
playbookId: data.playbook_id ?? null,
isArchived: data.is_archived ?? false,
},
}
},
@@ -66,5 +74,6 @@ export const devinGetSessionTool: ToolConfig<DevinGetSessionParams, DevinGetSess
pullRequests: DEVIN_SESSION_OUTPUT_PROPERTIES.pullRequests,
structuredOutput: DEVIN_SESSION_OUTPUT_PROPERTIES.structuredOutput,
playbookId: DEVIN_SESSION_OUTPUT_PROPERTIES.playbookId,
isArchived: DEVIN_SESSION_OUTPUT_PROPERTIES.isArchived,
},
}
+59
View File
@@ -0,0 +1,59 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinGetSessionTagsParams, DevinSessionTagsResponse } from './types'
export const devinGetSessionTagsTool: ToolConfig<
DevinGetSessionTagsParams,
DevinSessionTagsResponse
> = {
id: 'devin_get_session_tags',
name: 'get_session_tags',
description: 'Retrieve the tags currently applied to a Devin session.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to retrieve tags for',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/tags`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
tags: data.tags ?? [],
},
}
},
outputs: {
tags: {
type: 'json',
description: 'Tags applied to the session (array of strings)',
},
},
}
+7
View File
@@ -1,4 +1,11 @@
export { devinAppendSessionTagsTool } from './append_session_tags'
export { devinArchiveSessionTool } from './archive_session'
export { devinCreateSessionTool } from './create_session'
export { devinGetSessionTool } from './get_session'
export { devinGetSessionTagsTool } from './get_session_tags'
export { devinListSessionAttachmentsTool } from './list_session_attachments'
export { devinListSessionMessagesTool } from './list_session_messages'
export { devinListSessionsTool } from './list_sessions'
export { devinReplaceSessionTagsTool } from './replace_session_tags'
export { devinSendMessageTool } from './send_message'
export { devinTerminateSessionTool } from './terminate_session'
@@ -0,0 +1,74 @@
import type { ToolConfig } from '@/tools/types'
import type {
DevinListSessionAttachmentsParams,
DevinListSessionAttachmentsResponse,
} from './types'
import { DEVIN_SESSION_ATTACHMENT_PROPERTIES } from './types'
export const devinListSessionAttachmentsTool: ToolConfig<
DevinListSessionAttachmentsParams,
DevinListSessionAttachmentsResponse
> = {
id: 'devin_list_session_attachments',
name: 'list_session_attachments',
description: 'List the files uploaded to or produced by a Devin session.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to list attachments for',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/attachments`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
const items = Array.isArray(data) ? data : (data.items ?? [])
return {
success: true,
output: {
attachments: items.map((item: Record<string, unknown>) => ({
attachmentId: item.attachment_id ?? null,
name: item.name ?? null,
url: item.url ?? null,
source: item.source ?? null,
contentType: item.content_type ?? null,
})),
},
}
},
outputs: {
attachments: {
type: 'array',
description: 'Attachments associated with the session',
items: {
type: 'object',
properties: DEVIN_SESSION_ATTACHMENT_PROPERTIES,
},
},
},
}
@@ -0,0 +1,105 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinListSessionMessagesParams, DevinListSessionMessagesResponse } from './types'
import { DEVIN_SESSION_MESSAGE_PROPERTIES } from './types'
export const devinListSessionMessagesTool: ToolConfig<
DevinListSessionMessagesParams,
DevinListSessionMessagesResponse
> = {
id: 'devin_list_session_messages',
name: 'list_session_messages',
description:
'List the messages exchanged in a Devin session, including messages from both the user and Devin.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to list messages for',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of messages to return (1-200, default: 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor (endCursor from a previous response) to fetch the next page',
},
},
request: {
url: (params) => {
const searchParams = new URLSearchParams()
if (params.limit) searchParams.set('first', String(params.limit))
if (params.after) searchParams.set('after', params.after.trim())
const qs = searchParams.toString()
return `https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/messages${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
const items = data.items ?? []
return {
success: true,
output: {
messages: items.map((item: Record<string, unknown>) => ({
eventId: item.event_id ?? null,
source: item.source ?? null,
message: item.message ?? null,
createdAt: item.created_at ?? null,
})),
endCursor: data.end_cursor ?? null,
hasNextPage: data.has_next_page ?? false,
total: data.total ?? null,
},
}
},
outputs: {
messages: {
type: 'array',
description: 'Messages exchanged in the session',
items: {
type: 'object',
properties: DEVIN_SESSION_MESSAGE_PROPERTIES,
},
},
endCursor: {
type: 'string',
description: 'Pagination cursor for the next page, or null if last page',
optional: true,
},
hasNextPage: {
type: 'boolean',
description: 'Whether more messages are available',
},
total: {
type: 'number',
description: 'Total number of messages, if provided',
optional: true,
},
},
}
+37 -2
View File
@@ -16,20 +16,34 @@ export const devinListSessionsTool: ToolConfig<DevinListSessionsParams, DevinLis
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of sessions to return (1-200, default: 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor (endCursor from a previous response) to fetch the next page',
},
},
request: {
url: (params) => {
const searchParams = new URLSearchParams()
if (params.limit) searchParams.set('first', String(params.limit))
if (params.after) searchParams.set('after', params.after.trim())
const qs = searchParams.toString()
return `https://api.devin.ai/v3/organizations/sessions${qs ? `?${qs}` : ''}`
return `https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
@@ -51,8 +65,15 @@ export const devinListSessionsTool: ToolConfig<DevinListSessionsParams, DevinLis
title: item.title ?? null,
createdAt: item.created_at ?? null,
updatedAt: item.updated_at ?? null,
tags: item.tags ?? null,
tags: item.tags ?? [],
acusConsumed: item.acus_consumed ?? null,
pullRequests: item.pull_requests ?? [],
playbookId: item.playbook_id ?? null,
isArchived: item.is_archived ?? false,
})),
endCursor: data.end_cursor ?? null,
hasNextPage: data.has_next_page ?? false,
total: data.total ?? null,
},
}
},
@@ -66,5 +87,19 @@ export const devinListSessionsTool: ToolConfig<DevinListSessionsParams, DevinLis
properties: DEVIN_SESSION_LIST_ITEM_PROPERTIES,
},
},
endCursor: {
type: 'string',
description: 'Pagination cursor for the next page, or null if last page',
optional: true,
},
hasNextPage: {
type: 'boolean',
description: 'Whether more sessions are available',
},
total: {
type: 'number',
description: 'Total number of sessions, if provided',
optional: true,
},
},
}
@@ -0,0 +1,71 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinReplaceSessionTagsParams, DevinSessionTagsResponse } from './types'
import { normalizeTags } from './utils'
export const devinReplaceSessionTagsTool: ToolConfig<
DevinReplaceSessionTagsParams,
DevinSessionTagsResponse
> = {
id: 'devin_replace_session_tags',
name: 'replace_session_tags',
description: 'Replace all tags on a Devin session with a new set of tags (max 50 tags).',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to replace tags on',
},
tags: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Tags that will overwrite the existing tags (comma-separated string or array of strings)',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/tags`,
method: 'PUT',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => ({
tags: normalizeTags(params.tags),
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
tags: data.tags ?? [],
},
}
},
outputs: {
tags: {
type: 'json',
description: 'Updated list of tags on the session (array of strings)',
},
},
}
+12 -3
View File
@@ -16,6 +16,12 @@ export const devinSendMessageTool: ToolConfig<DevinSendMessageParams, DevinSendM
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
@@ -31,7 +37,8 @@ export const devinSendMessageTool: ToolConfig<DevinSendMessageParams, DevinSendM
},
request: {
url: (params) => `https://api.devin.ai/v3/organizations/sessions/${params.sessionId}/messages`,
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/messages`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
@@ -55,10 +62,11 @@ export const devinSendMessageTool: ToolConfig<DevinSendMessageParams, DevinSendM
createdAt: data.created_at ?? null,
updatedAt: data.updated_at ?? null,
acusConsumed: data.acus_consumed ?? null,
tags: data.tags ?? null,
pullRequests: data.pull_requests ?? null,
tags: data.tags ?? [],
pullRequests: data.pull_requests ?? [],
structuredOutput: data.structured_output ?? null,
playbookId: data.playbook_id ?? null,
isArchived: data.is_archived ?? false,
},
}
},
@@ -76,5 +84,6 @@ export const devinSendMessageTool: ToolConfig<DevinSendMessageParams, DevinSendM
pullRequests: DEVIN_SESSION_OUTPUT_PROPERTIES.pullRequests,
structuredOutput: DEVIN_SESSION_OUTPUT_PROPERTIES.structuredOutput,
playbookId: DEVIN_SESSION_OUTPUT_PROPERTIES.playbookId,
isArchived: DEVIN_SESSION_OUTPUT_PROPERTIES.isArchived,
},
}
+92
View File
@@ -0,0 +1,92 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinTerminateSessionParams, DevinTerminateSessionResponse } from './types'
import { DEVIN_SESSION_OUTPUT_PROPERTIES } from './types'
export const devinTerminateSessionTool: ToolConfig<
DevinTerminateSessionParams,
DevinTerminateSessionResponse
> = {
id: 'devin_terminate_session',
name: 'terminate_session',
description:
'Terminate a Devin session. Optionally archive the session instead of permanently terminating it.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin API key (service user credential starting with cog_)',
},
orgId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Devin organization ID (prefixed with org-)',
},
sessionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The session ID to terminate',
},
archive: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Archive the session instead of permanently terminating it (default: false)',
},
},
request: {
url: (params) => {
const searchParams = new URLSearchParams()
if (params.archive) searchParams.set('archive', 'true')
const qs = searchParams.toString()
return `https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}${qs ? `?${qs}` : ''}`
},
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
sessionId: data.session_id ?? null,
url: data.url ?? null,
status: data.status ?? null,
statusDetail: data.status_detail ?? null,
title: data.title ?? null,
createdAt: data.created_at ?? null,
updatedAt: data.updated_at ?? null,
acusConsumed: data.acus_consumed ?? null,
tags: data.tags ?? [],
pullRequests: data.pull_requests ?? [],
structuredOutput: data.structured_output ?? null,
playbookId: data.playbook_id ?? null,
isArchived: data.is_archived ?? false,
},
}
},
outputs: {
sessionId: DEVIN_SESSION_OUTPUT_PROPERTIES.sessionId,
url: DEVIN_SESSION_OUTPUT_PROPERTIES.url,
status: DEVIN_SESSION_OUTPUT_PROPERTIES.status,
statusDetail: DEVIN_SESSION_OUTPUT_PROPERTIES.statusDetail,
title: DEVIN_SESSION_OUTPUT_PROPERTIES.title,
createdAt: DEVIN_SESSION_OUTPUT_PROPERTIES.createdAt,
updatedAt: DEVIN_SESSION_OUTPUT_PROPERTIES.updatedAt,
acusConsumed: DEVIN_SESSION_OUTPUT_PROPERTIES.acusConsumed,
tags: DEVIN_SESSION_OUTPUT_PROPERTIES.tags,
pullRequests: DEVIN_SESSION_OUTPUT_PROPERTIES.pullRequests,
structuredOutput: DEVIN_SESSION_OUTPUT_PROPERTIES.structuredOutput,
playbookId: DEVIN_SESSION_OUTPUT_PROPERTIES.playbookId,
isArchived: DEVIN_SESSION_OUTPUT_PROPERTIES.isArchived,
},
}
+174 -9
View File
@@ -2,28 +2,80 @@ import type { OutputProperty, ToolResponse } from '@/tools/types'
export interface DevinCreateSessionParams {
apiKey: string
orgId: string
prompt: string
playbookId?: string
maxAcuLimit?: number
tags?: string
tags?: string | string[]
}
export interface DevinGetSessionParams {
apiKey: string
orgId: string
sessionId: string
}
export interface DevinListSessionsParams {
apiKey: string
orgId: string
limit?: number
after?: string
}
export interface DevinSendMessageParams {
apiKey: string
orgId: string
sessionId: string
message: string
}
export interface DevinListSessionMessagesParams {
apiKey: string
orgId: string
sessionId: string
limit?: number
after?: string
}
export interface DevinListSessionAttachmentsParams {
apiKey: string
orgId: string
sessionId: string
}
export interface DevinGetSessionTagsParams {
apiKey: string
orgId: string
sessionId: string
}
export interface DevinAppendSessionTagsParams {
apiKey: string
orgId: string
sessionId: string
tags: string | string[]
}
export interface DevinReplaceSessionTagsParams {
apiKey: string
orgId: string
sessionId: string
tags: string | string[]
}
export interface DevinArchiveSessionParams {
apiKey: string
orgId: string
sessionId: string
}
export interface DevinTerminateSessionParams {
apiKey: string
orgId: string
sessionId: string
archive?: boolean
}
export const DEVIN_SESSION_OUTPUT_PROPERTIES = {
sessionId: {
type: 'string',
@@ -65,13 +117,11 @@ export const DEVIN_SESSION_OUTPUT_PROPERTIES = {
},
tags: {
type: 'json',
description: 'Tags associated with the session',
optional: true,
description: 'Tags associated with the session (array of strings)',
},
pullRequests: {
type: 'json',
description: 'Pull requests created during the session',
optional: true,
description: 'Pull requests created during the session ([{pr_url, pr_state}])',
},
structuredOutput: {
type: 'json',
@@ -83,6 +133,11 @@ export const DEVIN_SESSION_OUTPUT_PROPERTIES = {
description: 'Associated playbook ID',
optional: true,
},
isArchived: {
type: 'boolean',
description: 'Whether the session is archived',
optional: true,
},
} as const satisfies Record<string, OutputProperty>
export const DEVIN_SESSION_LIST_ITEM_PROPERTIES = {
@@ -120,7 +175,69 @@ export const DEVIN_SESSION_LIST_ITEM_PROPERTIES = {
},
tags: {
type: 'json',
description: 'Session tags',
description: 'Session tags (array of strings)',
},
acusConsumed: {
type: 'number',
description: 'ACUs consumed by the session',
optional: true,
},
pullRequests: {
type: 'json',
description: 'Pull requests created during the session ([{pr_url, pr_state}])',
},
playbookId: {
type: 'string',
description: 'Associated playbook ID',
optional: true,
},
isArchived: {
type: 'boolean',
description: 'Whether the session is archived',
optional: true,
},
} as const satisfies Record<string, OutputProperty>
export const DEVIN_SESSION_MESSAGE_PROPERTIES = {
eventId: {
type: 'string',
description: 'Unique identifier for the message event',
},
source: {
type: 'string',
description: 'Origin of the message (devin or user)',
},
message: {
type: 'string',
description: 'The message content',
},
createdAt: {
type: 'number',
description: 'Unix timestamp when the message was created',
optional: true,
},
} as const satisfies Record<string, OutputProperty>
export const DEVIN_SESSION_ATTACHMENT_PROPERTIES = {
attachmentId: {
type: 'string',
description: 'Unique identifier for the attachment',
},
name: {
type: 'string',
description: 'Attachment file name',
},
url: {
type: 'string',
description: 'URL to download the attachment',
},
source: {
type: 'string',
description: 'Origin of the attachment (devin or user)',
},
contentType: {
type: 'string',
description: 'MIME type of the attachment',
optional: true,
},
} as const satisfies Record<string, OutputProperty>
@@ -134,10 +251,11 @@ interface DevinSessionOutput {
createdAt: number | null
updatedAt: number | null
acusConsumed: number | null
tags: string[] | null
pullRequests: Array<{ pr_url: string; pr_state: string | null }> | null
tags: string[]
pullRequests: Array<{ pr_url: string; pr_state: string | null }>
structuredOutput: Record<string, unknown> | null
playbookId: string | null
isArchived: boolean
}
export interface DevinCreateSessionResponse extends ToolResponse {
@@ -158,11 +276,58 @@ export interface DevinListSessionsResponse extends ToolResponse {
title: string | null
createdAt: number | null
updatedAt: number | null
tags: string[] | null
tags: string[]
acusConsumed: number | null
pullRequests: Array<{ pr_url: string; pr_state: string | null }>
playbookId: string | null
isArchived: boolean
}>
endCursor: string | null
hasNextPage: boolean
total: number | null
}
}
export interface DevinSendMessageResponse extends ToolResponse {
output: DevinSessionOutput
}
export interface DevinListSessionMessagesResponse extends ToolResponse {
output: {
messages: Array<{
eventId: string
source: string
message: string
createdAt: number | null
}>
endCursor: string | null
hasNextPage: boolean
total: number | null
}
}
export interface DevinListSessionAttachmentsResponse extends ToolResponse {
output: {
attachments: Array<{
attachmentId: string
name: string
url: string
source: string
contentType: string | null
}>
}
}
export interface DevinSessionTagsResponse extends ToolResponse {
output: {
tags: string[]
}
}
export interface DevinArchiveSessionResponse extends ToolResponse {
output: DevinSessionOutput
}
export interface DevinTerminateSessionResponse extends ToolResponse {
output: DevinSessionOutput
}
+19
View File
@@ -0,0 +1,19 @@
/**
* Normalize a tags input into a clean string array.
*
* Tags can arrive either as a comma-separated string (typed into the block's
* text input) or as a string array (when wired from another block's JSON
* output, e.g. the tags returned by a get/append/replace tags operation).
*/
export function normalizeTags(input: string | string[] | undefined | null): string[] {
if (Array.isArray(input)) {
return input.map((tag) => String(tag).trim()).filter(Boolean)
}
if (typeof input === 'string') {
return input
.split(',')
.map((tag) => tag.trim())
.filter(Boolean)
}
return []
}
+26
View File
@@ -435,6 +435,8 @@ import {
cursorDownloadArtifactV2Tool,
cursorGetAgentTool,
cursorGetAgentV2Tool,
cursorGetApiKeyInfoTool,
cursorGetApiKeyInfoV2Tool,
cursorGetConversationTool,
cursorGetConversationV2Tool,
cursorLaunchAgentTool,
@@ -443,6 +445,10 @@ import {
cursorListAgentsV2Tool,
cursorListArtifactsTool,
cursorListArtifactsV2Tool,
cursorListModelsTool,
cursorListModelsV2Tool,
cursorListRepositoriesTool,
cursorListRepositoriesV2Tool,
cursorStopAgentTool,
cursorStopAgentV2Tool,
} from '@/tools/cursor'
@@ -487,10 +493,17 @@ import {
datadogSubmitMetricsTool,
} from '@/tools/datadog'
import {
devinAppendSessionTagsTool,
devinArchiveSessionTool,
devinCreateSessionTool,
devinGetSessionTagsTool,
devinGetSessionTool,
devinListSessionAttachmentsTool,
devinListSessionMessagesTool,
devinListSessionsTool,
devinReplaceSessionTagsTool,
devinSendMessageTool,
devinTerminateSessionTool,
} from '@/tools/devin'
import {
discordAddReactionTool,
@@ -4027,6 +4040,13 @@ export const tools: Record<string, ToolConfig> = {
devin_get_session: devinGetSessionTool,
devin_list_sessions: devinListSessionsTool,
devin_send_message: devinSendMessageTool,
devin_list_session_messages: devinListSessionMessagesTool,
devin_list_session_attachments: devinListSessionAttachmentsTool,
devin_get_session_tags: devinGetSessionTagsTool,
devin_append_session_tags: devinAppendSessionTagsTool,
devin_replace_session_tags: devinReplaceSessionTagsTool,
devin_archive_session: devinArchiveSessionTool,
devin_terminate_session: devinTerminateSessionTool,
dagster_delete_run: dagsterDeleteRunTool,
dagster_get_run: dagsterGetRunTool,
dagster_get_run_logs: dagsterGetRunLogsTool,
@@ -4822,6 +4842,12 @@ export const tools: Record<string, ToolConfig> = {
cursor_download_artifact_v2: cursorDownloadArtifactV2Tool,
cursor_list_artifacts: cursorListArtifactsTool,
cursor_list_artifacts_v2: cursorListArtifactsV2Tool,
cursor_list_models: cursorListModelsTool,
cursor_list_models_v2: cursorListModelsV2Tool,
cursor_list_repositories: cursorListRepositoriesTool,
cursor_list_repositories_v2: cursorListRepositoriesV2Tool,
cursor_get_api_key_info: cursorGetApiKeyInfoTool,
cursor_get_api_key_info_v2: cursorGetApiKeyInfoV2Tool,
trello_list_lists: trelloListListsTool,
trello_list_cards: trelloListCardsTool,
trello_create_card: trelloCreateCardTool,
+1
View File
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "simstudio",