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
5 changes: 4 additions & 1 deletion apps/desktop/src/main/channel-identity.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { describe, expect, it } from 'vitest'
import { describe, expect, it, vi } from 'vitest'

vi.mock('electron', () => import('@/test/electron-mock'))

import { APP_NAME_FOR_CHANNEL, channelForOrigin, DEFAULT_ORIGIN } from '@/main/config'
import { classifyNavigation } from '@/main/navigation'
import { DEV, identityForOrigin, LOCAL, PROD, STAGING } from '../../scripts/channels'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,29 @@ const oauthBlockConfig = {
tools: { access: ['slack_message'] },
}

const tableBlockConfig = {
type: 'table',
name: 'Table',
outputs: {},
subBlocks: [
{
id: 'operation',
type: 'dropdown',
options: [
{ label: 'Query Rows', id: 'query_rows' },
{ label: 'Insert Row', id: 'insert_row' },
],
},
],
tools: {
access: ['table_query_rows', 'table_insert_row'],
config: {
tool: (params: Record<string, unknown>) =>
params.operation === 'insert_row' ? 'table_insert_row' : 'table_query_rows',
},
},
}

const routerBlockConfig = {
type: 'router_v2',
name: 'Router',
Expand Down Expand Up @@ -205,6 +228,7 @@ const toolsByIdMock: Record<string, unknown> = {
const blockConfigsByType: Record<string, unknown> = {
condition: conditionBlockConfig,
slack: oauthBlockConfig,
table: tableBlockConfig,
router_v2: routerBlockConfig,
agent: agentBlockConfig,
pi: piBlockConfig,
Expand Down Expand Up @@ -1239,6 +1263,42 @@ describe('validateInputsForBlock - agent tools (tool-input)', () => {
expect(result.validInputs.tools).toBeDefined()
})

it('accepts a declared integration block operation', () => {
const result = validateInputsForBlock(
'agent',
{ tools: [{ type: 'table', operation: 'insert_row', usageControl: 'auto' }] },
'agent-1'
)

expect(result.errors).toHaveLength(0)
expect(result.validInputs.tools).toBeDefined()
})

it('rejects a prefixed tool id used as an integration block operation', () => {
const result = validateInputsForBlock(
'agent',
{ tools: [{ type: 'table', operation: 'table_insert_row', usageControl: 'auto' }] },
'agent-1'
)

expect(result.validInputs.tools).toBeUndefined()
expect(result.errors).toHaveLength(1)
expect(result.errors[0]?.error).toContain('invalid operation "table_insert_row"')
expect(result.errors[0]?.error).toContain('query_rows, insert_row')
expect(result.errors[0]?.error).toContain('may differ from the underlying tool id')
})

it('rejects a missing operation for a multi-operation integration block', () => {
const result = validateInputsForBlock(
'agent',
{ tools: [{ type: 'table', usageControl: 'auto' }] },
'agent-1'
)

expect(result.validInputs.tools).toBeUndefined()
expect(result.errors[0]?.error).toContain('requires an operation')
})

it('rejects an integration tool unavailable in this deployment', () => {
mockIsIntegrationDeploymentAvailable.mockReturnValue(false)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,34 @@ function validateAgentToolEntry(item: any, index: number): string | null {
if (!isIntegrationDeploymentAvailableForVisibility(type, overlayVisibility())) {
return `${where} block type "${type}" is unavailable in this deployment`
}

const operationConfig = block.subBlocks?.find((subBlock) => subBlock.id === 'operation')
if (operationConfig?.options) {
let validOperations: string[]
try {
const options =
typeof operationConfig.options === 'function'
? operationConfig.options()
: operationConfig.options
validOperations = options.map((option) => option.id)
} catch (error) {
return `${where} could not validate operations for block type "${type}": ${toError(error).message}`
}

const operation = item.operation
if (
validOperations.length > 1 &&
(typeof operation !== 'string' || operation.trim() === '')
) {
return `${where} block type "${type}" requires an operation. Valid operations: ${validOperations.join(', ')}`
}
if (
operation !== undefined &&
(typeof operation !== 'string' || !validOperations.includes(operation))
) {
return `${where} block type "${type}" has invalid operation "${String(operation)}". Valid operations: ${validOperations.join(', ')}. Use one of the block operation ids above; it may differ from the underlying tool id.`
}
}
}

return null
Expand Down
1 change: 0 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading