From 03750d1b0cc2698b68062f98167fc6139b395700 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Tue, 1 Apr 2025 13:31:23 -0600 Subject: [PATCH 01/18] Implementing "jsonMode" for LLM calls, and from the react app iframe calls --- charm/src/iframe/static.ts | 41 +++---- jumble/src/views/CharmDetailView.tsx | 2 +- llm/src/client.ts | 1 + toolshed/routes/ai/llm/generateText.ts | 147 ++++++++++++++++++++++++- toolshed/routes/ai/llm/llm.handlers.ts | 85 +++++++++++--- toolshed/routes/ai/llm/llm.routes.ts | 3 +- toolshed/routes/ai/llm/models.ts | 28 +++++ 7 files changed, 258 insertions(+), 49 deletions(-) diff --git a/charm/src/iframe/static.ts b/charm/src/iframe/static.ts index 95f3ee45b..2c736f15f 100644 --- a/charm/src/iframe/static.ts +++ b/charm/src/iframe/static.ts @@ -165,32 +165,6 @@ ${JSON.stringify(libraries)} }); })(); - window.grabJson = (gstr) => { - // Function to extract and parse JSON from a string - // This handles both raw JSON strings and code blocks with JSON - const jsonRegex = /\`\`\`(?:json)?\s*([\s\S]*?)\s*\`\`\`|({[\s\S]*})/; - const match = gstr.match(jsonRegex); - - if (match) { - // Use the first matching group that contains content - const jsonStr = match[1] || match[2]; - try { - return JSON.parse(jsonStr); - } catch (e) { - console.error("Failed to parse JSON:", e); - return null; - } - } else { - // If no JSON block found, attempt to parse the entire string - try { - return JSON.parse(gstr); - } catch (e) { - console.error("No valid JSON found in string"); - return null; - } - } - } - // Define readWebpage utility with React available window.readWebpage = (function() { const inflight = []; @@ -673,12 +647,23 @@ async function fetchLLMResponse() { system: 'Translate all the messages to emojis, reply in JSON.', messages: ['Hi', 'How can I help you today?', 'tell me a joke'] }; - // grabJson is available on the window, string -> JSON - const result = grabJson(await llm(promptPayload)); + const result = await llm(promptPayload) console.log('LLM responded:', result); } \`\`\` +If you need JSON to be returned from the LLM, you can enable the \`jsonMode\` flag in the \`promptPayload\`. + +\`\`\`jsx +const promptPayload = { + system: 'Translate all the messages to emojis, reply in JSON.', + messages: ['Hi', 'How can I help you today?', 'tell me a joke'], + jsonMode: true +}; +const result = await llm(promptPayload); +console.log('JSON response from llm:', result); +\`\`\` + ## 3. readWebpage Function \`\`\`jsx diff --git a/jumble/src/views/CharmDetailView.tsx b/jumble/src/views/CharmDetailView.tsx index c83062581..e5dce87ef 100644 --- a/jumble/src/views/CharmDetailView.tsx +++ b/jumble/src/views/CharmDetailView.tsx @@ -61,7 +61,7 @@ const variantModels = [ "anthropic:claude-3-5-sonnet-latest", "anthropic:claude-3-7-sonnet-latest", "groq:llama-3.3-70b-versatile", - "google:gemini-2.0-pro", + "google:gemini-2.5-pro", ] as const; // =================== Context for Shared State =================== diff --git a/llm/src/client.ts b/llm/src/client.ts index 0e5f9fa01..d5c4fa8e3 100644 --- a/llm/src/client.ts +++ b/llm/src/client.ts @@ -27,6 +27,7 @@ export type LLMRequest = { max_tokens?: number; stream?: boolean; stop?: string; + jsonMode?: boolean; }; export class LLMClient { diff --git a/toolshed/routes/ai/llm/generateText.ts b/toolshed/routes/ai/llm/generateText.ts index 6017ca643..f610fb31f 100644 --- a/toolshed/routes/ai/llm/generateText.ts +++ b/toolshed/routes/ai/llm/generateText.ts @@ -2,6 +2,16 @@ import { streamText } from "ai"; import { findModel, TASK_MODELS } from "./models.ts"; +// Constants for JSON mode +const JSON_SYSTEM_PROMPTS = { + DEFAULT: + "Ensure the response is valid JSON. DO NOT include any other text or formatting.", + CLAUDE: + "You are a JSON generation assistant. Your task is to generate valid, properly formatted JSON according to the user's request. Follow these guidelines:\n\n1. Only output valid JSON - no other text, explanations, or markdown formatting\n2. Ensure all keys and string values are properly quoted with double quotes\n3. Maintain proper nesting and indentation\n4. Close all brackets and braces properly\n5. Use proper JSON syntax with commas between elements but not after the last element in arrays or objects\n\nYour entire response must be a single valid JSON object or array that could be directly parsed by JSON.parse().", + GROQ: + "You must respond with pure, correct JSON only - no text descriptions, no ```json code blocks, and no formatting outside of valid JSON. Your entire response should be a valid JSON object that can be parsed directly by JSON.parse() with no additional processing.", +}; + // Core generation logic separated from HTTP handling export interface GenerateTextParams { model?: string; @@ -12,6 +22,7 @@ export interface GenerateTextParams { stop_token?: string; abortSignal?: AbortSignal; max_tokens?: number; + jsonMode?: boolean; } export interface GenerateTextResult { @@ -19,6 +30,97 @@ export interface GenerateTextResult { stream?: ReadableStream; } +// Configure the model parameters for JSON mode based on provider +function configureJsonMode( + streamParams: Record, + modelName: string, + messages: { role: "user" | "assistant"; content: string }[], + isStreaming: boolean, +): void { + // Default to using the generic JSON mode + streamParams.mode = "json"; + + // Apply provider-specific configurations + if (modelName?.startsWith("groq:")) { + // Groq uses response_format parameter + streamParams.response_format = { type: "json_object" }; + + // Ensure it's also passed through providerOptions for the Vercel AI SDK + streamParams.providerOptions = { + ...streamParams.providerOptions, + groq: { + response_format: { type: "json_object" }, + }, + }; + + // Add a stronger system prompt for Groq to prevent markdown code blocks + if (!streamParams.system) { + streamParams.system = JSON_SYSTEM_PROMPTS.GROQ; + } else { + streamParams.system = streamParams.system + "\n\n" + + JSON_SYSTEM_PROMPTS.GROQ; + } + + // Remove standard mode parameter as Groq doesn't support it + delete streamParams.mode; + } else if (modelName?.startsWith("openai:")) { + // OpenAI uses response_format parameter + streamParams.response_format = { type: "json_object" }; + + // Ensure it's also passed through providerOptions for the Vercel AI SDK + streamParams.providerOptions = { + ...streamParams.providerOptions, + openai: { + response_format: { type: "json_object" }, + }, + }; + + // Remove the mode parameter since OpenAI uses response_format instead + delete streamParams.mode; + } else if (modelName?.startsWith("anthropic:")) { + // Update or set system prompt for Claude + if (!streamParams.system) { + streamParams.system = JSON_SYSTEM_PROMPTS.CLAUDE; + } else { + // Prepend the JSON assistant role and append the JSON-specific instructions + streamParams.system = "You are a JSON generation assistant. " + + streamParams.system + + "\n\nImportant: Your response must be ONLY valid JSON - no other text, explanations, or markdown formatting. The output should be directly parseable by JSON.parse()."; + } + + // Use prefill for non-streaming responses to anchor the JSON structure + if ( + !isStreaming && messages.length > 0 && + messages[messages.length - 1].role === "user" + ) { + streamParams.prefill = { + text: "{\n", + }; + } + } else { + // For other providers, set a standard system prompt if one isn't provided + if (!streamParams.system) { + streamParams.system = JSON_SYSTEM_PROMPTS.DEFAULT; + } else if (!streamParams.system.toLowerCase().includes("json")) { + streamParams.system += "\n" + JSON_SYSTEM_PROMPTS.DEFAULT; + } + } +} + +// Add a helper function to clean up JSON responses from markdown code blocks +function cleanJsonResponse(text: string): string { + // Check if the response is wrapped in markdown code blocks + const jsonCodeBlockRegex = /```(json)?\s*\n([\s\S]*?)\n```/; + const match = text.match(jsonCodeBlockRegex); + + if (match && match[2]) { + // Return just the JSON content inside the code block + return match[2].trim(); + } + + return text; +} + export async function generateText( params: GenerateTextParams, ): Promise { @@ -45,8 +147,18 @@ export async function generateText( throw new Error(`Unsupported model: ${modelName}`); } + // Check if jsonMode is requested but not supported + if (params.jsonMode && !modelConfig.capabilities.jsonMode) { + throw new Error(`Model ${modelName} does not support jsonMode.`); + } + + // Groq models don't support streaming in JSON mode + if (params.jsonMode && params.stream && modelName?.startsWith("groq:")) { + throw new Error("Groq models don't support streaming in JSON mode"); + } + const messages = params.messages; - const streamParams = { + const streamParams: Record = { model: modelConfig.model || modelName!, messages, stream: params.stream, @@ -57,6 +169,16 @@ export async function generateText( maxTokens: params.max_tokens, }; + // Apply JSON mode configuration if requested and supported + if (params.jsonMode && modelConfig.capabilities.jsonMode) { + configureJsonMode( + streamParams, + modelName!, + messages, + params.stream || false, + ); + } + // Handle models that don't support system prompts if ( !modelConfig.capabilities.systemPrompt && params.system && @@ -84,7 +206,16 @@ export async function generateText( throw new Error("No response from LLM"); } - if ((await llmStream.finishReason) === "stop" && params.stop_token) { + // Clean up JSON responses when jsonMode is enabled + if (params.jsonMode) { + result = cleanJsonResponse(result); + } + + // Only add stop token if not in JSON mode to avoid breaking JSON structure + if ( + (await llmStream.finishReason) === "stop" && params.stop_token && + !params.jsonMode + ) { result += params.stop_token; } @@ -117,14 +248,22 @@ export async function generateText( ); } - // Add stop sequence if specified - if ((await llmStream.finishReason) === "stop" && params.stop_token) { + // Only add stop token if not in JSON mode to avoid breaking JSON structure + if ( + (await llmStream.finishReason) === "stop" && params.stop_token && + !params.jsonMode + ) { result += params.stop_token; controller.enqueue( new TextEncoder().encode(JSON.stringify(params.stop_token) + "\n"), ); } + // For JSON mode, clean the result to strip any markdown code blocks + if (params.jsonMode) { + result = cleanJsonResponse(result); + } + // Update message history if (messages[messages.length - 1].role === "user") { messages.push({ role: "assistant", content: result }); diff --git a/toolshed/routes/ai/llm/llm.handlers.ts b/toolshed/routes/ai/llm/llm.handlers.ts index b131c5ac0..e3e73f6cf 100644 --- a/toolshed/routes/ai/llm/llm.handlers.ts +++ b/toolshed/routes/ai/llm/llm.handlers.ts @@ -6,6 +6,47 @@ import * as cache from "./cache.ts"; import type { Context } from "@hono/hono"; import { generateText as generateTextCore } from "./generateText.ts"; import { findModel } from "./models.ts"; + +/** + * Validates that the model and JSON mode settings are compatible + * @returns An error response object if validation fails, or null if validation passes + */ +function validateModelAndJsonMode( + c: Context, + modelString: string | undefined, + jsonMode: boolean | undefined, +) { + const model = modelString ? findModel(modelString) : null; + + if (!model) { + return c.json({ error: "Invalid model" }, HttpStatusCodes.BAD_REQUEST); + } + + // Validate jsonMode support if requested + if (jsonMode && !model.capabilities.jsonMode) { + return c.json( + { error: `Model ${modelString} does not support jsonMode.` }, + HttpStatusCodes.BAD_REQUEST, + ); + } + + // Groq models don't support streaming with JSON mode + if ( + jsonMode && c.req.query("stream") === "true" && + modelString?.startsWith("groq:") + ) { + return c.json( + { + error: + "Groq models don't support streaming in JSON mode. Please set stream to false.", + }, + HttpStatusCodes.BAD_REQUEST, + ); + } + + return null; +} + /** * Handler for GET /models endpoint * Returns filtered list of available LLM models based on search criteria @@ -57,20 +98,30 @@ export const generateText: AppRouteHandler = async (c) => { const payload = await c.req.json(); const modelString = payload.model; - const model = modelString ? findModel(modelString) : null; - const modelDefaultMaxTokens = model?.capabilities.maxOutputTokens || 8000; - if (!model) { - return c.json({ error: "Invalid model" }, HttpStatusCodes.BAD_REQUEST); + + // Validate model and JSON mode compatibility + const validationError = validateModelAndJsonMode( + c, + modelString, + payload.jsonMode, + ); + if (validationError) { + return validationError; } + const model = findModel(modelString!); + const modelDefaultMaxTokens = model?.capabilities.maxOutputTokens || 8000; + try { - // Check cache for existing response - const cacheKey = await cache.hashKey(JSON.stringify(payload)); - const cachedResult = await cache.loadItem(cacheKey); - if (cachedResult) { - const lastMessage = - cachedResult.messages[cachedResult.messages.length - 1]; - return c.json(lastMessage); + // Check cache for existing response - skip caching for jsonMode requests + if (!payload.jsonMode) { + const cacheKey = await cache.hashKey(JSON.stringify(payload)); + const cachedResult = await cache.loadItem(cacheKey); + if (cachedResult) { + const lastMessage = + cachedResult.messages[cachedResult.messages.length - 1]; + return c.json(lastMessage); + } } const result = await generateTextCore({ @@ -80,10 +131,14 @@ export const generateText: AppRouteHandler = async (c) => { }); if (!payload.stream) { - await cache.saveItem(cacheKey, { - ...payload, - messages: [...payload.messages, result.message], - }); + // Save to cache only if not jsonMode + if (!payload.jsonMode) { + const cacheKey = await cache.hashKey(JSON.stringify(payload)); + await cache.saveItem(cacheKey, { + ...payload, + messages: [...payload.messages, result.message], + }); + } return c.json(result.message); } diff --git a/toolshed/routes/ai/llm/llm.routes.ts b/toolshed/routes/ai/llm/llm.routes.ts index 25996f442..4cbaa207a 100644 --- a/toolshed/routes/ai/llm/llm.routes.ts +++ b/toolshed/routes/ai/llm/llm.routes.ts @@ -23,6 +23,7 @@ export const LLMRequestSchema = z.object({ stop_token: z.string().optional(), max_completion_tokens: z.number().optional(), stream: z.boolean().default(false), + jsonMode: z.boolean().optional().default(false), }); export const ModelInfoSchema = z.object({ @@ -111,7 +112,7 @@ export const generateText = createRoute({ "application/json": { schema: LLMRequestSchema.openapi({ example: { - model: "claude-3-5-sonnet", + model: "anthropic:claude-3-7-sonnet-latest", system: "You are a pirate, make sure you talk like one.", stream: false, messages: [ diff --git a/toolshed/routes/ai/llm/models.ts b/toolshed/routes/ai/llm/models.ts index b20b1f4eb..7b45db65d 100644 --- a/toolshed/routes/ai/llm/models.ts +++ b/toolshed/routes/ai/llm/models.ts @@ -16,6 +16,7 @@ export type Capabilities = { stopSequences: boolean; prefill: boolean; images: boolean; + jsonMode?: boolean; }; type ModelConfig = { @@ -104,6 +105,7 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -119,6 +121,7 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); addModel({ @@ -133,6 +136,7 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -151,6 +155,7 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, providerOptions: { anthropic: { @@ -171,6 +176,7 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); } @@ -191,6 +197,7 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, }); @@ -206,6 +213,7 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, }); @@ -221,6 +229,7 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, }); @@ -236,6 +245,7 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: true, stopSequences: true, streaming: false, + jsonMode: true, }, }); @@ -251,6 +261,7 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: true, stopSequences: true, streaming: false, + jsonMode: true, }, }); @@ -266,6 +277,7 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: true, stopSequences: true, streaming: false, + jsonMode: true, }, }); } @@ -286,6 +298,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -301,6 +314,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, providerOptions: { reasoningEffort: "low", @@ -319,6 +333,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, providerOptions: { reasoningEffort: "medium", @@ -337,6 +352,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, providerOptions: { reasoningEffort: "high", @@ -355,6 +371,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, providerOptions: { reasoningEffort: "low", @@ -373,6 +390,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, providerOptions: { reasoningEffort: "medium", @@ -391,6 +409,7 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, + jsonMode: true, }, providerOptions: { reasoningEffort: "high", @@ -423,6 +442,7 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -438,6 +458,7 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -453,6 +474,7 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -468,6 +490,7 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); @@ -483,6 +506,7 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: true, }, }); } @@ -503,6 +527,7 @@ if (env.CTTS_AI_LLM_CEREBRAS_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, + jsonMode: false, }, }); } @@ -526,6 +551,7 @@ if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { systemPrompt: false, stopSequences: true, streaming: true, + jsonMode: false, }, }); @@ -541,6 +567,7 @@ if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { systemPrompt: false, stopSequences: true, streaming: true, + jsonMode: false, }, }); @@ -556,6 +583,7 @@ if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { systemPrompt: false, stopSequences: true, streaming: true, + jsonMode: false, }, }); } From 902b6819285ef8c106b8b080e3242f9629fde023 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Tue, 1 Apr 2025 16:12:56 -0600 Subject: [PATCH 02/18] removing rarely used models and their dependencies --- deno.lock | 874 +------------------------------ toolshed/deno.json | 2 - toolshed/routes/ai/llm/models.ts | 203 +------ 3 files changed, 17 insertions(+), 1062 deletions(-) diff --git a/deno.lock b/deno.lock index db4bb3c92..ec81b1290 100644 --- a/deno.lock +++ b/deno.lock @@ -45,9 +45,7 @@ "jsr:@std/streams@^1.0.9": "1.0.9", "jsr:@std/testing@1": "1.0.9", "jsr:@zip-js/zip-js@^2.7.52": "2.7.57", - "npm:@ai-sdk/amazon-bedrock@^1.1.6": "1.1.6_zod@3.24.2", "npm:@ai-sdk/anthropic@^1.1.6": "1.1.15_zod@3.24.2", - "npm:@ai-sdk/cerebras@~0.1.8": "0.1.13_zod@3.24.2", "npm:@ai-sdk/google-vertex@^2.1.12": "2.1.24_zod@3.24.2", "npm:@ai-sdk/groq@^1.1.7": "1.1.12_zod@3.24.2", "npm:@ai-sdk/openai@^1.1.9": "1.2.2_zod@3.24.2", @@ -316,29 +314,11 @@ } }, "npm": { - "@ai-sdk/amazon-bedrock@1.1.6_zod@3.24.2": { - "integrity": "sha512-h6SJWpku+i8OsSz0A4RT2g2uD+3E0SUgWHsWRIpxmPNgM1DnH6lgSby5sxqAZDY5xJyJtRFW5vB9G3GEBjHy/g==", - "dependencies": [ - "@ai-sdk/provider@1.0.7", - "@ai-sdk/provider-utils@2.1.6_zod@3.24.2", - "@aws-sdk/client-bedrock-runtime", - "zod" - ] - }, "@ai-sdk/anthropic@1.1.15_zod@3.24.2": { "integrity": "sha512-KqI2vjEPLieBmZh+QIB0055JGUh9F7QcMdqj+dOGrtBawd0zjhZ2uBxP8Ghvl4WhbuTEOo54mlAg7RZO0eP2Tg==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", - "zod" - ] - }, - "@ai-sdk/cerebras@0.1.13_zod@3.24.2": { - "integrity": "sha512-jrNKpZx1LzG7+t5ARHR62PhUJ1pB6HDj7E94eTRaVZjZ6+1YkATTz5MplNsv3Eyy91JCr3GQZEyPf0dDiwKwbA==", - "dependencies": [ - "@ai-sdk/openai-compatible", - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "zod" ] }, @@ -347,8 +327,8 @@ "dependencies": [ "@ai-sdk/anthropic", "@ai-sdk/google", - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "google-auth-library", "zod" ] @@ -356,49 +336,31 @@ "@ai-sdk/google@1.1.20_zod@3.24.2": { "integrity": "sha512-vsYtmFYy5vQAovWWAqb9XoLZ01lmcfpfxviY8lMV92YwwbLLhYcaPQ4dKaaKo0tSksCWsO2Qehw8bN3eBxmZdA==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "zod" ] }, "@ai-sdk/groq@1.1.12_zod@3.24.2": { "integrity": "sha512-Cjvqrd1RLpdo6k7KQCENLiEDIYjXQdkfWcsBWn9WiGkiXgLyOwBZhxV0HK1jJKl17zO2AU4+QJODaqR9rQkLRA==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", - "zod" - ] - }, - "@ai-sdk/openai-compatible@0.1.13_zod@3.24.2": { - "integrity": "sha512-hgj6BdvasVXCTmJwbsiWo+e626GkmEBJKG8PYwpVq7moLWj93wJnfBNlDjxVjhZ32d5KGT32RIMZjqaX8QkClg==", - "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "zod" ] }, "@ai-sdk/openai@1.2.2_zod@3.24.2": { "integrity": "sha512-5355FLtSOH8sz9N9fsSwWpTaEgfqKOPMMHgSs1j4Aih5kQc9PhJ/oAPZuH308c/ktrbx6GcCW/hVrITimYsQhQ==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "zod" ] }, "@ai-sdk/provider-utils@2.1.11_zod@3.24.2": { "integrity": "sha512-lMnXA5KaRJidzW7gQmlo/SnX6D+AKk5GxHFcQtOaGOSJNmu/qcNZc1rGaO7K5qW52OvCLXtnWudR4cc/FvMpVQ==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "eventsource-parser@3.0.0", - "nanoid", - "secure-json-parse", - "zod" - ] - }, - "@ai-sdk/provider-utils@2.1.6_zod@3.24.2": { - "integrity": "sha512-Pfyaj0QZS22qyVn5Iz7IXcJ8nKIKlu2MeSAdKJzTwkAks7zdLaKVB+396Rqcp1bfQnxl7vaduQVMQiXUrgK8Gw==", - "dependencies": [ - "@ai-sdk/provider@1.0.7", + "@ai-sdk/provider", "eventsource-parser@3.0.0", "nanoid", "secure-json-parse", @@ -411,16 +373,10 @@ "json-schema" ] }, - "@ai-sdk/provider@1.0.7": { - "integrity": "sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==", - "dependencies": [ - "json-schema" - ] - }, "@ai-sdk/react@1.1.21_react@18.3.1_zod@3.24.2": { "integrity": "sha512-VKgqzG5wKjyLhROiFhRdyMuDcGu5QPfdLU5J7ovqR1HecknxymL3nCXsxWbAaiZ0khm2EsST6L6zwUbriZrKgg==", "dependencies": [ - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider-utils", "@ai-sdk/ui-utils", "react", "swr", @@ -431,8 +387,8 @@ "@ai-sdk/ui-utils@1.1.17_zod@3.24.2": { "integrity": "sha512-fCnp/wntZGqPf6tiCmhuQoSDLSBhXoI5DU2JX4As96EO870+jliE6ozvYUwYOZC6Ta2OKAjjWPcSP7HeHX0b+g==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "zod", "zod-to-json-schema" ] @@ -480,396 +436,6 @@ "zod" ] }, - "@aws-crypto/crc32@5.2.0": { - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", - "dependencies": [ - "@aws-crypto/util", - "@aws-sdk/types", - "tslib" - ] - }, - "@aws-crypto/sha256-browser@5.2.0": { - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "dependencies": [ - "@aws-crypto/sha256-js", - "@aws-crypto/supports-web-crypto", - "@aws-crypto/util", - "@aws-sdk/types", - "@aws-sdk/util-locate-window", - "@smithy/util-utf8@2.3.0", - "tslib" - ] - }, - "@aws-crypto/sha256-js@5.2.0": { - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "dependencies": [ - "@aws-crypto/util", - "@aws-sdk/types", - "tslib" - ] - }, - "@aws-crypto/supports-web-crypto@5.2.0": { - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "dependencies": [ - "tslib" - ] - }, - "@aws-crypto/util@5.2.0": { - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/util-utf8@2.3.0", - "tslib" - ] - }, - "@aws-sdk/client-bedrock-runtime@3.758.0": { - "integrity": "sha512-T7s+fULUxN3AcJP+lgoUKLawzVEtyCTi+5Ga+wrHnqEPwAsM/wg7VctsZfow1fCgARLT/lzmP2LTCi8ycRnQWg==", - "dependencies": [ - "@aws-crypto/sha256-browser", - "@aws-crypto/sha256-js", - "@aws-sdk/core", - "@aws-sdk/credential-provider-node", - "@aws-sdk/middleware-host-header", - "@aws-sdk/middleware-logger", - "@aws-sdk/middleware-recursion-detection", - "@aws-sdk/middleware-user-agent", - "@aws-sdk/region-config-resolver", - "@aws-sdk/types", - "@aws-sdk/util-endpoints", - "@aws-sdk/util-user-agent-browser", - "@aws-sdk/util-user-agent-node", - "@smithy/config-resolver", - "@smithy/core", - "@smithy/eventstream-serde-browser", - "@smithy/eventstream-serde-config-resolver", - "@smithy/eventstream-serde-node", - "@smithy/fetch-http-handler", - "@smithy/hash-node", - "@smithy/invalid-dependency", - "@smithy/middleware-content-length", - "@smithy/middleware-endpoint", - "@smithy/middleware-retry", - "@smithy/middleware-serde", - "@smithy/middleware-stack", - "@smithy/node-config-provider", - "@smithy/node-http-handler", - "@smithy/protocol-http", - "@smithy/smithy-client", - "@smithy/types", - "@smithy/url-parser", - "@smithy/util-base64", - "@smithy/util-body-length-browser", - "@smithy/util-body-length-node", - "@smithy/util-defaults-mode-browser", - "@smithy/util-defaults-mode-node", - "@smithy/util-endpoints", - "@smithy/util-middleware", - "@smithy/util-retry", - "@smithy/util-stream", - "@smithy/util-utf8@4.0.0", - "@types/uuid", - "tslib", - "uuid" - ] - }, - "@aws-sdk/client-sso@3.758.0": { - "integrity": "sha512-BoGO6IIWrLyLxQG6txJw6RT2urmbtlwfggapNCrNPyYjlXpzTSJhBYjndg7TpDATFd0SXL0zm8y/tXsUXNkdYQ==", - "dependencies": [ - "@aws-crypto/sha256-browser", - "@aws-crypto/sha256-js", - "@aws-sdk/core", - "@aws-sdk/middleware-host-header", - "@aws-sdk/middleware-logger", - "@aws-sdk/middleware-recursion-detection", - "@aws-sdk/middleware-user-agent", - "@aws-sdk/region-config-resolver", - "@aws-sdk/types", - "@aws-sdk/util-endpoints", - "@aws-sdk/util-user-agent-browser", - "@aws-sdk/util-user-agent-node", - "@smithy/config-resolver", - "@smithy/core", - "@smithy/fetch-http-handler", - "@smithy/hash-node", - "@smithy/invalid-dependency", - "@smithy/middleware-content-length", - "@smithy/middleware-endpoint", - "@smithy/middleware-retry", - "@smithy/middleware-serde", - "@smithy/middleware-stack", - "@smithy/node-config-provider", - "@smithy/node-http-handler", - "@smithy/protocol-http", - "@smithy/smithy-client", - "@smithy/types", - "@smithy/url-parser", - "@smithy/util-base64", - "@smithy/util-body-length-browser", - "@smithy/util-body-length-node", - "@smithy/util-defaults-mode-browser", - "@smithy/util-defaults-mode-node", - "@smithy/util-endpoints", - "@smithy/util-middleware", - "@smithy/util-retry", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@aws-sdk/core@3.758.0": { - "integrity": "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/core", - "@smithy/node-config-provider", - "@smithy/property-provider", - "@smithy/protocol-http", - "@smithy/signature-v4", - "@smithy/smithy-client", - "@smithy/types", - "@smithy/util-middleware", - "fast-xml-parser", - "tslib" - ] - }, - "@aws-sdk/credential-provider-env@3.758.0": { - "integrity": "sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w==", - "dependencies": [ - "@aws-sdk/core", - "@aws-sdk/types", - "@smithy/property-provider", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/credential-provider-http@3.758.0": { - "integrity": "sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q==", - "dependencies": [ - "@aws-sdk/core", - "@aws-sdk/types", - "@smithy/fetch-http-handler", - "@smithy/node-http-handler", - "@smithy/property-provider", - "@smithy/protocol-http", - "@smithy/smithy-client", - "@smithy/types", - "@smithy/util-stream", - "tslib" - ] - }, - "@aws-sdk/credential-provider-ini@3.758.0": { - "integrity": "sha512-cymSKMcP5d+OsgetoIZ5QCe1wnp2Q/tq+uIxVdh9MbfdBBEnl9Ecq6dH6VlYS89sp4QKuxHxkWXVnbXU3Q19Aw==", - "dependencies": [ - "@aws-sdk/core", - "@aws-sdk/credential-provider-env", - "@aws-sdk/credential-provider-http", - "@aws-sdk/credential-provider-process", - "@aws-sdk/credential-provider-sso", - "@aws-sdk/credential-provider-web-identity", - "@aws-sdk/nested-clients", - "@aws-sdk/types", - "@smithy/credential-provider-imds", - "@smithy/property-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/credential-provider-node@3.758.0": { - "integrity": "sha512-+DaMv63wiq7pJrhIQzZYMn4hSarKiizDoJRvyR7WGhnn0oQ/getX9Z0VNCV3i7lIFoLNTb7WMmQ9k7+z/uD5EQ==", - "dependencies": [ - "@aws-sdk/credential-provider-env", - "@aws-sdk/credential-provider-http", - "@aws-sdk/credential-provider-ini", - "@aws-sdk/credential-provider-process", - "@aws-sdk/credential-provider-sso", - "@aws-sdk/credential-provider-web-identity", - "@aws-sdk/types", - "@smithy/credential-provider-imds", - "@smithy/property-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/credential-provider-process@3.758.0": { - "integrity": "sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA==", - "dependencies": [ - "@aws-sdk/core", - "@aws-sdk/types", - "@smithy/property-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/credential-provider-sso@3.758.0": { - "integrity": "sha512-x0FYJqcOLUCv8GLLFDYMXRAQKGjoM+L0BG4BiHYZRDf24yQWFCAZsCQAYKo6XZYh2qznbsW6f//qpyJ5b0QVKQ==", - "dependencies": [ - "@aws-sdk/client-sso", - "@aws-sdk/core", - "@aws-sdk/token-providers", - "@aws-sdk/types", - "@smithy/property-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/credential-provider-web-identity@3.758.0": { - "integrity": "sha512-XGguXhBqiCXMXRxcfCAVPlMbm3VyJTou79r/3mxWddHWF0XbhaQiBIbUz6vobVTD25YQRbWSmSch7VA8kI5Lrw==", - "dependencies": [ - "@aws-sdk/core", - "@aws-sdk/nested-clients", - "@aws-sdk/types", - "@smithy/property-provider", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/middleware-host-header@3.734.0": { - "integrity": "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/protocol-http", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/middleware-logger@3.734.0": { - "integrity": "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/middleware-recursion-detection@3.734.0": { - "integrity": "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/protocol-http", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/middleware-user-agent@3.758.0": { - "integrity": "sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==", - "dependencies": [ - "@aws-sdk/core", - "@aws-sdk/types", - "@aws-sdk/util-endpoints", - "@smithy/core", - "@smithy/protocol-http", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/nested-clients@3.758.0": { - "integrity": "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg==", - "dependencies": [ - "@aws-crypto/sha256-browser", - "@aws-crypto/sha256-js", - "@aws-sdk/core", - "@aws-sdk/middleware-host-header", - "@aws-sdk/middleware-logger", - "@aws-sdk/middleware-recursion-detection", - "@aws-sdk/middleware-user-agent", - "@aws-sdk/region-config-resolver", - "@aws-sdk/types", - "@aws-sdk/util-endpoints", - "@aws-sdk/util-user-agent-browser", - "@aws-sdk/util-user-agent-node", - "@smithy/config-resolver", - "@smithy/core", - "@smithy/fetch-http-handler", - "@smithy/hash-node", - "@smithy/invalid-dependency", - "@smithy/middleware-content-length", - "@smithy/middleware-endpoint", - "@smithy/middleware-retry", - "@smithy/middleware-serde", - "@smithy/middleware-stack", - "@smithy/node-config-provider", - "@smithy/node-http-handler", - "@smithy/protocol-http", - "@smithy/smithy-client", - "@smithy/types", - "@smithy/url-parser", - "@smithy/util-base64", - "@smithy/util-body-length-browser", - "@smithy/util-body-length-node", - "@smithy/util-defaults-mode-browser", - "@smithy/util-defaults-mode-node", - "@smithy/util-endpoints", - "@smithy/util-middleware", - "@smithy/util-retry", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@aws-sdk/region-config-resolver@3.734.0": { - "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/node-config-provider", - "@smithy/types", - "@smithy/util-config-provider", - "@smithy/util-middleware", - "tslib" - ] - }, - "@aws-sdk/token-providers@3.758.0": { - "integrity": "sha512-ckptN1tNrIfQUaGWm/ayW1ddG+imbKN7HHhjFdS4VfItsP0QQOB0+Ov+tpgb4MoNR4JaUghMIVStjIeHN2ks1w==", - "dependencies": [ - "@aws-sdk/nested-clients", - "@aws-sdk/types", - "@smithy/property-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/types@3.734.0": { - "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@aws-sdk/util-endpoints@3.743.0": { - "integrity": "sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/types", - "@smithy/util-endpoints", - "tslib" - ] - }, - "@aws-sdk/util-locate-window@3.723.0": { - "integrity": "sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==", - "dependencies": [ - "tslib" - ] - }, - "@aws-sdk/util-user-agent-browser@3.734.0": { - "integrity": "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==", - "dependencies": [ - "@aws-sdk/types", - "@smithy/types", - "bowser", - "tslib" - ] - }, - "@aws-sdk/util-user-agent-node@3.758.0": { - "integrity": "sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==", - "dependencies": [ - "@aws-sdk/middleware-user-agent", - "@aws-sdk/types", - "@smithy/node-config-provider", - "@smithy/types", - "tslib" - ] - }, "@babel/code-frame@7.26.2": { "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dependencies": [ @@ -2269,397 +1835,6 @@ "qr-creator" ] }, - "@smithy/abort-controller@4.0.1": { - "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/config-resolver@4.0.1": { - "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", - "dependencies": [ - "@smithy/node-config-provider", - "@smithy/types", - "@smithy/util-config-provider", - "@smithy/util-middleware", - "tslib" - ] - }, - "@smithy/core@3.1.5": { - "integrity": "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==", - "dependencies": [ - "@smithy/middleware-serde", - "@smithy/protocol-http", - "@smithy/types", - "@smithy/util-body-length-browser", - "@smithy/util-middleware", - "@smithy/util-stream", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@smithy/credential-provider-imds@4.0.1": { - "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", - "dependencies": [ - "@smithy/node-config-provider", - "@smithy/property-provider", - "@smithy/types", - "@smithy/url-parser", - "tslib" - ] - }, - "@smithy/eventstream-codec@4.0.1": { - "integrity": "sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==", - "dependencies": [ - "@aws-crypto/crc32", - "@smithy/types", - "@smithy/util-hex-encoding", - "tslib" - ] - }, - "@smithy/eventstream-serde-browser@4.0.1": { - "integrity": "sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==", - "dependencies": [ - "@smithy/eventstream-serde-universal", - "@smithy/types", - "tslib" - ] - }, - "@smithy/eventstream-serde-config-resolver@4.0.1": { - "integrity": "sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/eventstream-serde-node@4.0.1": { - "integrity": "sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==", - "dependencies": [ - "@smithy/eventstream-serde-universal", - "@smithy/types", - "tslib" - ] - }, - "@smithy/eventstream-serde-universal@4.0.1": { - "integrity": "sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==", - "dependencies": [ - "@smithy/eventstream-codec", - "@smithy/types", - "tslib" - ] - }, - "@smithy/fetch-http-handler@5.0.1": { - "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", - "dependencies": [ - "@smithy/protocol-http", - "@smithy/querystring-builder", - "@smithy/types", - "@smithy/util-base64", - "tslib" - ] - }, - "@smithy/hash-node@4.0.1": { - "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", - "dependencies": [ - "@smithy/types", - "@smithy/util-buffer-from@4.0.0", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@smithy/invalid-dependency@4.0.1": { - "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/is-array-buffer@2.2.0": { - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/is-array-buffer@4.0.0": { - "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/middleware-content-length@4.0.1": { - "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", - "dependencies": [ - "@smithy/protocol-http", - "@smithy/types", - "tslib" - ] - }, - "@smithy/middleware-endpoint@4.0.6": { - "integrity": "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==", - "dependencies": [ - "@smithy/core", - "@smithy/middleware-serde", - "@smithy/node-config-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "@smithy/url-parser", - "@smithy/util-middleware", - "tslib" - ] - }, - "@smithy/middleware-retry@4.0.7": { - "integrity": "sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==", - "dependencies": [ - "@smithy/node-config-provider", - "@smithy/protocol-http", - "@smithy/service-error-classification", - "@smithy/smithy-client", - "@smithy/types", - "@smithy/util-middleware", - "@smithy/util-retry", - "tslib", - "uuid" - ] - }, - "@smithy/middleware-serde@4.0.2": { - "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/middleware-stack@4.0.1": { - "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/node-config-provider@4.0.1": { - "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", - "dependencies": [ - "@smithy/property-provider", - "@smithy/shared-ini-file-loader", - "@smithy/types", - "tslib" - ] - }, - "@smithy/node-http-handler@4.0.3": { - "integrity": "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==", - "dependencies": [ - "@smithy/abort-controller", - "@smithy/protocol-http", - "@smithy/querystring-builder", - "@smithy/types", - "tslib" - ] - }, - "@smithy/property-provider@4.0.1": { - "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/protocol-http@5.0.1": { - "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/querystring-builder@4.0.1": { - "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", - "dependencies": [ - "@smithy/types", - "@smithy/util-uri-escape", - "tslib" - ] - }, - "@smithy/querystring-parser@4.0.1": { - "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/service-error-classification@4.0.1": { - "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", - "dependencies": [ - "@smithy/types" - ] - }, - "@smithy/shared-ini-file-loader@4.0.1": { - "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/signature-v4@5.0.1": { - "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", - "dependencies": [ - "@smithy/is-array-buffer@4.0.0", - "@smithy/protocol-http", - "@smithy/types", - "@smithy/util-hex-encoding", - "@smithy/util-middleware", - "@smithy/util-uri-escape", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@smithy/smithy-client@4.1.6": { - "integrity": "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==", - "dependencies": [ - "@smithy/core", - "@smithy/middleware-endpoint", - "@smithy/middleware-stack", - "@smithy/protocol-http", - "@smithy/types", - "@smithy/util-stream", - "tslib" - ] - }, - "@smithy/types@4.1.0": { - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/url-parser@4.0.1": { - "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", - "dependencies": [ - "@smithy/querystring-parser", - "@smithy/types", - "tslib" - ] - }, - "@smithy/util-base64@4.0.0": { - "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", - "dependencies": [ - "@smithy/util-buffer-from@4.0.0", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@smithy/util-body-length-browser@4.0.0": { - "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/util-body-length-node@4.0.0": { - "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/util-buffer-from@2.2.0": { - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": [ - "@smithy/is-array-buffer@2.2.0", - "tslib" - ] - }, - "@smithy/util-buffer-from@4.0.0": { - "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", - "dependencies": [ - "@smithy/is-array-buffer@4.0.0", - "tslib" - ] - }, - "@smithy/util-config-provider@4.0.0": { - "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/util-defaults-mode-browser@4.0.7": { - "integrity": "sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==", - "dependencies": [ - "@smithy/property-provider", - "@smithy/smithy-client", - "@smithy/types", - "bowser", - "tslib" - ] - }, - "@smithy/util-defaults-mode-node@4.0.7": { - "integrity": "sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==", - "dependencies": [ - "@smithy/config-resolver", - "@smithy/credential-provider-imds", - "@smithy/node-config-provider", - "@smithy/property-provider", - "@smithy/smithy-client", - "@smithy/types", - "tslib" - ] - }, - "@smithy/util-endpoints@3.0.1": { - "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", - "dependencies": [ - "@smithy/node-config-provider", - "@smithy/types", - "tslib" - ] - }, - "@smithy/util-hex-encoding@4.0.0": { - "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/util-middleware@4.0.1": { - "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", - "dependencies": [ - "@smithy/types", - "tslib" - ] - }, - "@smithy/util-retry@4.0.1": { - "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", - "dependencies": [ - "@smithy/service-error-classification", - "@smithy/types", - "tslib" - ] - }, - "@smithy/util-stream@4.1.2": { - "integrity": "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==", - "dependencies": [ - "@smithy/fetch-http-handler", - "@smithy/node-http-handler", - "@smithy/types", - "@smithy/util-base64", - "@smithy/util-buffer-from@4.0.0", - "@smithy/util-hex-encoding", - "@smithy/util-utf8@4.0.0", - "tslib" - ] - }, - "@smithy/util-uri-escape@4.0.0": { - "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", - "dependencies": [ - "tslib" - ] - }, - "@smithy/util-utf8@2.3.0": { - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": [ - "@smithy/util-buffer-from@2.2.0", - "tslib" - ] - }, - "@smithy/util-utf8@4.0.0": { - "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", - "dependencies": [ - "@smithy/util-buffer-from@4.0.0", - "tslib" - ] - }, "@tailwindcss/node@4.0.13": { "integrity": "sha512-P9TmtE9Vew0vv5FwyD4bsg/dHHsIsAuUXkenuGUc5gm8fYgaxpdoxIKngCyEMEQxyCKR8PQY5V5VrrKNOx7exg==", "dependencies": [ @@ -3044,9 +2219,6 @@ "@types/unist@3.0.3": { "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, - "@types/uuid@9.0.8": { - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" - }, "@types/webxr@0.5.21": { "integrity": "sha512-geZIAtLzjGmgY2JUi6VxXdCrTb99A7yP49lxLr2Nm/uIK0PkkxcEi4OGhoGDO4pxCf3JwGz2GiJL2Ej4K2bKaA==" }, @@ -3397,8 +2569,8 @@ "ai@4.1.54_react@18.3.1_zod@3.24.2": { "integrity": "sha512-VcUZhNEC9i1OpdhDaz1cF0IllgMqhwoUdqHQT1U3dKvS9KnOa9qvEtUUAilA+VHI/1LSZF4VzGhXPC7QMT9NMg==", "dependencies": [ - "@ai-sdk/provider@1.0.10", - "@ai-sdk/provider-utils@2.1.11_zod@3.24.2", + "@ai-sdk/provider", + "@ai-sdk/provider-utils", "@ai-sdk/react", "@ai-sdk/ui-utils", "@opentelemetry/api", @@ -3530,9 +2702,6 @@ "bignumber.js@9.1.2": { "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" }, - "bowser@2.11.0": { - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" - }, "brace-expansion@2.0.1": { "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": [ @@ -4238,12 +3407,6 @@ "fast-safe-stringify@2.1.1": { "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, - "fast-xml-parser@4.4.1": { - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "dependencies": [ - "strnum" - ] - }, "fastq@1.19.1": { "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dependencies": [ @@ -6326,9 +5489,6 @@ "strip-json-comments@3.1.1": { "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, - "strnum@1.1.2": { - "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==" - }, "style-mod@4.1.2": { "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" }, @@ -7082,9 +6242,7 @@ "toolshed": { "dependencies": [ "jsr:@std/cli@^1.0.12", - "npm:@ai-sdk/amazon-bedrock@^1.1.6", "npm:@ai-sdk/anthropic@^1.1.6", - "npm:@ai-sdk/cerebras@~0.1.8", "npm:@ai-sdk/google-vertex@^2.1.12", "npm:@ai-sdk/groq@^1.1.7", "npm:@ai-sdk/openai@^1.1.9", diff --git a/toolshed/deno.json b/toolshed/deno.json index 02d1395de..77cc581a5 100644 --- a/toolshed/deno.json +++ b/toolshed/deno.json @@ -9,9 +9,7 @@ }, "imports": { "@/": "./", - "@ai-sdk/amazon-bedrock": "npm:@ai-sdk/amazon-bedrock@^1.1.6", "@ai-sdk/anthropic": "npm:@ai-sdk/anthropic@^1.1.6", - "@ai-sdk/cerebras": "npm:@ai-sdk/cerebras@^0.1.8", "@ai-sdk/google-vertex": "npm:@ai-sdk/google-vertex@^2.1.12", "@std/cli": "jsr:@std/cli@^1.0.12", "gcp-metadata": "npm:gcp-metadata@6.1.0", diff --git a/toolshed/routes/ai/llm/models.ts b/toolshed/routes/ai/llm/models.ts index 7b45db65d..cbb6a2a0c 100644 --- a/toolshed/routes/ai/llm/models.ts +++ b/toolshed/routes/ai/llm/models.ts @@ -3,7 +3,6 @@ import { createOpenAI } from "@ai-sdk/openai"; import { createGroq, groq } from "@ai-sdk/groq"; import { openai } from "@ai-sdk/openai"; import { createVertex, vertex } from "@ai-sdk/google-vertex"; -import { cerebras, createCerebras } from "@ai-sdk/cerebras"; import env from "@/env.ts"; @@ -51,8 +50,7 @@ const addModel = ({ | typeof anthropic | typeof groq | typeof openai - | typeof vertex - | typeof cerebras; + | typeof vertex; name: string; aliases: string[]; capabilities: Capabilities; @@ -93,21 +91,6 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { const anthropicProvider = createAnthropic({ apiKey: env.CTTS_AI_LLM_ANTHROPIC_API_KEY, }); - addModel({ - provider: anthropicProvider, - name: "anthropic:claude-3-5-haiku-20241022", - aliases: ["anthropic:claude-3-5-haiku-latest", "claude-3-5-haiku"], - capabilities: { - contextWindow: 200_000, - maxOutputTokens: 8192, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: true, - }, - }); addModel({ provider: anthropicProvider, @@ -163,22 +146,6 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { }, }, }); - - addModel({ - provider: anthropicProvider, - name: "anthropic:claude-3-opus-20240229", - aliases: ["anthropic:claude-3-opus-latest", "claude-3-opus"], - capabilities: { - contextWindow: 200_000, - maxOutputTokens: 4096, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: true, - }, - }); } if (env.CTTS_AI_LLM_GROQ_API_KEY) { @@ -264,22 +231,6 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { jsonMode: true, }, }); - - addModel({ - provider: groqProvider, - name: "groq:llama-3.2-90b-vision-preview", - aliases: ["groq:llama-3.2-90b-vision", "llama-3.2-90b-vision"], - capabilities: { - contextWindow: 128_000, - maxOutputTokens: 8000, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: false, - jsonMode: true, - }, - }); } if (env.CTTS_AI_LLM_OPENAI_API_KEY) { @@ -430,70 +381,6 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { location: env.CTTS_AI_LLM_GOOGLE_VERTEX_LOCATION, }); - addModel({ - provider: vertexProvider, - name: "google:gemini-2.0-flash", - aliases: ["google:gemini-2.0-flash", "gemini-2.0-flash"], - capabilities: { - contextWindow: 1_048_576, - maxOutputTokens: 8192, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: true, - }, - }); - - addModel({ - provider: vertexProvider, - name: "google:gemini-2.0-flash-lite-preview-02-05", - aliases: ["google:gemini-2.0-flash-lite", "gemini-2.0-flash-lite"], - capabilities: { - contextWindow: 1_048_576, - maxOutputTokens: 8192, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: true, - }, - }); - - addModel({ - provider: vertexProvider, - name: "google:gemini-2.0-flash-thinking-exp-01-21", - aliases: ["google:gemini-2.0-flash-thinking", "gemini-2.0-flash-thinking"], - capabilities: { - contextWindow: 1_048_576, - maxOutputTokens: 8192, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: true, - }, - }); - - addModel({ - provider: vertexProvider, - name: "google:gemini-2.0-pro-exp-02-05", - aliases: ["google:gemini-2.0-pro", "gemini-2.0-pro"], - capabilities: { - contextWindow: 2_097_152, - maxOutputTokens: 8192, - images: true, - prefill: true, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: true, - }, - }); - addModel({ provider: vertexProvider, name: "google:gemini-2.5-pro-exp-03-25", @@ -511,27 +398,6 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { }); } -if (env.CTTS_AI_LLM_CEREBRAS_API_KEY) { - const cerebrasProvider = createCerebras({ - apiKey: env.CTTS_AI_LLM_CEREBRAS_API_KEY, - }); - addModel({ - provider: cerebrasProvider, - name: "cerebras:llama-3.3-70b", - aliases: ["cerebras"], - capabilities: { - contextWindow: 8192, - maxOutputTokens: 8192, - images: false, - prefill: false, - systemPrompt: true, - stopSequences: true, - streaming: true, - jsonMode: false, - }, - }); -} - if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { const perplexityProvider = createOpenAI({ name: "perplexity", @@ -570,75 +436,8 @@ if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { jsonMode: false, }, }); - - addModel({ - provider: perplexityProvider, - name: "perplexity:sonar", - aliases: ["sonar"], - capabilities: { - contextWindow: 127_000, - maxOutputTokens: 8000, - images: false, - prefill: false, - systemPrompt: false, - stopSequences: true, - streaming: true, - jsonMode: false, - }, - }); } -// FIXME(jake): There's some package import error with the bedrock provider. Commenting out for now. -// if ( -// env.CTTS_AI_LLM_AWS_ACCESS_KEY_ID && -// env.CTTS_AI_LLM_AWS_SECRET_ACCESS_KEY -// ) { -// addModel({ -// provider: bedrock, -// name: "us.amazon.nova-micro-v1:0", -// aliases: ["amazon:nova-micro", "nova-micro"], -// capabilities: { -// contextWindow: 128_000, -// maxOutputTokens: 5000, -// images: false, -// prefill: true, -// systemPrompt: true, -// stopSequences: true, -// streaming: true, -// }, -// }); - -// addModel({ -// provider: bedrock, -// name: "us.amazon.nova-lite-v1:0", -// aliases: ["amazon:nova-lite", "nova-lite"], -// capabilities: { -// contextWindow: 300_000, -// maxOutputTokens: 5000, -// images: true, -// prefill: true, -// systemPrompt: true, -// stopSequences: true, -// streaming: true, -// }, -// }); - -// addModel({ -// provider: bedrock, -// name: "us.amazon.nova-pro-v1:0", -// aliases: ["amazon:nova-pro", "nova-pro"], -// capabilities: { -// contextWindow: 300_000, -// maxOutputTokens: 5000, -// images: true, -// prefill: true, -// systemPrompt: true, -// stopSequences: true, -// streaming: true, -// }, -// }); -// } - export const findModel = (name: string) => { return MODELS[name]; }; From 594b03bc657d9de6531314acbb41eac604b3cb70 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 09:05:22 -0600 Subject: [PATCH 03/18] adding new cached llm responses --- ...50a1f503e51a8fd3e6192b100e3cb49d1e308.json | 19 ++++++++++++++++++ ...8fc10f4b0b5f705ef353de1f26f02e0a60f30.json | 19 ++++++++++++++++++ ...98033d146e3b2627adac30477a9aa8a41cab.json} | 4 ++-- ...7221231dac12cd20e0af4e5d3e89a5919daeb.json | 20 ------------------- ...30bac958a51df98cdd3316b9914bb655ec5b6.json | 20 +++++++++++++++++++ ...5ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json | 19 ------------------ 6 files changed, 60 insertions(+), 41 deletions(-) create mode 100644 jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json create mode 100644 jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json rename jumble/integration/cache/llm-api-cache/{c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json => 9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json} (65%) delete mode 100644 jumble/integration/cache/llm-api-cache/b3fc0f350fc478943cc9c8b7b227221231dac12cd20e0af4e5d3e89a5919daeb.json create mode 100644 jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json delete mode 100644 jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json diff --git a/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json b/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json new file mode 100644 index 000000000..65abfd58f --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json @@ -0,0 +1,19 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", + "stream": false, + "messages": [ + { + "role": "user", + "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]" + }, + { + "role": "assistant", + "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." + }, + { + "role": "assistant", + "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." + } + ] +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json b/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json new file mode 100644 index 000000000..8b215aa49 --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json @@ -0,0 +1,19 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", + "stream": false, + "messages": [ + { + "role": "user", + "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"count of values\"}]}]" + }, + { + "role": "assistant", + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + }, + { + "role": "assistant", + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + } + ] +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json b/jumble/integration/cache/llm-api-cache/9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json similarity index 65% rename from jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json rename to jumble/integration/cache/llm-api-cache/9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json index c32ce2ec5..61b508939 100644 --- a/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json +++ b/jumble/integration/cache/llm-api-cache/9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting values in an array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"minimum\": 0,\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting occurrences in the values array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting values in an array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"minimum\": 0,\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting occurrences in the values array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/b3fc0f350fc478943cc9c8b7b227221231dac12cd20e0af4e5d3e89a5919daeb.json b/jumble/integration/cache/llm-api-cache/b3fc0f350fc478943cc9c8b7b227221231dac12cd20e0af4e5d3e89a5919daeb.json deleted file mode 100644 index a489cd05e..000000000 --- a/jumble/integration/cache/llm-api-cache/b3fc0f350fc478943cc9c8b7b227221231dac12cd20e0af4e5d3e89a5919daeb.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"minimum\": 0,\n \"default\": 0\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n // grabJson is available on the window, string -> JSON\n const result = grabJson(await llm(promptPayload));\n console.log('LLM responded:', result);\n}\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Get the original data structure\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalCount, setTotalCount] = useDoc(\"totalCount\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n \n // Local state for new value input\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the values array and count occurrences\n React.useEffect(() => {\n const values = simpleValue2.values || [];\n \n // Update original data\n setOriginalData({ simpleValue2: { values: [...values] } });\n \n // Count occurrences of each unique value\n const countMap = {};\n values.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts\n setCounts(countMap);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2.values]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === \"\") return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setNewValue(\"\");\n };\n \n // Remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ values: updatedValues });\n };\n \n // Clear all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n {/* Current values list */}\n
\n
\n

Current Values:

\n {simpleValue2.values && simpleValue2.values.length > 0 && (\n \n Clear All\n \n )}\n
\n \n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n
\n \n {/* Results section */}\n
\n {/* Count summary */}\n
\n

Count Summary

\n
\n
\n

Total Values

\n

{totalCount}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n
\n \n {/* Value counts */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalCount > 0 ? ((count / totalCount) * 100).toFixed(1) + \"%\" : \"0%\"}\n
\n
\n ) : (\n

No data to display

\n )}\n
\n
\n
\n );\n }\n\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Get the original data structure\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalCount, setTotalCount] = useDoc(\"totalCount\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n \n // Local state for new value input\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the values array and count occurrences\n React.useEffect(() => {\n const values = simpleValue2.values || [];\n \n // Update original data\n setOriginalData({ simpleValue2: { values: [...values] } });\n \n // Count occurrences of each unique value\n const countMap = {};\n values.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts\n setCounts(countMap);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2.values]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === \"\") return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setNewValue(\"\");\n };\n \n // Remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ values: updatedValues });\n };\n \n // Clear all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n {/* Current values list */}\n
\n
\n

Current Values:

\n {simpleValue2.values && simpleValue2.values.length > 0 && (\n \n Clear All\n \n )}\n
\n \n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n
\n \n {/* Results section */}\n
\n {/* Count summary */}\n
\n

Count Summary

\n
\n
\n

Total Values

\n

{totalCount}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n
\n \n {/* Value counts */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalCount > 0 ? ((count / totalCount) * 100).toFixed(1) + \"%\" : \"0%\"}\n
\n
\n ) : (\n

No data to display

\n )}\n
\n
\n
\n );\n }\n\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json b/jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json new file mode 100644 index 000000000..71f4a2219 --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `jsonMode` flag in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n jsonMode: true\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Get the original data structure\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalCount, setTotalCount] = useDoc(\"totalCount\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n \n // Local state for new value input\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the values array and count occurrences\n React.useEffect(() => {\n // Extract the values array\n const values = simpleValue2.values || [];\n \n // Count occurrences of each unique value\n const valueCounts = {};\n values.forEach(value => {\n valueCounts[value] = (valueCounts[value] || 0) + 1;\n });\n \n // Update the counts, total count, and unique count\n setCounts(valueCounts);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(valueCounts).length);\n \n // Update the original data\n setOriginalData({ simpleValue2: { values: [...values] } });\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim()) {\n const updatedValues = [...simpleValue2.values, newValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setNewValue(\"\");\n }\n };\n \n // Remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter((_, index) => index !== valueToRemove);\n setSimpleValue2({ values: updatedValues });\n };\n \n // Clear all values\n const handleClearValues = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n \n Clear All Values\n \n
\n \n {/* Values list */}\n
\n

Values List

\n {simpleValue2.values.length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {simpleValue2.values.map((value, index) => (\n \n \n \n \n \n ))}\n \n
IndexValueAction
{index}{value}\n handleRemoveValue(index)}\n className=\"text-red-600 hover:text-red-900\"\n >\n Remove\n \n
\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Count summary */}\n
\n

