Compare commits
4 Commits
131a45e305
...
46c9fe9fac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46c9fe9fac | ||
|
|
eb3f58b2e6 | ||
|
|
6e8a336143 | ||
|
|
839cea7fe6 |
69
cli2.js
69
cli2.js
@@ -16,16 +16,77 @@ modelDialog.on('reasoningUpdate', (output) => {
|
|||||||
//console.log(chalk.blue('reasoning event'),output);
|
//console.log(chalk.blue('reasoning event'),output);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// $ / 1million tokens
|
||||||
|
const price = {
|
||||||
|
'gpt-5-2025-08-07': {
|
||||||
|
input: 1.25,
|
||||||
|
cached: 0.125,
|
||||||
|
output: 10
|
||||||
|
},
|
||||||
|
'gpt-5-mini-2025-08-07': {
|
||||||
|
input: 0.25,
|
||||||
|
cached: 0.025,
|
||||||
|
output: 2
|
||||||
|
},
|
||||||
|
'gpt-5-nano-2025-08-07': {
|
||||||
|
input: 0.05,
|
||||||
|
cached: 0.005,
|
||||||
|
output: 0.4
|
||||||
|
},
|
||||||
|
'gpt-4.1-2025-04-14': {
|
||||||
|
input: 2,
|
||||||
|
cached: 0.5,
|
||||||
|
output: 8
|
||||||
|
},
|
||||||
|
'gpt-4.1-mini-2025-04-14': {
|
||||||
|
input: 0.4,
|
||||||
|
cached: 0.1,
|
||||||
|
output: 1.6
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
(async ()=>{
|
(async ()=>{
|
||||||
//const output = await modelDialog.interrogate('Can you remember "seven" ?');
|
//const output = await modelDialog.interrogate('Can you remember "seven" ?');
|
||||||
//console.log(output.output,JSON.stringify(output.reasoning,null,2));
|
//console.log(output.output,JSON.stringify(output.reasoning,null,2));
|
||||||
//const output2 = await modelDialog.interrogate('read a file that is what you remebered plus 1 as a word with txt ending, check that file.');
|
//const output2 = await modelDialog.interrogate('read a file that is what you remebered plus 1 as a word with txt ending, check that file.');
|
||||||
const output2 = await modelDialog.interrogate('schaue welche Dateien du findet und wenn du webseiten findest, invertiere die farben in ihnen.');
|
const output2 = await modelDialog.interrogate('Hi, use the list files tools and the read files tool on /readme.txt in same variations to test it. use the tools in parallel.');
|
||||||
console.log('final output:',output2.output);
|
console.log('final output:',output2.output);
|
||||||
console.log('reasoning:',output2.reasoning);
|
console.log('reasoning:',output2.reasoning);
|
||||||
console.log('Tokens:',output2.inputTokens,output2.cachedTokens,output2.outputTokens);
|
//Ti: { 'gpt-5-2025-08-07': 3019 } Tc: { 'gpt-5-2025-08-07': 0 } To: { 'gpt-5-2025-08-07': 751 }
|
||||||
|
console.log('Ti:',output2.inputTokens,'Tc:',output2.cachedTokens,'To:',output2.outputTokens);
|
||||||
|
// cost breakdown per model and totals (prices are per 1M tokens)
|
||||||
|
const perMillion = 1_000_000;
|
||||||
|
const models = new Set([
|
||||||
|
...Object.keys(output2.inputTokens || {}),
|
||||||
|
...Object.keys(output2.cachedTokens || {}),
|
||||||
|
...Object.keys(output2.outputTokens || {})
|
||||||
|
]);
|
||||||
|
|
||||||
|
let grandTotal = 0;
|
||||||
|
for (const model of models) {
|
||||||
|
const inputT = (output2.inputTokens || {})[model];
|
||||||
|
const cachedT = (output2.cachedTokens || {})[model];
|
||||||
|
const outputT = (output2.outputTokens || {})[model];
|
||||||
|
|
||||||
|
const p = price[model];
|
||||||
|
const inputCost = (typeof inputT === 'number' && p) ? (inputT / perMillion) * p.input : undefined;
|
||||||
|
const cachedCost = (typeof cachedT === 'number' && p) ? (cachedT / perMillion) * p.cached : undefined;
|
||||||
|
const outputCost = (typeof outputT === 'number' && p) ? (outputT / perMillion) * p.output : undefined;
|
||||||
|
|
||||||
|
const subtotal = [inputCost, cachedCost, outputCost].every(v => typeof v === 'number')
|
||||||
|
? (inputCost + cachedCost + outputCost)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (typeof subtotal === 'number') grandTotal += subtotal;
|
||||||
|
|
||||||
|
console.log('cost for', model, {
|
||||||
|
inputCost: parseFloat(inputCost.toFixed(6)),
|
||||||
|
cachedCost: parseFloat(cachedCost.toFixed(6)),
|
||||||
|
outputCost: parseFloat(outputCost.toFixed(6)),
|
||||||
|
subtotal: parseFloat(subtotal.toFixed(4))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('total cost:', grandTotal);
|
||||||
})()
|
})()
|
||||||
|
|||||||
@@ -56,9 +56,12 @@ class ModelDialog {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleUsage = (usage, model) => {
|
handleUsage = (usage, model) => {
|
||||||
this.inputTokens[model] = usage.input_tokens-usage.input_tokens_details.cached_tokens;
|
if (typeof this.inputTokens[model] !== 'number') this.inputTokens[model] = 0;
|
||||||
this.outputTokens[model] = usage.output_tokens;
|
if (typeof this.outputTokens[model] !== 'number') this.outputTokens[model] = 0;
|
||||||
this.cachedTokens[model] = usage.input_tokens_details.cached_tokens;
|
if (typeof this.cachedTokens[model] !== 'number') this.cachedTokens[model] = 0;
|
||||||
|
this.inputTokens[model] += usage.input_tokens - usage.input_tokens_details.cached_tokens;
|
||||||
|
this.outputTokens[model] += usage.output_tokens;
|
||||||
|
this.cachedTokens[model] += usage.input_tokens_details.cached_tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
on = (event, callback) => {
|
on = (event, callback) => {
|
||||||
@@ -85,17 +88,26 @@ class ModelDialog {
|
|||||||
|
|
||||||
do{
|
do{
|
||||||
const messagesToSend = this.messages.splice(0);
|
const messagesToSend = this.messages.splice(0);
|
||||||
|
console.log(chalk.blue('sending messages:'),messagesToSend.length);
|
||||||
|
//console.log(chalk.blue('messages:'),JSON.stringify(messagesToSend,null,2));
|
||||||
this.messagesSent.push(...messagesToSend);
|
this.messagesSent.push(...messagesToSend);
|
||||||
|
|
||||||
|
const model = 'gpt-5-mini';
|
||||||
|
|
||||||
const call = {
|
const call = {
|
||||||
model: 'gpt-5',
|
model: model,
|
||||||
input: messagesToSend,
|
input: messagesToSend,
|
||||||
text: { format: { type: 'text' }, verbosity: 'low' },
|
text: { format: { type: 'text' } },
|
||||||
reasoning: { effort: 'low', summary: 'detailed' },
|
|
||||||
tools: Object.values(toolsByFile).map(t => t.def),
|
tools: Object.values(toolsByFile).map(t => t.def),
|
||||||
store: true,
|
store: true,
|
||||||
previous_response_id: this.previousResponseId
|
previous_response_id: this.previousResponseId,
|
||||||
|
parallel_tool_calls: true
|
||||||
}
|
}
|
||||||
|
if(model.startsWith('gpt-5')){
|
||||||
|
call.reasoning = { effort: 'low', summary: 'detailed' };
|
||||||
|
//call.text.format.verbosity = 'low';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.currentStream = openai.responses.stream(call);
|
this.currentStream = openai.responses.stream(call);
|
||||||
this.currentStream.on('response.created', (event) => {
|
this.currentStream.on('response.created', (event) => {
|
||||||
@@ -127,6 +139,7 @@ class ModelDialog {
|
|||||||
|
|
||||||
|
|
||||||
this.currentStream.on('response.completed', async (event) => {
|
this.currentStream.on('response.completed', async (event) => {
|
||||||
|
//console.log(chalk.blue('response completed:'),event.response.usage);
|
||||||
this.handleUsage(event.response.usage, event.response.model);
|
this.handleUsage(event.response.usage, event.response.model);
|
||||||
outputs.push(...event.response.output);
|
outputs.push(...event.response.output);
|
||||||
|
|
||||||
|
|||||||
@@ -103,24 +103,24 @@ export default {
|
|||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
path: {
|
path: {
|
||||||
type: "string",
|
type: ["string", "null"],
|
||||||
description: "Directory or file path relative to the root. Use '/' for the root. Defaults to root if not specified.",
|
description: "Directory or file path relative to the root. Use '/' for the root. Defaults to root if not specified.",
|
||||||
},
|
},
|
||||||
depth: {
|
depth: {
|
||||||
type: "integer",
|
type: ["integer", "null"],
|
||||||
description: "Maximum subdirectory levels to traverse. Use -1 for unlimited depth. Defaults to 1.",
|
description: "Maximum subdirectory levels to traverse. Use -1 for unlimited depth. Defaults to 1.",
|
||||||
minimum: -1,
|
minimum: -1,
|
||||||
},
|
},
|
||||||
includeHidden: {
|
includeHidden: {
|
||||||
type: "boolean",
|
type: ["boolean", "null"],
|
||||||
description: "Whether to include hidden files and directories (starting with '.'). Defaults to false.",
|
description: "Whether to include hidden files and directories (starting with '.'). Defaults to false.",
|
||||||
default: false,
|
default: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
required: ["path", "depth", "includeHidden"],
|
required: [],
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
strict: true,
|
strict: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function run(args) {
|
export async function run(args) {
|
||||||
@@ -159,7 +159,10 @@ export async function run(args) {
|
|||||||
return { err: `Path does not exist${inputPath ? `: ${inputPath}` : ""}` };
|
return { err: `Path does not exist${inputPath ? `: ${inputPath}` : ""}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
const cwd = path.relative(chrootResolved, stat.isFile() ? path.dirname(resolvedBase) : resolvedBase) || ".";
|
const cwd = toDisplayPath(
|
||||||
|
stat.isFile() ? path.dirname(resolvedBase) : resolvedBase,
|
||||||
|
chrootResolved
|
||||||
|
);
|
||||||
|
|
||||||
// Handle single file case
|
// Handle single file case
|
||||||
if (stat.isFile()) {
|
if (stat.isFile()) {
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ const virtual_chroot = '/workspaces/aiTools/root';
|
|||||||
// Ensures reads are confined to `virtual_chroot`.
|
// Ensures reads are confined to `virtual_chroot`.
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
type: "function", name: "read_file", description: "read a file", strict: true,
|
type: "function", name: "read_file", description: "read a file", strict: false,
|
||||||
parameters: {
|
parameters: {
|
||||||
type: "object", required: ["path","linesToSkip","linesToRead"], additionalProperties: false, properties: {
|
type: "object", required: ["path"], additionalProperties: false, properties: {
|
||||||
path: { type: "string", description: "The path to the file to read.", },
|
path: { type: "string", description: "The path to the file to read.", },
|
||||||
linesToSkip: { type: "integer", description: "The number of lines to skip. Use 0 to read from the beginning.", minimum: 0 },
|
linesToSkip: { type: ["integer", "null"], description: "The number of lines to skip. Use 0 to read from the beginning, which is the default.", minimum: 0 },
|
||||||
linesToRead: { type: "integer", description: "1-400 The number of lines to read.", minimum: 1, maximum: 400 }
|
linesToRead: { type: ["integer", "null"], description: "1-400 The number of lines to read. 400 is the default.", minimum: 1, maximum: 400 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user