Skip to content
Draft
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
172 changes: 172 additions & 0 deletions apps/server/src/provider/Drivers/AcpRegistryDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import {
AcpRegistrySettings,
ProviderDriverKind,
TextGenerationError,
type ServerProvider,
} from "@t3tools/contracts";
import { Effect, FileSystem, Path, Schema, Stream } from "effect";
import { ChildProcessSpawner } from "effect/unstable/process";

import { ServerConfig } from "../../config.ts";
import { ProviderDriverError } from "../Errors.ts";
import { makeGenericAcpAdapter } from "../Layers/GenericAcpAdapter.ts";
import { ProviderEventLoggers } from "../Layers/ProviderEventLoggers.ts";
import { makeManagedServerProvider } from "../makeManagedServerProvider.ts";
import {
defaultProviderContinuationIdentity,
type ProviderDriver,
type ProviderInstance,
} from "../ProviderDriver.ts";
import {
buildServerProvider,
providerModelsFromSettings,
type ServerProviderDraft,
} from "../providerSnapshot.ts";
import { mergeProviderInstanceEnvironment } from "../ProviderInstanceEnvironment.ts";

const DRIVER_KIND = ProviderDriverKind.make("acpRegistry");

export type AcpRegistryDriverEnv =
| ChildProcessSpawner.ChildProcessSpawner
| FileSystem.FileSystem
| Path.Path
| ProviderEventLoggers
| ServerConfig;

const unsupportedTextGeneration = (operation: string) =>
Effect.fail(
new TextGenerationError({
operation,
detail: "Generic ACP providers do not support git text generation yet.",
}),
);

const makeTextGeneration = () => ({
generateCommitMessage: () => unsupportedTextGeneration("generateCommitMessage"),
generatePrContent: () => unsupportedTextGeneration("generatePrContent"),
generateBranchName: () => unsupportedTextGeneration("generateBranchName"),
generateThreadTitle: () => unsupportedTextGeneration("generateThreadTitle"),
});

function withIdentity(input: {
readonly instanceId: ProviderInstance["instanceId"];
readonly displayName: string | undefined;
readonly accentColor: string | undefined;
readonly iconUrl: string | undefined;
readonly continuationGroupKey: string;
}) {
return (snapshot: ServerProviderDraft): ServerProvider => ({
...snapshot,
instanceId: input.instanceId,
driver: DRIVER_KIND,
...(input.displayName ? { displayName: input.displayName } : {}),
...(input.accentColor ? { accentColor: input.accentColor } : {}),
...(input.iconUrl ? { iconUrl: input.iconUrl } : {}),
continuation: { groupKey: input.continuationGroupKey },
});
}

function initialSnapshot(settings: AcpRegistrySettings): ServerProviderDraft {
const checkedAt = new Date().toISOString();
const command = settings.command.trim();
const enabled = settings.enabled && command.length > 0;
return buildServerProvider({
presentation: {
displayName: "ACP Registry",
badgeLabel: "ACP",
showInteractionModeToggle: true,
},
enabled,
checkedAt,
models: providerModelsFromSettings(
[{ slug: "default", name: "Default", isCustom: false, capabilities: null }],
DRIVER_KIND,
settings.customModels,
{ optionDescriptors: [] },
),
probe: {
installed: enabled,
version: null,
status: enabled ? "ready" : "warning",
auth: { status: "unknown" },
message: enabled ? "ACP provider configured." : "Configure a launch command to enable.",
},
});
}

