Skip to content
Open
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
8 changes: 7 additions & 1 deletion apps/server/src/provider/Drivers/CodexDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const httpClient = yield* HttpClient.HttpClient;
const eventLoggers = yield* ProviderEventLoggers;
const serverConfig = yield* ServerConfig;
const processEnv = mergeProviderInstanceEnvironment(environment);
const homeLayout = yield* resolveCodexHomeLayout(config);
const continuationIdentity = codexContinuationIdentity(homeLayout);
Expand Down Expand Up @@ -159,7 +160,12 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
// in as instance rebuilds from the registry rather than in-place
// updates. Pre-provide `ChildProcessSpawner` so the check fits
// `makeManagedServerProvider.checkProvider`'s `R = never`.
const checkProvider = checkCodexProviderStatus(effectiveConfig, undefined, processEnv).pipe(
const checkProvider = checkCodexProviderStatus(
effectiveConfig,
serverConfig.cwd,
undefined,
processEnv,
).pipe(
Effect.map(stampIdentity),
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
);
Expand Down
7 changes: 6 additions & 1 deletion apps/server/src/provider/Drivers/CursorDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
const path = yield* Path.Path;
const httpClient = yield* HttpClient.HttpClient;
const eventLoggers = yield* ProviderEventLoggers;
const serverConfig = yield* ServerConfig;
const processEnv = mergeProviderInstanceEnvironment(environment);
const continuationIdentity = defaultProviderContinuationIdentity({
driverKind: DRIVER_KIND,
Expand All @@ -123,7 +124,11 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
});
const textGeneration = yield* makeCursorTextGeneration(effectiveConfig, processEnv);

const checkProvider = checkCursorProviderStatus(effectiveConfig, processEnv).pipe(
const checkProvider = checkCursorProviderStatus(
effectiveConfig,
serverConfig.cwd,
processEnv,
).pipe(
Effect.map(stampIdentity),
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
Effect.provideService(FileSystem.FileSystem, fileSystem),
Expand Down
7 changes: 6 additions & 1 deletion apps/server/src/provider/Drivers/GrokDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const httpClient = yield* HttpClient.HttpClient;
const eventLoggers = yield* ProviderEventLoggers;
const serverConfig = yield* ServerConfig;
const processEnv = mergeProviderInstanceEnvironment(environment);
const continuationIdentity = defaultProviderContinuationIdentity({
driverKind: DRIVER_KIND,
Expand All @@ -105,7 +106,11 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
});
const textGeneration = yield* makeGrokTextGeneration(effectiveConfig, processEnv);

const checkProvider = checkGrokProviderStatus(effectiveConfig, processEnv).pipe(
const checkProvider = checkGrokProviderStatus(
effectiveConfig,
serverConfig.cwd,
processEnv,
).pipe(
Effect.map(stampIdentity),
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
);
Expand Down
40 changes: 39 additions & 1 deletion apps/server/src/provider/Layers/CodexProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,43 @@ const requestAllCodexModels = Effect.fn("requestAllCodexModels")(function* (
return models;
});

export const listCodexProviderSkills = Effect.fn("listCodexProviderSkills")(function* (input: {
readonly binaryPath: string;
readonly homePath?: string;
readonly cwd: string;
readonly environment: NodeJS.ProcessEnv;
}) {
const resolvedHomePath = input.homePath ? expandHomePath(input.homePath) : undefined;
// The app-server command layer is scoped; callers must run this effect with
// `Effect.scoped` so the spawned process finalizer is released.
const clientContext = yield* Layer.build(
CodexClient.layerCommand({
command: input.binaryPath,
args: ["app-server"],
cwd: input.cwd,
env: {
...input.environment,
...(resolvedHomePath ? { CODEX_HOME: resolvedHomePath } : {}),
},
}),
);
const client = yield* Effect.service(CodexClient.CodexAppServerClient).pipe(
Effect.provide(clientContext),
);

yield* client.request("initialize", buildCodexInitializeParams());
yield* client.notify("initialized", undefined);
const accountResponse = yield* client.request("account/read", {});
if (!accountResponse.account && accountResponse.requiresOpenaiAuth) {
return [];
}

const response = yield* client.request("skills/list", {
cwds: [input.cwd],
});
return parseCodexSkillsListResponse(response, input.cwd);
});

export function buildCodexInitializeParams(): CodexSchema.V1InitializeParams {
return {
clientInfo: {
Expand Down Expand Up @@ -438,6 +475,7 @@ function accountProbeStatus(account: CodexAppServerProviderSnapshot["account"]):

export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(function* (
codexSettings: CodexSettings,
cwd: string,
probe: (input: {
readonly binaryPath: string;
readonly homePath?: string;
Expand Down Expand Up @@ -478,7 +516,7 @@ export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(fu
const probeResult = yield* probe({
binaryPath: codexSettings.binaryPath,
homePath: codexSettings.homePath,
cwd: process.cwd(),
cwd,
customModels: codexSettings.customModels,
environment,
}).pipe(
Expand Down
31 changes: 19 additions & 12 deletions apps/server/src/provider/Layers/CursorProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ describe("checkCursorProviderStatus", () => {
apiEndpoint: "",
customModels: [],
},
process.cwd(),
{
...process.env,
T3_ACP_REQUEST_LOG_PATH: requestLogPath,
Expand All @@ -444,12 +445,15 @@ describe("discoverCursorModelsViaAcp", () => {
const wrapperPath = await runNode(makeMockAgentWrapper());

const models = await Effect.runPromise(
discoverCursorModelsViaAcp({
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
}).pipe(Effect.provide(NodeServices.layer), Effect.scoped),
discoverCursorModelsViaAcp(
{
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
},
process.cwd(),
).pipe(Effect.provide(NodeServices.layer), Effect.scoped),
);

expect(models.map((model) => model.slug)).toEqual([
Expand All @@ -466,12 +470,15 @@ describe("discoverCursorModelsViaAcp", () => {
);

await Effect.runPromise(
discoverCursorModelsViaAcp({
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
}).pipe(Effect.provide(NodeServices.layer)),
discoverCursorModelsViaAcp(
{
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
},
process.cwd(),
).pipe(Effect.provide(NodeServices.layer)),
);

const exitLog = await runNode(waitForFileContent(exitLogPath));
Expand Down
16 changes: 11 additions & 5 deletions apps/server/src/provider/Layers/CursorProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ function buildCursorDiscoveredModelsFromAvailableModelsResponse(

const makeCursorAcpProbeRuntime = (
cursorSettings: CursorSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
) =>
Effect.gen(function* () {
Expand All @@ -406,10 +407,10 @@ const makeCursorAcpProbeRuntime = (
...(cursorSettings.apiEndpoint ? (["-e", cursorSettings.apiEndpoint] as const) : []),
"acp",
],
cwd: process.cwd(),
cwd,
env: environment,
},
cwd: process.cwd(),
cwd,
clientInfo: { name: "t3-code-provider-probe", version: "0.0.0" },
authMethodId: "cursor_login",
clientCapabilities: CURSOR_PARAMETERIZED_MODEL_PICKER_CAPABILITIES,
Expand All @@ -420,10 +421,11 @@ const makeCursorAcpProbeRuntime = (

const withCursorAcpProbeRuntime = <A, E, R>(
cursorSettings: CursorSettings,
cwd: string,
useRuntime: (acp: AcpSessionRuntime["Service"]) => Effect.Effect<A, E, R>,
environment: NodeJS.ProcessEnv = process.env,
) =>
makeCursorAcpProbeRuntime(cursorSettings, environment).pipe(
makeCursorAcpProbeRuntime(cursorSettings, cwd, environment).pipe(
Effect.flatMap(useRuntime),
Effect.scoped,
);
Expand Down Expand Up @@ -542,10 +544,12 @@ export function resolveCursorAcpConfigUpdates(

const discoverCursorModelsViaListAvailableModels = (
cursorSettings: CursorSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
) =>
withCursorAcpProbeRuntime(
cursorSettings,
cwd,
(acp) =>
Effect.gen(function* () {
yield* acp.start();
Expand All @@ -558,8 +562,9 @@ const discoverCursorModelsViaListAvailableModels = (

export const discoverCursorModelsViaAcp = (
cursorSettings: CursorSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
) => discoverCursorModelsViaListAvailableModels(cursorSettings, environment);
) => discoverCursorModelsViaListAvailableModels(cursorSettings, cwd, environment);

export function getCursorFallbackModels(
cursorSettings: Pick<CursorSettings, "customModels">,
Expand Down Expand Up @@ -967,6 +972,7 @@ const runCursorAboutCommand = (

export const checkCursorProviderStatus = Effect.fn("checkCursorProviderStatus")(function* (
cursorSettings: CursorSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
): Effect.fn.Return<
ServerProviderDraft,
Expand Down Expand Up @@ -1062,7 +1068,7 @@ export const checkCursorProviderStatus = Effect.fn("checkCursorProviderStatus")(
let discoveryWarning: string | undefined;
if (parsed.auth.status !== "unauthenticated") {
const discoveryExit = yield* Effect.exit(
discoverCursorModelsViaAcp(cursorSettings, environment).pipe(
discoverCursorModelsViaAcp(cursorSettings, cwd, environment).pipe(
Effect.timeoutOption(CURSOR_ACP_MODEL_DISCOVERY_TIMEOUT_MS),
),
);
Expand Down
3 changes: 3 additions & 0 deletions apps/server/src/provider/Layers/GrokProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ it.layer(NodeServices.layer)("checkGrokProviderStatus", (it) => {
enabled: true,
binaryPath: "/definitely/not/installed/grok-binary",
}),
process.cwd(),
);
expect(snapshot.enabled).toBe(true);
expect(snapshot.installed).toBe(false);
Expand All @@ -68,6 +69,7 @@ it.layer(NodeServices.layer)("checkGrokProviderStatus", (it) => {

return yield* checkGrokProviderStatus(
decodeGrokSettings({ enabled: true, binaryPath: grokPath }),
process.cwd(),
);
}),
);
Expand Down Expand Up @@ -95,6 +97,7 @@ it.layer(NodeServices.layer)("checkGrokProviderStatus", (it) => {

return yield* checkGrokProviderStatus(
decodeGrokSettings({ enabled: true, binaryPath: grokPath }),
process.cwd(),
);
}),
);
Expand Down
6 changes: 4 additions & 2 deletions apps/server/src/provider/Layers/GrokProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ function buildGrokDiscoveredModelsFromSessionModelState(

const discoverGrokModelsViaAcp = (
grokSettings: GrokSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
) =>
Effect.gen(function* () {
Expand All @@ -139,7 +140,7 @@ const discoverGrokModelsViaAcp = (
grokSettings,
environment,
childProcessSpawner,
cwd: process.cwd(),
cwd,
clientInfo: { name: "t3-code-provider-probe", version: "0.0.0" },
});
const started = yield* acp.start();
Expand All @@ -162,6 +163,7 @@ const runGrokVersionCommand = (

export const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(function* (
grokSettings: GrokSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
): Effect.fn.Return<ServerProviderDraft, never, ChildProcessSpawner.ChildProcessSpawner> {
const checkedAt = DateTime.formatIso(yield* DateTime.now);
Expand Down Expand Up @@ -244,7 +246,7 @@ export const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(func
});
}

const discoveryExit = yield* discoverGrokModelsViaAcp(grokSettings, environment).pipe(
const discoveryExit = yield* discoverGrokModelsViaAcp(grokSettings, cwd, environment).pipe(
Effect.timeoutOption(GROK_ACP_MODEL_DISCOVERY_TIMEOUT_MS),
Effect.exit,
);
Expand Down
Loading
Loading