fix(core): persist assistant text state
This commit is contained in:
parent
fc8bbb153f
commit
ce1203ce83
8 changed files with 144 additions and 36 deletions
|
|
@ -15,6 +15,36 @@ const model = ModelV2.Ref.make({ id: ModelV2.ID.make("model"), providerID: Provi
|
|||
const build = AgentV2.defaultID
|
||||
|
||||
describe("toLLMMessages", () => {
|
||||
test("restores same-model provider state on assistant text", () => {
|
||||
const messages = toLLMMessages(
|
||||
[
|
||||
SessionMessage.Assistant.make({
|
||||
id: id("assistant-text-state"),
|
||||
type: "assistant",
|
||||
agent: build,
|
||||
model,
|
||||
content: [
|
||||
SessionMessage.AssistantText.make({
|
||||
type: "text",
|
||||
text: "Checking.",
|
||||
state: { itemId: "msg_commentary", phase: "commentary" },
|
||||
}),
|
||||
],
|
||||
time: { created, completed: created },
|
||||
}),
|
||||
],
|
||||
model,
|
||||
)
|
||||
|
||||
expect(messages[0]?.content).toEqual([
|
||||
{
|
||||
type: "text",
|
||||
text: "Checking.",
|
||||
providerMetadata: { provider: { itemId: "msg_commentary", phase: "commentary" } },
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test("omits empty assistant turns", () => {
|
||||
const assistant = (value: string, content: SessionMessage.Assistant["content"]) =>
|
||||
SessionMessage.Assistant.make({
|
||||
|
|
@ -661,6 +691,11 @@ Recent work
|
|||
agent: build,
|
||||
model: { id: ModelV2.ID.make("old-model"), providerID: ProviderV2.ID.make("provider") },
|
||||
content: [
|
||||
SessionMessage.AssistantText.make({
|
||||
type: "text",
|
||||
text: "Checking",
|
||||
state: { itemId: "msg_old", phase: "commentary" },
|
||||
}),
|
||||
SessionMessage.AssistantReasoning.make({
|
||||
type: "reasoning",
|
||||
text: "Visible thought",
|
||||
|
|
@ -705,6 +740,7 @@ Recent work
|
|||
)
|
||||
|
||||
expect(messages[0]?.content).toEqual([
|
||||
{ type: "text", text: "Checking", providerMetadata: undefined },
|
||||
{ type: "text", text: "Visible thought" },
|
||||
{
|
||||
type: "tool-call",
|
||||
|
|
|
|||
|
|
@ -2434,6 +2434,51 @@ describe("SessionRunnerLLM", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("preserves assistant text provider state across durable continuation", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
yield* admit(session, "Check this")
|
||||
|
||||
const providerMetadata = { openai: { itemId: "msg_commentary", phase: "commentary" } }
|
||||
responses = [
|
||||
[
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.textStart({ id: "msg_commentary", providerMetadata }),
|
||||
LLMEvent.textDelta({ id: "msg_commentary", text: "Checking.", providerMetadata }),
|
||||
LLMEvent.textEnd({ id: "msg_commentary", providerMetadata }),
|
||||
LLMEvent.toolCall({ id: "call-echo", name: "echo", input: { text: "hello" } }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
|
||||
LLMEvent.finish({ reason: "tool-calls" }),
|
||||
],
|
||||
reply.text("Done", "text-final"),
|
||||
]
|
||||
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(requests[1]?.messages[1]?.content[0]).toEqual({
|
||||
type: "text",
|
||||
text: "Checking.",
|
||||
providerMetadata,
|
||||
})
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Check this" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Checking.",
|
||||
state: { itemId: "msg_commentary", phase: "commentary" },
|
||||
},
|
||||
{ type: "tool", id: "call-echo" },
|
||||
],
|
||||
},
|
||||
{ type: "assistant", content: [{ type: "text", text: "Done" }] },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("reloads a model switch before a tool-driven continuation step", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue