Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions apps/docs/content/docs/en/tools/azure_devops.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ Get the execution timeline for an Azure DevOps build — every stage, job, and t
| ↳ `warningCount` | number | Number of warnings |
| ↳ `startTime` | string | ISO 8601 start timestamp |
| ↳ `finishTime` | string | ISO 8601 finish timestamp |
| ↳ `failedRecords` | array | Subset of records where result === "failed" — use logId to fetch logs |
| ↳ `failedRecords` | array | Subset of records where result is failed, partiallySucceeded, or succeededWithIssues — use logId to fetch logs |
| ↳ `id` | string | Record GUID |
| ↳ `name` | string | Step name |
| ↳ `type` | string | Stage \| Phase \| Job \| Task |
Expand Down Expand Up @@ -333,7 +333,8 @@ Execute a WIQL query to search for work items in Azure DevOps and return full fi
| --------- | ---- | ----------- |
| `content` | string | Human-readable summary of matching work items |
| `metadata` | object | Work items metadata |
| ↳ `count` | number | Number of work items returned |
| ↳ `count` | number | Number of work items returned \(after hydration\) |
| ↳ `totalMatched` | number | Total number of work items matched by the WIQL query before hydration |
| ↳ `workItems` | array | Array of work item details |
| ↳ `id` | number | Work item ID |
| ↳ `title` | string | Work item title |
Expand Down Expand Up @@ -372,15 +373,15 @@ Fetch full details of a single work item by ID from Azure DevOps, including titl

### `azure_devops_get_work_items_batch`

