Skip to content

Commit a7ae33b

Browse files
committed
Add support for duration units to timeout
1 parent f1b52ed commit a7ae33b

3 files changed

Lines changed: 31 additions & 5 deletions

File tree

packages/opencode/src/cli/cmd/run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ export const RunCommand = cmd({
8383
describe: "title for the session (uses truncated prompt if no value provided)",
8484
})
8585
.option("timeout", {
86-
type: "number",
87-
describe: "timeout in milliseconds for each AI request (default: 300000 ms, 5 mins)",
86+
type: "string",
87+
describe: "timeout for each AI request (e.g., '60s', '2m', '1h', '500ms', default: '5m')",
8888
})
8989
},
9090
handler: async (args) => {

packages/opencode/src/session/prompt.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { $, fileURLToPath } from "bun"
5151
import { ConfigMarkdown } from "../config/markdown"
5252
import { SessionSummary } from "./summary"
5353
import { Config } from "@/config/config"
54+
import { parseTimeout } from "@/util/timeout"
5455

5556
export namespace SessionPrompt {
5657
const log = Log.create({ service: "session.prompt" })
@@ -98,7 +99,7 @@ export namespace SessionPrompt {
9899
noReply: z.boolean().optional(),
99100
system: z.string().optional(),
100101
tools: z.record(z.string(), z.boolean()).optional(),
101-
timeout: z.number().int().positive().optional(),
102+
timeout: z.string().optional(),
102103
parts: z.array(
103104
z.discriminatedUnion("type", [
104105
MessageV2.TextPart.omit({
@@ -165,7 +166,7 @@ export namespace SessionPrompt {
165166
let runtimeOptions: Record<string, unknown> | undefined = undefined
166167
if (input.timeout) {
167168
runtimeOptions ??= {}
168-
runtimeOptions.timeout = input.timeout
169+
runtimeOptions.timeout = parseTimeout(input.timeout)
169170
}
170171

171172
const agent = await Agent.get(input.agent ?? "build")
@@ -1489,7 +1490,7 @@ export namespace SessionPrompt {
14891490
model: z.string().optional(),
14901491
arguments: z.string(),
14911492
command: z.string(),
1492-
timeout: z.number().int().positive().optional(),
1493+
timeout: z.string().optional(),
14931494
})
14941495
export type CommandInput = z.infer<typeof CommandInput>
14951496
const bashRegex = /!`([^`]+)`/g

packages/opencode/src/util/timeout.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,28 @@ export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
1212
}),
1313
])
1414
}
15+
16+
export function parseTimeout(timeout: string): number {
17+
const match = timeout.match(/^(\d+(?:\.\d+)?)\s*(h|m|s|ms)?$/)
18+
if (!match) {
19+
throw new Error(
20+
`Invalid timeout format (${timeout}). Expected format: "60s", "2m", "1h", "500ms".`,
21+
)
22+
}
23+
24+
const value = parseFloat(match[1])
25+
const unit = match[2] || "ms"
26+
27+
switch (unit) {
28+
case "h":
29+
return value * 60 * 60 * 1000
30+
case "m":
31+
return value * 60 * 1000
32+
case "s":
33+
return value * 1000
34+
case "ms":
35+
return value
36+
default:
37+
throw new Error(`Invalid timeout unit (${unit}). Expected h, m, s, or ms.`)
38+
}
39+
}

0 commit comments

Comments
 (0)