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
6 changes: 6 additions & 0 deletions .changeset/daytona-sandbox-config-extension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@truefoundry/trueforge-assistant-ui-runtime': minor
'@truefoundry/trueforge-ui': minor
---

Make sandbox provider port types identity-only; move Daytona lifecycle fields (`execTimeoutMs`, auto-stop/archive/delete intervals) onto host `DaytonaSandboxConfig`.
2 changes: 0 additions & 2 deletions packages/assistant-ui-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,9 @@ export type {
SandboxBase,
SandboxCatalogEntry,
SandboxCatalogServer,
SandboxConfig,
SandboxCreatedEvent,
SandboxProviderBase,
SandboxProviderCatalogEntry,
SandboxProviderConfig,
SandboxProviderListEntry,
SandboxSnapshotSyncStatus,
SaveAgentRequest,
Expand Down
2 changes: 0 additions & 2 deletions packages/assistant-ui-runtime/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,8 @@ export type {
SandboxBase,
SandboxCatalogEntry,
SandboxCatalogServer,
SandboxConfig,
SandboxProviderBase,
SandboxProviderCatalogEntry,
SandboxProviderConfig,
SandboxProviderListEntry,
SandboxSnapshotSyncStatus,
SaveAgentRequest,
Expand Down
20 changes: 6 additions & 14 deletions packages/assistant-ui-runtime/src/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -724,25 +724,18 @@ export interface SkillCatalogServer<
// Sandbox providers catalog — public rows omit credentials; writes accept them
// ---------------------------------------------------------------------------

/** Mutable sandbox provider settings shared by catalog rows, create, and update. */
export interface SandboxConfig {
execTimeoutMs: number;
autoStopIntervalInMinutes: number;
autoArchiveIntervalInMinutes: number;
autoDeleteIntervalInMinutes: number;
}

export interface SandboxCatalogEntry extends SandboxConfig {
/** Discovery catalog row. Hosts extend for provider-specific defaults. */
export interface SandboxCatalogEntry {
id: string;
name: string;
type: string;
}

/**
* Connected sandbox provider row (settings/sandboxes). No raw `apiKey`.
* Includes last-saved config so update forms can show previous values.
* Hosts extend for provider-specific settings shown on update forms.
*/
export interface SandboxBase extends SandboxConfig {
export interface SandboxBase {
id: string;
name: string;
catalogId: string;
Expand All @@ -759,22 +752,21 @@ export interface SandboxProviderListEntry<TSandbox extends SandboxBase = Sandbox
snapshotSyncStatus: SandboxSnapshotSyncStatus;
}

export interface CreateSandboxRequest extends SandboxConfig {
export interface CreateSandboxRequest {
/** `SandboxCatalogEntry.id` used to create this sandbox provider. */
catalogId: string;
name: string;
type: string;
apiKey: string;
}

export interface UpdateSandboxRequest extends SandboxConfig {
export interface UpdateSandboxRequest {
id: string;
/** Omit to keep the existing key; send a value to rotate. */
apiKey?: string;
}

/** Host-facing aliases (trueforge-ui public names). */
export type SandboxProviderConfig = SandboxConfig;
export type SandboxProviderCatalogEntry = SandboxCatalogEntry;
export type SandboxProviderBase = SandboxBase;
export type CreateSandboxProviderRequest = CreateSandboxRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { Accordion, AccordionDetails, AccordionSummary } from '../../atoms/primi
import { Button } from '../../atoms/primitives/Button.js';
import { CenteredModal } from '../../atoms/primitives/CenteredModal.js';
import { Icon } from '../../icons/Icon.js';
import type { SandboxProviderConfig } from '../../server/types.js';
import type { DaytonaSandboxConfig } from '../../plugins/trueforge-agent-server-adapter/catalogs/sandboxProviderCatalog.js';

export type SandboxConfigDraft = SandboxProviderConfig & {
export type SandboxConfigDraft = DaytonaSandboxConfig & {
apiKey: string;
};

Expand All @@ -21,16 +21,15 @@ type ConfigureSandboxFormProps = {
title: string;
description?: string;
/** Prefills config fields; apiKey is never autofilled. */
initialConfig?: SandboxProviderConfig | null;
initialConfig?: DaytonaSandboxConfig | null;
/** When false (updates), empty apiKey means keep the existing key. */
requireApiKey?: boolean;
busy?: boolean;
error?: string | null;
};

/** Sensible defaults so the advanced fields are never blank, even without a catalog preset. */
const EMPTY_CONFIG: SandboxProviderConfig = {
// Snapshot/image is release-owned now; kept only to satisfy the external SandboxProviderConfig type.
const EMPTY_CONFIG: DaytonaSandboxConfig = {
execTimeoutMs: 300000,
autoStopIntervalInMinutes: 15,
autoArchiveIntervalInMinutes: 10080,
Expand Down Expand Up @@ -110,7 +109,6 @@ const ConfigureSandboxForm = ({

try {
await onSave({
// Snapshot/image is release-owned; the field is retained only for the external type.
execTimeoutMs: execTimeout,
autoStopIntervalInMinutes: autoStop,
autoArchiveIntervalInMinutes: autoArchive,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { Spinner } from '@/atoms/primitives/Spinner.js';
import { Button } from '../../atoms/primitives/Button.js';
import { Tooltip } from '../../atoms/primitives/Tooltip.js';
import { Icon } from '../../icons/Icon.js';
import {
isDaytonaSandboxConfig,
type DaytonaSandboxConfig,
} from '../../plugins/trueforge-agent-server-adapter/catalogs/sandboxProviderCatalog.js';
import { useCatalogServer } from '../../server/ServerContext.js';
import type {
SandboxProviderBase,
SandboxProviderCatalogEntry,
SandboxProviderConfig,
SandboxProviderListEntry,
SandboxSnapshotSyncStatus,
} from '../../server/types.js';
Expand All @@ -25,7 +28,7 @@ const configFrom = ({
autoStopIntervalInMinutes,
autoArchiveIntervalInMinutes,
autoDeleteIntervalInMinutes,
}: SandboxProviderConfig): SandboxProviderConfig => ({
}: DaytonaSandboxConfig): DaytonaSandboxConfig => ({
execTimeoutMs,
autoStopIntervalInMinutes,
autoArchiveIntervalInMinutes,
Expand Down Expand Up @@ -144,10 +147,11 @@ const SandboxSettings = () => {
return catalog.filter(entry => !connectedCatalogIds.has(entry.id));
}, [catalog, providers, hasConfiguredProvider]);

const formInitialConfig = useMemo(
() => (updateProvider ? configFrom(updateProvider) : createEntry ? configFrom(createEntry) : null),
[updateProvider, createEntry],
);
const formInitialConfig = useMemo(() => {
const source = updateProvider ?? createEntry;
if (source == null || !isDaytonaSandboxConfig(source)) return null;
return configFrom(source);
}, [updateProvider, createEntry]);

if (!sandboxCatalog) {
return <p className="text-sm text-text-secondary">Sandbox provider catalog is not available.</p>;
Expand Down Expand Up @@ -202,6 +206,7 @@ const SandboxSettings = () => {
};

const handleRetry = (provider: SandboxProviderBase) => {
if (!isDaytonaSandboxConfig(provider)) return;
void runMutation(async () => {
await sandboxCatalog.updateSandboxProvider({
id: provider.id,
Expand Down
2 changes: 1 addition & 1 deletion packages/trueforge-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,6 @@ export type {
SandboxCatalogServer,
SandboxProviderBase,
SandboxProviderCatalogEntry,
SandboxProviderConfig,
SandboxProviderListEntry,
SandboxSnapshotSyncStatus,
SaveAgentRequest,
Expand Down Expand Up @@ -477,6 +476,7 @@ export type {
AgentSessionsProps,
} from './atoms/agent-details/types.js';
export { AgentMetricsContainer } from './containers/AgentMetricsContainer.js';
export type { DaytonaSandboxConfig } from './plugins/trueforge-agent-server-adapter/catalogs/sandboxProviderCatalog.js';
export type { SessionEventTimelineSegment, SessionEventType } from './utils/sessionEventTimeline.js';
export type { SessionTurnView } from './utils/sessionTurnViews.js';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,42 @@
* UI: multi-row providers with `id` / `catalogId` / `name` / flat `apiKey`.
* Harness: one Daytona provider per tenant; catalog YAML has no name — synthetic
* identity uses `type` (`daytona`) as id/catalogId and display name `Daytona`.
*
* Daytona lifecycle fields live here as a host extension of the generic sandbox
* port types (identity + credentials only).
*/
import type { TrueForge } from '@truefoundry/trueforge-sdk';
import { TrueForgeApi } from '@truefoundry/trueforge-sdk';
import type {
CreateSandboxProviderRequest,
SandboxCatalogServer,
SandboxProviderBase,
SandboxProviderCatalogEntry,
SandboxProviderConfig,
SandboxProviderListEntry,
UpdateSandboxProviderRequest,
} from '../../../server/types.js';

export type UiSandboxProvider = SandboxProviderBase;
export type UiSandboxProviderCatalogEntry = SandboxProviderCatalogEntry;
export type UiSandboxProviderListEntry = SandboxProviderListEntry;
/** Daytona-only sandbox lifecycle settings. Not on the generic sandbox port. */
export interface DaytonaSandboxConfig {
execTimeoutMs: number;
autoStopIntervalInMinutes: number;
autoArchiveIntervalInMinutes: number;
autoDeleteIntervalInMinutes: number;
}

export type UiSandboxProvider = SandboxProviderBase & DaytonaSandboxConfig;
export type UiSandboxProviderCatalogEntry = SandboxProviderCatalogEntry & DaytonaSandboxConfig;
export type UiSandboxProviderListEntry = SandboxProviderListEntry<UiSandboxProvider>;
export type UiCreateSandboxProviderRequest = CreateSandboxProviderRequest & DaytonaSandboxConfig;
export type UiUpdateSandboxProviderRequest = UpdateSandboxProviderRequest & DaytonaSandboxConfig;

export type DaytonaSandboxCatalogServer = SandboxCatalogServer<
UiSandboxProvider,
UiSandboxProviderCatalogEntry,
UiCreateSandboxProviderRequest,
UiUpdateSandboxProviderRequest,
UiSandboxProviderListEntry
>;

const DAYTONA_TYPE = 'daytona';
const DAYTONA_DISPLAY_NAME = 'Daytona';
Expand All @@ -30,9 +52,22 @@ function displayNameForType(type: string): string {
return type;
}

export function isDaytonaSandboxConfig(value: object): value is DaytonaSandboxConfig {
return (
'execTimeoutMs' in value &&
typeof value.execTimeoutMs === 'number' &&
'autoStopIntervalInMinutes' in value &&
typeof value.autoStopIntervalInMinutes === 'number' &&
'autoArchiveIntervalInMinutes' in value &&
typeof value.autoArchiveIntervalInMinutes === 'number' &&
'autoDeleteIntervalInMinutes' in value &&
typeof value.autoDeleteIntervalInMinutes === 'number'
);
}

export function configFromHarness(
provider: TrueForgeApi.CatalogSandboxProvider | TrueForgeApi.SandboxProviderManifest,
): SandboxProviderConfig {
): DaytonaSandboxConfig {
return {
execTimeoutMs: provider.execTimeoutMs,
autoStopIntervalInMinutes: provider.autoStopIntervalInMinutes,
Expand Down Expand Up @@ -94,7 +129,7 @@ export function toHarnessManifest(
req: {
type: string;
apiKey: string;
} & SandboxProviderConfig,
} & DaytonaSandboxConfig,
): TrueForgeApi.SandboxProviderManifest {
if (req.type !== DAYTONA_TYPE) {
throw new Error(`Unsupported sandbox provider type: ${req.type}`);
Expand All @@ -110,7 +145,7 @@ export function toHarnessManifest(
}

/** Settings sandbox-catalog port for `createTrueForgeServer`. Delete omitted (no BE route). */
export function createSandboxProviderCatalog(client: TrueForge): SandboxCatalogServer {
export function createSandboxProviderCatalog(client: TrueForge): DaytonaSandboxCatalogServer {
async function resolveApiKey(apiKey: string | undefined): Promise<string> {
const trimmed = apiKey?.trim();
if (trimmed !== undefined && trimmed !== '') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@ export {
configFromHarness,
createSandboxProviderCatalog,
filterUiSandboxProviders,
isDaytonaSandboxConfig,
toHarnessManifest as toHarnessSandboxManifest,
toUiCatalogEntry as toUiSandboxCatalogEntry,
toUiSandboxProvider,
toUiSandboxProviderListEntry,
type DaytonaSandboxCatalogServer,
type DaytonaSandboxConfig,
type UiCreateSandboxProviderRequest,
type UiSandboxProvider,
type UiSandboxProviderCatalogEntry,
type UiSandboxProviderListEntry,
type UiUpdateSandboxProviderRequest,
} from './catalogs/sandboxProviderCatalog.js';
export { createSkillCatalog, toHarnessManifest as toHarnessSkillManifest, toUiSkill } from './catalogs/skillCatalog.js';
export {
Expand Down
1 change: 0 additions & 1 deletion packages/trueforge-ui/src/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ export type {
SandboxCatalogServer,
SandboxProviderBase,
SandboxProviderCatalogEntry,
SandboxProviderConfig,
SandboxProviderListEntry,
SandboxSnapshotSyncStatus,
SaveAgentRequest,
Expand Down
Loading
Loading