Skip to content

Commit 42749c9

Browse files
committed
chore(dashboard-agent): cut the agent, tool and watch-tick comments to their invariants
1 parent 5153cca commit 42749c9

6 files changed

Lines changed: 190 additions & 755 deletions

File tree

internal-packages/dashboard-agent/src/dashboard-agent.eval.ts

Lines changed: 22 additions & 111 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
// The webapp imports the task type from here for end-to-end transport typing. Always
2-
// `type`-only: a value import would pull the task's runtime dependencies (postgres,
3-
// drizzle, ai) into the webapp bundle and try to register the task in the webapp's
4-
// context.
1+
// Webapp imports must stay `type`-only: a value import pulls postgres/drizzle/ai into
2+
// the webapp bundle and registers the task in the wrong context.
53
export * from "./dashboard-agent.js";
64

7-
// The watch tasks, type-only for the same reason. The webapp triggers them by id
8-
// (`dashboard-agent-watch`, `dashboard-agent-watch-batch`), never by importing the
9-
// task value.
105
export type {
116
WatchBatchCheckEntry,
127
WatchBatchCheckResponse,
@@ -16,6 +11,4 @@ export type {
1611
watchTick,
1712
} from "./watch-tick.js";
1813

19-
// The view-catalog block types live in `@internal/dashboard-agent-contracts` and are
20-
// re-exported here so existing import sites keep working.
2114
export type { ChartBlock, DiagnosisBlock, ViewBlock } from "@internal/dashboard-agent-contracts";

internal-packages/dashboard-agent/src/tool-schemas.ts

Lines changed: 13 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
/**
2-
* Schema-only tool definitions plus the default system prompt text, shared between
3-
* the chat.agent task and the webapp's `chat.headStart` route handler.
4-
*
5-
* Bundle isolation is a hard constraint: the head-start route imports this file and
6-
* runs it in the webapp process, so anything imported here lands in that bundle.
7-
* Allowed imports are `ai`, `zod`, type-only AI SDK, and
8-
* `@internal/dashboard-agent-contracts` (a zod-only leaf package) — no
9-
* dashboard-agent-db, no `@trigger.dev/sdk` runtime, no postgres/drizzle. The
10-
* `execute` fns live in `tools.ts` and the route handler never sees them.
2+
* This file runs in the webapp bundle too. Only `ai`, `zod`, type-only AI SDK and
3+
* `@internal/dashboard-agent-contracts` may be imported here.
114
*/
125
import {
136
runFiltersSchema,
@@ -255,11 +248,8 @@ export const searchDocsSchema = tool({
255248
}),
256249
});
257250

258-
// `navigate_to` never emits a dashboard URL. It emits a `navigate` intent whose
259-
// target is a `trigger://` URI (the frozen grammar in dashboard-agent-contracts),
260-
// built server-side from typed params plus the turn's project ref and environment
261-
// id. The host resolves the URI to the current dashboard route, so a route rename
262-
// can't break a stored transcript and the model can never fabricate a link.
251+
// `navigate_to` emits a `navigate` intent carrying a `trigger://` URI, never a
252+
// dashboard URL. The URI is built server-side from the turn's project and env.
263253

264254
export const getCurrentPageSchema = tool({
265255
description:
@@ -302,27 +292,14 @@ export const navigateToSchema = tool({
302292
}),
303293
});
304294

305-
// The view catalog. The agent renders UI by emitting a spec of blocks from a fixed
306-
// catalog rather than arbitrary markup; the webapp maps each block `type` to a
307-
// React component in components/dashboard-agent/view-catalog.tsx.
308-
//
309-
// Block schemas live in `@internal/dashboard-agent-contracts` (src/blocks.ts) so
310-
// the webapp, the agent and persistence share one definition. Add a new block
311-
// there, then add a renderer entry in the webapp registry.
312-
//
313-
// The tool takes `viewBlockInputSchema`, the body-only schema with no
314-
// `{ id, revision, version }` envelope: block identity is system-owned, and the
315-
// executor in `tools.ts` stamps the envelope on. The enveloped `viewBlockSchema`
316-
// is for renderers and storage, never for the model.
295+
// A new block needs a schema in dashboard-agent-contracts (src/blocks.ts) and a
296+
// renderer entry in components/dashboard-agent/view-catalog.tsx.
317297