Count Summary

\n
\n
\n
\n

Total Values

\n

{totalCount}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n
\n
\n \n {/* Value counts */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalCount > 0 ? `${((count / totalCount) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No values to count.

\n )}\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Get the original data structure\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalCount, setTotalCount] = useDoc(\"totalCount\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n \n // Local state for new value input\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the values array and count occurrences\n React.useEffect(() => {\n // Extract the values array\n const values = simpleValue2.values || [];\n \n // Count occurrences of each unique value\n const valueCounts = {};\n values.forEach(value => {\n valueCounts[value] = (valueCounts[value] || 0) + 1;\n });\n \n // Update the counts, total count, and unique count\n setCounts(valueCounts);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(valueCounts).length);\n \n // Update the original data\n setOriginalData({ simpleValue2: { values: [...values] } });\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim()) {\n const updatedValues = [...simpleValue2.values, newValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setNewValue(\"\");\n }\n };\n \n // Remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter((_, index) => index !== valueToRemove);\n setSimpleValue2({ values: updatedValues });\n };\n \n // Clear all values\n const handleClearValues = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n \n Clear All Values\n \n
\n \n {/* Values list */}\n
\n

Values List

\n {simpleValue2.values.length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {simpleValue2.values.map((value, index) => (\n \n \n \n \n \n ))}\n \n
IndexValueAction
{index}{value}\n handleRemoveValue(index)}\n className=\"text-red-600 hover:text-red-900\"\n >\n Remove\n \n
\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Count summary */}\n
\n

Count Summary

\n
\n
\n
\n

Total Values

\n

{totalCount}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n
\n
\n \n {/* Value counts */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalCount > 0 ? `${((count / totalCount) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No values to count.

\n )}\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json b/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json deleted file mode 100644 index 5090ee82f..000000000 --- a/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", - "stream": false, - "messages": [ - { - "role": "user", - "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"count of values\"}]}]" - }, - { - "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running count for each unique value entered and displays the current totals. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and update the counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalItems\": {\n \"type\": \"integer\",\n \"title\": \"Total Items\",\n \"description\": \"Total number of items counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last updated\"\n },\n \"sortBy\": {\n \"type\": \"string\",\n \"title\": \"Sort By\",\n \"description\": \"How to sort the values when displaying\",\n \"enum\": [\"value\", \"count\", \"none\"],\n \"default\": \"none\"\n }\n },\n \"required\": [\"counts\", \"totalItems\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 5,\n \"banana\": 3,\n \"orange\": 2,\n \"grape\": 1\n },\n \"totalItems\": 11,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\",\n \"sortBy\": \"count\"\n}\n" - }, - { - "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running count for each unique value entered and displays the current totals. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and update the counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalItems\": {\n \"type\": \"integer\",\n \"title\": \"Total Items\",\n \"description\": \"Total number of items counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last updated\"\n },\n \"sortBy\": {\n \"type\": \"string\",\n \"title\": \"Sort By\",\n \"description\": \"How to sort the values when displaying\",\n \"enum\": [\"value\", \"count\", \"none\"],\n \"default\": \"none\"\n }\n },\n \"required\": [\"counts\", \"totalItems\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 5,\n \"banana\": 3,\n \"orange\": 2,\n \"grape\": 1\n },\n \"totalItems\": 11,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\",\n \"sortBy\": \"count\"\n}\n" - } - ] -} \ No newline at end of file From 374f2fb875cbda3c39139cadc8c49a3485112aca Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 09:06:22 -0600 Subject: [PATCH 04/18] Bumping llm timeout to 60s, which should only ever impact runs of rebuild-llm-cache.sh --- .gitignore | 2 +- jumble/integration/utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 422ec15ad..f335b9ecf 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ cache artifact _deno.lock -!/jumble/integration/cache/llm-api-cache +!/jumble/integration/cache .claude-prompt.tmp .pr-desc.tmp dist/ \ No newline at end of file diff --git a/jumble/integration/utils.ts b/jumble/integration/utils.ts index d0f99c43c..4d81201c3 100644 --- a/jumble/integration/utils.ts +++ b/jumble/integration/utils.ts @@ -108,7 +108,7 @@ export const waitForSelectorWithText = async ( selector: string, text: string, ): Promise => { - const retries = 30; + const retries = 60; const timeout = 1000; for (let i = 0; i < retries; i++) { const el = await page.waitForSelector(selector); From 5ff3d13bba460ec0a2c7eaccc06866278bef8fdd Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 09:06:42 -0600 Subject: [PATCH 05/18] improving rebuild-llm-cache.sh script * Now ensures processes get cleaned up on failure * Creates a temporary cache directory, so we can understand what the new cache files are, passes CACHE_DIR into toolshed * Copies cache files to the correct location --- jumble/integration/rebuild-llm-cache.sh | 40 ++++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/jumble/integration/rebuild-llm-cache.sh b/jumble/integration/rebuild-llm-cache.sh index 5b07987ef..034ca45ec 100755 --- a/jumble/integration/rebuild-llm-cache.sh +++ b/jumble/integration/rebuild-llm-cache.sh @@ -1,6 +1,20 @@ #!/bin/bash set -e # Exit on error +# Function to clean up processes +cleanup() { + echo "Cleaning up processes..." + if [ ! -z "$TOOLSHED_PID" ]; then + kill $TOOLSHED_PID 2>/dev/null || true + fi + if [ ! -z "$JUMBLE_PID" ]; then + kill $JUMBLE_PID 2>/dev/null || true + fi +} + +# Set up trap to call cleanup on script exit (success or failure) +trap cleanup EXIT + echo "Starting integration test environment..." # Ensure we're at the root of the repo @@ -12,6 +26,10 @@ elif [[ "$(basename "$(pwd)")" == "jumble" ]]; then cd .. fi +#0. Create temp cache directory +echo "Creating temp cache directory..." +TEMP_CACHE_DIR=$(mktemp -d) + # 1. Delete existing cache echo "Deleting existing LLM cache..." rm -rf jumble/integration/cache/llm-api-cache @@ -20,7 +38,7 @@ mkdir -p jumble/integration/cache/llm-api-cache # 2. Start toolshed on port 8000 echo "Starting toolshed on port 8000..." cd toolshed -deno run dev & +CACHE_DIR=$TEMP_CACHE_DIR deno run dev & TOOLSHED_PID=$! cd .. @@ -47,15 +65,21 @@ cd .. # 5. Copy cache files echo "Copying LLM cache files to integration directory..." -mkdir -p integration/cache/llm-api-cache -cp -r toolshed/cache/llm-api-cache/* integration/cache/llm-api-cache/ -# 6. Clean up processes -echo "Cleaning up processes..." -kill $TOOLSHED_PID -kill $JUMBLE_PID +echo "List of fresh llm cache artifacts:" +ls -la $TEMP_CACHE_DIR/llm-api-cache + +# Ensure target directory exists +mkdir -p jumble/integration/cache/llm-api-cache + +# Copy files from temp cache to integration cache +cp -r $TEMP_CACHE_DIR/llm-api-cache/* jumble/integration/cache/llm-api-cache/ + +# Verify files were copied +echo "Verifying copied files:" +ls -la jumble/integration/cache/llm-api-cache/ -# 7. Print report and status +# 6. Print report and status echo "===============================================" echo "Integration test run complete!" echo "Cache files have been copied to integration/cache/llm-api-cache" From 07cb4be2393e6c01877f7a4866f9203ec06c2e6a Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 09:39:25 -0600 Subject: [PATCH 06/18] tweaking things to be mode: "json" --- charm/src/iframe/static.ts | 4 ++-- llm/src/client.ts | 2 +- llm/src/prompts/json-gen.ts | 1 + toolshed/routes/ai/llm/generateText.ts | 23 +++++++++-------------- toolshed/routes/ai/llm/llm.handlers.ts | 23 +++++++++-------------- toolshed/routes/ai/llm/llm.routes.ts | 2 +- toolshed/routes/ai/llm/models.ts | 19 ------------------- 7 files changed, 23 insertions(+), 51 deletions(-) diff --git a/charm/src/iframe/static.ts b/charm/src/iframe/static.ts index 2c736f15f..76b598996 100644 --- a/charm/src/iframe/static.ts +++ b/charm/src/iframe/static.ts @@ -652,13 +652,13 @@ async function fetchLLMResponse() { } \`\`\` -If you need JSON to be returned from the LLM, you can enable the \`jsonMode\` flag in the \`promptPayload\`. +If you need JSON to be returned from the LLM, you can enable the \`mode: 'json'\` in the \`promptPayload\`. \`\`\`jsx const promptPayload = { system: 'Translate all the messages to emojis, reply in JSON.', messages: ['Hi', 'How can I help you today?', 'tell me a joke'], - jsonMode: true + mode: 'json' }; const result = await llm(promptPayload); console.log('JSON response from llm:', result); diff --git a/llm/src/client.ts b/llm/src/client.ts index d5c4fa8e3..7acbc2581 100644 --- a/llm/src/client.ts +++ b/llm/src/client.ts @@ -27,7 +27,7 @@ export type LLMRequest = { max_tokens?: number; stream?: boolean; stop?: string; - jsonMode?: boolean; + mode?: "json"; }; export class LLMClient { diff --git a/llm/src/prompts/json-gen.ts b/llm/src/prompts/json-gen.ts index 18518055d..262d6e6ae 100644 --- a/llm/src/prompts/json-gen.ts +++ b/llm/src/prompts/json-gen.ts @@ -62,6 +62,7 @@ export async function generateJSON( content: PROMPT, }, ], + mode: "json", }); const jsonString = parseTagFromResponse(response, "json_blob"); diff --git a/toolshed/routes/ai/llm/generateText.ts b/toolshed/routes/ai/llm/generateText.ts index f610fb31f..057f1c837 100644 --- a/toolshed/routes/ai/llm/generateText.ts +++ b/toolshed/routes/ai/llm/generateText.ts @@ -22,7 +22,7 @@ export interface GenerateTextParams { stop_token?: string; abortSignal?: AbortSignal; max_tokens?: number; - jsonMode?: boolean; + mode?: "json"; } export interface GenerateTextResult { @@ -147,13 +147,8 @@ export async function generateText( throw new Error(`Unsupported model: ${modelName}`); } - // Check if jsonMode is requested but not supported - if (params.jsonMode && !modelConfig.capabilities.jsonMode) { - throw new Error(`Model ${modelName} does not support jsonMode.`); - } - // Groq models don't support streaming in JSON mode - if (params.jsonMode && params.stream && modelName?.startsWith("groq:")) { + if (params.mode && params.stream && modelName?.startsWith("groq:")) { throw new Error("Groq models don't support streaming in JSON mode"); } @@ -169,8 +164,8 @@ export async function generateText( maxTokens: params.max_tokens, }; - // Apply JSON mode configuration if requested and supported - if (params.jsonMode && modelConfig.capabilities.jsonMode) { + // Apply JSON mode configuration if requested + if (params.mode) { configureJsonMode( streamParams, modelName!, @@ -206,15 +201,15 @@ export async function generateText( throw new Error("No response from LLM"); } - // Clean up JSON responses when jsonMode is enabled - if (params.jsonMode) { + // Clean up JSON responses when mode is enabled + if (params.mode) { result = cleanJsonResponse(result); } // Only add stop token if not in JSON mode to avoid breaking JSON structure if ( (await llmStream.finishReason) === "stop" && params.stop_token && - !params.jsonMode + !params.mode ) { result += params.stop_token; } @@ -251,7 +246,7 @@ export async function generateText( // Only add stop token if not in JSON mode to avoid breaking JSON structure if ( (await llmStream.finishReason) === "stop" && params.stop_token && - !params.jsonMode + !params.mode ) { result += params.stop_token; controller.enqueue( @@ -260,7 +255,7 @@ export async function generateText( } // For JSON mode, clean the result to strip any markdown code blocks - if (params.jsonMode) { + if (params.mode) { result = cleanJsonResponse(result); } diff --git a/toolshed/routes/ai/llm/llm.handlers.ts b/toolshed/routes/ai/llm/llm.handlers.ts index e3e73f6cf..b00572f56 100644 --- a/toolshed/routes/ai/llm/llm.handlers.ts +++ b/toolshed/routes/ai/llm/llm.handlers.ts @@ -14,7 +14,7 @@ import { findModel } from "./models.ts"; function validateModelAndJsonMode( c: Context, modelString: string | undefined, - jsonMode: boolean | undefined, + mode: string | undefined, ) { const model = modelString ? findModel(modelString) : null; @@ -22,17 +22,12 @@ function validateModelAndJsonMode( return c.json({ error: "Invalid model" }, HttpStatusCodes.BAD_REQUEST); } - // Validate jsonMode support if requested - if (jsonMode && !model.capabilities.jsonMode) { - return c.json( - { error: `Model ${modelString} does not support jsonMode.` }, - HttpStatusCodes.BAD_REQUEST, - ); - } + // Validate JSON mode support if requested + const isJsonMode = mode === "json"; // Groq models don't support streaming with JSON mode if ( - jsonMode && c.req.query("stream") === "true" && + isJsonMode && c.req.query("stream") === "true" && modelString?.startsWith("groq:") ) { return c.json( @@ -103,7 +98,7 @@ export const generateText: AppRouteHandler = async (c) => { const validationError = validateModelAndJsonMode( c, modelString, - payload.jsonMode, + payload.mode, ); if (validationError) { return validationError; @@ -113,8 +108,8 @@ export const generateText: AppRouteHandler = async (c) => { const modelDefaultMaxTokens = model?.capabilities.maxOutputTokens || 8000; try { - // Check cache for existing response - skip caching for jsonMode requests - if (!payload.jsonMode) { + // Check cache for existing response - skip caching for JSON mode requests + if (!payload.mode) { const cacheKey = await cache.hashKey(JSON.stringify(payload)); const cachedResult = await cache.loadItem(cacheKey); if (cachedResult) { @@ -131,8 +126,8 @@ export const generateText: AppRouteHandler = async (c) => { }); if (!payload.stream) { - // Save to cache only if not jsonMode - if (!payload.jsonMode) { + // Save to cache only if not in JSON mode + if (!payload.mode) { const cacheKey = await cache.hashKey(JSON.stringify(payload)); await cache.saveItem(cacheKey, { ...payload, diff --git a/toolshed/routes/ai/llm/llm.routes.ts b/toolshed/routes/ai/llm/llm.routes.ts index 4cbaa207a..93e26220e 100644 --- a/toolshed/routes/ai/llm/llm.routes.ts +++ b/toolshed/routes/ai/llm/llm.routes.ts @@ -23,7 +23,7 @@ export const LLMRequestSchema = z.object({ stop_token: z.string().optional(), max_completion_tokens: z.number().optional(), stream: z.boolean().default(false), - jsonMode: z.boolean().optional().default(false), + mode: z.enum(["json"]).optional(), }); export const ModelInfoSchema = z.object({ diff --git a/toolshed/routes/ai/llm/models.ts b/toolshed/routes/ai/llm/models.ts index cbb6a2a0c..c62a7674b 100644 --- a/toolshed/routes/ai/llm/models.ts +++ b/toolshed/routes/ai/llm/models.ts @@ -15,7 +15,6 @@ export type Capabilities = { stopSequences: boolean; prefill: boolean; images: boolean; - jsonMode?: boolean; }; type ModelConfig = { @@ -104,7 +103,6 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, - jsonMode: true, }, }); addModel({ @@ -119,7 +117,6 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, - jsonMode: true, }, }); @@ -138,7 +135,6 @@ if (env.CTTS_AI_LLM_ANTHROPIC_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, - jsonMode: true, }, providerOptions: { anthropic: { @@ -164,7 +160,6 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, }); @@ -180,7 +175,6 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, }); @@ -196,7 +190,6 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, }); @@ -212,7 +205,6 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: true, stopSequences: true, streaming: false, - jsonMode: true, }, }); @@ -228,7 +220,6 @@ if (env.CTTS_AI_LLM_GROQ_API_KEY) { systemPrompt: true, stopSequences: true, streaming: false, - jsonMode: true, }, }); } @@ -249,7 +240,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: true, stopSequences: true, streaming: true, - jsonMode: true, }, }); @@ -265,7 +255,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, providerOptions: { reasoningEffort: "low", @@ -284,7 +273,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, providerOptions: { reasoningEffort: "medium", @@ -303,7 +291,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, providerOptions: { reasoningEffort: "high", @@ -322,7 +309,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, providerOptions: { reasoningEffort: "low", @@ -341,7 +327,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, providerOptions: { reasoningEffort: "medium", @@ -360,7 +345,6 @@ if (env.CTTS_AI_LLM_OPENAI_API_KEY) { systemPrompt: false, stopSequences: false, streaming: true, - jsonMode: true, }, providerOptions: { reasoningEffort: "high", @@ -393,7 +377,6 @@ if (env.CTTS_AI_LLM_GOOGLE_APPLICATION_CREDENTIALS) { systemPrompt: true, stopSequences: true, streaming: true, - jsonMode: true, }, }); } @@ -417,7 +400,6 @@ if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { systemPrompt: false, stopSequences: true, streaming: true, - jsonMode: false, }, }); @@ -433,7 +415,6 @@ if (env.CTTS_AI_LLM_PERPLEXITY_API_KEY) { systemPrompt: false, stopSequences: true, streaming: true, - jsonMode: false, }, }); } From 9c80a6e2b61330ce4e9b80b1e77d473a95907470 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 09:59:29 -0600 Subject: [PATCH 07/18] adding some tests --- toolshed/routes/ai/llm/generateText.test.ts | 201 ++++++++++++++++++++ toolshed/routes/ai/llm/generateText.ts | 7 +- 2 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 toolshed/routes/ai/llm/generateText.test.ts diff --git a/toolshed/routes/ai/llm/generateText.test.ts b/toolshed/routes/ai/llm/generateText.test.ts new file mode 100644 index 000000000..3e131d365 --- /dev/null +++ b/toolshed/routes/ai/llm/generateText.test.ts @@ -0,0 +1,201 @@ +import { assertEquals } from "@std/assert"; +import env from "@/env.ts"; + +// Import the functions for testing +import { cleanJsonResponse, configureJsonMode } from "./generateText.ts"; + +if (env.ENV !== "test") { + throw new Error("ENV must be 'test'"); +} + +Deno.test("JSON mode configuration", async (t) => { + // Test for Groq models + await t.step("Configures JSON mode correctly for Groq models", () => { + const streamParams: Record = {}; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "groq:llama-3.3-70b", messages, false); + + assertEquals(streamParams.mode, undefined); + assertEquals(streamParams.response_format, { type: "json_object" }); + assertEquals(streamParams.providerOptions?.groq?.response_format, { + type: "json_object", + }); + assertEquals(typeof streamParams.system, "string"); + assertEquals( + streamParams.system.includes("respond with pure, correct JSON only"), + true, + ); + }); + + // Test for OpenAI models + await t.step("Configures JSON mode correctly for OpenAI models", () => { + const streamParams: Record = {}; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "openai:gpt-4o", messages, false); + + assertEquals(streamParams.mode, undefined); + assertEquals(streamParams.response_format, { type: "json_object" }); + assertEquals(streamParams.providerOptions?.openai?.response_format, { + type: "json_object", + }); + }); + + // Test for Anthropic models + await t.step("Configures JSON mode correctly for Anthropic models", () => { + const streamParams: Record = {}; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode( + streamParams, + "anthropic:claude-3-7-sonnet", + messages, + false, + ); + + assertEquals(streamParams.mode, "json"); + assertEquals( + streamParams.system.includes("JSON generation assistant"), + true, + ); + assertEquals(streamParams.prefill?.text, "{\n"); + }); + + // Test with existing system prompt + await t.step( + "Preserves existing system prompt while adding JSON instructions", + () => { + const streamParams: Record = { + system: "You are an expert assistant.", + }; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode( + streamParams, + "anthropic:claude-3-7-sonnet", + messages, + false, + ); + + assertEquals( + streamParams.system.includes( + "You are a JSON generation assistant. You are an expert assistant.", + ), + true, + ); + assertEquals( + streamParams.system.includes("response must be ONLY valid JSON"), + true, + ); + }, + ); + + // Test for other providers + await t.step("Configures JSON mode correctly for other providers", () => { + const streamParams: Record = {}; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "other:model", messages, false); + + assertEquals(streamParams.mode, "json"); + assertEquals( + streamParams.system.includes("Ensure the response is valid JSON"), + true, + ); + }); + + // Test for other providers with existing system prompt + await t.step( + "Adds JSON instructions to existing system prompt for other providers", + () => { + const streamParams: Record = { + system: "You are an expert assistant.", + }; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "other:model", messages, false); + + assertEquals( + streamParams.system, + "You are an expert assistant.\nEnsure the response is valid JSON. DO NOT include any other text or formatting.", + ); + }, + ); + + // Test that JSON instructions are always added, even if the prompt already mentions JSON + await t.step( + "Always adds JSON instructions even when system prompt already mentions JSON", + () => { + const streamParams: Record = { + system: "You are an expert assistant who responds in JSON format.", + }; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "other:model", messages, false); + + // Should always add our JSON instructions + assertEquals( + streamParams.system, + "You are an expert assistant who responds in JSON format.\nEnsure the response is valid JSON. DO NOT include any other text or formatting.", + ); + }, + ); +}); + +Deno.test("cleanJsonResponse function", async (t) => { + await t.step("Extracts JSON from markdown code blocks", () => { + const input = '```json\n{"name": "Test", "value": 123}\n```'; + const expected = '{"name": "Test", "value": 123}'; + assertEquals(cleanJsonResponse(input), expected); + }); + + await t.step( + "Extracts JSON from code blocks without language specifier", + () => { + const input = '```\n{"name": "Test", "value": 123}\n```'; + const expected = '{"name": "Test", "value": 123}'; + assertEquals(cleanJsonResponse(input), expected); + }, + ); + + await t.step("Handles multiline JSON in code blocks", () => { + const input = '```json\n{\n "name": "Test",\n "value": 123\n}\n```'; + const expected = '{\n "name": "Test",\n "value": 123\n}'; + assertEquals(cleanJsonResponse(input), expected); + }); + + await t.step("Returns original text if no code blocks found", () => { + const input = '{"name": "Test", "value": 123}'; + assertEquals(cleanJsonResponse(input), input); + }); + + await t.step( + "Returns original text if code block format is incorrect", + () => { + const input = '```json {"name": "Test", "value": 123}```'; + assertEquals(cleanJsonResponse(input), input); + }, + ); +}); diff --git a/toolshed/routes/ai/llm/generateText.ts b/toolshed/routes/ai/llm/generateText.ts index 057f1c837..3d5d14bf7 100644 --- a/toolshed/routes/ai/llm/generateText.ts +++ b/toolshed/routes/ai/llm/generateText.ts @@ -31,7 +31,7 @@ export interface GenerateTextResult { } // Configure the model parameters for JSON mode based on provider -function configureJsonMode( +export function configureJsonMode( streamParams: Record, modelName: string, messages: { role: "user" | "assistant"; content: string }[], @@ -101,14 +101,15 @@ function configureJsonMode( // For other providers, set a standard system prompt if one isn't provided if (!streamParams.system) { streamParams.system = JSON_SYSTEM_PROMPTS.DEFAULT; - } else if (!streamParams.system.toLowerCase().includes("json")) { + } else { + // Always append JSON instructions, even if the prompt already mentions JSON streamParams.system += "\n" + JSON_SYSTEM_PROMPTS.DEFAULT; } } } // Add a helper function to clean up JSON responses from markdown code blocks -function cleanJsonResponse(text: string): string { +export function cleanJsonResponse(text: string): string { // Check if the response is wrapped in markdown code blocks const jsonCodeBlockRegex = /```(json)?\s*\n([\s\S]*?)\n```/; const match = text.match(jsonCodeBlockRegex); From 5e62e9ee0e8a1e550de093aca9be90b90e9bb3b9 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 10:02:11 -0600 Subject: [PATCH 08/18] updating cache --- ...50a1f503e51a8fd3e6192b100e3cb49d1e308.json | 19 ------------------ ...890619add3c6a7feddf9733a7f522932625d3.json | 20 +++++++++++++++++++ ...6f5a8920618bc6c852d3802351529b5e1191.json} | 4 ++-- ...30bac958a51df98cdd3316b9914bb655ec5b6.json | 20 ------------------- ...9211adcdd67baa80dcc1a9ec3877197842a0.json} | 4 ++-- 5 files changed, 24 insertions(+), 43 deletions(-) delete mode 100644 jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json create mode 100644 jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json rename jumble/integration/cache/llm-api-cache/{9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json => 3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json} (57%) delete mode 100644 jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json rename jumble/integration/cache/llm-api-cache/{9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json => cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json} (63%) diff --git a/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json b/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json deleted file mode 100644 index 65abfd58f..000000000 --- a/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", - "stream": false, - "messages": [ - { - "role": "user", - "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]" - }, - { - "role": "assistant", - "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." - }, - { - "role": "assistant", - "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." - } - ] -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json b/jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json new file mode 100644 index 000000000..ec3e69937 --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: {} });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to add a new value to the array\n const addValue = () => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...simpleValue2.values, inputValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setInputValue(\"\");\n };\n\n // Function to remove a value from the array\n const removeValue = (index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ values: updatedValues });\n };\n\n // Function to analyze and count values\n const analyzeValues = () => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n // Count occurrences of each value\n const valuesCounts = {};\n const values = simpleValue2.values || [];\n \n values.forEach(value => {\n valuesCounts[value] = (valuesCounts[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(valuesCounts);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(valuesCounts).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n };\n\n // Function to clear all data\n const clearAll = () => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n };\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Input Values

\n \n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n {/* Values list */}\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n
\n \n {isAnalyzing ? \"Analyzing...\" : \"Analyze Values\"}\n \n \n \n Clear All\n \n
\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n \n
\n
\n

Total Values

\n

{totalValues}

\n
\n \n
\n

Unique Values

\n

{uniqueValues}

\n
\n \n
\n

Last Updated

\n

\n {new Date(timestamp).toLocaleString()}\n

\n
\n
\n \n

Value Counts:

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? ((count / totalValues) * 100).toFixed(1) + \"%\" : \"0%\"}\n
\n
\n
\n )}\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: {} });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to add a new value to the array\n const addValue = () => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...simpleValue2.values, inputValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setInputValue(\"\");\n };\n\n // Function to remove a value from the array\n const removeValue = (index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ values: updatedValues });\n };\n\n // Function to analyze and count values\n const analyzeValues = () => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n // Count occurrences of each value\n const valuesCounts = {};\n const values = simpleValue2.values || [];\n \n values.forEach(value => {\n valuesCounts[value] = (valuesCounts[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(valuesCounts);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(valuesCounts).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n };\n\n // Function to clear all data\n const clearAll = () => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n };\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Input Values

\n \n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n {/* Values list */}\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n
\n \n {isAnalyzing ? \"Analyzing...\" : \"Analyze Values\"}\n \n \n \n Clear All\n \n
\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n \n
\n
\n

Total Values

\n

{totalValues}

\n
\n \n
\n

Unique Values

\n

{uniqueValues}

\n
\n \n
\n

Last Updated

\n

\n {new Date(timestamp).toLocaleString()}\n

\n
\n
\n \n

Value Counts:

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? ((count / totalValues) * 100).toFixed(1) + \"%\" : \"0%\"}\n
\n
\n
\n )}\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json b/jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json similarity index 57% rename from jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json rename to jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json index 8b215aa49..eb7ded58e 100644 --- a/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json +++ b/jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display values and their frequencies\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"default\": 0,\n \"minimum\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last updated\"\n },\n \"mostFrequent\": {\n \"type\": \"string\",\n \"title\": \"Most Frequent\",\n \"description\": \"The value that appears most frequently\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1,\n \"pear\": 1\n },\n \"totalEntries\": 7,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\",\n \"mostFrequent\": \"apple\"\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display values and their frequencies\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"default\": 0,\n \"minimum\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last updated\"\n },\n \"mostFrequent\": {\n \"type\": \"string\",\n \"title\": \"Most Frequent\",\n \"description\": \"The value that appears most frequently\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1,\n \"pear\": 1\n },\n \"totalEntries\": 7,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\",\n \"mostFrequent\": \"apple\"\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json b/jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json deleted file mode 100644 index 71f4a2219..000000000 --- a/jumble/integration/cache/llm-api-cache/c7d7182e68202f131adfa9e2f2830bac958a51df98cdd3316b9914bb655ec5b6.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `jsonMode` flag in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n jsonMode: true\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" - }, - { - "role": "assistant", - "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Get the original data structure\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalCount, setTotalCount] = useDoc(\"totalCount\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n \n // Local state for new value input\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the values array and count occurrences\n React.useEffect(() => {\n // Extract the values array\n const values = simpleValue2.values || [];\n \n // Count occurrences of each unique value\n const valueCounts = {};\n values.forEach(value => {\n valueCounts[value] = (valueCounts[value] || 0) + 1;\n });\n \n // Update the counts, total count, and unique count\n setCounts(valueCounts);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(valueCounts).length);\n \n // Update the original data\n setOriginalData({ simpleValue2: { values: [...values] } });\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim()) {\n const updatedValues = [...simpleValue2.values, newValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setNewValue(\"\");\n }\n };\n \n // Remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter((_, index) => index !== valueToRemove);\n setSimpleValue2({ values: updatedValues });\n };\n \n // Clear all values\n const handleClearValues = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n \n Clear All Values\n \n
\n \n {/* Values list */}\n
\n

Values List

\n {simpleValue2.values.length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {simpleValue2.values.map((value, index) => (\n \n \n \n \n \n ))}\n \n
IndexValueAction
{index}{value}\n handleRemoveValue(index)}\n className=\"text-red-600 hover:text-red-900\"\n >\n Remove\n \n
\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Count summary */}\n
\n

