| ... | ... | @@ -972,6 +972,52 @@ function sdkNativeMethod(message: SDKMessage): string { |
| 972 | 972 | return `claude/${message.type}`; |
| 973 | 973 | } |
| 974 | 974 | |
| 975 | // Discriminator/identity keys carry no human-readable content; everything else |
| 976 | // on an unmodeled SDK message is potentially worth surfacing in the work log. |
| 977 | const SDK_MESSAGE_NOISE_KEYS = new Set([ |
| 978 | "type", |
| 979 | "subtype", |
| 980 | "uuid", |
| 981 | "parent_uuid", |
| 982 | "session_id", |
| 983 | "parent_tool_use_id", |
| 984 | "request_id", |
| 985 | ]); |
| 986 | |
| 987 | // Pull the salient scalar content out of a message the adapter doesn't model |
| 988 | // yet, so the work-log row shows what actually arrived (e.g. a notification's |
| 989 | // text) instead of an opaque "unhandled subtype" placeholder. Nested structures |
| 990 | // are left to the full payload retained in the event's `detail`. |
| 991 | function previewUnknownSdkContent(message: unknown): string | undefined { |
| 992 | if (!message || typeof message !== "object") { |
| 993 | return undefined; |
| 994 | } |
| 995 | const parts: string[] = []; |
| 996 | for (const [key, value] of Object.entries(message as Record<string, unknown>)) { |
| 997 | if (SDK_MESSAGE_NOISE_KEYS.has(key)) { |
| 998 | continue; |
| 999 | } |
| 1000 | if (typeof value === "string") { |
| 1001 | const trimmed = value.trim(); |
| 1002 | if (trimmed.length > 0) { |
| 1003 | parts.push(`${key}: ${trimmed}`); |
| 1004 | } |
| 1005 | } else if (typeof value === "number" || typeof value === "boolean") { |
| 1006 | parts.push(`${key}: ${String(value)}`); |
| 1007 | } |
| 1008 | } |
| 1009 | if (parts.length === 0) { |
| 1010 | return undefined; |
| 1011 | } |
| 1012 | const joined = parts.join(" · "); |
| 1013 | return joined.length > 280 ? `${joined.slice(0, 279)}…` : joined; |
| 1014 | } |
| 1015 | |
| 1016 | function describeUnknownSdkMessage(kind: string, message: unknown): string { |
| 1017 | const preview = previewUnknownSdkContent(message); |
| 1018 | return preview ? `${kind} — ${preview}` : `${kind} (no displayable text content)`; |
| 1019 | } |
| 1020 | |
| 975 | 1021 | function sdkNativeItemId(message: SDKMessage): string | undefined { |
| 976 | 1022 | if (message.type === "assistant") { |
| 977 | 1023 | const maybeId = (message.message as { id?: unknown }).id; |
| ... | ... | @@ -2291,7 +2337,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2291 | 2337 | default: |
| 2292 | 2338 | yield* emitRuntimeWarning( |
| 2293 | 2339 | context, |
| 2294 | | `Unhandled Claude system message subtype '${message.subtype}'.`, |
| 2340 | describeUnknownSdkMessage(`Claude system message '${message.subtype}'`, message), |
| 2295 | 2341 | message, |
| 2296 | 2342 | ); |
| 2297 | 2343 | return; |
| ... | ... | @@ -2405,7 +2451,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2405 | 2451 | default: |
| 2406 | 2452 | yield* emitRuntimeWarning( |
| 2407 | 2453 | context, |
| 2408 | | `Unhandled Claude SDK message type '${message.type}'.`, |
| 2454 | describeUnknownSdkMessage(`Claude SDK message '${message.type}'`, message), |
| 2409 | 2455 | message, |
| 2410 | 2456 | ); |
| 2411 | 2457 | return; |