From 00210d3e1bd7866df29a2a0e5bf45e8402c8ff55 Mon Sep 17 00:00:00 2001 From: "trueforge-dev-bot[bot]" Date: Fri, 11 Sep 2026 07:47:18 +0000 Subject: [PATCH 1/9] Regenerate OpenAPI document and TypeScript SDK --- .github/fern/openapi/openapi.json | 5 ++++- docs/openapi.json | 5 ++++- packages/trueforge-sdk/reference.md | 1 + .../src/api/resources/agents/client/Client.ts | 1 + .../agents/client/requests/CreateAgentRequest.ts | 3 ++- .../agents/client/requests/CreateAgentRequest.ts | 4 ++-- packages/trueforge-sdk/tests/wire/agents.test.ts | 12 ++++++++---- 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/fern/openapi/openapi.json b/.github/fern/openapi/openapi.json index b295b3484..3bcea27c9 100644 --- a/.github/fern/openapi/openapi.json +++ b/.github/fern/openapi/openapi.json @@ -32,6 +32,7 @@ "description": { "description": "Short summary of what the agent does.", "maxLength": 1024, + "minLength": 1, "type": "string" }, "id": { @@ -989,9 +990,9 @@ "additionalProperties": false, "properties": { "description": { - "default": "", "description": "Short summary of what the agent does.", "maxLength": 1024, + "minLength": 1, "type": "string" }, "manifest": { @@ -1003,6 +1004,7 @@ }, "required": [ "name", + "description", "manifest" ], "type": "object" @@ -5341,6 +5343,7 @@ "description": { "description": "Short summary of what the agent does.", "maxLength": 1024, + "minLength": 1, "type": "string" }, "manifest": { diff --git a/docs/openapi.json b/docs/openapi.json index b295b3484..3bcea27c9 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -32,6 +32,7 @@ "description": { "description": "Short summary of what the agent does.", "maxLength": 1024, + "minLength": 1, "type": "string" }, "id": { @@ -989,9 +990,9 @@ "additionalProperties": false, "properties": { "description": { - "default": "", "description": "Short summary of what the agent does.", "maxLength": 1024, + "minLength": 1, "type": "string" }, "manifest": { @@ -1003,6 +1004,7 @@ }, "required": [ "name", + "description", "manifest" ], "type": "object" @@ -5341,6 +5343,7 @@ "description": { "description": "Short summary of what the agent does.", "maxLength": 1024, + "minLength": 1, "type": "string" }, "manifest": { diff --git a/packages/trueforge-sdk/reference.md b/packages/trueforge-sdk/reference.md index dd0e0a9aa..dca445821 100644 --- a/packages/trueforge-sdk/reference.md +++ b/packages/trueforge-sdk/reference.md @@ -150,6 +150,7 @@ Creates an agent and allocates an immutable id. Fails if `name` is already taken ```typescript await client.agents.create({ + description: "description", manifest: { model: { name: "name" diff --git a/packages/trueforge-sdk/src/api/resources/agents/client/Client.ts b/packages/trueforge-sdk/src/api/resources/agents/client/Client.ts index fa1440f6f..658b0ce64 100644 --- a/packages/trueforge-sdk/src/api/resources/agents/client/Client.ts +++ b/packages/trueforge-sdk/src/api/resources/agents/client/Client.ts @@ -115,6 +115,7 @@ export class AgentsClient { * * @example * await client.agents.create({ + * description: "description", * manifest: { * model: { * name: "name" diff --git a/packages/trueforge-sdk/src/api/resources/agents/client/requests/CreateAgentRequest.ts b/packages/trueforge-sdk/src/api/resources/agents/client/requests/CreateAgentRequest.ts index 42f88b580..e62e24391 100644 --- a/packages/trueforge-sdk/src/api/resources/agents/client/requests/CreateAgentRequest.ts +++ b/packages/trueforge-sdk/src/api/resources/agents/client/requests/CreateAgentRequest.ts @@ -5,6 +5,7 @@ import type * as TrueForge from "../../../../index.js"; /** * @example * { + * description: "description", * manifest: { * model: { * name: "name" @@ -15,7 +16,7 @@ import type * as TrueForge from "../../../../index.js"; */ export interface CreateAgentRequest { /** Short summary of what the agent does. */ - description?: string; + description: string; manifest: TrueForge.AgentSpec; name: TrueForge.ResourceName; } diff --git a/packages/trueforge-sdk/src/serialization/resources/agents/client/requests/CreateAgentRequest.ts b/packages/trueforge-sdk/src/serialization/resources/agents/client/requests/CreateAgentRequest.ts index 93993fa7c..1fff2647c 100644 --- a/packages/trueforge-sdk/src/serialization/resources/agents/client/requests/CreateAgentRequest.ts +++ b/packages/trueforge-sdk/src/serialization/resources/agents/client/requests/CreateAgentRequest.ts @@ -10,14 +10,14 @@ export const CreateAgentRequest: core.serialization.Schema< serializers.CreateAgentRequest.Raw, TrueForge.CreateAgentRequest > = core.serialization.object({ - description: core.serialization.string().optional(), + description: core.serialization.string(), manifest: AgentSpec, name: ResourceName, }); export declare namespace CreateAgentRequest { export interface Raw { - description?: string | null; + description: string; manifest: AgentSpec.Raw; name: ResourceName.Raw; } diff --git a/packages/trueforge-sdk/tests/wire/agents.test.ts b/packages/trueforge-sdk/tests/wire/agents.test.ts index b6cec38fd..62ff88e92 100644 --- a/packages/trueforge-sdk/tests/wire/agents.test.ts +++ b/packages/trueforge-sdk/tests/wire/agents.test.ts @@ -65,7 +65,7 @@ describe("AgentsClient", () => { test("create (1)", async () => { const server = mockServerPool.createServer(); const client = new TrueForge({ maxRetries: 0, token: "test", baseUrl: server.baseUrl }); - const rawRequestBody = { manifest: { model: { name: "name" } }, name: "name" }; + const rawRequestBody = { description: "description", manifest: { model: { name: "name" } }, name: "name" }; const rawResponseBody = { data: { created_by_subject: { @@ -97,6 +97,7 @@ describe("AgentsClient", () => { .build(); const response = await client.agents.create({ + description: "description", manifest: { model: { name: "name", @@ -146,7 +147,7 @@ describe("AgentsClient", () => { test("create (2)", async () => { const server = mockServerPool.createServer(); const client = new TrueForge({ maxRetries: 0, token: "test", baseUrl: server.baseUrl }); - const rawRequestBody = { manifest: { model: { name: "x" } }, name: "xy" }; + const rawRequestBody = { description: "x", manifest: { model: { name: "x" } }, name: "xy" }; const rawResponseBody = { error: { message: "message" } }; server @@ -160,6 +161,7 @@ describe("AgentsClient", () => { await expect(async () => { return await client.agents.create({ + description: "x", manifest: { model: { name: "x", @@ -173,7 +175,7 @@ describe("AgentsClient", () => { test("create (3)", async () => { const server = mockServerPool.createServer(); const client = new TrueForge({ maxRetries: 0, token: "test", baseUrl: server.baseUrl }); - const rawRequestBody = { manifest: { model: { name: "x" } }, name: "xy" }; + const rawRequestBody = { description: "x", manifest: { model: { name: "x" } }, name: "xy" }; const rawResponseBody = { error: { message: "message" } }; server @@ -187,6 +189,7 @@ describe("AgentsClient", () => { await expect(async () => { return await client.agents.create({ + description: "x", manifest: { model: { name: "x", @@ -200,7 +203,7 @@ describe("AgentsClient", () => { test("create (4)", async () => { const server = mockServerPool.createServer(); const client = new TrueForge({ maxRetries: 0, token: "test", baseUrl: server.baseUrl }); - const rawRequestBody = { manifest: { model: { name: "x" } }, name: "xy" }; + const rawRequestBody = { description: "x", manifest: { model: { name: "x" } }, name: "xy" }; const rawResponseBody = { error: { message: "message" } }; server @@ -214,6 +217,7 @@ describe("AgentsClient", () => { await expect(async () => { return await client.agents.create({ + description: "x", manifest: { model: { name: "x", From af0f972efbf4b8a615551a852ad96d10ba320fff Mon Sep 17 00:00:00 2001 From: Harshil Vasoya Date: Fri, 11 Sep 2026 15:21:39 +0530 Subject: [PATCH 2/9] Chore: Add agent description support in UI --- .changeset/agent-description-ui.md | 5 + .../trueforge-ui/src/atoms/AgentsLibrary.tsx | 27 +- .../src/atoms/SaveAgentButton.tsx | 1 + .../trueforge-ui/src/atoms/SaveAgentForm.tsx | 32 +- .../src/atoms/agent-details/AgentOverview.tsx | 288 +++++++++--------- .../atoms/agent-details/AgentOverviewCard.tsx | 2 +- .../src/atoms/agent-details/types.ts | 2 +- .../agentSessionsServer.ts | 3 +- .../builderServer.ts | 19 +- .../chatServer.ts | 4 +- .../test/atoms/AgentDetailsPage.test.tsx | 2 + .../test/atoms/AgentsLibrary.test.tsx | 7 +- .../test/atoms/SaveAgentButton.test.tsx | 43 ++- .../agentSessionsServer.test.ts | 7 +- .../harnessBuilderServer.test.ts | 50 ++- 15 files changed, 322 insertions(+), 170 deletions(-) create mode 100644 .changeset/agent-description-ui.md diff --git a/.changeset/agent-description-ui.md b/.changeset/agent-description-ui.md new file mode 100644 index 000000000..41547498f --- /dev/null +++ b/.changeset/agent-description-ui.md @@ -0,0 +1,5 @@ +--- +"@truefoundry/trueforge-ui": patch +--- + +Round-trip agent description through save/load and show it in the library and agent details. diff --git a/packages/trueforge-ui/src/atoms/AgentsLibrary.tsx b/packages/trueforge-ui/src/atoms/AgentsLibrary.tsx index 086b103cf..35d0f5772 100644 --- a/packages/trueforge-ui/src/atoms/AgentsLibrary.tsx +++ b/packages/trueforge-ui/src/atoms/AgentsLibrary.tsx @@ -177,6 +177,7 @@ export function AgentLibraryRow({ const skillsTitle = skillNames.length ? skillNames.join(', ') : `${skillsCount} skills`; const hasConfiguration = modelLabel != null || skillsCount > 0 || mcpCount > 0; const hasNoSchedules = scheduleSummary != null && scheduleSummary.count === 0; + const description = spec?.description?.trim() ? spec.description : null; return ( @@ -194,6 +195,17 @@ export function AgentLibraryRow({ )} + + {description ? ( + + {description} + + ) : ( + + — + + )} + {hasConfiguration ? (
@@ -254,7 +266,7 @@ export function AgentLibraryRow({ )} ) : null} - +
@@ -474,14 +486,15 @@ export function AgentsLibrary({ onSelectAgent }: AgentsLibraryProps) { ) : ( <>
- +
- Agent name - Configuration - {showCreatedByColumn ? Created by : null} - {showSchedulesColumn ? Schedules : null} - + Agent name + Description + Configuration + {showCreatedByColumn ? Created by : null} + {showSchedulesColumn ? Schedules : null} + Actions diff --git a/packages/trueforge-ui/src/atoms/SaveAgentButton.tsx b/packages/trueforge-ui/src/atoms/SaveAgentButton.tsx index e9c5c4fe8..81bae6ba8 100644 --- a/packages/trueforge-ui/src/atoms/SaveAgentButton.tsx +++ b/packages/trueforge-ui/src/atoms/SaveAgentButton.tsx @@ -120,6 +120,7 @@ function SaveAgentButtonContent({ if (intent === 'update' && !canManageAgent) return; const normalizedName = name.trim(); if (!normalizedName || !draftSpec.model.name.trim()) return; + if (intent === 'create' && !(draftSpec.description?.trim() ?? '')) return; setSaving(true); setError(null); try { diff --git a/packages/trueforge-ui/src/atoms/SaveAgentForm.tsx b/packages/trueforge-ui/src/atoms/SaveAgentForm.tsx index 8c6d0f236..8a7dc0ad9 100644 --- a/packages/trueforge-ui/src/atoms/SaveAgentForm.tsx +++ b/packages/trueforge-ui/src/atoms/SaveAgentForm.tsx @@ -25,6 +25,7 @@ export function SaveAgentForm({ saving, error, onNameChange, + onChange, onCancel, onSave, }: SaveAgentFormProps) { @@ -36,6 +37,11 @@ export function SaveAgentForm({ errorRef.current?.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' }); }, [error]); + const canSave = + name.trim() !== '' && + spec.model.name.trim() !== '' && + (intent === 'update' || (spec.description?.trim() ?? '') !== ''); + return (
@@ -50,18 +56,18 @@ export function SaveAgentForm({ /> - {/* TODO: Uncomment the description field when the backend supports description */} - {/*