diff --git a/src/lib/backend/convex/user_enabled_models.ts b/src/lib/backend/convex/user_enabled_models.ts index 764d3ec..a1bc3ce 100644 --- a/src/lib/backend/convex/user_enabled_models.ts +++ b/src/lib/backend/convex/user_enabled_models.ts @@ -28,7 +28,7 @@ export const get_enabled = query({ .withIndex('by_user', (q) => q.eq('user_id', session.userId)) .collect(); - return array.toMap(models, (m) => [getModelKey(m), m]); + return array.toRecord(models, (m) => [getModelKey(m), m]); }, }); diff --git a/src/lib/utils/array.ts b/src/lib/utils/array.ts index 07f315e..1162663 100644 --- a/src/lib/utils/array.ts +++ b/src/lib/utils/array.ts @@ -61,6 +61,34 @@ export function sum(arr: T[], fn: (item: T) => number): number { return total; } +/** Maps the provided array into a record + * + * @param arr Array of items to be entered into a record + * @param fn A mapping function to transform each item into a key value pair + * @returns + * + * ## Usage + * ```ts + * const record = toRecord([5, 4, 3, 2, 1], (item, i) => [i, item]); + * + * console.log(record); // { "0": 5, "1": 4, "2": 3, "3": 2, "4": 1 } + * ``` + */ +export function toRecord( + arr: T[], + fn: (item: T, index: number) => [key: string, value: V] +): Record { + const record: Record = {}; + + for (let i = 0; i < arr.length; i++) { + const [key, value] = fn(arr[i]!, i); + + record[key] = value; + } + + return record; +} + /** Maps the provided array into a map * * @param arr Array of items to be entered into a map @@ -74,16 +102,16 @@ export function sum(arr: T[], fn: (item: T) => number): number { * console.log(map); // Map(5) { 0 => 5, 1 => 4, 2 => 3, 3 => 2, 4 => 1 } * ``` */ -export function toMap( +export function toMap( arr: T[], - fn: (item: T, index: number) => [key: string, value: V] -): Record { - const map: Record = {}; + fn: (item: T, index: number) => [key: K, value: V] +): Map { + const map: Map = new Map(); for (let i = 0; i < arr.length; i++) { const [key, value] = fn(arr[i]!, i); - map[key] = value; + map.set(key, value); } return map; diff --git a/src/routes/api/generate-message/+server.ts b/src/routes/api/generate-message/+server.ts index ed08ca8..08e0ecd 100644 --- a/src/routes/api/generate-message/+server.ts +++ b/src/routes/api/generate-message/+server.ts @@ -12,6 +12,7 @@ import OpenAI from 'openai'; import { z } from 'zod/v4'; import { generationAbortControllers } from './cache.js'; import { md } from '$lib/utils/markdown-it.js'; +import * as array from '$lib/utils/array'; // Set to true to enable debug logging const ENABLE_LOGGING = true; @@ -371,13 +372,22 @@ async function generateAIResponse({ return; } - const attachedRules = [ - ...rulesResult.value.filter((r) => r.attach === 'always'), - ...parseMessageForRules( - userMessage.content, + let attachedRules = rulesResult.value.filter((r) => r.attach === 'always'); + + for (const message of messages) { + const parsedRules = parseMessageForRules( + message.content, rulesResult.value.filter((r) => r.attach === 'manual') - ), - ]; + ); + + attachedRules.push(...parsedRules); + } + + // remove duplicates + attachedRules = array.fromMap( + array.toMap(attachedRules, (r) => [r._id, r]), + (_k, v) => v + ); log(`Background: ${attachedRules.length} rules attached`, startTime); @@ -412,7 +422,7 @@ async function generateAIResponse({ ...formattedMessages, { role: 'system' as const, - content: `Respond in markdown format. The user may have mentioned one or more rules to follow with the @ syntax. Please follow these rules. + content: `The user has mentioned one or more rules to follow with the @ syntax. Please follow these rules as they apply. Rules to follow: ${attachedRules.map((r) => `- ${r.name}: ${r.rule}`).join('\n')}`, },