Skip to content

Commit d3b8619

Browse files
committed
fix(core,webapp): plumb maxDuration / lockToVersion / region through SessionTriggerConfig + sync playground transport clientData
Two fixes from Devin's review on PR #3173. ## SessionTriggerConfig is missing 3 fields the playground UI shows The playground sidebar (`PlaygroundSidebar`) renders working controls for `maxDuration`, `version`, and `region`. The action received the form fields, but `SessionTriggerConfig` didn't accept them so they were `void`-suppressed and silently dropped. Runs ignored the user's max-duration cap, the version pin didn't apply, and region selection had no effect. - `packages/core/src/v3/schemas/api.ts` — add three optional fields to `SessionTriggerConfig`: `maxDuration` (positive int, seconds), `lockToVersion` (string), `region` (string). All three forward to the matching field on `TaskRunOptions`. - `apps/webapp/app/services/realtime/sessionRunManager.server.ts` — extend `triggerSessionRun`'s `body.options` to thread the three fields through to `TriggerTaskService` when present. - `apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.action.tsx` — fold the three form fields into `triggerConfig`; remove the `void` suppressions. ## Playground transport's clientData becomes stale after edits The route constructs `TriggerChatTransport` directly via `useRef` (to avoid the React-version mismatch the hook had). The hook normally calls `setClientData` whenever `clientData` changes, but this manual construction bypassed that — so `clientData` was captured at construction and never updated. Per-turn `metadata` merges (`this.defaultMetadata` in `packages/trigger-sdk/src/v3/chat.ts`) used the stale initial value for the whole conversation. `startSession` was already reading from the live ref so session creation was unaffected; this only fixed the per-turn path. - `apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.$agentParam/route.tsx` — add a `useEffect` that calls `transport.setClientData(...)` whenever `clientDataJson` changes. Changeset (patch, @trigger.dev/core) for the schema additions; server- changes file for the webapp-only behaviour fix.
1 parent b8b1b8a commit d3b8619

6 files changed

Lines changed: 34 additions & 7 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/core": patch
3+
---
4+
5+
Extend `SessionTriggerConfig` with three optional fields previously missing from the schema: `maxDuration` (per-run wall-clock cap, seconds), `lockToVersion` (pin every run to a specific worker version), and `region` (geographic scheduling). Each forwards to the matching field on `TaskRunOptions` when the run is triggered. Existing sessions without these fields are unaffected.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
area: webapp
3+
type: fix
4+
---
5+
6+
Playground action now forwards `maxDuration`, `version` (as `lockToVersion`), and `region` from the sidebar form into the Session's `triggerConfig`. Previously the form fields rendered as working controls but were silently dropped (`void`-suppressed) because `SessionTriggerConfig` didn't accept them — runs ignored the user's max duration, version pin, and region selection. With the schema extended in core, the playground now plumbs them through to `ensureRunForSession`.
7+
8+
Also fixes stale `clientData` in the playground transport: the JSON editor's value was captured at construction and never updated, so per-turn `metadata` merges used the original value across the whole conversation. Added a `useEffect` that calls `transport.setClientData(...)` whenever `clientDataJson` changes.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.$agentParam/route.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,15 @@ function PlaygroundChat() {
292292
}
293293
const transport = transportRef.current;
294294

295+
// Keep the transport's `defaultMetadata` in sync with the JSON editor.
296+
// Without this the transport uses the value captured at construction for
297+
// every per-turn metadata merge, even after the user edits the JSON.
298+
// `startSession` reads from `clientDataJsonRef.current` directly so session
299+
// creation is unaffected — this only fixes the per-turn metadata path.
300+
useEffect(() => {
301+
transport.setClientData(JSON.parse(clientDataJson || "{}") as Record<string, unknown>);
302+
}, [clientDataJson, transport]);
303+
295304
// Initial messages from persisted conversation (for resume)
296305
const initialMessages = activeConversation?.messages
297306
? (activeConversation.messages as UIMessage[])

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.action.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
131131
...(machine ? { machine } : {}),
132132
tags,
133133
...(maxAttempts ? { maxAttempts: parseInt(maxAttempts, 10) } : {}),
134+
...(maxDuration ? { maxDuration: parseInt(maxDuration, 10) } : {}),
135+
...(version ? { lockToVersion: version } : {}),
136+
...(region ? { region } : {}),
134137
};
135138

136139
// Atomic: upsert the Session, then trigger the first run via
@@ -213,13 +216,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
213216
},
214217
});
215218

216-
// Avoid unused-var lint while preserving the request shape
217-
// — these knobs are now folded into triggerConfig at the
218-
// session create above.
219-
void maxDuration;
220-
void version;
221-
void region;
222-
223219
const publicAccessToken = await mintSessionToken(
224220
environment as unknown as AuthenticatedEnvironment,
225221
chatId

apps/webapp/app/services/realtime/sessionRunManager.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ async function triggerSessionRun(params: {
223223
...(config.queue ? { queue: { name: config.queue } } : {}),
224224
...(config.tags ? { tags: config.tags } : {}),
225225
...(config.maxAttempts !== undefined ? { maxAttempts: config.maxAttempts } : {}),
226+
...(config.maxDuration !== undefined ? { maxDuration: config.maxDuration } : {}),
227+
...(config.lockToVersion ? { lockToVersion: config.lockToVersion } : {}),
228+
...(config.region ? { region: config.region } : {}),
226229
},
227230
};
228231

packages/core/src/v3/schemas/api.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,12 @@ export const SessionTriggerConfig = z.object({
14951495
queue: z.string().max(128).optional(),
14961496
tags: z.array(z.string().max(128)).max(5).optional(),
14971497
maxAttempts: z.number().int().positive().max(10).optional(),
1498+
/** Per-run wall-clock cap (seconds). Forwarded to `TaskRunOptions.maxDuration`. */
1499+
maxDuration: z.number().int().positive().optional(),
1500+
/** Pin every run to a specific worker version. Forwarded to `TaskRunOptions.lockToVersion`. */
1501+
lockToVersion: z.string().optional(),
1502+
/** Region to schedule runs in. Forwarded to `TaskRunOptions.region`. */
1503+
region: z.string().optional(),
14981504
/** Convenience field surfaced to chat.agent via the wire payload. */
14991505
idleTimeoutInSeconds: z.number().int().positive().max(3600).optional(),
15001506
});

0 commit comments

Comments
 (0)