Skip to content

Commit ff581d6

Browse files
Normalize tool lifecycle payloads
- Canonicalize provider runtime tool data and usage snapshots - Update work log extraction and user input contracts for the new schema - Add coverage for the revised lifecycle and ingestion shapes
1 parent 3f48ad2 commit ff581d6

File tree

16 files changed

+543
-240
lines changed

16 files changed

+543
-240
lines changed

apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,9 @@ describe("ProviderRuntimeIngestion", () => {
18091809
status: "in_progress",
18101810
title: "Run tests",
18111811
detail: "bun test",
1812-
data: { pid: 123 },
1812+
data: {
1813+
kind: "generic",
1814+
},
18131815
},
18141816
});
18151817

apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
ApprovalRequestId,
33
type AssistantDeliveryMode,
4+
type CanonicalJsonValue,
45
CommandId,
56
MessageId,
67
type OrchestrationEvent,
@@ -102,6 +103,16 @@ function asString(value: unknown): string | undefined {
102103
return typeof value === "string" ? value : undefined;
103104
}
104105

106+
function toCanonicalJsonValue(value: unknown): CanonicalJsonValue | undefined {
107+
if (value === undefined) {
108+
return undefined;
109+
}
110+
const normalized = JSON.parse(
111+
JSON.stringify(value, (_key, nestedValue) => (nestedValue === undefined ? null : nestedValue)),
112+
) as CanonicalJsonValue | null;
113+
return normalized ?? undefined;
114+
}
115+
105116
function buildContextWindowActivityPayload(
106117
event: ProviderRuntimeEvent,
107118
): ThreadTokenUsageSnapshot | undefined {
@@ -283,7 +294,9 @@ function runtimeEventToActivities(
283294
summary: "Runtime warning",
284295
payload: {
285296
message: truncateDetail(event.payload.message),
286-
...(event.payload.detail !== undefined ? { detail: event.payload.detail } : {}),
297+
...(event.payload.detail !== undefined
298+
? { detail: toCanonicalJsonValue(event.payload.detail) }
299+
: {}),
287300
},
288301
turnId: toTurnId(event.turnId) ?? null,
289302
...maybeSequence,
@@ -433,7 +446,9 @@ function runtimeEventToActivities(
433446
summary: "Context compacted",
434447
payload: {
435448
state: event.payload.state,
436-
...(event.payload.detail !== undefined ? { detail: event.payload.detail } : {}),
449+
...(event.payload.detail !== undefined
450+
? { detail: toCanonicalJsonValue(event.payload.detail) }
451+
: {}),
437452
},
438453
turnId: toTurnId(event.turnId) ?? null,
439454
...maybeSequence,

apps/server/src/provider/Layers/ClaudeAdapter.test.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -914,12 +914,13 @@ describe("ClaudeAdapterLive", () => {
914914
const toolInputUpdated = runtimeEvents.find(
915915
(event) =>
916916
event.type === "item.updated" &&
917-
(event.payload.data as { input?: { pattern?: string; path?: string } } | undefined)?.input
918-
?.pattern === "foo",
917+
event.payload.data?.kind === "generic" &&
918+
event.payload.data.input?.pattern === "foo",
919919
);
920920
assert.equal(toolInputUpdated?.type, "item.updated");
921921
if (toolInputUpdated?.type === "item.updated") {
922922
assert.deepEqual(toolInputUpdated.payload.data, {
923+
kind: "generic",
923924
toolName: "Grep",
924925
input: {
925926
pattern: "foo",
@@ -931,17 +932,25 @@ describe("ClaudeAdapterLive", () => {
931932
const toolResultUpdated = runtimeEvents.find(
932933
(event) =>
933934
event.type === "item.updated" &&
934-
(event.payload.data as { result?: { tool_use_id?: string } } | undefined)?.result
935-
?.tool_use_id === "tool-grep-1",
935+
event.payload.data?.kind === "generic" &&
936+
event.payload.data.result !== undefined &&
937+
event.payload.data.result !== null &&
938+
typeof event.payload.data.result === "object" &&
939+
!Array.isArray(event.payload.data.result) &&
940+
"tool_use_id" in event.payload.data.result &&
941+
event.payload.data.result.tool_use_id === "tool-grep-1",
936942
);
937943
assert.equal(toolResultUpdated?.type, "item.updated");
938944
if (toolResultUpdated?.type === "item.updated") {
939945
assert.equal(
940-
(
941-
toolResultUpdated.payload.data as {
942-
result?: { content?: string };
943-
}
944-
).result?.content,
946+
toolResultUpdated.payload.data?.kind === "generic" &&
947+
toolResultUpdated.payload.data.result !== undefined &&
948+
toolResultUpdated.payload.data.result !== null &&
949+
typeof toolResultUpdated.payload.data.result === "object" &&
950+
!Array.isArray(toolResultUpdated.payload.data.result) &&
951+
"content" in toolResultUpdated.payload.data.result
952+
? toolResultUpdated.payload.data.result.content
953+
: undefined,
945954
"src/example.ts:1:foo",
946955
);
947956
}

0 commit comments

Comments
 (0)