Skip to content

Commit 82d1483

Browse files
justanotheratomcursoragentowner
authored
Preferencevalidator groq (#3)
* Reimplement preferenceValidatorAgent to use Groq with structured output - Switch from OpenAI tool-calling to Groq openai/gpt-oss-20b model - Add new system prompt with multi-language support (EN/ES/PT/IT) - Implement structured output parsing for [[ ## reasoning ## ]] and [[ ## output ## ]] format - Add PreferenceValidatorGroq model to ModelName enum - Update genericAgent to handle Groq API routing and structured output - Maintain same function signature for backward compatibility - Support report_success() and report_failure() function calls from structured output * Fix Groq API compatibility by excluding metadata field - Remove metadata field from request body when using PreferenceValidatorGroq model - Groq API doesn't support metadata field, causing invalid_request_error - Maintain metadata for other models (OpenAI, AnyScale) for logging purposes * Fix Groq API compatibility by excluding store field - Remove store field from request body when using PreferenceValidatorGroq model - Groq API doesn't support store field, causing invalid_request_error - Maintain store and metadata for other models (OpenAI, AnyScale) for logging purposes * Fix Groq API tool calling issue by excluding tools entirely - Remove tools and tool_choice from request body when using PreferenceValidatorGroq model - Groq model was trying to call tools despite tool_choice: 'none', causing tool_use_failed error - Use structured output parsing instead of function calling for Groq model - Maintain tools and tool_choice for other models (OpenAI, AnyScale) for function calling * Switch ingredientAnalyzerAgent from OpenAI to Gemini 2.5 Flash Lite - Replace finetuned OpenAI model with prompt-based Gemini model - Add Gemini API integration with proper endpoint and authentication - Implement structured output parsing for Gemini response format - Add comprehensive logging for debugging and monitoring - Fix response format mapping to match client expectations - Add loop detection and prevention mechanisms - Configure generation parameters (maxOutputTokens, topP, topK, stopSequences) - Add safety settings to prevent problematic responses - Implement fallback mechanism for graceful error handling - Maintain backward compatibility with existing API response format This migration follows the same pattern as preferenceValidatorAgent switch to Groq, but adapted for Gemini's API format and ingredient analysis requirements. * Refactor LLM agent architecture with Gemini support * Fix Groq model usage in preference validator * feat: Add debug logging and env var support to ingredient analyzer Co-authored-by: owner <owner@fungee.llc> * Refactor: Update ingredient analyzer model to gemini-2.5-flash-lite Co-authored-by: owner <owner@fungee.llc> * Refactor genericAgent to handle invalid JSON args and boolean continue flag Co-authored-by: owner <owner@fungee.llc> * Fix: Log error when parsing tool call arguments Co-authored-by: owner <owner@fungee.llc> * Fix: Improve regex for preference validator agent output parsing Co-authored-by: owner <owner@fungee.llc> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: owner <owner@fungee.llc>
1 parent af1f009 commit 82d1483

12 files changed

Lines changed: 1742 additions & 594 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
local/finetuning/preferencevalidatordataset/.env

deno.lock

Lines changed: 133 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

supabase/functions/import_map.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"imports": {
3-
"@supabase/supabase-js": "https://esm.sh/@supabase/supabase-js@2.39.3"
3+
"@supabase/supabase-js": "https://esm.sh/@supabase/supabase-js@2.39.3",
4+
"oak": "https://deno.land/x/oak@v12.6.0/mod.ts"
45
}
56
}
Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,59 @@
1-
import { Context } from "https://deno.land/x/oak@v12.6.0/mod.ts"
2-
import * as DB from '../db.ts'
3-
import * as GenericAgent from './genericagent.ts'
4-
import { extractorAgentSystemMessage, extractorAgentFunctions } from './extractoragent_types.ts'
1+
import { Context } from "oak";
2+
import * as DB from "../db.ts";
3+
import { genericAgent } from "./genericagent.ts";
4+
import {
5+
extractorAgentFunctions,
6+
extractorAgentSystemMessage,
7+
} from "./extractoragent_types.ts";
8+
import { createOpenAIProgram } from "./programs.ts";
9+
import { ChatMessage } from "./types.ts";
510

611
export async function extractorAgent(
7-
ctx: Context,
8-
productImagesOCR: string[])
9-
: Promise<DB.Product>
10-
{
11-
let extractedProduct = DB.defaultProduct()
12-
13-
async function record_product_details(parameters: { product: DB.Product }): Promise<[any, boolean]> {
14-
extractedProduct = parameters.product
15-
return [parameters.product, false]
16-
}
17-
18-
const functionObject = {
19-
record_product_details: record_product_details
20-
}
21-
22-
const userMessage = productImagesOCR.join('\n---------------\n')
23-
24-
const messages: GenericAgent.ChatMessage[] = [
25-
{
26-
role: 'system',
27-
content: extractorAgentSystemMessage
28-
},
29-
{
30-
role: 'user',
31-
content: userMessage
32-
}
33-
]
34-
35-
const _ = await GenericAgent.genericAgent(
36-
ctx,
37-
'extractoragent',
38-
messages,
39-
extractorAgentFunctions,
40-
GenericAgent.ModelName.ExtractorFineTuned,
41-
functionObject,
42-
crypto.randomUUID(),
43-
[]
44-
)
45-
46-
return extractedProduct
47-
}
12+
ctx: Context,
13+
productImagesOCR: string[],
14+
): Promise<DB.Product> {
15+
let extractedProduct = DB.defaultProduct();
16+
17+
async function record_product_details(
18+
parameters: { product: DB.Product },
19+
): Promise<[any, boolean]> {
20+
extractedProduct = parameters.product;
21+
return [parameters.product, false];
22+
}
23+
24+
const functionObject = {
25+
record_product_details: record_product_details,
26+
};
27+
28+
const userMessage = productImagesOCR.join("\n---------------\n");
29+
30+
const messages: ChatMessage[] = [
31+
{
32+
role: "system",
33+
content: extractorAgentSystemMessage,
34+
},
35+
{
36+
role: "user",
37+
content: userMessage,
38+
},
39+
];
40+
41+
const program = createOpenAIProgram({
42+
id: "extractor-openai-ft",
43+
model: Deno.env.get("EXTRACTOR_MODEL") ??
44+
"ft:gpt-4o-mini-2024-07-18:personal:extractor:9ob7B1Fq",
45+
});
46+
47+
await genericAgent(
48+
ctx,
49+
program,
50+
"extractoragent",
51+
messages,
52+
extractorAgentFunctions,
53+
functionObject,
54+
crypto.randomUUID(),
55+
[],
56+
);
57+
58+
return extractedProduct;
59+
}
Lines changed: 48 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
export const extractorAgentSystemMessage = `
32
You are an expert in reading OCR text of food product images. You specialize
43
in extracting name, brand, and list of ingredients from the OCR text
@@ -12,61 +11,57 @@ export const extractorAgentSystemMessage = `
1211
e.g does it sound like a brand name?
1312
e.g does it sound like a product name?
1413
e.g does it sound like an ingredient name?
15-
`
14+
`;
1615

17-
interface ChatFunction {
18-
name: string
19-
description?: string
20-
parameters: Record<string, unknown>
21-
}
16+
import { ChatFunction } from "./types.ts";
2217

2318
export const extractorAgentFunctions: ChatFunction[] = [
24-
{
25-
name: 'record_product_details',
26-
description: 'Record the product details',
27-
parameters: {
28-
type: 'object',
29-
properties: {
30-
product: {
31-
type: 'object',
32-
properties: {
33-
brand: { type: 'string' },
34-
name: { type: 'string' },
19+
{
20+
name: "record_product_details",
21+
description: "Record the product details",
22+
parameters: {
23+
type: "object",
24+
properties: {
25+
product: {
26+
type: "object",
27+
properties: {
28+
brand: { type: "string" },
29+
name: { type: "string" },
30+
ingredients: {
31+
type: "array",
32+
items: {
33+
type: "object",
34+
properties: {
35+
name: { type: "string" },
36+
ingredients: {
37+
type: "array",
38+
items: {
39+
type: "object",
40+
properties: {
41+
name: { type: "string" },
3542
ingredients: {
36-
type: 'array',
37-
items: {
38-
type: 'object',
39-
properties: {
40-
name: { type: 'string' },
41-
ingredients: {
42-
type: 'array',
43-
items: {
44-
type: 'object',
45-
properties: {
46-
name: { type: 'string' },
47-
ingredients: {
48-
type: 'array',
49-
items: {
50-
type: 'object',
51-
properties: {
52-
name: { type: 'string' },
53-
},
54-
required: ['name']
55-
}
56-
}
57-
},
58-
required: ['name']
59-
}
60-
}
61-
},
62-
required: ['name']
63-
}
64-
}
43+
type: "array",
44+
items: {
45+
type: "object",
46+
properties: {
47+
name: { type: "string" },
48+
},
49+
required: ["name"],
50+
},
51+
},
52+
},
53+
required: ["name"],
6554
},
66-
required: ['ingredients']
67-
}
55+
},
56+
},
57+
required: ["name"],
58+
},
6859
},
69-
required: ['product']
70-
}
71-
}
72-
]
60+
},
61+
required: ["ingredients"],
62+
},
63+
},
64+
required: ["product"],
65+
},
66+
},
67+
];

0 commit comments

Comments
 (0)