prompt-content.test.ts 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { describe, expect } from "bun:test"
  2. import type { PromptResponse } from "@agentclientprotocol/sdk"
  3. import { Effect } from "effect"
  4. import { writeFile } from "node:fs/promises"
  5. import path from "node:path"
  6. import { pathToFileURL } from "node:url"
  7. import { cliIt } from "../../lib/cli-process"
  8. import { expectOk } from "./acp-test-client"
  9. import { createAcpClient, initialize, newSession, verifierConfig } from "./helpers"
  10. const tinyPng = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII="
  11. describe("kirincode acp prompt content subprocess", () => {
  12. cliIt.live(
  13. "accepts embedded text resource image and file resource link prompt content",
  14. ({ home, llm, kirincode }) =>
  15. Effect.gen(function* () {
  16. yield* Effect.promise(() => writeFile(path.join(home, "README.md"), "# ACP content smoke\n"))
  17. const acp = yield* createAcpClient(
  18. { kirincode },
  19. { KIRINCODE_CONFIG_CONTENT: JSON.stringify(promptContentConfig(llm.url)) },
  20. )
  21. yield* initialize(acp)
  22. const session = yield* newSession(acp, home)
  23. yield* llm.text("embedded resource accepted")
  24. expectOk(
  25. yield* acp.request<PromptResponse>("session/prompt", {
  26. sessionId: session.sessionId,
  27. prompt: [
  28. { type: "text", text: "Use this embedded resource." },
  29. {
  30. type: "resource",
  31. resource: { uri: "file:///context.txt", mimeType: "text/plain", text: "embedded context" },
  32. },
  33. ],
  34. }),
  35. )
  36. yield* llm.text("image accepted")
  37. expectOk(
  38. yield* acp.request<PromptResponse>("session/prompt", {
  39. sessionId: session.sessionId,
  40. prompt: [
  41. { type: "text", text: "Use this image." },
  42. {
  43. type: "image",
  44. mimeType: "image/png",
  45. data: tinyPng,
  46. },
  47. ],
  48. }),
  49. )
  50. yield* llm.text("file link accepted")
  51. const linked = expectOk(
  52. yield* acp.request<PromptResponse>("session/prompt", {
  53. sessionId: session.sessionId,
  54. prompt: [
  55. { type: "text", text: "Use this linked file." },
  56. {
  57. type: "resource_link",
  58. uri: pathToFileURL(path.join(home, "README.md")).href,
  59. name: "README.md",
  60. mimeType: "text/markdown",
  61. },
  62. ],
  63. }),
  64. )
  65. expect(linked.stopReason).toBe("end_turn")
  66. }),
  67. 60_000,
  68. )
  69. })
  70. function promptContentConfig(llmUrl: string) {
  71. const config = verifierConfig(llmUrl)
  72. return {
  73. ...config,
  74. provider: {
  75. test: {
  76. ...config.provider.test,
  77. models: Object.fromEntries(
  78. Object.entries(config.provider.test.models).map(([id, model]) => [
  79. id,
  80. {
  81. ...model,
  82. attachment: true,
  83. reasoning: true,
  84. },
  85. ]),
  86. ),
  87. },
  88. },
  89. }
  90. }