experimental devbox support
This commit is contained in:
@@ -20,6 +20,34 @@ const ChatWebSearchEngineSchema = z.preprocess(
|
||||
z.enum(["exa", "searxng"]).default("exa")
|
||||
);
|
||||
|
||||
const BooleanFlagSchema = z.preprocess((value) => {
|
||||
if (typeof value !== "string") return value;
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (!normalized) return undefined;
|
||||
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
||||
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
||||
return value;
|
||||
}, z.boolean().default(false));
|
||||
|
||||
const OptionalTrimmedStringSchema = z.preprocess(
|
||||
(value) => (typeof value === "string" && value.trim() === "" ? undefined : value),
|
||||
z.string().trim().min(1).optional()
|
||||
);
|
||||
|
||||
function defaultedPositiveInt(defaultValue: number) {
|
||||
return z.preprocess(
|
||||
(value) => (typeof value === "string" && value.trim() === "" ? undefined : value),
|
||||
z.coerce.number().int().positive().default(defaultValue)
|
||||
);
|
||||
}
|
||||
|
||||
function defaultedTrimmedString(defaultValue: string) {
|
||||
return z.preprocess(
|
||||
(value) => (typeof value === "string" && value.trim() === "" ? undefined : value),
|
||||
z.string().trim().min(1).default(defaultValue)
|
||||
);
|
||||
}
|
||||
|
||||
const EnvSchema = z.object({
|
||||
PORT: z.coerce.number().int().positive().default(8787),
|
||||
HOST: z.string().default("0.0.0.0"),
|
||||
@@ -36,6 +64,17 @@ const EnvSchema = z.object({
|
||||
// Chat-mode web_search tool configuration. Search mode remains Exa-only for now.
|
||||
CHAT_WEB_SEARCH_ENGINE: ChatWebSearchEngineSchema,
|
||||
SEARXNG_BASE_URL: OptionalUrlSchema,
|
||||
|
||||
// Optional chat-mode Codex tool. When enabled, the server SSHes into a remote
|
||||
// devbox and runs `codex exec` in a persistent scratch directory there.
|
||||
CHAT_CODEX_TOOL_ENABLED: BooleanFlagSchema,
|
||||
CHAT_CODEX_REMOTE_HOST: OptionalTrimmedStringSchema,
|
||||
CHAT_CODEX_REMOTE_USER: OptionalTrimmedStringSchema,
|
||||
CHAT_CODEX_REMOTE_PORT: defaultedPositiveInt(22),
|
||||
CHAT_CODEX_REMOTE_WORKDIR: defaultedTrimmedString("/workspace/sybil-codex"),
|
||||
CHAT_CODEX_SSH_KEY_PATH: OptionalTrimmedStringSchema,
|
||||
CHAT_CODEX_SSH_PRIVATE_KEY_B64: OptionalTrimmedStringSchema,
|
||||
CHAT_CODEX_EXEC_TIMEOUT_MS: defaultedPositiveInt(600_000),
|
||||
}).superRefine((value, ctx) => {
|
||||
if (value.CHAT_WEB_SEARCH_ENGINE === "searxng" && !value.SEARXNG_BASE_URL) {
|
||||
ctx.addIssue({
|
||||
@@ -44,6 +83,14 @@ const EnvSchema = z.object({
|
||||
message: "SEARXNG_BASE_URL is required when CHAT_WEB_SEARCH_ENGINE=searxng",
|
||||
});
|
||||
}
|
||||
|
||||
if (value.CHAT_CODEX_TOOL_ENABLED && !value.CHAT_CODEX_REMOTE_HOST) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
path: ["CHAT_CODEX_REMOTE_HOST"],
|
||||
message: "CHAT_CODEX_REMOTE_HOST is required when CHAT_CODEX_TOOL_ENABLED=true",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export type Env = z.infer<typeof EnvSchema>;
|
||||
|
||||
Reference in New Issue
Block a user