Count Summary

\n
\n
\n
\n

Total Values

\n

{totalCount}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n
\n
\n \n {/* Value counts */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalCount > 0 ? `${((count / totalCount) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No values to count.

\n )}\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Get the original data structure\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalCount, setTotalCount] = useDoc(\"totalCount\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n \n // Local state for new value input\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the values array and count occurrences\n React.useEffect(() => {\n // Extract the values array\n const values = simpleValue2.values || [];\n \n // Count occurrences of each unique value\n const valueCounts = {};\n values.forEach(value => {\n valueCounts[value] = (valueCounts[value] || 0) + 1;\n });\n \n // Update the counts, total count, and unique count\n setCounts(valueCounts);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(valueCounts).length);\n \n // Update the original data\n setOriginalData({ simpleValue2: { values: [...values] } });\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim()) {\n const updatedValues = [...simpleValue2.values, newValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setNewValue(\"\");\n }\n };\n \n // Remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter((_, index) => index !== valueToRemove);\n setSimpleValue2({ values: updatedValues });\n };\n \n // Clear all values\n const handleClearValues = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n \n Clear All Values\n \n
\n \n {/* Values list */}\n
\n

Values List

\n {simpleValue2.values.length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {simpleValue2.values.map((value, index) => (\n \n \n \n \n \n ))}\n \n
IndexValueAction
{index}{value}\n handleRemoveValue(index)}\n className=\"text-red-600 hover:text-red-900\"\n >\n Remove\n \n
\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Count summary */}\n
\n

Count Summary

\n
\n
\n
\n

Total Values

\n

{totalCount}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n
\n
\n \n {/* Value counts */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalCount > 0 ? `${((count / totalCount) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No values to count.

\n )}\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json b/jumble/integration/cache/llm-api-cache/cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json similarity index 63% rename from jumble/integration/cache/llm-api-cache/9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json rename to jumble/integration/cache/llm-api-cache/cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json index 61b508939..e6bca0186 100644 --- a/jumble/integration/cache/llm-api-cache/9fbdc34b0cfd31001621cf6a1e4498033d146e3b2627adac30477a9aa8a41cab.json +++ b/jumble/integration/cache/llm-api-cache/cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting occurrences in the values array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"required\": [\"counts\", \"totalValues\", \"uniqueValues\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the existing object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Generate a result object containing the original data plus the count information.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting occurrences in the values array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"required\": [\"counts\", \"totalValues\", \"uniqueValues\"]\n}\n" } ] } \ No newline at end of file From ce8b69ada8808c8c30c0a6632d7963ae1384170d Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 11:31:42 -0600 Subject: [PATCH 09/18] updating cache --- ...356e4e617817d38434ec29f008b7b661c5230.json | 19 ++++++++++++++++++ ...50a1f503e51a8fd3e6192b100e3cb49d1e308.json | 19 ++++++++++++++++++ ...890619add3c6a7feddf9733a7f522932625d3.json | 20 ------------------- ...e6f5a8920618bc6c852d3802351529b5e1191.json | 19 ------------------ ...7e5f1f3201717f7409e8e7ab43baef8b11f2f.json | 20 +++++++++++++++++++ 5 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json create mode 100644 jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json delete mode 100644 jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json delete mode 100644 jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json create mode 100644 jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json diff --git a/jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json b/jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json new file mode 100644 index 000000000..14a79df64 --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json @@ -0,0 +1,19 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", + "stream": false, + "messages": [ + { + "role": "user", + "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"count of values\"}]}]" + }, + { + "role": "assistant", + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" + }, + { + "role": "assistant", + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" + } + ] +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json b/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json new file mode 100644 index 000000000..65abfd58f --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json @@ -0,0 +1,19 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", + "stream": false, + "messages": [ + { + "role": "user", + "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]" + }, + { + "role": "assistant", + "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." + }, + { + "role": "assistant", + "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." + } + ] +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json b/jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json deleted file mode 100644 index ec3e69937..000000000 --- a/jumble/integration/cache/llm-api-cache/1e28e7cdbdb11f565b8a7ac8fdd890619add3c6a7feddf9733a7f522932625d3.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: {} });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to add a new value to the array\n const addValue = () => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...simpleValue2.values, inputValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setInputValue(\"\");\n };\n\n // Function to remove a value from the array\n const removeValue = (index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ values: updatedValues });\n };\n\n // Function to analyze and count values\n const analyzeValues = () => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n // Count occurrences of each value\n const valuesCounts = {};\n const values = simpleValue2.values || [];\n \n values.forEach(value => {\n valuesCounts[value] = (valuesCounts[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(valuesCounts);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(valuesCounts).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n };\n\n // Function to clear all data\n const clearAll = () => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n };\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Input Values

