Skip to content

Commit 3591372

Browse files
authored
feat(tool): increase question header and label limits (#9201)
1 parent 90f848f commit 3591372

File tree

2 files changed

+109
-2
lines changed

2 files changed

+109
-2
lines changed

packages/opencode/src/question/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export namespace Question {
1010

1111
export const Option = z
1212
.object({
13-
label: z.string().describe("Display text (1-5 words, concise)"),
13+
label: z.string().max(30).describe("Display text (1-5 words, concise)"),
1414
description: z.string().describe("Explanation of choice"),
1515
})
1616
.meta({
@@ -21,7 +21,7 @@ export namespace Question {
2121
export const Info = z
2222
.object({
2323
question: z.string().describe("Complete question"),
24-
header: z.string().max(12).describe("Very short label (max 12 chars)"),
24+
header: z.string().max(30).describe("Very short label (max 30 chars)"),
2525
options: z.array(Option).describe("Available choices"),
2626
multiple: z.boolean().optional().describe("Allow selecting multiple choices"),
2727
custom: z.boolean().optional().describe("Allow typing a custom answer (default: true)"),
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { describe, expect, test, spyOn, beforeEach, afterEach } from "bun:test"
2+
import { z } from "zod"
3+
import { QuestionTool } from "../../src/tool/question"
4+
import * as QuestionModule from "../../src/question"
5+
6+
const ctx = {
7+
sessionID: "test-session",
8+
messageID: "test-message",
9+
callID: "test-call",
10+
agent: "test-agent",
11+
abort: AbortSignal.any([]),
12+
metadata: () => {},
13+
ask: async () => {},
14+
}
15+
16+
describe("tool.question", () => {
17+
let askSpy: any;
18+
19+
beforeEach(() => {
20+
askSpy = spyOn(QuestionModule.Question, "ask").mockImplementation(async () => {
21+
return []
22+
})
23+
})
24+
25+
afterEach(() => {
26+
askSpy.mockRestore()
27+
})
28+
29+
test("should successfully execute with valid question parameters", async () => {
30+
const tool = await QuestionTool.init()
31+
const questions = [
32+
{
33+
question: "What is your favorite color?",
34+
header: "Color",
35+
options: [
36+
{ label: "Red", description: "The color of passion" },
37+
{ label: "Blue", description: "The color of sky" },
38+
],
39+
multiple: false,
40+
},
41+
]
42+
43+
askSpy.mockResolvedValueOnce([["Red"]])
44+
45+
const result = await tool.execute(
46+
{ questions },
47+
ctx,
48+
)
49+
expect(askSpy).toHaveBeenCalledTimes(1)
50+
expect(result.title).toBe("Asked 1 question")
51+
})
52+
53+
test("should now pass with a header longer than 12 but less than 30 chars", async () => {
54+
const tool = await QuestionTool.init()
55+
const questions = [
56+
{
57+
question: "What is your favorite animal?",
58+
header: "This Header is Over 12",
59+
options: [{ label: "Dog", description: "Man's best friend" }],
60+
},
61+
]
62+
63+
askSpy.mockResolvedValueOnce([["Dog"]])
64+
65+
const result = await tool.execute({ questions }, ctx)
66+
expect(result.output).toContain(`"What is your favorite animal?"="Dog"`)
67+
})
68+
69+
test("should throw an Error for header exceeding 30 characters", async () => {
70+
const tool = await QuestionTool.init()
71+
const questions = [
72+
{
73+
question: "What is your favorite animal?",
74+
header: "This Header is Definitely More Than Thirty Characters Long",
75+
options: [{ label: "Dog", description: "Man's best friend" }],
76+
},
77+
]
78+
try {
79+
await tool.execute({ questions }, ctx)
80+
// If it reaches here, the test should fail
81+
expect(true).toBe(false)
82+
} catch (e: any) {
83+
expect(e).toBeInstanceOf(Error)
84+
expect(e.cause).toBeInstanceOf(z.ZodError)
85+
}
86+
})
87+
88+
test("should throw an Error for label exceeding 30 characters", async () => {
89+
const tool = await QuestionTool.init()
90+
const questions = [
91+
{
92+
question: "A question with a very long label",
93+
header: "Long Label",
94+
options: [{ label: "This is a very, very, very long label that will exceed the limit", description: "A description" }],
95+
},
96+
]
97+
try {
98+
await tool.execute({ questions }, ctx)
99+
// If it reaches here, the test should fail
100+
expect(true).toBe(false)
101+
} catch (e: any) {
102+
expect(e).toBeInstanceOf(Error)
103+
expect(e.cause).toBeInstanceOf(z.ZodError)
104+
}
105+
})
106+
})
107+

0 commit comments

Comments
 (0)