chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -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,
},
}
+113
View File
@@ -0,0 +1,113 @@
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,
DevinCreateSessionResponse
> = {
id: 'devin_create_session',
name: 'create_session',
description:
'Create a new Devin session with a prompt. Devin will autonomously work on the task described in the prompt.',
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-)',
},
prompt: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The task prompt for Devin to work on',
},
playbookId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional playbook ID to guide the session',
},
maxAcuLimit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum ACU limit for the session',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tags for the session',
},
},
request: {
url: (params) => `https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {
prompt: params.prompt,
}
if (params.playbookId) body.playbook_id = params.playbookId
if (params.maxAcuLimit != null) {
body.max_acu_limit = params.maxAcuLimit
}
const tags = normalizeTags(params.tags)
if (tags.length > 0) body.tags = tags
return body
},
},
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,
},
}
+79
View File
@@ -0,0 +1,79 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinGetSessionParams, DevinGetSessionResponse } from './types'
import { DEVIN_SESSION_OUTPUT_PROPERTIES } from './types'
export const devinGetSessionTool: ToolConfig<DevinGetSessionParams, DevinGetSessionResponse> = {
id: 'devin_get_session',
name: 'get_session',
description:
'Retrieve details of an existing Devin session including status, tags, pull requests, and structured output.',
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',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}`,
method: 'GET',
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,
},
}
+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)',
},
},
}
+11
View File
@@ -0,0 +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,
},
},
}
+105
View File
@@ -0,0 +1,105 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinListSessionsParams, DevinListSessionsResponse } from './types'
import { DEVIN_SESSION_LIST_ITEM_PROPERTIES } from './types'
export const devinListSessionsTool: ToolConfig<DevinListSessionsParams, DevinListSessionsResponse> =
{
id: 'devin_list_sessions',
name: 'list_sessions',
description: 'List Devin sessions in the organization. Returns up to 100 sessions by default.',
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-)',
},
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/${params.orgId.trim()}/sessions${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: {
sessions: items.map((item: Record<string, unknown>) => ({
sessionId: item.session_id ?? null,
url: item.url ?? null,
status: item.status ?? null,
statusDetail: item.status_detail ?? null,
title: item.title ?? null,
createdAt: item.created_at ?? null,
updatedAt: item.updated_at ?? 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,
},
}
},
outputs: {
sessions: {
type: 'array',
description: 'List of Devin sessions',
items: {
type: 'object',
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)',
},
},
}
+89
View File
@@ -0,0 +1,89 @@
import type { ToolConfig } from '@/tools/types'
import type { DevinSendMessageParams, DevinSendMessageResponse } from './types'
import { DEVIN_SESSION_OUTPUT_PROPERTIES } from './types'
export const devinSendMessageTool: ToolConfig<DevinSendMessageParams, DevinSendMessageResponse> = {
id: 'devin_send_message',
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.',
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 send the message to',
},
message: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The message to send to Devin',
},
},
request: {
url: (params) =>
`https://api.devin.ai/v3/organizations/${params.orgId.trim()}/sessions/${params.sessionId.trim()}/messages`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => ({
message: params.message,
}),
},
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,
},
}
+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,
},
}
+333
View File
@@ -0,0 +1,333 @@
import type { OutputProperty, ToolResponse } from '@/tools/types'
export interface DevinCreateSessionParams {
apiKey: string
orgId: string
prompt: string
playbookId?: string
maxAcuLimit?: number
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',
description: 'Unique identifier for the session',
},
url: {
type: 'string',
description: 'URL to view the session in the Devin UI',
},
status: {
type: 'string',
description: 'Session status (new, claimed, running, exit, error, suspended, resuming)',
},
statusDetail: {
type: 'string',
description:
'Detailed status (working, waiting_for_user, waiting_for_approval, finished, inactivity, etc.)',
optional: true,
},
title: {
type: 'string',
description: 'Session title',
optional: true,
},
createdAt: {
type: 'number',
description: 'Unix timestamp when the session was created',
optional: true,
},
updatedAt: {
type: 'number',
description: 'Unix timestamp when the session was last updated',
optional: true,
},
acusConsumed: {
type: 'number',
description: 'ACUs consumed by the session',
optional: true,
},
tags: {
type: 'json',
description: 'Tags associated with the session (array of strings)',
},
pullRequests: {
type: 'json',
description: 'Pull requests created during the session ([{pr_url, pr_state}])',
},
structuredOutput: {
type: 'json',
description: 'Structured output from the session',
optional: true,
},
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_LIST_ITEM_PROPERTIES = {
sessionId: {
type: 'string',
description: 'Unique identifier for the session',
},
url: {
type: 'string',
description: 'URL to view the session',
},
status: {
type: 'string',
description: 'Session status',
},
statusDetail: {
type: 'string',
description: 'Detailed status',
optional: true,
},
title: {
type: 'string',
description: 'Session title',
optional: true,
},
createdAt: {
type: 'number',
description: 'Creation timestamp (Unix)',
optional: true,
},
updatedAt: {
type: 'number',
description: 'Last updated timestamp (Unix)',
optional: true,
},
tags: {
type: 'json',
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>
interface DevinSessionOutput {
sessionId: string
url: string
status: string
statusDetail: string | null
title: string | null
createdAt: number | null
updatedAt: number | null
acusConsumed: number | 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 {
output: DevinSessionOutput
}
export interface DevinGetSessionResponse extends ToolResponse {
output: DevinSessionOutput
}
export interface DevinListSessionsResponse extends ToolResponse {
output: {
sessions: Array<{
sessionId: string
url: string
status: string
statusDetail: string | null
title: string | null
createdAt: number | null
updatedAt: number | 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 []
}