\n \n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n {/* Values list */}\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n
\n \n {isAnalyzing ? \"Analyzing...\" : \"Analyze Values\"}\n \n \n \n Clear All\n \n
\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n \n
\n
\n

Total Values

\n

{totalValues}

\n
\n \n
\n

Unique Values

\n

{uniqueValues}

\n
\n \n
\n

Last Updated

\n

\n {new Date(timestamp).toLocaleString()}\n

\n
\n
\n \n

Value Counts:

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? ((count / totalValues) * 100).toFixed(1) + \"%\" : \"0%\"}\n
\n
\n
\n )}\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: {} });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to add a new value to the array\n const addValue = () => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...simpleValue2.values, inputValue.trim()];\n setSimpleValue2({ values: updatedValues });\n setInputValue(\"\");\n };\n\n // Function to remove a value from the array\n const removeValue = (index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ values: updatedValues });\n };\n\n // Function to analyze and count values\n const analyzeValues = () => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n // Count occurrences of each value\n const valuesCounts = {};\n const values = simpleValue2.values || [];\n \n values.forEach(value => {\n valuesCounts[value] = (valuesCounts[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(valuesCounts);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(valuesCounts).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n };\n\n // Function to clear all data\n const clearAll = () => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n };\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Input Values

\n \n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n {/* Values list */}\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n
\n \n {isAnalyzing ? \"Analyzing...\" : \"Analyze Values\"}\n \n \n \n Clear All\n \n
\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n \n
\n
\n

Total Values

\n

{totalValues}

\n
\n \n
\n

Unique Values

\n

{uniqueValues}

\n
\n \n
\n

Last Updated

\n

\n {new Date(timestamp).toLocaleString()}\n

\n
\n
\n \n

Value Counts:

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? ((count / totalValues) * 100).toFixed(1) + \"%\" : \"0%\"}\n
\n
\n
\n )}\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json b/jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json deleted file mode 100644 index eb7ded58e..000000000 --- a/jumble/integration/cache/llm-api-cache/3c0c3b9ec370437764cb139808fe6f5a8920618bc6c852d3802351529b5e1191.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", - "stream": false, - "messages": [ - { - "role": "user", - "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"count of values\"}]}]" - }, - { - "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display values and their frequencies\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"default\": 0,\n \"minimum\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last updated\"\n },\n \"mostFrequent\": {\n \"type\": \"string\",\n \"title\": \"Most Frequent\",\n \"description\": \"The value that appears most frequently\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1,\n \"pear\": 1\n },\n \"totalEntries\": 7,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\",\n \"mostFrequent\": \"apple\"\n}\n" - }, - { - "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display values and their frequencies\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"default\": 0,\n \"minimum\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last updated\"\n },\n \"mostFrequent\": {\n \"type\": \"string\",\n \"title\": \"Most Frequent\",\n \"description\": \"The value that appears most frequently\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1,\n \"pear\": 1\n },\n \"totalEntries\": 7,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\",\n \"mostFrequent\": \"apple\"\n}\n" - } - ] -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json b/jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json new file mode 100644 index 000000000..b035b41fb --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to count values\n const countValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const frequencyCounter = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n frequencyCounter[value] = (frequencyCounter[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(frequencyCounter);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(frequencyCounter).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n }, [simpleValue2, setCounts, setOriginalData, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue(\"\");\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n }, [setSimpleValue2, setCounts, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Remove a specific value\n const removeValue = React.useCallback((index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n }, [simpleValue2, setSimpleValue2]);\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n {isAnalyzing ? 'Analyzing...' : 'Count Values'}\n \n \n \n Clear All\n \n
\n
\n \n {/* Current values */}\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n
\n {value}\n \n
\n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n
\n
\n

Total Values

\n

{totalValues}

\n
\n
\n

Unique Values

\n

{uniqueValues}

\n
\n
\n \n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? `${((count / totalValues) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No data to display

\n )}\n \n

\n Last analyzed: {new Date(timestamp).toLocaleString()}\n

\n
\n )}\n
\n );\n }\n\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to count values\n const countValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const frequencyCounter = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n frequencyCounter[value] = (frequencyCounter[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(frequencyCounter);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(frequencyCounter).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n }, [simpleValue2, setCounts, setOriginalData, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue(\"\");\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n }, [setSimpleValue2, setCounts, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Remove a specific value\n const removeValue = React.useCallback((index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n }, [simpleValue2, setSimpleValue2]);\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n {isAnalyzing ? 'Analyzing...' : 'Count Values'}\n \n \n \n Clear All\n \n
\n
\n \n {/* Current values */}\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n
\n {value}\n \n
\n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n
\n
\n

Total Values

\n

{totalValues}

\n
\n
\n

Unique Values

\n

{uniqueValues}

\n
\n
\n \n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? `${((count / totalValues) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No data to display

\n )}\n \n

\n Last analyzed: {new Date(timestamp).toLocaleString()}\n

\n
\n )}\n
\n );\n }\n\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file From 1d5d58cc0ebbe4c71efc36a7a860991d6b04796d Mon Sep 17 00:00:00 2001 From: jakedahn Date: Wed, 2 Apr 2025 14:35:07 -0600 Subject: [PATCH 10/18] idk --- jumble/integration/basic-flow.test.ts | 4 ++-- ...356e4e617817d38434ec29f008b7b661c5230.json | 19 ------------------ ...50a1f503e51a8fd3e6192b100e3cb49d1e308.json | 19 ------------------ ...76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json} | 4 ++-- ...ca56220e30070df5e702a3a919b15a1df7890.json | 20 +++++++++++++++++++ ...8fc10f4b0b5f705ef353de1f26f02e0a60f30.json | 19 ++++++++++++++++++ ...7e5f1f3201717f7409e8e7ab43baef8b11f2f.json | 20 ------------------- toolshed/routes/ai/llm/llm.handlers.ts | 3 +++ 8 files changed, 46 insertions(+), 62 deletions(-) delete mode 100644 jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json delete mode 100644 jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json rename jumble/integration/cache/llm-api-cache/{cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json => 225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json} (57%) create mode 100644 jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json create mode 100644 jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json delete mode 100644 jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json diff --git a/jumble/integration/basic-flow.test.ts b/jumble/integration/basic-flow.test.ts index bcf81cc0f..b966d0875 100644 --- a/jumble/integration/basic-flow.test.ts +++ b/jumble/integration/basic-flow.test.ts @@ -22,7 +22,7 @@ import { const TOOLSHED_API_URL = Deno.env.get("TOOLSHED_API_URL") ?? "http://localhost:8000/"; const FRONTEND_URL = Deno.env.get("FRONTEND_URL") ?? "http://localhost:5173/"; -const HEADLESS = true; +const HEADLESS = false; const ASTRAL_TIMEOUT = 60_000; console.log(`TOOLSHED_API_URL=${TOOLSHED_API_URL}`); @@ -216,7 +216,7 @@ Deno.test({ await sleep(1000); await page.keyboard.press("Enter"); - await sleep(1000); + await sleep(300); await page.keyboard.type("count of values"); await sleep(1000); await page.keyboard.press("Enter"); diff --git a/jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json b/jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json deleted file mode 100644 index 14a79df64..000000000 --- a/jumble/integration/cache/llm-api-cache/0a5b50a7d3df347fa9d0519e5e5356e4e617817d38434ec29f008b7b661c5230.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", - "stream": false, - "messages": [ - { - "role": "user", - "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"count of values\"}]}]" - }, - { - "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" - }, - { - "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" - } - ] -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json b/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json deleted file mode 100644 index 65abfd58f..000000000 --- a/jumble/integration/cache/llm-api-cache/1121698eba5445cf467a71ae23350a1f503e51a8fd3e6192b100e3cb49d1e308.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", - "stream": false, - "messages": [ - { - "role": "user", - "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]" - }, - { - "role": "assistant", - "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." - }, - { - "role": "assistant", - "content": "I need more information about what you'd like to create. Please provide a feature request or describe what you're trying to build, and I'll help you create a minimal viable product specification for it." - } - ] -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json b/jumble/integration/cache/llm-api-cache/225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json similarity index 57% rename from jumble/integration/cache/llm-api-cache/cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json rename to jumble/integration/cache/llm-api-cache/225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json index e6bca0186..808639cd6 100644 --- a/jumble/integration/cache/llm-api-cache/cd47c89196f8dfc62b5e655b2e0d9211adcdd67baa80dcc1a9ec3877197842a0.json +++ b/jumble/integration/cache/llm-api-cache/225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"required\": [\"counts\", \"totalValues\", \"uniqueValues\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the input object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Return a result object containing the original data plus the count results.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting values in an array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"required\": [\"counts\", \"totalValues\", \"uniqueValues\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the input object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Return a result object containing the original data plus the count results.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting values in an array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json b/jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json new file mode 100644 index 000000000..5460beeff --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Parse the input object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Return a result object containing the original data plus the count results.\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n const [originalData, setOriginalData] = useDoc('originalData', { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc('counts', {});\n const [totalCount, setTotalCount] = useDoc('totalCount', 0);\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n \n // UI state\n const [inputValue, setInputValue] = React.useState('');\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Process the values array and count occurrences\n const analyzeValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n try {\n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const countMap = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts\n setCounts(countMap);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(countMap).length);\n } catch (error) {\n console.error(\"Error analyzing values:\", error);\n } finally {\n setIsAnalyzing(false);\n }\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim()) {\n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue('');\n }\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalCount(0);\n setUniqueCount(0);\n }, [setSimpleValue2, setCounts, setTotalCount, setUniqueCount]);\n\n // Handle input change\n const handleInputChange = React.useCallback((e) => {\n setInputValue(e.target.value);\n }, []);\n\n // Handle key press (Enter to add)\n const handleKeyPress = React.useCallback((e) => {\n if (e.key === 'Enter') {\n addValue();\n }\n }, [addValue]);\n\n return (\n
\n

