authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-19 21:11:33-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-19 21:11:33-07:00
log742dd7af0dcb54c32774f87fd354105726c7a9db
tree45d2a18f157ea43645a48bf8aa3bda0cf56647d7
parent5c1ac922574340be4560eacf928237929497d11d
signature Signed by PGP key B5690EEEBB952194

[codex] Standardize Effect protocol adapter services (#3201)

Co-authored-by: codex <codex@users.noreply.github.com>

14 files changed, 661 insertions(+), 544 deletions(-)

apps/server/src/provider/Layers/CodexProvider.ts+3-2
...@@ -7,7 +7,8 @@ import * as Result from "effect/Result";...@@ -7,7 +7,8 @@ import * as Result from "effect/Result";
7import * as Schema from "effect/Schema";7import * as Schema from "effect/Schema";
8import * as Scope from "effect/Scope";8import * as Scope from "effect/Scope";
9import * as Types from "effect/Types";9import * as Types from "effect/Types";
10import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";10import * as ChildProcess from "effect/unstable/process/ChildProcess";
11import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
11import * as CodexClient from "effect-codex-app-server/client";12import * as CodexClient from "effect-codex-app-server/client";
12import * as CodexSchema from "effect-codex-app-server/schema";13import * as CodexSchema from "effect-codex-app-server/schema";
13import * as CodexErrors from "effect-codex-app-server/errors";14import * as CodexErrors from "effect-codex-app-server/errors";
...@@ -253,7 +254,7 @@ function parseCodexSkillsListResponse(...@@ -253,7 +254,7 @@ function parseCodexSkillsListResponse(
253}254}
254255
255const requestAllCodexModels = Effect.fn("requestAllCodexModels")(function* (256const requestAllCodexModels = Effect.fn("requestAllCodexModels")(function* (
256 client: CodexClient.CodexAppServerClientShape,257 client: CodexClient.CodexAppServerClient["Service"],
257) {258) {
258 const models: ServerProviderModel[] = [];259 const models: ServerProviderModel[] = [];
259 let cursor: string | null | undefined = undefined;260 let cursor: string | null | undefined = undefined;
apps/server/src/provider/Layers/CursorAdapter.ts+4-4
...@@ -36,7 +36,7 @@ import * as Scope from "effect/Scope";...@@ -36,7 +36,7 @@ import * as Scope from "effect/Scope";
36import * as Semaphore from "effect/Semaphore";36import * as Semaphore from "effect/Semaphore";
37import * as Stream from "effect/Stream";37import * as Stream from "effect/Stream";
38import * as SynchronizedRef from "effect/SynchronizedRef";38import * as SynchronizedRef from "effect/SynchronizedRef";
39import { ChildProcessSpawner } from "effect/unstable/process";39import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
40import * as EffectAcpErrors from "effect-acp/errors";40import * as EffectAcpErrors from "effect-acp/errors";
41import type * as EffectAcpSchema from "effect-acp/schema";41import type * as EffectAcpSchema from "effect-acp/schema";
4242
...@@ -50,7 +50,7 @@ import {...@@ -50,7 +50,7 @@ import {
50 ProviderAdapterValidationError,50 ProviderAdapterValidationError,
51} from "../Errors.ts";51} from "../Errors.ts";
52import { acpPermissionOutcome, mapAcpToAdapterError } from "../acp/AcpAdapterSupport.ts";52import { acpPermissionOutcome, mapAcpToAdapterError } from "../acp/AcpAdapterSupport.ts";
53import { type AcpSessionRuntimeShape } from "../acp/AcpSessionRuntime.ts";53import type * as AcpSessionRuntime from "../acp/AcpSessionRuntime.ts";
54import {54import {
55 makeAcpAssistantItemEvent,55 makeAcpAssistantItemEvent,
56 makeAcpContentDeltaEvent,56 makeAcpContentDeltaEvent,
...@@ -126,7 +126,7 @@ interface CursorSessionContext {...@@ -126,7 +126,7 @@ interface CursorSessionContext {
126 readonly threadId: ThreadId;126 readonly threadId: ThreadId;
127 session: ProviderSession;127 session: ProviderSession;
128 readonly scope: Scope.Closeable;128 readonly scope: Scope.Closeable;
129 readonly acp: AcpSessionRuntimeShape;129 readonly acp: AcpSessionRuntime.AcpSessionRuntime["Service"];
130 notificationFiber: Fiber.Fiber<void, never> | undefined;130 notificationFiber: Fiber.Fiber<void, never> | undefined;
131 readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>;131 readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>;
132 readonly pendingUserInputs: Map<ApprovalRequestId, PendingUserInput>;132 readonly pendingUserInputs: Map<ApprovalRequestId, PendingUserInput>;
...@@ -246,7 +246,7 @@ function resolveRequestedModeId(input: {...@@ -246,7 +246,7 @@ function resolveRequestedModeId(input: {
246}246}
247247
248function applyRequestedSessionConfiguration<E>(input: {248function applyRequestedSessionConfiguration<E>(input: {
249 readonly runtime: AcpSessionRuntimeShape;249 readonly runtime: AcpSessionRuntime.AcpSessionRuntime["Service"];
250 readonly runtimeMode: RuntimeMode;250 readonly runtimeMode: RuntimeMode;
251 readonly interactionMode: ProviderInteractionMode | undefined;251 readonly interactionMode: ProviderInteractionMode | undefined;
252 readonly modelSelection:252 readonly modelSelection:
apps/server/src/provider/Layers/CursorProvider.ts+7-4
...@@ -21,7 +21,8 @@ import * as Path from "effect/Path";...@@ -21,7 +21,8 @@ import * as Path from "effect/Path";
21import * as Result from "effect/Result";21import * as Result from "effect/Result";
22import * as Schema from "effect/Schema";22import * as Schema from "effect/Schema";
23import { HttpClient } from "effect/unstable/http";23import { HttpClient } from "effect/unstable/http";
24import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";24import * as ChildProcess from "effect/unstable/process/ChildProcess";
25import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
25import {26import {
26 createModelCapabilities,27 createModelCapabilities,
27 getProviderOptionBooleanSelectionValue,28 getProviderOptionBooleanSelectionValue,
...@@ -43,7 +44,7 @@ import {...@@ -43,7 +44,7 @@ import {
43 enrichProviderSnapshotWithVersionAdvisory,44 enrichProviderSnapshotWithVersionAdvisory,
44 type ProviderMaintenanceCapabilities,45 type ProviderMaintenanceCapabilities,
45} from "../providerMaintenance.ts";46} from "../providerMaintenance.ts";
46import { AcpSessionRuntime } from "../acp/AcpSessionRuntime.ts";47import * as AcpSessionRuntime from "../acp/AcpSessionRuntime.ts";
47import { CursorListAvailableModelsResponse } from "../acp/CursorAcpExtension.ts";48import { CursorListAvailableModelsResponse } from "../acp/CursorAcpExtension.ts";
4849
49const decodeCursorListAvailableModelsResponse = Schema.decodeUnknownEffect(50const decodeCursorListAvailableModelsResponse = Schema.decodeUnknownEffect(
...@@ -416,12 +417,14 @@ const makeCursorAcpProbeRuntime = (...@@ -416,12 +417,14 @@ const makeCursorAcpProbeRuntime = (
416 clientCapabilities: CURSOR_PARAMETERIZED_MODEL_PICKER_CAPABILITIES,417 clientCapabilities: CURSOR_PARAMETERIZED_MODEL_PICKER_CAPABILITIES,
417 }).pipe(Layer.provide(Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner))),418 }).pipe(Layer.provide(Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner))),
418 );419 );
419 return yield* Effect.service(AcpSessionRuntime).pipe(Effect.provide(acpContext));420 return yield* Effect.service(AcpSessionRuntime.AcpSessionRuntime).pipe(
421 Effect.provide(acpContext),
422 );
420 });423 });
421424
422const withCursorAcpProbeRuntime = <A, E, R>(425const withCursorAcpProbeRuntime = <A, E, R>(
423 cursorSettings: CursorSettings,426 cursorSettings: CursorSettings,
424 useRuntime: (acp: AcpSessionRuntime["Service"]) => Effect.Effect<A, E, R>,427 useRuntime: (acp: AcpSessionRuntime.AcpSessionRuntime["Service"]) => Effect.Effect<A, E, R>,
425 environment?: NodeJS.ProcessEnv,428 environment?: NodeJS.ProcessEnv,
426) =>429) =>
427 makeCursorAcpProbeRuntime(cursorSettings, environment).pipe(430 makeCursorAcpProbeRuntime(cursorSettings, environment).pipe(
apps/server/src/provider/Layers/GrokAdapter.ts+3-3
...@@ -27,7 +27,7 @@ import * as Scope from "effect/Scope";...@@ -27,7 +27,7 @@ import * as Scope from "effect/Scope";
27import * as Semaphore from "effect/Semaphore";27import * as Semaphore from "effect/Semaphore";
28import * as Stream from "effect/Stream";28import * as Stream from "effect/Stream";
29import * as SynchronizedRef from "effect/SynchronizedRef";29import * as SynchronizedRef from "effect/SynchronizedRef";
30import { ChildProcessSpawner } from "effect/unstable/process";30import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
31import * as EffectAcpErrors from "effect-acp/errors";31import * as EffectAcpErrors from "effect-acp/errors";
32import type * as EffectAcpSchema from "effect-acp/schema";32import type * as EffectAcpSchema from "effect-acp/schema";
3333
...@@ -41,7 +41,7 @@ import {...@@ -41,7 +41,7 @@ import {
41 ProviderAdapterValidationError,41 ProviderAdapterValidationError,
42} from "../Errors.ts";42} from "../Errors.ts";
43import { mapAcpToAdapterError } from "../acp/AcpAdapterSupport.ts";43import { mapAcpToAdapterError } from "../acp/AcpAdapterSupport.ts";
44import { type AcpSessionRuntimeShape } from "../acp/AcpSessionRuntime.ts";44import type * as AcpSessionRuntime from "../acp/AcpSessionRuntime.ts";
45import {45import {
46 makeAcpAssistantItemEvent,46 makeAcpAssistantItemEvent,
47 makeAcpContentDeltaEvent,47 makeAcpContentDeltaEvent,
...@@ -101,7 +101,7 @@ interface GrokSessionContext {...@@ -101,7 +101,7 @@ interface GrokSessionContext {
101 readonly acpSessionId: string;101 readonly acpSessionId: string;
102 session: ProviderSession;102 session: ProviderSession;
103 readonly scope: Scope.Closeable;103 readonly scope: Scope.Closeable;
104 readonly acp: AcpSessionRuntimeShape;104 readonly acp: AcpSessionRuntime.AcpSessionRuntime["Service"];
105 notificationFiber: Fiber.Fiber<void, never> | undefined;105 notificationFiber: Fiber.Fiber<void, never> | undefined;
106 readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>;106 readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>;
107 readonly pendingUserInputs: Map<ApprovalRequestId, PendingUserInput>;107 readonly pendingUserInputs: Map<ApprovalRequestId, PendingUserInput>;
apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+12-12
...@@ -10,7 +10,7 @@ import * as Effect from "effect/Effect";...@@ -10,7 +10,7 @@ import * as Effect from "effect/Effect";
10import * as Stream from "effect/Stream";10import * as Stream from "effect/Stream";
11import { describe, expect } from "vite-plus/test";11import { describe, expect } from "vite-plus/test";
1212
13import { AcpSessionRuntime, type AcpSessionRequestLogEvent } from "./AcpSessionRuntime.ts";13import * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
14import type * as EffectAcpProtocol from "effect-acp/protocol";14import type * as EffectAcpProtocol from "effect-acp/protocol";
1515
16const __dirname = path.dirname(fileURLToPath(import.meta.url));16const __dirname = path.dirname(fileURLToPath(import.meta.url));
...@@ -20,9 +20,9 @@ const mockAgentArgs = [mockAgentPath];...@@ -20,9 +20,9 @@ const mockAgentArgs = [mockAgentPath];
2020
21describe("AcpSessionRuntime", () => {21describe("AcpSessionRuntime", () => {
22 it.effect("merges custom initialize client capabilities into the ACP handshake", () => {22 it.effect("merges custom initialize client capabilities into the ACP handshake", () => {
23 const requestEvents: Array<AcpSessionRequestLogEvent> = [];23 const requestEvents: Array<AcpSessionRuntime.AcpSessionRequestLogEvent> = [];
24 return Effect.gen(function* () {24 return Effect.gen(function* () {
25 const runtime = yield* AcpSessionRuntime;25 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
26 yield* runtime.start();26 yield* runtime.start();
2727
28 const initializeStarted = requestEvents.find(28 const initializeStarted = requestEvents.find(
...@@ -64,7 +64,7 @@ describe("AcpSessionRuntime", () => {...@@ -64,7 +64,7 @@ describe("AcpSessionRuntime", () => {
6464
65 it.effect("starts a session, prompts, and emits normalized events against the mock agent", () =>65 it.effect("starts a session, prompts, and emits normalized events against the mock agent", () =>
66 Effect.gen(function* () {66 Effect.gen(function* () {
67 const runtime = yield* AcpSessionRuntime;67 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
68 const started = yield* runtime.start();68 const started = yield* runtime.start();
6969
70 expect(started.initializeResult).toMatchObject({ protocolVersion: 1 });70 expect(started.initializeResult).toMatchObject({ protocolVersion: 1 });
...@@ -115,7 +115,7 @@ describe("AcpSessionRuntime", () => {...@@ -115,7 +115,7 @@ describe("AcpSessionRuntime", () => {
115115
116 it.effect("segments assistant text around ACP tool calls", () =>116 it.effect("segments assistant text around ACP tool calls", () =>
117 Effect.gen(function* () {117 Effect.gen(function* () {
118 const runtime = yield* AcpSessionRuntime;118 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
119 yield* runtime.start();119 yield* runtime.start();
120120
121 const promptResult = yield* runtime.prompt({121 const promptResult = yield* runtime.prompt({
...@@ -176,7 +176,7 @@ describe("AcpSessionRuntime", () => {...@@ -176,7 +176,7 @@ describe("AcpSessionRuntime", () => {
176176
177 it.effect("suppresses generic placeholder tool updates until completion", () =>177 it.effect("suppresses generic placeholder tool updates until completion", () =>
178 Effect.gen(function* () {178 Effect.gen(function* () {
179 const runtime = yield* AcpSessionRuntime;179 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
180 yield* runtime.start();180 yield* runtime.start();
181181
182 const promptResult = yield* runtime.prompt({182 const promptResult = yield* runtime.prompt({
...@@ -213,9 +213,9 @@ describe("AcpSessionRuntime", () => {...@@ -213,9 +213,9 @@ describe("AcpSessionRuntime", () => {
213 );213 );
214214
215 it.effect("logs ACP requests from the shared runtime", () => {215 it.effect("logs ACP requests from the shared runtime", () => {
216 const requestEvents: Array<AcpSessionRequestLogEvent> = [];216 const requestEvents: Array<AcpSessionRuntime.AcpSessionRequestLogEvent> = [];
217 return Effect.gen(function* () {217 return Effect.gen(function* () {
218 const runtime = yield* AcpSessionRuntime;218 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
219 yield* runtime.start();219 yield* runtime.start();
220220
221 yield* runtime.setModel("composer-2");221 yield* runtime.setModel("composer-2");
...@@ -265,9 +265,9 @@ describe("AcpSessionRuntime", () => {...@@ -265,9 +265,9 @@ describe("AcpSessionRuntime", () => {
265 });265 });
266266
267 it.effect("skips no-op session config writes when the requested value is already active", () => {267 it.effect("skips no-op session config writes when the requested value is already active", () => {
268 const requestEvents: Array<AcpSessionRequestLogEvent> = [];268 const requestEvents: Array<AcpSessionRuntime.AcpSessionRequestLogEvent> = [];
269 return Effect.gen(function* () {269 return Effect.gen(function* () {
270 const runtime = yield* AcpSessionRuntime;270 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
271 yield* runtime.start();271 yield* runtime.start();
272272
273 yield* runtime.setConfigOption("model", "default");273 yield* runtime.setConfigOption("model", "default");
...@@ -302,7 +302,7 @@ describe("AcpSessionRuntime", () => {...@@ -302,7 +302,7 @@ describe("AcpSessionRuntime", () => {
302 it.effect("emits low-level ACP protocol logs for raw and decoded messages", () => {302 it.effect("emits low-level ACP protocol logs for raw and decoded messages", () => {
303 const protocolEvents: Array<EffectAcpProtocol.AcpProtocolLogEvent> = [];303 const protocolEvents: Array<EffectAcpProtocol.AcpProtocolLogEvent> = [];
304 return Effect.gen(function* () {304 return Effect.gen(function* () {
305 const runtime = yield* AcpSessionRuntime;305 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
306 yield* runtime.start();306 yield* runtime.start();
307307
308 yield* runtime.prompt({308 yield* runtime.prompt({
...@@ -350,7 +350,7 @@ describe("AcpSessionRuntime", () => {...@@ -350,7 +350,7 @@ describe("AcpSessionRuntime", () => {
350 const tempDir = mkdtempSync(path.join(os.tmpdir(), "acp-runtime-"));350 const tempDir = mkdtempSync(path.join(os.tmpdir(), "acp-runtime-"));
351 const requestLogPath = path.join(tempDir, "requests.ndjson");351 const requestLogPath = path.join(tempDir, "requests.ndjson");
352 return Effect.gen(function* () {352 return Effect.gen(function* () {
353 const runtime = yield* AcpSessionRuntime;353 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
354 yield* runtime.start();354 yield* runtime.start();
355355
356 const error = yield* runtime.setModel("composer-2[fast=false]").pipe(Effect.flip);356 const error = yield* runtime.setModel("composer-2[fast=false]").pipe(Effect.flip);
apps/server/src/provider/acp/AcpNativeLogging.ts+5-5
...@@ -6,9 +6,9 @@ import * as Effect from "effect/Effect";...@@ -6,9 +6,9 @@ import * as Effect from "effect/Effect";
6import type * as EffectAcpProtocol from "effect-acp/protocol";6import type * as EffectAcpProtocol from "effect-acp/protocol";
77
8import type { EventNdjsonLogger } from "../Layers/EventNdjsonLogger.ts";8import type { EventNdjsonLogger } from "../Layers/EventNdjsonLogger.ts";
9import type { AcpSessionRequestLogEvent, AcpSessionRuntimeOptions } from "./AcpSessionRuntime.ts";9import type * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
1010
11function formatRequestLogPayload(event: AcpSessionRequestLogEvent) {11function formatRequestLogPayload(event: AcpSessionRuntime.AcpSessionRequestLogEvent) {
12 return {12 return {
13 method: event.method,13 method: event.method,
14 status: event.status,14 status: event.status,
...@@ -24,7 +24,7 @@ export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory"...@@ -24,7 +24,7 @@ export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory"
24 readonly nativeEventLogger: EventNdjsonLogger | undefined;24 readonly nativeEventLogger: EventNdjsonLogger | undefined;
25 readonly provider: ProviderDriverKind;25 readonly provider: ProviderDriverKind;
26 readonly threadId: ThreadId;26 readonly threadId: ThreadId;
27 }): Pick<AcpSessionRuntimeOptions, "requestLogger" | "protocolLogging"> => {27 }): Pick<AcpSessionRuntime.AcpSessionRuntimeOptions, "requestLogger" | "protocolLogging"> => {
28 const writeNativeAcpLog = (logInput: {28 const writeNativeAcpLog = (logInput: {
29 readonly kind: "request" | "protocol";29 readonly kind: "request" | "protocol";
30 readonly payload: unknown;30 readonly payload: unknown;
...@@ -57,7 +57,7 @@ export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory"...@@ -57,7 +57,7 @@ export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory"
57 );57 );
5858
59 return {59 return {
60 requestLogger: (event: AcpSessionRequestLogEvent) =>60 requestLogger: (event: AcpSessionRuntime.AcpSessionRequestLogEvent) =>
61 writeNativeAcpLog({61 writeNativeAcpLog({
62 kind: "request",62 kind: "request",
63 payload: formatRequestLogPayload(event),63 payload: formatRequestLogPayload(event),
...@@ -72,7 +72,7 @@ export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory"...@@ -72,7 +72,7 @@ export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory"
72 kind: "protocol",72 kind: "protocol",
73 payload: event,73 payload: event,
74 }),74 }),
75 } satisfies NonNullable<AcpSessionRuntimeOptions["protocolLogging"]>,75 } satisfies NonNullable<AcpSessionRuntime.AcpSessionRuntimeOptions["protocolLogging"]>,
76 }76 }
77 : {}),77 : {}),
78 };78 };
apps/server/src/provider/acp/AcpSessionRuntime.ts+161-63
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1import * as Cause from "effect/Cause";1import * as Cause from "effect/Cause";
2import * as Context from "effect/Context";
2import * as Deferred from "effect/Deferred";3import * as Deferred from "effect/Deferred";
3import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
4import * as Exit from "effect/Exit";5import * as Exit from "effect/Exit";
...@@ -6,9 +7,9 @@ import * as Layer from "effect/Layer";...@@ -6,9 +7,9 @@ import * as Layer from "effect/Layer";
6import * as Queue from "effect/Queue";7import * as Queue from "effect/Queue";
7import * as Ref from "effect/Ref";8import * as Ref from "effect/Ref";
8import * as Scope from "effect/Scope";9import * as Scope from "effect/Scope";
9import * as Context from "effect/Context";
10import * as Stream from "effect/Stream";10import * as Stream from "effect/Stream";
11import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";11import * as ChildProcess from "effect/unstable/process/ChildProcess";
12import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
12import * as EffectAcpClient from "effect-acp/client";13import * as EffectAcpClient from "effect-acp/client";
13import * as EffectAcpErrors from "effect-acp/errors";14import * as EffectAcpErrors from "effect-acp/errors";
14import type * as EffectAcpSchema from "effect-acp/schema";15import type * as EffectAcpSchema from "effect-acp/schema";
...@@ -75,50 +76,153 @@ export interface AcpSessionRuntimeStartResult {...@@ -75,50 +76,153 @@ export interface AcpSessionRuntimeStartResult {
75 readonly modelConfigId: string | undefined;76 readonly modelConfigId: string | undefined;
76}77}
7778
78export interface AcpSessionRuntimeShape {79export class AcpSessionRuntime extends Context.Service<
79 readonly handleRequestPermission: EffectAcpClient.AcpClientShape["handleRequestPermission"];80 AcpSessionRuntime,
80 readonly handleElicitation: EffectAcpClient.AcpClientShape["handleElicitation"];81 {
81 readonly handleReadTextFile: EffectAcpClient.AcpClientShape["handleReadTextFile"];82 /**
82 readonly handleWriteTextFile: EffectAcpClient.AcpClientShape["handleWriteTextFile"];83 * Registers a handler for `session/request_permission`.
83 readonly handleCreateTerminal: EffectAcpClient.AcpClientShape["handleCreateTerminal"];84 * @see https://agentclientprotocol.com/protocol/schema#session/request_permission
84 readonly handleTerminalOutput: EffectAcpClient.AcpClientShape["handleTerminalOutput"];85 */
85 readonly handleTerminalWaitForExit: EffectAcpClient.AcpClientShape["handleTerminalWaitForExit"];86 readonly handleRequestPermission: EffectAcpClient.AcpClient["Service"]["handleRequestPermission"];
86 readonly handleTerminalKill: EffectAcpClient.AcpClientShape["handleTerminalKill"];87 /**
87 readonly handleTerminalRelease: EffectAcpClient.AcpClientShape["handleTerminalRelease"];88 * Registers a handler for `session/elicitation`.
88 readonly handleSessionUpdate: EffectAcpClient.AcpClientShape["handleSessionUpdate"];89 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation
89 readonly handleElicitationComplete: EffectAcpClient.AcpClientShape["handleElicitationComplete"];90 */
90 readonly handleUnknownExtRequest: EffectAcpClient.AcpClientShape["handleUnknownExtRequest"];91 readonly handleElicitation: EffectAcpClient.AcpClient["Service"]["handleElicitation"];
91 readonly handleUnknownExtNotification: EffectAcpClient.AcpClientShape["handleUnknownExtNotification"];92 /**
92 readonly handleExtRequest: EffectAcpClient.AcpClientShape["handleExtRequest"];93 * Registers a handler for `fs/read_text_file`.
93 readonly handleExtNotification: EffectAcpClient.AcpClientShape["handleExtNotification"];94 * @see https://agentclientprotocol.com/protocol/schema#fs/read_text_file
94 readonly start: () => Effect.Effect<AcpSessionRuntimeStartResult, EffectAcpErrors.AcpError>;95 */
95 readonly getEvents: () => Stream.Stream<AcpParsedSessionEvent, never>;96 readonly handleReadTextFile: EffectAcpClient.AcpClient["Service"]["handleReadTextFile"];
96 readonly getModeState: Effect.Effect<AcpSessionModeState | undefined>;97 /**
97 readonly getConfigOptions: Effect.Effect<ReadonlyArray<EffectAcpSchema.SessionConfigOption>>;98 * Registers a handler for `fs/write_text_file`.
98 readonly prompt: (99 * @see https://agentclientprotocol.com/protocol/schema#fs/write_text_file
99 payload: Omit<EffectAcpSchema.PromptRequest, "sessionId">,100 */
100 ) => Effect.Effect<EffectAcpSchema.PromptResponse, EffectAcpErrors.AcpError>;101 readonly handleWriteTextFile: EffectAcpClient.AcpClient["Service"]["handleWriteTextFile"];
101 readonly cancel: Effect.Effect<void, EffectAcpErrors.AcpError>;102 /**
102 readonly setMode: (103 * Registers a handler for `terminal/create`.
103 modeId: string,104 * @see https://agentclientprotocol.com/protocol/schema#terminal/create
104 ) => Effect.Effect<EffectAcpSchema.SetSessionModeResponse, EffectAcpErrors.AcpError>;105 */
105 readonly setConfigOption: (106 readonly handleCreateTerminal: EffectAcpClient.AcpClient["Service"]["handleCreateTerminal"];
106 configId: string,107 /**
107 value: string | boolean,108 * Registers a handler for `terminal/output`.
108 ) => Effect.Effect<EffectAcpSchema.SetSessionConfigOptionResponse, EffectAcpErrors.AcpError>;109 * @see https://agentclientprotocol.com/protocol/schema#terminal/output
109 readonly setModel: (model: string) => Effect.Effect<void, EffectAcpErrors.AcpError>;110 */
110 readonly setSessionModel: (111 readonly handleTerminalOutput: EffectAcpClient.AcpClient["Service"]["handleTerminalOutput"];
111 modelId: string,112 /**
112 ) => Effect.Effect<EffectAcpSchema.SetSessionModelResponse, EffectAcpErrors.AcpError>;113 * Registers a handler for `terminal/wait_for_exit`.
113 readonly request: (114 * @see https://agentclientprotocol.com/protocol/schema#terminal/wait_for_exit
114 method: string,115 */
115 payload: unknown,116 readonly handleTerminalWaitForExit: EffectAcpClient.AcpClient["Service"]["handleTerminalWaitForExit"];
116 ) => Effect.Effect<unknown, EffectAcpErrors.AcpError>;117 /**
117 readonly notify: (118 * Registers a handler for `terminal/kill`.
118 method: string,119 * @see https://agentclientprotocol.com/protocol/schema#terminal/kill
119 payload: unknown,120 */
120 ) => Effect.Effect<void, EffectAcpErrors.AcpError>;121 readonly handleTerminalKill: EffectAcpClient.AcpClient["Service"]["handleTerminalKill"];
121}122 /**
123 * Registers a handler for `terminal/release`.
124 * @see https://agentclientprotocol.com/protocol/schema#terminal/release
125 */
126 readonly handleTerminalRelease: EffectAcpClient.AcpClient["Service"]["handleTerminalRelease"];
127 /**
128 * Registers a handler for `session/update`.
129 * @see https://agentclientprotocol.com/protocol/schema#session/update
130 */
131 readonly handleSessionUpdate: EffectAcpClient.AcpClient["Service"]["handleSessionUpdate"];
132 /**
133 * Registers a handler for `session/elicitation/complete`.
134 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation/complete
135 */
136 readonly handleElicitationComplete: EffectAcpClient.AcpClient["Service"]["handleElicitationComplete"];
137 /**
138 * Registers a fallback extension request handler.
139 * @see https://agentclientprotocol.com/protocol/extensibility
140 */
141 readonly handleUnknownExtRequest: EffectAcpClient.AcpClient["Service"]["handleUnknownExtRequest"];
142 /**
143 * Registers a fallback extension notification handler.
144 * @see https://agentclientprotocol.com/protocol/extensibility
145 */
146 readonly handleUnknownExtNotification: EffectAcpClient.AcpClient["Service"]["handleUnknownExtNotification"];
147 /**
148 * Registers a typed extension request handler.
149 * @see https://agentclientprotocol.com/protocol/extensibility
150 */
151 readonly handleExtRequest: EffectAcpClient.AcpClient["Service"]["handleExtRequest"];
152 /**
153 * Registers a typed extension notification handler.
154 * @see https://agentclientprotocol.com/protocol/extensibility
155 */
156 readonly handleExtNotification: EffectAcpClient.AcpClient["Service"]["handleExtNotification"];
157 /**
158 * Initializes the ACP connection, authenticates, and loads, resumes, or creates the session.
159 * Concurrent calls share the same in-flight startup and a failed startup may be retried.
160 */
161 readonly start: () => Effect.Effect<AcpSessionRuntimeStartResult, EffectAcpErrors.AcpError>;
162 /** Stream of parsed ACP session events emitted after startup. */
163 readonly getEvents: () => Stream.Stream<AcpParsedSessionEvent, never>;
164 /** Latest mode state observed from session setup and `session/update` notifications. */
165 readonly getModeState: Effect.Effect<AcpSessionModeState | undefined>;
166 /** Latest configuration options observed from session setup and configuration writes. */
167 readonly getConfigOptions: Effect.Effect<ReadonlyArray<EffectAcpSchema.SessionConfigOption>>;
168 /**
169 * Sends a prompt turn to the active session.
170 * @see https://agentclientprotocol.com/protocol/schema#session/prompt
171 */
172 readonly prompt: (
173 payload: Omit<EffectAcpSchema.PromptRequest, "sessionId">,
174 ) => Effect.Effect<EffectAcpSchema.PromptResponse, EffectAcpErrors.AcpError>;
175 /**
176 * Sends a real ACP `session/cancel` notification for the active session.
177 * @see https://agentclientprotocol.com/protocol/schema#session/cancel
178 */
179 readonly cancel: Effect.Effect<void, EffectAcpErrors.AcpError>;
180 /**
181 * Selects the active mode through the negotiated `mode` configuration option.
182 * This is a no-op when the requested mode is already active.
183 * @see https://agentclientprotocol.com/protocol/schema#session/set_config_option
184 */
185 readonly setMode: (
186 modeId: string,
187 ) => Effect.Effect<EffectAcpSchema.SetSessionModeResponse, EffectAcpErrors.AcpError>;
188 /**
189 * Updates a session configuration option and the runtime configuration snapshot.
190 * @see https://agentclientprotocol.com/protocol/schema#session/set_config_option
191 */
192 readonly setConfigOption: (
193 configId: string,
194 value: string | boolean,
195 ) => Effect.Effect<EffectAcpSchema.SetSessionConfigOptionResponse, EffectAcpErrors.AcpError>;
196 /**
197 * Selects the base model through the negotiated model configuration option.
198 * @see https://agentclientprotocol.com/protocol/schema#session/set_config_option
199 */
200 readonly setModel: (model: string) => Effect.Effect<void, EffectAcpErrors.AcpError>;
201 /**
202 * Selects the active model through the unstable ACP `session/set_model` capability.
203 * @see https://agentclientprotocol.com/protocol/schema#session/set_model
204 */
205 readonly setSessionModel: (
206 modelId: string,
207 ) => Effect.Effect<EffectAcpSchema.SetSessionModelResponse, EffectAcpErrors.AcpError>;
208 /**
209 * Sends a generic ACP extension request and records it through the request logger.
210 * @see https://agentclientprotocol.com/protocol/extensibility
211 */
212 readonly request: (
213 method: string,
214 payload: unknown,
215 ) => Effect.Effect<unknown, EffectAcpErrors.AcpError>;
216 /**
217 * Sends a generic ACP extension notification.
218 * @see https://agentclientprotocol.com/protocol/extensibility
219 */
220 readonly notify: (
221 method: string,
222 payload: unknown,
223 ) => Effect.Effect<void, EffectAcpErrors.AcpError>;
224 }
225>()("t3/provider/acp/AcpSessionRuntime") {}
122226
123interface AcpStartedState extends AcpSessionRuntimeStartResult {}227interface AcpStartedState extends AcpSessionRuntimeStartResult {}
124228
...@@ -140,24 +244,10 @@ interface EnsureActiveAssistantSegmentResult {...@@ -140,24 +244,10 @@ interface EnsureActiveAssistantSegmentResult {
140 readonly startedEvent?: Extract<AcpParsedSessionEvent, { readonly _tag: "AssistantItemStarted" }>;244 readonly startedEvent?: Extract<AcpParsedSessionEvent, { readonly _tag: "AssistantItemStarted" }>;
141}245}
142246
143export class AcpSessionRuntime extends Context.Service<AcpSessionRuntime, AcpSessionRuntimeShape>()(247export const make = (
144 "t3/provider/acp/AcpSessionRuntime",
145) {
146 static layer(
147 options: AcpSessionRuntimeOptions,
148 ): Layer.Layer<
149 AcpSessionRuntime,
150 EffectAcpErrors.AcpError,
151 ChildProcessSpawner.ChildProcessSpawner
152 > {
153 return Layer.effect(AcpSessionRuntime, makeAcpSessionRuntime(options));
154 }
155}
156
157const makeAcpSessionRuntime = (
158 options: AcpSessionRuntimeOptions,248 options: AcpSessionRuntimeOptions,
159): Effect.Effect<249): Effect.Effect<
160 AcpSessionRuntimeShape,250 AcpSessionRuntime["Service"],
161 EffectAcpErrors.AcpError,251 EffectAcpErrors.AcpError,
162 ChildProcessSpawner.ChildProcessSpawner | Scope.Scope252 ChildProcessSpawner.ChildProcessSpawner | Scope.Scope
163> =>253> =>
...@@ -573,9 +663,17 @@ const makeAcpSessionRuntime = (...@@ -573,9 +663,17 @@ const makeAcpSessionRuntime = (
573 request: (method, payload) =>663 request: (method, payload) =>
574 runLoggedRequest(method, payload, acp.raw.request(method, payload)),664 runLoggedRequest(method, payload, acp.raw.request(method, payload)),
575 notify: acp.raw.notify,665 notify: acp.raw.notify,
576 } satisfies AcpSessionRuntimeShape;666 } satisfies AcpSessionRuntime["Service"];
577 });667 });
578668
669export const layer = (
670 options: AcpSessionRuntimeOptions,
671): Layer.Layer<
672 AcpSessionRuntime,
673 EffectAcpErrors.AcpError,
674 ChildProcessSpawner.ChildProcessSpawner
675> => Layer.effect(AcpSessionRuntime, make(options));
676
579function sessionConfigOptionsFromSetup(677function sessionConfigOptionsFromSetup(
580 response:678 response:
581 | {679 | {
apps/server/src/provider/acp/CursorAcpCliProbe.test.ts+4-4
...@@ -9,12 +9,12 @@ import * as Effect from "effect/Effect";...@@ -9,12 +9,12 @@ import * as Effect from "effect/Effect";
9import { describe, expect } from "vite-plus/test";9import { describe, expect } from "vite-plus/test";
10import type * as EffectAcpSchema from "effect-acp/schema";10import type * as EffectAcpSchema from "effect-acp/schema";
1111
12import { AcpSessionRuntime } from "./AcpSessionRuntime.ts";12import * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
1313
14describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe", () => {14describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe", () => {
15 it.effect("initialize and authenticate against real agent acp", () =>15 it.effect("initialize and authenticate against real agent acp", () =>
16 Effect.gen(function* () {16 Effect.gen(function* () {
17 const runtime = yield* AcpSessionRuntime;17 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
18 const started = yield* runtime.start();18 const started = yield* runtime.start();
19 expect(started.initializeResult).toBeDefined();19 expect(started.initializeResult).toBeDefined();
20 }).pipe(20 }).pipe(
...@@ -42,7 +42,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe",...@@ -42,7 +42,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe",
4242
43 it.effect("session/new returns configOptions with a model selector", () =>43 it.effect("session/new returns configOptions with a model selector", () =>
44 Effect.gen(function* () {44 Effect.gen(function* () {
45 const runtime = yield* AcpSessionRuntime;45 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
46 const started = yield* runtime.start();46 const started = yield* runtime.start();
47 const result = started.sessionSetupResult;47 const result = started.sessionSetupResult;
48 // @effect-diagnostics-next-line preferSchemaOverJson:off48 // @effect-diagnostics-next-line preferSchemaOverJson:off
...@@ -97,7 +97,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe",...@@ -97,7 +97,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe",
9797
98 it.effect("session/set_config_option switches the model in-session", () =>98 it.effect("session/set_config_option switches the model in-session", () =>
99 Effect.gen(function* () {99 Effect.gen(function* () {
100 const runtime = yield* AcpSessionRuntime;100 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
101 const started = yield* runtime.start();101 const started = yield* runtime.start();
102 const newResult = started.sessionSetupResult;102 const newResult = started.sessionSetupResult;
103103
apps/server/src/provider/acp/CursorAcpSupport.ts+13-12
...@@ -2,7 +2,7 @@ import { type CursorSettings, type ProviderOptionSelection } from "@t3tools/cont...@@ -2,7 +2,7 @@ import { type CursorSettings, type ProviderOptionSelection } from "@t3tools/cont
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";3import * as Layer from "effect/Layer";
4import * as Scope from "effect/Scope";4import * as Scope from "effect/Scope";
5import { ChildProcessSpawner } from "effect/unstable/process";5import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
6import type * as EffectAcpErrors from "effect-acp/errors";6import type * as EffectAcpErrors from "effect-acp/errors";
77
8import {8import {
...@@ -10,17 +10,12 @@ import {...@@ -10,17 +10,12 @@ import {
10 resolveCursorAcpBaseModelId,10 resolveCursorAcpBaseModelId,
11 resolveCursorAcpConfigUpdates,11 resolveCursorAcpConfigUpdates,
12} from "../Layers/CursorProvider.ts";12} from "../Layers/CursorProvider.ts";
13import {13import * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
14 AcpSessionRuntime,
15 type AcpSessionRuntimeOptions,
16 type AcpSessionRuntimeShape,
17 type AcpSpawnInput,
18} from "./AcpSessionRuntime.ts";
1914
20type CursorAcpRuntimeCursorSettings = Pick<CursorSettings, "apiEndpoint" | "binaryPath">;15type CursorAcpRuntimeCursorSettings = Pick<CursorSettings, "apiEndpoint" | "binaryPath">;
2116
22export interface CursorAcpRuntimeInput extends Omit<17export interface CursorAcpRuntimeInput extends Omit<
23 AcpSessionRuntimeOptions,18 AcpSessionRuntime.AcpSessionRuntimeOptions,
24 "authMethodId" | "clientCapabilities" | "spawn"19 "authMethodId" | "clientCapabilities" | "spawn"
25> {20> {
26 readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"];21 readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"];
...@@ -38,7 +33,7 @@ export function buildCursorAcpSpawnInput(...@@ -38,7 +33,7 @@ export function buildCursorAcpSpawnInput(
38 cursorSettings: CursorAcpRuntimeCursorSettings | null | undefined,33 cursorSettings: CursorAcpRuntimeCursorSettings | null | undefined,
39 cwd: string,34 cwd: string,
40 environment?: NodeJS.ProcessEnv,35 environment?: NodeJS.ProcessEnv,
41): AcpSpawnInput {36): AcpSessionRuntime.AcpSpawnInput {
42 return {37 return {
43 command: cursorSettings?.binaryPath || "agent",38 command: cursorSettings?.binaryPath || "agent",
44 args: [39 args: [
...@@ -52,7 +47,11 @@ export function buildCursorAcpSpawnInput(...@@ -52,7 +47,11 @@ export function buildCursorAcpSpawnInput(
5247
53export const makeCursorAcpRuntime = (48export const makeCursorAcpRuntime = (
54 input: CursorAcpRuntimeInput,49 input: CursorAcpRuntimeInput,
55): Effect.Effect<AcpSessionRuntimeShape, EffectAcpErrors.AcpError, Scope.Scope> =>50): Effect.Effect<
51 AcpSessionRuntime.AcpSessionRuntime["Service"],
52 EffectAcpErrors.AcpError,
53 Scope.Scope
54> =>
56 Effect.gen(function* () {55 Effect.gen(function* () {
57 const acpContext = yield* Layer.build(56 const acpContext = yield* Layer.build(
58 AcpSessionRuntime.layer({57 AcpSessionRuntime.layer({
...@@ -66,11 +65,13 @@ export const makeCursorAcpRuntime = (...@@ -66,11 +65,13 @@ export const makeCursorAcpRuntime = (
66 ),65 ),
67 ),66 ),
68 );67 );
69 return yield* Effect.service(AcpSessionRuntime).pipe(Effect.provide(acpContext));68 return yield* Effect.service(AcpSessionRuntime.AcpSessionRuntime).pipe(
69 Effect.provide(acpContext),
70 );
70 });71 });
7172
72interface CursorAcpModelSelectionRuntime {73interface CursorAcpModelSelectionRuntime {
73 readonly getConfigOptions: AcpSessionRuntimeShape["getConfigOptions"];74 readonly getConfigOptions: AcpSessionRuntime.AcpSessionRuntime["Service"]["getConfigOptions"];
74 readonly setConfigOption: (75 readonly setConfigOption: (
75 configId: string,76 configId: string,
76 value: string | boolean,77 value: string | boolean,
apps/server/src/provider/acp/GrokAcpSupport.ts+13-12
...@@ -2,17 +2,12 @@ import { type GrokSettings, ProviderDriverKind } from "@t3tools/contracts";...@@ -2,17 +2,12 @@ import { type GrokSettings, ProviderDriverKind } from "@t3tools/contracts";
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";3import * as Layer from "effect/Layer";
4import * as Scope from "effect/Scope";4import * as Scope from "effect/Scope";
5import { ChildProcessSpawner } from "effect/unstable/process";5import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
6import * as EffectAcpErrors from "effect-acp/errors";6import * as EffectAcpErrors from "effect-acp/errors";
7import type * as EffectAcpSchema from "effect-acp/schema";7import type * as EffectAcpSchema from "effect-acp/schema";
8import { normalizeModelSlug } from "@t3tools/shared/model";8import { normalizeModelSlug } from "@t3tools/shared/model";
99
10import {10import * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
11 AcpSessionRuntime,
12 type AcpSessionRuntimeOptions,
13 type AcpSessionRuntimeShape,
14 type AcpSpawnInput,
15} from "./AcpSessionRuntime.ts";
1611
17const GROK_API_KEY_ENV = "XAI_API_KEY";12const GROK_API_KEY_ENV = "XAI_API_KEY";
18const GROK_OAUTH2_REFERRER_ENV = "GROK_OAUTH2_REFERRER";13const GROK_OAUTH2_REFERRER_ENV = "GROK_OAUTH2_REFERRER";
...@@ -24,7 +19,7 @@ const GROK_DRIVER_KIND = ProviderDriverKind.make("grok");...@@ -24,7 +19,7 @@ const GROK_DRIVER_KIND = ProviderDriverKind.make("grok");
24type GrokAcpRuntimeGrokSettings = Pick<GrokSettings, "binaryPath">;19type GrokAcpRuntimeGrokSettings = Pick<GrokSettings, "binaryPath">;
2520
26interface GrokAcpRuntimeInput extends Omit<21interface GrokAcpRuntimeInput extends Omit<
27 AcpSessionRuntimeOptions,22 AcpSessionRuntime.AcpSessionRuntimeOptions,
28 "authMethodId" | "clientCapabilities" | "spawn"23 "authMethodId" | "clientCapabilities" | "spawn"
29> {24> {
30 readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"];25 readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"];
...@@ -36,7 +31,7 @@ export function buildGrokAcpSpawnInput(...@@ -36,7 +31,7 @@ export function buildGrokAcpSpawnInput(
36 grokSettings: GrokAcpRuntimeGrokSettings | null | undefined,31 grokSettings: GrokAcpRuntimeGrokSettings | null | undefined,
37 cwd: string,32 cwd: string,
38 environment?: NodeJS.ProcessEnv,33 environment?: NodeJS.ProcessEnv,
39): AcpSpawnInput {34): AcpSessionRuntime.AcpSpawnInput {
40 return {35 return {
41 command: grokSettings?.binaryPath || "grok",36 command: grokSettings?.binaryPath || "grok",
42 args: ["agent", "stdio"],37 args: ["agent", "stdio"],
...@@ -56,7 +51,11 @@ function resolveGrokAuthMethodId(environment: NodeJS.ProcessEnv | undefined): st...@@ -56,7 +51,11 @@ function resolveGrokAuthMethodId(environment: NodeJS.ProcessEnv | undefined): st
5651
57export const makeGrokAcpRuntime = (52export const makeGrokAcpRuntime = (
58 input: GrokAcpRuntimeInput,53 input: GrokAcpRuntimeInput,
59): Effect.Effect<AcpSessionRuntimeShape, EffectAcpErrors.AcpError, Scope.Scope> =>54): Effect.Effect<
55 AcpSessionRuntime.AcpSessionRuntime["Service"],
56 EffectAcpErrors.AcpError,
57 Scope.Scope
58> =>
60 Effect.gen(function* () {59 Effect.gen(function* () {
61 const acpContext = yield* Layer.build(60 const acpContext = yield* Layer.build(
62 AcpSessionRuntime.layer({61 AcpSessionRuntime.layer({
...@@ -69,7 +68,9 @@ export const makeGrokAcpRuntime = (...@@ -69,7 +68,9 @@ export const makeGrokAcpRuntime = (
69 ),68 ),
70 ),69 ),
71 );70 );
72 return yield* Effect.service(AcpSessionRuntime).pipe(Effect.provide(acpContext));71 return yield* Effect.service(AcpSessionRuntime.AcpSessionRuntime).pipe(
72 Effect.provide(acpContext),
73 );
73 });74 });
7475
75export function resolveGrokAcpBaseModelId(model: string | null | undefined): string {76export function resolveGrokAcpBaseModelId(model: string | null | undefined): string {
...@@ -88,7 +89,7 @@ export function currentGrokModelIdFromSessionSetup(...@@ -88,7 +89,7 @@ export function currentGrokModelIdFromSessionSetup(
88}89}
8990
90export function applyGrokAcpModelSelection<E>(input: {91export function applyGrokAcpModelSelection<E>(input: {
91 readonly runtime: Pick<AcpSessionRuntimeShape, "setSessionModel">;92 readonly runtime: Pick<AcpSessionRuntime.AcpSessionRuntime["Service"], "setSessionModel">;
92 readonly currentModelId: string | undefined;93 readonly currentModelId: string | undefined;
93 readonly requestedModelId: string | undefined;94 readonly requestedModelId: string | undefined;
94 readonly mapError: (cause: EffectAcpErrors.AcpError) => E;95 readonly mapError: (cause: EffectAcpErrors.AcpError) => E;
packages/effect-acp/src/agent.ts+177-176
...@@ -27,189 +27,190 @@ export interface AcpAgentOptions {...@@ -27,189 +27,190 @@ export interface AcpAgentOptions {
27 readonly logger?: (event: AcpProtocol.AcpProtocolLogEvent) => Effect.Effect<void, never>;27 readonly logger?: (event: AcpProtocol.AcpProtocolLogEvent) => Effect.Effect<void, never>;
28}28}
2929
30export interface AcpAgentShape {30export class AcpAgent extends Context.Service<
31 readonly raw: {31 AcpAgent,
32 {
33 readonly raw: {
34 /**
35 * Stream of inbound ACP notifications observed on the connection.
36 */
37 readonly notifications: Stream.Stream<AcpProtocol.AcpIncomingNotification>;
38 /**
39 * Sends a generic ACP extension request.
40 * @see https://agentclientprotocol.com/protocol/extensibility
41 */
42 readonly request: (
43 method: string,
44 payload: unknown,
45 ) => Effect.Effect<unknown, AcpError.AcpError>;
46 /**
47 * Sends a generic ACP extension notification.
48 * @see https://agentclientprotocol.com/protocol/extensibility
49 */
50 readonly notify: (method: string, payload: unknown) => Effect.Effect<void, AcpError.AcpError>;
51 };
52 readonly client: {
53 /**
54 * Requests client permission for an operation.
55 * @see https://agentclientprotocol.com/protocol/schema#session/request_permission
56 */
57 readonly requestPermission: (
58 payload: AcpSchema.RequestPermissionRequest,
59 ) => Effect.Effect<AcpSchema.RequestPermissionResponse, AcpError.AcpError>;
60 /**
61 * Requests structured user input from the client.
62 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation
63 */
64 readonly elicit: (
65 payload: AcpSchema.ElicitationRequest,
66 ) => Effect.Effect<AcpSchema.ElicitationResponse, AcpError.AcpError>;
67 /**
68 * Requests file contents from the client.
69 * @see https://agentclientprotocol.com/protocol/schema#fs/read_text_file
70 */
71 readonly readTextFile: (
72 payload: AcpSchema.ReadTextFileRequest,
73 ) => Effect.Effect<AcpSchema.ReadTextFileResponse, AcpError.AcpError>;
74 /**
75 * Writes a text file through the client.
76 * @see https://agentclientprotocol.com/protocol/schema#fs/write_text_file
77 */
78 readonly writeTextFile: (
79 payload: AcpSchema.WriteTextFileRequest,
80 ) => Effect.Effect<AcpSchema.WriteTextFileResponse, AcpError.AcpError>;
81 /**
82 * Creates a terminal on the client side.
83 * @see https://agentclientprotocol.com/protocol/schema#terminal/create
84 */
85 readonly createTerminal: (
86 payload: AcpSchema.CreateTerminalRequest,
87 ) => Effect.Effect<AcpTerminal.AcpTerminal, AcpError.AcpError>;
88 /**
89 * Sends a `session/update` notification to the client.
90 * @see https://agentclientprotocol.com/protocol/schema#session/update
91 */
92 readonly sessionUpdate: (
93 payload: AcpSchema.SessionNotification,
94 ) => Effect.Effect<void, AcpError.AcpError>;
95 /**
96 * Sends a `session/elicitation/complete` notification to the client.
97 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation/complete
98 */
99 readonly elicitationComplete: (
100 payload: AcpSchema.ElicitationCompleteNotification,
101 ) => Effect.Effect<void, AcpError.AcpError>;
102 /**
103 * Sends an ACP extension request to the client.
104 * @see https://agentclientprotocol.com/protocol/extensibility
105 */
106 readonly extRequest: (
107 method: string,
108 payload: unknown,
109 ) => Effect.Effect<unknown, AcpError.AcpError>;
110 /**
111 * Sends an ACP extension notification to the client.
112 * @see https://agentclientprotocol.com/protocol/extensibility
113 */
114 readonly extNotification: (
115 method: string,
116 payload: unknown,
117 ) => Effect.Effect<void, AcpError.AcpError>;
118 };
32 /**119 /**
33 * Stream of inbound ACP notifications observed on the connection.120 * Registers a handler for `initialize`.
121 * @see https://agentclientprotocol.com/protocol/schema#initialize
34 */122 */
35 readonly notifications: Stream.Stream<AcpProtocol.AcpIncomingNotification>;123 readonly handleInitialize: (
124 handler: (
125 request: AcpSchema.InitializeRequest,
126 ) => Effect.Effect<AcpSchema.InitializeResponse, AcpError.AcpError>,
127 ) => Effect.Effect<void>;
36 /**128 /**
37 * Sends a generic ACP extension request.129 * Registers a handler for `authenticate`.
38 * @see https://agentclientprotocol.com/protocol/extensibility130 * @see https://agentclientprotocol.com/protocol/schema#authenticate
39 */131 */
40 readonly request: (132 readonly handleAuthenticate: (
41 method: string,133 handler: (
42 payload: unknown,134 request: AcpSchema.AuthenticateRequest,
43 ) => Effect.Effect<unknown, AcpError.AcpError>;135 ) => Effect.Effect<AcpSchema.AuthenticateResponse, AcpError.AcpError>,
44 /**136 ) => Effect.Effect<void>;
45 * Sends a generic ACP extension notification.137 readonly handleLogout: (
46 * @see https://agentclientprotocol.com/protocol/extensibility138 handler: (
47 */139 request: AcpSchema.LogoutRequest,
48 readonly notify: (method: string, payload: unknown) => Effect.Effect<void, AcpError.AcpError>;140 ) => Effect.Effect<AcpSchema.LogoutResponse, AcpError.AcpError>,
49 };141 ) => Effect.Effect<void>;
50 readonly client: {142 readonly handleCreateSession: (
51 /**143 handler: (
52 * Requests client permission for an operation.144 request: AcpSchema.NewSessionRequest,
53 * @see https://agentclientprotocol.com/protocol/schema#session/request_permission145 ) => Effect.Effect<AcpSchema.NewSessionResponse, AcpError.AcpError>,
54 */146 ) => Effect.Effect<void>;
55 readonly requestPermission: (147 readonly handleLoadSession: (
56 payload: AcpSchema.RequestPermissionRequest,148 handler: (
57 ) => Effect.Effect<AcpSchema.RequestPermissionResponse, AcpError.AcpError>;149 request: AcpSchema.LoadSessionRequest,
58 /**150 ) => Effect.Effect<AcpSchema.LoadSessionResponse, AcpError.AcpError>,
59 * Requests structured user input from the client.151 ) => Effect.Effect<void>;
60 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation152 readonly handleListSessions: (
61 */153 handler: (
62 readonly elicit: (154 request: AcpSchema.ListSessionsRequest,
63 payload: AcpSchema.ElicitationRequest,155 ) => Effect.Effect<AcpSchema.ListSessionsResponse, AcpError.AcpError>,
64 ) => Effect.Effect<AcpSchema.ElicitationResponse, AcpError.AcpError>;156 ) => Effect.Effect<void>;
65 /**157 readonly handleForkSession: (
66 * Requests file contents from the client.158 handler: (
67 * @see https://agentclientprotocol.com/protocol/schema#fs/read_text_file159 request: AcpSchema.ForkSessionRequest,
68 */160 ) => Effect.Effect<AcpSchema.ForkSessionResponse, AcpError.AcpError>,
69 readonly readTextFile: (161 ) => Effect.Effect<void>;
70 payload: AcpSchema.ReadTextFileRequest,162 readonly handleResumeSession: (
71 ) => Effect.Effect<AcpSchema.ReadTextFileResponse, AcpError.AcpError>;163 handler: (
72 /**164 request: AcpSchema.ResumeSessionRequest,
73 * Writes a text file through the client.165 ) => Effect.Effect<AcpSchema.ResumeSessionResponse, AcpError.AcpError>,
74 * @see https://agentclientprotocol.com/protocol/schema#fs/write_text_file166 ) => Effect.Effect<void>;
75 */167 readonly handleCloseSession: (
76 readonly writeTextFile: (168 handler: (
77 payload: AcpSchema.WriteTextFileRequest,169 request: AcpSchema.CloseSessionRequest,
78 ) => Effect.Effect<AcpSchema.WriteTextFileResponse, AcpError.AcpError>;170 ) => Effect.Effect<AcpSchema.CloseSessionResponse, AcpError.AcpError>,
171 ) => Effect.Effect<void>;
172 readonly handleSetSessionModel: (
173 handler: (
174 request: AcpSchema.SetSessionModelRequest,
175 ) => Effect.Effect<AcpSchema.SetSessionModelResponse, AcpError.AcpError>,
176 ) => Effect.Effect<void>;
177 readonly handleSetSessionConfigOption: (
178 handler: (
179 request: AcpSchema.SetSessionConfigOptionRequest,
180 ) => Effect.Effect<AcpSchema.SetSessionConfigOptionResponse, AcpError.AcpError>,
181 ) => Effect.Effect<void>;
182 readonly handlePrompt: (
183 handler: (
184 request: AcpSchema.PromptRequest,
185 ) => Effect.Effect<AcpSchema.PromptResponse, AcpError.AcpError>,
186 ) => Effect.Effect<void>;
79 /**187 /**
80 * Creates a terminal on the client side.188 * Registers a handler for `session/cancel`.
81 * @see https://agentclientprotocol.com/protocol/schema#terminal/create189 * @see https://agentclientprotocol.com/protocol/schema#session/cancel
82 */190 */
83 readonly createTerminal: (191 readonly handleCancel: (
84 payload: AcpSchema.CreateTerminalRequest,192 handler: (
85 ) => Effect.Effect<AcpTerminal.AcpTerminal, AcpError.AcpError>;193 notification: AcpSchema.CancelNotification,
86 /**194 ) => Effect.Effect<void, AcpError.AcpError>,
87 * Sends a `session/update` notification to the client.195 ) => Effect.Effect<void>;
88 * @see https://agentclientprotocol.com/protocol/schema#session/update196 readonly handleUnknownExtRequest: (
89 */197 handler: (method: string, params: unknown) => Effect.Effect<unknown, AcpError.AcpError>,
90 readonly sessionUpdate: (198 ) => Effect.Effect<void>;
91 payload: AcpSchema.SessionNotification,199 readonly handleUnknownExtNotification: (
92 ) => Effect.Effect<void, AcpError.AcpError>;200 handler: (method: string, params: unknown) => Effect.Effect<void, AcpError.AcpError>,
93 /**201 ) => Effect.Effect<void>;
94 * Sends a `session/elicitation/complete` notification to the client.202 readonly handleExtRequest: <A, I>(
95 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation/complete
96 */
97 readonly elicitationComplete: (
98 payload: AcpSchema.ElicitationCompleteNotification,
99 ) => Effect.Effect<void, AcpError.AcpError>;
100 /**
101 * Sends an ACP extension request to the client.
102 * @see https://agentclientprotocol.com/protocol/extensibility
103 */
104 readonly extRequest: (
105 method: string,203 method: string,
106 payload: unknown,204 payload: Schema.Codec<A, I>,
107 ) => Effect.Effect<unknown, AcpError.AcpError>;205 handler: (payload: A) => Effect.Effect<unknown, AcpError.AcpError>,
108 /**206 ) => Effect.Effect<void>;
109 * Sends an ACP extension notification to the client.207 readonly handleExtNotification: <A, I>(
110 * @see https://agentclientprotocol.com/protocol/extensibility
111 */
112 readonly extNotification: (
113 method: string,208 method: string,
114 payload: unknown,209 payload: Schema.Codec<A, I>,
115 ) => Effect.Effect<void, AcpError.AcpError>;210 handler: (payload: A) => Effect.Effect<void, AcpError.AcpError>,
116 };211 ) => Effect.Effect<void>;
117 /**212 }
118 * Registers a handler for `initialize`.213>()("effect-acp/agent/AcpAgent") {}
119 * @see https://agentclientprotocol.com/protocol/schema#initialize
120 */
121 readonly handleInitialize: (
122 handler: (
123 request: AcpSchema.InitializeRequest,
124 ) => Effect.Effect<AcpSchema.InitializeResponse, AcpError.AcpError>,
125 ) => Effect.Effect<void>;
126 /**
127 * Registers a handler for `authenticate`.
128 * @see https://agentclientprotocol.com/protocol/schema#authenticate
129 */
130 readonly handleAuthenticate: (
131 handler: (
132 request: AcpSchema.AuthenticateRequest,
133 ) => Effect.Effect<AcpSchema.AuthenticateResponse, AcpError.AcpError>,
134 ) => Effect.Effect<void>;
135 readonly handleLogout: (
136 handler: (
137 request: AcpSchema.LogoutRequest,
138 ) => Effect.Effect<AcpSchema.LogoutResponse, AcpError.AcpError>,
139 ) => Effect.Effect<void>;
140 readonly handleCreateSession: (
141 handler: (
142 request: AcpSchema.NewSessionRequest,
143 ) => Effect.Effect<AcpSchema.NewSessionResponse, AcpError.AcpError>,
144 ) => Effect.Effect<void>;
145 readonly handleLoadSession: (
146 handler: (
147 request: AcpSchema.LoadSessionRequest,
148 ) => Effect.Effect<AcpSchema.LoadSessionResponse, AcpError.AcpError>,
149 ) => Effect.Effect<void>;
150 readonly handleListSessions: (
151 handler: (
152 request: AcpSchema.ListSessionsRequest,
153 ) => Effect.Effect<AcpSchema.ListSessionsResponse, AcpError.AcpError>,
154 ) => Effect.Effect<void>;
155 readonly handleForkSession: (
156 handler: (
157 request: AcpSchema.ForkSessionRequest,
158 ) => Effect.Effect<AcpSchema.ForkSessionResponse, AcpError.AcpError>,
159 ) => Effect.Effect<void>;
160 readonly handleResumeSession: (
161 handler: (
162 request: AcpSchema.ResumeSessionRequest,
163 ) => Effect.Effect<AcpSchema.ResumeSessionResponse, AcpError.AcpError>,
164 ) => Effect.Effect<void>;
165 readonly handleCloseSession: (
166 handler: (
167 request: AcpSchema.CloseSessionRequest,
168 ) => Effect.Effect<AcpSchema.CloseSessionResponse, AcpError.AcpError>,
169 ) => Effect.Effect<void>;
170 readonly handleSetSessionModel: (
171 handler: (
172 request: AcpSchema.SetSessionModelRequest,
173 ) => Effect.Effect<AcpSchema.SetSessionModelResponse, AcpError.AcpError>,
174 ) => Effect.Effect<void>;
175 readonly handleSetSessionConfigOption: (
176 handler: (
177 request: AcpSchema.SetSessionConfigOptionRequest,
178 ) => Effect.Effect<AcpSchema.SetSessionConfigOptionResponse, AcpError.AcpError>,
179 ) => Effect.Effect<void>;
180 readonly handlePrompt: (
181 handler: (
182 request: AcpSchema.PromptRequest,
183 ) => Effect.Effect<AcpSchema.PromptResponse, AcpError.AcpError>,
184 ) => Effect.Effect<void>;
185 /**
186 * Registers a handler for `session/cancel`.
187 * @see https://agentclientprotocol.com/protocol/schema#session/cancel
188 */
189 readonly handleCancel: (
190 handler: (notification: AcpSchema.CancelNotification) => Effect.Effect<void, AcpError.AcpError>,
191 ) => Effect.Effect<void>;
192 readonly handleUnknownExtRequest: (
193 handler: (method: string, params: unknown) => Effect.Effect<unknown, AcpError.AcpError>,
194 ) => Effect.Effect<void>;
195 readonly handleUnknownExtNotification: (
196 handler: (method: string, params: unknown) => Effect.Effect<void, AcpError.AcpError>,
197 ) => Effect.Effect<void>;
198 readonly handleExtRequest: <A, I>(
199 method: string,
200 payload: Schema.Codec<A, I>,
201 handler: (payload: A) => Effect.Effect<unknown, AcpError.AcpError>,
202 ) => Effect.Effect<void>;
203 readonly handleExtNotification: <A, I>(
204 method: string,
205 payload: Schema.Codec<A, I>,
206 handler: (payload: A) => Effect.Effect<void, AcpError.AcpError>,
207 ) => Effect.Effect<void>;
208}
209
210export class AcpAgent extends Context.Service<AcpAgent, AcpAgentShape>()(
211 "effect-acp/agent/AcpAgent",
212) {}
213214
214interface AcpCoreAgentRequestHandlers {215interface AcpCoreAgentRequestHandlers {
215 initialize?: (216 initialize?: (
...@@ -255,7 +256,7 @@ const decodeCancelNotification = Schema.decodeUnknownEffect(AcpSchema.CancelNoti...@@ -255,7 +256,7 @@ const decodeCancelNotification = Schema.decodeUnknownEffect(AcpSchema.CancelNoti
255export const make = Effect.fn("effect-acp/AcpAgent.make")(function* (256export const make = Effect.fn("effect-acp/AcpAgent.make")(function* (
256 stdio: Stdio.Stdio,257 stdio: Stdio.Stdio,
257 options: AcpAgentOptions = {},258 options: AcpAgentOptions = {},
258): Effect.fn.Return<AcpAgentShape, never, Scope.Scope> {259): Effect.fn.Return<AcpAgent["Service"], never, Scope.Scope> {
259 const coreHandlers: AcpCoreAgentRequestHandlers = {};260 const coreHandlers: AcpCoreAgentRequestHandlers = {};
260 const cancelHandlers: Array<261 const cancelHandlers: Array<
261 (notification: AcpSchema.CancelNotification) => Effect.Effect<void, AcpError.AcpError>262 (notification: AcpSchema.CancelNotification) => Effect.Effect<void, AcpError.AcpError>
packages/effect-acp/src/client.ts+209-207
...@@ -7,7 +7,7 @@ import * as Scope from "effect/Scope";...@@ -7,7 +7,7 @@ import * as Scope from "effect/Scope";
7import * as Stream from "effect/Stream";7import * as Stream from "effect/Stream";
8import * as RpcClient from "effect/unstable/rpc/RpcClient";8import * as RpcClient from "effect/unstable/rpc/RpcClient";
9import * as RpcServer from "effect/unstable/rpc/RpcServer";9import * as RpcServer from "effect/unstable/rpc/RpcServer";
10import { ChildProcessSpawner } from "effect/unstable/process";10import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
1111
12import * as AcpError from "./errors.ts";12import * as AcpError from "./errors.ts";
13import * as AcpProtocol from "./protocol.ts";13import * as AcpProtocol from "./protocol.ts";
...@@ -34,237 +34,236 @@ type AcpClientRaw = {...@@ -34,237 +34,236 @@ type AcpClientRaw = {
34 readonly notify: (method: string, payload: unknown) => Effect.Effect<void, AcpError.AcpError>;34 readonly notify: (method: string, payload: unknown) => Effect.Effect<void, AcpError.AcpError>;
35};35};
3636
37export interface AcpClientShape {37export class AcpClient extends Context.Service<
38 readonly raw: AcpClientRaw;38 AcpClient,
39 readonly agent: {39 {
40 readonly raw: AcpClientRaw;
41 readonly agent: {
42 /**
43 * Initializes the ACP session and negotiates capabilities.
44 * @see https://agentclientprotocol.com/protocol/schema#initialize
45 */
46 readonly initialize: (
47 payload: AcpSchema.InitializeRequest,
48 ) => Effect.Effect<AcpSchema.InitializeResponse, AcpError.AcpError>;
49 /**
50 * Performs ACP authentication when the agent requires it.
51 * @see https://agentclientprotocol.com/protocol/schema#authenticate
52 */
53 readonly authenticate: (
54 payload: AcpSchema.AuthenticateRequest,
55 ) => Effect.Effect<AcpSchema.AuthenticateResponse, AcpError.AcpError>;
56 /**
57 * Logs out the current ACP identity.
58 * @see https://agentclientprotocol.com/protocol/schema#logout
59 */
60 readonly logout: (
61 payload: AcpSchema.LogoutRequest,
62 ) => Effect.Effect<AcpSchema.LogoutResponse, AcpError.AcpError>;
63 /**
64 * Starts a new ACP session.
65 * @see https://agentclientprotocol.com/protocol/schema#session/new
66 */
67 readonly createSession: (
68 payload: AcpSchema.NewSessionRequest,
69 ) => Effect.Effect<AcpSchema.NewSessionResponse, AcpError.AcpError>;
70 /**
71 * Loads a previously saved ACP session.
72 * @see https://agentclientprotocol.com/protocol/schema#session/load
73 */
74 readonly loadSession: (
75 payload: AcpSchema.LoadSessionRequest,
76 ) => Effect.Effect<AcpSchema.LoadSessionResponse, AcpError.AcpError>;
77 /**
78 * Lists available ACP sessions.
79 * @see https://agentclientprotocol.com/protocol/schema#session/list
80 */
81 readonly listSessions: (
82 payload: AcpSchema.ListSessionsRequest,
83 ) => Effect.Effect<AcpSchema.ListSessionsResponse, AcpError.AcpError>;
84 /**
85 * Forks an ACP session.
86 * @see https://agentclientprotocol.com/protocol/schema#session/fork
87 */
88 readonly forkSession: (
89 payload: AcpSchema.ForkSessionRequest,
90 ) => Effect.Effect<AcpSchema.ForkSessionResponse, AcpError.AcpError>;
91 /**
92 * Resumes an ACP session.
93 * @see https://agentclientprotocol.com/protocol/schema#session/resume
94 */
95 readonly resumeSession: (
96 payload: AcpSchema.ResumeSessionRequest,
97 ) => Effect.Effect<AcpSchema.ResumeSessionResponse, AcpError.AcpError>;
98 /**
99 * Closes an ACP session.
100 * @see https://agentclientprotocol.com/protocol/schema#session/close
101 */
102 readonly closeSession: (
103 payload: AcpSchema.CloseSessionRequest,
104 ) => Effect.Effect<AcpSchema.CloseSessionResponse, AcpError.AcpError>;
105 /**
106 * Selects the active model for a session.
107 * @see https://agentclientprotocol.com/protocol/schema#session/set_model
108 */
109 readonly setSessionModel: (
110 payload: AcpSchema.SetSessionModelRequest,
111 ) => Effect.Effect<AcpSchema.SetSessionModelResponse, AcpError.AcpError>;
112 /**
113 * Updates a session configuration option.
114 * @see https://agentclientprotocol.com/protocol/schema#session/set_config_option
115 */
116 readonly setSessionConfigOption: (
117 payload: AcpSchema.SetSessionConfigOptionRequest,
118 ) => Effect.Effect<AcpSchema.SetSessionConfigOptionResponse, AcpError.AcpError>;
119 /**
120 * Sends a prompt turn to the agent.
121 * @see https://agentclientprotocol.com/protocol/schema#session/prompt
122 */
123 readonly prompt: (
124 payload: AcpSchema.PromptRequest,
125 ) => Effect.Effect<AcpSchema.PromptResponse, AcpError.AcpError>;
126 /**
127 * Sends a real ACP `session/cancel` notification.
128 * @see https://agentclientprotocol.com/protocol/schema#session/cancel
129 */
130 readonly cancel: (
131 payload: AcpSchema.CancelNotification,
132 ) => Effect.Effect<void, AcpError.AcpError>;
133 };
40 /**134 /**
41 * Initializes the ACP session and negotiates capabilities.135 * Registers a handler for `session/request_permission`.
42 * @see https://agentclientprotocol.com/protocol/schema#initialize136 * @see https://agentclientprotocol.com/protocol/schema#session/request_permission
43 */137 */
44 readonly initialize: (138 readonly handleRequestPermission: (
45 payload: AcpSchema.InitializeRequest,139 handler: (
46 ) => Effect.Effect<AcpSchema.InitializeResponse, AcpError.AcpError>;140 request: AcpSchema.RequestPermissionRequest,
141 ) => Effect.Effect<AcpSchema.RequestPermissionResponse, AcpError.AcpError>,
142 ) => Effect.Effect<void>;
47 /**143 /**
48 * Performs ACP authentication when the agent requires it.144 * Registers a handler for `session/elicitation`.
49 * @see https://agentclientprotocol.com/protocol/schema#authenticate145 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation
50 */146 */
51 readonly authenticate: (147 readonly handleElicitation: (
52 payload: AcpSchema.AuthenticateRequest,148 handler: (
53 ) => Effect.Effect<AcpSchema.AuthenticateResponse, AcpError.AcpError>;149 request: AcpSchema.ElicitationRequest,
150 ) => Effect.Effect<AcpSchema.ElicitationResponse, AcpError.AcpError>,
151 ) => Effect.Effect<void>;
54 /**152 /**
55 * Logs out the current ACP identity.153 * Registers a handler for `fs/read_text_file`.
56 * @see https://agentclientprotocol.com/protocol/schema#logout154 * @see https://agentclientprotocol.com/protocol/schema#fs/read_text_file
57 */155 */
58 readonly logout: (156 readonly handleReadTextFile: (
59 payload: AcpSchema.LogoutRequest,157 handler: (
60 ) => Effect.Effect<AcpSchema.LogoutResponse, AcpError.AcpError>;158 request: AcpSchema.ReadTextFileRequest,
159 ) => Effect.Effect<AcpSchema.ReadTextFileResponse, AcpError.AcpError>,
160 ) => Effect.Effect<void>;
61 /**161 /**
62 * Starts a new ACP session.162 * Registers a handler for `fs/write_text_file`.
63 * @see https://agentclientprotocol.com/protocol/schema#session/new163 * @see https://agentclientprotocol.com/protocol/schema#fs/write_text_file
64 */164 */
65 readonly createSession: (165 readonly handleWriteTextFile: (
66 payload: AcpSchema.NewSessionRequest,166 handler: (
67 ) => Effect.Effect<AcpSchema.NewSessionResponse, AcpError.AcpError>;167 request: AcpSchema.WriteTextFileRequest,
168 ) => Effect.Effect<AcpSchema.WriteTextFileResponse | void, AcpError.AcpError>,
169 ) => Effect.Effect<void>;
68 /**170 /**
69 * Loads a previously saved ACP session.171 * Registers a handler for `terminal/create`.
70 * @see https://agentclientprotocol.com/protocol/schema#session/load172 * @see https://agentclientprotocol.com/protocol/schema#terminal/create
71 */173 */
72 readonly loadSession: (174 readonly handleCreateTerminal: (
73 payload: AcpSchema.LoadSessionRequest,175 handler: (
74 ) => Effect.Effect<AcpSchema.LoadSessionResponse, AcpError.AcpError>;176 request: AcpSchema.CreateTerminalRequest,
177 ) => Effect.Effect<AcpSchema.CreateTerminalResponse, AcpError.AcpError>,
178 ) => Effect.Effect<void>;
75 /**179 /**
76 * Lists available ACP sessions.180 * Registers a handler for `terminal/output`.
77 * @see https://agentclientprotocol.com/protocol/schema#session/list181 * @see https://agentclientprotocol.com/protocol/schema#terminal/output
78 */182 */
79 readonly listSessions: (183 readonly handleTerminalOutput: (
80 payload: AcpSchema.ListSessionsRequest,184 handler: (
81 ) => Effect.Effect<AcpSchema.ListSessionsResponse, AcpError.AcpError>;185 request: AcpSchema.TerminalOutputRequest,
186 ) => Effect.Effect<AcpSchema.TerminalOutputResponse, AcpError.AcpError>,
187 ) => Effect.Effect<void>;
82 /**188 /**
83 * Forks an ACP session.189 * Registers a handler for `terminal/wait_for_exit`.
84 * @see https://agentclientprotocol.com/protocol/schema#session/fork190 * @see https://agentclientprotocol.com/protocol/schema#terminal/wait_for_exit
85 */191 */
86 readonly forkSession: (192 readonly handleTerminalWaitForExit: (
87 payload: AcpSchema.ForkSessionRequest,193 handler: (
88 ) => Effect.Effect<AcpSchema.ForkSessionResponse, AcpError.AcpError>;194 request: AcpSchema.WaitForTerminalExitRequest,
195 ) => Effect.Effect<AcpSchema.WaitForTerminalExitResponse, AcpError.AcpError>,
196 ) => Effect.Effect<void>;
89 /**197 /**
90 * Resumes an ACP session.198 * Registers a handler for `terminal/kill`.
91 * @see https://agentclientprotocol.com/protocol/schema#session/resume199 * @see https://agentclientprotocol.com/protocol/schema#terminal/kill
92 */200 */
93 readonly resumeSession: (201 readonly handleTerminalKill: (
94 payload: AcpSchema.ResumeSessionRequest,202 handler: (
95 ) => Effect.Effect<AcpSchema.ResumeSessionResponse, AcpError.AcpError>;203 request: AcpSchema.KillTerminalRequest,
204 ) => Effect.Effect<AcpSchema.KillTerminalResponse | void, AcpError.AcpError>,
205 ) => Effect.Effect<void>;
96 /**206 /**
97 * Closes an ACP session.207 * Registers a handler for `terminal/release`.
98 * @see https://agentclientprotocol.com/protocol/schema#session/close208 * @see https://agentclientprotocol.com/protocol/schema#terminal/release
99 */209 */
100 readonly closeSession: (210 readonly handleTerminalRelease: (
101 payload: AcpSchema.CloseSessionRequest,211 handler: (
102 ) => Effect.Effect<AcpSchema.CloseSessionResponse, AcpError.AcpError>;212 request: AcpSchema.ReleaseTerminalRequest,
213 ) => Effect.Effect<AcpSchema.ReleaseTerminalResponse | void, AcpError.AcpError>,
214 ) => Effect.Effect<void>;
103 /**215 /**
104 * Selects the active model for a session.216 * Registers a handler for `session/update`.
105 * @see https://agentclientprotocol.com/protocol/schema#session/set_model217 * @see https://agentclientprotocol.com/protocol/schema#session/update
106 */218 */
107 readonly setSessionModel: (219 readonly handleSessionUpdate: (
108 payload: AcpSchema.SetSessionModelRequest,220 handler: (
109 ) => Effect.Effect<AcpSchema.SetSessionModelResponse, AcpError.AcpError>;221 notification: AcpSchema.SessionNotification,
222 ) => Effect.Effect<void, AcpError.AcpError>,
223 ) => Effect.Effect<void>;
110 /**224 /**
111 * Updates a session configuration option.225 * Registers a handler for `session/elicitation/complete`.
112 * @see https://agentclientprotocol.com/protocol/schema#session/set_config_option226 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation/complete
113 */227 */
114 readonly setSessionConfigOption: (228 readonly handleElicitationComplete: (
115 payload: AcpSchema.SetSessionConfigOptionRequest,229 handler: (
116 ) => Effect.Effect<AcpSchema.SetSessionConfigOptionResponse, AcpError.AcpError>;230 notification: AcpSchema.ElicitationCompleteNotification,
231 ) => Effect.Effect<void, AcpError.AcpError>,
232 ) => Effect.Effect<void>;
117 /**233 /**
118 * Sends a prompt turn to the agent.234 * Registers a fallback extension request handler.
119 * @see https://agentclientprotocol.com/protocol/schema#session/prompt235 * @see https://agentclientprotocol.com/protocol/extensibility
120 */236 */
121 readonly prompt: (237 readonly handleUnknownExtRequest: (
122 payload: AcpSchema.PromptRequest,238 handler: (method: string, params: unknown) => Effect.Effect<unknown, AcpError.AcpError>,
123 ) => Effect.Effect<AcpSchema.PromptResponse, AcpError.AcpError>;239 ) => Effect.Effect<void>;
124 /**240 /**
125 * Sends a real ACP `session/cancel` notification.241 * Registers a fallback extension notification handler.
126 * @see https://agentclientprotocol.com/protocol/schema#session/cancel242 * @see https://agentclientprotocol.com/protocol/extensibility
127 */243 */
128 readonly cancel: (244 readonly handleUnknownExtNotification: (
129 payload: AcpSchema.CancelNotification,245 handler: (method: string, params: unknown) => Effect.Effect<void, AcpError.AcpError>,
130 ) => Effect.Effect<void, AcpError.AcpError>;246 ) => Effect.Effect<void>;
131 };247 /**
132 /**248 * Registers a typed extension request handler.
133 * Registers a handler for `session/request_permission`.249 * @see https://agentclientprotocol.com/protocol/extensibility
134 * @see https://agentclientprotocol.com/protocol/schema#session/request_permission250 */
135 */251 readonly handleExtRequest: <A, I>(
136 readonly handleRequestPermission: (252 method: string,
137 handler: (253 payload: Schema.Codec<A, I>,
138 request: AcpSchema.RequestPermissionRequest,254 handler: (payload: A) => Effect.Effect<unknown, AcpError.AcpError>,
139 ) => Effect.Effect<AcpSchema.RequestPermissionResponse, AcpError.AcpError>,255 ) => Effect.Effect<void>;
140 ) => Effect.Effect<void>;256 /**
141 /**257 * Registers a typed extension notification handler.
142 * Registers a handler for `session/elicitation`.258 * @see https://agentclientprotocol.com/protocol/extensibility
143 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation259 */
144 */260 readonly handleExtNotification: <A, I>(
145 readonly handleElicitation: (261 method: string,
146 handler: (262 payload: Schema.Codec<A, I>,
147 request: AcpSchema.ElicitationRequest,263 handler: (payload: A) => Effect.Effect<void, AcpError.AcpError>,
148 ) => Effect.Effect<AcpSchema.ElicitationResponse, AcpError.AcpError>,264 ) => Effect.Effect<void>;
149 ) => Effect.Effect<void>;265 }
150 /**266>()("effect-acp/client/AcpClient") {}
151 * Registers a handler for `fs/read_text_file`.
152 * @see https://agentclientprotocol.com/protocol/schema#fs/read_text_file
153 */
154 readonly handleReadTextFile: (
155 handler: (
156 request: AcpSchema.ReadTextFileRequest,
157 ) => Effect.Effect<AcpSchema.ReadTextFileResponse, AcpError.AcpError>,
158 ) => Effect.Effect<void>;
159 /**
160 * Registers a handler for `fs/write_text_file`.
161 * @see https://agentclientprotocol.com/protocol/schema#fs/write_text_file
162 */
163 readonly handleWriteTextFile: (
164 handler: (
165 request: AcpSchema.WriteTextFileRequest,
166 ) => Effect.Effect<AcpSchema.WriteTextFileResponse | void, AcpError.AcpError>,
167 ) => Effect.Effect<void>;
168 /**
169 * Registers a handler for `terminal/create`.
170 * @see https://agentclientprotocol.com/protocol/schema#terminal/create
171 */
172 readonly handleCreateTerminal: (
173 handler: (
174 request: AcpSchema.CreateTerminalRequest,
175 ) => Effect.Effect<AcpSchema.CreateTerminalResponse, AcpError.AcpError>,
176 ) => Effect.Effect<void>;
177 /**
178 * Registers a handler for `terminal/output`.
179 * @see https://agentclientprotocol.com/protocol/schema#terminal/output
180 */
181 readonly handleTerminalOutput: (
182 handler: (
183 request: AcpSchema.TerminalOutputRequest,
184 ) => Effect.Effect<AcpSchema.TerminalOutputResponse, AcpError.AcpError>,
185 ) => Effect.Effect<void>;
186 /**
187 * Registers a handler for `terminal/wait_for_exit`.
188 * @see https://agentclientprotocol.com/protocol/schema#terminal/wait_for_exit
189 */
190 readonly handleTerminalWaitForExit: (
191 handler: (
192 request: AcpSchema.WaitForTerminalExitRequest,
193 ) => Effect.Effect<AcpSchema.WaitForTerminalExitResponse, AcpError.AcpError>,
194 ) => Effect.Effect<void>;
195 /**
196 * Registers a handler for `terminal/kill`.
197 * @see https://agentclientprotocol.com/protocol/schema#terminal/kill
198 */
199 readonly handleTerminalKill: (
200 handler: (
201 request: AcpSchema.KillTerminalRequest,
202 ) => Effect.Effect<AcpSchema.KillTerminalResponse | void, AcpError.AcpError>,
203 ) => Effect.Effect<void>;
204 /**
205 * Registers a handler for `terminal/release`.
206 * @see https://agentclientprotocol.com/protocol/schema#terminal/release
207 */
208 readonly handleTerminalRelease: (
209 handler: (
210 request: AcpSchema.ReleaseTerminalRequest,
211 ) => Effect.Effect<AcpSchema.ReleaseTerminalResponse | void, AcpError.AcpError>,
212 ) => Effect.Effect<void>;
213 /**
214 * Registers a handler for `session/update`.
215 * @see https://agentclientprotocol.com/protocol/schema#session/update
216 */
217 readonly handleSessionUpdate: (
218 handler: (
219 notification: AcpSchema.SessionNotification,
220 ) => Effect.Effect<void, AcpError.AcpError>,
221 ) => Effect.Effect<void>;
222 /**
223 * Registers a handler for `session/elicitation/complete`.
224 * @see https://agentclientprotocol.com/protocol/schema#session/elicitation/complete
225 */
226 readonly handleElicitationComplete: (
227 handler: (
228 notification: AcpSchema.ElicitationCompleteNotification,
229 ) => Effect.Effect<void, AcpError.AcpError>,
230 ) => Effect.Effect<void>;
231 /**
232 * Registers a fallback extension request handler.
233 * @see https://agentclientprotocol.com/protocol/extensibility
234 */
235 readonly handleUnknownExtRequest: (
236 handler: (method: string, params: unknown) => Effect.Effect<unknown, AcpError.AcpError>,
237 ) => Effect.Effect<void>;
238 /**
239 * Registers a fallback extension notification handler.
240 * @see https://agentclientprotocol.com/protocol/extensibility
241 */
242 readonly handleUnknownExtNotification: (
243 handler: (method: string, params: unknown) => Effect.Effect<void, AcpError.AcpError>,
244 ) => Effect.Effect<void>;
245 /**
246 * Registers a typed extension request handler.
247 * @see https://agentclientprotocol.com/protocol/extensibility
248 */
249 readonly handleExtRequest: <A, I>(
250 method: string,
251 payload: Schema.Codec<A, I>,
252 handler: (payload: A) => Effect.Effect<unknown, AcpError.AcpError>,
253 ) => Effect.Effect<void>;
254 /**
255 * Registers a typed extension notification handler.
256 * @see https://agentclientprotocol.com/protocol/extensibility
257 */
258 readonly handleExtNotification: <A, I>(
259 method: string,
260 payload: Schema.Codec<A, I>,
261 handler: (payload: A) => Effect.Effect<void, AcpError.AcpError>,
262 ) => Effect.Effect<void>;
263}
264
265export class AcpClient extends Context.Service<AcpClient, AcpClientShape>()(
266 "effect-acp/client/AcpClient",
267) {}
268267
269interface AcpCoreRequestHandlers {268interface AcpCoreRequestHandlers {
270 requestPermission?: (269 requestPermission?: (
...@@ -310,7 +309,7 @@ export const make = Effect.fn("effect-acp/AcpClient.make")(function* (...@@ -310,7 +309,7 @@ export const make = Effect.fn("effect-acp/AcpClient.make")(function* (
310 stdio: Stdio.Stdio,309 stdio: Stdio.Stdio,
311 options: AcpClientOptions = {},310 options: AcpClientOptions = {},
312 terminationError?: Effect.Effect<AcpError.AcpError>,311 terminationError?: Effect.Effect<AcpError.AcpError>,
313): Effect.fn.Return<AcpClientShape, never, Scope.Scope> {312): Effect.fn.Return<AcpClient["Service"], never, Scope.Scope> {
314 const coreHandlers: AcpCoreRequestHandlers = {};313 const coreHandlers: AcpCoreRequestHandlers = {};
315 const notificationHandlers: AcpNotificationHandlers = {314 const notificationHandlers: AcpNotificationHandlers = {
316 sessionUpdate: { handlers: [], pending: [] },315 sessionUpdate: { handlers: [], pending: [] },
...@@ -559,6 +558,9 @@ export const make = Effect.fn("effect-acp/AcpClient.make")(function* (...@@ -559,6 +558,9 @@ export const make = Effect.fn("effect-acp/AcpClient.make")(function* (
559 });558 });
560});559});
561560
561export const layer = (stdio: Stdio.Stdio, options: AcpClientOptions = {}): Layer.Layer<AcpClient> =>
562 Layer.effect(AcpClient, make(stdio, options));
563
562export const layerChildProcess = (564export const layerChildProcess = (
563 handle: ChildProcessSpawner.ChildProcessHandle,565 handle: ChildProcessSpawner.ChildProcessHandle,
564 options: AcpClientOptions = {},566 options: AcpClientOptions = {},
packages/effect-acp/src/errors.ts+5-1
...@@ -45,7 +45,11 @@ export class AcpTransportError extends Schema.TaggedErrorClass<AcpTransportError...@@ -45,7 +45,11 @@ export class AcpTransportError extends Schema.TaggedErrorClass<AcpTransportError
45 detail: Schema.String,45 detail: Schema.String,
46 cause: Schema.Defect(),46 cause: Schema.Defect(),
47 },47 },
48) {}48) {
49 override get message() {
50 return this.detail;
51 }
52}
4953
50export class AcpRequestError extends Schema.TaggedErrorClass<AcpRequestError>()("AcpRequestError", {54export class AcpRequestError extends Schema.TaggedErrorClass<AcpRequestError>()("AcpRequestError", {
51 code: AcpSchema.ErrorCode,55 code: AcpSchema.ErrorCode,
packages/effect-codex-app-server/src/client.ts+45-39
...@@ -5,7 +5,7 @@ import * as Schema from "effect/Schema";...@@ -5,7 +5,7 @@ import * as Schema from "effect/Schema";
5import * as Scope from "effect/Scope";5import * as Scope from "effect/Scope";
6import * as Stdio from "effect/Stdio";6import * as Stdio from "effect/Stdio";
7import * as Stream from "effect/Stream";7import * as Stream from "effect/Stream";
8import { ChildProcessSpawner } from "effect/unstable/process";8import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
99
10import * as CodexRpc from "./_generated/meta.gen.ts";10import * as CodexRpc from "./_generated/meta.gen.ts";
11import * as CodexError from "./errors.ts";11import * as CodexError from "./errors.ts";
...@@ -35,45 +35,46 @@ interface CodexAppServerClientRaw {...@@ -35,45 +35,46 @@ interface CodexAppServerClientRaw {
35 readonly respondError: CodexProtocol.CodexAppServerPatchedProtocol["respondError"];35 readonly respondError: CodexProtocol.CodexAppServerPatchedProtocol["respondError"];
36}36}
3737
38export interface CodexAppServerClientShape {
39 readonly raw: CodexAppServerClientRaw;
40 readonly request: <M extends CodexRpc.ClientRequestMethod>(
41 method: M,
42 payload: CodexRpc.ClientRequestParamsByMethod[M],
43 ) => Effect.Effect<CodexRpc.ClientRequestResponsesByMethod[M], CodexError.CodexAppServerError>;
44 readonly notify: <M extends CodexRpc.ClientNotificationMethod>(
45 method: M,
46 payload: CodexRpc.ClientNotificationParamsByMethod[M],
47 ) => Effect.Effect<void, CodexError.CodexAppServerError>;
48 readonly handleServerRequest: <M extends CodexRpc.ServerRequestMethod>(
49 method: M,
50 handler: (
51 payload: CodexRpc.ServerRequestParamsByMethod[M],
52 ) => Effect.Effect<CodexRpc.ServerRequestResponsesByMethod[M], CodexError.CodexAppServerError>,
53 ) => Effect.Effect<void>;
54 readonly handleServerNotification: <M extends CodexRpc.ServerNotificationMethod>(
55 method: M,
56 handler: (
57 payload: CodexRpc.ServerNotificationParamsByMethod[M],
58 ) => Effect.Effect<void, CodexError.CodexAppServerError>,
59 ) => Effect.Effect<void>;
60 readonly handleUnknownServerRequest: (
61 handler: (
62 method: string,
63 params: unknown,
64 ) => Effect.Effect<unknown, CodexError.CodexAppServerError>,
65 ) => Effect.Effect<void>;
66 readonly handleUnknownServerNotification: (
67 handler: (
68 method: string,
69 params: unknown,
70 ) => Effect.Effect<void, CodexError.CodexAppServerError>,
71 ) => Effect.Effect<void>;
72}
73
74export class CodexAppServerClient extends Context.Service<38export class CodexAppServerClient extends Context.Service<
75 CodexAppServerClient,39 CodexAppServerClient,
76 CodexAppServerClientShape40 {
41 readonly raw: CodexAppServerClientRaw;
42 readonly request: <M extends CodexRpc.ClientRequestMethod>(
43 method: M,
44 payload: CodexRpc.ClientRequestParamsByMethod[M],
45 ) => Effect.Effect<CodexRpc.ClientRequestResponsesByMethod[M], CodexError.CodexAppServerError>;
46 readonly notify: <M extends CodexRpc.ClientNotificationMethod>(
47 method: M,
48 payload: CodexRpc.ClientNotificationParamsByMethod[M],
49 ) => Effect.Effect<void, CodexError.CodexAppServerError>;
50 readonly handleServerRequest: <M extends CodexRpc.ServerRequestMethod>(
51 method: M,
52 handler: (
53 payload: CodexRpc.ServerRequestParamsByMethod[M],
54 ) => Effect.Effect<
55 CodexRpc.ServerRequestResponsesByMethod[M],
56 CodexError.CodexAppServerError
57 >,
58 ) => Effect.Effect<void>;
59 readonly handleServerNotification: <M extends CodexRpc.ServerNotificationMethod>(
60 method: M,
61 handler: (
62 payload: CodexRpc.ServerNotificationParamsByMethod[M],
63 ) => Effect.Effect<void, CodexError.CodexAppServerError>,
64 ) => Effect.Effect<void>;
65 readonly handleUnknownServerRequest: (
66 handler: (
67 method: string,
68 params: unknown,
69 ) => Effect.Effect<unknown, CodexError.CodexAppServerError>,
70 ) => Effect.Effect<void>;
71 readonly handleUnknownServerNotification: (
72 handler: (
73 method: string,
74 params: unknown,
75 ) => Effect.Effect<void, CodexError.CodexAppServerError>,
76 ) => Effect.Effect<void>;
77 }
77>()("effect-codex-app-server/client/CodexAppServerClient") {}78>()("effect-codex-app-server/client/CodexAppServerClient") {}
7879
79type ServerRequestHandler = (80type ServerRequestHandler = (
...@@ -87,7 +88,7 @@ export const make = Effect.fn("effect-codex-app-server/CodexAppServerClient.make...@@ -87,7 +88,7 @@ export const make = Effect.fn("effect-codex-app-server/CodexAppServerClient.make
87 stdio: Stdio.Stdio,88 stdio: Stdio.Stdio,
88 options: CodexAppServerClientOptions = {},89 options: CodexAppServerClientOptions = {},
89 terminationError?: Effect.Effect<CodexError.CodexAppServerError>,90 terminationError?: Effect.Effect<CodexError.CodexAppServerError>,
90): Effect.fn.Return<CodexAppServerClientShape, never, Scope.Scope> {91): Effect.fn.Return<CodexAppServerClient["Service"], never, Scope.Scope> {
91 const requestHandlers = new Map<string, ServerRequestHandler>();92 const requestHandlers = new Map<string, ServerRequestHandler>();
92 const notificationHandlers = new Map<string, Array<ServerNotificationHandler>>();93 const notificationHandlers = new Map<string, Array<ServerNotificationHandler>>();
93 let unknownRequestHandler:94 let unknownRequestHandler:
...@@ -249,6 +250,11 @@ export const make = Effect.fn("effect-codex-app-server/CodexAppServerClient.make...@@ -249,6 +250,11 @@ export const make = Effect.fn("effect-codex-app-server/CodexAppServerClient.make
249 });250 });
250});251});
251252
253export const layer = (
254 stdio: Stdio.Stdio,
255 options: CodexAppServerClientOptions = {},
256): Layer.Layer<CodexAppServerClient> => Layer.effect(CodexAppServerClient, make(stdio, options));
257
252export const layerChildProcess = (258export const layerChildProcess = (
253 handle: ChildProcessSpawner.ChildProcessHandle,259 handle: ChildProcessSpawner.ChildProcessHandle,
254 options: CodexAppServerClientOptions = {},260 options: CodexAppServerClientOptions = {},