|
|
@@ -506,6 +506,52 @@ it.instance("loop calls LLM and returns assistant message", () =>
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
+it.instance("loop surfaces content-filter finishes as session errors", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const { llm } = yield* useServerConfig(providerCfg)
|
|
|
+ const events = yield* EventV2Bridge.Service
|
|
|
+ const prompt = yield* SessionPrompt.Service
|
|
|
+ const sessions = yield* Session.Service
|
|
|
+ const chat = yield* sessions.create({ title: "Pinned" })
|
|
|
+ const errors: NonNullable<SessionV1.Assistant["error"]>[] = []
|
|
|
+ const expected = {
|
|
|
+ name: "ContentFilterError",
|
|
|
+ data: { message: "The response was blocked by the provider's content filter" },
|
|
|
+ } satisfies NonNullable<SessionV1.Assistant["error"]>
|
|
|
+ const off = yield* events.listen((event) => {
|
|
|
+ if (event.type !== Session.Event.Error.type) return Effect.void
|
|
|
+ const data = event.data as typeof Session.Event.Error.data.Type
|
|
|
+ if (data.sessionID === chat.id && data.error) errors.push(data.error)
|
|
|
+ return Effect.void
|
|
|
+ })
|
|
|
+
|
|
|
+ yield* prompt.prompt({
|
|
|
+ sessionID: chat.id,
|
|
|
+ agent: "build",
|
|
|
+ noReply: true,
|
|
|
+ parts: [{ type: "text", text: "hello" }],
|
|
|
+ })
|
|
|
+ yield* llm.push(reply().text("partial response").contentFilter())
|
|
|
+
|
|
|
+ const result = yield* prompt.loop({ sessionID: chat.id })
|
|
|
+ const stored = yield* MessageV2.get({ sessionID: chat.id, messageID: result.info.id })
|
|
|
+ yield* off
|
|
|
+
|
|
|
+ expect(yield* llm.hits).toHaveLength(1)
|
|
|
+ expect(result.info.role).toBe("assistant")
|
|
|
+ expect(stored.info.role).toBe("assistant")
|
|
|
+ if (result.info.role === "assistant" && stored.info.role === "assistant") {
|
|
|
+ expect(result.info.finish).toBe("content-filter")
|
|
|
+ expect(result.info.error).toEqual(expected)
|
|
|
+ expect(stored.info.error).toEqual(result.info.error)
|
|
|
+ expect(errors).toContainEqual(expected)
|
|
|
+ }
|
|
|
+ expect(result.parts).toEqual(
|
|
|
+ expect.arrayContaining([expect.objectContaining({ type: "text", text: "partial response" })]),
|
|
|
+ )
|
|
|
+ }),
|
|
|
+)
|
|
|
+
|
|
|
it.instance("loop stops provider overflow instead of auto-compacting when disabled", () =>
|
|
|
Effect.gen(function* () {
|
|
|
const { llm } = yield* useServerConfig((url) => ({
|