{title}

\n \n {/* Input Section */}\n
\n

Add Values

\n
\n \n \n Add\n \n \n Clear All\n \n
\n
\n \n {/* Current Values */}\n
\n

Current Values

\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n \n {value}\n \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n
\n 0)}\n className={`px-4 py-2 rounded text-white ${\n isAnalyzing || !(simpleValue2.values && simpleValue2.values.length > 0)\n ? 'bg-gray-400 cursor-not-allowed'\n : 'bg-green-600 hover:bg-green-700 transition-colors'\n }`}\n >\n {isAnalyzing ? 'Analyzing...' : 'Analyze Values'}\n \n
\n
\n \n {/* Results Section */}\n
\n

Analysis Results

\n \n
\n
\n

Summary

\n

Total values: {totalCount}

\n

Unique values: {uniqueCount}

\n
\n \n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n {value}\n {count}\n
\n ))}\n
\n ) : (\n

No analysis data yet

\n )}\n
\n
\n
\n \n {/* Original Data Section */}\n
\n

Original Data

\n
\n
\n              {JSON.stringify(originalData, null, 2)}\n            
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n const [originalData, setOriginalData] = useDoc('originalData', { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc('counts', {});\n const [totalCount, setTotalCount] = useDoc('totalCount', 0);\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n \n // UI state\n const [inputValue, setInputValue] = React.useState('');\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Process the values array and count occurrences\n const analyzeValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n try {\n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const countMap = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts\n setCounts(countMap);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(countMap).length);\n } catch (error) {\n console.error(\"Error analyzing values:\", error);\n } finally {\n setIsAnalyzing(false);\n }\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim()) {\n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue('');\n }\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalCount(0);\n setUniqueCount(0);\n }, [setSimpleValue2, setCounts, setTotalCount, setUniqueCount]);\n\n // Handle input change\n const handleInputChange = React.useCallback((e) => {\n setInputValue(e.target.value);\n }, []);\n\n // Handle key press (Enter to add)\n const handleKeyPress = React.useCallback((e) => {\n if (e.key === 'Enter') {\n addValue();\n }\n }, [addValue]);\n\n return (\n
\n

{title}

\n \n {/* Input Section */}\n
\n

Add Values

\n
\n \n \n Add\n \n \n Clear All\n \n
\n
\n \n {/* Current Values */}\n
\n

Current Values

\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n \n {value}\n \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n
\n 0)}\n className={`px-4 py-2 rounded text-white ${\n isAnalyzing || !(simpleValue2.values && simpleValue2.values.length > 0)\n ? 'bg-gray-400 cursor-not-allowed'\n : 'bg-green-600 hover:bg-green-700 transition-colors'\n }`}\n >\n {isAnalyzing ? 'Analyzing...' : 'Analyze Values'}\n \n
\n
\n \n {/* Results Section */}\n
\n

Analysis Results

\n \n
\n
\n

Summary

\n

Total values: {totalCount}

\n

Unique values: {uniqueCount}

\n
\n \n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n {value}\n {count}\n
\n ))}\n
\n ) : (\n

No analysis data yet

\n )}\n
\n
\n
\n \n {/* Original Data Section */}\n
\n

Original Data

\n
\n
\n              {JSON.stringify(originalData, null, 2)}\n            
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json b/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json new file mode 100644 index 000000000..8b215aa49 --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json @@ -0,0 +1,19 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "\nYou are creating a simple minimal viable product (MVP) based on a user's goal. Focus on the simplest implementation that works.\n\nGiven a user's feature request, you will:\n1. Create a short title (2-5 words) that names the artifact\n2. Create a one-sentence description in the format \"A to \"\n3. Create a concise specification (3-5 sentences max)\n4. Generate a brief implementation plan (3 steps max)\n5. Design a minimal JSON schema that represents the core data model\n\nYour response must be structured as follows:\n\n\n[Short title for the artifact, 2-5 words]\n\n\n\n[One-sentence description in the format \"A to \"]\n\n\n\n[Concise specification that captures only the essential requirements]\n\n\n\n[Brief 3-step implementation plan]\n\n\n\n[Minimal JSON Schema in valid JSON format that represents the core data model]\n\n\n\n[Simple example data that conforms to the schema]\n\n\nSCHEMA GUIDELINES:\n1. Keep it minimal:\n - Include only essential fields (5-7 properties max)\n - Focus on the core functionality\n - If user requested complex features, simplify for this first version\n \n2. Each property should have:\n - A descriptive \"title\" field\n - A brief \"description\" field\n - A sensible default value where appropriate\n \n3. Example of a simple schema:\n```json\n{\n \"type\": \"object\",\n \"title\": \"Note\",\n \"description\": \"A simple note for the user\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"title\": \"Title\",\n \"description\": \"Title of the note\",\n \"default\": \"New Note\"\n },\n \"content\": {\n \"type\": \"string\",\n \"title\": \"Content\",\n \"description\": \"Content of the note\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the note was created\",\n }\n },\n \"required\": [\"title\", \"content\"]\n}\n```\n\nIMPORTANT:\n- Focus on the simplest working version\n- Aim for fewer fields rather than more\n- But still capture all the important state the user is creating\n- Remember, the user can always iterate and improve the solution later\n", + "stream": false, + "messages": [ + { + "role": "user", + "content": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"count of values\"}]}]" + }, + { + "role": "assistant", + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + }, + { + "role": "assistant", + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + } + ] +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json b/jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json deleted file mode 100644 index b035b41fb..000000000 --- a/jumble/integration/cache/llm-api-cache/a2a0e87f5f1019ab7bbee0a11df7e5f1f3201717f7409e8e7ab43baef8b11f2f.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\"\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalValues\": {\n \"type\": \"integer\",\n \"title\": \"Total Values\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueValues\": {\n \"type\": \"integer\",\n \"title\": \"Unique Values\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n },\n \"timestamp\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Timestamp\",\n \"description\": \"When the count was performed\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object\n2. Count occurrences of each unique string value using a frequency counter approach\n3. Generate a result object with the counts while preserving the original data\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to count values\n const countValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const frequencyCounter = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n frequencyCounter[value] = (frequencyCounter[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(frequencyCounter);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(frequencyCounter).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n }, [simpleValue2, setCounts, setOriginalData, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue(\"\");\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n }, [setSimpleValue2, setCounts, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Remove a specific value\n const removeValue = React.useCallback((index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n }, [simpleValue2, setSimpleValue2]);\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n {isAnalyzing ? 'Analyzing...' : 'Count Values'}\n \n \n \n Clear All\n \n
\n
\n \n {/* Current values */}\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n
\n {value}\n \n
\n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n
\n
\n

