Get Recommendation History
get_recommendation_historyRetrieve your past recommendation submissions and received model codes, ordered newest first, to review previous explorations and prevent duplicate recommendations.
Instructions
Fetch the caller's past recommendation calls (problems submitted and the model codes that were returned), newest first. Useful for 'what did we explore last time?' and for avoiding re-recommending the same models.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max rows to return (default 20, max 100) | |
| offset | No | Pagination offset (default 0) |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| count | Yes | ||
| limit | Yes | ||
| offset | Yes | ||
| recommendations | Yes |
Implementation Reference
- src/tools/models.ts:1126-1227 (registration)Registration of the 'get_recommendation_history' tool via server.registerTool(). Defines inputSchema (limit, offset) and outputSchema (count, limit, offset, recommendations array).
// Tool: Retrieve past recommendations for the authenticated caller server.registerTool( "get_recommendation_history", { title: "Get Recommendation History", description: "Fetch the caller's past recommendation calls (problems submitted and the model codes that were returned), newest first. Useful for 'what did we explore last time?' and for avoiding re-recommending the same models.", inputSchema: z.object({ limit: z .number() .int() .min(1) .max(100) .optional() .describe("Max rows to return (default 20, max 100)"), offset: z.number().int().min(0).optional().describe("Pagination offset (default 0)"), }), outputSchema: z.object({ count: z.number(), limit: z.number(), offset: z.number(), recommendations: z.array( z.object({ id: z.string(), problem: z.string(), model_codes: z.array(z.string()), top_pattern: z.string().nullable(), created_at: z.string(), }) ), }), }, async ({ limit, offset }) => { if (!API_CONFIG.apiKey) { return { content: [ { type: "text", text: "HUMMBL API key not configured. Set HUMMBL_API_KEY to retrieve recommendation history.", }, ], isError: true, structuredContent: undefined, } as const; } const params = new URLSearchParams(); if (limit !== undefined) params.set("limit", String(limit)); if (offset !== undefined) params.set("offset", String(offset)); const qs = params.toString(); const url = `${API_CONFIG.baseUrl}/v1/recommendations${qs ? `?${qs}` : ""}`; try { const response = await fetch(url, { headers: { Authorization: `Bearer ${API_CONFIG.apiKey}` }, }); if (!response.ok) { const errorText = await response.text(); return { content: [ { type: "text", text: `API request failed: ${response.status} ${response.statusText}\n${errorText}`, }, ], isError: true, structuredContent: undefined, } as const; } const payload = (await response.json()) as { count: number; limit: number; offset: number; recommendations: Array<{ id: string; problem: string; model_codes: string[]; top_pattern: string | null; created_at: string; }>; }; return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }], structuredContent: payload, }; } catch (error) { return { content: [ { type: "text", text: `Failed to fetch recommendation history: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], isError: true, structuredContent: undefined, } as const; } } ); - src/tools/models.ts:1158-1226 (handler)Handler function for the tool. Checks API key, then calls the internal REST API at /v1/recommendations with limit/offset params, passing the API key as Bearer token. Returns the JSON response as tool output.
async ({ limit, offset }) => { if (!API_CONFIG.apiKey) { return { content: [ { type: "text", text: "HUMMBL API key not configured. Set HUMMBL_API_KEY to retrieve recommendation history.", }, ], isError: true, structuredContent: undefined, } as const; } const params = new URLSearchParams(); if (limit !== undefined) params.set("limit", String(limit)); if (offset !== undefined) params.set("offset", String(offset)); const qs = params.toString(); const url = `${API_CONFIG.baseUrl}/v1/recommendations${qs ? `?${qs}` : ""}`; try { const response = await fetch(url, { headers: { Authorization: `Bearer ${API_CONFIG.apiKey}` }, }); if (!response.ok) { const errorText = await response.text(); return { content: [ { type: "text", text: `API request failed: ${response.status} ${response.statusText}\n${errorText}`, }, ], isError: true, structuredContent: undefined, } as const; } const payload = (await response.json()) as { count: number; limit: number; offset: number; recommendations: Array<{ id: string; problem: string; model_codes: string[]; top_pattern: string | null; created_at: string; }>; }; return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }], structuredContent: payload, }; } catch (error) { return { content: [ { type: "text", text: `Failed to fetch recommendation history: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], isError: true, structuredContent: undefined, } as const; } } - src/tools/models.ts:1133-1156 (schema)Input/output schemas for the tool. Input: optional limit (1-100) and offset (0+). Output: count, limit, offset, and array of recommendations with id, problem, model_codes, top_pattern, created_at.
inputSchema: z.object({ limit: z .number() .int() .min(1) .max(100) .optional() .describe("Max rows to return (default 20, max 100)"), offset: z.number().int().min(0).optional().describe("Pagination offset (default 0)"), }), outputSchema: z.object({ count: z.number(), limit: z.number(), offset: z.number(), recommendations: z.array( z.object({ id: z.string(), problem: z.string(), model_codes: z.array(z.string()), top_pattern: z.string().nullable(), created_at: z.string(), }) ), }), - src/storage/d1-client.ts:674-720 (helper)D1 database helper getRecommendationHistory(). Queries the recommendations table for a given apiKeyId, ordered by created_at DESC with LIMIT/OFFSET. Deserializes model_codes from JSON string to string array.
async getRecommendationHistory( apiKeyId: string, limit = 20, offset = 0 ): Promise< Array<{ id: string; problem: string; modelCodes: string[]; topPattern: string | null; createdAt: string; }> > { const rows = await this.query<{ id: string; problem: string; model_codes: string; top_pattern: string | null; created_at: string; }>( `SELECT id, problem, model_codes, top_pattern, created_at FROM recommendations WHERE api_key_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?`, apiKeyId, limit, offset ); return rows.map((r) => { let modelCodes: string[] = []; try { const parsed = JSON.parse(r.model_codes); if (Array.isArray(parsed)) modelCodes = parsed.filter((v) => typeof v === "string"); } catch { // Malformed row — surface an empty list rather than throwing. } return { id: r.id, problem: r.problem, modelCodes, topPattern: r.top_pattern, createdAt: r.created_at, }; }); } - src/api.ts:501-531 (handler)REST API endpoint GET /v1/recommendations that the tool handler calls. Authenticates the user, calls db.getRecommendationHistory(), and returns the paginated recommendation rows as JSON.
// List recent recommendation history for the authenticated caller app.get("/v1/recommendations", authenticate, async (c: AppContext) => { const user = c.get("user"); if (!user) { return c.json({ error: "Unauthenticated" }, 401); } const limitParam = c.req.query("limit"); const offsetParam = c.req.query("offset"); const limit = Math.min(Math.max(parseInt(limitParam ?? "20", 10) || 20, 1), 100); const offset = Math.max(parseInt(offsetParam ?? "0", 10) || 0, 0); const db = createD1Client(c.env.DB); try { const rows = await db.getRecommendationHistory(user.id, limit, offset); return c.json({ count: rows.length, limit, offset, recommendations: rows.map((r) => ({ id: r.id, problem: r.problem, model_codes: r.modelCodes, top_pattern: r.topPattern, created_at: r.createdAt, })), }); } catch { return c.json({ error: "Failed to load recommendation history" }, 500); } });