| ... | ... | @@ -341,6 +341,19 @@ describe("EventNdjsonLogger", () => { |
| 341 | 341 | }, |
| 342 | 342 | threadId, |
| 343 | 343 | ); |
| 344 | yield* native.write( |
| 345 | { |
| 346 | event: { |
| 347 | type: "message.part.updated", |
| 348 | payload: { |
| 349 | properties: { |
| 350 | part: { type: "tool", state: { status: "running", output: "progress" } }, |
| 351 | }, |
| 352 | }, |
| 353 | }, |
| 354 | }, |
| 355 | threadId, |
| 356 | ); |
| 344 | 357 | yield* native.write({ type: "turn.completed", id: "native-final" }, threadId); |
| 345 | 358 | yield* store.close(); |
| 346 | 359 | |
| ... | ... | @@ -362,6 +375,51 @@ describe("EventNdjsonLogger", () => { |
| 362 | 375 | }), |
| 363 | 376 | ); |
| 364 | 377 | |
| 378 | it.effect("keeps OpenCode tool input, final output, and errors in native logs", () => |
| 379 | Effect.gen(function* () { |
| 380 | const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-log-")); |
| 381 | const basePath = NodePath.join(tempDir, "events.log"); |
| 382 | const threadId = ThreadId.make("thread-tool-lifecycle"); |
| 383 | |
| 384 | try { |
| 385 | const store = yield* makeEventNdjsonLogStore(basePath, { batchWindowMs: 0 }); |
| 386 | const native = store.logger("native"); |
| 387 | const input = { command: "run-build" }; |
| 388 | const states = [ |
| 389 | { status: "pending", input }, |
| 390 | { status: "completed", input, output: "Build complete", time: { start: 1, end: 2 } }, |
| 391 | { status: "error", input, error: "Build failed", time: { start: 3, end: 4 } }, |
| 392 | { status: "unknown", input }, |
| 393 | null, |
| 394 | ]; |
| 395 | const events = states.map((state) => ({ |
| 396 | event: { |
| 397 | type: "message.part.updated", |
| 398 | payload: { properties: { part: { type: "tool", state } } }, |
| 399 | }, |
| 400 | })); |
| 401 | for (const event of events) { |
| 402 | yield* native.write(event, threadId); |
| 403 | } |
| 404 | yield* store.close(); |
| 405 | |
| 406 | const payloads = NodeFS.readFileSync( |
| 407 | ownedLogPath(basePath, "thread-tool-lifecycle"), |
| 408 | "utf8", |
| 409 | ) |
| 410 | .trim() |
| 411 | .split("\n") |
| 412 | .map((line) => parseLogLine(line).payload); |
| 413 | assert.deepEqual( |
| 414 | payloads, |
| 415 | events.map((event) => encodeUnknownJson(event)), |
| 416 | ); |
| 417 | } finally { |
| 418 | NodeFS.rmSync(tempDir, { recursive: true, force: true }); |
| 419 | } |
| 420 | }), |
| 421 | ); |
| 422 | |
| 365 | 423 | it.effect("contains hostile event accessors inside guarded serialization", () => |
| 366 | 424 | Effect.gen(function* () { |
| 367 | 425 | const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-log-")); |