@@ -12,31 +12,29 @@ import {
1212 tool ,
1313 type Tool as AITool ,
1414 type LanguageModelUsage ,
15+ type UIMessage ,
1516} from "ai"
1617import { z , ZodSchema } from "zod"
1718import { Decimal } from "decimal.js"
1819
19- import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
20- import PROMPT_ANTHROPIC_SPOOF from "./prompt/anthropic_spoof.txt"
21- import PROMPT_TITLE from "./prompt/title.txt"
22- import PROMPT_SUMMARIZE from "./prompt/summarize.txt"
2320import PROMPT_INITIALIZE from "../session/prompt/initialize.txt"
2421
2522import { Share } from "../share/share"
2623import { Message } from "./message"
2724import { Bus } from "../bus"
2825import { Provider } from "../provider/provider"
29- import { SessionContext } from "./context"
30- import { ListTool } from "../tool/ls"
3126import { MCP } from "../mcp"
3227import { NamedError } from "../util/error"
28+ import type { Tool } from "../tool/tool"
29+ import { SystemPrompt } from "./system"
3330
3431export namespace Session {
3532 const log = Log . create ( { service : "session" } )
3633
3734 export const Info = z
3835 . object ( {
3936 id : Identifier . schema ( "session" ) ,
37+ parentID : Identifier . schema ( "session" ) . optional ( ) ,
4038 share : z
4139 . object ( {
4240 secret : z . string ( ) ,
@@ -79,10 +77,11 @@ export namespace Session {
7977 }
8078 } )
8179
82- export async function create ( ) {
80+ export async function create ( parentID ?: string ) {
8381 const result : Info = {
8482 id : Identifier . descending ( "session" ) ,
85- title : "New Session - " + new Date ( ) . toISOString ( ) ,
83+ parentID,
84+ title : "Child Session - " + new Date ( ) . toISOString ( ) ,
8685 time : {
8786 created : Date . now ( ) ,
8887 updated : Date . now ( ) ,
@@ -91,11 +90,12 @@ export namespace Session {
9190 log . info ( "created" , result )
9291 state ( ) . sessions . set ( result . id , result )
9392 await Storage . writeJSON ( "session/info/" + result . id , result )
94- share ( result . id ) . then ( ( share ) => {
95- update ( result . id , ( draft ) => {
96- draft . share = share
93+ if ( ! result . parentID )
94+ share ( result . id ) . then ( ( share ) => {
95+ update ( result . id , ( draft ) => {
96+ draft . share = share
97+ } )
9798 } )
98- } )
9999 Bus . publish ( Event . Updated , {
100100 info : result ,
101101 } )
@@ -186,12 +186,16 @@ export namespace Session {
186186 providerID : string
187187 modelID : string
188188 parts : Message . Part [ ]
189+ system ?: string [ ]
190+ tools ?: Tool . Info [ ]
189191 } ) {
190192 const l = log . clone ( ) . tag ( "session" , input . sessionID )
191193 l . info ( "chatting" )
192194 const model = await Provider . getModel ( input . providerID , input . modelID )
193195 let msgs = await messages ( input . sessionID )
194196 const previous = msgs . at ( - 1 )
197+
198+ // auto summarize if too long
195199 if ( previous ?. metadata . assistant ) {
196200 const tokens =
197201 previous . metadata . assistant . tokens . input +
@@ -214,95 +218,25 @@ export namespace Session {
214218 const lastSummary = msgs . findLast (
215219 ( msg ) => msg . metadata . assistant ?. summary === true ,
216220 )
217- if ( lastSummary )
218- msgs = msgs . filter (
219- ( msg ) => msg . role === "system" || msg . id >= lastSummary . id ,
220- )
221+ if ( lastSummary ) msgs = msgs . filter ( ( msg ) => msg . id >= lastSummary . id )
221222
223+ const app = App . info ( )
222224 if ( msgs . length === 0 ) {
223- const app = App . info ( )
224- if ( input . providerID === "anthropic" ) {
225- const claude : Message . Info = {
226- id : Identifier . ascending ( "message" ) ,
227- role : "system" ,
228- parts : [
229- {
230- type : "text" ,
231- text : PROMPT_ANTHROPIC_SPOOF . trim ( ) ,
232- } ,
233- ] ,
234- metadata : {
235- sessionID : input . sessionID ,
236- time : {
237- created : Date . now ( ) ,
238- } ,
239- tool : { } ,
240- } ,
241- }
242- await updateMessage ( claude )
243- msgs . push ( claude )
244- }
245- const system : Message . Info = {
246- id : Identifier . ascending ( "message" ) ,
247- role : "system" ,
248- parts : [
249- {
250- type : "text" ,
251- text : PROMPT_ANTHROPIC ,
252- } ,
253- {
254- type : "text" ,
255- text : [
256- `Here is some useful information about the environment you are running in:` ,
257- `<env>` ,
258- `Working directory: ${ app . path . cwd } ` ,
259- `Is directory a git repo: ${ app . git ? "yes" : "no" } ` ,
260- `Platform: ${ process . platform } ` ,
261- `Today's date: ${ new Date ( ) . toISOString ( ) } ` ,
262- `</env>` ,
263- `<project>` ,
264- `${ app . git ? await ListTool . execute ( { path : app . path . cwd , ignore : [ ] } , { sessionID : input . sessionID , abort : abort . signal } ) . then ( ( x ) => x . output ) : "" } ` ,
265- `</project>` ,
266- ] . join ( "\n" ) ,
267- } ,
268- ] ,
269- metadata : {
270- sessionID : input . sessionID ,
271- time : {
272- created : Date . now ( ) ,
273- } ,
274- tool : { } ,
275- } ,
276- }
277- const context = await SessionContext . find ( )
278- if ( context ) {
279- system . parts . push ( {
280- type : "text" ,
281- text : context ,
282- } )
283- }
284- msgs . push ( system )
285225 generateText ( {
286226 maxOutputTokens : 20 ,
287227 messages : convertToModelMessages ( [
288- {
289- role : "system" ,
290- parts : [
291- {
292- type : "text" ,
293- text : PROMPT_ANTHROPIC_SPOOF . trim ( ) ,
294- } ,
295- ] ,
296- } ,
297- {
298- role : "system" ,
299- parts : [
300- {
301- type : "text" ,
302- text : PROMPT_TITLE ,
303- } ,
304- ] ,
305- } ,
228+ ...SystemPrompt . title ( input . providerID ) . map (
229+ ( x ) : UIMessage => ( {
230+ id : Identifier . ascending ( "message" ) ,
231+ role : "system" ,
232+ parts : [
233+ {
234+ type : "text" ,
235+ text : x ,
236+ } ,
237+ ] ,
238+ } ) ,
239+ ) ,
306240 {
307241 role : "user" ,
308242 parts : input . parts ,
@@ -317,7 +251,6 @@ export namespace Session {
317251 } )
318252 } )
319253 . catch ( ( ) => { } )
320- await updateMessage ( system )
321254 }
322255 const msg : Message . Info = {
323256 role : "user" ,
@@ -334,12 +267,21 @@ export namespace Session {
334267 await updateMessage ( msg )
335268 msgs . push ( msg )
336269
270+ const system = input . system ?? SystemPrompt . provider ( input . providerID )
271+ system . push ( ...( await SystemPrompt . environment ( input . sessionID ) ) )
272+ system . push ( ...( await SystemPrompt . custom ( ) ) )
273+
337274 const next : Message . Info = {
338275 id : Identifier . ascending ( "message" ) ,
339276 role : "assistant" ,
340277 parts : [ ] ,
341278 metadata : {
342279 assistant : {
280+ system,
281+ path : {
282+ cwd : app . path . cwd ,
283+ root : app . path . root ,
284+ } ,
343285 cost : 0 ,
344286 tokens : {
345287 input : 0 ,
@@ -358,6 +300,7 @@ export namespace Session {
358300 }
359301 await updateMessage ( next )
360302 const tools : Record < string , AITool > = { }
303+
361304 for ( const item of await Provider . tools ( input . providerID ) ) {
362305 tools [ item . id . replaceAll ( "." , "_" ) ] = tool ( {
363306 id : item . id as any ,
@@ -369,6 +312,7 @@ export namespace Session {
369312 const result = await item . execute ( args , {
370313 sessionID : input . sessionID ,
371314 abort : abort . signal ,
315+ messageID : next . id ,
372316 } )
373317 next . metadata ! . tool ! [ opts . toolCallId ] = {
374318 ...result . metadata ,
@@ -395,6 +339,7 @@ export namespace Session {
395339 } ,
396340 } )
397341 }
342+
398343 for ( const [ key , item ] of Object . entries ( await MCP . tools ( ) ) ) {
399344 const execute = item . execute
400345 if ( ! execute ) continue
@@ -576,7 +521,21 @@ export namespace Session {
576521 toolCallStreaming : true ,
577522 abortSignal : abort . signal ,
578523 stopWhen : stepCountIs ( 1000 ) ,
579- messages : convertToModelMessages ( msgs ) ,
524+ messages : convertToModelMessages ( [
525+ ...system . map (
526+ ( x ) : UIMessage => ( {
527+ id : Identifier . ascending ( "message" ) ,
528+ role : "system" ,
529+ parts : [
530+ {
531+ type : "text" ,
532+ text : x ,
533+ } ,
534+ ] ,
535+ } ) ,
536+ ) ,
537+ ...msgs ,
538+ ] ) ,
580539 temperature : model . info . id === "codex-mini-latest" ? undefined : 0 ,
581540 tools : {
582541 ...( await MCP . tools ( ) ) ,
@@ -618,10 +577,11 @@ export namespace Session {
618577 const lastSummary = msgs . findLast (
619578 ( msg ) => msg . metadata . assistant ?. summary === true ,
620579 ) ?. id
621- const filtered = msgs . filter (
622- ( msg ) => msg . role !== "system" && ( ! lastSummary || msg . id >= lastSummary ) ,
623- )
580+ const filtered = msgs . filter ( ( msg ) => ! lastSummary || msg . id >= lastSummary )
624581 const model = await Provider . getModel ( input . providerID , input . modelID )
582+ const app = App . info ( )
583+ const system = SystemPrompt . summarize ( input . providerID )
584+
625585 const next : Message . Info = {
626586 id : Identifier . ascending ( "message" ) ,
627587 role : "assistant" ,
@@ -630,6 +590,11 @@ export namespace Session {
630590 tool : { } ,
631591 sessionID : input . sessionID ,
632592 assistant : {
593+ system,
594+ path : {
595+ cwd : app . path . cwd ,
596+ root : app . path . root ,
597+ } ,
633598 summary : true ,
634599 cost : 0 ,
635600 modelID : input . modelID ,
@@ -650,15 +615,18 @@ export namespace Session {
650615 abortSignal : abort . signal ,
651616 model : model . language ,
652617 messages : convertToModelMessages ( [
653- {
654- role : "system" ,
655- parts : [
656- {
657- type : "text" ,
658- text : PROMPT_SUMMARIZE ,
659- } ,
660- ] ,
661- } ,
618+ ...system . map (
619+ ( x ) : UIMessage => ( {
620+ id : Identifier . ascending ( "message" ) ,
621+ role : "system" ,
622+ parts : [
623+ {
624+ type : "text" ,
625+ text : x ,
626+ } ,
627+ ] ,
628+ } ) ,
629+ ) ,
662630 ...filtered ,
663631 {
664632 role : "user" ,
0 commit comments