Total Values

\n

{totalValues}

\n
\n
\n

Unique Values

\n

{uniqueValues}

\n
\n
\n \n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? `${((count / totalValues) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No data to display

\n )}\n \n

\n Last analyzed: {new Date(timestamp).toLocaleString()}\n

\n
\n )}\n
\n );\n }\n\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [originalData, setOriginalData] = useDoc(\"originalData\", { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [totalValues, setTotalValues] = useDoc(\"totalValues\", 0);\n const [uniqueValues, setUniqueValues] = useDoc(\"uniqueValues\", 0);\n const [timestamp, setTimestamp] = useDoc(\"timestamp\", \"\");\n \n // UI state\n const [inputValue, setInputValue] = React.useState(\"\");\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Function to count values\n const countValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const frequencyCounter = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n frequencyCounter[value] = (frequencyCounter[value] || 0) + 1;\n });\n \n // Update state with results\n setCounts(frequencyCounter);\n setTotalValues(values.length);\n setUniqueValues(Object.keys(frequencyCounter).length);\n setTimestamp(new Date().toISOString());\n \n setIsAnalyzing(false);\n }, [simpleValue2, setCounts, setOriginalData, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim() === \"\") return;\n \n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue(\"\");\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalValues(0);\n setUniqueValues(0);\n setTimestamp(\"\");\n }, [setSimpleValue2, setCounts, setTotalValues, setUniqueValues, setTimestamp]);\n\n // Remove a specific value\n const removeValue = React.useCallback((index) => {\n const updatedValues = [...simpleValue2.values];\n updatedValues.splice(index, 1);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n }, [simpleValue2, setSimpleValue2]);\n\n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setInputValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n {isAnalyzing ? 'Analyzing...' : 'Count Values'}\n \n \n \n Clear All\n \n
\n
\n \n {/* Current values */}\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n
\n {value}\n \n
\n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Results section */}\n {timestamp && (\n
\n

Analysis Results

\n
\n
\n

Total Values

\n

{totalValues}

\n
\n
\n

Unique Values

\n

{uniqueValues}

\n
\n
\n \n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count], index) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {totalValues > 0 ? `${((count / totalValues) * 100).toFixed(1)}%` : '0%'}\n
\n
\n ) : (\n

No data to display

\n )}\n \n

\n Last analyzed: {new Date(timestamp).toLocaleString()}\n

\n
\n )}\n
\n );\n }\n\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/toolshed/routes/ai/llm/llm.handlers.ts b/toolshed/routes/ai/llm/llm.handlers.ts index b00572f56..7e86b7cdd 100644 --- a/toolshed/routes/ai/llm/llm.handlers.ts +++ b/toolshed/routes/ai/llm/llm.handlers.ts @@ -92,6 +92,9 @@ export const getModels: AppRouteHandler = (c) => { export const generateText: AppRouteHandler = async (c) => { const payload = await c.req.json(); + console.log("LLM HASH", await cache.hashKey(JSON.stringify(payload))); + console.log("LLM PAYLOAD", JSON.stringify(payload, null, 2)); + const modelString = payload.model; // Validate model and JSON mode compatibility From bff7ea8bbde7f4addfaf101f463bd46705bb740a Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 09:27:39 -0600 Subject: [PATCH 11/18] attempting to fix --- toolshed/routes/ai/llm/llm.handlers.ts | 39 +++++++++++--------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/toolshed/routes/ai/llm/llm.handlers.ts b/toolshed/routes/ai/llm/llm.handlers.ts index 7e86b7cdd..0bc131794 100644 --- a/toolshed/routes/ai/llm/llm.handlers.ts +++ b/toolshed/routes/ai/llm/llm.handlers.ts @@ -95,33 +95,27 @@ export const generateText: AppRouteHandler = async (c) => { console.log("LLM HASH", await cache.hashKey(JSON.stringify(payload))); console.log("LLM PAYLOAD", JSON.stringify(payload, null, 2)); - const modelString = payload.model; + // Check cache for existing response + const cacheKey = await cache.hashKey(JSON.stringify(payload)); + const cachedResult = await cache.loadItem(cacheKey); + if (cachedResult) { + const lastMessage = cachedResult.messages[cachedResult.messages.length - 1]; + return c.json(lastMessage); + } - // Validate model and JSON mode compatibility const validationError = validateModelAndJsonMode( c, - modelString, + payload.model, payload.mode, ); if (validationError) { return validationError; } - const model = findModel(modelString!); + const model = findModel(payload.model); const modelDefaultMaxTokens = model?.capabilities.maxOutputTokens || 8000; try { - // Check cache for existing response - skip caching for JSON mode requests - if (!payload.mode) { - const cacheKey = await cache.hashKey(JSON.stringify(payload)); - const cachedResult = await cache.loadItem(cacheKey); - if (cachedResult) { - const lastMessage = - cachedResult.messages[cachedResult.messages.length - 1]; - return c.json(lastMessage); - } - } - const result = await generateTextCore({ ...payload, abortSignal: c.req.raw.signal, @@ -129,14 +123,13 @@ export const generateText: AppRouteHandler = async (c) => { }); if (!payload.stream) { - // Save to cache only if not in JSON mode - if (!payload.mode) { - const cacheKey = await cache.hashKey(JSON.stringify(payload)); - await cache.saveItem(cacheKey, { - ...payload, - messages: [...payload.messages, result.message], - }); - } + // Save to cache + const cacheKey = await cache.hashKey(JSON.stringify(payload)); + await cache.saveItem(cacheKey, { + ...payload, + // FIXME(jake): I believe this is persisting duplicate messages to the cached json blobs. + messages: [...payload.messages, result.message], + }); return c.json(result.message); } From e571dbfd7503d225844ad2fbb508b9f777989a57 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 09:27:48 -0600 Subject: [PATCH 12/18] cache redo --- ...ca56220e30070df5e702a3a919b15a1df7890.json | 20 ------------------- ...ea150c72a7da2ed5f74edf36b8339730e170.json} | 4 ++-- ...cabc127c171712e18faa968046f776b0a30ab.json | 20 +++++++++++++++++++ 3 files changed, 22 insertions(+), 22 deletions(-) delete mode 100644 jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json rename jumble/integration/cache/llm-api-cache/{225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json => 98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json} (52%) create mode 100644 jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json diff --git a/jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json b/jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json deleted file mode 100644 index 5460beeff..000000000 --- a/jumble/integration/cache/llm-api-cache/2d69893376f0df31fb459fa67a2ca56220e30070df5e702a3a919b15a1df7890.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Parse the input object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Return a result object containing the original data plus the count results.\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n```" - }, - { - "role": "assistant", - "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n const [originalData, setOriginalData] = useDoc('originalData', { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc('counts', {});\n const [totalCount, setTotalCount] = useDoc('totalCount', 0);\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n \n // UI state\n const [inputValue, setInputValue] = React.useState('');\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Process the values array and count occurrences\n const analyzeValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n try {\n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const countMap = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts\n setCounts(countMap);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(countMap).length);\n } catch (error) {\n console.error(\"Error analyzing values:\", error);\n } finally {\n setIsAnalyzing(false);\n }\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim()) {\n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue('');\n }\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalCount(0);\n setUniqueCount(0);\n }, [setSimpleValue2, setCounts, setTotalCount, setUniqueCount]);\n\n // Handle input change\n const handleInputChange = React.useCallback((e) => {\n setInputValue(e.target.value);\n }, []);\n\n // Handle key press (Enter to add)\n const handleKeyPress = React.useCallback((e) => {\n if (e.key === 'Enter') {\n addValue();\n }\n }, [addValue]);\n\n return (\n
\n

{title}

\n \n {/* Input Section */}\n
\n

Add Values

\n
\n \n \n Add\n \n \n Clear All\n \n
\n
\n \n {/* Current Values */}\n
\n

Current Values

\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n \n {value}\n \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n
\n 0)}\n className={`px-4 py-2 rounded text-white ${\n isAnalyzing || !(simpleValue2.values && simpleValue2.values.length > 0)\n ? 'bg-gray-400 cursor-not-allowed'\n : 'bg-green-600 hover:bg-green-700 transition-colors'\n }`}\n >\n {isAnalyzing ? 'Analyzing...' : 'Analyze Values'}\n \n
\n
\n \n {/* Results Section */}\n
\n

Analysis Results

\n \n
\n
\n

Summary

\n

Total values: {totalCount}

\n

Unique values: {uniqueCount}

\n
\n \n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n {value}\n {count}\n
\n ))}\n
\n ) : (\n

No analysis data yet

\n )}\n
\n
\n
\n \n {/* Original Data Section */}\n
\n

Original Data

\n
\n
\n              {JSON.stringify(originalData, null, 2)}\n            
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mount, sourceData) {\n function ValueCounter() {\n // Persistent state from schema\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n const [originalData, setOriginalData] = useDoc('originalData', { simpleValue2: { values: [] } });\n const [counts, setCounts] = useDoc('counts', {});\n const [totalCount, setTotalCount] = useDoc('totalCount', 0);\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n \n // UI state\n const [inputValue, setInputValue] = React.useState('');\n const [isAnalyzing, setIsAnalyzing] = React.useState(false);\n\n // Process the values array and count occurrences\n const analyzeValues = React.useCallback(() => {\n setIsAnalyzing(true);\n \n try {\n // Store original data\n setOriginalData({ simpleValue2: { ...simpleValue2 } });\n \n const values = simpleValue2.values || [];\n const countMap = {};\n \n // Count occurrences of each value\n values.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts\n setCounts(countMap);\n setTotalCount(values.length);\n setUniqueCount(Object.keys(countMap).length);\n } catch (error) {\n console.error(\"Error analyzing values:\", error);\n } finally {\n setIsAnalyzing(false);\n }\n }, [simpleValue2, setCounts, setTotalCount, setUniqueCount, setOriginalData]);\n\n // Add a new value to the array\n const addValue = React.useCallback(() => {\n if (inputValue.trim()) {\n const updatedValues = [...(simpleValue2.values || []), inputValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setInputValue('');\n }\n }, [inputValue, simpleValue2, setSimpleValue2]);\n\n // Clear all values\n const clearValues = React.useCallback(() => {\n setSimpleValue2({ values: [] });\n setCounts({});\n setTotalCount(0);\n setUniqueCount(0);\n }, [setSimpleValue2, setCounts, setTotalCount, setUniqueCount]);\n\n // Handle input change\n const handleInputChange = React.useCallback((e) => {\n setInputValue(e.target.value);\n }, []);\n\n // Handle key press (Enter to add)\n const handleKeyPress = React.useCallback((e) => {\n if (e.key === 'Enter') {\n addValue();\n }\n }, [addValue]);\n\n return (\n
\n

{title}

\n \n {/* Input Section */}\n
\n

Add Values

\n
\n \n \n Add\n \n \n Clear All\n \n
\n
\n \n {/* Current Values */}\n
\n

Current Values

\n
\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n {simpleValue2.values.map((value, index) => (\n \n {value}\n \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n
\n 0)}\n className={`px-4 py-2 rounded text-white ${\n isAnalyzing || !(simpleValue2.values && simpleValue2.values.length > 0)\n ? 'bg-gray-400 cursor-not-allowed'\n : 'bg-green-600 hover:bg-green-700 transition-colors'\n }`}\n >\n {isAnalyzing ? 'Analyzing...' : 'Analyze Values'}\n \n
\n
\n \n {/* Results Section */}\n
\n

Analysis Results

\n \n
\n
\n

Summary

\n

Total values: {totalCount}

\n

Unique values: {uniqueCount}

\n
\n \n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n {value}\n {count}\n
\n ))}\n
\n ) : (\n

No analysis data yet

\n )}\n
\n
\n
\n \n {/* Original Data Section */}\n
\n

Original Data

\n
\n
\n              {JSON.stringify(originalData, null, 2)}\n            
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json b/jumble/integration/cache/llm-api-cache/98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json similarity index 52% rename from jumble/integration/cache/llm-api-cache/225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json rename to jumble/integration/cache/llm-api-cache/98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json index 808639cd6..ce2c5e96b 100644 --- a/jumble/integration/cache/llm-api-cache/225c33b771564ea833779e01c40e76e5f20ec05bee5fc8a81bbc49ca3b16bf12.json +++ b/jumble/integration/cache/llm-api-cache/98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the input object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Return a result object containing the original data plus the count results.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting values in an array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will generate a report showing each unique value and its count. The counter will handle empty arrays and maintain the original data structure while adding the count results.\n\n\n\n1. Parse the input object and extract the \"values\" array from simpleValue2.\n2. Count occurrences of each unique string value in the array.\n3. Return a result object containing the original data plus the count results.\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Result of counting values in an array\",\n \"properties\": {\n \"originalData\": {\n \"type\": \"object\",\n \"title\": \"Original Data\",\n \"description\": \"The original data structure that was analyzed\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Count of occurrences for each unique value\",\n \"additionalProperties\": {\n \"type\": \"integer\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values in the array\",\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values in the array\",\n \"default\": 0\n }\n },\n \"required\": [\"originalData\", \"counts\", \"totalCount\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json b/jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json new file mode 100644 index 000000000..c0a44b35b --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array and count values\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Handle adding a new value\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Handle removing a value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter(value => value !== valueToRemove);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Handle clearing all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Values list */}\n
\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Counts display */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
    \n {Object.entries(counts).map(([value, count], index) => (\n
  • \n {value}\n \n {count}\n \n
  • \n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary statistics */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array and count values\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Handle adding a new value\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Handle removing a value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter(value => value !== valueToRemove);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Handle clearing all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Values list */}\n
\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Counts display */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
    \n {Object.entries(counts).map(([value, count], index) => (\n
  • \n {value}\n \n {count}\n \n
  • \n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary statistics */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file From 39425521f25704d01a746c3b7da3a8d13060e083 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 09:50:04 -0600 Subject: [PATCH 13/18] cache streaming responses --- toolshed/routes/ai/llm/generateText.ts | 10 ++++++++++ toolshed/routes/ai/llm/llm.handlers.ts | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/toolshed/routes/ai/llm/generateText.ts b/toolshed/routes/ai/llm/generateText.ts index 3d5d14bf7..f4037fe73 100644 --- a/toolshed/routes/ai/llm/generateText.ts +++ b/toolshed/routes/ai/llm/generateText.ts @@ -23,6 +23,10 @@ export interface GenerateTextParams { abortSignal?: AbortSignal; max_tokens?: number; mode?: "json"; + // Optional callback for when streaming is complete (used for caching) + onStreamComplete?: ( + finalMessage: { role: "user" | "assistant"; content: string }, + ) => void; } export interface GenerateTextResult { @@ -267,6 +271,12 @@ export async function generateText( messages[messages.length - 1].content = result; } + // Call the onStreamComplete callback with the final message, if provided + // This is used to save the completed stream response to the cache + if (params.onStreamComplete) { + params.onStreamComplete(messages[messages.length - 1]); + } + controller.close(); }, }); diff --git a/toolshed/routes/ai/llm/llm.handlers.ts b/toolshed/routes/ai/llm/llm.handlers.ts index 0bc131794..c463d5475 100644 --- a/toolshed/routes/ai/llm/llm.handlers.ts +++ b/toolshed/routes/ai/llm/llm.handlers.ts @@ -120,11 +120,24 @@ export const generateText: AppRouteHandler = async (c) => { ...payload, abortSignal: c.req.raw.signal, max_tokens: payload.max_tokens || modelDefaultMaxTokens, + onStreamComplete: payload.stream + ? (finalMessage) => { + // Save the completed stream response to the cache + cache.saveItem(cacheKey, { + ...payload, + messages: [...payload.messages, finalMessage], + }).catch((e) => { + console.error("Error saving streamed response to cache:", e); + }); + } + : undefined, }); if (!payload.stream) { // Save to cache - const cacheKey = await cache.hashKey(JSON.stringify(payload)); + console.log("messagesssssss", [...payload.messages, result.message]); + console.log("======================="); + console.log("minus one", [...payload.messages]); await cache.saveItem(cacheKey, { ...payload, // FIXME(jake): I believe this is persisting duplicate messages to the cached json blobs. From 9ace6142bcb947d377e16d709deeb55b516734f1 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 09:50:13 -0600 Subject: [PATCH 14/18] cache tweaks --- ...1b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json | 20 +++++++++++++++++++ ...cabc127c171712e18faa968046f776b0a30ab.json | 20 ------------------- ...a7f4dd0f0009012cf01e01c725a837301f03.json} | 4 ++-- ...ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json} | 0 4 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json delete mode 100644 jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json rename jumble/integration/cache/llm-api-cache/{98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json => c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json} (76%) rename jumble/integration/cache/llm-api-cache/{9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json => cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json} (100%) diff --git a/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json b/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json new file mode 100644 index 000000000..7ebed1a2f --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mountNode) {\n function ValueCounter() {\n // Get the values array from simpleValue2\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n // Get/set the counts object that maps values to their occurrence counts\n const [counts, setCounts] = useDoc('counts', {});\n // Get/set the total count of all values\n const [total, setTotal] = useDoc('total', 0);\n // Get/set the count of unique values\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n // Get/set the source identifier\n const [source, setSource] = useDoc('source', 'simpleValue2.values');\n \n // State for the new value to add\n const [newValue, setNewValue] = React.useState('');\n \n // Function to count occurrences in the values array\n const countValues = React.useCallback(() => {\n const { values } = simpleValue2;\n if (!values || !Array.isArray(values)) return;\n \n const newCounts = {};\n let newTotal = 0;\n \n // Count occurrences of each value\n values.forEach(value => {\n if (value in newCounts) {\n newCounts[value]++;\n } else {\n newCounts[value] = 1;\n }\n newTotal++;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(newCounts);\n setTotal(newTotal);\n setUniqueCount(Object.keys(newCounts).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Count values when the component mounts or when values change\n React.useEffect(() => {\n countValues();\n }, [simpleValue2, countValues]);\n \n // Function to add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === '') return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue('');\n };\n \n // Function to remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Function to clear all values\n const handleClearValues = () => {\n setSimpleValue2({ ...simpleValue2, values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input form to add new values */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n
\n \n Recount Values\n \n \n Clear All Values\n \n
\n
\n \n {/* Display the values array */}\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n 🗑️\n \n
  • \n ))}\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Display the counts */}\n
\n

Value Counts

\n
\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n \n {Object.keys(counts).length > 0 ? (\n
\n

Breakdown

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {total > 0 ? `${((count / total) * 100).toFixed(1)}%` : '0%'}\n
\n
\n
\n ) : (\n

No counts available.

\n )}\n
\n
\n \n
\n Source: {source}\n
\n
\n );\n }\n \n ReactDOM.createRoot(mountNode).render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mountNode) {\n function ValueCounter() {\n // Get the values array from simpleValue2\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n // Get/set the counts object that maps values to their occurrence counts\n const [counts, setCounts] = useDoc('counts', {});\n // Get/set the total count of all values\n const [total, setTotal] = useDoc('total', 0);\n // Get/set the count of unique values\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n // Get/set the source identifier\n const [source, setSource] = useDoc('source', 'simpleValue2.values');\n \n // State for the new value to add\n const [newValue, setNewValue] = React.useState('');\n \n // Function to count occurrences in the values array\n const countValues = React.useCallback(() => {\n const { values } = simpleValue2;\n if (!values || !Array.isArray(values)) return;\n \n const newCounts = {};\n let newTotal = 0;\n \n // Count occurrences of each value\n values.forEach(value => {\n if (value in newCounts) {\n newCounts[value]++;\n } else {\n newCounts[value] = 1;\n }\n newTotal++;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(newCounts);\n setTotal(newTotal);\n setUniqueCount(Object.keys(newCounts).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Count values when the component mounts or when values change\n React.useEffect(() => {\n countValues();\n }, [simpleValue2, countValues]);\n \n // Function to add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === '') return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue('');\n };\n \n // Function to remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Function to clear all values\n const handleClearValues = () => {\n setSimpleValue2({ ...simpleValue2, values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input form to add new values */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n
\n \n Recount Values\n \n \n Clear All Values\n \n
\n
\n \n {/* Display the values array */}\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n 🗑️\n \n
  • \n ))}\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Display the counts */}\n
\n

Value Counts

