2026-01-16 21:21:13 +00:00
import { Hono } from "hono"
import { stream } from "hono/streaming"
import { describeRoute , validator , resolver } from "hono-openapi"
2026-03-11 23:40:50 +00:00
import { SessionID , MessageID , PartID } from "@/session/schema"
2026-01-16 21:21:13 +00:00
import z from "zod"
import { Session } from "../../session"
import { MessageV2 } from "../../session/message-v2"
import { SessionPrompt } from "../../session/prompt"
import { SessionCompaction } from "../../session/compaction"
import { SessionRevert } from "../../session/revert"
import { SessionStatus } from "@/session/status"
import { SessionSummary } from "@/session/summary"
import { Todo } from "../../session/todo"
import { Agent } from "../../agent/agent"
import { Snapshot } from "@/snapshot"
import { Log } from "../../util/log"
import { PermissionNext } from "@/permission/next"
2026-03-12 01:49:57 +00:00
import { PermissionID } from "@/permission/schema"
2026-01-16 21:21:13 +00:00
import { errors } from "../error"
import { lazy } from "../../util/lazy"
const log = Log . create ( { service : "server" } )
export const SessionRoutes = lazy ( ( ) = >
new Hono ( )
. get (
"/" ,
describeRoute ( {
summary : "List sessions" ,
description : "Get a list of all OpenCode sessions, sorted by most recently updated." ,
operationId : "session.list" ,
responses : {
200 : {
description : "List of sessions" ,
content : {
"application/json" : {
schema : resolver ( Session . Info . array ( ) ) ,
} ,
} ,
} ,
} ,
} ) ,
validator (
"query" ,
z . object ( {
directory : z.string ( ) . optional ( ) . meta ( { description : "Filter sessions by project directory" } ) ,
roots : z.coerce.boolean ( ) . optional ( ) . meta ( { description : "Only return root sessions (no parentID)" } ) ,
start : z.coerce
. number ( )
. optional ( )
. meta ( { description : "Filter sessions updated on or after this timestamp (milliseconds since epoch)" } ) ,
search : z.string ( ) . optional ( ) . meta ( { description : "Filter sessions by title (case-insensitive)" } ) ,
limit : z.coerce.number ( ) . optional ( ) . meta ( { description : "Maximum number of sessions to return" } ) ,
} ) ,
) ,
async ( c ) = > {
const query = c . req . valid ( "query" )
const sessions : Session.Info [ ] = [ ]
2026-02-14 18:40:49 +00:00
for await ( const session of Session . list ( {
directory : query.directory ,
roots : query.roots ,
start : query.start ,
search : query.search ,
limit : query.limit ,
} ) ) {
2026-01-16 21:21:13 +00:00
sessions . push ( session )
}
return c . json ( sessions )
} ,
)
. get (
"/status" ,
describeRoute ( {
summary : "Get session status" ,
description : "Retrieve the current status of all sessions, including active, idle, and completed states." ,
operationId : "session.status" ,
responses : {
200 : {
description : "Get session status" ,
content : {
"application/json" : {
schema : resolver ( z . record ( z . string ( ) , SessionStatus . Info ) ) ,
} ,
} ,
} ,
. . . errors ( 400 ) ,
} ,
} ) ,
async ( c ) = > {
const result = SessionStatus . list ( )
return c . json ( result )
} ,
)
. get (
"/:sessionID" ,
describeRoute ( {
summary : "Get session" ,
description : "Retrieve detailed information about a specific OpenCode session." ,
tags : [ "Session" ] ,
operationId : "session.get" ,
responses : {
200 : {
description : "Get session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
sessionID : Session.get.schema ,
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
log . info ( "SEARCH" , { url : c.req.url } )
const session = await Session . get ( sessionID )
return c . json ( session )
} ,
)
. get (
"/:sessionID/children" ,
describeRoute ( {
summary : "Get session children" ,
tags : [ "Session" ] ,
description : "Retrieve all child sessions that were forked from the specified parent session." ,
operationId : "session.children" ,
responses : {
200 : {
description : "List of children" ,
content : {
"application/json" : {
schema : resolver ( Session . Info . array ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
sessionID : Session.children.schema ,
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const session = await Session . children ( sessionID )
return c . json ( session )
} ,
)
. get (
"/:sessionID/todo" ,
describeRoute ( {
summary : "Get session todos" ,
description : "Retrieve the todo list associated with a specific session, showing tasks and action items." ,
operationId : "session.todo" ,
responses : {
200 : {
description : "Todo list" ,
content : {
"application/json" : {
schema : resolver ( Todo . Info . array ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const todos = await Todo . get ( sessionID )
return c . json ( todos )
} ,
)
. post (
"/" ,
describeRoute ( {
summary : "Create session" ,
description : "Create a new OpenCode session for interacting with AI assistants and managing conversations." ,
operationId : "session.create" ,
responses : {
. . . errors ( 400 ) ,
200 : {
description : "Successfully created session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
} ,
} ) ,
validator ( "json" , Session . create . schema . optional ( ) ) ,
async ( c ) = > {
const body = c . req . valid ( "json" ) ? ? { }
const session = await Session . create ( body )
return c . json ( session )
} ,
)
. delete (
"/:sessionID" ,
describeRoute ( {
summary : "Delete session" ,
description : "Delete a session and permanently remove all associated data, including messages and history." ,
operationId : "session.delete" ,
responses : {
200 : {
description : "Successfully deleted session" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
sessionID : Session.remove.schema ,
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
await Session . remove ( sessionID )
return c . json ( true )
} ,
)
. patch (
"/:sessionID" ,
describeRoute ( {
summary : "Update session" ,
description : "Update properties of an existing session, such as title or other metadata." ,
operationId : "session.update" ,
responses : {
200 : {
description : "Successfully updated session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator (
"json" ,
z . object ( {
title : z.string ( ) . optional ( ) ,
time : z
. object ( {
archived : z.number ( ) . optional ( ) ,
} )
. optional ( ) ,
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const updates = c . req . valid ( "json" )
2026-02-14 04:19:02 +00:00
let session = await Session . get ( sessionID )
if ( updates . title !== undefined ) {
session = await Session . setTitle ( { sessionID , title : updates.title } )
}
if ( updates . time ? . archived !== undefined ) {
session = await Session . setArchived ( { sessionID , time : updates.time.archived } )
}
2026-01-16 21:21:13 +00:00
2026-02-14 04:19:02 +00:00
return c . json ( session )
2026-01-16 21:21:13 +00:00
} ,
)
. post (
"/:sessionID/init" ,
describeRoute ( {
summary : "Initialize session" ,
description :
"Analyze the current application and create an AGENTS.md file with project-specific agent configurations." ,
operationId : "session.init" ,
responses : {
200 : {
description : "200" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , Session . initialize . schema . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
await Session . initialize ( { . . . body , sessionID } )
return c . json ( true )
} ,
)
. post (
"/:sessionID/fork" ,
describeRoute ( {
summary : "Fork session" ,
description : "Create a new session by forking an existing session at a specific message point." ,
operationId : "session.fork" ,
responses : {
200 : {
description : "200" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
sessionID : Session.fork.schema.shape.sessionID ,
} ) ,
) ,
validator ( "json" , Session . fork . schema . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
const result = await Session . fork ( { . . . body , sessionID } )
return c . json ( result )
} ,
)
. post (
"/:sessionID/abort" ,
describeRoute ( {
summary : "Abort session" ,
description : "Abort an active session and stop any ongoing AI processing or command execution." ,
operationId : "session.abort" ,
responses : {
200 : {
description : "Aborted session" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
async ( c ) = > {
SessionPrompt . cancel ( c . req . valid ( "param" ) . sessionID )
return c . json ( true )
} ,
)
. post (
"/:sessionID/share" ,
describeRoute ( {
summary : "Share session" ,
description : "Create a shareable link for a session, allowing others to view the conversation." ,
operationId : "session.share" ,
responses : {
200 : {
description : "Successfully shared session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
await Session . share ( sessionID )
const session = await Session . get ( sessionID )
return c . json ( session )
} ,
)
. get (
"/:sessionID/diff" ,
describeRoute ( {
summary : "Get message diff" ,
description : "Get the file changes (diff) that resulted from a specific user message in the session." ,
operationId : "session.diff" ,
responses : {
200 : {
description : "Successfully retrieved diff" ,
content : {
"application/json" : {
schema : resolver ( Snapshot . FileDiff . array ( ) ) ,
} ,
} ,
} ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
sessionID : SessionSummary.diff.schema.shape.sessionID ,
} ) ,
) ,
validator (
"query" ,
z . object ( {
messageID : SessionSummary.diff.schema.shape.messageID ,
} ) ,
) ,
async ( c ) = > {
const query = c . req . valid ( "query" )
const params = c . req . valid ( "param" )
const result = await SessionSummary . diff ( {
sessionID : params.sessionID ,
messageID : query.messageID ,
} )
return c . json ( result )
} ,
)
. delete (
"/:sessionID/share" ,
describeRoute ( {
summary : "Unshare session" ,
description : "Remove the shareable link for a session, making it private again." ,
operationId : "session.unshare" ,
responses : {
200 : {
description : "Successfully unshared session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
sessionID : Session.unshare.schema ,
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
await Session . unshare ( sessionID )
const session = await Session . get ( sessionID )
return c . json ( session )
} ,
)
. post (
"/:sessionID/summarize" ,
describeRoute ( {
summary : "Summarize session" ,
description : "Generate a concise summary of the session using AI compaction to preserve key information." ,
operationId : "session.summarize" ,
responses : {
200 : {
description : "Summarized session" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator (
"json" ,
z . object ( {
providerID : z.string ( ) ,
modelID : z.string ( ) ,
auto : z.boolean ( ) . optional ( ) . default ( false ) ,
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
const session = await Session . get ( sessionID )
await SessionRevert . cleanup ( session )
const msgs = await Session . messages ( { sessionID } )
let currentAgent = await Agent . defaultAgent ( )
for ( let i = msgs . length - 1 ; i >= 0 ; i -- ) {
const info = msgs [ i ] . info
if ( info . role === "user" ) {
currentAgent = info . agent || ( await Agent . defaultAgent ( ) )
break
}
}
await SessionCompaction . create ( {
sessionID ,
agent : currentAgent ,
model : {
providerID : body.providerID ,
modelID : body.modelID ,
} ,
auto : body.auto ,
} )
2026-02-06 22:13:11 +00:00
await SessionPrompt . loop ( { sessionID } )
2026-01-16 21:21:13 +00:00
return c . json ( true )
} ,
)
. get (
"/:sessionID/message" ,
describeRoute ( {
summary : "Get session messages" ,
description : "Retrieve all messages in a session, including user prompts and AI responses." ,
operationId : "session.messages" ,
responses : {
200 : {
description : "List of messages" ,
content : {
"application/json" : {
schema : resolver ( MessageV2 . WithParts . array ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator (
"query" ,
z . object ( {
limit : z.coerce.number ( ) . optional ( ) ,
} ) ,
) ,
async ( c ) = > {
const query = c . req . valid ( "query" )
const messages = await Session . messages ( {
sessionID : c.req.valid ( "param" ) . sessionID ,
limit : query.limit ,
} )
return c . json ( messages )
} ,
)
. get (
"/:sessionID/message/:messageID" ,
describeRoute ( {
summary : "Get message" ,
description : "Retrieve a specific message from a session by its message ID." ,
operationId : "session.message" ,
responses : {
200 : {
description : "Message" ,
content : {
"application/json" : {
schema : resolver (
z . object ( {
info : MessageV2.Info ,
parts : MessageV2.Part.array ( ) ,
} ) ,
) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-03-11 23:30:17 +00:00
messageID : MessageID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
async ( c ) = > {
const params = c . req . valid ( "param" )
const message = await MessageV2 . get ( {
sessionID : params.sessionID ,
messageID : params.messageID ,
} )
return c . json ( message )
} ,
)
2026-02-25 14:25:26 +00:00
. delete (
"/:sessionID/message/:messageID" ,
describeRoute ( {
summary : "Delete message" ,
description :
"Permanently delete a specific message (and all of its parts) from a session. This does not revert any file changes that may have been made while processing the message." ,
operationId : "session.deleteMessage" ,
responses : {
200 : {
description : "Successfully deleted message" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-03-11 23:30:17 +00:00
messageID : MessageID.zod ,
2026-02-25 14:25:26 +00:00
} ) ,
) ,
async ( c ) = > {
const params = c . req . valid ( "param" )
SessionPrompt . assertNotBusy ( params . sessionID )
await Session . removeMessage ( {
sessionID : params.sessionID ,
messageID : params.messageID ,
} )
return c . json ( true )
} ,
)
2026-01-16 21:21:13 +00:00
. delete (
"/:sessionID/message/:messageID/part/:partID" ,
describeRoute ( {
description : "Delete a part from a message" ,
operationId : "part.delete" ,
responses : {
200 : {
description : "Successfully deleted part" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-03-11 23:30:17 +00:00
messageID : MessageID.zod ,
2026-03-11 23:40:50 +00:00
partID : PartID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
async ( c ) = > {
const params = c . req . valid ( "param" )
await Session . removePart ( {
sessionID : params.sessionID ,
messageID : params.messageID ,
partID : params.partID ,
} )
return c . json ( true )
} ,
)
. patch (
"/:sessionID/message/:messageID/part/:partID" ,
describeRoute ( {
description : "Update a part in a message" ,
operationId : "part.update" ,
responses : {
200 : {
description : "Successfully updated part" ,
content : {
"application/json" : {
schema : resolver ( MessageV2 . Part ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-03-11 23:30:17 +00:00
messageID : MessageID.zod ,
2026-03-11 23:40:50 +00:00
partID : PartID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , MessageV2 . Part ) ,
async ( c ) = > {
const params = c . req . valid ( "param" )
const body = c . req . valid ( "json" )
if ( body . id !== params . partID || body . messageID !== params . messageID || body . sessionID !== params . sessionID ) {
throw new Error (
` Part mismatch: body.id=' ${ body . id } ' vs partID=' ${ params . partID } ', body.messageID=' ${ body . messageID } ' vs messageID=' ${ params . messageID } ', body.sessionID=' ${ body . sessionID } ' vs sessionID=' ${ params . sessionID } ' ` ,
)
}
const part = await Session . updatePart ( body )
return c . json ( part )
} ,
)
. post (
"/:sessionID/message" ,
describeRoute ( {
summary : "Send message" ,
description : "Create and send a new message to a session, streaming the AI response." ,
operationId : "session.prompt" ,
responses : {
200 : {
description : "Created message" ,
content : {
"application/json" : {
schema : resolver (
z . object ( {
info : MessageV2.Assistant ,
parts : MessageV2.Part.array ( ) ,
} ) ,
) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , SessionPrompt . PromptInput . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
c . status ( 200 )
c . header ( "Content-Type" , "application/json" )
return stream ( c , async ( stream ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
const msg = await SessionPrompt . prompt ( { . . . body , sessionID } )
stream . write ( JSON . stringify ( msg ) )
} )
} ,
)
. post (
"/:sessionID/prompt_async" ,
describeRoute ( {
summary : "Send async message" ,
description :
"Create and send a new message to a session asynchronously, starting the session if needed and returning immediately." ,
operationId : "session.prompt_async" ,
responses : {
204 : {
description : "Prompt accepted" ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , SessionPrompt . PromptInput . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
c . status ( 204 )
c . header ( "Content-Type" , "application/json" )
return stream ( c , async ( ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
SessionPrompt . prompt ( { . . . body , sessionID } )
} )
} ,
)
. post (
"/:sessionID/command" ,
describeRoute ( {
summary : "Send command" ,
description : "Send a new command to a session for execution by the AI assistant." ,
operationId : "session.command" ,
responses : {
200 : {
description : "Created message" ,
content : {
"application/json" : {
schema : resolver (
z . object ( {
info : MessageV2.Assistant ,
parts : MessageV2.Part.array ( ) ,
} ) ,
) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , SessionPrompt . CommandInput . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
const msg = await SessionPrompt . command ( { . . . body , sessionID } )
return c . json ( msg )
} ,
)
. post (
"/:sessionID/shell" ,
describeRoute ( {
summary : "Run shell command" ,
description : "Execute a shell command within the session context and return the AI's response." ,
operationId : "session.shell" ,
responses : {
200 : {
description : "Created message" ,
content : {
"application/json" : {
schema : resolver ( MessageV2 . Assistant ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , SessionPrompt . ShellInput . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const body = c . req . valid ( "json" )
const msg = await SessionPrompt . shell ( { . . . body , sessionID } )
return c . json ( msg )
} ,
)
. post (
"/:sessionID/revert" ,
describeRoute ( {
summary : "Revert message" ,
description : "Revert a specific message in a session, undoing its effects and restoring the previous state." ,
operationId : "session.revert" ,
responses : {
200 : {
description : "Updated session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , SessionRevert . RevertInput . omit ( { sessionID : true } ) ) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
log . info ( "revert" , c . req . valid ( "json" ) )
const session = await SessionRevert . revert ( {
sessionID ,
. . . c . req . valid ( "json" ) ,
} )
return c . json ( session )
} ,
)
. post (
"/:sessionID/unrevert" ,
describeRoute ( {
summary : "Restore reverted messages" ,
description : "Restore all previously reverted messages in a session." ,
operationId : "session.unrevert" ,
responses : {
200 : {
description : "Updated session" ,
content : {
"application/json" : {
schema : resolver ( Session . Info ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
async ( c ) = > {
const sessionID = c . req . valid ( "param" ) . sessionID
const session = await SessionRevert . unrevert ( { sessionID } )
return c . json ( session )
} ,
)
. post (
"/:sessionID/permissions/:permissionID" ,
describeRoute ( {
summary : "Respond to permission" ,
deprecated : true ,
description : "Approve or deny a permission request from the AI assistant." ,
operationId : "permission.respond" ,
responses : {
200 : {
description : "Permission processed successfully" ,
content : {
"application/json" : {
schema : resolver ( z . boolean ( ) ) ,
} ,
} ,
} ,
. . . errors ( 400 , 404 ) ,
} ,
} ) ,
validator (
"param" ,
z . object ( {
2026-03-11 23:16:56 +00:00
sessionID : SessionID.zod ,
2026-03-12 01:49:57 +00:00
permissionID : PermissionID.zod ,
2026-01-16 21:21:13 +00:00
} ) ,
) ,
validator ( "json" , z . object ( { response : PermissionNext.Reply } ) ) ,
async ( c ) = > {
const params = c . req . valid ( "param" )
PermissionNext . reply ( {
requestID : params.permissionID ,
reply : c.req.valid ( "json" ) . response ,
} )
return c . json ( true )
} ,
) ,
)