feat(tui): add quark timeline experiment
This commit is contained in:
parent
e6607fb58d
commit
daf8e539bf
22 changed files with 2804 additions and 122 deletions
76
script/quark-group-drive.ts
Normal file
76
script/quark-group-drive.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { Effect, Stream } from "effect"
|
||||
import { defineScript, Llm } from "opencode-drive"
|
||||
|
||||
const marker = "QUARK_GROUP_COMPLETE"
|
||||
|
||||
export default defineScript({
|
||||
project: {
|
||||
git: true,
|
||||
files: {
|
||||
"src/one.ts": "export const one = 1\n",
|
||||
"src/two.ts": "export const two = 2\n",
|
||||
},
|
||||
},
|
||||
config: {
|
||||
permissions: [
|
||||
{ action: "*", resource: "*", effect: "ask" },
|
||||
{ action: "read", resource: "*one.ts", effect: "allow" },
|
||||
],
|
||||
},
|
||||
tui: { viewport: { cols: 120, rows: 36 }, recording: true },
|
||||
run: ({ llm, ui }) =>
|
||||
Effect.gen(function* () {
|
||||
yield* ui.waitFor((state) => state.focused.editor)
|
||||
let attempt = 0
|
||||
yield* llm.serve(() => {
|
||||
const current = attempt++
|
||||
if (current === 0)
|
||||
return Stream.make(
|
||||
Llm.toolCall({
|
||||
index: 0,
|
||||
id: "call_read_one",
|
||||
name: "read",
|
||||
input: { path: "src/one.ts" },
|
||||
}),
|
||||
Llm.finish("tool-calls"),
|
||||
)
|
||||
if (current === 1)
|
||||
return Stream.make(
|
||||
Llm.toolCall({
|
||||
index: 0,
|
||||
id: "call_read_two",
|
||||
name: "read",
|
||||
input: { path: "src/two.ts" },
|
||||
}),
|
||||
Llm.finish("tool-calls"),
|
||||
)
|
||||
return Stream.make(Llm.text(marker), Llm.finish("stop"))
|
||||
})
|
||||
yield* ui.submit("Inspect both source modules, then finish.")
|
||||
yield* ui.waitFor("Permission required", { timeout: 15_000 })
|
||||
const frame = yield* ui.capture()
|
||||
const row = frame.lines.findIndex((line) => line.spans.some((span) => span.text.includes("Exploring")))
|
||||
if (row === -1) throw new Error("the exploration summary was not visible")
|
||||
const column = 8
|
||||
const candidates = (yield* ui.state()).elements.filter(
|
||||
(element) =>
|
||||
element.x <= column &&
|
||||
element.x + element.width > column &&
|
||||
element.y <= row &&
|
||||
element.y + element.height > row,
|
||||
)
|
||||
if (candidates.length === 0) throw new Error("the exploration summary had no renderable target")
|
||||
const summary = candidates.reduce((smallest, element) =>
|
||||
element.width * element.height < smallest.width * smallest.height ? element : smallest,
|
||||
)
|
||||
yield* ui.click(summary, { x: column - summary.x, y: row - summary.y })
|
||||
yield* ui.waitFor("src/one.ts")
|
||||
const before = yield* ui.screenshot("group-expanded-pending")
|
||||
yield* ui.enter()
|
||||
yield* ui.waitFor(marker, { timeout: 15_000 })
|
||||
yield* ui.waitFor("src/two.ts")
|
||||
const after = yield* ui.screenshot("group-expanded-complete")
|
||||
yield* Effect.sync(() => console.log(`ARTIFACT group_before=${before}`))
|
||||
yield* Effect.sync(() => console.log(`ARTIFACT group_after=${after}`))
|
||||
}),
|
||||
})
|
||||
46
script/quark-timeline-drive.ts
Normal file
46
script/quark-timeline-drive.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { Effect } from "effect"
|
||||
import { defineScript, Llm } from "opencode-drive"
|
||||
|
||||
const marker = "QUARK_TIMELINE_COMPLETE"
|
||||
const reasoning = Array.from(
|
||||
{ length: 16 },
|
||||
(_, index) => `Reasoning segment ${index + 1} checks streamed timeline updates.`,
|
||||
).join(" ")
|
||||
const response = `${Array.from(
|
||||
{ length: 24 },
|
||||
(_, index) => `Timeline chunk ${index + 1} remains visible and ordered.`,
|
||||
).join(" ")} ${marker}`
|
||||
|
||||
export default defineScript({
|
||||
project: {
|
||||
git: true,
|
||||
files: {
|
||||
"src/example.ts": "export const timeline = true\n",
|
||||
},
|
||||
},
|
||||
tui: { viewport: { cols: 120, rows: 36 } },
|
||||
run: ({ opencode, llm, ui }) =>
|
||||
Effect.gen(function* () {
|
||||
yield* ui.waitFor((state) => state.focused.editor)
|
||||
yield* llm.title(() => Effect.succeed("Timeline comparison"))
|
||||
const started = Date.now()
|
||||
yield* ui.submit("Explain how this project handles its timeline.")
|
||||
yield* llm.send(
|
||||
Llm.reasoning(reasoning, { delay: 1, chunkSize: 8 }),
|
||||
Llm.text(response, { delay: 1, chunkSize: 8 }),
|
||||
)
|
||||
yield* ui.waitFor(marker, { timeout: 30_000 })
|
||||
const session = (yield* opencode.session.list({})).data[0]
|
||||
if (!session) throw new Error("the Drive session was not projected")
|
||||
const assistant = (yield* opencode.message.list({ sessionID: session.id })).data.findLast(
|
||||
(message) => message.type === "assistant",
|
||||
)
|
||||
if (assistant?.type !== "assistant") throw new Error("the assistant message was not projected")
|
||||
if (assistant.content.find((part) => part.type === "reasoning")?.text !== reasoning)
|
||||
throw new Error("the projected reasoning content did not match")
|
||||
if (assistant.content.find((part) => part.type === "text")?.text !== response)
|
||||
throw new Error("the projected text content did not match")
|
||||
if (assistant.finish !== "stop") throw new Error("the projected assistant message did not finish")
|
||||
yield* Effect.sync(() => console.log(`METRIC tui_timeline_drive_ms=${Date.now() - started}`))
|
||||
}),
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue