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
20 changes: 17 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,19 @@ jobs:

deploy:
name: Deploy → Vercel
needs: [library, website, cockpit, cockpit-examples-build, cockpit-smoke, cockpit-secret-integration, cockpit-deploy-smoke, chat-agent-smoke, cockpit-e2e, website-e2e]
needs:
[
library,
website,
cockpit,
cockpit-examples-build,
cockpit-smoke,
cockpit-secret-integration,
cockpit-deploy-smoke,
chat-agent-smoke,
cockpit-e2e,
website-e2e,
]
runs-on: ubuntu-latest
# Only deploy on pushes to main, not on pull requests
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
Expand Down Expand Up @@ -297,8 +309,10 @@ jobs:
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
- name: Verify LangGraph backends
run: npx tsx scripts/verify-langgraph-deployments.ts
- name: Verify shared LangGraph backend
run: npx tsx scripts/verify-shared-deployment.ts
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
- name: Run production smoke tests
run: npx playwright test apps/cockpit/e2e/production-smoke.spec.ts --reporter=list
env:
Expand Down
106 changes: 23 additions & 83 deletions .github/workflows/deploy-langgraph.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,89 +4,32 @@ on:
push:
branches: [main]
paths:
- 'cockpit/**/python/**'
- 'cockpit/langgraph/**/python/**'
- 'cockpit/deep-agents/**/python/**'
- 'apps/cockpit/scripts/capability-registry.ts'
- 'scripts/generate-shared-deployment-config.ts'
- 'deployments/shared-dev/langgraph.json'
workflow_dispatch:
inputs:
capability:
description: 'Capability path (e.g., langgraph/streaming)'
description: 'Deprecated and ignored by the shared deployment flow'
required: false
type: string

jobs:
deploy:
name: Deploy to LangGraph Cloud
name: Deploy shared cockpit-dev to LangGraph Cloud
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: streaming
path: cockpit/langgraph/streaming/python
- name: persistence
path: cockpit/langgraph/persistence/python
- name: interrupts
path: cockpit/langgraph/interrupts/python
- name: memory
path: cockpit/langgraph/memory/python
- name: durable-execution
path: cockpit/langgraph/durable-execution/python
- name: subgraphs
path: cockpit/langgraph/subgraphs/python
- name: time-travel
path: cockpit/langgraph/time-travel/python
- name: deployment-runtime
path: cockpit/langgraph/deployment-runtime/python
- name: planning
path: cockpit/deep-agents/planning/python
- name: filesystem
path: cockpit/deep-agents/filesystem/python
- name: da-subagents
path: cockpit/deep-agents/subagents/python
- name: da-memory
path: cockpit/deep-agents/memory/python
- name: skills
path: cockpit/deep-agents/skills/python
- name: sandboxes
path: cockpit/deep-agents/sandboxes/python
# Chat capabilities
- name: c-a2ui
path: cockpit/chat/a2ui/python
- name: c-debug
path: cockpit/chat/debug/python
- name: c-generative-ui
path: cockpit/chat/generative-ui/python
- name: c-input
path: cockpit/chat/input/python
- name: c-interrupts
path: cockpit/chat/interrupts/python
- name: c-messages
path: cockpit/chat/messages/python
- name: c-subagents
path: cockpit/chat/subagents/python
- name: c-theming
path: cockpit/chat/theming/python
- name: c-threads
path: cockpit/chat/threads/python
- name: c-timeline
path: cockpit/chat/timeline/python
- name: c-tool-calls
path: cockpit/chat/tool-calls/python
# Render capabilities
- name: r-computed-functions
path: cockpit/render/computed-functions/python
- name: r-element-rendering
path: cockpit/render/element-rendering/python
- name: r-registry
path: cockpit/render/registry/python
- name: r-repeat-loops
path: cockpit/render/repeat-loops/python
- name: r-spec-rendering
path: cockpit/render/spec-rendering/python
- name: r-state-management
path: cockpit/render/state-management/python
steps:
- uses: actions/checkout@v6.0.2

- uses: actions/setup-node@v6.3.0
with:
node-version: 22
cache: npm

- run: npm ci