export const AcpRegistryDriver: ProviderDriver<AcpRegistrySettings, AcpRegistryDriverEnv> = {
driverKind: DRIVER_KIND,
metadata: {
displayName: "ACP Registry",
supportsMultipleInstances: true,
},
configSchema: AcpRegistrySettings,
defaultConfig: (): AcpRegistrySettings => Schema.decodeSync(AcpRegistrySettings)({}),
create: ({ instanceId, displayName, accentColor, iconUrl, environment, enabled, config }) =>
Effect.gen(function* () {
const eventLoggers = yield* ProviderEventLoggers;
const effectiveConfig = { ...config, enabled: enabled && config.enabled };
const effectiveIconUrl = iconUrl ?? effectiveConfig.iconUrl;
const processEnv = {
...effectiveConfig.env,
...mergeProviderInstanceEnvironment(environment),
};
const continuationIdentity = defaultProviderContinuationIdentity({
driverKind: DRIVER_KIND,
instanceId,
});
const stamp = withIdentity({
instanceId,
displayName,
accentColor,
iconUrl: effectiveIconUrl,
continuationGroupKey: continuationIdentity.continuationKey,
});

const adapter = yield* makeGenericAcpAdapter(
{
enabled: effectiveConfig.enabled,
command: effectiveConfig.command || "acp",
args: effectiveConfig.args,
},
{
provider: DRIVER_KIND,
instanceId,
environment: processEnv,
readyReason: "ACP session ready",
...(eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}),
},
);

const snapshot = yield* makeManagedServerProvider<AcpRegistrySettings>({
getSettings: Effect.succeed(effectiveConfig),
streamSettings: Stream.never,
haveSettingsChanged: () => false,
initialSnapshot: (settings) => stamp(initialSnapshot(settings)),
checkProvider: Effect.succeed(stamp(initialSnapshot(effectiveConfig))),
}).pipe(
Effect.mapError(
(cause) =>
new ProviderDriverError({
driver: DRIVER_KIND,
instanceId,
detail: `Failed to build ACP Registry snapshot: ${cause.message ?? String(cause)}`,
cause,
}),
),
);

return {
instanceId,
driverKind: DRIVER_KIND,
continuationIdentity,
displayName,
accentColor,
iconUrl: effectiveIconUrl,
enabled: effectiveConfig.enabled,
snapshot,
adapter,
textGeneration: makeTextGeneration(),
} satisfies ProviderInstance;
}),
};
6 changes: 5 additions & 1 deletion apps/server/src/provider/Drivers/ClaudeDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const withInstanceIdentity =
readonly instanceId: ProviderInstance["instanceId"];
readonly displayName: string | undefined;
readonly accentColor: string | undefined;
readonly iconUrl: string | undefined;
readonly continuationGroupKey: string;
}) =>
(snapshot: ServerProviderDraft): ServerProvider => ({
Expand All @@ -60,6 +61,7 @@ const withInstanceIdentity =
driver: DRIVER_KIND,
...(input.displayName ? { displayName: input.displayName } : {}),
...(input.accentColor ? { accentColor: input.accentColor } : {}),
...(input.iconUrl ? { iconUrl: input.iconUrl } : {}),
continuation: { groupKey: input.continuationGroupKey },
});

Expand All @@ -71,7 +73,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {
},
configSchema: ClaudeSettings,
defaultConfig: (): ClaudeSettings => Schema.decodeSync(ClaudeSettings)({}),
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) =>
create: ({ instanceId, displayName, accentColor, iconUrl, environment, enabled, config }) =>
Effect.gen(function* () {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const path = yield* Path.Path;
Expand All @@ -87,6 +89,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {
instanceId,
displayName,
accentColor,
iconUrl,
continuationGroupKey,
});

Expand Down Expand Up @@ -148,6 +151,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {
},
displayName,
accentColor,
iconUrl,
enabled,
snapshot,
adapter,
Expand Down
6 changes: 5 additions & 1 deletion apps/server/src/provider/Drivers/CodexDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const withInstanceIdentity =
readonly instanceId: ProviderInstance["instanceId"];
readonly displayName: string | undefined;
readonly accentColor: string | undefined;
readonly iconUrl: string | undefined;
readonly continuationGroupKey: string;
}) =>
(snapshot: ServerProviderDraft): ServerProvider => ({
Expand All @@ -75,6 +76,7 @@ const withInstanceIdentity =
driver: DRIVER_KIND,
...(input.displayName ? { displayName: input.displayName } : {}),
...(input.accentColor ? { accentColor: input.accentColor } : {}),
...(input.iconUrl ? { iconUrl: input.iconUrl } : {}),
continuation: { groupKey: input.continuationGroupKey },
});

