Skip to content

Instantly share code, notes, and snippets.

@dikamilo
Created June 9, 2025 16:03
Show Gist options
  • Save dikamilo/337d872694834a85460200a1f5ad63b3 to your computer and use it in GitHub Desktop.
Save dikamilo/337d872694834a85460200a1f5ad63b3 to your computer and use it in GitHub Desktop.
import { readdir } from 'fs/promises'
import { promises as fs } from 'node:fs'
import { join } from 'path'
import { HeadquartersService, ReportResponse } from '@core/headquarters'
import { logger } from '@core/logger'
import { OpenAIModel, OpenAIService } from '@core/openai'
import { extractResultTag } from '@core/text'
import { questionSystemPrompt } from './agent.prompt'
import { QuestionResponse, State } from './types'
const DOCUMENTS_DIR_PATH = join(__dirname, 'files/facts')
export class AgentService {
private readonly agentKey: string
private readonly openAIService: OpenAIService
private readonly headquartersService: HeadquartersService
private state: State
private static readonly REPORT_TYPE = 'phone'
constructor(agentKey: string) {
this.agentKey = agentKey
this.openAIService = new OpenAIService()
this.headquartersService = new HeadquartersService()
this.state = {
facts: [],
transcriptions: {},
questions: [],
answered: [],
config: {
max_steps: 10,
current_step: 0,
},
}
}
async initialize() {
logger.info('⚙️ Initializing...')
logger.info('⚙️ Loading facts...')
this.state.facts = await this.loadFacts()
logger.info('⚙️ Retrieving questions and transcriptions...')
this.state.questions = await this.headquartersService.retrievePhonesQuestions(this.agentKey)
this.state.transcriptions = await this.headquartersService.retrievePhonesTranscriptions(
this.agentKey
)
}
private async processQuestions() {
for (const question of this.state.questions) {
logger.info('❓ Processing question: ', question.question)
const prompt = questionSystemPrompt(
this.state.facts,
this.state.transcriptions,
this.state.answered
)
const response = await this.openAIService.completion(
[
{
role: 'system',
content: prompt,
},
{ role: 'user', content: JSON.stringify(question) },
],
OpenAIModel.GPT41,
false,
false
)
const answer = JSON.parse(
extractResultTag(response.choices[0].message.content as string)
) as QuestionResponse
logger.info(` 🧠 Thinking: ${answer._thinking}`)
if (answer.answer || !answer.action?.name) {
logger.info(` 👉 Answer: ${answer.answer}`)
this.state.answered.push({
...question,
answer: answer.answer || '',
})
}
if (answer.action?.name) {
logger.info(' 🔧 Additional action required: ', answer.action.name)
const { parameters } = answer.action || {}
const apiResponse = await this.check_api_endpoint(parameters?.url, parameters?.password)
this.state.answered.push({
...question,
answer: apiResponse,
})
}
}
}
async correctQuestion(message: string) {
logger.info('😤 Correcting question...')
const prompt = questionSystemPrompt(
this.state.facts,
this.state.transcriptions,
this.state.answered
)
const response = await this.openAIService.completion(
[
{
role: 'system',
content: prompt,
},
{ role: 'user', content: message },
],
OpenAIModel.GPT41,
false,
false
)
const answer = JSON.parse(
extractResultTag(response.choices[0].message.content as string)
) as QuestionResponse
logger.info(` 🧠 Thinking: ${answer._thinking}`)
await Promise.all(
this.state.answered.map(async question => {
if (question.index === answer.question_index) {
if (answer.answer || !answer.action?.name) {
logger.info(` 👉 Answer: ${answer.answer}`)
question.answer = answer.answer!
}
if (answer.action?.name) {
logger.info(' 🔧 Additional action required: ', answer.action.name)
const { parameters } = answer.action || {}
question.answer = await this.check_api_endpoint(parameters?.url, parameters?.password)
}
}
return question
})
)
}
async process() {
await this.processQuestions()
logger.info('✅ Questions processed successfully!')
for (let i = 0; i < this.state.config.max_steps; i++) {
this.state.config.current_step++
const payload = this.state.answered.reduce(
(acc, item, index) => {
const key = String(index + 1).padStart(2, '0') as string
acc[key] = item.answer
return acc
},
{} as { [index: string]: string }
)
const reportResponse = await this.headquartersService.report(
this.agentKey,
AgentService.REPORT_TYPE,
payload
)
if (reportResponse.code === 0) {
logger.info('✅ Report submitted successfully:', reportResponse.message)
break
}
logger.error(`🤦 Aw, shit! Here we go again: ${reportResponse.message}`)
await this.correctQuestion(reportResponse.message)
}
}
private async check_api_endpoint(url: string, password: string) {
const response = await fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
password,
}),
})
const result = (await response.json()) as ReportResponse
logger.info(` 🌍 Endpoint response: ${result.message}`)
return result.message
}
private async loadFacts() {
const files = await readdir(DOCUMENTS_DIR_PATH)
return await Promise.all(
files.map(async fileName => await this.loadFile(join(DOCUMENTS_DIR_PATH, fileName)))
)
}
private async loadFile(filePath: string) {
const fileData = await fs.readFile(filePath)
return fileData.toString()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment