11import z from "zod"
22import path from "path"
3+ import { Effect } from "effect"
34import { Tool } from "./tool"
45import { Question } from "../question"
56import { Session } from "../session"
@@ -9,123 +10,71 @@ import { Instance } from "../project/instance"
910import { type SessionID , MessageID , PartID } from "../session/schema"
1011import EXIT_DESCRIPTION from "./plan-exit.txt"
1112
12- async function getLastModel ( sessionID : SessionID ) {
13- for await ( const item of MessageV2 . stream ( sessionID ) ) {
13+ function getLastModel ( sessionID : SessionID ) {
14+ for ( const item of MessageV2 . stream ( sessionID ) ) {
1415 if ( item . info . role === "user" && item . info . model ) return item . info . model
1516 }
16- return Provider . defaultModel ( )
17+ return undefined
1718}
1819
19- export const PlanExitTool = Tool . define ( "plan_exit" , {
20- description : EXIT_DESCRIPTION ,
21- parameters : z . object ( { } ) ,
22- async execute ( _params , ctx ) {
23- const session = await Session . get ( ctx . sessionID )
24- const plan = path . relative ( Instance . worktree , Session . plan ( session ) )
25- const answers = await Question . ask ( {
26- sessionID : ctx . sessionID ,
27- questions : [
28- {
29- question : `Plan at ${ plan } is complete. Would you like to switch to the build agent and start implementing?` ,
30- header : "Build Agent" ,
31- custom : false ,
32- options : [
33- { label : "Yes" , description : "Switch to build agent and start implementing the plan" } ,
34- { label : "No" , description : "Stay with plan agent to continue refining the plan" } ,
35- ] ,
36- } ,
37- ] ,
38- tool : ctx . callID ? { messageID : ctx . messageID , callID : ctx . callID } : undefined ,
39- } )
40-
41- const answer = answers [ 0 ] ?. [ 0 ]
42- if ( answer === "No" ) throw new Question . RejectedError ( )
43-
44- const model = await getLastModel ( ctx . sessionID )
45-
46- const userMsg : MessageV2 . User = {
47- id : MessageID . ascending ( ) ,
48- sessionID : ctx . sessionID ,
49- role : "user" ,
50- time : {
51- created : Date . now ( ) ,
52- } ,
53- agent : "build" ,
54- model,
55- }
56- await Session . updateMessage ( userMsg )
57- await Session . updatePart ( {
58- id : PartID . ascending ( ) ,
59- messageID : userMsg . id ,
60- sessionID : ctx . sessionID ,
61- type : "text" ,
62- text : `The plan at ${ plan } has been approved, you can now edit files. Execute the plan` ,
63- synthetic : true ,
64- } satisfies MessageV2 . TextPart )
20+ export const PlanExitTool = Tool . defineEffect (
21+ "plan_exit" ,
22+ Effect . gen ( function * ( ) {
23+ const session = yield * Session . Service
24+ const question = yield * Question . Service
25+ const provider = yield * Provider . Service
6526
6627 return {
67- title : "Switching to build agent" ,
68- output : "User approved switching to build agent. Wait for further instructions." ,
69- metadata : { } ,
70- }
71- } ,
72- } )
28+ description : EXIT_DESCRIPTION ,
29+ parameters : z . object ( { } ) ,
30+ execute : ( _params : { } , ctx : Tool . Context ) =>
31+ Effect . gen ( function * ( ) {
32+ const info = yield * session . get ( ctx . sessionID )
33+ const plan = path . relative ( Instance . worktree , Session . plan ( info ) )
34+ const answers = yield * question . ask ( {
35+ sessionID : ctx . sessionID ,
36+ questions : [
37+ {
38+ question : `Plan at ${ plan } is complete. Would you like to switch to the build agent and start implementing?` ,
39+ header : "Build Agent" ,
40+ custom : false ,
41+ options : [
42+ { label : "Yes" , description : "Switch to build agent and start implementing the plan" } ,
43+ { label : "No" , description : "Stay with plan agent to continue refining the plan" } ,
44+ ] ,
45+ } ,
46+ ] ,
47+ tool : ctx . callID ? { messageID : ctx . messageID , callID : ctx . callID } : undefined ,
48+ } )
7349
74- /*
75- export const PlanEnterTool = Tool.define("plan_enter", {
76- description: ENTER_DESCRIPTION,
77- parameters: z.object({}),
78- async execute(_params, ctx) {
79- const session = await Session.get(ctx.sessionID)
80- const plan = path.relative(Instance.worktree, Session.plan(session))
50+ if ( answers [ 0 ] ?. [ 0 ] === "No" ) yield * new Question . RejectedError ( )
8151
82- const answers = await Question.ask({
83- sessionID: ctx.sessionID,
84- questions: [
85- {
86- question: `Would you like to switch to the plan agent and create a plan saved to ${plan}?`,
87- header: "Plan Mode",
88- custom: false,
89- options: [
90- { label: "Yes", description: "Switch to plan agent for research and planning" },
91- { label: "No", description: "Stay with build agent to continue making changes" },
92- ],
93- },
94- ],
95- tool: ctx.callID ? { messageID: ctx.messageID, callID: ctx.callID } : undefined,
96- })
52+ const model = getLastModel ( ctx . sessionID ) ?? ( yield * provider . defaultModel ( ) )
9753
98- const answer = answers[0]?.[0]
54+ const msg : MessageV2 . User = {
55+ id : MessageID . ascending ( ) ,
56+ sessionID : ctx . sessionID ,
57+ role : "user" ,
58+ time : { created : Date . now ( ) } ,
59+ agent : "build" ,
60+ model,
61+ }
62+ yield * session . updateMessage ( msg )
63+ yield * session . updatePart ( {
64+ id : PartID . ascending ( ) ,
65+ messageID : msg . id ,
66+ sessionID : ctx . sessionID ,
67+ type : "text" ,
68+ text : `The plan at ${ plan } has been approved, you can now edit files. Execute the plan` ,
69+ synthetic : true ,
70+ } satisfies MessageV2 . TextPart )
9971
100- if (answer === "No") throw new Question.RejectedError()
101-
102- const model = await getLastModel(ctx.sessionID)
103-
104- const userMsg: MessageV2.User = {
105- id: MessageID.ascending(),
106- sessionID: ctx.sessionID,
107- role: "user",
108- time: {
109- created: Date.now(),
110- },
111- agent: "plan",
112- model,
113- }
114- await Session.updateMessage(userMsg)
115- await Session.updatePart({
116- id: PartID.ascending(),
117- messageID: userMsg.id,
118- sessionID: ctx.sessionID,
119- type: "text",
120- text: "User has requested to enter plan mode. Switch to plan mode and begin planning.",
121- synthetic: true,
122- } satisfies MessageV2.TextPart)
123-
124- return {
125- title: "Switching to plan agent",
126- output: `User confirmed to switch to plan mode. A new message has been created to switch you to plan mode. The plan file will be at ${plan}. Begin planning.`,
127- metadata: {},
72+ return {
73+ title : "Switching to build agent" ,
74+ output : "User approved switching to build agent. Wait for further instructions." ,
75+ metadata : { } ,
76+ }
77+ } ) . pipe ( Effect . runPromise ) ,
12878 }
129- },
130- })
131- */
79+ } ) ,
80+ )
0 commit comments