Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/dashboard-agent-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: "🤖 Deploy dashboard agent"

# Deploys the @internal/dashboard-agent chat.agent to its Trigger.dev project
# with --skip-promotion, so a deploy never becomes "current" on its own. The
# consuming app cuts over by pinning DASHBOARD_AGENT_VERSION to the new version.
# Runs a leg per environment (staging + prod), each gated by its own environment;
# a push to main that touches the agent or its store triggers both. Version
# numbers are per-environment, so pin each environment to its own leg's version.

on:
push:
branches: [main]
paths:
- "internal-packages/dashboard-agent/**"
- "internal-packages/dashboard-agent-db/**"
workflow_dispatch:

permissions: {}

jobs:
deploy:
name: Deploy dashboard agent (${{ matrix.environment }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
environment: [staging, prod]
# Per-environment reviewer gate + source of the scoped deploy PAT.
environment: dashboard-agent-${{ matrix.environment }}
concurrency:
group: dashboard-agent-deploy-${{ matrix.environment }}
cancel-in-progress: false
permissions:
contents: read
env:
TRIGGER_API_URL: https://api.trigger.dev
TRIGGER_DASHBOARD_AGENT_PROJECT_REF: ${{ vars.TRIGGER_DASHBOARD_AGENT_PROJECT_REF }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Setup pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
with:
version: 10.33.2

- name: Setup node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 20.20.2
cache: "pnpm"

- name: Install + build the CLI and the agent's deps
run: |
set -euo pipefail
pnpm install --frozen-lockfile
# Prisma client is needed because the build closure pulls in @trigger.dev/database.
pnpm run generate
# Config-time imports the agent's trigger.config.ts needs: defineConfig (sdk), aptGet (build).
pnpm run build --filter trigger.dev --filter @trigger.dev/build --filter @trigger.dev/sdk

- name: Deploy (--skip-promotion)
working-directory: internal-packages/dashboard-agent
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_DASHBOARD_AGENT_DEPLOY_TOKEN }}
# Invoke the built CLI directly (what the workspace .bin/trigger wrapper does),
# so a not-yet-linked bin after a fresh install can't break the deploy.
run: node ../../packages/cli-v3/dist/esm/index.js deploy --skip-promotion --env ${{ matrix.environment }}
3 changes: 3 additions & 0 deletions apps/webapp/app/env.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ const EnvironmentSchema = z
// standard chat.agent SDK flow. When unset, the live agent is disabled — the
// conversation store / History still work, no chat can start.
DASHBOARD_AGENT_SECRET_KEY: z.string().optional(),
// Pins agent sessions to a specific deployed version (paired with
// --skip-promotion deploys); unset => the project env's current version.
DASHBOARD_AGENT_VERSION: z.string().optional(),
// Global default for the `hasDashboardAgentAccess` flag. "0" (off) ships the
// agent dark; flip to "1" to enable it for everyone at GA. Per-org overrides
// (org featureFlags) win regardless.
Expand Down
11 changes: 10 additions & 1 deletion apps/webapp/app/services/dashboardAgent.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,22 @@ export function isDashboardAgentConfigured(): boolean {
return Boolean(env.DASHBOARD_AGENT_SECRET_KEY);
}

// Pins every agent session (and its continuation runs) to a deployed version
// when DASHBOARD_AGENT_VERSION is set; unset runs on the env's current version.
export function dashboardAgentTriggerConfig(): { lockToVersion: string } | undefined {
return env.DASHBOARD_AGENT_VERSION ? { lockToVersion: env.DASHBOARD_AGENT_VERSION } : undefined;
}

export async function startDashboardAgentSession(params: {
chatId: string;
clientData?: Record<string, unknown>;
}): Promise<{ publicAccessToken: string }> {
const config = dashboardAgentConfig();
if (!config) throw new Error("DASHBOARD_AGENT_SECRET_KEY is not set");
const startSession = chat.createStartSessionAction(TASK_ID, { apiClient: config });
const startSession = chat.createStartSessionAction(TASK_ID, {
apiClient: config,
triggerConfig: dashboardAgentTriggerConfig(),
});
return startSession({ chatId: params.chatId, clientData: params.clientData });
}

Expand Down
6 changes: 5 additions & 1 deletion apps/webapp/app/services/dashboardAgentHeadStart.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import {
import { chat as chatServer } from "@trigger.dev/sdk/chat-server";
import { streamText, type UIMessage } from "ai";
import { env } from "~/env.server";
import { dashboardAgentApiOrigin } from "~/services/dashboardAgent.server";
import {
dashboardAgentApiOrigin,
dashboardAgentTriggerConfig,
} from "~/services/dashboardAgent.server";
import { logger } from "~/services/logger.server";

const TASK_ID = "dashboard-agent";
Expand Down Expand Up @@ -43,6 +46,7 @@ export async function startDashboardAgentHeadStart(params: {
chatId: params.chatId,
messages: params.messages,
metadata: params.metadata,
triggerConfig: dashboardAgentTriggerConfig(),
// Scope session creation + the agent trigger to the agent's project/env. The
// Anthropic key here only powers the warm step-1 call.
apiClient: {
Expand Down