Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,6 @@ LIVEKIT_API_SECRET=
AI_PROVIDER=anthropic
AI_MODEL=claude-sonnet-4-20250514
AI_EFFORT=medium
AI_API_KEY=
AI_API_KEY=
# If blank default is used
OPENAI_BASE_URL=https://openrouter.ai/api/v1
119 changes: 78 additions & 41 deletions src/core/systems/ServerAI.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,68 +178,105 @@ export class ServerAI extends System {

class OpenAIClient {
constructor(apiKey, model, effort) {
this.client = new OpenAI({ apiKey })
const config = { apiKey }

// Check for custom base URL override
const baseURL = process.env.OPENAI_BASE_URL
if (baseURL) {
config.baseURL = baseURL
}

this.client = new OpenAI(config)
this.model = model
this.effort = effort
}


async create(prompt) {
const resp = await this.client.responses.create({
const resp = await this.client.chat.completions.create({
model: this.model,
reasoning: { effort: this.effort },
// max_output_tokens: 8192,
instructions: `
${docs}
===============
You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`,
input: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`,
max_tokens: 8192,
messages: [
{
role: 'system',
content: `
${docs}
===============
You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`,
},
{
role: 'user',
content: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`,
},
],
})
return resp.output_text
return resp.choices[0].message.content
}

async edit(code, prompt) {
const resp = await this.client.responses.create({
const resp = await this.client.chat.completions.create({
model: this.model,
reasoning: { effort: this.effort },
// max_output_tokens: 8192,
instructions: `
${docs}
===============
You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.
Here is the existing script that you will be working with:
===============
${code}`,
input: `Please edit the code above to satisfy the following request:\n\n"${prompt}"`,
max_tokens: 8192,
messages: [
{
role: 'system',
content: `
${docs}
===============
You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.
Here is the existing script that you will be working with:
===============
${code}`,
},
{
role: 'user',
content: `Please edit the code above to satisfy the following request:\n\n"${prompt}"`,
},
],
})
return resp.output_text
return resp.choices[0].message.content
}

async fix(code, error) {
const resp = await this.client.responses.create({
const resp = await this.client.chat.completions.create({
model: this.model,
reasoning: { effort: this.effort },
// max_output_tokens: 8192,
instructions: `
${docs}
===============
You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.
Here is the existing script that you will be working with:
===============
${code}`,
input: `This code has an error please fix it:\n\n"${JSON.stringify(error, null, 2)}"`,
max_tokens: 8192,
messages: [
{
role: 'system',
content: `
${docs}
===============
You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.
Here is the existing script that you will be working with:
===============
${code}`,
},
{
role: 'user',
content: `This code has an error please fix it:\n\n"${JSON.stringify(error, null, 2)}"`,
},
],
})
return resp.output_text
return resp.choices[0].message.content
}

async classify(prompt) {
const resp = await this.client.responses.create({
const resp = await this.client.chat.completions.create({
model: this.model,
reasoning: { effort: this.effort },
// max_output_tokens: 8192,
instructions: `You are a classifier. We will give you a prompt that a user has entered to generate a 3D object and your job is respond with a short name for the object. For example if someone prompts "a cool gamer desk with neon lights" you would respond with something like "Gamer Desk" because it is a short descriptive name that captures the essence of the object.`,
input: `Please classify the following prompt:\n\n"${prompt}"`,
max_tokens: 8192,
messages: [
{
role: 'system',
content: `You are a classifier. We will give you a prompt that a user has entered to generate a 3D object and your job is respond with a short name for the object. For example if someone prompts "a cool gamer desk with neon lights" you would respond with something like "Gamer Desk" because it is a short descriptive name that captures the essence of the object.`,
},
{
role: 'user',
content: `Please classify the following prompt:\n\n"${prompt}"`,
},
],
})
return resp.output_text
return resp.choices[0].message.content
}
}

Expand Down Expand Up @@ -552,4 +589,4 @@ class XAIClient {
const data = await resp.json()
return data.choices[0].message.content
}
}
}