Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,9 @@ function runtimeEventToActivities(
createdAt: event.createdAt,
tone: "info",
kind: "runtime.warning",
summary: "Runtime warning",
// Use the adapter-supplied message as the row label so the work log
// shows what the warning was about, not a generic "Runtime warning".
summary: truncateDetail(event.payload.message, 120),
payload: {
message: truncateDetail(event.payload.message),
...(event.payload.detail !== undefined ? { detail: event.payload.detail } : {}),
Expand Down
50 changes: 48 additions & 2 deletions apps/server/src/provider/Layers/ClaudeAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,52 @@ function sdkNativeMethod(message: SDKMessage): string {
return `claude/${message.type}`;
}

// Discriminator/identity keys carry no human-readable content; everything else
// on an unmodeled SDK message is potentially worth surfacing in the work log.
const SDK_MESSAGE_NOISE_KEYS = new Set([
"type",
"subtype",
"uuid",
"parent_uuid",
"session_id",
"parent_tool_use_id",
"request_id",
]);

// Pull the salient scalar content out of a message the adapter doesn't model
// yet, so the work-log row shows what actually arrived (e.g. a notification's
// text) instead of an opaque "unhandled subtype" placeholder. Nested structures
// are left to the full payload retained in the event's `detail`.
function previewUnknownSdkContent(message: unknown): string | undefined {
if (!message || typeof message !== "object") {
return undefined;
}
const parts: string[] = [];
for (const [key, value] of Object.entries(message as Record<string, unknown>)) {
if (SDK_MESSAGE_NOISE_KEYS.has(key)) {
continue;
}
if (typeof value === "string") {
const trimmed = value.trim();
if (trimmed.length > 0) {
parts.push(`${key}: ${trimmed}`);
}
} else if (typeof value === "number" || typeof value === "boolean") {
parts.push(`${key}: ${String(value)}`);
}
}
if (parts.length === 0) {
return undefined;
}
const joined = parts.join(" · ");
return joined.length > 280 ? `${joined.slice(0, 279)}…` : joined;
}

function describeUnknownSdkMessage(kind: string, message: unknown): string {
const preview = previewUnknownSdkContent(message);
return preview ? `${kind} — ${preview}` : `${kind} (no displayable text content)`;
}

function sdkNativeItemId(message: SDKMessage): string | undefined {
if (message.type === "assistant") {
const maybeId = (message.message as { id?: unknown }).id;
Expand Down Expand Up @@ -2270,7 +2316,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
default:
yield* emitRuntimeWarning(
context,
`Unhandled Claude system message subtype '${message.subtype}'.`,
describeUnknownSdkMessage(`Claude system message '${message.subtype}'`, message),
message,
);
return;
Expand Down Expand Up @@ -2384,7 +2430,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
default:
yield* emitRuntimeWarning(
context,
`Unhandled Claude SDK message type '${message.type}'.`,
describeUnknownSdkMessage(`Claude SDK message '${message.type}'`, message),
message,
);
return;
Expand Down
Loading