Run tasks on Codex beside Claude; drop turn caps and mid-turn snapshots
This commit is contained in:
Vendored
+26
-10
@@ -4,7 +4,19 @@ import { markdown } from "./markdown.js";
|
||||
import { previewURL } from "./preview.js";
|
||||
import { currentSession, findTask, focusTab, focusTask, onEach, pinSnapshot, setFocus, state } from "./state.js";
|
||||
import { taskStyle } from "./taskcolor.js";
|
||||
export const models = ["claude-opus-5-5", "claude-sonnet-5-5", "claude-haiku-5-5", "claude-fable-5-1"];
|
||||
export const models = [
|
||||
"claude-opus-5-5",
|
||||
"claude-sonnet-5-5",
|
||||
"claude-haiku-5-5",
|
||||
"claude-fable-5-1",
|
||||
"gpt-6.1-sol",
|
||||
"gpt-6-astra",
|
||||
"gpt-6-sol",
|
||||
"gpt-6-luna",
|
||||
"gpt-5.6-sol",
|
||||
"gpt-5.6-terra",
|
||||
"gpt-5.6-luna",
|
||||
];
|
||||
const quietReply = "NO_REPLY";
|
||||
const taskSource = {
|
||||
key: () => state.selectedTaskId,
|
||||
@@ -76,7 +88,7 @@ function taskHead(rerender) {
|
||||
return [h("div", { class: "head-actions" }, task.status)];
|
||||
}
|
||||
const target = state.projects.find((p) => p.id === task.project_id)?.default_branch ?? "the default branch";
|
||||
const busy = sess?.state === "running" || sess?.state === "queued";
|
||||
const busy = sess?.state === "running";
|
||||
const held = task.merge_queued_at !== undefined;
|
||||
const merge = h("button", {
|
||||
class: "merge-button",
|
||||
@@ -239,7 +251,7 @@ export function mountChat(root, src, makeHead) {
|
||||
const sess = src.session();
|
||||
const live = sess && sess.state !== "completed" ? sess : undefined;
|
||||
composerModel = live ? live.model || context.get(live.id)?.model || "" : "";
|
||||
const form = composeForm(src, key, live?.id, live?.state ?? "idle", composerModel, showPending);
|
||||
const form = composeForm(src, key, live?.id, live?.state ?? "idle", composerModel, live?.vendor, showPending);
|
||||
const old = composer.querySelector("textarea");
|
||||
const caret = old !== null && document.activeElement === old ? [old.selectionStart, old.selectionEnd] : undefined;
|
||||
replace(composer, form);
|
||||
@@ -589,20 +601,24 @@ function releaseImages(imgs) {
|
||||
}
|
||||
}
|
||||
const modelChoices = new Map();
|
||||
function modelSelect(key, current) {
|
||||
const options = current && !models.includes(current) ? [current, ...models] : models;
|
||||
function vendorOf(model) {
|
||||
return model.startsWith("gpt-") ? "codex" : "claude";
|
||||
}
|
||||
function modelSelect(key, current, vendor) {
|
||||
const offered = vendor ? models.filter((m) => vendorOf(m) === vendor) : models;
|
||||
const options = current && !offered.includes(current) ? [current, ...offered] : offered;
|
||||
const select = h("select", { title: "Model for the next turn" }, ...options.map((m) => h("option", { value: m }, m)));
|
||||
select.value = modelChoices.get(key) ?? (current || models[0]);
|
||||
select.value = modelChoices.get(key) ?? (current || options[0]);
|
||||
select.onchange = () => {
|
||||
modelChoices.set(key, select.value);
|
||||
};
|
||||
return select;
|
||||
}
|
||||
function composeForm(src, key, sessionId, sessionState, currentModel, showPending) {
|
||||
function composeForm(src, key, sessionId, sessionState, currentModel, vendor, showPending) {
|
||||
const text = h("textarea", { placeholder: src.placeholder(sessionState), rows: 3 });
|
||||
const clearDraft = keepDraft(text, `message:${key}`);
|
||||
const send = h("button", { type: "submit", disabled: !src.canSend(sessionState) }, "Send");
|
||||
const interrupt = h("button", { type: "button", class: "danger", disabled: sessionState !== "running" && sessionState !== "queued" }, sessionState === "queued" ? "Cancel queued turn" : "Interrupt");
|
||||
const interrupt = h("button", { type: "button", class: "danger", disabled: sessionState !== "running" }, "Interrupt");
|
||||
interrupt.onclick = async () => {
|
||||
if (!sessionId) {
|
||||
return;
|
||||
@@ -615,7 +631,7 @@ function composeForm(src, key, sessionId, sessionState, currentModel, showPendin
|
||||
}
|
||||
};
|
||||
const modelKey = `message:${sessionId ?? key}`;
|
||||
const model = modelSelect(modelKey, currentModel);
|
||||
const model = modelSelect(modelKey, currentModel, vendor);
|
||||
const form = h("form", { class: "compose" });
|
||||
const tray = imageTray(form, text, `message:${key}`);
|
||||
form.append(tray.el, text, h("div", { class: "compose-actions" }, model, interrupt, send));
|
||||
@@ -888,7 +904,7 @@ function messageImages(ids) {
|
||||
export async function confirmMerge(taskId) {
|
||||
const task = findTask(taskId);
|
||||
const sessionState = currentSession(taskId)?.state;
|
||||
if (!task || task.status !== "active" || task.merge_queued_at !== undefined || sessionState === "running" || sessionState === "queued") {
|
||||
if (!task || task.status !== "active" || task.merge_queued_at !== undefined || sessionState === "running") {
|
||||
return;
|
||||
}
|
||||
const target = state.projects.find((p) => p.id === task.project_id)?.default_branch ?? "the default branch";
|
||||
|
||||
Reference in New Issue
Block a user