\n
\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n \n {Object.keys(counts).length > 0 ? (\n
\n

Breakdown

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {total > 0 ? `${((count / total) * 100).toFixed(1)}%` : '0%'}\n
\n
\n
\n ) : (\n

No counts available.

\n )}\n
\n
\n \n
\n Source: {source}\n
\n
\n );\n }\n \n ReactDOM.createRoot(mountNode).render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json b/jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json deleted file mode 100644 index c0a44b35b..000000000 --- a/jumble/integration/cache/llm-api-cache/b1363273cbc40ff08c170d50489cabc127c171712e18faa968046f776b0a30ab.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array and count values\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Handle adding a new value\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Handle removing a value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter(value => value !== valueToRemove);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Handle clearing all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Values list */}\n
\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Counts display */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
    \n {Object.entries(counts).map(([value, count], index) => (\n
  • \n {value}\n \n {count}\n \n
  • \n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary statistics */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array and count values\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Handle adding a new value\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Handle removing a value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter(value => value !== valueToRemove);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Handle clearing all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Values list */}\n
\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Counts display */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
    \n {Object.entries(counts).map(([value, count], index) => (\n
  • \n {value}\n \n {count}\n \n
  • \n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary statistics */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json b/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json similarity index 76% rename from jumble/integration/cache/llm-api-cache/98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json rename to jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json index ce2c5e96b..0c5ad8c24 100644 --- a/jumble/integration/cache/llm-api-cache/98c9ec0b31b42e4309362c5dba33ea150c72a7da2ed5f74edf36b8339730e170.json +++ b/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json b/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json similarity index 100% rename from jumble/integration/cache/llm-api-cache/9c45292fe62aed90a791ba25a758fc10f4b0b5f705ef353de1f26f02e0a60f30.json rename to jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json From b5ae245637ac57e7630d06e1388b70c21028fc7a Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 09:53:45 -0600 Subject: [PATCH 15/18] moar --- ...1b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json | 20 ------------------- ...fa7f4dd0f0009012cf01e01c725a837301f03.json | 4 ++-- ...5ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json | 4 ++-- ...7bb0536bfbe59a9a68150658ce044a856ba66.json | 20 +++++++++++++++++++ jumble/integration/rebuild-llm-cache.sh | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json create mode 100644 jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json diff --git a/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json b/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json deleted file mode 100644 index 7ebed1a2f..000000000 --- a/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": "anthropic:claude-3-7-sonnet-latest", - "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", - "messages": [ - { - "role": "user", - "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n```" - }, - { - "role": "assistant", - "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mountNode) {\n function ValueCounter() {\n // Get the values array from simpleValue2\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n // Get/set the counts object that maps values to their occurrence counts\n const [counts, setCounts] = useDoc('counts', {});\n // Get/set the total count of all values\n const [total, setTotal] = useDoc('total', 0);\n // Get/set the count of unique values\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n // Get/set the source identifier\n const [source, setSource] = useDoc('source', 'simpleValue2.values');\n \n // State for the new value to add\n const [newValue, setNewValue] = React.useState('');\n \n // Function to count occurrences in the values array\n const countValues = React.useCallback(() => {\n const { values } = simpleValue2;\n if (!values || !Array.isArray(values)) return;\n \n const newCounts = {};\n let newTotal = 0;\n \n // Count occurrences of each value\n values.forEach(value => {\n if (value in newCounts) {\n newCounts[value]++;\n } else {\n newCounts[value] = 1;\n }\n newTotal++;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(newCounts);\n setTotal(newTotal);\n setUniqueCount(Object.keys(newCounts).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Count values when the component mounts or when values change\n React.useEffect(() => {\n countValues();\n }, [simpleValue2, countValues]);\n \n // Function to add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === '') return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue('');\n };\n \n // Function to remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Function to clear all values\n const handleClearValues = () => {\n setSimpleValue2({ ...simpleValue2, values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input form to add new values */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n
\n \n Recount Values\n \n \n Clear All Values\n \n
\n
\n \n {/* Display the values array */}\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n 🗑️\n \n
  • \n ))}\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Display the counts */}\n
\n

Value Counts

\n
\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n \n {Object.keys(counts).length > 0 ? (\n
\n

Breakdown

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {total > 0 ? `${((count / total) * 100).toFixed(1)}%` : '0%'}\n
\n
\n
\n ) : (\n

No counts available.

\n )}\n
\n
\n \n
\n Source: {source}\n
\n
\n );\n }\n \n ReactDOM.createRoot(mountNode).render();\n}\n```" - }, - { - "role": "assistant", - "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mountNode) {\n function ValueCounter() {\n // Get the values array from simpleValue2\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n // Get/set the counts object that maps values to their occurrence counts\n const [counts, setCounts] = useDoc('counts', {});\n // Get/set the total count of all values\n const [total, setTotal] = useDoc('total', 0);\n // Get/set the count of unique values\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n // Get/set the source identifier\n const [source, setSource] = useDoc('source', 'simpleValue2.values');\n \n // State for the new value to add\n const [newValue, setNewValue] = React.useState('');\n \n // Function to count occurrences in the values array\n const countValues = React.useCallback(() => {\n const { values } = simpleValue2;\n if (!values || !Array.isArray(values)) return;\n \n const newCounts = {};\n let newTotal = 0;\n \n // Count occurrences of each value\n values.forEach(value => {\n if (value in newCounts) {\n newCounts[value]++;\n } else {\n newCounts[value] = 1;\n }\n newTotal++;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(newCounts);\n setTotal(newTotal);\n setUniqueCount(Object.keys(newCounts).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Count values when the component mounts or when values change\n React.useEffect(() => {\n countValues();\n }, [simpleValue2, countValues]);\n \n // Function to add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === '') return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue('');\n };\n \n // Function to remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Function to clear all values\n const handleClearValues = () => {\n setSimpleValue2({ ...simpleValue2, values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input form to add new values */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n
\n \n Recount Values\n \n \n Clear All Values\n \n
\n
\n \n {/* Display the values array */}\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n 🗑️\n \n
  • \n ))}\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Display the counts */}\n
\n

Value Counts

\n
\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n \n {Object.keys(counts).length > 0 ? (\n
\n

Breakdown

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {total > 0 ? `${((count / total) * 100).toFixed(1)}%` : '0%'}\n
\n
\n
\n ) : (\n

No counts available.

\n )}\n
\n
\n \n
\n Source: {source}\n
\n
\n );\n }\n \n ReactDOM.createRoot(mountNode).render();\n}\n```" - } - ], - "stop": "\n```", - "stream": false -} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json b/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json index 0c5ad8c24..ce2c5e96b 100644 --- a/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json +++ b/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json b/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json index 8b215aa49..14a79df64 100644 --- a/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json +++ b/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to input values and track how many times each unique value appears. It maintains a running tally of each value entered and displays the current count for each. The counter should support text values and provide a simple way to add new entries or reset counts.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add values and increment their counts\n3. Build a simple interface to display the current counts and allow input\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalEntries\": {\n \"type\": \"integer\",\n \"title\": \"Total Entries\",\n \"description\": \"Total number of values entered\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastAdded\": {\n \"type\": \"string\",\n \"title\": \"Last Added\",\n \"description\": \"The most recently added value\",\n \"default\": \"\"\n },\n \"created\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Created Date\",\n \"description\": \"When the counter was created\"\n }\n },\n \"required\": [\"counts\", \"totalEntries\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 3,\n \"banana\": 2,\n \"orange\": 1\n },\n \"totalEntries\": 6,\n \"lastAdded\": \"apple\",\n \"created\": \"2023-05-15T14:30:00Z\"\n}\n" + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json b/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json new file mode 100644 index 000000000..c32a2785b --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array to count occurrences\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Remove a specific value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (value, index) => {\n // Only remove the first occurrence of the value\n if (value === valueToRemove) {\n const firstIndex = simpleValue2.values.indexOf(valueToRemove);\n return index !== firstIndex;\n }\n return true;\n }\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Clear all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Current values section */}\n
\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Count results section */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n
\n
Value
\n
Count
\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n
{value}
\n
{count}
\n
\n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary section */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array to count occurrences\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Remove a specific value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (value, index) => {\n // Only remove the first occurrence of the value\n if (value === valueToRemove) {\n const firstIndex = simpleValue2.values.indexOf(valueToRemove);\n return index !== firstIndex;\n }\n return true;\n }\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Clear all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Current values section */}\n
\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Count results section */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n
\n
Value
\n
Count
\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n
{value}
\n
{count}
\n
\n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary section */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file diff --git a/jumble/integration/rebuild-llm-cache.sh b/jumble/integration/rebuild-llm-cache.sh index 034ca45ec..345a7d444 100755 --- a/jumble/integration/rebuild-llm-cache.sh +++ b/jumble/integration/rebuild-llm-cache.sh @@ -32,7 +32,7 @@ TEMP_CACHE_DIR=$(mktemp -d) # 1. Delete existing cache echo "Deleting existing LLM cache..." -rm -rf jumble/integration/cache/llm-api-cache +# rm -rf jumble/integration/cache/llm-api-cache mkdir -p jumble/integration/cache/llm-api-cache # 2. Start toolshed on port 8000 From 523e0bcb234decd623ebf15945cc42a499de8a29 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 10:00:39 -0600 Subject: [PATCH 16/18] progress? --- ...1b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json | 20 +++++++++++++++++++ ...fa7f4dd0f0009012cf01e01c725a837301f03.json | 4 ++-- ...5ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json | 4 ++-- ...7bb0536bfbe59a9a68150658ce044a856ba66.json | 4 ++-- jumble/integration/rebuild-llm-cache.sh | 7 +------ 5 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json diff --git a/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json b/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json new file mode 100644 index 000000000..d22b0d3c4 --- /dev/null +++ b/jumble/integration/cache/llm-api-cache/61063134e61d3f147733a0cf9711b6fa9cf9f2d5acf81bfeccf71285c0ed93f9.json @@ -0,0 +1,20 @@ +{ + "model": "anthropic:claude-3-7-sonnet-latest", + "system": "# React Component Builder\n\nCreate an interactive React component that fulfills the user's request. Focus on delivering a clean, useful implementation with appropriate features.\n\n## You Are Part of a Two-Phase Process\n\n1. First phase (already completed):\n - Analyzed the user's request\n - Created a detailed specification\n - Generated a structured data schema\n\n2. Your job (second phase):\n - Create a reactive UI component based on the provided specification and schema\n - Implement the UI exactly according to the specification\n - Strictly adhere to the data schema provided\n\n## Required Elements\n- Define a title with `const title = 'Your App Name';`\n- Implement both `onLoad` and `onReady` functions\n- Use Tailwind CSS for styling with tasteful defaults\n- Do not write inline, use emoji for icons\n- Carefully avoid infinite loops and recursion that may cause performance issues\n\n## Code Structure\n1. React and ReactDOM are pre-imported - don't import them again\n2. All React hooks must be namespaced (e.g., `React.useState`, `React.useEffect`)\n3. Follow React hooks rules - never nest or conditionally call hooks\n4. For form handling, use `onClick` handlers instead of `onSubmit`\n\n## Available APIs\n- **useDoc(key, defaultValue)** - Persistent data storage with reactive updates\n- **llm(promptPayload)** - Send requests to the language model\n- **readWebpage(url)** - Fetch and parse external web content\n- **generateImage(prompt)** - Create AI-generated images\n\n## Important Note About useDoc\n- **useDoc is a React Hook** and must follow all React hook rules\n- It should only be used for persistent state and must draw from the provided schema\n - For any ephemeral state, use `React.useState`\n- Only call useDoc at the top level of your function components or custom hooks\n- Do not call useDoc inside loops, conditions, or nested functions\n- useDoc cannot be used outside of `onReady` components - it must be called during rendering\n\n## Library Usage\n- Request additional libraries in `onLoad` by returning an array of module names\n- Available libraries:\n - imports : [object Object]\n- Only use the explicitly provided libraries\n\n## Security Restrictions\n- Do not use browser dialog functions (`prompt()`, `alert()`, `confirm()`)\n- Avoid any methods that could compromise security or user experience\n\n\n\n{\n \"type\": \"object\",\n \"properties\": {\n \"simpleValue2\": {\n \"type\": \"object\",\n \"properties\": {\n \"values\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"title\": \"Value Counter\",\n \"description\": \"A utility to count occurrences of values in an array.\"\n}\n\n\n\n# SDK Usage Guide\n\n## 1. `useDoc` Hook\n\nThe `useDoc` hook binds to a reactive cell given key and returns a tuple `[doc, setDoc]`:\n\nAny keys from the view-model-schema are valid for useDoc, any other keys will fail. Provide a default as the second argument, **do not set an initial value explicitly**.\n\nFor this schema:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"counter\": {\n \"type\": \"number\",\n },\n \"title\": {\n \"type\": \"string\",\n \"default\": \"My Counter App\"\n }\n }\n}\n```\n\n```jsx\nfunction CounterComponent() {\n // Correct: useDoc called at top level of component\n const [counter, setCounter] = useDoc(\"counter\", -1); // default\n\n // Incorrect: would cause errors\n // if(something) {\n // const [data, setData] = useDoc(\"data\", {}); // Never do this!\n // }\n\n const onIncrement = useCallback(() => {\n // writing to the cell automatically triggers a re-render\n setCounter(counter + 1);\n }, [counter]);\n\n return (\n \n );\n}\n```\n\n## 2. llm Function\n\n```jsx\nasync function fetchLLMResponse() {\n // place user-level requirements in system prompt\n const promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke']\n };\n const result = await llm(promptPayload)\n console.log('LLM responded:', result);\n}\n```\n\nIf you need JSON to be returned from the LLM, you can enable the `mode: 'json'` in the `promptPayload`.\n\n```jsx\nconst promptPayload = {\n system: 'Translate all the messages to emojis, reply in JSON.',\n messages: ['Hi', 'How can I help you today?', 'tell me a joke'],\n mode: 'json'\n};\nconst result = await llm(promptPayload);\nconsole.log('JSON response from llm:', result);\n```\n\n## 3. readWebpage Function\n\n```jsx\nasync function fetchFromUrl() {\n const url = 'https://twopm.studio';\n const result = await readWebpage(url);\n console.log('Markdown:', result.content);\n}\n```\n\n## 4. generateImage Function\n\n```jsx\nfunction ImageComponent() {\n return \"Generated;\n}\n\n```\n## 5. Using the Interface Functions\n\n```javascript\n// Import from modern ESM libraries:\n// - react\n// - react-dom\n// - react-dom/client\n// - d3\n// - moment\n// - marked\n// - @react-spring/web\n// - @use-gesture/react\n// - uuid\n// - tone\nfunction onLoad() {\n return ['@react-spring/web']; // Request the modules you need\n}\n\nconst title = 'My ESM App';\nfunction ImageComponent({ url }) {\n return \"Generated;\n}\n\nfunction MyComponent({ label, description }) {\n return (\n
\n

{label}

\n

{description}

\n \n
\n );\n}\n\nfunction TodoItem({ todo, onToggle, onDelete }) {\n return (\n
\n \n \n {todo.text}\n \n \n Delete\n \n
\n );\n}\n\nfunction TodoList({ todo, setTodos}) {\n const [newTodo, setNewTodo] = React.useState('');\n\n const addTodo = () => {\n if (newTodo.trim() === '') return;\n\n const newTodoItem = {\n id: Date.now(),\n text: newTodo,\n completed: false\n };\n\n setTodos([...todos, newTodoItem]);\n setNewTodo('');\n };\n\n const toggleTodo = (id) => {\n setTodos(todos.map(todo =>\n todo.id === id ? { ...todo, completed: !todo.completed } : todo\n ));\n };\n\n const deleteTodo = (id) => {\n setTodos(todos.filter(todo => todo.id !== id));\n };\n\n return (\n
\n

Todo List

\n\n
\n setNewTodo(e.target.value)}\n placeholder=\"Add a new todo\"\n className=\"flex-grow p-2 border rounded-l\"\n />\n \n Add\n \n
\n\n
\n {todos.length > 0 ? (\n todos.map(todo => (\n toggleTodo(todo.id)}\n onDelete={() => deleteTodo(todo.id)}\n />\n ))\n ) : (\n

No todos yet!

\n )}\n
\n
\n );\n}\n\n// Main application code with modules passed as third parameter\nfunction onReady(mount, sourceData, libs) {\n const { useState, useEffect } = React; // React is available globally\n const { useSpring, animated } = libs['@react-spring/web']; // Access imported module\n\n function MyApp() {\n const [count, setCount] = useDoc('count', 0);\n const [todos, setTodos] = useDoc('todos', [\n { id: 1, text: 'Learn React', completed: false },\n { id: 2, text: 'Build a Todo App', completed: false }\n ]);\n const props = useSpring({\n from: { opacity: 0 },\n to: { opacity: 1 }\n });\n\n return (\n
\n \n setCount(count + 1)}\n >\n Clicks: {count}\n \n \n \n
\n );\n }\n\n // Use the client API for React 18\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```\n\n", + "messages": [ + { + "role": "user", + "content": "The user asked you to create the source code with the following specification:\n```\ncount of values\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mountNode) {\n function ValueCounter() {\n // Get the values array from simpleValue2\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n // Get the counts object that maps values to their occurrence counts\n const [counts, setCounts] = useDoc('counts', {});\n // Get the total count of all values\n const [total, setTotal] = useDoc('total', 0);\n // Get the count of unique values\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n // Get the source identifier\n const [source, setSource] = useDoc('source', 'simpleValue2.values');\n \n // Input state for adding new values\n const [newValue, setNewValue] = React.useState('');\n \n // Function to count occurrences in the values array\n const countValues = React.useCallback(() => {\n const { values } = simpleValue2;\n if (!Array.isArray(values)) return;\n \n const newCounts = {};\n let newTotal = 0;\n \n // Count occurrences of each value\n values.forEach(value => {\n if (typeof value === 'string') {\n newCounts[value] = (newCounts[value] || 0) + 1;\n newTotal++;\n }\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(newCounts);\n setTotal(newTotal);\n setUniqueCount(Object.keys(newCounts).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Count values when the component mounts or when values change\n React.useEffect(() => {\n countValues();\n }, [simpleValue2, countValues]);\n \n // Function to add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === '') return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue('');\n };\n \n // Function to remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Function to clear all values\n const handleClearValues = () => {\n setSimpleValue2({ ...simpleValue2, values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input form to add new values */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n
\n \n {/* Display current values */}\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n 🗑️\n \n
  • \n ))}\n
\n
\n \n Clear All\n \n
\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Display counts */}\n
\n

Value Counts

