agent-variant.test.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import { describe, expect, test } from "bun:test";
  2. import type { PluginConfig } from "../config";
  3. import {
  4. applyAgentVariant,
  5. normalizeAgentName,
  6. resolveAgentVariant,
  7. resolveRuntimeAgentName,
  8. rewriteDisplayNameMentions,
  9. } from "./agent-variant";
  10. describe("normalizeAgentName", () => {
  11. test("returns name unchanged if no @ prefix", () => {
  12. expect(normalizeAgentName("oracle")).toBe("oracle");
  13. });
  14. test("strips @ prefix from agent name", () => {
  15. expect(normalizeAgentName("@oracle")).toBe("oracle");
  16. });
  17. test("trims whitespace", () => {
  18. expect(normalizeAgentName(" oracle ")).toBe("oracle");
  19. });
  20. test("handles @ prefix with whitespace", () => {
  21. expect(normalizeAgentName(" @explore ")).toBe("explore");
  22. });
  23. test("handles empty string", () => {
  24. expect(normalizeAgentName("")).toBe("");
  25. });
  26. });
  27. describe("resolveAgentVariant", () => {
  28. test("returns undefined when config is undefined", () => {
  29. expect(resolveAgentVariant(undefined, "oracle")).toBeUndefined();
  30. });
  31. test("returns undefined when agents is undefined", () => {
  32. const config = {} as PluginConfig;
  33. expect(resolveAgentVariant(config, "oracle")).toBeUndefined();
  34. });
  35. test("returns undefined when agent has no variant", () => {
  36. const config = {
  37. agents: {
  38. oracle: { model: "gpt-4" },
  39. },
  40. } as PluginConfig;
  41. expect(resolveAgentVariant(config, "oracle")).toBeUndefined();
  42. });
  43. test("returns variant when configured", () => {
  44. const config = {
  45. agents: {
  46. oracle: { variant: "high" },
  47. },
  48. } as PluginConfig;
  49. expect(resolveAgentVariant(config, "oracle")).toBe("high");
  50. });
  51. test("normalizes agent name with @ prefix", () => {
  52. const config = {
  53. agents: {
  54. oracle: { variant: "low" },
  55. },
  56. } as PluginConfig;
  57. expect(resolveAgentVariant(config, "@oracle")).toBe("low");
  58. });
  59. test("returns undefined for empty string variant", () => {
  60. const config = {
  61. agents: {
  62. oracle: { variant: "" },
  63. },
  64. } as PluginConfig;
  65. expect(resolveAgentVariant(config, "oracle")).toBeUndefined();
  66. });
  67. test("returns undefined for whitespace-only variant", () => {
  68. const config = {
  69. agents: {
  70. oracle: { variant: " " },
  71. },
  72. } as PluginConfig;
  73. expect(resolveAgentVariant(config, "oracle")).toBeUndefined();
  74. });
  75. test("trims variant whitespace", () => {
  76. const config = {
  77. agents: {
  78. oracle: { variant: " medium " },
  79. },
  80. } as PluginConfig;
  81. expect(resolveAgentVariant(config, "oracle")).toBe("medium");
  82. });
  83. test("returns undefined for non-string variant", () => {
  84. const config = {
  85. agents: {
  86. oracle: { variant: 123 as unknown as string },
  87. },
  88. } as PluginConfig;
  89. expect(resolveAgentVariant(config, "oracle")).toBeUndefined();
  90. });
  91. test("resolves displayName alias to internal agent for variant lookup", () => {
  92. const config = {
  93. agents: {
  94. oracle: { displayName: "advisor", variant: "high" },
  95. },
  96. } as PluginConfig;
  97. expect(resolveAgentVariant(config, "@advisor")).toBe("high");
  98. });
  99. });
  100. describe("resolveRuntimeAgentName", () => {
  101. test("keeps internal agent names unchanged", () => {
  102. const config = {
  103. agents: {
  104. oracle: { displayName: "advisor" },
  105. },
  106. } as PluginConfig;
  107. expect(resolveRuntimeAgentName(config, "oracle")).toBe("oracle");
  108. });
  109. test("resolves displayName to internal name", () => {
  110. const config = {
  111. agents: {
  112. oracle: { displayName: "advisor" },
  113. },
  114. } as PluginConfig;
  115. expect(resolveRuntimeAgentName(config, "advisor")).toBe("oracle");
  116. });
  117. test("resolves displayName with @ prefix and whitespace", () => {
  118. const config = {
  119. agents: {
  120. oracle: { displayName: "advisor" },
  121. },
  122. } as PluginConfig;
  123. expect(resolveRuntimeAgentName(config, " @advisor ")).toBe("oracle");
  124. });
  125. test("resolves displayName configured via legacy alias key", () => {
  126. const config = {
  127. agents: {
  128. explore: { displayName: "researcher" },
  129. },
  130. } as PluginConfig;
  131. expect(resolveRuntimeAgentName(config, "researcher")).toBe("explorer");
  132. });
  133. test("returns normalized name when no displayName match exists", () => {
  134. const config = {
  135. agents: {
  136. oracle: { displayName: "advisor" },
  137. },
  138. } as PluginConfig;
  139. expect(resolveRuntimeAgentName(config, " @unknown ")).toBe("unknown");
  140. });
  141. });
  142. describe("rewriteDisplayNameMentions", () => {
  143. test("rewrites displayName mentions to internal names for direct invocation", () => {
  144. const config = {
  145. agents: {
  146. oracle: { displayName: "advisor" },
  147. },
  148. } as PluginConfig;
  149. expect(rewriteDisplayNameMentions(config, "ask @advisor about this")).toBe(
  150. "ask @oracle about this"
  151. );
  152. });
  153. test("keeps internal mentions working while rewriting aliases", () => {
  154. const config = {
  155. agents: {
  156. oracle: { displayName: "advisor" },
  157. },
  158. } as PluginConfig;
  159. expect(
  160. rewriteDisplayNameMentions(config, "compare @advisor with @oracle")
  161. ).toBe("compare @oracle with @oracle");
  162. });
  163. test("does not rewrite embedded text such as email addresses", () => {
  164. const config = {
  165. agents: {
  166. oracle: { displayName: "advisor" },
  167. },
  168. } as PluginConfig;
  169. expect(
  170. rewriteDisplayNameMentions(
  171. config,
  172. "email foo@advisor.com and ask @advisor directly"
  173. )
  174. ).toBe("email foo@advisor.com and ask @oracle directly");
  175. });
  176. test("resolves custom agents by displayName for variant/runtime lookups", () => {
  177. const config = {
  178. agents: {
  179. "custom-reviewer": {
  180. displayName: "reviewer",
  181. variant: "high",
  182. model: "openai/gpt-5.5",
  183. },
  184. },
  185. } as PluginConfig;
  186. expect(resolveRuntimeAgentName(config, "@reviewer")).toBe(
  187. "custom-reviewer"
  188. );
  189. expect(
  190. rewriteDisplayNameMentions(config, "ask @reviewer for details")
  191. ).toBe("ask @custom-reviewer for details");
  192. expect(resolveAgentVariant(config, "@reviewer")).toBe("high");
  193. });
  194. });
  195. describe("applyAgentVariant", () => {
  196. test("returns body unchanged when variant is undefined", () => {
  197. const body = { agent: "oracle", parts: [] };
  198. const result = applyAgentVariant(undefined, body);
  199. expect(result).toEqual(body);
  200. expect(result).toBe(body); // Same reference
  201. });
  202. test("returns body unchanged when body already has variant", () => {
  203. const body = { agent: "oracle", variant: "medium", parts: [] };
  204. const result = applyAgentVariant("high", body);
  205. expect(result.variant).toBe("medium");
  206. expect(result).toBe(body); // Same reference
  207. });
  208. test("applies variant to body without variant", () => {
  209. const body = { agent: "oracle", parts: [] };
  210. const result = applyAgentVariant("high", body);
  211. expect(result.variant).toBe("high");
  212. expect(result.agent).toBe("oracle");
  213. expect(result).not.toBe(body); // New object
  214. });
  215. test("preserves all existing body properties", () => {
  216. const body = {
  217. agent: "oracle",
  218. parts: [{ type: "text" as const, text: "hello" }],
  219. tools: { task: false },
  220. };
  221. const result = applyAgentVariant("low", body);
  222. expect(result.agent).toBe("oracle");
  223. expect(result.parts).toEqual([{ type: "text", text: "hello" }]);
  224. expect(result.tools).toEqual({ task: false });
  225. expect(result.variant).toBe("low");
  226. });
  227. });