- uses: actions/setup-python@v5
with:
python-version: '3.12'
Expand All @@ -97,19 +40,16 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Write .env for deployment
if: |
github.event_name == 'workflow_dispatch' && (inputs.capability == '' || contains(matrix.path, inputs.capability))
|| github.event_name == 'push'
working-directory: ${{ matrix.path }}
- name: Generate shared deployment manifest
run: npx tsx scripts/generate-shared-deployment-config.ts

- name: Write .env for shared deployment
run: |
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" > .env
mkdir -p deployments/shared-dev
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" > deployments/shared-dev/.env

- name: Deploy ${{ matrix.name }}
if: |
github.event_name == 'workflow_dispatch' && (inputs.capability == '' || contains(matrix.path, inputs.capability))
|| github.event_name == 'push'
working-directory: ${{ matrix.path }}
run: uv run --with langgraph-cli langgraph deploy --name ${{ matrix.name }} --no-wait
- name: Deploy cockpit-dev
working-directory: deployments/shared-dev
run: uv run --with langgraph-cli langgraph deploy --config langgraph.json --name cockpit-dev --no-wait
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ This file is for agents working in this repository. It is contributor-facing, no
- The workspace is Nx-based. Prefer project-scoped commands over broad workspace runs unless the task actually needs broader verification.
- Inspect `project.json`, `nx.json`, and existing scripts before inventing commands.
- If you need Nx-specific syntax or behavior and it is not obvious from local config, verify it from current Nx docs rather than relying on memory.
- The intended always-on LangSmith footprint is one shared cockpit dev deployment. Active capability keys in `deployment-urls.json` may all point at the same URL, and render demos stay local/static.
- Respect generated and public-facing context files. If the task changes docs, API surface, positioning, or package guidance, check whether agent context or docs should be regenerated.

