mention.test.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import { expect, test } from "bun:test"
  2. import type { PromptInput } from "@opencode-ai/schema"
  3. import {
  4. expandPromptInputPastedText,
  5. realignPromptInputMentions,
  6. realignPromptMentions,
  7. } from "../../src/prompt/mention"
  8. test("realigns reordered, duplicate, deleted, and prefix-related mentions", () => {
  9. const mentions = [
  10. { start: 0, end: 4, text: "@one" },
  11. { start: 5, end: 10, text: "@same" },
  12. { start: 11, end: 15, text: "@two" },
  13. { start: 16, end: 21, text: "@same" },
  14. { start: 22, end: 27, text: "@gone" },
  15. ]
  16. const before = structuredClone(mentions)
  17. expect(realignPromptMentions("@two @same @one @same", mentions)).toEqual([
  18. { start: 11, end: 15, text: "@one" },
  19. { start: 5, end: 10, text: "@same" },
  20. { start: 0, end: 4, text: "@two" },
  21. { start: 16, end: 21, text: "@same" },
  22. undefined,
  23. ])
  24. expect(mentions).toEqual(before)
  25. expect(
  26. realignPromptMentions("@foobar @foo", [
  27. { start: 0, end: 4, text: "@foo" },
  28. { start: 5, end: 12, text: "@foobar" },
  29. ]),
  30. ).toEqual([
  31. { start: 8, end: 12, text: "@foo" },
  32. { start: 0, end: 7, text: "@foobar" },
  33. ])
  34. expect(
  35. realignPromptMentions("@foobar @foobar", [
  36. { start: 0, end: 4, text: "@foo" },
  37. { start: 13, end: 20, text: "@foobar" },
  38. ]),
  39. ).toEqual([undefined, { start: 8, end: 15, text: "@foobar" }])
  40. expect(
  41. realignPromptMentions("@same @same", [
  42. { start: 100, end: 105, text: "@same" },
  43. { start: 4, end: 9, text: "@same" },
  44. ]),
  45. ).toEqual([
  46. { start: 6, end: 11, text: "@same" },
  47. { start: 0, end: 5, text: "@same" },
  48. ])
  49. })
  50. test("realigns mixed prompt attachments without mutation", () => {
  51. const input = {
  52. text: "@file @gone @agent",
  53. files: [
  54. { uri: "file:///file", mention: { start: 0, end: 5, text: "@file" } },
  55. { uri: "data:image/png;base64,YWJj", name: "image.png" },
  56. { uri: "file:///gone", mention: { start: 6, end: 11, text: "@gone" } },
  57. ],
  58. agents: [{ name: "agent", mention: { start: 12, end: 18, text: "@agent" } }],
  59. } satisfies PromptInput.Prompt
  60. const before = structuredClone(input)
  61. const output = realignPromptInputMentions("@agent then @file", input)
  62. expect(output).toEqual({
  63. text: "@agent then @file",
  64. files: [
  65. { uri: "file:///file", mention: { start: 12, end: 17, text: "@file" } },
  66. { uri: "data:image/png;base64,YWJj", name: "image.png", mention: undefined },
  67. ],
  68. agents: [{ name: "agent", mention: { start: 0, end: 6, text: "@agent" } }],
  69. })
  70. expect(input).toEqual(before)
  71. expect(output.files).not.toBe(input.files)
  72. expect(output.agents).not.toBe(input.agents)
  73. })
  74. test("shifts mention hints when pasted placeholders expand", () => {
  75. const input = {
  76. text: "[Pasted text #1] @same @same",
  77. files: [{ uri: "file:///same", mention: { start: 23, end: 28, text: "@same" } }],
  78. } satisfies PromptInput.Prompt
  79. const expanded = expandPromptInputPastedText(input, [
  80. { text: "a much longer pasted value", source: { start: 0, end: 16 } },
  81. ])
  82. expect(expanded.files?.[0]?.mention).toEqual({ start: 33, end: 38, text: "@same" })
  83. expect(realignPromptInputMentions(expanded.text, expanded).files?.[0]?.mention).toEqual({
  84. start: 33,
  85. end: 38,
  86. text: "@same",
  87. })
  88. })