1- import type { AgentInputItem , Session } from '@openai/agents' ;
2- import { protocol } from '@openai/agents' ;
3- import * as fs from 'node:fs/promises' ;
4- import * as path from 'node:path' ;
5- import { randomUUID } from 'node:crypto' ;
6-
7- export type FileSessionOptions = {
8- /**
9- * Directory where session files are stored. Defaults to `./.agents-sessions`.
10- */
11- dir ?: string ;
12- /**
13- * Optional pre-existing session id to bind to.
14- */
15- sessionId ?: string ;
16- } ;
17-
18- /**
19- * A simple filesystem-backed Session implementation that stores history as a JSON array.
20- */
21- export class FileSession implements Session {
22- #dir: string ;
23- #sessionId?: string ;
24-
25- constructor ( options : FileSessionOptions = { } ) {
26- this . #dir = options . dir ?? path . resolve ( process . cwd ( ) , '.agents-sessions' ) ;
27- this . #sessionId = options . sessionId ;
28- }
29-
30- /**
31- * Get the current session id, creating one if necessary.
32- */
33- async getSessionId ( ) : Promise < string > {
34- if ( ! this . #sessionId) {
35- // Compact, URL-safe-ish id without dashes.
36- this . #sessionId = randomUUID ( ) . replace ( / - / g, '' ) . slice ( 0 , 24 ) ;
37- }
38- await this . #ensureDir( ) ;
39- // Ensure the file exists.
40- const file = this . #filePath( this . #sessionId) ;
41- try {
42- await fs . access ( file ) ;
43- } catch {
44- await fs . writeFile ( file , '[]' , 'utf8' ) ;
45- }
46- return this . #sessionId;
47- }
48-
49- /**
50- * Retrieve items from the conversation history.
51- */
52- async getItems ( limit ?: number ) : Promise < AgentInputItem [ ] > {
53- const sessionId = await this . getSessionId ( ) ;
54- const items = await this . #readItems( sessionId ) ;
55- if ( typeof limit === 'number' && limit >= 0 ) {
56- return items . slice ( - limit ) ;
57- }
58- return items ;
59- }
60-
61- /**
62- * Append new items to the conversation history.
63- */
64- async addItems ( items : AgentInputItem [ ] ) : Promise < void > {
65- if ( ! items . length ) return ;
66- const sessionId = await this . getSessionId ( ) ;
67- const current = await this . #readItems( sessionId ) ;
68- const next = current . concat ( items ) ;
69- await this . #writeItems( sessionId , next ) ;
70- }
71-
72- /**
73- * Remove and return the most recent item, if any.
74- */
75- async popItem ( ) : Promise < AgentInputItem | undefined > {
76- const sessionId = await this . getSessionId ( ) ;
77- const items = await this . #readItems( sessionId ) ;
78- if ( items . length === 0 ) return undefined ;
79- const popped = items . pop ( ) ;
80- await this . #writeItems( sessionId , items ) ;
81- return popped ;
82- }
83-
84- /**
85- * Delete all stored items and reset the session state.
86- */
87- async clearSession ( ) : Promise < void > {
88- if ( ! this . #sessionId) return ; // Nothing to clear.
89- const file = this . #filePath( this . #sessionId) ;
90- try {
91- await fs . unlink ( file ) ;
92- } catch {
93- // Ignore if already removed or inaccessible.
94- }
95- this . #sessionId = undefined ;
96- }
97-
98- // Internal helpers
99- async #ensureDir( ) : Promise < void > {
100- await fs . mkdir ( this . #dir, { recursive : true } ) ;
101- }
102-
103- #filePath( sessionId : string ) : string {
104- return path . join ( this . #dir, `${ sessionId } .json` ) ;
105- }
106-
107- async #readItems( sessionId : string ) : Promise < AgentInputItem [ ] > {
108- const file = this . #filePath( sessionId ) ;
109- try {
110- const data = await fs . readFile ( file , 'utf8' ) ;
111- const parsed = JSON . parse ( data ) ;
112- if ( ! Array . isArray ( parsed ) ) return [ ] ;
113- // Validate and coerce items to the protocol shape where possible.
114- const result : AgentInputItem [ ] = [ ] ;
115- for ( const raw of parsed ) {
116- const check = protocol . ModelItem . safeParse ( raw ) ;
117- if ( check . success ) {
118- result . push ( check . data as AgentInputItem ) ;
119- }
120- // Silently skip invalid entries.
121- }
122- return result ;
123- } catch ( err : any ) {
124- // On missing file, return empty list.
125- if ( err && ( err . code === 'ENOENT' || err . code === 'ENOTDIR' ) ) return [ ] ;
126- // For other errors, rethrow.
127- throw err ;
128- }
129- }
130-
131- async #writeItems( sessionId : string , items : AgentInputItem [ ] ) : Promise < void > {
132- await this . #ensureDir( ) ;
133- const file = this . #filePath( sessionId ) ;
134- // Keep JSON compact but deterministic.
135- await fs . writeFile ( file , JSON . stringify ( items , null , 2 ) , 'utf8' ) ;
136- }
137- }
138-
139- import { Agent , run } from '@openai/agents' ;
1+ import { Agent , run , tool } from '@openai/agents' ;
2+ import { FileSession } from './sessions' ;
3+ import { z } from 'zod' ;
4+
5+ const lookupCustomerProfile = tool ( {
6+ name : 'lookup_customer_profile' ,
7+ description :
8+ 'Look up stored profile details for a customer by their internal id.' ,
9+ parameters : z . object ( {
10+ id : z
11+ . string ( )
12+ . describe ( 'The internal identifier for the customer to retrieve.' ) ,
13+ } ) ,
14+ async execute ( { id } ) {
15+ const directory : Record < string , string > = {
16+ '1' : 'Customer 1 (tier gold). Notes: Prefers concise replies.' ,
17+ '2' : 'Customer 2 (tier standard). Notes: Interested in tutorials.' ,
18+ } ;
19+ return directory [ id ] ?? `No customer found for id ${ id } .` ;
20+ } ,
21+ } ) ;
14022
14123async function main ( ) {
14224 const agent = new Agent ( {
14325 name : 'Assistant' ,
144- instructions : 'You are a helpful assistant. be VERY concise.' ,
26+ instructions : 'You are a helpful assistant.' ,
27+ modelSettings : { toolChoice : 'required' } ,
28+ tools : [ lookupCustomerProfile ] ,
14529 } ) ;
14630
14731 const session = new FileSession ( { dir : './tmp/' } ) ;
@@ -161,7 +45,9 @@ async function main() {
16145async function mainStream ( ) {
16246 const agent = new Agent ( {
16347 name : 'Assistant' ,
164- instructions : 'You are a helpful assistant. be VERY concise.' ,
48+ instructions : 'You are a helpful assistant.' ,
49+ modelSettings : { toolChoice : 'required' } ,
50+ tools : [ lookupCustomerProfile ] ,
16551 } ) ;
16652
16753 const session = new FileSession ( { dir : './tmp/' } ) ;
0 commit comments