refactor(opencode): stop legacy v2 event emission (#33993)
This commit is contained in:
parent
9859b19b93
commit
a1f093a748
7 changed files with 111 additions and 555 deletions
|
|
@ -854,12 +854,12 @@ describe("session.compaction.process", () => {
|
|||
const msg = yield* createUserMessage(session.id, "hello")
|
||||
const msgs = yield* ssn.messages({ sessionID: session.id })
|
||||
const done = yield* Deferred.make<void, Error>()
|
||||
let seen = false
|
||||
const seen: string[] = []
|
||||
const unsub = yield* events.listen((evt) => {
|
||||
seen.push(evt.type)
|
||||
if (evt.type !== SessionCompaction.Event.Compacted.type) return Effect.void
|
||||
if ((evt.data as typeof SessionCompaction.Event.Compacted.data.Type).sessionID !== session.id)
|
||||
return Effect.void
|
||||
seen = true
|
||||
Deferred.doneUnsafe(done, Effect.void)
|
||||
return Effect.void
|
||||
})
|
||||
|
|
@ -874,7 +874,8 @@ describe("session.compaction.process", () => {
|
|||
|
||||
yield* Deferred.await(done).pipe(Effect.timeout("500 millis"))
|
||||
expect(result).toBe("continue")
|
||||
expect(seen).toBe(true)
|
||||
expect(seen).toContain(SessionCompaction.Event.Compacted.type)
|
||||
expect(seen.filter((type) => type.startsWith("session.next."))).toEqual([])
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import { raw, reply, TestLLMServer } from "../lib/llm-server"
|
|||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { SessionEvent } from "@opencode-ai/core/session/event"
|
||||
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
||||
import { LLMEvent } from "@opencode-ai/llm"
|
||||
|
||||
|
|
@ -981,10 +980,9 @@ itProviderError.live("session.processor effect tests fail provider-executed erro
|
|||
const parent = yield* user(chat.id, "provider tool error")
|
||||
const msg = yield* assistant(chat.id, parent.id, path.resolve(dir))
|
||||
const mdl = yield* provider.getModel(ref.providerID, ref.modelID)
|
||||
const settlements: Array<typeof SessionEvent.Tool.Failed.Type> = []
|
||||
const seen: string[] = []
|
||||
const off = yield* events.listen((event) => {
|
||||
if (event.type === SessionEvent.Tool.Failed.type)
|
||||
settlements.push(event as typeof SessionEvent.Tool.Failed.Type)
|
||||
seen.push(event.type)
|
||||
return Effect.void
|
||||
})
|
||||
const handle = yield* processors.create({ assistantMessage: msg, sessionID: chat.id, model: mdl })
|
||||
|
|
@ -1011,19 +1009,15 @@ itProviderError.live("session.processor effect tests fail provider-executed erro
|
|||
const call = parts.find((part): part is SessionV1.ToolPart => part.type === "tool")
|
||||
expect(call?.state.status).toBe("error")
|
||||
if (call?.state.status === "error") expect(call.state.error).toBe("provider boom")
|
||||
expect(settlements).toHaveLength(1)
|
||||
expect(settlements[0]?.data).toMatchObject({
|
||||
callID: "call-1",
|
||||
error: { type: "unknown", message: "provider boom" },
|
||||
result: { type: "error", value: "provider boom" },
|
||||
provider: { executed: true },
|
||||
})
|
||||
expect(seen).toContain(MessageV2.Event.PartUpdated.type)
|
||||
expect(seen).toContain(MessageV2.Event.Updated.type)
|
||||
expect(seen.filter((type) => type.startsWith("session.next."))).toEqual([])
|
||||
}),
|
||||
{ config: cfg },
|
||||
),
|
||||
)
|
||||
|
||||
itFragmentFailure.live("session.processor effect tests flush partial v2 fragments before step failure", () =>
|
||||
itFragmentFailure.live("session.processor effect tests retain partial legacy parts without v2 events", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -1035,14 +1029,8 @@ itFragmentFailure.live("session.processor effect tests flush partial v2 fragment
|
|||
const msg = yield* assistant(chat.id, parent.id, path.resolve(dir))
|
||||
const mdl = yield* provider.getModel(ref.providerID, ref.modelID)
|
||||
const seen: string[] = []
|
||||
let text: string | undefined
|
||||
let reasoning: string | undefined
|
||||
const off = yield* events.listen((event) => {
|
||||
seen.push(event.type)
|
||||
if (event.type === SessionEvent.Text.Ended.type)
|
||||
text = (event.data as typeof SessionEvent.Text.Ended.data.Type).text
|
||||
if (event.type === SessionEvent.Reasoning.Ended.type)
|
||||
reasoning = (event.data as typeof SessionEvent.Reasoning.Ended.data.Type).text
|
||||
return Effect.void
|
||||
})
|
||||
const handle = yield* processors.create({ assistantMessage: msg, sessionID: chat.id, model: mdl })
|
||||
|
|
@ -1067,12 +1055,16 @@ itFragmentFailure.live("session.processor effect tests flush partial v2 fragment
|
|||
).toBe("stop")
|
||||
yield* off
|
||||
|
||||
const failed = seen.indexOf(SessionEvent.Step.Failed.type)
|
||||
expect(failed).toBeGreaterThan(-1)
|
||||
expect(seen.indexOf(SessionEvent.Text.Ended.type)).toBeLessThan(failed)
|
||||
expect(seen.indexOf(SessionEvent.Reasoning.Ended.type)).toBeLessThan(failed)
|
||||
expect(text).toBe("partial")
|
||||
expect(reasoning).toBe("thinking")
|
||||
const parts = yield* MessageV2.parts(msg.id)
|
||||
expect(parts).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ type: "text", text: "partial" }),
|
||||
expect.objectContaining({ type: "reasoning", text: "thinking" }),
|
||||
]),
|
||||
)
|
||||
expect(seen).toContain(MessageV2.Event.PartUpdated.type)
|
||||
expect(seen).toContain(Session.Event.Error.type)
|
||||
expect(seen.filter((type) => type.startsWith("session.next."))).toEqual([])
|
||||
}),
|
||||
{ config: cfg },
|
||||
),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { FetchHttpClient } from "effect/unstable/http"
|
|||
import { expect } from "bun:test"
|
||||
import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer } from "effect"
|
||||
import path from "path"
|
||||
import { fileURLToPath, pathToFileURL } from "url"
|
||||
import { fileURLToPath } from "url"
|
||||
import { NamedError } from "@opencode-ai/core/util/error"
|
||||
import { Agent as AgentSvc } from "../../src/agent/agent"
|
||||
import { BackgroundJob } from "@/background/job"
|
||||
|
|
@ -317,11 +317,6 @@ const writeText = Effect.fn("test.writeText")(function* (file: string, text: str
|
|||
yield* fs.writeWithDirs(file, text)
|
||||
})
|
||||
|
||||
const ensureDir = Effect.fn("test.ensureDir")(function* (dir: string) {
|
||||
const fs = yield* FSUtil.Service
|
||||
yield* fs.ensureDir(dir)
|
||||
})
|
||||
|
||||
const writeConfig = Effect.fn("test.writeConfig")(function* (dir: string, config: Partial<ConfigV1.Info>) {
|
||||
yield* writeText(
|
||||
path.join(dir, "opencode.json"),
|
||||
|
|
@ -554,6 +549,54 @@ withMcpInstructions.instance(
|
|||
15_000,
|
||||
)
|
||||
|
||||
it.instance("legacy prompt emits message events without session.next events", () =>
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2Bridge.Service
|
||||
const prompt = yield* SessionPrompt.Service
|
||||
const sessions = yield* Session.Service
|
||||
const chat = yield* sessions.create({
|
||||
title: "Pinned",
|
||||
agent: "plan",
|
||||
model: { providerID: ProviderV2.ID.make("old"), id: ModelV2.ID.make("old-model") },
|
||||
})
|
||||
const seen: string[] = []
|
||||
const off = yield* events.listen((event) => {
|
||||
seen.push(event.type)
|
||||
return Effect.void
|
||||
})
|
||||
|
||||
const first = yield* prompt.prompt({
|
||||
sessionID: chat.id,
|
||||
agent: "build",
|
||||
model: ref,
|
||||
noReply: true,
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
})
|
||||
const second = yield* prompt.prompt({
|
||||
sessionID: chat.id,
|
||||
agent: "build",
|
||||
noReply: true,
|
||||
parts: [{ type: "text", text: "again" }],
|
||||
})
|
||||
yield* off
|
||||
|
||||
expect(first.info.role).toBe("user")
|
||||
expect(second.info.role).toBe("user")
|
||||
if (first.info.role === "user" && second.info.role === "user") {
|
||||
expect(first.info.model).toEqual(ref)
|
||||
expect(second.info.model).toEqual(ref)
|
||||
}
|
||||
expect(yield* sessions.get(chat.id)).toMatchObject({
|
||||
agent: "build",
|
||||
model: { providerID: ref.providerID, id: ref.modelID },
|
||||
})
|
||||
expect(seen).toContain(Session.Event.Updated.type)
|
||||
expect(seen).toContain(MessageV2.Event.Updated.type)
|
||||
expect(seen).toContain(MessageV2.Event.PartUpdated.type)
|
||||
expect(seen.filter((type) => type.startsWith("session.next."))).toEqual([])
|
||||
}),
|
||||
)
|
||||
|
||||
it.instance("loop surfaces content-filter finishes as session errors", () =>
|
||||
Effect.gen(function* () {
|
||||
const { llm } = yield* useServerConfig(providerCfg)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue