Skip to content

Commit 316d23e

Browse files
authored
feat(inbox): Show signals report data in the detail pane (#1552)
1 parent c9a5649 commit 316d23e

File tree

6 files changed

+676
-203
lines changed

6 files changed

+676
-203
lines changed

apps/code/src/renderer/api/posthogClient.ts

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import type {
2+
ActionabilityJudgmentArtefact,
23
AvailableSuggestedReviewer,
34
AvailableSuggestedReviewersResponse,
5+
PriorityJudgmentArtefact,
46
SandboxEnvironment,
57
SandboxEnvironmentInput,
8+
SignalFindingArtefact,
69
SignalProcessingStateResponse,
710
SignalReport,
811
SignalReportArtefact,
@@ -76,19 +79,138 @@ function optionalString(value: unknown): string | null {
7679
return typeof value === "string" ? value : null;
7780
}
7881

79-
type AnyArtefact = SignalReportArtefact | SuggestedReviewersArtefact;
82+
type AnyArtefact =
83+
| SignalReportArtefact
84+
| PriorityJudgmentArtefact
85+
| ActionabilityJudgmentArtefact
86+
| SignalFindingArtefact
87+
| SuggestedReviewersArtefact;
88+
89+
const PRIORITY_VALUES = new Set(["P0", "P1", "P2", "P3", "P4"]);
90+
91+
function normalizePriorityJudgmentArtefact(
92+
value: Record<string, unknown>,
93+
): PriorityJudgmentArtefact | null {
94+
const id = optionalString(value.id);
95+
if (!id) return null;
96+
97+
const contentValue = isObjectRecord(value.content) ? value.content : null;
98+
if (!contentValue) return null;
99+
100+
const priority = optionalString(contentValue.priority);
101+
if (!priority || !PRIORITY_VALUES.has(priority)) return null;
102+
103+
return {
104+
id,
105+
type: "priority_judgment",
106+
created_at: optionalString(value.created_at) ?? new Date(0).toISOString(),
107+
content: {
108+
explanation: optionalString(contentValue.explanation) ?? "",
109+
priority: priority as PriorityJudgmentArtefact["content"]["priority"],
110+
},
111+
};
112+
}
113+
114+
const ACTIONABILITY_VALUES = new Set([
115+
"immediately_actionable",
116+
"requires_human_input",
117+
"not_actionable",
118+
]);
119+
120+
function normalizeActionabilityJudgmentArtefact(
121+
value: Record<string, unknown>,
122+
): ActionabilityJudgmentArtefact | null {
123+
const id = optionalString(value.id);
124+
if (!id) return null;
125+
126+
const contentValue = isObjectRecord(value.content) ? value.content : null;
127+
if (!contentValue) return null;
128+
129+
// Support both agentic ("actionability") and legacy ("choice") field names
130+
const actionability =
131+
optionalString(contentValue.actionability) ??
132+
optionalString(contentValue.choice);
133+
if (!actionability || !ACTIONABILITY_VALUES.has(actionability)) return null;
134+
135+
return {
136+
id,
137+
type: "actionability_judgment",
138+
created_at: optionalString(value.created_at) ?? new Date(0).toISOString(),
139+
content: {
140+
explanation: optionalString(contentValue.explanation) ?? "",
141+
actionability:
142+
actionability as ActionabilityJudgmentArtefact["content"]["actionability"],
143+
already_addressed:
144+
typeof contentValue.already_addressed === "boolean"
145+
? contentValue.already_addressed
146+
: false,
147+
},
148+
};
149+
}
150+
151+
function normalizeSignalFindingArtefact(
152+
value: Record<string, unknown>,
153+
): SignalFindingArtefact | null {
154+
const id = optionalString(value.id);
155+
if (!id) return null;
156+
157+
const contentValue = isObjectRecord(value.content) ? value.content : null;
158+
if (!contentValue) return null;
159+
160+
const signalId = optionalString(contentValue.signal_id);
161+
if (!signalId) return null;
162+
163+
return {
164+
id,
165+
type: "signal_finding",
166+
created_at: optionalString(value.created_at) ?? new Date(0).toISOString(),
167+
content: {
168+
signal_id: signalId,
169+
relevant_code_paths: Array.isArray(contentValue.relevant_code_paths)
170+
? contentValue.relevant_code_paths.filter(
171+
(p: unknown): p is string => typeof p === "string",
172+
)
173+
: [],
174+
relevant_commit_hashes: isObjectRecord(
175+
contentValue.relevant_commit_hashes,
176+
)
177+
? Object.fromEntries(
178+
Object.entries(contentValue.relevant_commit_hashes).filter(
179+
(e): e is [string, string] => typeof e[1] === "string",
180+
),
181+
)
182+
: {},
183+
data_queried: optionalString(contentValue.data_queried) ?? "",
184+
verified:
185+
typeof contentValue.verified === "boolean"
186+
? contentValue.verified
187+
: false,
188+
},
189+
};
190+
}
80191

81192
function normalizeSignalReportArtefact(value: unknown): AnyArtefact | null {
82193
if (!isObjectRecord(value)) {
83194
return null;
84195
}
85196

197+
const dispatchType = optionalString(value.type);
198+
if (dispatchType === "signal_finding") {
199+
return normalizeSignalFindingArtefact(value);
200+
}
201+
if (dispatchType === "actionability_judgment") {
202+
return normalizeActionabilityJudgmentArtefact(value);
203+
}
204+
if (dispatchType === "priority_judgment") {
205+
return normalizePriorityJudgmentArtefact(value);
206+
}
207+
86208
const id = optionalString(value.id);
87209
if (!id) {
88210
return null;
89211
}
90212

91-
const type = optionalString(value.type) ?? "unknown";
213+
const type = dispatchType ?? "unknown";
92214
const created_at =
93215
optionalString(value.created_at) ?? new Date(0).toISOString();
94216

0 commit comments

Comments
 (0)