Skip to content

Commit e64b101

Browse files
authored
feat(webapp): Add test payload AI generation to the test page based on payload schemas (#3188)
<img width="2191" height="1023" alt="CleanShot 2026-03-06 at 13 36 53" src="https://github.com/user-attachments/assets/4eba0d1a-1528-49a3-be5b-6bde89030193" /> <img width="411" height="1069" alt="CleanShot 2026-03-06 at 13 37 28" src="https://github.com/user-attachments/assets/e5f7bb9c-c894-41cc-9ca6-96b43fcf6005" /> Add a tabbed sidebar to the Test page for standard tasks, reusing the ClientTabs pattern from the Query page. - Options tab: existing sidebar content (machine, version, queue, etc.) - AI tab: AI-powered payload generation with streaming, supports JSON Schema, inferred schema from recent runs, and task source code lookup via tool calling for tasks without schemas - Schema tab: displays payload JSON Schema (from schemaTask), inferred schema (from recent runs via @jsonhero/schema-infer), or empty state with schemaTask docs and example code Data layer changes: - Surface payloadSchema and inferredPayloadSchema from TestTaskPresenter - Add payloadSchema and fileId to WorkerDeploymentWithWorkerTasks type - Decompress zlib-deflated source files for AI context
1 parent 6f6523f commit e64b101

File tree

10 files changed

+1236
-253
lines changed

10 files changed

+1236
-253
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: feature
4+
---
5+
6+
Add sidebar tabs (Options, AI, Schema) to the Test page for schemaTask payload generation and schema viewing.

apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type TaskRunTemplate,
77
PrismaClientOrTransaction,
88
} from "@trigger.dev/database";
9+
import { inferSchema } from "@jsonhero/schema-infer";
910
import parse from "parse-duration";
1011
import { type PrismaClient } from "~/db.server";
1112
import { RunsRepository } from "~/services/runsRepository/runsRepository.server";
@@ -34,6 +35,8 @@ type Task = {
3435
taskIdentifier: string;
3536
filePath: string;
3637
friendlyId: string;
38+
payloadSchema?: unknown;
39+
inferredPayloadSchema?: unknown;
3740
};
3841

3942
type Queue = {
@@ -244,11 +247,30 @@ export class TestTaskPresenter {
244247
},
245248
});
246249

250+
// Infer schema from existing run payloads when no explicit schema is defined
251+
let inferredPayloadSchema: unknown | undefined;
252+
if (!task.payloadSchema && latestRuns.length > 0 && task.triggerSource === "STANDARD") {
253+
let inference: ReturnType<typeof inferSchema> | undefined;
254+
for (const run of latestRuns) {
255+
try {
256+
const parsed = await parsePacket({ data: run.payload, dataType: run.payloadType });
257+
inference = inferSchema(parsed, inference);
258+
} catch {
259+
// Skip malformed runs — inference is best-effort
260+
}
261+
}
262+
if (inference) {
263+
inferredPayloadSchema = inference.toJSONSchema();
264+
}
265+
}
266+
247267
const taskWithEnvironment = {
248268
id: task.id,
249269
taskIdentifier: task.slug,
250270
filePath: task.filePath,
251271
friendlyId: task.friendlyId,
272+
payloadSchema: task.payloadSchema ?? undefined,
273+
inferredPayloadSchema,
252274
};
253275

254276
switch (task.triggerSource) {

0 commit comments

Comments
 (0)