Изменение выносит типы контента в :content-api и разделяет потоки событий.
This commit is contained in:
@@ -28,14 +28,14 @@ class LiveTurnTest {
|
||||
fun `full happy path accumulates reasoning and answer`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartReasoning(at()),
|
||||
OnlineEvent.AppendText(at(), "сначала "),
|
||||
OnlineEvent.AppendText(at(), "подумаем"),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
OnlineEvent.AppendText(at(), "Привет, "),
|
||||
OnlineEvent.AppendText(at(), "мир!"),
|
||||
Event.End(at()),
|
||||
OnlineEvent.End(at()),
|
||||
)
|
||||
|
||||
assertEquals(TurnPhase.DONE, turn.phase)
|
||||
@@ -52,11 +52,11 @@ class LiveTurnTest {
|
||||
fun `tool call and result are stitched into one block`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
Event.ToolCall(at(), id = "t1", title = "grep", toolName = "grep", toolArgs = "{\"q\":\"x\"}"),
|
||||
Event.ToolResult(at(), toolCallId = "t1", toolName = "grep", result = "found 3"),
|
||||
Event.End(at()),
|
||||
OnlineEvent.End(at()),
|
||||
)
|
||||
|
||||
val tools = turn.blocks.filterIsInstance<LiveBlock.Tool>()
|
||||
@@ -72,7 +72,7 @@ class LiveTurnTest {
|
||||
fun `orphan tool result creates a block`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
Event.ToolResult(at(), toolCallId = "missing", toolName = null, result = "ok"),
|
||||
)
|
||||
@@ -87,7 +87,7 @@ class LiveTurnTest {
|
||||
fun `tool failed marks the block`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
Event.ToolCall(at(), id = "t9", title = null, toolName = "bash", toolArgs = "{}"),
|
||||
Event.ToolFailed(at(), toolCallId = "t9", toolName = "bash", message = "boom", durationMs = 5),
|
||||
)
|
||||
@@ -100,7 +100,7 @@ class LiveTurnTest {
|
||||
fun `error appends failure block and fails the turn`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
OnlineEvent.AppendText(at(), "partial"),
|
||||
Event.Error(at(), message = "llm down", code = "E500"),
|
||||
@@ -118,7 +118,7 @@ class LiveTurnTest {
|
||||
fun `interrupted turn is terminal and keeps partial text`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
OnlineEvent.AppendText(at(), "не до конца"),
|
||||
Event.Interrupted(at()),
|
||||
@@ -133,7 +133,7 @@ class LiveTurnTest {
|
||||
fun `text after tool call starts a new answer block`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
OnlineEvent.AppendText(at(), "до"),
|
||||
Event.ToolCall(at(), id = "t1", title = null, toolName = "grep", toolArgs = "{}"),
|
||||
@@ -152,10 +152,10 @@ class LiveTurnTest {
|
||||
val bytes = byteArrayOf(1, 2, 3)
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.IMAGE),
|
||||
OnlineEvent.AppendImage(at(), body = bytes, mime = "image/png"),
|
||||
Event.End(at()),
|
||||
OnlineEvent.End(at()),
|
||||
)
|
||||
|
||||
assertTrue(turn.blocks.filterIsInstance<LiveBlock.Answer>().isEmpty())
|
||||
@@ -168,12 +168,12 @@ class LiveTurnTest {
|
||||
fun `working resets the previous turn`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.StartResponse(at(), OnlineEvent.ResponseType.TEXT),
|
||||
OnlineEvent.AppendText(at(), "старое"),
|
||||
Event.End(at()),
|
||||
OnlineEvent.End(at()),
|
||||
)
|
||||
turn.feed(Event.Working(at()), OnlineEvent.AppendText(at(), "новое"))
|
||||
turn.feed(OnlineEvent.Working(at()), OnlineEvent.AppendText(at(), "новое"))
|
||||
|
||||
assertEquals(1, turn.blocks.size)
|
||||
assertEquals("новое", turn.answerText())
|
||||
@@ -182,7 +182,7 @@ class LiveTurnTest {
|
||||
@Test
|
||||
fun `append without explicit start response still streams as answer`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(Event.Working(at()), OnlineEvent.AppendText(at(), "без старта"))
|
||||
turn.feed(OnlineEvent.Working(at()), OnlineEvent.AppendText(at(), "без старта"))
|
||||
|
||||
assertEquals(TurnPhase.RESPONDING, turn.phase)
|
||||
assertEquals("без старта", turn.answerText())
|
||||
@@ -193,7 +193,7 @@ class LiveTurnTest {
|
||||
val turn = LiveTurn()
|
||||
var count = 0
|
||||
turn.onChange = { count++ }
|
||||
turn.feed(Event.Working(at()), OnlineEvent.AppendText(at(), "x"))
|
||||
turn.feed(OnlineEvent.Working(at()), OnlineEvent.AppendText(at(), "x"))
|
||||
|
||||
assertEquals(2, count)
|
||||
}
|
||||
@@ -202,13 +202,13 @@ class LiveTurnTest {
|
||||
fun `preview text collapses whitespace and truncates`() {
|
||||
val turn = LiveTurn()
|
||||
turn.feed(
|
||||
Event.Working(at()),
|
||||
OnlineEvent.Working(at()),
|
||||
OnlineEvent.AppendText(at(), "Первая строка\n\nвторая строка "),
|
||||
)
|
||||
assertEquals("Первая строка вторая строка", turn.previewText())
|
||||
|
||||
val long = LiveTurn()
|
||||
long.feed(Event.Working(at()), OnlineEvent.AppendText(at(), "слово ".repeat(60)))
|
||||
long.feed(OnlineEvent.Working(at()), OnlineEvent.AppendText(at(), "слово ".repeat(60)))
|
||||
val preview = long.previewText(maxLength = 30)
|
||||
assertTrue(preview.length <= 31)
|
||||
assertTrue(preview.endsWith("…"))
|
||||
|
||||
Reference in New Issue
Block a user