Expand All @@ -86,7 +88,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
},
configSchema: CodexSettings,
defaultConfig: (): CodexSettings => Schema.decodeSync(CodexSettings)({}),
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) =>
create: ({ instanceId, displayName, accentColor, iconUrl, environment, enabled, config }) =>
Effect.gen(function* () {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const eventLoggers = yield* ProviderEventLoggers;
Expand All @@ -97,6 +99,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
instanceId,
displayName,
accentColor,
iconUrl,
continuationGroupKey: continuationIdentity.continuationKey,
});
yield* materializeCodexShadowHome(homeLayout).pipe(
Expand Down Expand Up @@ -162,6 +165,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
continuationIdentity,
displayName,
accentColor,
iconUrl,
enabled,
snapshot,
adapter,
Expand Down
6 changes: 5 additions & 1 deletion apps/server/src/provider/Drivers/CursorDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const withInstanceIdentity =
readonly instanceId: ProviderInstance["instanceId"];
readonly displayName: string | undefined;
readonly accentColor: string | undefined;
readonly iconUrl: string | undefined;
readonly continuationGroupKey: string;
}) =>
(snapshot: ServerProviderDraft): ServerProvider => ({
Expand All @@ -58,6 +59,7 @@ const withInstanceIdentity =
driver: DRIVER_KIND,
...(input.displayName ? { displayName: input.displayName } : {}),
...(input.accentColor ? { accentColor: input.accentColor } : {}),
...(input.iconUrl ? { iconUrl: input.iconUrl } : {}),
continuation: { groupKey: input.continuationGroupKey },
});

Expand All @@ -69,7 +71,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
},
configSchema: CursorSettings,
defaultConfig: (): CursorSettings => Schema.decodeSync(CursorSettings)({}),
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) =>
create: ({ instanceId, displayName, accentColor, iconUrl, environment, enabled, config }) =>
Effect.gen(function* () {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const fileSystem = yield* FileSystem.FileSystem;
Expand All @@ -84,6 +86,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
instanceId,
displayName,
accentColor,
iconUrl,
continuationGroupKey: continuationIdentity.continuationKey,
});
const effectiveConfig = { ...config, enabled } satisfies CursorSettings;
Expand Down Expand Up @@ -139,6 +142,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
continuationIdentity,
displayName,
accentColor,
iconUrl,
enabled,
snapshot,
adapter,
Expand Down
6 changes: 5 additions & 1 deletion apps/server/src/provider/Drivers/OpenCodeDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const withInstanceIdentity =
readonly instanceId: ProviderInstance["instanceId"];
readonly displayName: string | undefined;
readonly accentColor: string | undefined;
readonly iconUrl: string | undefined;
readonly continuationGroupKey: string;
}) =>
(snapshot: ServerProviderDraft): ServerProvider => ({
Expand All @@ -59,6 +60,7 @@ const withInstanceIdentity =
driver: DRIVER_KIND,
...(input.displayName ? { displayName: input.displayName } : {}),
...(input.accentColor ? { accentColor: input.accentColor } : {}),
...(input.iconUrl ? { iconUrl: input.iconUrl } : {}),
continuation: { groupKey: input.continuationGroupKey },
});

Expand All @@ -70,7 +72,7 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>
},
configSchema: OpenCodeSettings,
defaultConfig: (): OpenCodeSettings => Schema.decodeSync(OpenCodeSettings)({}),
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) =>
create: ({ instanceId, displayName, accentColor, iconUrl, environment, enabled, config }) =>
Effect.gen(function* () {
const openCodeRuntime = yield* OpenCodeRuntime;
const serverConfig = yield* ServerConfig;
Expand All @@ -84,6 +86,7 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>
instanceId,
displayName,
accentColor,
iconUrl,
continuationGroupKey: continuationIdentity.continuationKey,
});
const effectiveConfig = { ...config, enabled } satisfies OpenCodeSettings;
Expand Down Expand Up @@ -126,6 +129,7 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>
continuationIdentity,
displayName,
accentColor,
iconUrl,
enabled,
snapshot,
adapter,
Expand Down
Loading
Loading