Fetch full details for multiple work items by ID from Azure DevOps in a single call. Pass comma-separated IDs (e.g.
Fetch full details for multiple work items by ID from Azure DevOps. Pass comma-separated IDs (e.g.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `organization` | string | Yes | Azure DevOps organization name |
| `project` | string | Yes | Azure DevOps project name |
| `ids` | string | Yes | Comma-separated work item IDs to fetch \(e.g. "123,456,789"\). Maximum 200 IDs. |
| `ids` | string | Yes | Comma-separated work item IDs to fetch \(e.g. "123,456,789"\). Lists longer than 200 IDs are chunked automatically. |

#### Output

Expand All @@ -389,6 +390,7 @@ Fetch full details for multiple work items by ID from Azure DevOps in a single c
| `content` | string | Human-readable summary of the fetched work items |
| `metadata` | object | Work items metadata |
| ↳ `count` | number | Number of work items returned |
| ↳ `totalRequested` | number | Total number of IDs requested \(across all chunks\) |
| ↳ `workItems` | array | Array of work item details |
| ↳ `id` | number | Work item ID |
| ↳ `title` | string | Work item title |
Expand Down
1 change: 0 additions & 1 deletion apps/docs/content/docs/en/tools/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@
"upstash",
"vercel",
"video_generator",
"vision",
"wealthbox",
"webflow",
"whatsapp",
Expand Down
60 changes: 0 additions & 60 deletions apps/docs/content/docs/en/tools/vision.mdx

This file was deleted.

8 changes: 4 additions & 4 deletions apps/docs/content/docs/en/triggers/azure_devops.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Trigger workflow when an Azure DevOps build fails, is canceled, or partially suc
| `branch` | string | Source branch name \(refs/heads/ prefix stripped\) |
| `commitSha` | string | Source commit SHA |
| `triggeredBy` | string | Display name of the person who triggered the build |
| `triggeredByEmail` | string | Email/unique name of the person who triggered the build |
| `triggeredByEmail` | string | Email/unique name of the person who triggered the build, or null if not set |
| `startTime` | string | Build start time \(ISO 8601\) |
| `finishTime` | string | Build finish time \(ISO 8601\) |
| `buildUrl` | string | API URL for the build resource |
Expand Down Expand Up @@ -72,12 +72,12 @@ Trigger workflow when a work item is created in Azure DevOps
| `workItemType` | string | Work item type for Basic process \(e.g. Issue, Task, Epic\) |
| `title` | string | Work item title |
| `state` | string | Work item state for Basic process \(e.g. To Do, Doing, Done\) |
| `createdBy` | string | Display name of the creator |
| `assignedTo` | string | Assignee display name, or empty string if unassigned |
| `createdBy` | string | Display name of the creator, or null if not set |
| `assignedTo` | string | Assignee display name, or null if unassigned |
| `priority` | number | Priority \(1–4\), or 0 if not set |
| `areaPath` | string | Area path |
| `iterationPath` | string | Iteration path |
| `description` | string | Work item description \(HTML\), or empty string if not set |
| `description` | string | Work item description \(HTML\), or null if not set |
| `projectName` | string | Azure DevOps project name |
| `workItemUrl` | string | API URL for the work item resource |

2 changes: 0 additions & 2 deletions apps/sim/app/(landing)/integrations/data/icon-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ import {
EvernoteIcon,
ExaAIIcon,
ExtendIcon,
EyeIcon,
FathomIcon,
FindymailIcon,
FirecrawlIcon,
Expand Down Expand Up @@ -405,7 +404,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
upstash: UpstashIcon,
vercel: VercelIcon,
video_generator_v3: VideoIcon,
vision_v2: EyeIcon,
wealthbox: WealthboxIcon,
webflow: WebflowIcon,
whatsapp: WhatsAppIcon,
Expand Down
26 changes: 2 additions & 24 deletions apps/sim/app/(landing)/integrations/data/integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1938,7 +1938,7 @@
},
{
"name": "Get Work Items Batch",
"description": "Fetch full details for multiple work items by ID from Azure DevOps in a single call. Pass comma-separated IDs (e.g. "
"description": "Fetch full details for multiple work items by ID from Azure DevOps. Pass comma-separated IDs (e.g. "
},
{
"name": "Create Work Item",
Expand Down Expand Up @@ -4156,10 +4156,6 @@
"name": "Fetch",
"description": "Fetch and parse a file from a URL with optional custom headers."
},
{
"name": "Get",
"description": "Get a workspace file object from a selected file or canonical workspace file ID."
},
{
"name": "Write",
"description": "Create a new workspace file. If a file with the same name already exists, a numeric suffix is added (e.g., "
Expand All @@ -4169,7 +4165,7 @@
"description": "Append content to an existing workspace file. The file must already exist. Content is added to the end of the file."
}
],
"operationCount": 5,
"operationCount": 4,
"triggers": [],
"triggerCount": 0,
"authType": "none",
Expand Down Expand Up @@ -14253,24 +14249,6 @@
"integrationTypes": ["ai", "design"],
"tags": ["video-generation", "llm"]
},
{
"type": "vision_v2",
"slug": "vision",
"name": "Vision",
"description": "Analyze images with vision models",
"longDescription": "Integrate Vision into the workflow. Can analyze images with vision models.",
"bgColor": "#4D5FFF",
"iconName": "EyeIcon",
"docsUrl": "https://docs.sim.ai/tools/vision",
"operations": [],
"operationCount": 0,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",
"category": "tools",
"integrationTypes": ["ai", "documents"],
"tags": ["llm", "document-processing", "ocr"]
},
{
"type": "wealthbox",
"slug": "wealthbox",
Expand Down
84 changes: 49 additions & 35 deletions apps/sim/app/api/files/parse/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ const {
mockFsWriteFile,
mockJoin,
actualPath,
mockFileExistsInWorkspace,
mockListWorkspaceFiles,
mockUploadWorkspaceFile,
} = vi.hoisted(() => {
// eslint-disable-next-line @typescript-eslint/no-require-imports
Expand Down Expand Up @@ -62,9 +60,19 @@ const {
return actualPath.join(...args)
}),
actualPath,
mockFileExistsInWorkspace: vi.fn().mockResolvedValue(false),
mockListWorkspaceFiles: vi.fn().mockResolvedValue([]),
mockUploadWorkspaceFile: vi.fn().mockResolvedValue({}),
mockUploadWorkspaceFile: vi
.fn()
.mockImplementation(
async (workspaceId: string, _userId: string, _buffer: Buffer, fileName: string) => ({
id: 'wf_test',
name: fileName,
size: 0,
type: 'application/octet-stream',
url: `/api/files/serve/${workspaceId}/${fileName}`,
key: `${workspaceId}/${fileName}`,
context: 'workspace',
})
),
}
})

Expand Down Expand Up @@ -110,9 +118,7 @@ vi.mock('@/lib/uploads/contexts/execution', () => ({
uploadExecutionFile: vi.fn(),
}))

