diff --git a/bun.lockb b/bun.lockb index bb03571..e648f20 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/convex/action/lifecycle/private.ts b/convex/action/lifecycle/private.ts index be55c8d..3e1a063 100644 --- a/convex/action/lifecycle/private.ts +++ b/convex/action/lifecycle/private.ts @@ -241,6 +241,8 @@ export const _resolve = internalMutation({ skills: result.reactions.map((reaction) => ({ skillKey: reaction.skillKey, args: reaction.args, + status: reaction.status, + result: reaction.result, })), }); } diff --git a/convex/action/private.ts b/convex/action/private.ts index 58a1546..f304d6e 100644 --- a/convex/action/private.ts +++ b/convex/action/private.ts @@ -22,7 +22,7 @@ export const _add = internalMutation({ owner, depth, shouldReopen, - skills: [{ skillKey, args }], + skills: [{ skillKey, args, status: 'enqueued' }], }); return actionIds[0]; @@ -39,6 +39,8 @@ export const _addMany = internalMutation({ z.object({ skillKey: z.string().describe('The key of the skill to use'), args: z.record(z.any()), + status: z.enum(['enqueued', 'succeeded']), + result: z.string().optional(), }), ), }, @@ -53,22 +55,41 @@ export const _addMany = internalMutation({ // reopen if needed and requested if (!task.isActive && shouldReopen) { - skills.unshift({ skillKey: 'reopen', args: {} }); + skills.unshift({ skillKey: 'reopen', args: {}, status: 'enqueued' }); } const actionIds = await Promise.all( - skills.map((skill) => - ctx.db.insert('actions', { + skills.map((skill) => { + if (skill.status === 'enqueued') { + return ctx.db.insert('actions', { + taskId, + author, + owner, + depth, + status: 'enqueued', + result: null, + skillKey: skill.skillKey, + args: skill.args, + }); + } + + if (!skill.result) throw new Error('Skill result is required for succeeded actions.'); + + return ctx.db.insert('actions', { taskId, author, owner, depth, - status: 'enqueued', - result: null, + status: skill.status, + result: { + text: skill.result, + reactions: [], + }, skillKey: skill.skillKey, args: skill.args, - }), - ), + costs: [], + }); + }), ); await _runNextActionIfNeeded(ctx, taskId); diff --git a/convex/action/public.ts b/convex/action/public.ts index fc5a828..3c2eb7b 100644 --- a/convex/action/public.ts +++ b/convex/action/public.ts @@ -26,6 +26,7 @@ export const act = mutation({ author: currentUser._id, owner: currentUser._id, shouldReopen, + status: 'enqueued', }); }, }); diff --git a/convex/magicRock.tsx b/convex/magicRock.tsx index 1cea2d7..579e4c2 100644 --- a/convex/magicRock.tsx +++ b/convex/magicRock.tsx @@ -124,8 +124,33 @@ export async function _askMagicRock(args: MagicRockContext) { usage, warnings, providerMetadata, + reasoning, + reasoningDetails, + sources, + files, // - } = await generateText(args); + } = await generateText({ + ...args, + providerOptions: { + openai: { + reasoningEffort: 'high', + reasoningSummary: 'detailed', + }, + openrouter: { + reasoning: { effort: 'high' }, + provider: { + // only: ['baseten'], // "Not Found", no tools support + // only: ['novitaai'], // "Not Found", no tools support + // only: ['together'], // broken, possibly related to Harmony. + // only: ['fireworks'], // sort of works, but no nice. Possibly related to Harmony. + // only: ['parasail'], // "Not Found", no tools support + only: ['groq'], // the best yet, but not reliable. + allow_fallbacks: false, + require_parameters: true, + }, + }, + }, + }); const result = { finishReason, @@ -134,6 +159,10 @@ export async function _askMagicRock(args: MagicRockContext) { usage, warnings, providerMetadata, + reasoning, + reasoningDetails, + sources, + files, }; console.debug('askMagicRock', result); @@ -174,6 +203,9 @@ function languageModelFrom( // OpenAI // 'openai/gpt-4o': openai('gpt-4o', openAIconfig), // 'openai/gpt-4o-mini': openai('gpt-4o-mini', openAIconfig), + 'openai/gpt-5': openai('gpt-5', openAIconfig), + 'openai/gpt-5-mini': openai('gpt-5-mini', openAIconfig), + 'openai/gpt-5-nano': openai('gpt-5-nano', openAIconfig), 'openai/gpt-4.1': openai('gpt-4.1', openAIconfig), 'openai/gpt-4.1-mini': openai('gpt-4.1-mini', openAIconfig), 'openai/gpt-4.1-nano': openai('gpt-4.1-nano', openAIconfig), @@ -193,6 +225,12 @@ function languageModelFrom( // 'groq/llama-4-scout': groq('meta-llama/llama-4-scout-17b-16e-instruct'), // 'groq/llama-4-maverick': groq('meta-llama/llama-4-maverick-17b-128e-instruct'), 'groq/qwen3-32b': groq('qwen/qwen3-32b'), + // 'openai/gpt-oss-120b': openrouter('openai/gpt-oss-120b', { + // // reasoning: { enabled: false, effort: 'high' }, + // }), + // 'openai/gpt-oss-20b': openrouter('openai/gpt-oss-20b', { + // // reasoning: { enabled: false, effort: 'high' }, + // }), // DeepSeek 'deepseek/deepseek-v3': deepseek('deepseek-chat'), diff --git a/convex/schedules/lifecycle.ts b/convex/schedules/lifecycle.ts index 7196d51..fe72f35 100644 --- a/convex/schedules/lifecycle.ts +++ b/convex/schedules/lifecycle.ts @@ -28,6 +28,7 @@ export const _executeOneTime = internalMutation({ skillKey, args, depth, + status: 'enqueued', }); await ctx.db.delete(scheduleId); @@ -55,6 +56,7 @@ export const _executeRecurring = internalMutation({ skillKey, args, depth, + status: 'enqueued', }); const nextRunAt = computeNextRun(cronExpression, timeZone); diff --git a/convex/schemas/actionSchema.tsx b/convex/schemas/actionSchema.tsx index 0ed0dde..913077c 100644 --- a/convex/schemas/actionSchema.tsx +++ b/convex/schemas/actionSchema.tsx @@ -10,7 +10,7 @@ export const newActionSchema = z.object({ skillKey: z.string().describe('The key of the skill to use'), args: z.record(z.any()), depth: z.number().min(0).max(1000), - status: z.enum(['enqueued', 'succeeded']).default('enqueued').optional(), + status: z.enum(['enqueued', 'succeeded']).default('enqueued'), result: z.string().optional(), }); diff --git a/convex/schemas/skillSchema.tsx b/convex/schemas/skillSchema.tsx index 3710347..a9c7190 100644 --- a/convex/schemas/skillSchema.tsx +++ b/convex/schemas/skillSchema.tsx @@ -68,6 +68,9 @@ export const modelsSchema = z.enum([ 'openai/gpt-4.1', 'openai/gpt-4.1-mini', 'openai/gpt-4.1-nano', + 'openai/gpt-5', + 'openai/gpt-5-mini', + 'openai/gpt-5-nano', 'openai/gpt-oss-120b', 'openai/gpt-oss-20b', @@ -84,6 +87,8 @@ export const modelsSchema = z.enum([ // 'groq/llama-4-scout', // 'groq/llama-4-maverick', 'groq/qwen3-32b', + 'openai/gpt-oss-120b', + // 'openai/gpt-oss-20b', // DeepSeek 'deepseek/deepseek-v3', @@ -140,6 +145,12 @@ export function pricingFor(model: z.infer): { return pricePerMillionTokens({ input: 0.4, output: 1.6 }); case 'openai/gpt-4.1-nano': return pricePerMillionTokens({ input: 0.1, output: 0.4 }); + case 'openai/gpt-5': + return pricePerMillionTokens({ input: 1.25, output: 10 }); + case 'openai/gpt-5-mini': + return pricePerMillionTokens({ input: 0.25, output: 2 }); + case 'openai/gpt-5-nano': + return pricePerMillionTokens({ input: 0.05, output: 0.4 }); case 'openai/gpt-oss-120b': return pricePerMillionTokens({ input: 0.25, output: 0.75 }); case 'openai/gpt-oss-20b': @@ -166,6 +177,8 @@ export function pricingFor(model: z.infer): { // return pricePerMillionTokens({ input: 0.2, output: 0.6 }); case 'groq/qwen3-32b': return pricePerMillionTokens({ input: 0.29, output: 0.59 }); + // case 'openai/gpt-oss-20b': + // return pricePerMillionTokens({ input: 0.1, output: 0.5 }); // DeepSeek case 'deepseek/deepseek-v3': diff --git a/convex/skills/createAITool.ts b/convex/skills/createAITool.ts index be6affc..235ede8 100644 --- a/convex/skills/createAITool.ts +++ b/convex/skills/createAITool.ts @@ -40,6 +40,10 @@ export function createAITool( usage, warnings, providerMetadata, + reasoning, + reasoningDetails, + sources, + files, // } = await _askMagicRock(context); @@ -55,6 +59,7 @@ export function createAITool( author: action._id, owner: task.owner, depth: action.depth + 1, + status: 'enqueued', }); let reason = finishReason; @@ -65,6 +70,19 @@ export function createAITool( ); } + if (reasoning) { + reactions.push({ + skillKey: 'reason', + args: { reasoning }, + taskId: task._id, + author: action._id, + owner: task.owner, + depth: action.depth + 1, + status: 'succeeded', + result: reasoning, + }); + } + switch (reason) { // case 'tool-calls': @@ -94,6 +112,7 @@ export function createAITool( author: action._id, owner: task.owner, depth: action.depth + 1, + status: 'enqueued', }); break; @@ -101,7 +120,7 @@ export function createAITool( case 'stop': say(text); break; // prettier-ignore - case 'error': say(text); break; + case 'error': say(`Error: ${text}`); break; // prettier-ignore case 'content-filter': say(`[damn @sama] Content filter hit: ${warnings}`); break; diff --git a/convex/skills/createReactions.ts b/convex/skills/createReactions.ts index b09baa5..72d6bf1 100644 --- a/convex/skills/createReactions.ts +++ b/convex/skills/createReactions.ts @@ -1,4 +1,6 @@ +import { z } from 'zod'; import { Doc, Id } from '../_generated/dataModel'; +import { newActionSchema } from '../schemas/actionSchema'; export function createReactions( action: Doc<'actions'>, @@ -7,7 +9,8 @@ export function createReactions( args: Record; condition?: 'owner' | 'companion' | 'any'; }>, -) { +): Array> { + // return (reactions ?? []) .filter((reaction) => { // prettier-ignore @@ -24,5 +27,6 @@ export function createReactions( owner: action.owner, depth: action.depth + 1, author: action._id as Id<'actions'> | Id<'users'>, // I have no idea why I need that cast, as it expects a union of Id<'actions'> or Id<'users'> + status: 'enqueued' as const, })); } diff --git a/convex/skills/public.ts b/convex/skills/public.ts index 1323afb..07d0b8a 100644 --- a/convex/skills/public.ts +++ b/convex/skills/public.ts @@ -107,6 +107,42 @@ export const availableIntelligences = query({ return { default: env.DEFAULT_MODEL, recommended: [ + { + key: 'openai/gpt-5', + name: 'GPT-5', + provider: 'OpenAI', + description: 'Best performance per energy', + }, + { + key: 'openai/gpt-5-mini', + name: 'GPT-5 Mini', + provider: 'OpenAI', + description: 'Best performance per energy', + }, + { + key: 'openai/gpt-5-nano', + name: 'GPT-5 Nano', + provider: 'OpenAI', + description: 'Best performance per energy', + }, + { + key: 'openai/gpt-oss-120b', + name: 'GPT-OSS 120B', + provider: 'OpenAI', + description: 'Best performance per energy', + }, + // { + // key: 'openai/gpt-oss-20b', + // name: 'GPT-OSS 20B', + // provider: 'OpenAI', + // description: 'Best performance per energy', + // }, + { + key: 'anthropic/claude-4-sonnet', + name: 'Claude 4 Sonnet', + provider: 'Anthropic', + description: 'Best overall', + }, { key: 'moonshot/kimi-2', name: 'Kimi 2', @@ -151,6 +187,26 @@ export const availableIntelligences = query({ provider: 'Groq', description: 'Insanely faaaast, but not very smart', }, + { + key: 'openrouter/qwen-3-coder', + name: 'Qwen 3 Coder', + provider: 'OpenRouter', + }, + { + key: 'openrouter/GLM-4.5-Air', + name: 'GLM 4.5 Air', + provider: 'OpenRouter', + }, + { + key: 'openrouter/GLM-4.5', + name: 'GLM 4.5', + provider: 'OpenRouter', + }, + { + key: 'deepinfra/glm-4.5', + name: 'GLM 4.5', + provider: 'DeepInfra', + }, { key: 'cerebras/qwen3-235b', name: 'Qwen 235B', diff --git a/convex/tasks/private.ts b/convex/tasks/private.ts index c4eea6b..dd41514 100644 --- a/convex/tasks/private.ts +++ b/convex/tasks/private.ts @@ -131,12 +131,14 @@ export const _add = internalMutation({ { skillKey: 'increaseBudget', args: { amount: initialFunds, shouldIterate: false }, + status: 'enqueued' as const, }, ] : []), { skillKey: 'say', args: { message }, + status: 'enqueued' as const, }, ]; @@ -164,6 +166,8 @@ export const _addWithActions = internalMutation({ z.object({ skillKey: z.string().describe('The key of the skill to use'), args: z.record(z.any()), + status: z.enum(['enqueued', 'succeeded']), + result: z.string().optional(), }), ), }, diff --git a/convex/users/private.ts b/convex/users/private.ts index 5206608..6c25bf4 100644 --- a/convex/users/private.ts +++ b/convex/users/private.ts @@ -88,10 +88,12 @@ I'm also curious about Meseeks and would love to learn more about its capabiliti amount: asBigInt({ dollars: 1 }), shouldIterate: false, }, + status: 'enqueued' as const, }, { skillKey: 'lookAtMe', args: {}, + status: 'enqueued' as const, }, ], }); diff --git a/package.json b/package.json index 2daf0e5..9761008 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@vercel/analytics": "^1.4.1", "@vercel/speed-insights": "^1.1.0", "@vitejs/plugin-react": "^4.3.4", - "ai": "^4.3.9", + "ai": "^4.3.19", "caniuse-lite": "^1.0.30001721", "class-variance-authority": "^0.7.1", "clsx": "1.2.1",