code-program.client.spec.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. /** Recorded PTC argument validation and historical language selection. */
  2. import { describe, expect, it } from 'vitest'
  3. import { codeProgram } from '../src/client/code-program.ts'
  4. import type { TrajectoryCellProps } from '../src/client/trajectory-record.ts'
  5. const CELL: TrajectoryCellProps = {
  6. index: 1, kind: 'tool', toolName: 'run_code', text: 'run_code · {}', timeSeconds: 1,
  7. inputDetail: JSON.stringify({ code: 'return 42\n', description: 'Compute the answer' }),
  8. }
  9. describe('recorded code programs', () => {
  10. it('keeps the program and arguments verbatim', () => {
  11. expect(codeProgram(CELL)).toEqual({
  12. rawInput: CELL.inputDetail,
  13. source: 'return 42\n', description: 'Compute the answer',
  14. arguments: { code: 'return 42\n', description: 'Compute the answer' }, language: undefined,
  15. })
  16. })
  17. it.each([
  18. ['The program: the body of an async TypeScript function.', 'typescript'],
  19. ['The program: the body of an async Python function.', 'python'],
  20. ['A TypeScript or Python program.', undefined],
  21. ['An executable program.', undefined],
  22. ])('uses the recorded parameter description %s', (description, language) => {
  23. const schemaDetail = JSON.stringify({ parameters: { properties: { code: { description } } } })
  24. expect(codeProgram({ ...CELL, schemaDetail })?.language).toBe(language)
  25. })
  26. it.each([undefined, '{', '{}', 'null', '[]'])('keeps missing or unusable schemas plain: %s', (schemaDetail) => {
  27. expect(codeProgram({ ...CELL, ...(schemaDetail === undefined ? {} : { schemaDetail }) })?.language).toBeUndefined()
  28. })
  29. it('uses the first nonempty source line when a description is unavailable', () => {
  30. const source = '\n const x = 1\nreturn x\n'
  31. for (const description of [undefined, '', ' ']) {
  32. expect(codeProgram({ ...CELL, inputDetail: JSON.stringify({ code: source, description }) }))
  33. .toMatchObject({ source, description: 'const x = 1' })
  34. }
  35. })
  36. it('retains empty source and unknown argument fields for JSON inspection', () => {
  37. expect(codeProgram({ ...CELL, inputDetail: '{"code":"","extra":true}' }))
  38. .toMatchObject({ source: '', description: '', arguments: { code: '', extra: true } })
  39. })
  40. it.each([undefined, '{', '[]', 'null', '42', '{}', '{"code":42}', '{"code":"x","description":[]}' ])(
  41. 'declines incomplete or unsupported arguments: %s', (inputDetail) => {
  42. const cell = { ...CELL }
  43. if (inputDetail === undefined) delete cell.inputDetail
  44. else cell.inputDetail = inputDetail
  45. expect(codeProgram(cell)).toBeUndefined()
  46. },
  47. )
  48. it('uses recorded tool metadata independently of display text', () => {
  49. expect(codeProgram({ ...CELL, text: 'Execute program' })?.source).toBe('return 42\n')
  50. const withoutName = { ...CELL }
  51. delete withoutName.toolName
  52. expect(codeProgram(withoutName)).toBeUndefined()
  53. const rawInput = ' { "code": "return 42" }\n'
  54. expect(codeProgram({ ...CELL, inputDetail: rawInput })?.rawInput).toBe(rawInput)
  55. })
  56. it('does not specialize other tools or non-tool records', () => {
  57. expect(codeProgram({ ...CELL, kind: 'message' })).toBeUndefined()
  58. expect(codeProgram({ ...CELL, toolName: 'run_code_extra' })).toBeUndefined()
  59. expect(codeProgram({ ...CELL, kind: 'subtool' })?.source).toBe('return 42\n')
  60. })
  61. })