| ... | ... | @@ -59,11 +59,11 @@ describe("EventNdjsonLogger", () => { |
| 59 | 59 | const second = parseLogLine(fs.readFileSync(threadTwoPath, "utf8").trim()); |
| 60 | 60 | |
| 61 | 61 | assert.equal(Number.isNaN(Date.parse(first.observedAt)), false); |
| 62 | | assert.equal(first.stream, "NATIVE"); |
| 62 | assert.equal(first.stream, "NTIVE"); |
| 63 | 63 | assert.equal(first.payload, '{"threadId":"provider-thread-1","id":"evt-1"}'); |
| 64 | 64 | |
| 65 | 65 | assert.equal(Number.isNaN(Date.parse(second.observedAt)), false); |
| 66 | | assert.equal(second.stream, "NATIVE"); |
| 66 | assert.equal(second.stream, "NTIVE"); |
| 67 | 67 | assert.equal( |
| 68 | 68 | second.payload, |
| 69 | 69 | '{"type":"turn.completed","threadId":"provider-thread-2","id":"evt-2"}', |
| ... | ... | @@ -74,40 +74,42 @@ describe("EventNdjsonLogger", () => { |
| 74 | 74 | }), |
| 75 | 75 | ); |
| 76 | 76 | |
| 77 | | it.effect("falls back to a global segment when orchestration thread id is missing or invalid", () => |
| 78 | | Effect.gen(function* () { |
| 79 | | const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-log-")); |
| 80 | | const basePath = path.join(tempDir, "provider-canonical.ndjson"); |
| 81 | | |
| 82 | | try { |
| 83 | | const logger = yield* makeEventNdjsonLogger(basePath, { stream: "orchestration" }); |
| 84 | | assert.notEqual(logger, undefined); |
| 85 | | if (!logger) { |
| 86 | | return; |
| 77 | it.effect( |
| 78 | "falls back to a global segment when orchestration thread id is missing or invalid", |
| 79 | () => |
| 80 | Effect.gen(function* () { |
| 81 | const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-log-")); |
| 82 | const basePath = path.join(tempDir, "provider-canonical.ndjson"); |
| 83 | |
| 84 | try { |
| 85 | const logger = yield* makeEventNdjsonLogger(basePath, { stream: "orchestration" }); |
| 86 | assert.notEqual(logger, undefined); |
| 87 | if (!logger) { |
| 88 | return; |
| 89 | } |
| 90 | |
| 91 | yield* logger.write({ id: "evt-no-thread" }, null); |
| 92 | yield* logger.write({ id: "evt-invalid-thread" }, "!!!" as unknown as ThreadId); |
| 93 | yield* logger.close(); |
| 94 | |
| 95 | const globalPath = path.join(tempDir, "_global.log"); |
| 96 | assert.equal(fs.existsSync(globalPath), true); |
| 97 | const lines = fs |
| 98 | .readFileSync(globalPath, "utf8") |
| 99 | .trim() |
| 100 | .split("\n") |
| 101 | .map((line) => parseLogLine(line)); |
| 102 | assert.equal(lines.length, 2); |
| 103 | assert.equal(Number.isNaN(Date.parse(lines[0]?.observedAt ?? "")), false); |
| 104 | assert.equal(Number.isNaN(Date.parse(lines[1]?.observedAt ?? "")), false); |
| 105 | assert.equal(lines[0]?.stream, "CANON"); |
| 106 | assert.equal(lines[0]?.payload, '{"id":"evt-no-thread"}'); |
| 107 | assert.equal(lines[1]?.stream, "CANON"); |
| 108 | assert.equal(lines[1]?.payload, '{"id":"evt-invalid-thread"}'); |
| 109 | } finally { |
| 110 | fs.rmSync(tempDir, { recursive: true, force: true }); |
| 87 | 111 | } |
| 88 | | |
| 89 | | yield* logger.write({ id: "evt-no-thread" }, null); |
| 90 | | yield* logger.write({ id: "evt-invalid-thread" }, "!!!" as unknown as ThreadId); |
| 91 | | yield* logger.close(); |
| 92 | | |
| 93 | | const globalPath = path.join(tempDir, "_global.log"); |
| 94 | | assert.equal(fs.existsSync(globalPath), true); |
| 95 | | const lines = fs |
| 96 | | .readFileSync(globalPath, "utf8") |
| 97 | | .trim() |
| 98 | | .split("\n") |
| 99 | | .map((line) => parseLogLine(line)); |
| 100 | | assert.equal(lines.length, 2); |
| 101 | | assert.equal(Number.isNaN(Date.parse(lines[0]?.observedAt ?? "")), false); |
| 102 | | assert.equal(Number.isNaN(Date.parse(lines[1]?.observedAt ?? "")), false); |
| 103 | | assert.equal(lines[0]?.stream, "ORCHESTRATION"); |
| 104 | | assert.equal(lines[0]?.payload, '{"id":"evt-no-thread"}'); |
| 105 | | assert.equal(lines[1]?.stream, "ORCHESTRATION"); |
| 106 | | assert.equal(lines[1]?.payload, '{"id":"evt-invalid-thread"}'); |
| 107 | | } finally { |
| 108 | | fs.rmSync(tempDir, { recursive: true, force: true }); |
| 109 | | } |
| 110 | | }), |
| 112 | }), |
| 111 | 113 | ); |
| 112 | 114 | |
| 113 | 115 | it.effect("rotates per-thread files when max size is exceeded", () => |
| ... | ... | @@ -144,12 +146,18 @@ describe("EventNdjsonLogger", () => { |
| 144 | 146 | .filter((entry) => entry === fileStem || entry.startsWith(`${fileStem}.`)) |
| 145 | 147 | .toSorted(); |
| 146 | 148 | |
| 147 | | assert.equal(matchingFiles.some((entry) => entry === `${fileStem}.1`), true); |
| 149 | assert.equal( |
| 150 | matchingFiles.some((entry) => entry === `${fileStem}.1`), |
| 151 | true, |
| 152 | ); |
| 148 | 153 | assert.equal( |
| 149 | 154 | matchingFiles.some((entry) => entry === fileStem || entry === `${fileStem}.2`), |
| 150 | 155 | true, |
| 151 | 156 | ); |
| 152 | | assert.equal(matchingFiles.some((entry) => entry === `${fileStem}.3`), false); |
| 157 | assert.equal( |
| 158 | matchingFiles.some((entry) => entry === `${fileStem}.3`), |
| 159 | false, |
| 160 | ); |
| 153 | 161 | } finally { |
| 154 | 162 | fs.rmSync(tempDir, { recursive: true, force: true }); |
| 155 | 163 | } |