Skip to content
Draft
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
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions convex/action/lifecycle/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})),
});
}
Expand Down
37 changes: 29 additions & 8 deletions convex/action/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const _add = internalMutation({
owner,
depth,
shouldReopen,
skills: [{ skillKey, args }],
skills: [{ skillKey, args, status: 'enqueued' }],
});

return actionIds[0];
Expand All @@ -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(),
}),
),
},
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions convex/action/public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const act = mutation({
author: currentUser._id,
owner: currentUser._id,
shouldReopen,
status: 'enqueued',
});
},
});
Expand Down
40 changes: 39 additions & 1 deletion convex/magicRock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -134,6 +159,10 @@ export async function _askMagicRock(args: MagicRockContext) {
usage,
warnings,
providerMetadata,
reasoning,
reasoningDetails,
sources,
files,
};

console.debug('askMagicRock', result);
Expand Down Expand Up @@ -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),
Expand All @@ -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'),
Expand Down
2 changes: 2 additions & 0 deletions convex/schedules/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const _executeOneTime = internalMutation({
skillKey,
args,
depth,
status: 'enqueued',
});

await ctx.db.delete(scheduleId);
Expand Down Expand Up @@ -55,6 +56,7 @@ export const _executeRecurring = internalMutation({
skillKey,
args,
depth,
status: 'enqueued',
});

const nextRunAt = computeNextRun(cronExpression, timeZone);
Expand Down
2 changes: 1 addition & 1 deletion convex/schemas/actionSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
});

Expand Down
13 changes: 13 additions & 0 deletions convex/schemas/skillSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',

Expand All @@ -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',
Expand Down Expand Up @@ -140,6 +145,12 @@ export function pricingFor(model: z.infer<typeof modelsSchema>): {
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':
Expand All @@ -166,6 +177,8 @@ export function pricingFor(model: z.infer<typeof modelsSchema>): {
// 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':
Expand Down
21 changes: 20 additions & 1 deletion convex/skills/createAITool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export function createAITool(
usage,
warnings,
providerMetadata,
reasoning,
reasoningDetails,
sources,
files,
//
} = await _askMagicRock(context);

Expand All @@ -55,6 +59,7 @@ export function createAITool(
author: action._id,
owner: task.owner,
depth: action.depth + 1,
status: 'enqueued',
});

let reason = finishReason;
Expand All @@ -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':
Expand Down Expand Up @@ -94,14 +112,15 @@ export function createAITool(
author: action._id,
owner: task.owner,
depth: action.depth + 1,
status: 'enqueued',
});
break;

// prettier-ignore
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;
Expand Down
6 changes: 5 additions & 1 deletion convex/skills/createReactions.ts
Original file line number Diff line number Diff line change
@@ -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'>,
Expand All @@ -7,7 +9,8 @@ export function createReactions(
args: Record<string, any>;
condition?: 'owner' | 'companion' | 'any';
}>,
) {
): Array<z.infer<typeof newActionSchema>> {
//
return (reactions ?? [])
.filter((reaction) => {
// prettier-ignore
Expand All @@ -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,
}));
}
56 changes: 56 additions & 0 deletions convex/skills/public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down
4 changes: 4 additions & 0 deletions convex/tasks/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
];

Expand Down Expand Up @@ -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(),
}),
),
},
Expand Down
Loading