vi.mock('@/lib/uploads/contexts/workspace', () => ({
fileExistsInWorkspace: mockFileExistsInWorkspace,
listWorkspaceFiles: mockListWorkspaceFiles,
vi.mock('@/lib/uploads/contexts/workspace/workspace-file-manager', () => ({
uploadWorkspaceFile: mockUploadWorkspaceFile,
}))

Expand Down Expand Up @@ -190,9 +196,7 @@ describe('File Parse API Route', () => {
mockFsStat.mockResolvedValue({ isFile: () => true, size: 17 })
mockFsReadFile.mockResolvedValue(Buffer.from('test file content'))
mockIsSupportedFileType.mockReturnValue(true)
mockFileExistsInWorkspace.mockResolvedValue(false)
mockListWorkspaceFiles.mockResolvedValue([])
mockUploadWorkspaceFile.mockResolvedValue({})
mockUploadWorkspaceFile.mockClear()
mockParseFile.mockResolvedValue({
content: 'parsed content',
metadata: { pageCount: 1 },
Expand Down Expand Up @@ -384,34 +388,32 @@ describe('File Parse API Route', () => {
)
})

it('should preserve the full download cap when an external URL reuses a workspace file', async () => {
it('should never dedup external URL fetches by path filename — two URLs sharing image.png both download', async () => {
inputValidationMockFns.mockValidateUrlWithDNS.mockResolvedValue({
isValid: true,
resolvedIP: '203.0.113.10',
})
inputValidationMockFns.mockSecureFetchWithPinnedIP.mockResolvedValue(
new Response('file content', {
status: 200,
headers: { 'content-type': 'text/plain' },
})
)
mockFileExistsInWorkspace.mockResolvedValueOnce(false).mockResolvedValueOnce(true)
mockListWorkspaceFiles.mockResolvedValueOnce([
{ name: 'file2.txt', key: 'workspace-file2.txt' },
])

mockParseBuffer
.mockResolvedValueOnce({
content: 'a'.repeat(4 * 1024 * 1024),
metadata: { pageCount: 1 },
})
.mockResolvedValueOnce({
content: 'second file',
metadata: { pageCount: 1 },
})
inputValidationMockFns.mockSecureFetchWithPinnedIP
.mockResolvedValueOnce(
new Response('first image bytes', {
status: 200,
headers: { 'content-type': 'image/png' },
})
)
.mockResolvedValueOnce(
new Response('second image bytes — different content', {
status: 200,
headers: { 'content-type': 'image/png' },
})
)
mockIsSupportedFileType.mockReturnValue(false)
permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('write')

const req = createMockRequest('POST', {
filePath: ['https://example.com/file1.txt', 'https://example.com/file2.txt'],
filePath: [
'https://files.slack.com/files-pri/T07-FAAA/download/image.png',
'https://files.slack.com/files-pri/T07-FBBB/download/image.png',
],
workspaceId: 'workspace-id',
})

Expand All @@ -420,9 +422,21 @@ describe('File Parse API Route', () => {

expect(response.status).toBe(200)
expect(data.results).toHaveLength(2)
expect(storageServiceMockFns.mockDownloadFile).toHaveBeenCalledWith(
expect.objectContaining({ key: 'workspace-file2.txt', maxBytes: 100 * 1024 * 1024 })
expect(inputValidationMockFns.mockSecureFetchWithPinnedIP).toHaveBeenCalledTimes(2)
expect(inputValidationMockFns.mockSecureFetchWithPinnedIP).toHaveBeenNthCalledWith(
1,
'https://files.slack.com/files-pri/T07-FAAA/download/image.png',
'203.0.113.10',
expect.any(Object)
)
expect(inputValidationMockFns.mockSecureFetchWithPinnedIP).toHaveBeenNthCalledWith(
2,
'https://files.slack.com/files-pri/T07-FBBB/download/image.png',
'203.0.113.10',
expect.any(Object)
)
expect(mockUploadWorkspaceFile).toHaveBeenCalledTimes(2)
expect(storageServiceMockFns.mockDownloadFile).not.toHaveBeenCalled()
})

it('should stop multi-file parsing once the combined parsed output is too large', async () => {
Expand Down
Loading
Loading