## Docs and Generated Context
Expand Down
24 changes: 12 additions & 12 deletions apps/cockpit/scripts/capability-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const capabilities: readonly Capability[] = [
{ id: 'deployment-runtime', product: 'langgraph', topic: 'deployment-runtime', angularProject: 'cockpit-langgraph-deployment-runtime-angular', port: 4307, pythonDir: 'cockpit/langgraph/deployment-runtime/python', graphName: 'deployment-runtime' },
{ id: 'planning', product: 'deep-agents', topic: 'planning', angularProject: 'cockpit-deep-agents-planning-angular', port: 4310, pythonDir: 'cockpit/deep-agents/planning/python', graphName: 'planning' },
{ id: 'filesystem', product: 'deep-agents', topic: 'filesystem', angularProject: 'cockpit-deep-agents-filesystem-angular', port: 4311, pythonDir: 'cockpit/deep-agents/filesystem/python', graphName: 'filesystem' },
{ id: 'da-subagents', product: 'deep-agents', topic: 'subagents', angularProject: 'cockpit-deep-agents-subagents-angular', port: 4312, pythonDir: 'cockpit/deep-agents/subagents/python', graphName: 'da-subagents' },
{ id: 'da-subagents', product: 'deep-agents', topic: 'subagents', angularProject: 'cockpit-deep-agents-subagents-angular', port: 4312, pythonDir: 'cockpit/deep-agents/subagents/python', graphName: 'subagents' },
{ id: 'da-memory', product: 'deep-agents', topic: 'memory', angularProject: 'cockpit-deep-agents-memory-angular', port: 4313, pythonDir: 'cockpit/deep-agents/memory/python', graphName: 'da-memory' },
{ id: 'skills', product: 'deep-agents', topic: 'skills', angularProject: 'cockpit-deep-agents-skills-angular', port: 4314, pythonDir: 'cockpit/deep-agents/skills/python', graphName: 'skills' },
{ id: 'sandboxes', product: 'deep-agents', topic: 'sandboxes', angularProject: 'cockpit-deep-agents-sandboxes-angular', port: 4315, pythonDir: 'cockpit/deep-agents/sandboxes/python', graphName: 'sandboxes' },
Expand All @@ -35,17 +35,17 @@ export const capabilities: readonly Capability[] = [
{ id: 'repeat-loops', product: 'render', topic: 'repeat-loops', angularProject: 'cockpit-render-repeat-loops-angular', port: 4405, pythonDir: 'cockpit/render/repeat-loops/python', graphName: 'repeat-loops' },
{ id: 'computed-functions', product: 'render', topic: 'computed-functions', angularProject: 'cockpit-render-computed-functions-angular', port: 4406, pythonDir: 'cockpit/render/computed-functions/python', graphName: 'computed-functions' },
// Chat capabilities
{ id: 'c-messages', product: 'chat', topic: 'messages', angularProject: 'cockpit-chat-messages-angular', port: 4501, pythonDir: 'cockpit/chat/messages/python', graphName: 'c-messages' },
{ id: 'c-input', product: 'chat', topic: 'input', angularProject: 'cockpit-chat-input-angular', port: 4502, pythonDir: 'cockpit/chat/input/python', graphName: 'c-input' },
{ id: 'c-interrupts', product: 'chat', topic: 'interrupts', angularProject: 'cockpit-chat-interrupts-angular', port: 4503, pythonDir: 'cockpit/chat/interrupts/python', graphName: 'c-interrupts' },
{ id: 'c-tool-calls', product: 'chat', topic: 'tool-calls', angularProject: 'cockpit-chat-tool-calls-angular', port: 4504, pythonDir: 'cockpit/chat/tool-calls/python', graphName: 'c-tool-calls' },
{ id: 'c-subagents', product: 'chat', topic: 'subagents', angularProject: 'cockpit-chat-subagents-angular', port: 4505, pythonDir: 'cockpit/chat/subagents/python', graphName: 'c-subagents' },
{ id: 'c-threads', product: 'chat', topic: 'threads', angularProject: 'cockpit-chat-threads-angular', port: 4506, pythonDir: 'cockpit/chat/threads/python', graphName: 'c-threads' },
{ id: 'c-timeline', product: 'chat', topic: 'timeline', angularProject: 'cockpit-chat-timeline-angular', port: 4507, pythonDir: 'cockpit/chat/timeline/python', graphName: 'c-timeline' },
{ id: 'c-generative-ui', product: 'chat', topic: 'generative-ui', angularProject: 'cockpit-chat-generative-ui-angular', port: 4508, pythonDir: 'cockpit/chat/generative-ui/python', graphName: 'c-generative-ui' },
{ id: 'c-debug', product: 'chat', topic: 'debug', angularProject: 'cockpit-chat-debug-angular', port: 4509, pythonDir: 'cockpit/chat/debug/python', graphName: 'c-debug' },
{ id: 'c-theming', product: 'chat', topic: 'theming', angularProject: 'cockpit-chat-theming-angular', port: 4510, pythonDir: 'cockpit/chat/theming/python', graphName: 'c-theming' },
{ id: 'c-a2ui', product: 'chat', topic: 'a2ui', angularProject: 'cockpit-chat-a2ui-angular', port: 4511, pythonDir: 'cockpit/chat/a2ui/python', graphName: 'c-a2ui' },
{ id: 'c-messages', product: 'chat', topic: 'messages', angularProject: 'cockpit-chat-messages-angular', port: 4501, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-messages' },
{ id: 'c-input', product: 'chat', topic: 'input', angularProject: 'cockpit-chat-input-angular', port: 4502, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-input' },
{ id: 'c-interrupts', product: 'chat', topic: 'interrupts', angularProject: 'cockpit-chat-interrupts-angular', port: 4503, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-interrupts' },
{ id: 'c-tool-calls', product: 'chat', topic: 'tool-calls', angularProject: 'cockpit-chat-tool-calls-angular', port: 4504, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-tool-calls' },
{ id: 'c-subagents', product: 'chat', topic: 'subagents', angularProject: 'cockpit-chat-subagents-angular', port: 4505, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-subagents' },
{ id: 'c-threads', product: 'chat', topic: 'threads', angularProject: 'cockpit-chat-threads-angular', port: 4506, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-threads' },
{ id: 'c-timeline', product: 'chat', topic: 'timeline', angularProject: 'cockpit-chat-timeline-angular', port: 4507, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-timeline' },
{ id: 'c-generative-ui', product: 'chat', topic: 'generative-ui', angularProject: 'cockpit-chat-generative-ui-angular', port: 4508, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-generative-ui' },
{ id: 'c-debug', product: 'chat', topic: 'debug', angularProject: 'cockpit-chat-debug-angular', port: 4509, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-debug' },
{ id: 'c-theming', product: 'chat', topic: 'theming', angularProject: 'cockpit-chat-theming-angular', port: 4510, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-theming' },
{ id: 'c-a2ui', product: 'chat', topic: 'a2ui', angularProject: 'cockpit-chat-a2ui-angular', port: 4511, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'c-a2ui' },
] as const;

export function findCapability(id: string): Capability | undefined {
Expand Down
42 changes: 39 additions & 3 deletions apps/cockpit/scripts/generate-combined-langgraph.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
import { writeFileSync } from 'fs';
import { readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';
import { capabilities } from './capability-registry';

type LangGraphManifest = {
graphs: Record<string, string>;
};

const manifestCache = new Map<string, LangGraphManifest>();
function readManifest(pythonDir: string): LangGraphManifest {
const existing = manifestCache.get(pythonDir);
if (existing) {
return existing;
}

const manifestPath = resolve(process.cwd(), pythonDir, 'langgraph.json');
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as LangGraphManifest;
manifestCache.set(pythonDir, manifest);
return manifest;
}

function normalizeEntrypoint(pythonDir: string, graphName: string): string {
const manifest = readManifest(pythonDir);
const entrypoint = manifest.graphs[graphName]
?? (() => {
const manifestEntries = Object.entries(manifest.graphs);
if (manifestEntries.length === 1) {
return manifestEntries[0]?.[1];
}
return undefined;
})();
if (!entrypoint) {
throw new Error(`Missing graph '${graphName}' in ${pythonDir}/langgraph.json`);
}

return entrypoint.startsWith('./') ? entrypoint.slice(2) : entrypoint;
}

const graphs: Record<string, string> = {};
const dependencies = new Set<string>();
for (const c of capabilities) {
graphs[c.graphName] = `./${c.pythonDir}/src/graph.py:graph`;
graphs[c.graphName] = `./${c.pythonDir}/${normalizeEntrypoint(c.pythonDir, c.graphName)}`;
dependencies.add(`./${c.pythonDir}`);
}

const config = { graphs, dependencies: capabilities.map((c) => `./${c.pythonDir}/pyproject.toml`), env: '.env' };
const config = { graphs, dependencies: [...dependencies], env: '.env' };
const out = resolve(process.cwd(), 'langgraph-combined.json');
writeFileSync(out, JSON.stringify(config, null, 2) + '\n');
console.log(`Generated ${out} with ${Object.keys(graphs).length} graphs`);
2 changes: 1 addition & 1 deletion cockpit/chat/a2ui/angular/src/environments/environment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const environment = {
production: true,
langGraphApiUrl: '/api',
a2uiAssistantId: 'a2ui_form',
a2uiAssistantId: 'c-a2ui',
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const environment = {
production: true,
langGraphApiUrl: '/api',
generativeUiAssistantId: 'generative_ui',
generativeUiAssistantId: 'c-generative-ui',
};
4 changes: 2 additions & 2 deletions cockpit/langgraph/streaming/python/langgraph.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"graphs": {
"streaming": "./src/graph.py:graph",
"generative_ui": "./src/chat_graphs.py:generative_ui",
"c-generative-ui": "./src/chat_graphs.py:generative_ui",
"c-messages": "./src/chat_graphs.py:c_messages",
"c-input": "./src/chat_graphs.py:c_input",
"c-debug": "./src/chat_graphs.py:c_debug",
Expand All @@ -11,7 +11,7 @@
"c-timeline": "./src/chat_graphs.py:c_timeline",
"c-tool-calls": "./src/chat_graphs.py:c_tool_calls",
"c-subagents": "./src/chat_graphs.py:c_subagents",
"a2ui_form": "./src/a2ui_graph.py:graph"
"c-a2ui": "./src/a2ui_graph.py:graph"
},
"dependencies": [
"."
Expand Down
Loading
Loading