@@ -12,10 +12,9 @@ import type {
1212} from "@agentclientprotocol/sdk"
1313import type { OpencodeClient } from "@opencode-ai/sdk/v2"
1414import { ProviderV2 } from "@opencode-ai/core/provider"
15- import { Effect , ManagedRuntime } from "effect"
15+ import { Effect } from "effect"
1616import * as ACPService from "@/acp/service"
1717import * as ACPError from "@/acp/error"
18- import { ACPSession } from "@/acp/session"
1918import { UsageService } from "@/acp/usage"
2019import type { Provider } from "@/provider/provider"
2120
@@ -142,7 +141,10 @@ const provider: Provider.Info = {
142141}
143142
144143describe ( "ACP service sessions" , ( ) => {
145- const makeService = ( messages : readonly { info : unknown ; parts : readonly unknown [ ] } [ ] = [ ] ) => {
144+ const makeService = (
145+ messages : readonly { info : unknown ; parts : readonly unknown [ ] } [ ] = [ ] ,
146+ options ?: { abort ?: ( input : { sessionID : string } ) => Promise < { data : boolean } > } ,
147+ ) => {
146148 const updates : SessionNotification [ ] = [ ]
147149 const mcpAdds : string [ ] = [ ]
148150 const aborts : string [ ] = [ ]
@@ -220,10 +222,12 @@ describe("ACP service sessions", () => {
220222 summarizes . push ( input )
221223 return Promise . resolve ( { data : true } )
222224 } ,
223- abort : ( input : { sessionID : string } ) => {
224- aborts . push ( input . sessionID )
225- return Promise . resolve ( { data : true } )
226- } ,
225+ abort :
226+ options ?. abort ??
227+ ( ( input : { sessionID : string } ) => {
228+ aborts . push ( input . sessionID )
229+ return Promise . resolve ( { data : true } )
230+ } ) ,
227231 fork : ( input : { sessionID : string } ) => {
228232 forks . push ( input . sessionID )
229233 return Promise . resolve ( { data : { id : `fork_${ input . sessionID } ` } } )
@@ -381,34 +385,28 @@ describe("ACP service sessions", () => {
381385 expect ( await Effect . runPromise ( service . closeSession ( { sessionId : "missing" } ) ) ) . toEqual ( { } )
382386 } )
383387
384- it ( "does not fail close when backing abort fails" , async ( ) => {
385- const sessionService = ManagedRuntime . make ( ACPSession . defaultLayer ) . runSync (
386- ACPSession . Service . use ( ( service ) => Effect . succeed ( service ) ) ,
388+ it ( "cancel aborts the backing session and keeps the ACP session" , async ( ) => {
389+ const { service, aborts } = makeService ( )
390+ const created = await Effect . runPromise ( service . newSession ( { cwd : "/workspace" , mcpServers : [ ] } ) )
391+
392+ await Effect . runPromise ( service . cancel ( { sessionId : created . sessionId } ) )
393+
394+ // The running turn was aborted via the core session API.
395+ expect ( aborts ) . toEqual ( [ created . sessionId ] )
396+ // Unlike closeSession, the ACP session is still present afterwards so
397+ // the client can keep prompting.
398+ const stillUsable = await Effect . runPromise (
399+ service . setSessionConfigOption ( { sessionId : created . sessionId , configId : "effort" , value : "high" } ) ,
387400 )
388- const { service } = makeService ( )
389- const sdk = {
390- config : {
391- providers : ( ) => Promise . resolve ( { data : { providers : [ provider ] , default : { test : modelID } } } ) ,
392- get : ( ) => Promise . resolve ( { data : { } } ) ,
393- } ,
394- app : {
395- agents : ( ) => Promise . resolve ( { data : [ { name : "build" , mode : "primary" , permission : [ ] , options : { } } ] } ) ,
396- skills : ( ) => Promise . resolve ( { data : [ ] } ) ,
397- } ,
398- command : {
399- list : ( ) => Promise . resolve ( { data : [ ] } ) ,
400- } ,
401- session : {
402- abort : ( ) => Promise . reject ( new Error ( "nope" ) ) ,
403- } ,
404- mcp : {
405- add : ( ) => Promise . resolve ( { data : { } } ) ,
406- } ,
407- } as unknown as OpencodeClient
408- const closing = ACPService . make ( { sdk, session : sessionService } )
409- await Effect . runPromise ( sessionService . create ( { id : "ses_close" , cwd : "/workspace" } ) )
401+ expect ( stillUsable ) . toBeDefined ( )
402+ } )
410403
411- expect ( await Effect . runPromise ( closing . closeSession ( { sessionId : "ses_close" } ) ) ) . toEqual ( { } )
404+ it ( "does not fail cancel or close when the backing abort fails" , async ( ) => {
405+ const { service } = makeService ( [ ] , { abort : ( ) => Promise . reject ( new Error ( "nope" ) ) } )
406+ const created = await Effect . runPromise ( service . newSession ( { cwd : "/workspace" , mcpServers : [ ] } ) )
407+
408+ await Effect . runPromise ( service . cancel ( { sessionId : created . sessionId } ) )
409+ expect ( await Effect . runPromise ( service . closeSession ( { sessionId : created . sessionId } ) ) ) . toEqual ( { } )
412410 expect ( await Effect . runPromise ( service . closeSession ( { sessionId : "missing" } ) ) ) . toEqual ( { } )
413411 } )
414412
0 commit comments