Skip to content

Commit f5f70c1

Browse files
author
bcode
committed
fix(bcode-laminar): address cubic review
- processor.ts: spawningSpanIdToToolUseId is keyed by UUID (otelSpanIdToUUID(spanId)) at insert time but onEnd was deleting by raw hex span id, so entries were never cleaned up. Use the UUID for delete to match. - plugin.ts: server.instance.disposed now ends any open turn spans, clears the subagent map, and shuts down the NodeSDK (which drains the BatchSpanProcessor and unregisters the global TracerProvider). - plugin.ts: LMNR_GRPC_PORT is validated (positive integer in 1..65535) before use, with fallback to the appropriate default (8443 for api.lmnr.ai, 443 elsewhere). Garbage values no longer produce NaN endpoint URLs.
1 parent 58cc2fd commit f5f70c1

2 files changed

Lines changed: 28 additions & 8 deletions

File tree

packages/bcode-laminar/src/plugin.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,22 @@ import { OpenCodeLaminarSpanProcessor } from "./processor"
1818
import { startTurnSpan } from "./span"
1919
import { sessionCurrentTurnSpan, subagentSessionIds } from "./state"
2020

21+
const DEFAULT_GRPC_PORT_LMNR = 8443
22+
const DEFAULT_GRPC_PORT_GENERIC = 443
23+
24+
const parsePort = (raw: string | undefined, fallback: number): number => {
25+
if (!raw) return fallback
26+
const n = Number(raw)
27+
return Number.isInteger(n) && n > 0 && n <= 65535 ? n : fallback
28+
}
29+
2130
export const LaminarPlugin: Plugin = ({ client }) => {
2231
const projectApiKey = process.env.LMNR_PROJECT_API_KEY
2332
const baseUrl = process.env.LMNR_BASE_URL ?? "https://api.lmnr.ai"
24-
const port = process.env.LMNR_GRPC_PORT
25-
? Number(process.env.LMNR_GRPC_PORT)
26-
: baseUrl === "https://api.lmnr.ai"
27-
? 8443
28-
: 443
33+
const port = parsePort(
34+
process.env.LMNR_GRPC_PORT,
35+
baseUrl === "https://api.lmnr.ai" ? DEFAULT_GRPC_PORT_LMNR : DEFAULT_GRPC_PORT_GENERIC,
36+
)
2937

3038
const log = (level: "debug" | "info" | "warn" | "error", message: string) => {
3139
client.app
@@ -64,9 +72,19 @@ export const LaminarPlugin: Plugin = ({ client }) => {
6472
await processor.forceFlush()
6573
break
6674
}
67-
case "server.instance.disposed":
68-
await processor.shutdown()
75+
case "server.instance.disposed": {
76+
// End any turn spans still open so they're flushed before shutdown.
77+
for (const [sessionId, span] of Object.entries(sessionCurrentTurnSpan)) {
78+
span.end()
79+
delete sessionCurrentTurnSpan[sessionId]
80+
}
81+
for (const key of Object.keys(subagentSessionIds)) delete subagentSessionIds[key]
82+
// sdk.shutdown() drains the inner BatchSpanProcessor and exporter
83+
// and removes the global TracerProvider; explicit processor.shutdown()
84+
// is redundant but harmless.
85+
await sdk.shutdown().catch(() => {})
6986
break
87+
}
7088
case "session.created":
7189
case "session.updated":
7290
if (event.properties.info.parentID) {

packages/bcode-laminar/src/processor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ export class OpenCodeLaminarSpanProcessor implements SpanProcessor {
165165
const spanId = span.spanContext().spanId
166166
this.spanIdLists.delete(spanId)
167167
this.spanIdToPath.delete(spanId)
168-
delete this.spawningSpanIdToToolUseId[spanId]
168+
// spawningSpanIdToToolUseId is keyed by UUID (matches `lmnr.span.ids_path`
169+
// entries that the descendant scan iterates), not by the raw hex span id.
170+
delete this.spawningSpanIdToToolUseId[otelSpanIdToUUID(spanId)]
169171
makeSpanOtelV2Compatible(span)
170172
this.inner.onEnd(span)
171173
}

0 commit comments

Comments
 (0)