\n
\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n \n {Object.keys(counts).length > 0 ? (\n
\n

Breakdown

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {total > 0 ? `${((count / total) * 100).toFixed(1)}%` : '0%'}\n
\n
\n
\n ) : (\n

No data to display.

\n )}\n
\n
\n \n
\n Source: {source}\n
\n
\n );\n }\n \n ReactDOM.createRoot(mountNode).render();\n}\n```" + }, + { + "role": "assistant", + "content": "\nconst title = 'Value Counter';\n\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nfunction onReady(mountNode) {\n function ValueCounter() {\n // Get the values array from simpleValue2\n const [simpleValue2, setSimpleValue2] = useDoc('simpleValue2', { values: [] });\n // Get the counts object that maps values to their occurrence counts\n const [counts, setCounts] = useDoc('counts', {});\n // Get the total count of all values\n const [total, setTotal] = useDoc('total', 0);\n // Get the count of unique values\n const [uniqueCount, setUniqueCount] = useDoc('uniqueCount', 0);\n // Get the source identifier\n const [source, setSource] = useDoc('source', 'simpleValue2.values');\n \n // Input state for adding new values\n const [newValue, setNewValue] = React.useState('');\n \n // Function to count occurrences in the values array\n const countValues = React.useCallback(() => {\n const { values } = simpleValue2;\n if (!Array.isArray(values)) return;\n \n const newCounts = {};\n let newTotal = 0;\n \n // Count occurrences of each value\n values.forEach(value => {\n if (typeof value === 'string') {\n newCounts[value] = (newCounts[value] || 0) + 1;\n newTotal++;\n }\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(newCounts);\n setTotal(newTotal);\n setUniqueCount(Object.keys(newCounts).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Count values when the component mounts or when values change\n React.useEffect(() => {\n countValues();\n }, [simpleValue2, countValues]);\n \n // Function to add a new value to the array\n const handleAddValue = () => {\n if (newValue.trim() === '') return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue('');\n };\n \n // Function to remove a value from the array\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (_, index) => index !== valueToRemove\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Function to clear all values\n const handleClearValues = () => {\n setSimpleValue2({ ...simpleValue2, values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input form to add new values */}\n
\n
\n setNewValue(e.target.value)}\n placeholder=\"Enter a value\"\n className=\"flex-grow p-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n \n Add Value\n \n
\n
\n \n {/* Display current values */}\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(index)}\n className=\"text-red-500 hover:text-red-700\"\n >\n 🗑️\n \n
  • \n ))}\n
\n
\n \n Clear All\n \n
\n
\n ) : (\n

No values added yet.

\n )}\n
\n \n {/* Display counts */}\n
\n

Value Counts

\n
\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n \n {Object.keys(counts).length > 0 ? (\n
\n

Breakdown

\n
\n \n \n \n \n \n \n \n \n \n {Object.entries(counts).map(([value, count]) => (\n \n \n \n \n \n ))}\n \n
ValueCountPercentage
{value}{count}\n {total > 0 ? `${((count / total) * 100).toFixed(1)}%` : '0%'}\n
\n
\n
\n ) : (\n

No data to display.

\n )}\n
\n
\n \n
\n Source: {source}\n
\n
\n );\n }\n \n ReactDOM.createRoot(mountNode).render();\n}\n```" + } + ], + "stop": "\n```", + "stream": false +} \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json b/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json index ce2c5e96b..0c5ad8c24 100644 --- a/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json +++ b/jumble/integration/cache/llm-api-cache/c02a73eaaab29ba5c9f480e301afa7f4dd0f0009012cf01e01c725a837301f03.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of each unique value to its count\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" + "content": "\nValue Counter\n\n\n\nA utility to count occurrences of values in an array.\n\n\n\nThe Value Counter will analyze the \"values\" array within the simpleValue2 object and count the occurrences of each unique string. It will return a summary object containing each unique value as a key and its count as the corresponding value. This simple counter will maintain the existing schema structure while providing useful aggregation functionality.\n\n\n\n1. Extract the \"values\" array from the simpleValue2 object in the existing schema\n2. Process the array to count occurrences of each unique string value\n3. Return a result object with the counts mapped by value\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"Value Count Result\",\n \"description\": \"Count of occurrences for each unique value in the array\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Value Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n },\n \"total\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Total number of values counted\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"uniqueCount\": {\n \"type\": \"integer\",\n \"title\": \"Unique Count\",\n \"description\": \"Number of unique values found\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"source\": {\n \"type\": \"string\",\n \"title\": \"Source\",\n \"description\": \"Identifier of the source array that was counted\",\n \"default\": \"simpleValue2.values\"\n }\n },\n \"required\": [\"counts\", \"total\", \"uniqueCount\"]\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json b/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json index 14a79df64..dfd73f789 100644 --- a/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json +++ b/jumble/integration/cache/llm-api-cache/cfbaaaf5efb72c9d307842196b35ed8a9106ec2f5e150b3f95b4fcab9d1f112f.json @@ -9,11 +9,11 @@ }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values. It maintains a running count for each unique value entered. Users can add new values, increment existing ones, and view the current counts for all tracked values.\n\n\n\n1. Create a data structure to store values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to interact with the counter\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value counts\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 5,\n \"banana\": 3,\n \"orange\": 2,\n \"grape\": 1\n },\n \"totalCount\": 11,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" }, { "role": "assistant", - "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values or items. It maintains a running tally of each unique value entered and displays the current count for each. The counter should support adding new values, incrementing existing ones, and viewing the complete count distribution.\n\n\n\n1. Create a data structure to store unique values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to display and manage the value counts\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value occurrences\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"red\": 5,\n \"blue\": 3,\n \"green\": 7,\n \"yellow\": 2\n },\n \"totalCount\": 17,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" + "content": "\nValue Counter\n\n\n\nA tool to count and track the frequency of values.\n\n\n\nThe Value Counter allows users to track occurrences of different values. It maintains a running count for each unique value entered. Users can add new values, increment existing ones, and view the current counts for all tracked values.\n\n\n\n1. Create a data structure to store values and their counts\n2. Implement functions to add/increment values and retrieve counts\n3. Build a simple interface to interact with the counter\n\n\n\n{\n \"type\": \"object\",\n \"title\": \"ValueCounter\",\n \"description\": \"Tracks the frequency of different values\",\n \"properties\": {\n \"counts\": {\n \"type\": \"object\",\n \"title\": \"Counts\",\n \"description\": \"Map of values to their occurrence counts\",\n \"additionalProperties\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"default\": {}\n },\n \"totalCount\": {\n \"type\": \"integer\",\n \"title\": \"Total Count\",\n \"description\": \"Sum of all value counts\",\n \"minimum\": 0,\n \"default\": 0\n },\n \"lastUpdated\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"title\": \"Last Updated\",\n \"description\": \"When the counter was last modified\"\n }\n },\n \"required\": [\"counts\", \"totalCount\"]\n}\n\n\n\n{\n \"counts\": {\n \"apple\": 5,\n \"banana\": 3,\n \"orange\": 2,\n \"grape\": 1\n },\n \"totalCount\": 11,\n \"lastUpdated\": \"2023-05-15T14:30:45Z\"\n}\n" } ] } \ No newline at end of file diff --git a/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json b/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json index c32a2785b..02d28eff6 100644 --- a/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json +++ b/jumble/integration/cache/llm-api-cache/d62fdd4fd8616f9e94add2234ce7bb0536bfbe59a9a68150658ce044a856ba66.json @@ -8,11 +8,11 @@ }, { "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array to count occurrences\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Remove a specific value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (value, index) => {\n // Only remove the first occurrence of the value\n if (value === valueToRemove) {\n const firstIndex = simpleValue2.values.indexOf(valueToRemove);\n return index !== firstIndex;\n }\n return true;\n }\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Clear all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Current values section */}\n
\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Count results section */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n
\n
Value
\n
Count
\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n
{value}
\n
{count}
\n
\n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary section */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array to count occurrences\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Handle adding a new value\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Handle removing a value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter(value => value !== valueToRemove);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Handle clearing all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Values list */}\n
\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Counts display */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
    \n {Object.entries(counts).map(([value, count], index) => (\n
  • \n {value}\n \n {count}\n \n
  • \n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary statistics */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" }, { "role": "assistant", - "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array to count occurrences\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Add a new value to the array\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Remove a specific value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = (simpleValue2.values || []).filter(\n (value, index) => {\n // Only remove the first occurrence of the value\n if (value === valueToRemove) {\n const firstIndex = simpleValue2.values.indexOf(valueToRemove);\n return index !== firstIndex;\n }\n return true;\n }\n );\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Clear all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Current values section */}\n
\n
\n

Current Values

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Count results section */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
\n
\n
Value
\n
Count
\n
\n {Object.entries(counts).map(([value, count], index) => (\n
\n
{value}
\n
{count}
\n
\n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary section */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" + "content": "\nfunction onLoad() {\n return []; // No additional libraries needed\n}\n\nconst title = 'Value Counter';\n\nfunction onReady(mount) {\n function ValueCounter() {\n // Get the source array from simpleValue2.values\n const [simpleValue2, setSimpleValue2] = useDoc(\"simpleValue2\", { values: [] });\n const [counts, setCounts] = useDoc(\"counts\", {});\n const [total, setTotal] = useDoc(\"total\", 0);\n const [uniqueCount, setUniqueCount] = useDoc(\"uniqueCount\", 0);\n const [source, setSource] = useDoc(\"source\", \"simpleValue2.values\");\n \n // Local state for input field\n const [newValue, setNewValue] = React.useState(\"\");\n \n // Process the array to count occurrences\n React.useEffect(() => {\n if (!simpleValue2 || !simpleValue2.values) return;\n \n const valueArray = simpleValue2.values;\n const countMap = {};\n \n // Count occurrences of each value\n valueArray.forEach(value => {\n countMap[value] = (countMap[value] || 0) + 1;\n });\n \n // Update the counts, total, and uniqueCount\n setCounts(countMap);\n setTotal(valueArray.length);\n setUniqueCount(Object.keys(countMap).length);\n }, [simpleValue2, setCounts, setTotal, setUniqueCount]);\n \n // Handle adding a new value\n const handleAddValue = () => {\n if (!newValue.trim()) return;\n \n const updatedValues = [...(simpleValue2.values || []), newValue.trim()];\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n setNewValue(\"\");\n };\n \n // Handle removing a value\n const handleRemoveValue = (valueToRemove) => {\n const updatedValues = simpleValue2.values.filter(value => value !== valueToRemove);\n setSimpleValue2({ ...simpleValue2, values: updatedValues });\n };\n \n // Handle clearing all values\n const handleClearAll = () => {\n setSimpleValue2({ values: [] });\n };\n \n return (\n
\n

{title}

\n \n {/* Input section */}\n
\n

Add Values

\n
\n setNewValue(e.target.value)}\n className=\"flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder=\"Enter a value\"\n />\n \n Add\n \n
\n \n
\n \n Clear All\n \n
\n
\n \n {/* Values list */}\n
\n
\n

Values List

\n {simpleValue2.values && simpleValue2.values.length > 0 ? (\n
    \n {simpleValue2.values.map((value, index) => (\n
  • \n {value}\n handleRemoveValue(value)}\n className=\"text-red-500 hover:text-red-700\"\n >\n ❌\n \n
  • \n ))}\n
\n ) : (\n

No values added yet

\n )}\n
\n \n {/* Counts display */}\n
\n

Value Counts

\n {Object.keys(counts).length > 0 ? (\n
    \n {Object.entries(counts).map(([value, count], index) => (\n
  • \n {value}\n \n {count}\n \n
  • \n ))}\n
\n ) : (\n

No counts available

\n )}\n
\n
\n \n {/* Summary statistics */}\n
\n

Summary

\n
\n
\n

Total Values

\n

{total}

\n
\n
\n

Unique Values

\n

{uniqueCount}

\n
\n
\n

Source

\n

{source}

\n
\n
\n
\n
\n );\n }\n\n // Render the component\n const root = ReactDOM.createRoot(mount);\n root.render();\n}\n```" } ], "stop": "\n```", diff --git a/jumble/integration/rebuild-llm-cache.sh b/jumble/integration/rebuild-llm-cache.sh index 345a7d444..57529f3f7 100755 --- a/jumble/integration/rebuild-llm-cache.sh +++ b/jumble/integration/rebuild-llm-cache.sh @@ -26,15 +26,10 @@ elif [[ "$(basename "$(pwd)")" == "jumble" ]]; then cd .. fi -#0. Create temp cache directory +#1. Create temp cache directory echo "Creating temp cache directory..." TEMP_CACHE_DIR=$(mktemp -d) -# 1. Delete existing cache -echo "Deleting existing LLM cache..." -# rm -rf jumble/integration/cache/llm-api-cache -mkdir -p jumble/integration/cache/llm-api-cache - # 2. Start toolshed on port 8000 echo "Starting toolshed on port 8000..." cd toolshed From 45d2c25b1fcfa4cb678532e1f3ace0fb4498cc93 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 10:09:02 -0600 Subject: [PATCH 17/18] Fixing duplicate message in cache artifacts, and cleaning up caching logic --- jumble/integration/basic-flow.test.ts | 2 +- toolshed/routes/ai/llm/generateText.ts | 26 +++++++++++------ toolshed/routes/ai/llm/llm.handlers.ts | 40 ++++++++++++-------------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/jumble/integration/basic-flow.test.ts b/jumble/integration/basic-flow.test.ts index b966d0875..66f2ca8e2 100644 --- a/jumble/integration/basic-flow.test.ts +++ b/jumble/integration/basic-flow.test.ts @@ -22,7 +22,7 @@ import { const TOOLSHED_API_URL = Deno.env.get("TOOLSHED_API_URL") ?? "http://localhost:8000/"; const FRONTEND_URL = Deno.env.get("FRONTEND_URL") ?? "http://localhost:5173/"; -const HEADLESS = false; +const HEADLESS = true; const ASTRAL_TIMEOUT = 60_000; console.log(`TOOLSHED_API_URL=${TOOLSHED_API_URL}`); diff --git a/toolshed/routes/ai/llm/generateText.ts b/toolshed/routes/ai/llm/generateText.ts index f4037fe73..e1165b59b 100644 --- a/toolshed/routes/ai/llm/generateText.ts +++ b/toolshed/routes/ai/llm/generateText.ts @@ -23,14 +23,17 @@ export interface GenerateTextParams { abortSignal?: AbortSignal; max_tokens?: number; mode?: "json"; - // Optional callback for when streaming is complete (used for caching) - onStreamComplete?: ( - finalMessage: { role: "user" | "assistant"; content: string }, - ) => void; + // Updated callback to receive complete data for caching + onStreamComplete?: (result: { + message: { role: "user" | "assistant"; content: string }; + messages: { role: "user" | "assistant"; content: string }[]; + originalRequest: GenerateTextParams; + }) => void; } export interface GenerateTextResult { message: { role: "user" | "assistant"; content: string }; + messages: { role: "user" | "assistant"; content: string }[]; stream?: ReadableStream; } @@ -225,7 +228,10 @@ export async function generateText( messages[messages.length - 1].content = result; } - return { message: messages[messages.length - 1] }; + return { + message: messages[messages.length - 1], + messages: [...messages], + }; } // Create streaming response @@ -271,10 +277,13 @@ export async function generateText( messages[messages.length - 1].content = result; } - // Call the onStreamComplete callback with the final message, if provided - // This is used to save the completed stream response to the cache + // Call the onStreamComplete callback with all the data needed for caching if (params.onStreamComplete) { - params.onStreamComplete(messages[messages.length - 1]); + params.onStreamComplete({ + message: messages[messages.length - 1], + messages: [...messages], + originalRequest: params, + }); } controller.close(); @@ -283,6 +292,7 @@ export async function generateText( return { message: messages[messages.length - 1], + messages: [...messages], stream, }; } diff --git a/toolshed/routes/ai/llm/llm.handlers.ts b/toolshed/routes/ai/llm/llm.handlers.ts index c463d5475..76edeb251 100644 --- a/toolshed/routes/ai/llm/llm.handlers.ts +++ b/toolshed/routes/ai/llm/llm.handlers.ts @@ -92,10 +92,7 @@ export const getModels: AppRouteHandler = (c) => { export const generateText: AppRouteHandler = async (c) => { const payload = await c.req.json(); - console.log("LLM HASH", await cache.hashKey(JSON.stringify(payload))); - console.log("LLM PAYLOAD", JSON.stringify(payload, null, 2)); - - // Check cache for existing response + // First, check whether the request is cached, if so return the cached result const cacheKey = await cache.hashKey(JSON.stringify(payload)); const cachedResult = await cache.loadItem(cacheKey); if (cachedResult) { @@ -103,6 +100,19 @@ export const generateText: AppRouteHandler = async (c) => { return c.json(lastMessage); } + const persistCache = async ( + messages: { role: string; content: string }[], + ) => { + try { + await cache.saveItem(cacheKey, { + ...payload, + messages, + }); + } catch (e) { + console.error("Error saving response to cache:", e); + } + }; + const validationError = validateModelAndJsonMode( c, payload.model, @@ -120,29 +130,17 @@ export const generateText: AppRouteHandler = async (c) => { ...payload, abortSignal: c.req.raw.signal, max_tokens: payload.max_tokens || modelDefaultMaxTokens, + // If response is streaming, save to cache after the stream is complete onStreamComplete: payload.stream - ? (finalMessage) => { - // Save the completed stream response to the cache - cache.saveItem(cacheKey, { - ...payload, - messages: [...payload.messages, finalMessage], - }).catch((e) => { - console.error("Error saving streamed response to cache:", e); - }); + ? async (result) => { + await persistCache(result.messages); } : undefined, }); + // If response is not streaming, save to cache and return the message if (!payload.stream) { - // Save to cache - console.log("messagesssssss", [...payload.messages, result.message]); - console.log("======================="); - console.log("minus one", [...payload.messages]); - await cache.saveItem(cacheKey, { - ...payload, - // FIXME(jake): I believe this is persisting duplicate messages to the cached json blobs. - messages: [...payload.messages, result.message], - }); + await persistCache(result.messages); return c.json(result.message); } From c94dc9f3852c2b4da89e18b9e89087766fa90b64 Mon Sep 17 00:00:00 2001 From: jakedahn Date: Thu, 3 Apr 2025 12:33:23 -0600 Subject: [PATCH 18/18] tweaking tests --- toolshed/routes/ai/llm/generateText.test.ts | 185 +++++++++----------- 1 file changed, 81 insertions(+), 104 deletions(-) diff --git a/toolshed/routes/ai/llm/generateText.test.ts b/toolshed/routes/ai/llm/generateText.test.ts index 3e131d365..96b176c29 100644 --- a/toolshed/routes/ai/llm/generateText.test.ts +++ b/toolshed/routes/ai/llm/generateText.test.ts @@ -1,16 +1,14 @@ import { assertEquals } from "@std/assert"; +import { describe, it } from "@std/testing/bdd"; import env from "@/env.ts"; - -// Import the functions for testing import { cleanJsonResponse, configureJsonMode } from "./generateText.ts"; if (env.ENV !== "test") { throw new Error("ENV must be 'test'"); } -Deno.test("JSON mode configuration", async (t) => { - // Test for Groq models - await t.step("Configures JSON mode correctly for Groq models", () => { +describe("configureJsonMode", () => { + it("configures JSON mode correctly for Groq models", () => { const streamParams: Record = {}; const messages = [{ role: "user" as const, @@ -31,8 +29,7 @@ Deno.test("JSON mode configuration", async (t) => { ); }); - // Test for OpenAI models - await t.step("Configures JSON mode correctly for OpenAI models", () => { + it("configures JSON mode correctly for OpenAI models", () => { const streamParams: Record = {}; const messages = [{ role: "user" as const, @@ -48,8 +45,7 @@ Deno.test("JSON mode configuration", async (t) => { }); }); - // Test for Anthropic models - await t.step("Configures JSON mode correctly for Anthropic models", () => { + it("configures JSON mode correctly for Anthropic models", () => { const streamParams: Record = {}; const messages = [{ role: "user" as const, @@ -71,40 +67,35 @@ Deno.test("JSON mode configuration", async (t) => { assertEquals(streamParams.prefill?.text, "{\n"); }); - // Test with existing system prompt - await t.step( - "Preserves existing system prompt while adding JSON instructions", - () => { - const streamParams: Record = { - system: "You are an expert assistant.", - }; - const messages = [{ - role: "user" as const, - content: "Generate a JSON response", - }]; - - configureJsonMode( - streamParams, - "anthropic:claude-3-7-sonnet", - messages, - false, - ); - - assertEquals( - streamParams.system.includes( - "You are a JSON generation assistant. You are an expert assistant.", - ), - true, - ); - assertEquals( - streamParams.system.includes("response must be ONLY valid JSON"), - true, - ); - }, - ); - - // Test for other providers - await t.step("Configures JSON mode correctly for other providers", () => { + it("preserves existing system prompt while adding JSON instructions", () => { + const streamParams: Record = { + system: "You are an expert assistant.", + }; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode( + streamParams, + "anthropic:claude-3-7-sonnet", + messages, + false, + ); + + assertEquals( + streamParams.system.includes( + "You are a JSON generation assistant. You are an expert assistant.", + ), + true, + ); + assertEquals( + streamParams.system.includes("response must be ONLY valid JSON"), + true, + ); + }); + + it("configures JSON mode correctly for other providers", () => { const streamParams: Record = {}; const messages = [{ role: "user" as const, @@ -120,82 +111,68 @@ Deno.test("JSON mode configuration", async (t) => { ); }); - // Test for other providers with existing system prompt - await t.step( - "Adds JSON instructions to existing system prompt for other providers", - () => { - const streamParams: Record = { - system: "You are an expert assistant.", - }; - const messages = [{ - role: "user" as const, - content: "Generate a JSON response", - }]; - - configureJsonMode(streamParams, "other:model", messages, false); - - assertEquals( - streamParams.system, - "You are an expert assistant.\nEnsure the response is valid JSON. DO NOT include any other text or formatting.", - ); - }, - ); - - // Test that JSON instructions are always added, even if the prompt already mentions JSON - await t.step( - "Always adds JSON instructions even when system prompt already mentions JSON", - () => { - const streamParams: Record = { - system: "You are an expert assistant who responds in JSON format.", - }; - const messages = [{ - role: "user" as const, - content: "Generate a JSON response", - }]; - - configureJsonMode(streamParams, "other:model", messages, false); - - // Should always add our JSON instructions - assertEquals( - streamParams.system, - "You are an expert assistant who responds in JSON format.\nEnsure the response is valid JSON. DO NOT include any other text or formatting.", - ); - }, - ); + it("adds JSON instructions to existing system prompt for other providers", () => { + const streamParams: Record = { + system: "You are an expert assistant.", + }; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "other:model", messages, false); + + assertEquals( + streamParams.system, + "You are an expert assistant.\nEnsure the response is valid JSON. DO NOT include any other text or formatting.", + ); + }); + + it("always adds JSON instructions even when system prompt already mentions JSON", () => { + const streamParams: Record = { + system: "You are an expert assistant who responds in JSON format.", + }; + const messages = [{ + role: "user" as const, + content: "Generate a JSON response", + }]; + + configureJsonMode(streamParams, "other:model", messages, false); + + // Should always add our JSON instructions + assertEquals( + streamParams.system, + "You are an expert assistant who responds in JSON format.\nEnsure the response is valid JSON. DO NOT include any other text or formatting.", + ); + }); }); -Deno.test("cleanJsonResponse function", async (t) => { - await t.step("Extracts JSON from markdown code blocks", () => { +describe("cleanJsonResponse", () => { + it("extracts JSON from markdown code blocks", () => { const input = '```json\n{"name": "Test", "value": 123}\n```'; const expected = '{"name": "Test", "value": 123}'; assertEquals(cleanJsonResponse(input), expected); }); - await t.step( - "Extracts JSON from code blocks without language specifier", - () => { - const input = '```\n{"name": "Test", "value": 123}\n```'; - const expected = '{"name": "Test", "value": 123}'; - assertEquals(cleanJsonResponse(input), expected); - }, - ); + it("extracts JSON from code blocks without language specifier", () => { + const input = '```\n{"name": "Test", "value": 123}\n```'; + const expected = '{"name": "Test", "value": 123}'; + assertEquals(cleanJsonResponse(input), expected); + }); - await t.step("Handles multiline JSON in code blocks", () => { + it("handles multiline JSON in code blocks", () => { const input = '```json\n{\n "name": "Test",\n "value": 123\n}\n```'; const expected = '{\n "name": "Test",\n "value": 123\n}'; assertEquals(cleanJsonResponse(input), expected); }); - await t.step("Returns original text if no code blocks found", () => { + it("returns original text if no code blocks found", () => { const input = '{"name": "Test", "value": 123}'; assertEquals(cleanJsonResponse(input), input); }); - await t.step( - "Returns original text if code block format is incorrect", - () => { - const input = '```json {"name": "Test", "value": 123}```'; - assertEquals(cleanJsonResponse(input), input); - }, - ); + it("returns original text if code block format is incorrect", () => { + const input = '```json {"name": "Test", "value": 123}```'; + assertEquals(cleanJsonResponse(input), input); + }); });