visualizer.e2e.ts 4.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /** Keyless assembled-Web proof for the opt-in Visualizer Host authority. */
  2. import { join } from 'node:path'
  3. import { fileURLToPath } from 'node:url'
  4. import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
  5. import type { AgentHandle } from '@deepseek-ai/dsh-agent'
  6. import type { ReplayProviderConfig } from '@deepseek-ai/dsh-llm-replay'
  7. import { createUserMessage } from '@deepseek-ai/dsh-llm'
  8. import { SessionId } from '@deepseek-ai/dsh-session'
  9. import type {} from '@deepseek-ai/dsh-agent-presets'
  10. import {
  11. assertFixtureInventory,
  12. launchWebScaffold,
  13. recordFixture,
  14. webSnapshotMode,
  15. type WebScaffold,
  16. } from './scaffold.ts'
  17. const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/visualizer-host', import.meta.url))
  18. const FIXTURE = join(SNAPSHOT_DIR, 'session.v2.jsonl')
  19. const PROMPT = 'Call widget_guidelines with the interactive and chart modules, then reply exactly "Guidance loaded." Do not call show_widget.'
  20. const VISUALIZER_TOOLS = ['show_widget', 'widget_guidelines']
  21. const RECORDED_PROVIDER_CATALOG = [{
  22. id: 'deepseek-official',
  23. name: 'DeepSeek',
  24. models: [{
  25. id: 'deepseek-v4-flash',
  26. name: 'DeepSeek-V4-Flash',
  27. contextWindow: 1_000_000,
  28. defaultMaxTokens: 256_000,
  29. reasoningEfforts: ['off', 'low', 'high', 'max'],
  30. defaultReasoningEffort: 'high',
  31. }],
  32. }] satisfies readonly ReplayProviderConfig[]
  33. const MODE = webSnapshotMode()
  34. describe('Visualizer Host explicit composition', () => {
  35. let scaffold: WebScaffold
  36. let agentHandle: AgentHandle
  37. let authorityId: string
  38. beforeAll(async () => {
  39. scaffold = await launchWebScaffold(MODE === 'record'
  40. ? {}
  41. : { replayFixture: FIXTURE, replayProviders: [...RECORDED_PROVIDER_CATALOG] })
  42. const presetKey = await scaffold.ctx.agentPresets.standingKeyFor('standard')
  43. authorityId = await scaffold.ctx.loader.create({ name: '@deepseek-ai/dsh-tool-visualizer' })
  44. await scaffold.ctx.loader.await()
  45. await vi.waitFor(() => {
  46. expect(scaffold.ctx.tools.schemas(presetKey).map(schema => schema.name)
  47. .filter(name => VISUALIZER_TOOLS.includes(name)).sort()).toEqual(VISUALIZER_TOOLS)
  48. })
  49. agentHandle = await scaffold.ctx.agents.create({
  50. sessionId: SessionId('visualizer-host-snapshot'),
  51. meta: { cwd: scaffold.workspaceCwd, agentPreset: 'standard' },
  52. agentOptions: { provider: 'deepseek-official', model: 'deepseek-v4-flash' },
  53. setup: agentCtx => scaffold.ctx.agentPresets.mount(agentCtx, 'standard').then(() => undefined),
  54. })
  55. expect(scaffold.ctx.tools.schemas(agentHandle.agent).map(schema => schema.name)
  56. .filter(name => VISUALIZER_TOOLS.includes(name)).sort()).toEqual(VISUALIZER_TOOLS)
  57. agentHandle.agent.followup(createUserMessage({
  58. content: [{ type: 'text', text: PROMPT }],
  59. source: { kind: 'user' },
  60. }))
  61. await agentHandle.agent.whenIdle()
  62. if (MODE === 'record') await recordFixture(scaffold, agentHandle.agent.session.id, FIXTURE)
  63. })
  64. afterAll(async () => {
  65. const failures: unknown[] = []
  66. await agentHandle?.dispose().catch((error: unknown) => failures.push(error))
  67. if (authorityId !== undefined) {
  68. await scaffold.ctx.loader.remove(authorityId).catch((error: unknown) => failures.push(error))
  69. }
  70. await scaffold?.close().catch((error: unknown) => failures.push(error))
  71. if (failures.length === 1) throw failures[0]
  72. if (failures.length > 1) throw new AggregateError(failures, 'Visualizer Host snapshot teardown failed')
  73. })
  74. it('records the prompt plus two schemas from an explicit Host composition', async () => {
  75. expect(scaffold.ctx.get('visualizer')).toBeDefined()
  76. const requestHeader = agentHandle.agent.session.requestHeader()
  77. if (requestHeader === undefined) throw new Error('the Visualizer Host scenario issued no model request')
  78. expect(requestHeader.system).toContain('Use show_widget for a temporary inline visual')
  79. expect(requestHeader.tools?.map(schema => schema.name).filter(name => VISUALIZER_TOOLS.includes(name)).sort())
  80. .toEqual(VISUALIZER_TOOLS)
  81. expect(requestHeader.tools?.toSorted((left, right) => left.name.localeCompare(right.name)))
  82. .toEqual(scaffold.ctx.tools.schemas(agentHandle.agent).toSorted((left, right) => left.name.localeCompare(right.name)))
  83. await assertFixtureInventory(SNAPSHOT_DIR, [
  84. 'session.jsonl',
  85. 'system-prompt.expected.md',
  86. 'tool-schemas.expected.json',
  87. ])
  88. })
  89. })