mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: survive a malformed message rather than take the viewer down
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b4c0622f3f
commit
2f5354ea7b
@@ -144,3 +144,17 @@ describe('the max-iterations path', () => {
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
// A result is whatever a script returned, so every nested field is arbitrary even
|
||||
// once the messages have roles. A throw in here takes down the whole result
|
||||
// viewer, including the ordinary error such a payload usually rides on.
|
||||
describe('a malformed message that still has a role', () => {
|
||||
it.each([
|
||||
['tool_calls that are not a list', { role: 'assistant', tool_calls: {} }],
|
||||
['annotations that are not a list', { role: 'assistant', content: 'hi', annotations: 'abc' }],
|
||||
['a content object', { role: 'assistant', content: { text: 'hi' } }],
|
||||
['an agent_action that is not an object', { role: 'tool', agent_action: 'tool_call' }]
|
||||
])('survives %s', (_label, message) => {
|
||||
expect(() => buildAgentTrace([message as never])).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -46,7 +46,7 @@ function contentText(content: unknown): string {
|
||||
|
||||
function sourcesOf(message: AgentMessage): WebSearchSource[] | undefined {
|
||||
const annotations = message.annotations
|
||||
if (!annotations?.length) {
|
||||
if (!Array.isArray(annotations) || annotations.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
const sources = annotations
|
||||
@@ -61,7 +61,14 @@ export function buildAgentTrace(messages: AgentMessage[]): AgentTraceEntry[] {
|
||||
// the two are joined by `tool_call_id`.
|
||||
const argsByCallId = new Map<string, string>()
|
||||
for (const message of messages) {
|
||||
for (const call of message.tool_calls ?? []) {
|
||||
// A job result is whatever its script returned, and the shape check that got
|
||||
// us here only proves each message has a `role`. Anything nested is still
|
||||
// arbitrary, and a throw here would take the whole result viewer down with
|
||||
// it — including the plain error a lookalike payload is usually attached to.
|
||||
if (!Array.isArray(message.tool_calls)) {
|
||||
continue
|
||||
}
|
||||
for (const call of message.tool_calls) {
|
||||
if (call.id && typeof call.function?.arguments === 'string') {
|
||||
argsByCallId.set(call.id, call.function.arguments)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user