318298
export const renderViewSchema = tool({
319299
description:
320300
"Render a structured view in the dashboard panel: a stack of catalog blocks, instead of plain prose. The catalog has four blocks: `diagnosis` (the 'why did this run fail?' failure card, after gathering evidence with the read/source tools), `chart` (a line/bar chart of run_query results), `actions` (a row of 1-3 buttons offering next steps — a `watch` intent opens the watch configuration card pre-filled with the spec you composed, an `ask` intent sends the labelled question as the user's next message), and `investigation` (a live card for a hypothesis-driven investigation: report the state and the tool assigns and keeps its identity, so re-rendering it updates the same card). The result carries the `investigationId` it assigned — pass that back as `investigationId` when you render the same investigation again, including on a later turn. An investigation is rendered at least TWICE: once as `in_progress` when you open it, then again with the same `investigationId` carrying the final outcome (`concluded` or `inconclusive`), as the last tool call of the turn. A card left at `in_progress` is an unfinished answer whatever your prose says: the user is left watching a spinner. Keep any accompanying message to a one-line lead-in.",
321301
inputSchema: z.object({
322302
blocks: z.array(viewBlockInputSchema).min(1).describe("The blocks to render, top to bottom."),
323-
// Cross-turn continuation. Identity stays out of the block body: this is a
324-
// tool-level pointer at an existing row, and the store verifies it belongs to
325-
// this chat, project and environment before touching it.
326303
investigationId: z
327304
.string()
328305
.optional()
@@ -332,11 +309,8 @@ export const renderViewSchema = tool({
332309
}),
333310
});
334311

335-
// The spec the model composes is the frozen contract (`watchSpecSchema`). Its
336-
// cadence floors and 24h ceiling are enforced by the schema, so an over-eager watch
337-
// fails validation instead of becoming a hot loop. `since` for error recurrence is
338-
// server-set on persist and deliberately absent here, so the model can't backdate a
339-
// recurrence window.
312+
// `watchSpecSchema` enforces the cadence floors and 24h ceiling. `since` for error
313+
// recurrence is server-set on persist, so it is absent here.
340314

341315
export const scheduleWatchSchema = tool({
342316
description:
@@ -348,10 +322,6 @@ export const scheduleWatchSchema = tool({
348322
}),
349323
});
350324

351-
// Watch alerts: project-level email subscriptions on top of the always-on
352-
// dashboard notification. Creating one is a write the user has to ask for, and it
353-
// can be denied by plan or feature flag with a 403.
354-
355325
export const listAlertsSchema = tool({
356326
description:
357327
'List this project\'s alert subscriptions for watch results — who gets notified when a watch resolves, and whether each one is enabled. Use this to answer "what alerts do I have?".',
@@ -379,8 +349,7 @@ export const deleteAlertSchema = tool({
379349
}),
380350
});
381351

382-
// Code-mode tools, present only when the project has a connected GitHub repo. They
383-
// read the repo's source at a pinned commit from the agent's filesystem.
352+
// Code-mode tools, present only when the project has a connected GitHub repo.
384353
const runIdField = z
385354
.string()
386355
.optional()
@@ -437,11 +406,7 @@ export const searchCodeSchema = tool({
437406
}),
438407
});
439408

440-
/**
441-
* The schema-only tool set, in the same key order `tools.ts` attaches executes in.
442-
* Passed to `chat.headStart`'s `streamText` so step 1 can emit tool calls; the
443-
* agent run executes them on step 2+.
444-
*/
409+
/** The schema-only tool set, in the same key order `tools.ts` attaches executes in. */
445410
export const dashboardAgentToolSchemas = {
446411
list_projects: listProjectsSchema,
447412
list_environments: listEnvironmentsSchema,
@@ -455,8 +420,7 @@ export const dashboardAgentToolSchemas = {
455420
run_query: runQuerySchema,
456421
ask_support: askSupportSchema,
457422
render_view: renderViewSchema,
458-
// Appended, never reordered: this key order is the head-start warm step's tool
459-
// order too, and a reshuffle changes the prompt prefix the provider caches.
423+
// Append, never reorder: this key order is the prompt prefix the provider caches.
460424
get_report: getReportSchema,
461425
get_queue: getQueueSchema,
462426
list_deploys: listDeploysSchema,
@@ -482,13 +446,8 @@ export const dashboardAgentCodeToolSchemas = {
482446
search_code: searchCodeSchema,
483447
};
484448

485-
/**
486-
* Default model and system prompt, single-sourced in this light module so the
487-
* managed prompt in `prompts.ts` and the head-start route share them without the
488-
* route importing the SDK runtime. A dashboard override only affects the agent run;
489-
* the warm step 1 uses these defaults, so both sides run the same model and don't
490-
* shift tone mid-turn.
491-
*/
449+
// Defaults live here so the head-start route can read them without importing the SDK
450+
// runtime. A dashboard prompt override only affects the agent run, not the warm step.
492451
export const DASHBOARD_AGENT_MODEL = "claude-sonnet-4-6";
493452

494453
export const DASHBOARD_AGENT_SYSTEM_PROMPT = `You are the Trigger.dev dashboard agent, an assistant embedded in the Trigger.dev web dashboard.

0 commit comments

Comments
 (0)