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
3 changes: 3 additions & 0 deletions apps/app/src/app/api/health/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function GET() {
return Response.json({ status: "ok" });
}
24 changes: 14 additions & 10 deletions apps/app/src/components/generative-ui/save-template-overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useState, useCallback, useMemo, useRef, type ReactNode } from "react";
import { useState, useCallback, useEffect, useMemo, type ReactNode } from "react";
import { useAgent } from "@copilotkit/react-core/v2";
import { SEED_TEMPLATES } from "@/components/template-library/seed-templates";

Expand Down Expand Up @@ -35,25 +35,29 @@ export function SaveTemplateOverlay({
const [saveState, setSaveState] = useState<SaveState>("idle");
const [templateName, setTemplateName] = useState("");

// Capture pending_template at mount time β€” it may be cleared by the agent later
// Capture pending_template once β€” it may be cleared by the agent later.
// Syncs external agent state into local state (legitimate effect-based setState).
const pending = agent.state?.pending_template as { id: string; name: string } | null | undefined;
const sourceRef = useRef<{ id: string; name: string } | null>(null);
if (pending?.id && !sourceRef.current) {
sourceRef.current = pending;
}
const [capturedSource, setCapturedSource] = useState<{ id: string; name: string } | null>(null);
useEffect(() => {
if (pending?.id) {
// eslint-disable-next-line react-hooks/set-state-in-effect -- one-time capture of external agent state
setCapturedSource((prev) => prev ?? pending);
}
}, [pending]);

// Check if this content matches an existing template:
// 1. Exact HTML match (seed templates rendered as-is)
// 2. Source template captured from pending_template (applied templates with modified data)
const matchedTemplate = useMemo(() => {
// First check source template from apply flow
if (sourceRef.current) {
if (capturedSource) {
const allTemplates = [
...SEED_TEMPLATES,
...((agent.state?.templates as { id: string; name: string }[]) || []),
];
const source = allTemplates.find((t) => t.id === sourceRef.current!.id);
if (source) return source;
const found = allTemplates.find((t) => t.id === capturedSource.id);
if (found) return found;
}
// Then check exact HTML match
if (!html) return null;
Expand All @@ -64,7 +68,7 @@ export function SaveTemplateOverlay({
...((agent.state?.templates as { id: string; name: string; html: string }[]) || []),
];
return allTemplates.find((t) => t.html && normalise(t.html) === norm) ?? null;
}, [html, agent.state?.templates]);
}, [html, agent.state?.templates, capturedSource]);

const handleSave = useCallback(() => {
const name = templateName.trim() || title || "Untitled Template";
Expand Down
29 changes: 22 additions & 7 deletions render.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
services:
# ── Agent (LangGraph Python) β€” private, not exposed to internet ──
- type: pserv
# ── Agent (LangGraph Python) β€” Docker required for langgraph-api image ──
- type: web
name: open-generative-ui-agent
runtime: docker
plan: starter
dockerfilePath: docker/Dockerfile.agent
healthCheckPath: /ok
scaling:
minInstances: 1
maxInstances: 3
targetMemoryPercent: 80
targetCPUPercent: 70
envVars:
- key: OPENAI_API_KEY
sync: false
Expand All @@ -18,17 +23,28 @@ services:
- apps/agent/**
- docker/Dockerfile.agent

# ── Frontend (Next.js) β€” public web service ──
# ── Frontend (Next.js) β€” native Node runtime ──
- type: web
name: open-generative-ui-app
runtime: docker
runtime: node
plan: starter
dockerfilePath: docker/Dockerfile.app
scaling:
minInstances: 1
maxInstances: 3
targetMemoryPercent: 80
targetCPUPercent: 70
buildCommand: corepack enable && pnpm install --no-frozen-lockfile && pnpm --filter @repo/app build
startCommand: pnpm --filter @repo/app start
healthCheckPath: /api/health
envVars:
- key: NODE_VERSION
value: "22"
- key: SKIP_INSTALL_DEPS
value: "true"
- key: LANGGRAPH_DEPLOYMENT_URL
fromService:
name: open-generative-ui-agent
type: pserv
type: web
property: hostport
- key: LANGSMITH_API_KEY
sync: false
Expand All @@ -44,4 +60,3 @@ services:
- package.json
- pnpm-lock.yaml
- turbo.json
- docker/Dockerfile.app
Loading