chore: prepare temporary Frank production validation
This commit is contained in:
parent
3644cb9845
commit
fcffd90b9d
2 changed files with 93 additions and 15 deletions
|
|
@ -581,7 +581,26 @@ export type SessionsContextOutput = {
|
|||
readonly reasoning: number
|
||||
readonly cache: { readonly read: number; readonly write: number }
|
||||
}
|
||||
readonly error?: { readonly type: "unknown"; readonly message: string }
|
||||
readonly error?:
|
||||
| { readonly type: "unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "provider"
|
||||
readonly category:
|
||||
| "invalid-request"
|
||||
| "no-route"
|
||||
| "authentication"
|
||||
| "rate-limit"
|
||||
| "quota-exceeded"
|
||||
| "content-policy"
|
||||
| "provider-internal"
|
||||
| "transport"
|
||||
| "invalid-provider-output"
|
||||
| "unknown"
|
||||
readonly message: string
|
||||
readonly status?: number | null
|
||||
readonly retryable: boolean
|
||||
readonly retryAfterMs?: number | null
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly type: "compaction"
|
||||
|
|
@ -802,7 +821,26 @@ export type SessionsEventsOutput =
|
|||
readonly timestamp: number
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly error: { readonly type: "unknown"; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "provider"
|
||||
readonly category:
|
||||
| "invalid-request"
|
||||
| "no-route"
|
||||
| "authentication"
|
||||
| "rate-limit"
|
||||
| "quota-exceeded"
|
||||
| "content-policy"
|
||||
| "provider-internal"
|
||||
| "transport"
|
||||
| "invalid-provider-output"
|
||||
| "unknown"
|
||||
readonly message: string
|
||||
readonly status?: number | undefined
|
||||
readonly retryable: boolean
|
||||
readonly retryAfterMs?: number | undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
| {
|
||||
|
|
@ -1261,7 +1299,26 @@ export type SessionsMessageOutput = {
|
|||
readonly reasoning: number
|
||||
readonly cache: { readonly read: number; readonly write: number }
|
||||
}
|
||||
readonly error?: { readonly type: "unknown"; readonly message: string }
|
||||
readonly error?:
|
||||
| { readonly type: "unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "provider"
|
||||
readonly category:
|
||||
| "invalid-request"
|
||||
| "no-route"
|
||||
| "authentication"
|
||||
| "rate-limit"
|
||||
| "quota-exceeded"
|
||||
| "content-policy"
|
||||
| "provider-internal"
|
||||
| "transport"
|
||||
| "invalid-provider-output"
|
||||
| "unknown"
|
||||
readonly message: string
|
||||
readonly status?: number | null
|
||||
readonly retryable: boolean
|
||||
readonly retryAfterMs?: number | null
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly type: "compaction"
|
||||
|
|
|
|||
|
|
@ -103,11 +103,12 @@ test("embedded client uses the real router and handlers", async () => {
|
|||
}
|
||||
})
|
||||
|
||||
test("embedded session events live-tail location-owned durable rows through provider failure", async () => {
|
||||
test("embedded session events live-tail stateless tool continuation through provider failure", async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-live-tail-"))
|
||||
const database = Flag.OPENCODE_DB
|
||||
Flag.OPENCODE_DB = join(directory, "opencode.sqlite")
|
||||
let requests = 0
|
||||
const requestBodies: unknown[] = []
|
||||
const server = Bun.serve({
|
||||
port: 0,
|
||||
async fetch(request) {
|
||||
|
|
@ -115,26 +116,29 @@ test("embedded session events live-tail location-owned durable rows through prov
|
|||
if (JSON.stringify(body).includes("Generate a title for this conversation")) {
|
||||
return new Response(
|
||||
[
|
||||
'data: {"choices":[{"delta":{"role":"assistant"}}]}',
|
||||
'data: {"choices":[{"delta":{"content":"Live tail"}}]}',
|
||||
'data: {"choices":[{"delta":{},"finish_reason":"stop"}]}',
|
||||
"data: [DONE]",
|
||||
'data: {"type":"response.output_text.delta","item_id":"title","delta":"Live tail"}',
|
||||
'data: {"type":"response.completed","response":{}}',
|
||||
"",
|
||||
].join("\n\n"),
|
||||
{ headers: { "content-type": "text/event-stream" } },
|
||||
)
|
||||
}
|
||||
requests++
|
||||
requestBodies.push(body)
|
||||
if (requests > 1) {
|
||||
return Response.json({ error: { message: "Provider failed on turn B", type: "server_error" } }, { status: 500 })
|
||||
}
|
||||
return new Response(
|
||||
[
|
||||
'data: {"choices":[{"delta":{"role":"assistant"}}]}',
|
||||
'data: {"choices":[{"delta":{"tool_calls":[{"index":0,"id":"call_live_tail","type":"function","function":{"name":"live_tail_tool","arguments":""}}]}}]}',
|
||||
'data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\\"value\\":\\"A\\"}"}}]}}]}',
|
||||
'data: {"choices":[{"delta":{},"finish_reason":"tool_calls"}]}',
|
||||
"data: [DONE]",
|
||||
'data: {"type":"response.output_item.added","item":{"type":"reasoning","id":"rs_live_tail","encrypted_content":null}}',
|
||||
'data: {"type":"response.reasoning_summary_part.added","item_id":"rs_live_tail","summary_index":0}',
|
||||
'data: {"type":"response.reasoning_summary_text.delta","item_id":"rs_live_tail","summary_index":0,"delta":"Run the tool."}',
|
||||
'data: {"type":"response.reasoning_summary_part.done","item_id":"rs_live_tail","summary_index":0}',
|
||||
'data: {"type":"response.output_item.done","item":{"type":"reasoning","id":"rs_live_tail","encrypted_content":"encrypted-live-tail"}}',
|
||||
'data: {"type":"response.output_item.added","item":{"type":"function_call","id":"item_live_tail","call_id":"call_live_tail","name":"live_tail_tool","arguments":""}}',
|
||||
'data: {"type":"response.function_call_arguments.delta","item_id":"item_live_tail","delta":"{\\"value\\":\\"A\\"}"}',
|
||||
'data: {"type":"response.output_item.done","item":{"type":"function_call","id":"item_live_tail","call_id":"call_live_tail","name":"live_tail_tool","arguments":"{\\"value\\":\\"A\\"}"}}',
|
||||
'data: {"type":"response.completed","response":{}}',
|
||||
"",
|
||||
].join("\n\n"),
|
||||
{ headers: { "content-type": "text/event-stream" } },
|
||||
|
|
@ -155,11 +159,13 @@ test("embedded session events live-tail location-owned durable rows through prov
|
|||
name: "Test",
|
||||
api: {
|
||||
type: "aisdk",
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
package: "@ai-sdk/openai",
|
||||
url: `http://127.0.0.1:${server.port}/v1`,
|
||||
settings: {},
|
||||
},
|
||||
request: { body: { apiKey: "test-key" } },
|
||||
request: {
|
||||
body: { apiKey: "test-key", store: false, include: ["reasoning.encrypted_content"] },
|
||||
},
|
||||
models: {
|
||||
"test-model": {
|
||||
name: "Test Model",
|
||||
|
|
@ -219,6 +225,21 @@ test("embedded session events live-tail location-owned durable rows through prov
|
|||
|
||||
expect(executions).toEqual(["A"])
|
||||
expect(requests).toBeGreaterThanOrEqual(2)
|
||||
expect(requestBodies.slice(0, 2)).toMatchObject([
|
||||
{ store: false },
|
||||
{
|
||||
store: false,
|
||||
input: expect.arrayContaining([
|
||||
{
|
||||
type: "reasoning",
|
||||
id: "rs_live_tail",
|
||||
summary: [{ type: "summary_text", text: "Run the tool." }],
|
||||
encrypted_content: "encrypted-live-tail",
|
||||
},
|
||||
{ type: "function_call_output", call_id: "call_live_tail", output: '{"value":"A"}' },
|
||||
]),
|
||||
},
|
||||
])
|
||||
expect(durable.at(-1)?.type).toBe("session.next.step.failed")
|
||||
expect(durable.map((event) => event.durable!.seq)).toEqual(
|
||||
Array.from({ length: durable.length }, (_, index) => durable[0]!.durable!.seq + index),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue