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
19 changes: 19 additions & 0 deletions apps/sim/tools/function/execute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
MOUNTED_WORKSPACE_FILES_PROVENANCE_KEY,
PRIVATE_SECRET_PROVENANCE_FIELD,
} from '@/lib/execution/private-tool-metadata'
import { MAX_FUNCTION_CODE_LENGTH } from '@/lib/function-execution/limits'
import { buildFunctionExecuteBody, functionExecuteTool } from '@/tools/function/execute'
import { createLLMToolSchema, createUserToolSchema } from '@/tools/params'

Expand Down Expand Up @@ -59,6 +60,24 @@ describe('Function Execute Tool', () => {
expect(body.timeout).toBe(DEFAULT_EXECUTION_TIMEOUT_MS)
})

it('sends display code the route accepts when inlined references outgrow the source cap', () => {
const inlinedValue = 'x'.repeat(MAX_FUNCTION_CODE_LENGTH)
const body = buildFunctionExecuteBody({
code: 'return __blockRef_0.length',
sourceCode: `return "${inlinedValue}".length`,
contextVariables: { __blockRef_0: inlinedValue },
})

expect(functionExecuteBodySchema.safeParse(body).success).toBe(true)
expect(body.sourceCode).toBeUndefined()

const withinCap = buildFunctionExecuteBody({
code: 'return __blockRef_0',
sourceCode: 'return <api.data>',
})
expect(withinCap.sourceCode).toBe('return <api.data>')
})

it('preserves reference context and large-value authorization', () => {
const body = buildFunctionExecuteBody({
code: 'return contextVariables.previous.result',
Expand Down
14 changes: 12 additions & 2 deletions apps/sim/tools/function/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DEFAULT_EXECUTION_TIMEOUT_MS } from '@/lib/execution/constants'
import { DEFAULT_CODE_LANGUAGE } from '@/lib/execution/languages'
import { PRIVATE_SECRET_PROVENANCE_FIELD } from '@/lib/execution/private-tool-metadata'
import { SANDBOX_INPUT_DIR, SANDBOX_OUTPUT_DIR } from '@/lib/execution/remote-sandbox/sandbox-paths'
import { MAX_FUNCTION_CODE_LENGTH } from '@/lib/function-execution/limits'
import type { UserFile } from '@/executor/types'
import type { CodeExecutionInput, CodeExecutionOutput } from '@/tools/function/types'
import type { InternalToolConfig } from '@/tools/types'
Expand Down Expand Up @@ -43,15 +44,24 @@ function normalizeSandboxInputFiles(value: unknown): FunctionExecuteBody['files'
return userFiles.map((file) => ({ ...file }))
}

/** Builds the canonical Function protocol body for both HTTP compatibility and in-process calls. */
/**
* Builds the canonical Function protocol body for both HTTP compatibility and in-process calls.
*
* `sourceCode` is the display copy used only to render errors, with referenced values inlined,
* so it can far outgrow the executed code. Past the route's source cap it is omitted, and errors
* fall back to the executed code, rather than failing a request whose executed code is in bounds.
*/
export function buildFunctionExecuteBody(params: CodeExecutionInput): FunctionExecuteBody {
const codeContent = Array.isArray(params.code)
? params.code.map((entry: { content: string }) => entry.content).join('\n')
: params.code

return {
code: codeContent,
sourceCode: params.sourceCode,
sourceCode:
params.sourceCode !== undefined && params.sourceCode.length <= MAX_FUNCTION_CODE_LENGTH
? params.sourceCode
: undefined,
language: params.language || DEFAULT_CODE_LANGUAGE,
timeout: params.timeout || DEFAULT_EXECUTION_TIMEOUT_MS,
title: params.title,
Expand Down
Loading