You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2026/09/24 13:02:09 UTC
(skywalking-horizon-ui) branch fix/conversation-view-langchain-requests created (now bb3ca454)
This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a change to branch fix/conversation-view-langchain-requests
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
at bb3ca454 fix(conversation-view): read a LangChain agent's prompts in LangChain's words
This branch includes the following new commits:
new bb3ca454 fix(conversation-view): read a LangChain agent's prompts in LangChain's words
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(skywalking-horizon-ui) 01/01: fix(conversation-view): read a LangChain agent's prompts in LangChain's words
Posted by wu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch fix/conversation-view-langchain-requests
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
commit bb3ca4540fa35f3f14dcfa2ced86980de3e5e70e
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Thu Sep 24 21:02:02 2026 +0800
fix(conversation-view): read a LangChain agent's prompts in LangChain's words
For a LangChain or LangGraph agent, the AI Sessionizer stores what
LangChain handed its model: a list of prompts, each a list of LangChain's
serialized messages. The Prompt tab took any list under `messages` for the
Anthropic Messages API, so it drew each such request as one message with no
role and nothing in it, and fell back to raw JSON for every response.
The reader now takes the Anthropic shape only when every message is an
object. Otherwise it reads LangChain's shape when there is one prompt, or
one generation: each message by its own type, system, human, ai or tool,
with its tool calls, and each tool result under the call it answers,
marked failed when LangChain marked it. A call that the content repeats is
drawn once, where the content has it, with the arguments LangChain parsed.
A response shows the answer, the model and the token counts LangChain
reported. A message with no content it can read is shown as its JSON, and
a body of several prompts as the document it is. An empty settings section
is no longer drawn.
The fixture is a real LangGraph agent with SummarizationMiddleware on
Amazon Bedrock, landed by the Sessionizer: 13 model calls in 14 files.
---
.licenserc.yaml | 2 +-
docs/changelog/1.1.0.md | 2 +
docs/operate/ai-agent-conversations.md | 6 +-
packages/conversation-view/src/prompt/messages.ts | 156 +-
packages/conversation-view/src/view/prompt.ts | 5 +-
.../test/fixtures/langchain/conversation.json | 2068 ++++++++++++++++++++
.../test/fixtures/langchain/provider_body-10.sd | 4 +
.../test/fixtures/langchain/provider_body-12.sd | 4 +
.../test/fixtures/langchain/provider_body-14.sd | 4 +
.../test/fixtures/langchain/provider_body-16.sd | 4 +
.../test/fixtures/langchain/provider_body-18.sd | 4 +
.../test/fixtures/langchain/provider_body-2.sd | 3 +
.../test/fixtures/langchain/provider_body-20.sd | 4 +
.../test/fixtures/langchain/provider_body-22.sd | 4 +
.../test/fixtures/langchain/provider_body-24.sd | 4 +
.../test/fixtures/langchain/provider_body-26.sd | 4 +
.../test/fixtures/langchain/provider_body-28.sd | 3 +
.../test/fixtures/langchain/provider_body-4.sd | 4 +
.../test/fixtures/langchain/provider_body-6.sd | 4 +
.../test/fixtures/langchain/provider_body-8.sd | 4 +
.../test/prompt-langchain.test.ts | 223 +++
21 files changed, 2506 insertions(+), 10 deletions(-)
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 9c423b70..8195a336 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -61,7 +61,7 @@ header:
# Landed Session Data captured from the AI Sessionizer, kept as a test
# fixture. Every line is one record the reader parses and whose bytes it
# checks against a digest, so a header comment would make the file invalid.
- - '**/test/fixtures/*.sd'
+ - '**/test/fixtures/**/*.sd'
- 'pnpm-lock.yaml'
- '.browserslistrc'
- '.prettierrc'
diff --git a/docs/changelog/1.1.0.md b/docs/changelog/1.1.0.md
index 449e9e15..5786bfe2 100644
--- a/docs/changelog/1.1.0.md
+++ b/docs/changelog/1.1.0.md
@@ -24,6 +24,8 @@
**The conversation page shows the prompt each model call sent, and the answer it got.** When the AI Sessionizer captured the bodies a call exchanged with its model provider, the call's step gains a **Prompt** tab: the exact request as it was sent and the exact response as it came back, neither of which a transcript holds. The bodies are not part of the conversation document — they are megabytes per call — so the tab opens on an offer stating how many stored files of the session it needs [...]
+**The Prompt tab reads a LangChain or LangGraph agent's calls.** For such an agent the Sessionizer stores what LangChain handed its model, a list of LangChain's own serialized messages, and the tab drew each of those requests as one empty message. It now shows every message in LangChain's words, `system`, `human`, `ai` and `tool`, with the tool calls an `ai` message made, each drawn once with the arguments LangChain parsed even where the provider repeats it in the message content, and ea [...]
+
**The inspector says where a step sits in words.** Its Details tab opens with the step's place: the activity window and its number, the agent, the talk by its opening line and its place in the stream, the run's place in the talk, and the step by kind and name, instead of a chain of clipped identifiers; the identifiers stay in the tooltip.
**Tool inputs and results read as fields.** On the conversation page, a tool call's card and its Details tab draw the input the agent recorded as the fields it holds instead of one escaped JSON string: a shell command as the lines that were run, an edit as its path and the text before and after, a result's output and error streams apart. A long text is cut short with a *show all* link that opens it in place, and where the document clipped the text a note says how much of it is there. Eve [...]
diff --git a/docs/operate/ai-agent-conversations.md b/docs/operate/ai-agent-conversations.md
index 2bf5ac13..45eb77b4 100644
--- a/docs/operate/ai-agent-conversations.md
+++ b/docs/operate/ai-agent-conversations.md
@@ -96,13 +96,15 @@ Each message is drawn in a box of its own, headed by its role and its place in t
A **response** is shown on its own: what stopped it, the token counts the provider reported, and the blocks it returned — text, reasoning, and the tool uses the agent went on to run. A tool result the provider marked failed says so. A long text is cut short with a *show all* link that opens it in place, as elsewhere on the page, and every text has a *copy* button that copies it in full, never the shortened preview.
+A **LangChain or LangGraph agent** is read in LangChain's own words. What the Sessionizer stores for such a call is what LangChain handed its model, before the model's client library turned it into the provider's request. Every message is headed by its type, `system`, `human`, `ai` or `tool`, and the system prompt is the first message rather than a section of its own. An `ai` message shows the tool calls it made, each once, and a `tool` message shows the result under the call it answers, [...]
+
**What is shown is checked, not trusted.** The Sessionizer stores a body cut into pieces so that history repeated across calls is stored once, and Horizon rebuilds each body in your browser and checks it against the byte count and the SHA-256 digest the Sessionizer recorded. A body it cannot rebuild says so instead of showing a partial one. A body of a shape it does not know — a provider other than the one it reads — is shown as the JSON document it is, with nothing left out.
### Limits
- **One document, all at once.** OAP sends the whole conversation, and its `viewTimeoutMs` budget (120 s by default, see [Configuration File](../setup/horizon-yaml.md)) covers the wait for the first byte. A conversation OAP cannot assemble within that time reports a timeout; try again, or raise the budget on both sides. Horizon holds the document before the browser starts receiving it, which is how the page knows the size to count against; that hold is a fifth of the document's size per [...]
- **Landed records are not on OAP, except the prompts.** The Sessionizer's own viewer can open the raw landed record behind any step; OAP stores the assembled document, so this page shows the text the document carries and says when it was clipped. The one exception is the provider bodies above, which OAP stores as files and serves on request.
-- **Prompts need a Sessionizer that captured them.** Provider bodies exist from AI Sessionizer 0.4.0, and only for the calls it was configured to capture. A call with none has no Prompt tab; nothing about it is hidden, it was never stored.
+- **Prompts need a Sessionizer that captured them.** Provider bodies exist from AI Sessionizer 0.4.0 for Claude Code, and from 0.5.0 for a LangChain or LangGraph agent, and only for the calls it was configured to capture. A call with none has no Prompt tab; nothing about it is hidden, it was never stored.
## Troubleshooting
@@ -112,6 +114,6 @@ A **response** is shown on its own: what stopped it, the token counts the provid
- **The conversation page says OAP holds no round for this agent.** The link names a agent OAP has no round of this conversation for — the Sessionizer was renamed between pushes, or the agent runtime in the link is not the one that pushed it. Open the conversation from the list again.
- **The page waits a long time, then reports a timeout.** OAP assembles the whole chain before answering, and a very long conversation can exceed the time budget. Try again; if it keeps happening, raise `performance.aiConversation.viewTimeoutMs` in Horizon and the matching `viewRequestTimeout` on OAP.
- **A row does nothing when clicked.** The browser blocked the new tab as a pop-up. Allow pop-ups for Horizon's address, or open the row with Enter after focusing it.
-- **A model call has no Prompt tab.** The Sessionizer captured no request or response body for it — either it is older than 0.4.0, or provider body capture was not configured for that agent runtime. The Sessionizer's [Claude Code provider bodies](https://skywalking.apache.org/docs/skywalking-ai-sessionizer/next/readme/) page says what it captures.
+- **A model call has no Prompt tab.** The Sessionizer captured no request or response body for it — either it is older than 0.4.0, or than 0.5.0 for a LangChain or LangGraph agent, or provider body capture was not configured for that agent runtime. The Sessionizer's [Claude Code provider bodies](https://skywalking.apache.org/docs/skywalking-ai-sessionizer/next/readme/) page says what it captures.
- **The prompt says a file is missing, or cannot be rebuilt.** OAP answered without one of the session's stored files, so the bodies that refer to it cannot be put back together. The file is past OAP's retention while the conversation document is not, or it never arrived. The panel names the file's position, and reading another call of the same session still works when its own history is there.
- **No tool call shows a change mark.** Change records exist from AI Sessionizer 0.3.0 with an OAP that carries them in the document. The runtime's own `Edit` and `Write` patches need no plugin, but a session collected by an earlier Sessionizer has none, since the record is made when the transcript is collected, not when it is re-read. Shell commands and edits inside subagents are recorded only where the asz Claude Code plugin is installed.
diff --git a/packages/conversation-view/src/prompt/messages.ts b/packages/conversation-view/src/prompt/messages.ts
index 719044a3..6df7d45d 100644
--- a/packages/conversation-view/src/prompt/messages.ts
+++ b/packages/conversation-view/src/prompt/messages.ts
@@ -20,10 +20,11 @@
/**
* Reading a provider body as a conversation.
*
- * The bodies are the runtime's own, so their shape is the provider's API, not the model's. This reads
- * the one shape the Sessionizer captures today, the Anthropic Messages API, and keeps everything it
- * does not know: an unread field stays under the settings, an unread block prints as JSON. A body of
- * another shape reads as one JSON document and nothing is lost.
+ * The bodies are the runtime's own, so their shape is the runtime's, not the model's. This reads the
+ * two shapes the Sessionizer captures: the Anthropic Messages API, which Claude Code sends, and
+ * LangChain's own serialized messages, which a LangChain or LangGraph agent hands its model. It keeps
+ * everything it does not know: an unread field stays under the settings, an unread block prints as
+ * JSON. A body of another shape reads as one JSON document and nothing is lost.
*/
export interface PromptBlock {
@@ -108,11 +109,29 @@ export function readBody(bytes: Uint8Array, role: string): ReadBody {
}
if (!value || typeof value !== 'object' || Array.isArray(value)) return { kind: 'other', raw: value };
const body = value as Record<string, unknown>;
- if (role === 'request' && Array.isArray(body['messages'])) return readRequest(body);
- if (role === 'response' && Array.isArray(body['content'])) return readResponse(body);
+ if (role === 'request') {
+ // Every message an object, or the list is not the Messages API. A LangChain request is a list of
+ // lists, and reading it as messages drew one message with no role and nothing in it.
+ if (isObjectList(body['messages'])) return readRequest(body);
+ const prompt = langChainPrompt(body['messages']);
+ if (prompt) return readLangChainRequest(body, prompt);
+ }
+ if (role === 'response') {
+ if (Array.isArray(body['content'])) return readResponse(body);
+ const generation = langChainGeneration(body['generations']);
+ if (generation) return readLangChainResponse(body, generation);
+ }
return { kind: 'other', raw: value };
}
+function isObjectList(value: unknown): value is Array<Record<string, unknown>> {
+ return Array.isArray(value) && value.every(isObject);
+}
+
+function isObject(value: unknown): value is Record<string, unknown> {
+ return !!value && typeof value === 'object' && !Array.isArray(value);
+}
+
function readRequest(body: Record<string, unknown>): ReadRequest {
// Object.create(null), not {}: a body may carry a field called __proto__, and assigning that into
// an ordinary object changes the object's prototype instead of keeping the value.
@@ -202,6 +221,131 @@ function readBlock(value: unknown): PromptBlock {
return { kind, json: value };
}
+/*
+ * LangChain's shape. A request's `messages` is a list of prompts, each a list of messages, and a chat
+ * model call has exactly one prompt. A response's `generations` is a list per prompt of what the model
+ * answered. A message is serialized with its class in `id` and its fields under `kwargs`, or is a plain
+ * object when the caller passed one. It is what the framework handed its model, not what the provider
+ * received, and it is read in LangChain's own words: a message's role is its `type`, `human`, `ai`,
+ * `system` or `tool`. Several prompts, or several generations, do not read as one conversation, and
+ * such a body is shown as the JSON it is.
+ */
+
+function langChainPrompt(messages: unknown): Array<Record<string, unknown>> | null {
+ if (!Array.isArray(messages) || messages.length !== 1) return null;
+ const prompt: unknown = messages[0];
+ return isObjectList(prompt) ? prompt : null;
+}
+
+function langChainGeneration(generations: unknown): Record<string, unknown> | null {
+ if (!Array.isArray(generations) || generations.length !== 1) return null;
+ const prompt: unknown = generations[0];
+ if (!Array.isArray(prompt) || prompt.length !== 1) return null;
+ const only: unknown = prompt[0];
+ return isObject(only) ? only : null;
+}
+
+function readLangChainRequest(body: Record<string, unknown>, prompt: Array<Record<string, unknown>>): ReadRequest {
+ const rest: Record<string, unknown> = Object.create(null) as Record<string, unknown>;
+ for (const [k, v] of Object.entries(body)) if (k !== 'messages') rest[k] = v;
+ // The system prompt is a message in the list, and the tools are not in the body at all: they are
+ // bound to the model, not sent with the messages.
+ return { kind: 'request', system: [], tools: [], messages: prompt.map(readLangChainMessage), rest, raw: body };
+}
+
+function readLangChainResponse(body: Record<string, unknown>, generation: Record<string, unknown>): ReadResponse {
+ const message = generation['message'];
+ const fields = isObject(message) ? langChainFields(message) : null;
+ const rest: Record<string, unknown> = Object.create(null) as Record<string, unknown>;
+ for (const [k, v] of Object.entries(fields ?? {})) {
+ if (!['content', 'tool_calls', 'invalid_tool_calls', 'usage_metadata', 'id', 'type'].includes(k)) rest[k] = v;
+ }
+ if (generation['generation_info'] != null) rest['generation_info'] = generation['generation_info'];
+ if (body['llm_output'] != null) rest['llm_output'] = body['llm_output'];
+ const metadata = fields?.['response_metadata'];
+ const output = body['llm_output'];
+ const model = (isObject(metadata) ? metadata['model_name'] : undefined) ?? (isObject(output) ? output['model_name'] : undefined);
+ const usage = fields?.['usage_metadata'];
+ // A completion model answers with text and no message.
+ const text = generation['text'];
+ return {
+ kind: 'response',
+ model: typeof model === 'string' ? model : undefined,
+ id: typeof fields?.['id'] === 'string' ? fields['id'] : undefined,
+ blocks: fields ? langChainBlocks(fields, message) : typeof text === 'string' ? [{ kind: 'text', text }] : [],
+ usage: isObject(usage) ? usage : undefined,
+ rest,
+ raw: body,
+ };
+}
+
+function readLangChainMessage(value: Record<string, unknown>): PromptMessage {
+ const fields = langChainFields(value);
+ const type = typeof fields['type'] === 'string' ? fields['type'] : '';
+ const role = typeof fields['role'] === 'string' ? fields['role'] : '';
+ // A ChatMessage carries a role of the caller's choosing, and a plain object may say role and not type.
+ return { role: type && type !== 'chat' ? type : role, blocks: langChainBlocks(fields, value), raw: value };
+}
+
+function langChainContentBlock(value: unknown): PromptBlock {
+ return isObject(value) && value['type'] === 'tool_call' ? langChainToolCall(value) : readBlock(value);
+}
+
+function langChainToolCall(c: Record<string, unknown>): PromptBlock {
+ const id = typeof c['id'] === 'string' ? c['id'] : undefined;
+ return { kind: 'tool_use', name: typeof c['name'] === 'string' ? c['name'] : '', ...(id ? { id } : {}), json: c['args'] };
+}
+
+function langChainFields(m: Record<string, unknown>): Record<string, unknown> {
+ const kwargs = m['kwargs'];
+ return m['lc'] === 1 && m['type'] === 'constructor' && isObject(kwargs) ? kwargs : m;
+}
+
+/**
+ * A message's content, then the tool calls it made. A tool message's content is the result of the call
+ * it names.
+ *
+ * A call can also sit in the content: as the provider's `tool_use` block, which Bedrock repeated on
+ * every call measured, or as LangChain's own `tool_call` block. It is drawn once, where the content
+ * has it, with the arguments from `tool_calls`. Those are LangChain's parsed arguments, the ones the
+ * agent ran with: a streamed provider block can still read `{}`, with the arguments in pieces beside it.
+ */
+function langChainBlocks(fields: Record<string, unknown>, raw: unknown): PromptBlock[] {
+ const content = fields['content'];
+ if (fields['type'] === 'tool' || fields['role'] === 'tool') {
+ const about = {
+ ...(typeof fields['tool_call_id'] === 'string' ? { id: fields['tool_call_id'] } : {}),
+ ...(fields['status'] === 'error' ? { failed: true } : {}),
+ };
+ return [typeof content === 'string' ? { kind: 'tool_result', text: content, json: raw, ...about } : { kind: 'tool_result', json: content ?? raw, ...about }];
+ }
+ const blocks: PromptBlock[] =
+ typeof content === 'string'
+ ? content
+ ? [{ kind: 'text', text: content, reminder: content.includes(REMINDER) }]
+ : []
+ : Array.isArray(content)
+ ? content.map(langChainContentBlock)
+ : [];
+ const at = new Map<string, number>();
+ blocks.forEach((b, i) => {
+ if (b.kind === 'tool_use' && b.id) at.set(b.id, i);
+ });
+ for (const call of Array.isArray(fields['tool_calls']) ? (fields['tool_calls'] as unknown[]) : []) {
+ const use = langChainToolCall(isObject(call) ? call : {});
+ const i = use.id ? at.get(use.id) : undefined;
+ if (i === undefined) blocks.push(use);
+ else blocks[i] = { ...use, name: use.name || (blocks[i]!.name ?? '') };
+ }
+ for (const call of Array.isArray(fields['invalid_tool_calls']) ? (fields['invalid_tool_calls'] as unknown[]) : []) {
+ blocks.push({ kind: 'invalid_tool_call', json: call });
+ }
+ if (blocks.length) return blocks;
+ // An empty answer is an empty text. A message whose content is not there at all, or is not a shape
+ // this reads, is shown as the JSON it is rather than as an empty box.
+ return typeof content === 'string' ? [{ kind: 'text', text: '' }] : [{ kind: 'unknown', json: raw }];
+}
+
/** What one request adds to the one before it. */
export interface PromptDelta {
/** The messages this request carries that the one before it did not. */
diff --git a/packages/conversation-view/src/view/prompt.ts b/packages/conversation-view/src/view/prompt.ts
index d7642d39..0439d94f 100644
--- a/packages/conversation-view/src/view/prompt.ts
+++ b/packages/conversation-view/src/view/prompt.ts
@@ -279,7 +279,10 @@ function drawRequest(ctx: ViewContext, e: Step, read: ReadRequest, sides: Sides,
read.messages.map((m, i) => message(ctx, m, i + 1, read.messages.length, `${e.id}|req|msg|${i}`)).join(''),
true,
);
- const settings = section(ctx, e, 'settings', s.promptSettings, Object.keys(read.rest).join(', '), json(ctx, read.rest, `${e.id}|req|set`));
+ // A LangChain request carries nothing but its messages, and an empty section says nothing.
+ const settings = Object.keys(read.rest).length
+ ? section(ctx, e, 'settings', s.promptSettings, Object.keys(read.rest).join(', '), json(ctx, read.rest, `${e.id}|req|set`))
+ : '';
const whole = section(ctx, e, 'request-raw', s.promptWholeBody, '', json(ctx, read.raw, `${e.id}|req|raw`));
return `${modes}${system}${tools}${messages}${settings}${whole}`;
}
diff --git a/packages/conversation-view/test/fixtures/langchain/conversation.json b/packages/conversation-view/test/fixtures/langchain/conversation.json
new file mode 100644
index 00000000..8dd98ced
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/conversation.json
@@ -0,0 +1,2068 @@
+{
+ "format": "asz.view",
+ "version": "1.0",
+ "conversation": "ls-history-history-middleware-7bf102b808e4",
+ "sessions": [
+ "ls-history-history-middleware-7bf102b808e4"
+ ],
+ "head": {
+ "round": 1,
+ "digest": "12d95b91eccf1dbc91cdcc28ab87338d754b7919e3d13795021b8d18245f370d"
+ },
+ "parser": "v1",
+ "policy": "v1+idle=10m0s",
+ "summary": {
+ "title": "Check checkout.",
+ "state": "verified",
+ "problems": [],
+ "talks": 6,
+ "steps": 36,
+ "streams": 1,
+ "segments": 1,
+ "rounds": 1,
+ "unresolved": 0,
+ "changes": 0,
+ "provider_bodies": 26,
+ "captured_prompts": 13,
+ "from": 1790171011262,
+ "to": 1790171059349,
+ "kinds": {
+ "epoch": 1,
+ "llm.call": 13,
+ "message.assistant": 13,
+ "message.external": 6,
+ "run": 6,
+ "segment": 1,
+ "session": 1,
+ "stream": 1,
+ "talk": 6,
+ "tool": 4
+ },
+ "relation_types": {
+ "in_segment": 6
+ },
+ "quality": {
+ "exact_unique": 6
+ }
+ },
+ "rounds": [
+ {
+ "round": 1,
+ "digest": "12d95b91eccf1dbc91cdcc28ab87338d754b7919e3d13795021b8d18245f370d",
+ "previous": null,
+ "from_seq": 1,
+ "through_seq": 28,
+ "input_digest": "31195a644de96ba9f42bc330c5393b555f6a9e27ef0e2755baf1ea0348485f2e",
+ "from_time": 1790171011262,
+ "through_time": 1790171059349,
+ "verified": true
+ }
+ ],
+ "files": [
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134334.859239000Z-000001.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 1,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 8,
+ "bytes": 4535,
+ "digest": "4610509768b068c37aa4d475198df6b9c5ac69650cb148e2acd7919060853278",
+ "from_time": 1790171011262,
+ "through_time": 1790171011303
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134334.859239000Z-000002.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 2,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 3,
+ "bytes": 1488,
+ "digest": "61a57060b04e6309b4b15d106c704170600ad8fe72da04449517f9642eff8aaf",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134335.002990000Z-000003.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 3,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 9,
+ "bytes": 6894,
+ "digest": "edc1ed427376be4bacb947ecc81fa2455920aa333533307c171f4629f702feac",
+ "from_time": 1790171013852,
+ "through_time": 1790171013862
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134335.002990000Z-000004.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 4,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 5343,
+ "digest": "ce9d485f9c2a8b6f3e6d5b38118eadb4095acb074ff64e0ccb93725c5508b5d6",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134340.319869000Z-000005.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 5,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 10,
+ "bytes": 6899,
+ "digest": "6b3f617c3db6b9f9a1fbad1146e470c70fc2fefe7d3a75783933046fbaf7199f",
+ "from_time": 1790171015617,
+ "through_time": 1790171015624
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134340.319869000Z-000006.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 6,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 6792,
+ "digest": "a09fa2aeba0cf130818e7ad56077cb8082f5fb6091b0b4152bf79c32446ff53b",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134340.632028000Z-000007.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 7,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 9,
+ "bytes": 6922,
+ "digest": "55d76691893eb3fa94deb54faefb32fe43157cfa23d37ded5a1efb7660a2fa89",
+ "from_time": 1790171017367,
+ "through_time": 1790171017377
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134340.632028000Z-000008.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 8,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 8439,
+ "digest": "340db057fdb1104aabb65db683882707312459ad3eb1aeb8fd2caa0040ee7d83",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134346.252773000Z-000009.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 9,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 10,
+ "bytes": 7251,
+ "digest": "4d303f0ac588494a9dc92f48082a2d64cd35cbac9de207d283ab0f8982a3190e",
+ "from_time": 1790171020750,
+ "through_time": 1790171020756
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134346.252773000Z-000010.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 10,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 7234,
+ "digest": "d1f9b84064fcd412d035fe41e2b815174f5b6eac7c8d5d7a8ff95e772f9be54a",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134346.762253000Z-000011.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 11,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 7,
+ "bytes": 5968,
+ "digest": "146d261e80d93fd12e9eeedf6c243ce3ffaee4fcd952e98c565a81213428e687",
+ "from_time": 1790171024966,
+ "through_time": 1790171024969
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134346.762253000Z-000012.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 12,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 8828,
+ "digest": "524c1a36addc7c058db5d54556721a90a60e9446ce8e50df958dc3f97643c60a",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134352.154696000Z-000013.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 13,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 9,
+ "bytes": 6863,
+ "digest": "f11c0e8b10f9ff3db9bfaff64f912d0a3ccf5ac46ee0731db4a75a0653b16ac5",
+ "from_time": 1790171027042,
+ "through_time": 1790171027049
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134352.154696000Z-000014.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 14,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 4968,
+ "digest": "25f7e43da288b0142da190998fe81149b64b3afb7fb0a64229576528dbd72674",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134352.294975000Z-000015.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 15,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 10,
+ "bytes": 7198,
+ "digest": "4631fd3ea10682518775d00567ca17f63329a57943f65af1388da00dfb1e495e",
+ "from_time": 1790171029043,
+ "through_time": 1790171029050
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134352.294975000Z-000016.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 16,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 7985,
+ "digest": "4e15e833cad4f2fbb4cacc399bead4739a37030e86f06817bb82ce226e42041e",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134408.402338000Z-000017.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 17,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 7,
+ "bytes": 6217,
+ "digest": "63a6f58be98793301b602bf7799c47e3166b7c380bbabe9bb4ade6bb5e2685ee",
+ "from_time": 1790171044170,
+ "through_time": 1790171044172
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134408.402338000Z-000018.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 18,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 8541,
+ "digest": "fd440c60b8815f74e697e8e07f8dcb148dcda98a9d048489b875c2bb083b4e9d",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134408.476950000Z-000019.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 19,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 10,
+ "bytes": 7120,
+ "digest": "89f495e890954e315589d11038fef230dd04e4b59213fbcb89d60f3c57e2b265",
+ "from_time": 1790171047632,
+ "through_time": 1790171047642
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134408.476950000Z-000020.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 20,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 5391,
+ "digest": "ffa585160bc676a3f7a56aa55330ffb0a9dc84921c855903658280a664362d87",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134413.598143000Z-000021.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 21,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 9,
+ "bytes": 7161,
+ "digest": "45eb4e9e4cbbb0dfacef0690bbcb2f62d3d9953b79aca6e008dc02421fae85cc",
+ "from_time": 1790171049393,
+ "through_time": 1790171049401
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134413.598143000Z-000022.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 22,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 8004,
+ "digest": "bffce2938d30718743f18f085723fbb0fca95e145cfa85dfc1a9abc61e201572",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134418.883017000Z-000023.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 23,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 7,
+ "bytes": 6307,
+ "digest": "d138f406f0adf355948c57472724a164f071fddc8345d54bd34141f5ec30a9e8",
+ "from_time": 1790171055077,
+ "through_time": 1790171055082
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134418.883017000Z-000024.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 24,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 8948,
+ "digest": "0838da52fe25f6a811363c5345e993e09921263a2ab6752fb8b3c83aa08dedaa",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134418.956112000Z-000025.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 25,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 10,
+ "bytes": 6969,
+ "digest": "f97fe003e52e5a13c024e3a86d90dba60883a30e9eeccc46874b00a31830fdda",
+ "from_time": 1790171057836,
+ "through_time": 1790171057848
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134418.956112000Z-000026.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 26,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 4,
+ "bytes": 4913,
+ "digest": "8a2426806b798b7a6984db8ab5133f124e4231252d060c345cc8a1ee51e82998",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/streams/main/transcript-20260923T134424.082316000Z-000027.sd",
+ "format": "sd",
+ "kind": "transcript",
+ "seq": 27,
+ "round": null,
+ "stream": "main",
+ "run": null,
+ "lines": 5,
+ "bytes": 2725,
+ "digest": "ea883c46d54407a615bcb28027cea861c02f0153af762df0c85353648541d0f0",
+ "from_time": 1790171059347,
+ "through_time": 1790171059349
+ },
+ {
+ "file": "ls-history-history-middleware-7bf102b808e4/provider_body/provider_body-20260923T134424.082316000Z-000028.sd",
+ "format": "sd",
+ "kind": "provider_body",
+ "seq": 28,
+ "round": null,
+ "stream": null,
+ "run": null,
+ "lines": 3,
+ "bytes": 2356,
+ "digest": "91f7139e9faa69cb004d9fee50f2e7b77cc1304ecd130753606b6c93d00bb370",
+ "from_time": null,
+ "through_time": null
+ },
+ {
+ "file": "_conversations/ls-history-history-middleware-7bf102b808e4/rounds/r000001-12d95b91eccf.sf",
+ "format": "sf",
+ "kind": "round",
+ "seq": null,
+ "round": 1,
+ "stream": null,
+ "run": null,
+ "lines": 60,
+ "bytes": 18013,
+ "digest": "24887d0a8943bbf241cec8199f14ccd8dbeb0ad96471e529c9493e9aa9338aeb",
+ "from_time": 1790171011262,
+ "through_time": 1790171059349
+ }
+ ],
+ "streams": [
+ {
+ "id": "stream/main",
+ "name": "main",
+ "role": "main",
+ "label": "",
+ "parent": "",
+ "records": 92,
+ "steps": 36,
+ "talk": "talk/main/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "named_by": "",
+ "opened_by": []
+ }
+ ],
+ "segments": [
+ {
+ "id": "segment/at_1_2",
+ "state": "open",
+ "committable": false,
+ "talks": 6,
+ "from": 1790171011262,
+ "to": 1790171059347
+ }
+ ],
+ "talks": [
+ {
+ "id": "talk/main/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "kind": "talk",
+ "parent": "epoch/main/0",
+ "stream": "main",
+ "at": 1790171011262,
+ "ref": {
+ "seq": 1,
+ "row": 2
+ },
+ "attrs": {
+ "loops": 1,
+ "runs": 1,
+ "trigger": "external"
+ },
+ "label": "Check checkout.",
+ "reply": "The checkout service is currently experiencing degraded performance with a p99 latency of 2350ms, which is significantly higher than the 410ms from an hour ago. The service also has a 1.2% error rate, with payment calls showing particularly high latency at 2210ms p99.",
+ "runs": 1,
+ "steps": 6,
+ "tools": 1,
+ "from": 1790171011262,
+ "to": 1790171015617,
+ "segment": "segment/at_1_2",
+ "children": [
+ {
+ "id": "run/talk_main_01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "kind": "run",
+ "parent": "talk/main/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "stream": "main",
+ "at": 1790171011262,
+ "ref": {
+ "seq": 1,
+ "row": 2
+ },
+ "attrs": {
+ "trigger": "external"
+ },
+ "children": [
+ {
+ "id": "input/1/2",
+ "kind": "message.external",
+ "parent": "run/talk_main_01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "stream": "main",
+ "at": 1790171011262,
+ "ref": {
+ "seq": 1,
+ "row": 2
+ },
+ "text": "Check checkout.",
+ "state": "available",
+ "bytes": 15,
+ "flags": [
+ "external_input"
+ ]
+ },
+ {
+ "id": "call/01a0ce81-d8e7-7dc1-9319-5678c3782076",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "stream": "main",
+ "at": 1790171011303,
+ "ref": {
+ "seq": 1,
+ "row": 6
+ },
+ "refs": [
+ {
+ "seq": 1,
+ "row": 6
+ },
+ {
+ "seq": 3,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 3
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 333,
+ "out": 57
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 2,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 4,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/3/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce81-d8e7-7dc1-9319-5678c3782076",
+ "stream": "main",
+ "at": 1790171013852,
+ "ref": {
+ "seq": 3,
+ "row": 7,
+ "block": 0
+ },
+ "text": "I'll check the health of the checkout service for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 81,
+ "flags": [
+ "finished"
+ ]
+ },
+ {
+ "id": "tool/tooluse_8G2kiRdP8vZqqW2boXDcnk",
+ "kind": "tool",
+ "parent": "call/01a0ce81-d8e7-7dc1-9319-5678c3782076",
+ "stream": "main",
+ "at": 1790171013852,
+ "ref": {
+ "seq": 3,
+ "row": 7,
+ "block": 2
+ },
+ "refs": [
+ {
+ "seq": 3,
+ "row": 7,
+ "block": 2
+ },
+ {
+ "seq": 3,
+ "row": 2,
+ "block": 0
+ }
+ ],
+ "attrs": {
+ "name": "service_health",
+ "result": "available",
+ "result_join": "exact_unique",
+ "timing": "unavailable"
+ },
+ "text": "I'll check the health of the checkout service for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 22,
+ "flags": [
+ "finished"
+ ],
+ "name": "service_health",
+ "result": "{\"p99_ms\": 2350, \"p99_ms_1h_ago\": 410, \"error_rate\": 0.012, \"calls\": {\"payment\": {\"p99_ms\": 2210}}}",
+ "result_state": "available",
+ "result_bytes": 99,
+ "request_to_result_ms": 5,
+ "request_to_result_join": "exact_unique"
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce81-e2e6-75e0-bd55-0ed8fe38ae19",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "stream": "main",
+ "at": 1790171013862,
+ "ref": {
+ "seq": 3,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 3,
+ "row": 5
+ },
+ {
+ "seq": 5,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 5
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 459,
+ "out": 62
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 4,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 6,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/5/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce81-e2e6-75e0-bd55-0ed8fe38ae19",
+ "stream": "main",
+ "at": 1790171015617,
+ "ref": {
+ "seq": 5,
+ "row": 7,
+ "block": 0
+ },
+ "text": "The checkout service is currently experiencing degraded performance with a p99 latency of 2350ms, which is significantly higher than the 410ms from an hour ago. The service also has a 1.2% error rate, with payment calls showing particularly high latency at 2210ms p99.",
+ "state": "available",
+ "bytes": 268,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "type": "in_segment",
+ "other": "segment/at_1_2",
+ "dir": "out",
+ "quality": "exact_unique",
+ "via": "activity window"
+ }
+ ]
+ },
+ {
+ "id": "talk/main/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "kind": "talk",
+ "parent": "epoch/main/0",
+ "stream": "main",
+ "at": 1790171015621,
+ "ref": {
+ "seq": 5,
+ "row": 1
+ },
+ "attrs": {
+ "loops": 1,
+ "runs": 1,
+ "trigger": "external"
+ },
+ "label": "Now check payment.",
+ "reply": "The payment service is experiencing severe performance degradation with a p99 latency of 2190ms, which is nearly 10 times higher than the 220ms from an hour ago, and it has a 1.9% error rate. Additionally, the database connection pool is completely saturated with all 20 connections in use, resulting in high wait times of 1840ms p99 for database connections.",
+ "runs": 1,
+ "steps": 6,
+ "tools": 1,
+ "from": 1790171015621,
+ "to": 1790171020750,
+ "segment": "segment/at_1_2",
+ "children": [
+ {
+ "id": "run/talk_main_01a0ce81-e9c5-7872-a69e-c0d477d573d6/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "kind": "run",
+ "parent": "talk/main/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "stream": "main",
+ "at": 1790171015621,
+ "ref": {
+ "seq": 5,
+ "row": 1
+ },
+ "attrs": {
+ "trigger": "external"
+ },
+ "children": [
+ {
+ "id": "input/5/1",
+ "kind": "message.external",
+ "parent": "run/talk_main_01a0ce81-e9c5-7872-a69e-c0d477d573d6/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "stream": "main",
+ "at": 1790171015621,
+ "ref": {
+ "seq": 5,
+ "row": 1
+ },
+ "text": "Now check payment.",
+ "state": "available",
+ "bytes": 18,
+ "flags": [
+ "external_input"
+ ]
+ },
+ {
+ "id": "call/01a0ce81-e9c8-71f1-b3a9-1faf6a016e07",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-e9c5-7872-a69e-c0d477d573d6/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "stream": "main",
+ "at": 1790171015624,
+ "ref": {
+ "seq": 5,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 5,
+ "row": 5
+ },
+ {
+ "seq": 7,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 7
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 528,
+ "out": 56
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 6,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 8,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/7/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce81-e9c8-71f1-b3a9-1faf6a016e07",
+ "stream": "main",
+ "at": 1790171017367,
+ "ref": {
+ "seq": 7,
+ "row": 7,
+ "block": 0
+ },
+ "text": "I'll check the health of the payment service for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 80,
+ "flags": [
+ "finished"
+ ]
+ },
+ {
+ "id": "tool/tooluse_9fbUIW8bgmop1oTMjSW2A8",
+ "kind": "tool",
+ "parent": "call/01a0ce81-e9c8-71f1-b3a9-1faf6a016e07",
+ "stream": "main",
+ "at": 1790171017367,
+ "ref": {
+ "seq": 7,
+ "row": 7,
+ "block": 2
+ },
+ "refs": [
+ {
+ "seq": 7,
+ "row": 7,
+ "block": 2
+ },
+ {
+ "seq": 7,
+ "row": 2,
+ "block": 0
+ }
+ ],
+ "attrs": {
+ "name": "service_health",
+ "result": "available",
+ "result_join": "exact_unique",
+ "timing": "unavailable"
+ },
+ "text": "I'll check the health of the payment service for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 21,
+ "flags": [
+ "finished"
+ ],
+ "name": "service_health",
+ "result": "{\"p99_ms\": 2190, \"p99_ms_1h_ago\": 220, \"error_rate\": 0.019, \"db_pool\": {\"size\": 20, \"in_use\": 20, \"wait_ms_p99\": 1840}}",
+ "result_state": "available",
+ "result_bytes": 119,
+ "request_to_result_ms": 5,
+ "request_to_result_join": "exact_unique"
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce81-f0a1-7e83-aca5-19e970530e8a",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-e9c5-7872-a69e-c0d477d573d6/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "stream": "main",
+ "at": 1790171017377,
+ "ref": {
+ "seq": 7,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 7,
+ "row": 5
+ },
+ {
+ "seq": 9,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 9
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 665,
+ "out": 82
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 8,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 10,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/9/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce81-f0a1-7e83-aca5-19e970530e8a",
+ "stream": "main",
+ "at": 1790171020750,
+ "ref": {
+ "seq": 9,
+ "row": 7,
+ "block": 0
+ },
+ "text": "The payment service is experiencing severe performance degradation with a p99 latency of 2190ms, which is nearly 10 times higher than the 220ms from an hour ago, and it has a 1.9% error rate. Additionally, the database connection pool is completely saturated with all 20 connections in use, resulting in high wait times of 1840ms p99 for database connections.",
+ "state": "available",
+ "bytes": 359,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "type": "in_segment",
+ "other": "segment/at_1_2",
+ "dir": "out",
+ "quality": "exact_unique",
+ "via": "activity window"
+ }
+ ]
+ },
+ {
+ "id": "talk/main/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "kind": "talk",
+ "parent": "epoch/main/0",
+ "stream": "main",
+ "at": 1790171020753,
+ "ref": {
+ "seq": 9,
+ "row": 1
+ },
+ "attrs": {
+ "loops": 1,
+ "runs": 1,
+ "trigger": "external"
+ },
+ "label": "And inventory?",
+ "reply": "The inventory service is performing normally with a p99 latency of 61ms, which is stable compared to 58ms an hour ago, and it has a 0% error rate. This indicates the inventory service is not contributing to the performance issues affecting the checkout and payment services.",
+ "runs": 1,
+ "steps": 8,
+ "tools": 1,
+ "from": 1790171020753,
+ "to": 1790171029043,
+ "segment": "segment/at_1_2",
+ "children": [
+ {
+ "id": "run/talk_main_01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "kind": "run",
+ "parent": "talk/main/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "stream": "main",
+ "at": 1790171020753,
+ "ref": {
+ "seq": 9,
+ "row": 1
+ },
+ "attrs": {
+ "trigger": "external"
+ },
+ "children": [
+ {
+ "id": "input/9/1",
+ "kind": "message.external",
+ "parent": "run/talk_main_01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "stream": "main",
+ "at": 1790171020753,
+ "ref": {
+ "seq": 9,
+ "row": 1
+ },
+ "text": "And inventory?",
+ "state": "available",
+ "bytes": 14,
+ "flags": [
+ "external_input"
+ ]
+ },
+ {
+ "id": "call/01a0ce81-fdd4-7630-a6d2-01b4216a2a52",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "stream": "main",
+ "at": 1790171020756,
+ "ref": {
+ "seq": 9,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 9,
+ "row": 5
+ },
+ {
+ "seq": 11,
+ "row": 5
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 5,
+ "seq": 11
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 727,
+ "out": 167
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 10,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 12,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/11/5:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce81-fdd4-7630-a6d2-01b4216a2a52",
+ "stream": "main",
+ "at": 1790171024966,
+ "ref": {
+ "seq": 11,
+ "row": 5,
+ "block": 0
+ },
+ "text": "## SESSION INTENT\nThe user's primary goal is to diagnose performance issues within the microservices system, starting with the checkout service and then the payment service.\n\n## SUMMARY\nThe checkout service was checked and found to be experiencing severe performance degradation. Its current p99 latency is 2350ms, a significant increase from 410ms an hour ago. The service also has a 1.2% error rate. A key finding is that calls to the payment service from wit [...]
+ "state": "available",
+ "bytes": 769,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce82-0e48-7421-be26-32080a141b1b",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "stream": "main",
+ "at": 1790171024969,
+ "ref": {
+ "seq": 11,
+ "row": 2
+ },
+ "refs": [
+ {
+ "seq": 11,
+ "row": 2
+ },
+ {
+ "seq": 13,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 13
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 731,
+ "out": 57
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 12,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 14,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/13/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-0e48-7421-be26-32080a141b1b",
+ "stream": "main",
+ "at": 1790171027042,
+ "ref": {
+ "seq": 13,
+ "row": 7,
+ "block": 0
+ },
+ "text": "I'll check the health of the inventory service for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 82,
+ "flags": [
+ "finished"
+ ]
+ },
+ {
+ "id": "tool/tooluse_XC4MUtPFpMcGVwrjYTFVV3",
+ "kind": "tool",
+ "parent": "call/01a0ce82-0e48-7421-be26-32080a141b1b",
+ "stream": "main",
+ "at": 1790171027042,
+ "ref": {
+ "seq": 13,
+ "row": 7,
+ "block": 2
+ },
+ "refs": [
+ {
+ "seq": 13,
+ "row": 7,
+ "block": 2
+ },
+ {
+ "seq": 13,
+ "row": 2,
+ "block": 0
+ }
+ ],
+ "attrs": {
+ "name": "service_health",
+ "result": "available",
+ "result_join": "exact_unique",
+ "timing": "unavailable"
+ },
+ "text": "I'll check the health of the inventory service for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 23,
+ "flags": [
+ "finished"
+ ],
+ "name": "service_health",
+ "result": "{\"p99_ms\": 61, \"p99_ms_1h_ago\": 58, \"error_rate\": 0.0}",
+ "result_state": "available",
+ "result_bytes": 54,
+ "request_to_result_ms": 3,
+ "request_to_result_join": "exact_unique"
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce82-1669-71e0-8668-7fb1407f70d7",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "stream": "main",
+ "at": 1790171027049,
+ "ref": {
+ "seq": 13,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 13,
+ "row": 5
+ },
+ {
+ "seq": 15,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 15
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 839,
+ "out": 58
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 14,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 16,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/15/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-1669-71e0-8668-7fb1407f70d7",
+ "stream": "main",
+ "at": 1790171029043,
+ "ref": {
+ "seq": 15,
+ "row": 7,
+ "block": 0
+ },
+ "text": "The inventory service is performing normally with a p99 latency of 61ms, which is stable compared to 58ms an hour ago, and it has a 0% error rate. This indicates the inventory service is not contributing to the performance issues affecting the checkout and payment services.",
+ "state": "available",
+ "bytes": 274,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "type": "in_segment",
+ "other": "segment/at_1_2",
+ "dir": "out",
+ "quality": "exact_unique",
+ "via": "activity window"
+ }
+ ]
+ },
+ {
+ "id": "talk/main/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "kind": "talk",
+ "parent": "epoch/main/0",
+ "stream": "main",
+ "at": 1790171029047,
+ "ref": {
+ "seq": 15,
+ "row": 1
+ },
+ "attrs": {
+ "loops": 1,
+ "runs": 1,
+ "trigger": "external"
+ },
+ "label": "Which of the three is in the worst state?",
+ "reply": "Based on the health data for all three services, the payment service is in the worst state with a p99 latency of 2190ms (vs. 220ms an hour ago) and a 1.9% error rate, followed by the checkout service with 2350ms p99 latency and 1.2% error rate, while the inventory service is performing normally with only 61ms p99 latency and 0% error rate. The payment service's database connection pool saturation (20/20 connections in use) makes it the primary bottleneck in the system.",
+ "runs": 1,
+ "steps": 5,
+ "from": 1790171029047,
+ "to": 1790171047632,
+ "segment": "segment/at_1_2",
+ "children": [
+ {
+ "id": "run/talk_main_01a0ce82-1e37-78b2-8c65-990b0fbe63a8/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "kind": "run",
+ "parent": "talk/main/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "stream": "main",
+ "at": 1790171029047,
+ "ref": {
+ "seq": 15,
+ "row": 1
+ },
+ "attrs": {
+ "trigger": "external"
+ },
+ "children": [
+ {
+ "id": "input/15/1",
+ "kind": "message.external",
+ "parent": "run/talk_main_01a0ce82-1e37-78b2-8c65-990b0fbe63a8/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "stream": "main",
+ "at": 1790171029047,
+ "ref": {
+ "seq": 15,
+ "row": 1
+ },
+ "text": "Which of the three is in the worst state?",
+ "state": "available",
+ "bytes": 41,
+ "flags": [
+ "external_input"
+ ]
+ },
+ {
+ "id": "call/01a0ce82-1e3a-77e3-8942-a55f5f69664e",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce82-1e37-78b2-8c65-990b0fbe63a8/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "stream": "main",
+ "at": 1790171029050,
+ "ref": {
+ "seq": 15,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 15,
+ "row": 5
+ },
+ {
+ "seq": 17,
+ "row": 5
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 5,
+ "seq": 17
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 929,
+ "out": 228
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 16,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 18,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/17/5:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-1e3a-77e3-8942-a55f5f69664e",
+ "stream": "main",
+ "at": 1790171044170,
+ "ref": {
+ "seq": 17,
+ "row": 5,
+ "block": 0
+ },
+ "text": "## SESSION INTENT\nDiagnose performance issues within the microservices system, starting with the checkout service and then the payment service, to identify the root cause of latency degradation.\n\n## SUMMARY\nThe checkout service has severe performance degradation (p99 latency: 2350ms vs. 410ms an hour ago, 1.2% error rate). Analysis identified calls to the payment service as a major contributor (p99: 2210ms). The payment service itself is confirmed as a root [...]
+ "state": "available",
+ "bytes": 1017,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce82-594c-75c3-af02-0ac7b3f6bc3e",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce82-1e37-78b2-8c65-990b0fbe63a8/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "stream": "main",
+ "at": 1790171044172,
+ "ref": {
+ "seq": 17,
+ "row": 2
+ },
+ "refs": [
+ {
+ "seq": 17,
+ "row": 2
+ },
+ {
+ "seq": 19,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 19
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 746,
+ "out": 118
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 18,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 20,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/19/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-594c-75c3-af02-0ac7b3f6bc3e",
+ "stream": "main",
+ "at": 1790171047632,
+ "ref": {
+ "seq": 19,
+ "row": 7,
+ "block": 0
+ },
+ "text": "Based on the health data for all three services, the payment service is in the worst state with a p99 latency of 2190ms (vs. 220ms an hour ago) and a 1.9% error rate, followed by the checkout service with 2350ms p99 latency and 1.2% error rate, while the inventory service is performing normally with only 61ms p99 latency and 0% error rate. The payment service's database connection pool saturation (20/20 connections in use) makes it the primary bottleneck in the [...]
+ "state": "available",
+ "bytes": 473,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "type": "in_segment",
+ "other": "segment/at_1_2",
+ "dir": "out",
+ "quality": "exact_unique",
+ "via": "activity window"
+ }
+ ]
+ },
+ {
+ "id": "talk/main/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "kind": "talk",
+ "parent": "epoch/main/0",
+ "stream": "main",
+ "at": 1790171047636,
+ "ref": {
+ "seq": 19,
+ "row": 1
+ },
+ "attrs": {
+ "loops": 1,
+ "runs": 1,
+ "trigger": "external"
+ },
+ "label": "Check checkout again.",
+ "reply": "The checkout service remains in severe degradation with p99 latency at 2350ms (vs. 410ms an hour ago) and a 1.2% error rate, with calls to the payment service showing 2210ms p99 latency. This confirms the checkout service's poor performance is primarily driven by the payment service issues identified earlier.",
+ "runs": 1,
+ "steps": 8,
+ "tools": 1,
+ "from": 1790171047636,
+ "to": 1790171057836,
+ "segment": "segment/at_1_2",
+ "children": [
+ {
+ "id": "run/talk_main_01a0ce82-66d4-7553-bc46-342573d999e8/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "kind": "run",
+ "parent": "talk/main/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "stream": "main",
+ "at": 1790171047636,
+ "ref": {
+ "seq": 19,
+ "row": 1
+ },
+ "attrs": {
+ "trigger": "external"
+ },
+ "children": [
+ {
+ "id": "input/19/1",
+ "kind": "message.external",
+ "parent": "run/talk_main_01a0ce82-66d4-7553-bc46-342573d999e8/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "stream": "main",
+ "at": 1790171047636,
+ "ref": {
+ "seq": 19,
+ "row": 1
+ },
+ "text": "Check checkout again.",
+ "state": "available",
+ "bytes": 21,
+ "flags": [
+ "external_input"
+ ]
+ },
+ {
+ "id": "call/01a0ce82-66d9-7083-8f4b-27e521242966",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce82-66d4-7553-bc46-342573d999e8/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "stream": "main",
+ "at": 1790171047642,
+ "ref": {
+ "seq": 19,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 19,
+ "row": 5
+ },
+ {
+ "seq": 21,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 21
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 871,
+ "out": 55
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 20,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 22,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/21/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-66d9-7083-8f4b-27e521242966",
+ "stream": "main",
+ "at": 1790171049393,
+ "ref": {
+ "seq": 21,
+ "row": 7,
+ "block": 0
+ },
+ "text": "I'll check the checkout service again for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 73,
+ "flags": [
+ "finished"
+ ]
+ },
+ {
+ "id": "tool/tooluse_Ou1tMOKPVifjxo1qxi9bQI",
+ "kind": "tool",
+ "parent": "call/01a0ce82-66d9-7083-8f4b-27e521242966",
+ "stream": "main",
+ "at": 1790171049393,
+ "ref": {
+ "seq": 21,
+ "row": 7,
+ "block": 2
+ },
+ "refs": [
+ {
+ "seq": 21,
+ "row": 7,
+ "block": 2
+ },
+ {
+ "seq": 21,
+ "row": 2,
+ "block": 0
+ }
+ ],
+ "attrs": {
+ "name": "service_health",
+ "result": "available",
+ "result_join": "exact_unique",
+ "timing": "unavailable"
+ },
+ "text": "I'll check the checkout service again for you.\n\n\u003c|DSML|function_calls",
+ "state": "available",
+ "bytes": 22,
+ "flags": [
+ "finished"
+ ],
+ "name": "service_health",
+ "result": "{\"p99_ms\": 2350, \"p99_ms_1h_ago\": 410, \"error_rate\": 0.012, \"calls\": {\"payment\": {\"p99_ms\": 2210}}}",
+ "result_state": "available",
+ "result_bytes": 99,
+ "request_to_result_ms": 5,
+ "request_to_result_join": "exact_unique"
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce82-6db9-7f42-b822-edeba984d08c",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce82-66d4-7553-bc46-342573d999e8/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "stream": "main",
+ "at": 1790171049401,
+ "ref": {
+ "seq": 21,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 21,
+ "row": 5
+ },
+ {
+ "seq": 23,
+ "row": 5
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 5,
+ "seq": 23
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 943,
+ "out": 259
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 22,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 24,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/23/5:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-6db9-7f42-b822-edeba984d08c",
+ "stream": "main",
+ "at": 1790171055077,
+ "ref": {
+ "seq": 23,
+ "row": 5,
+ "block": 0
+ },
+ "text": "## SESSION INTENT\nDiagnose performance issues within the microservices system to identify the root cause of latency degradation.\n\n## SUMMARY\nThe checkout service has severe performance degradation (p99 latency: 2350ms vs. 410ms an hour ago, 1.2% error rate). Analysis identified calls to the payment service as a major contributor (p99: 2210ms). The payment service is confirmed as the primary root cause, showing the most severe degradation (p99 latency: 2190m [...]
+ "state": "available",
+ "bytes": 1105,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "call/01a0ce82-83ea-7360-b77a-2900c5a4119e",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce82-66d4-7553-bc46-342573d999e8/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "stream": "main",
+ "at": 1790171055082,
+ "ref": {
+ "seq": 23,
+ "row": 2
+ },
+ "refs": [
+ {
+ "seq": 23,
+ "row": 2
+ },
+ {
+ "seq": 25,
+ "row": 7
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 7,
+ "seq": 25
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 847,
+ "out": 71
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 24,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 26,
+ "row": 2
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/25/7:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-83ea-7360-b77a-2900c5a4119e",
+ "stream": "main",
+ "at": 1790171057836,
+ "ref": {
+ "seq": 25,
+ "row": 7,
+ "block": 0
+ },
+ "text": "The checkout service remains in severe degradation with p99 latency at 2350ms (vs. 410ms an hour ago) and a 1.2% error rate, with calls to the payment service showing 2210ms p99 latency. This confirms the checkout service's poor performance is primarily driven by the payment service issues identified earlier.",
+ "state": "available",
+ "bytes": 310,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "type": "in_segment",
+ "other": "segment/at_1_2",
+ "dir": "out",
+ "quality": "exact_unique",
+ "via": "activity window"
+ }
+ ]
+ },
+ {
+ "id": "talk/main/01a0ce82-8eb2-7471-b49c-4dda11c1a929",
+ "kind": "talk",
+ "parent": "epoch/main/0",
+ "stream": "main",
+ "at": 1790171057842,
+ "ref": {
+ "seq": 25,
+ "row": 1
+ },
+ "attrs": {
+ "loops": 1,
+ "runs": 1,
+ "trigger": "external"
+ },
+ "label": "Say in one sentence what we found.",
+ "reply": "The payment service is in the worst state with severe latency degradation (2190ms p99) and database connection pool saturation, causing cascading issues to the checkout service.",
+ "runs": 1,
+ "steps": 3,
+ "from": 1790171057842,
+ "to": 1790171059347,
+ "segment": "segment/at_1_2",
+ "children": [
+ {
+ "id": "run/talk_main_01a0ce82-8eb2-7471-b49c-4dda11c1a929/01a0ce82-8eb2-7471-b49c-4dda11c1a929",
+ "kind": "run",
+ "parent": "talk/main/01a0ce82-8eb2-7471-b49c-4dda11c1a929",
+ "stream": "main",
+ "at": 1790171057842,
+ "ref": {
+ "seq": 25,
+ "row": 1
+ },
+ "attrs": {
+ "trigger": "external"
+ },
+ "children": [
+ {
+ "id": "input/25/1",
+ "kind": "message.external",
+ "parent": "run/talk_main_01a0ce82-8eb2-7471-b49c-4dda11c1a929/01a0ce82-8eb2-7471-b49c-4dda11c1a929",
+ "stream": "main",
+ "at": 1790171057842,
+ "ref": {
+ "seq": 25,
+ "row": 1
+ },
+ "text": "Say in one sentence what we found.",
+ "state": "available",
+ "bytes": 34,
+ "flags": [
+ "external_input"
+ ]
+ },
+ {
+ "id": "call/01a0ce82-8eb8-78a0-8e82-df1f6cbbf228",
+ "kind": "llm.call",
+ "parent": "run/talk_main_01a0ce82-8eb2-7471-b49c-4dda11c1a929/01a0ce82-8eb2-7471-b49c-4dda11c1a929",
+ "stream": "main",
+ "at": 1790171057848,
+ "ref": {
+ "seq": 25,
+ "row": 5
+ },
+ "refs": [
+ {
+ "seq": 25,
+ "row": 5
+ },
+ {
+ "seq": 27,
+ "row": 2
+ }
+ ],
+ "attrs": {
+ "fragments": 2,
+ "usage": "observed_replayable",
+ "usage_at": {
+ "row": 2,
+ "seq": 27
+ },
+ "usage_from": "last_fragment_in_line_order"
+ },
+ "usage": {
+ "in": 929,
+ "out": 35
+ },
+ "provider_bodies": [
+ {
+ "role": "request",
+ "ref": {
+ "seq": 26,
+ "row": 1
+ }
+ },
+ {
+ "role": "response",
+ "ref": {
+ "seq": 28,
+ "row": 1
+ }
+ }
+ ],
+ "children": [
+ {
+ "id": "msg/27/2:0",
+ "kind": "message.assistant",
+ "parent": "call/01a0ce82-8eb8-78a0-8e82-df1f6cbbf228",
+ "stream": "main",
+ "at": 1790171059347,
+ "ref": {
+ "seq": 27,
+ "row": 2,
+ "block": 0
+ },
+ "text": "The payment service is in the worst state with severe latency degradation (2190ms p99) and database connection pool saturation, causing cascading issues to the checkout service.",
+ "state": "available",
+ "bytes": 177,
+ "flags": [
+ "finished"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "type": "in_segment",
+ "other": "segment/at_1_2",
+ "dir": "out",
+ "quality": "exact_unique",
+ "via": "activity window"
+ }
+ ]
+ }
+ ],
+ "loose": [],
+ "relations": [
+ {
+ "id": "rel/in_segment/talk_main_01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7/segment_at_1_2",
+ "type": "in_segment",
+ "from": "talk/main/01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7",
+ "to": "segment/at_1_2",
+ "quality": "exact_unique",
+ "via": "activity window",
+ "evidence": [
+ {
+ "seq": 1,
+ "row": 2
+ }
+ ]
+ },
+ {
+ "id": "rel/in_segment/talk_main_01a0ce81-e9c5-7872-a69e-c0d477d573d6/segment_at_1_2",
+ "type": "in_segment",
+ "from": "talk/main/01a0ce81-e9c5-7872-a69e-c0d477d573d6",
+ "to": "segment/at_1_2",
+ "quality": "exact_unique",
+ "via": "activity window",
+ "evidence": [
+ {
+ "seq": 5,
+ "row": 1
+ }
+ ]
+ },
+ {
+ "id": "rel/in_segment/talk_main_01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd/segment_at_1_2",
+ "type": "in_segment",
+ "from": "talk/main/01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd",
+ "to": "segment/at_1_2",
+ "quality": "exact_unique",
+ "via": "activity window",
+ "evidence": [
+ {
+ "seq": 9,
+ "row": 1
+ }
+ ]
+ },
+ {
+ "id": "rel/in_segment/talk_main_01a0ce82-1e37-78b2-8c65-990b0fbe63a8/segment_at_1_2",
+ "type": "in_segment",
+ "from": "talk/main/01a0ce82-1e37-78b2-8c65-990b0fbe63a8",
+ "to": "segment/at_1_2",
+ "quality": "exact_unique",
+ "via": "activity window",
+ "evidence": [
+ {
+ "seq": 15,
+ "row": 1
+ }
+ ]
+ },
+ {
+ "id": "rel/in_segment/talk_main_01a0ce82-66d4-7553-bc46-342573d999e8/segment_at_1_2",
+ "type": "in_segment",
+ "from": "talk/main/01a0ce82-66d4-7553-bc46-342573d999e8",
+ "to": "segment/at_1_2",
+ "quality": "exact_unique",
+ "via": "activity window",
+ "evidence": [
+ {
+ "seq": 19,
+ "row": 1
+ }
+ ]
+ },
+ {
+ "id": "rel/in_segment/talk_main_01a0ce82-8eb2-7471-b49c-4dda11c1a929/segment_at_1_2",
+ "type": "in_segment",
+ "from": "talk/main/01a0ce82-8eb2-7471-b49c-4dda11c1a929",
+ "to": "segment/at_1_2",
+ "quality": "exact_unique",
+ "via": "activity window",
+ "evidence": [
+ {
+ "seq": 25,
+ "row": 1
+ }
+ ]
+ }
+ ],
+ "unresolved": [],
+ "workspace_changes": []
+}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-10.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-10.sd
new file mode 100644
index 00000000..3e669cf7
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-10.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":10,"at":"2026-09-23T13:43:46.266474Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"7600ee282608","bytes":3710,"id":"01a0ce81-fdd4-7630-a6d2-01b4216a2a52:request","call":"01a0ce81-fdd4-7630-a6d2-01b4216a2a52","run":"01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd","model":"deepseek.v3.2","parts":[{"k":"data","data":"<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\ [...]
+{"ord":1,"off":0,"sha":"62c7a6cef103","bytes":1648,"id":"01a0ce81-f0a1-7e83-aca5-19e970530e8a:response","call":"01a0ce81-f0a1-7e83-aca5-19e970530e8a","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134340.811268000Z-000012.request","sha256":"62c7a6cef103ce023ab2325175fededc0ec0c440d17e7f89d0f8e7fa5075ee65","bytes":1648,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"1979a1a425b9b804b2994768915e95ec9613f032f315b21129fbab4e7604041b"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-12.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-12.sd
new file mode 100644
index 00000000..af487fc8
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-12.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":12,"at":"2026-09-23T13:43:46.776398Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"d0130471d6da","bytes":4128,"id":"01a0ce82-0e48-7421-be26-32080a141b1b:request","call":"01a0ce82-0e48-7421-be26-32080a141b1b","run":"01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134345.031364000Z-000019.request","sha256":"d0130471d6daed9c2e87b8d2baa53724e783ca766d6f666686d474e6c53ba6f4","bytes":4128,"depth":0,"chain":"7b290942831b847c","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"282ae11826e8","bytes":2489,"id":"01a0ce81-fdd4-7630-a6d2-01b4216a2a52:response","call":"01a0ce81-fdd4-7630-a6d2-01b4216a2a52","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134345.031364000Z-000019.request","sha256":"282ae11826e87453c527ce9f9aa06b3efde825c04d73f76f4e344468fc0cad29","bytes":2489,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"950588cbf00e32b80ca17bd775861307edbc3d64ca189c4c3818121c25bf5c25"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-14.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-14.sd
new file mode 100644
index 00000000..9b523316
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-14.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":14,"at":"2026-09-23T13:43:52.167757Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"2310b6b2ea1e","bytes":5574,"id":"01a0ce82-1669-71e0-8668-7fb1407f70d7:request","call":"01a0ce82-1669-71e0-8668-7fb1407f70d7","run":"01a0ce81-fdd1-7e00-ad1d-dd2602ecf4fd","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134347.112024000Z-000023.request","sha256":"2310b6b2ea1e764b4626ef7695a9b1f012d64384aa952be96c8988e17889f07c","bytes":5574,"depth":1,"chain":"26e1e0a35217df11","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"17708fe14f9d","bytes":1350,"id":"01a0ce82-0e48-7421-be26-32080a141b1b:response","call":"01a0ce82-0e48-7421-be26-32080a141b1b","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134347.112024000Z-000023.request","sha256":"17708fe14f9dba28a3e1fe2be0262554ecc7a2ed90b0a9c969120668770eca55","bytes":1350,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"43f311f1ea84c248dc77e19f2fd16bbc4ec02c32d6267088c536c7982b12314a"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-16.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-16.sd
new file mode 100644
index 00000000..f72d7706
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-16.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":16,"at":"2026-09-23T13:43:52.307775Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"0efdf4c2aa33","bytes":4631,"id":"01a0ce82-1e3a-77e3-8942-a55f5f69664e:request","call":"01a0ce82-1e3a-77e3-8942-a55f5f69664e","run":"01a0ce82-1e37-78b2-8c65-990b0fbe63a8","model":"deepseek.v3.2","parts":[{"k":"data","data":"<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\ [...]
+{"ord":1,"off":0,"sha":"44ce320786e4","bytes":1478,"id":"01a0ce82-1669-71e0-8668-7fb1407f70d7:response","call":"01a0ce82-1669-71e0-8668-7fb1407f70d7","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134349.111887000Z-000025.request","sha256":"44ce320786e4565f4a280934bd0eaf89fe298d0079af95fdb959254b8159a57d","bytes":1478,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"545520048f88587057a3a6639e0f9490dcfa2d77840e0d486a18cdeb32a7f333"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-18.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-18.sd
new file mode 100644
index 00000000..54bc35b1
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-18.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":18,"at":"2026-09-23T13:44:08.415633Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"0fd8b5ed1e67","bytes":4251,"id":"01a0ce82-594c-75c3-af02-0ac7b3f6bc3e:request","call":"01a0ce82-594c-75c3-af02-0ac7b3f6bc3e","run":"01a0ce82-1e37-78b2-8c65-990b0fbe63a8","model":"deepseek.v3.2","parts":[{"k":"data","data":"Here is a summary of the conversation to date:\n\n## SESSION INTENT\nDiagnose performance issues within the microservices system, starting with the checkout service and then the payment service, to identify the root cause of latency degradation. [...]
+{"ord":1,"off":0,"sha":"7607c7873527","bytes":2988,"id":"01a0ce82-1e3a-77e3-8942-a55f5f69664e:response","call":"01a0ce82-1e3a-77e3-8942-a55f5f69664e","model":"deepseek.v3.2","parts":[{"k":"data","data":"## SESSION INTENT\nDiagnose performance issues within the microservices system, starting with the checkout service and then the payment service, to identify the root cause of latency degradation.\n\n## SUMMARY\nThe checkout service has severe performance degradation (p99 latency: 2350ms v [...]
+{"t":"end","records":2,"digest":"022ced8bf15b1768db38b4eea27f40dd50a7b8d38fde46ced363b266db6ec46b"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-2.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-2.sd
new file mode 100644
index 00000000..6316d892
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-2.sd
@@ -0,0 +1,3 @@
+{"h":1,"schema":"sd/1","seq":2,"at":"2026-09-23T13:43:34.87087Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"6867725063f5","bytes":417,"id":"01a0ce81-d8e7-7dc1-9319-5678c3782076:request","call":"01a0ce81-d8e7-7dc1-9319-5678c3782076","run":"01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134331.356289000Z-000003.request","sha256":"6867725063f5489c2982ef840cc78ca254f494a299a7cb4bd83144ddfa8b68c3","bytes":417,"depth":0,"chain":"4db5d5b770f8170c","model":"deepseek.v3.2 [...]
+{"t":"end","records":1,"digest":"fd28ccc3acb8bd1c263ec72af23cf4eacfb5f4343ecfd103becf89b9a319a11e"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-20.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-20.sd
new file mode 100644
index 00000000..4a17c594
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-20.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":20,"at":"2026-09-23T13:44:08.492417Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"5435ef738316","bytes":5707,"id":"01a0ce82-66d9-7083-8f4b-27e521242966:request","call":"01a0ce82-66d9-7083-8f4b-27e521242966","run":"01a0ce82-66d4-7553-bc46-342573d999e8","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134407.703682000Z-000003.request","sha256":"5435ef738316f10da9f1f197f105100d14cf2972e469d42cc9473f81bc8ad724","bytes":5707,"depth":1,"chain":"600f2662ced34a95","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"c7561d727ca2","bytes":1877,"id":"01a0ce82-594c-75c3-af02-0ac7b3f6bc3e:response","call":"01a0ce82-594c-75c3-af02-0ac7b3f6bc3e","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134407.703682000Z-000003.request","sha256":"c7561d727ca2d3a7862587c9c831cbf60d9c6ecc65f86722e193662c2ea62e87","bytes":1877,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"1e8e046e2697eec0d98475ff36ffa3fb9b651743c21e6113c4a4389240a1e05f"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-22.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-22.sd
new file mode 100644
index 00000000..4a4ff057
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-22.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":22,"at":"2026-09-23T13:44:13.623049Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"411e4b24d109","bytes":4752,"id":"01a0ce82-6db9-7f42-b822-edeba984d08c:request","call":"01a0ce82-6db9-7f42-b822-edeba984d08c","run":"01a0ce82-66d4-7553-bc46-342573d999e8","model":"deepseek.v3.2","parts":[{"k":"data","data":"<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\ [...]
+{"ord":1,"off":0,"sha":"d60231b3d2f4","bytes":1330,"id":"01a0ce82-66d9-7083-8f4b-27e521242966:response","call":"01a0ce82-66d9-7083-8f4b-27e521242966","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134409.461792000Z-000001.request","sha256":"d60231b3d2f4e7ffe3a63b88c0595c4a456014f5500a916d9a196d1005181227","bytes":1330,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"6c2cbd4ff95a0178e63cbde0e203c2a89ebcad4cbfe56bea467ff3ce5700410c"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-24.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-24.sd
new file mode 100644
index 00000000..5d0fe308
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-24.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":24,"at":"2026-09-23T13:44:18.898521Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"8379a9d692a9","bytes":4559,"id":"01a0ce82-83ea-7360-b77a-2900c5a4119e:request","call":"01a0ce82-83ea-7360-b77a-2900c5a4119e","run":"01a0ce82-66d4-7553-bc46-342573d999e8","model":"deepseek.v3.2","parts":[{"k":"data","data":"Here is a summary of the conversation to date:\n\n## SESSION INTENT\nDiagnose performance issues within the microservices system to identify the root cause of latency degradation.\n\n## SUMMARY\nThe checkout service has severe performance degrad [...]
+{"ord":1,"off":0,"sha":"9c9ea5717cf0","bytes":3163,"id":"01a0ce82-6db9-7f42-b822-edeba984d08c:response","call":"01a0ce82-6db9-7f42-b822-edeba984d08c","model":"deepseek.v3.2","parts":[{"k":"data","data":"## SESSION INTENT\nDiagnose performance issues within the microservices system to identify the root cause of latency degradation.\n\n## SUMMARY\nThe checkout service has severe performance degradation (p99 latency: 2350ms vs. 410ms an hour ago, 1.2% error rate). Analysis identified calls [...]
+{"t":"end","records":2,"digest":"64bbaa17b961fa53f00ca2df165429ece955e2110c873617bc6dd58c316bdb60"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-26.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-26.sd
new file mode 100644
index 00000000..b4bb15d2
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-26.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":26,"at":"2026-09-23T13:44:18.971954Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"49580c7e8548","bytes":5864,"id":"01a0ce82-8eb8-78a0-8e82-df1f6cbbf228:request","call":"01a0ce82-8eb8-78a0-8e82-df1f6cbbf228","run":"01a0ce82-8eb2-7471-b49c-4dda11c1a929","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134417.911261000Z-000003.request","sha256":"49580c7e85480a4c6cd4de5fa11c0f6ad93b0a008991ce5732b04e1660d8a738","bytes":5864,"depth":1,"chain":"e47cb9f714109347","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"18ba3e152434","bytes":1550,"id":"01a0ce82-83ea-7360-b77a-2900c5a4119e:response","call":"01a0ce82-83ea-7360-b77a-2900c5a4119e","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134417.911261000Z-000003.request","sha256":"18ba3e15243496da39171e9f8580e34ea4f11a2e13ecd8b3ba1fa9deb38a9135","bytes":1550,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"565fbdd2b8c823985d2d30a32b230d2b4455231ec38ea01c022311f77cd98ad0"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-28.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-28.sd
new file mode 100644
index 00000000..d67fa71c
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-28.sd
@@ -0,0 +1,3 @@
+{"h":1,"schema":"sd/1","seq":28,"at":"2026-09-23T13:44:24.104107Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"4b22b5b33ef4","bytes":1284,"id":"01a0ce82-8eb8-78a0-8e82-df1f6cbbf228:response","call":"01a0ce82-8eb8-78a0-8e82-df1f6cbbf228","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134419.404359000Z-000001.request","sha256":"4b22b5b33ef4e01c570397123f68741b7053952f4446ad7b97e286cb03b0bae4","bytes":1284,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":1,"digest":"dcc2f26e552d9b7a9b05a94ae2e4350fd7af3f2dc0a82f049a7cdc6f627ef992"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-4.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-4.sd
new file mode 100644
index 00000000..7eb8bb81
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-4.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":4,"at":"2026-09-23T13:43:35.016765Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"3aaba5e2a7ec","bytes":1911,"id":"01a0ce81-e2e6-75e0-bd55-0ed8fe38ae19:request","call":"01a0ce81-e2e6-75e0-bd55-0ed8fe38ae19","run":"01a0ce81-d8be-7ed0-aac7-f8a60dbb74c7","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134333.924913000Z-000005.request","sha256":"3aaba5e2a7ec1cb04b88f8b9999912f059d9097e4a76d36e7e2abab757f04c7f","bytes":1911,"depth":0,"chain":"d96a685037cdcafb","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"f7385437e1a4","bytes":1346,"id":"01a0ce81-d8e7-7dc1-9319-5678c3782076:response","call":"01a0ce81-d8e7-7dc1-9319-5678c3782076","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134333.924913000Z-000005.request","sha256":"f7385437e1a4437e9b2483cb7172fa0234fa0f9b97f4de2483f5027946981a79","bytes":1346,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"4cb80817fffd3350d7729d93fbee2dfd109a11a139a5e21ff7b232a580bdac79"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-6.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-6.sd
new file mode 100644
index 00000000..e53f757d
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-6.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":6,"at":"2026-09-23T13:43:40.333838Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"faa8b85f909b","bytes":3158,"id":"01a0ce81-e9c8-71f1-b3a9-1faf6a016e07:request","call":"01a0ce81-e9c8-71f1-b3a9-1faf6a016e07","run":"01a0ce81-e9c5-7872-a69e-c0d477d573d6","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134335.682868000Z-000001.request","sha256":"faa8b85f909b281df4e4546fcc56b9fb1689a315df4cd9c5a10fb2a7ed379f4a","bytes":3158,"depth":0,"chain":"10149bd3d6ddf20f","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"f84cbd014d3c","bytes":1466,"id":"01a0ce81-e2e6-75e0-bd55-0ed8fe38ae19:response","call":"01a0ce81-e2e6-75e0-bd55-0ed8fe38ae19","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134335.682868000Z-000001.request","sha256":"f84cbd014d3c2d145f5d624807ae161d578dbbff29855cd7eaadf24d5b178a3a","bytes":1466,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"80f19ac0b99a30f3e0a1dbfce4bf0bb8f548eb1cb59bc4f64439cd19dabe8f20"}
diff --git a/packages/conversation-view/test/fixtures/langchain/provider_body-8.sd b/packages/conversation-view/test/fixtures/langchain/provider_body-8.sd
new file mode 100644
index 00000000..b1e77ec3
--- /dev/null
+++ b/packages/conversation-view/test/fixtures/langchain/provider_body-8.sd
@@ -0,0 +1,4 @@
+{"h":1,"schema":"sd/1","seq":8,"at":"2026-09-23T13:43:40.646006Z","kind":"provider_body","adapter":"langsmith-ingest/0.1.0","dialect":"langsmith/1","src":".","session":"ls-history-history-middleware-7bf102b808e4"}
+{"ord":1,"off":0,"sha":"7de4254390a8","bytes":4671,"id":"01a0ce81-f0a1-7e83-aca5-19e970530e8a:request","call":"01a0ce81-f0a1-7e83-aca5-19e970530e8a","run":"01a0ce81-e9c5-7872-a69e-c0d477d573d6","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"request","src":"runs-20260923T134337.443361000Z-000005.request","sha256":"7de4254390a81acaebcabff57f225e6b3e7deddee793ea23a8350e0b51001c1e","bytes":4671,"depth":0,"chain":"ebe590958654c2c0","model":"deepseek.v3 [...]
+{"ord":1,"off":0,"sha":"953efd56cdc0","bytes":1342,"id":"01a0ce81-e9c8-71f1-b3a9-1faf6a016e07:response","call":"01a0ce81-e9c8-71f1-b3a9-1faf6a016e07","model":"deepseek.v3.2","parts":[{"k":"data","data":{"schema":"provider_body/1","role":"response","src":"runs-20260923T134337.443361000Z-000005.request","sha256":"953efd56cdc0a3c4b94a3a1a0b5949c84b923f93c10ac97a8fc6796bc31b0bd0","bytes":1342,"depth":0,"model":"deepseek.v3.2","session":"ls-history-history-middleware-7bf102b808e4","call":"01a [...]
+{"t":"end","records":2,"digest":"3d2335dec787004d3b86bf21861978a783a3ccaeb7c984379488d2a05daddfb7"}
diff --git a/packages/conversation-view/test/prompt-langchain.test.ts b/packages/conversation-view/test/prompt-langchain.test.ts
new file mode 100644
index 00000000..8ed9afac
--- /dev/null
+++ b/packages/conversation-view/test/prompt-langchain.test.ts
@@ -0,0 +1,223 @@
+/*
+ * Licensed to Apache Software Foundation (ASF) under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Apache Software Foundation (ASF) licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { readFileSync, readdirSync } from 'node:fs';
+import { resolve } from 'node:path';
+import { afterEach, describe, expect, it } from 'vitest';
+import { mountConversationView, type AszViewDocument, type ConversationView, type StoredFile } from '../src/index.js';
+import { readBody, type ReadBody, type ReadRequest, type ReadResponse } from '../src/prompt/messages.js';
+import { PromptStore, readProviderFile } from '../src/prompt/store.js';
+
+/**
+ * A LangGraph agent with LangChain's SummarizationMiddleware, run on Amazon Bedrock and landed by the
+ * Sessionizer: thirteen model calls, three of them the middleware's own, in fourteen files. Each body
+ * is LangChain's serialized message list, the shape the reader drew as one empty message.
+ */
+const DIR = resolve('test/fixtures/langchain');
+const doc = JSON.parse(readFileSync(resolve(DIR, 'conversation.json'), 'utf8')) as AszViewDocument;
+const files = new Map<number, Uint8Array>(
+ readdirSync(DIR)
+ .filter((n) => n.endsWith('.sd'))
+ .map((n) => [Number(/(\d+)\.sd$/.exec(n)![1]), new Uint8Array(readFileSync(resolve(DIR, n)))]),
+);
+
+function bodies(): Array<{ seq: number; row: number; role: string; read: ReadBody }> {
+ const store = new PromptStore();
+ for (const [seq, bytes] of files) store.addFile({ seq, file: `provider_body-${seq}.sd`, bytes });
+ const out: Array<{ seq: number; row: number; role: string; read: ReadBody }> = [];
+ for (const [seq, bytes] of [...files].sort((a, b) => a[0] - b[0])) {
+ for (const r of readProviderFile(seq, bytes)) {
+ out.push({ seq, row: r.row, role: r.manifest.role, read: readBody(store.bodyAt(seq, r.row), r.manifest.role) });
+ }
+ }
+ return out;
+}
+
+const requests = (): ReadRequest[] => bodies().flatMap((b) => (b.read.kind === 'request' ? [b.read] : []));
+const responses = (): ReadResponse[] => bodies().flatMap((b) => (b.read.kind === 'response' ? [b.read] : []));
+
+function read(body: unknown, role = 'request'): ReadBody {
+ return readBody(new TextEncoder().encode(JSON.stringify(body)), role);
+}
+
+describe('a LangChain body', () => {
+ it('reads as a conversation, every message with its role and its content', () => {
+ const all = bodies();
+ expect(all).toHaveLength(26);
+ for (const b of all) expect(b.read.kind).toBe(b.role);
+ for (const r of requests()) {
+ expect(r.messages.length).toBeGreaterThan(0);
+ for (const m of r.messages) {
+ expect(['system', 'human', 'ai', 'tool']).toContain(m.role);
+ expect(m.blocks.length).toBeGreaterThan(0);
+ }
+ }
+ });
+
+ it('draws each tool call once, and pairs each result with the call it answers', () => {
+ // Bedrock repeats every tool call in the message content, so a reader that also drew tool_calls
+ // showed each one twice.
+ let calls = 0;
+ for (const r of requests()) {
+ const used = r.messages.flatMap((m) => m.blocks).filter((b) => b.kind === 'tool_use');
+ const answered = r.messages.flatMap((m) => m.blocks).filter((b) => b.kind === 'tool_result');
+ const ids = used.map((b) => b.id);
+ expect(new Set(ids).size).toBe(ids.length);
+ for (const result of answered) expect(ids).toContain(result.id);
+ calls += used.length;
+ }
+ expect(calls).toBeGreaterThan(0);
+ });
+
+ it('keeps the summary the middleware wrote, as the message it sent', () => {
+ const summaries = requests().flatMap((r) =>
+ r.messages.filter((m) => m.role === 'human' && (m.blocks[0]?.text ?? '').startsWith('Here is a summary of the conversation to date:')),
+ );
+ expect(summaries.length).toBeGreaterThan(0);
+ });
+
+ it('reads the answer, the model and the tokens a response reports', () => {
+ const all = responses();
+ expect(all).toHaveLength(13);
+ for (const r of all) {
+ expect(r.blocks.length).toBeGreaterThan(0);
+ expect(r.model).toBe('deepseek.v3.2');
+ expect(r.usage?.['input_tokens']).toBeGreaterThan(0);
+ }
+ });
+
+ it('draws a call the content repeats once, with the arguments LangChain parsed', () => {
+ const ai = (content: unknown[]) =>
+ (
+ read({
+ messages: [
+ [
+ {
+ lc: 1,
+ type: 'constructor',
+ id: ['langchain', 'schema', 'messages', 'AIMessage'],
+ kwargs: { type: 'ai', content, tool_calls: [{ name: 'search', args: { q: 'weather' }, id: 'c1', type: 'tool_call' }] },
+ },
+ ],
+ ],
+ }) as ReadRequest
+ ).messages[0]!.blocks;
+ // a streamed provider block still reads {}, and the arguments are in pieces beside it
+ const streamed = ai([
+ { type: 'text', text: 'Looking.' },
+ { type: 'tool_use', id: 'c1', name: 'search', input: {}, partial_json: '{"q": "weather"}' },
+ { type: 'text', text: 'Then I answer.' },
+ ]);
+ // and it stays where the content has it
+ expect(streamed).toEqual([
+ { kind: 'text', text: 'Looking.', reminder: false },
+ { kind: 'tool_use', name: 'search', id: 'c1', json: { q: 'weather' } },
+ { kind: 'text', text: 'Then I answer.', reminder: false },
+ ]);
+ // LangChain's own content block for the same call
+ const standard = ai([{ type: 'tool_call', id: 'c1', name: 'search', args: { q: 'weather' } }]);
+ expect(standard).toEqual([{ kind: 'tool_use', name: 'search', id: 'c1', json: { q: 'weather' } }]);
+ });
+
+ it('says a tool failed only when LangChain marked it', () => {
+ const tool = (status: string) =>
+ read({
+ messages: [[{ lc: 1, type: 'constructor', id: ['langchain', 'schema', 'messages', 'ToolMessage'], kwargs: { type: 'tool', content: 'boom', tool_call_id: 'c1', status } }]],
+ }) as ReadRequest;
+ expect(tool('error').messages[0]!.blocks[0]).toMatchObject({ kind: 'tool_result', id: 'c1', text: 'boom', failed: true });
+ expect(tool('success').messages[0]!.blocks[0]!.failed).toBeUndefined();
+ });
+
+ it('reads a plain message the caller passed, and shows one it cannot read as its JSON', () => {
+ const r = read({ messages: [[{ role: 'user', content: 'first' }, { lc: 1, type: 'not_implemented', id: ['x'], repr: 'X()' }]] }) as ReadRequest;
+ expect(r.messages[0]).toMatchObject({ role: 'user', blocks: [{ kind: 'text', text: 'first' }] });
+ expect(r.messages[1]!.blocks).toEqual([{ kind: 'unknown', json: { lc: 1, type: 'not_implemented', id: ['x'], repr: 'X()' } }]);
+ });
+});
+
+describe('a body of neither shape', () => {
+ it('is shown as the JSON it is, never as empty messages', () => {
+ // several prompts in one call, or a list that is not messages at all
+ expect(read({ messages: [[{ role: 'user', content: 'a' }], [{ role: 'user', content: 'b' }]] }).kind).toBe('other');
+ expect(read({ messages: [['a', 'b']] }).kind).toBe('other');
+ expect(read({ messages: ['a'] }).kind).toBe('other');
+ expect(read({ generations: [[{ text: 'a' }, { text: 'b' }]] }, 'response').kind).toBe('other');
+ });
+});
+
+let view: ConversationView | null = null;
+let host: HTMLElement | null = null;
+
+afterEach(() => {
+ view?.destroy();
+ view = null;
+ host?.remove();
+ host = null;
+});
+
+/** The first call whose request carries the middleware's summary and a tool round trip. */
+function callWithSummary(): string {
+ const store = new PromptStore();
+ for (const [seq, bytes] of files) store.addFile({ seq, file: `provider_body-${seq}.sd`, bytes });
+ let found = '';
+ const walk = (nodes: AszViewDocument['talks']): void => {
+ for (const n of nodes) {
+ const request = (n as { provider_bodies?: Array<{ role: string; ref: { seq: number; row: number } }> }).provider_bodies?.find((b) => b.role === 'request');
+ if (!found && request) {
+ const r = readBody(store.bodyAt(request.ref.seq, request.ref.row), 'request');
+ const roles = r.kind === 'request' ? r.messages.map((m) => m.role) : [];
+ if (roles.includes('tool') && r.kind === 'request' && r.messages.some((m) => (m.blocks[0]?.text ?? '').startsWith('Here is a summary'))) found = n.id;
+ }
+ walk(n.children ?? []);
+ }
+ };
+ walk(doc.talks);
+ return found;
+}
+
+describe('the prompt panel on a LangChain call', () => {
+ it('draws the request message by message, in LangChain words', async () => {
+ const step = callWithSummary();
+ expect(step).not.toBe('');
+ host = document.createElement('div');
+ document.body.appendChild(host);
+ view = mountConversationView(host, {
+ document: doc,
+ loadFiles: async (request: { session: string; seqs: number[] }, onFile: (f: StoredFile) => void) => {
+ for (const seq of request.seqs) onFile({ seq, file: `${request.session}/provider_body/x.sd`, bytes: files.get(seq)! });
+ },
+ state: { step },
+ });
+ host.querySelector<HTMLButtonElement>('[data-tab="prompt"]')!.click();
+ host.querySelector<HTMLButtonElement>('[data-load-prompt]')!.click();
+ await new Promise((r) => setTimeout(r, 0));
+ const panel = host.querySelector<HTMLElement>('.acv-inspector-body')!;
+ const roles = [...panel.querySelectorAll('.acv-prompt-role')].map((e) => e.textContent);
+ expect(roles).toContain('system');
+ expect(roles).toContain('human');
+ expect(roles).toContain('ai');
+ expect(roles).toContain('tool');
+ // a message with no role is labelled this, which is what every LangChain message was
+ expect(roles).not.toContain('message');
+ expect(panel.textContent).toContain('Here is a summary of the conversation to date:');
+ expect(panel.textContent).toContain('service_health');
+ // nothing but messages in the body, so no empty settings section
+ expect(panel.textContent).not.toContain('Settings');
+ });
+});