Skip to content

Commit 72f384c

Browse files
committed
triple quotes case
1 parent e716220 commit 72f384c

2 files changed

Lines changed: 97 additions & 6 deletions

File tree

apps/sim/executor/variables/resolver.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,44 @@ describe('VariableResolver function block inputs', () => {
182182
expect(result.contextVariables).toEqual({ __blockRef_0: 'hello world' })
183183
})
184184

185+
it('breaks Python triple-double-quoted strings around block references', () => {
186+
const { block, ctx, resolver } = createResolver('python')
187+
188+
const result = resolver.resolveInputsForFunctionBlock(
189+
ctx,
190+
'function',
191+
{ code: 'prompt = """\nSummary: <Producer.result>\n"""\nreturn prompt' },
192+
block
193+
)
194+
195+
expect(result.resolvedInputs.code).toBe(
196+
'prompt = """\nSummary: """ + json.dumps(globals()["__blockRef_0"]) + """\n"""\nreturn prompt'
197+
)
198+
expect(result.displayInputs.code).toBe(
199+
'prompt = """\nSummary: "hello world"\n"""\nreturn prompt'
200+
)
201+
expect(result.contextVariables).toEqual({ __blockRef_0: 'hello world' })
202+
})
203+
204+
it('breaks Python triple-single-quoted strings around block references', () => {
205+
const { block, ctx, resolver } = createResolver('python')
206+
207+
const result = resolver.resolveInputsForFunctionBlock(
208+
ctx,
209+
'function',
210+
{ code: "prompt = '''\nSummary: <Producer.result>\n'''\nreturn prompt" },
211+
block
212+
)
213+
214+
expect(result.resolvedInputs.code).toBe(
215+
"prompt = '''\nSummary: ''' + json.dumps(globals()[\"__blockRef_0\"]) + '''\n'''\nreturn prompt"
216+
)
217+
expect(result.displayInputs.code).toBe(
218+
"prompt = '''\nSummary: \"hello world\"\n'''\nreturn prompt"
219+
)
220+
expect(result.contextVariables).toEqual({ __blockRef_0: 'hello world' })
221+
})
222+
185223
it('ignores Python comment quotes before later block references', () => {
186224
const { block, ctx, resolver } = createResolver('python')
187225

apps/sim/executor/variables/resolver.ts

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ export const FUNCTION_BLOCK_DISPLAY_CODE_KEY = '_runtimeDisplayCode'
2424
const logger = createLogger('VariableResolver')
2525

2626
type ShellQuoteContext = 'single' | 'double' | null
27-
type CodeStringQuoteContext = ShellQuoteContext | 'template'
27+
type CodeStringQuoteContext = ShellQuoteContext | 'triple-single' | 'triple-double' | 'template'
2828
type CodeScanMode =
2929
| { type: 'normal' }
3030
| { type: 'single' }
3131
| { type: 'double' }
32+
| { type: 'triple-single' }
33+
| { type: 'triple-double' }
3234
| { type: 'template' }
3335
| { type: 'template-expression'; depth: number }
3436
| { type: 'line-comment' }
@@ -362,8 +364,8 @@ export class VariableResolver {
362364
if (language === 'python') {
363365
const expression = `globals()[${JSON.stringify(varName)}]`
364366
const quoteContext = this.getCodeStringQuoteContext(template, matchIndex, language)
365-
if (quoteContext === 'single' || quoteContext === 'double') {
366-
const quote = quoteContext === 'single' ? "'" : '"'
367+
if (this.isPythonStringQuoteContext(quoteContext)) {
368+
const quote = this.getCodeStringQuoteToken(quoteContext)
367369
return `${quote} + json.dumps(${expression}) + ${quote}`
368370
}
369371
return expression
@@ -379,12 +381,32 @@ export class VariableResolver {
379381
return `\${JSON.stringify(${expression})}`
380382
}
381383
if (quoteContext === 'single' || quoteContext === 'double') {
382-
const quote = quoteContext === 'single' ? "'" : '"'
384+
const quote = this.getCodeStringQuoteToken(quoteContext)
383385
return `${quote} + JSON.stringify(${expression}) + ${quote}`
384386
}
385387
return expression
386388
}
387389

390+
private isPythonStringQuoteContext(
391+
quoteContext: CodeStringQuoteContext
392+
): quoteContext is 'single' | 'double' | 'triple-single' | 'triple-double' {
393+
return (
394+
quoteContext === 'single' ||
395+
quoteContext === 'double' ||
396+
quoteContext === 'triple-single' ||
397+
quoteContext === 'triple-double'
398+
)
399+
}
400+
401+
private getCodeStringQuoteToken(
402+
quoteContext: 'single' | 'double' | 'triple-single' | 'triple-double'
403+
): string {
404+
if (quoteContext === 'single') return "'"
405+
if (quoteContext === 'double') return '"'
406+
if (quoteContext === 'triple-single') return "'''"
407+
return '"""'
408+
}
409+
388410
private formatDisplayValueForCodeContext(
389411
value: unknown,
390412
language: string | undefined,
@@ -461,6 +483,15 @@ export class VariableResolver {
461483
continue
462484
}
463485

486+
if (mode.type === 'triple-single' || mode.type === 'triple-double') {
487+
const quote = mode.type === 'triple-single' ? "'" : '"'
488+
if (char === quote && next === quote && template[i + 2] === quote) {
489+
modes.pop()
490+
i += 2
491+
}
492+
continue
493+
}
494+
464495
if (mode.type === 'template') {
465496
if (char === '\\') {
466497
i++
@@ -488,6 +519,16 @@ export class VariableResolver {
488519
i++
489520
continue
490521
}
522+
if (isPython && char === "'" && next === "'" && template[i + 2] === "'") {
523+
modes.push({ type: 'triple-single' })
524+
i += 2
525+
continue
526+
}
527+
if (isPython && char === '"' && next === '"' && template[i + 2] === '"') {
528+
modes.push({ type: 'triple-double' })
529+
i += 2
530+
continue
531+
}
491532
if (char === "'") {
492533
modes.push({ type: 'single' })
493534
continue
@@ -527,7 +568,13 @@ export class VariableResolver {
527568
i++
528569
continue
529570
}
530-
if (char === "'") {
571+
if (isPython && char === "'" && next === "'" && template[i + 2] === "'") {
572+
modes.push({ type: 'triple-single' })
573+
i += 2
574+
} else if (isPython && char === '"' && next === '"' && template[i + 2] === '"') {
575+
modes.push({ type: 'triple-double' })
576+
i += 2
577+
} else if (char === "'") {
531578
modes.push({ type: 'single' })
532579
} else if (char === '"') {
533580
modes.push({ type: 'double' })
@@ -537,7 +584,13 @@ export class VariableResolver {
537584
}
538585

539586
const mode = modes[modes.length - 1]
540-
if (mode.type === 'single' || mode.type === 'double' || mode.type === 'template') {
587+
if (
588+
mode.type === 'single' ||
589+
mode.type === 'double' ||
590+
mode.type === 'triple-single' ||
591+
mode.type === 'triple-double' ||
592+
mode.type === 'template'
593+
) {
541594
return mode.type
542595
}
543596
return null

0 commit comments

Comments
 (0)