gencow 0.1.227 → 0.1.228

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/index.js CHANGED
@@ -268,6 +268,21 @@ function createGencowHttpRouteBuilders() {
268
268
  };
269
269
  }
270
270
 
271
+ // ../core/src/search-index-contract.ts
272
+ function buildSearchIndexNames(table, field) {
273
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(table) || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(field)) {
274
+ throw new Error("Search index identity contains an invalid identifier");
275
+ }
276
+ const identity = `${table}:${field}`;
277
+ let hash = 0xcbf29ce484222325n;
278
+ for (const character of identity) {
279
+ hash ^= BigInt(character.codePointAt(0) ?? 0);
280
+ hash = BigInt.asUintN(64, hash * 0x100000001b3n);
281
+ }
282
+ const prefix = `gencow_search_${hash.toString(16).padStart(16, "0")}`;
283
+ return { fts: `${prefix}_fts_idx`, trigram: `${prefix}_trgm_idx` };
284
+ }
285
+
271
286
  // ../core/src/document-types.ts
272
287
  function normalizeCachePart(value) {
273
288
  return value.trim() || "unknown";
@@ -5138,6 +5153,7 @@ export {
5138
5153
  buildRealtimeCtx,
5139
5154
  buildRealtimeQueryScopeHash,
5140
5155
  buildRealtimeQuerySubscriptionKey,
5156
+ buildSearchIndexNames,
5141
5157
  buildWakeAppBootFailedResult,
5142
5158
  buildWakeAppSuccessResult,
5143
5159
  compareUnreadCursors,
@@ -325,13 +325,14 @@ const sdkReply = await generateText({
325
325
  ai.chat({ messages, tools }) // respond with tool calls`,
326
326
  },
327
327
  "memory.ts": {
328
- title: "🧠 Agent Memory",
328
+ title: "🧠 Memory Toolkit",
329
329
  table: `| Function | Type | Description |
330
330
  | :--- | :--- | :--- |
331
331
  | \`createMemory()\` | \`factory\` | Compose memory with an extraction model and explicit embedding profile |
332
- | \`memory.extract()\` | \`function\` | Automatically extract facts from conversations |
333
- | \`memory.search()\` | \`function\` | Semantic search over related memories |
334
- | \`memory.buildContext()\` | \`function\` | Compose memory context for agents |`,
332
+ | \`memory.remember()\` | \`function\` | Add raw or extracted durable memory with an idempotency receipt |
333
+ | \`memory.search()\` | \`function\` | Owner/scope-isolated hybrid memory retrieval |
334
+ | \`memory.selectContext()\` | \`function\` | Deterministically select untrusted prompt data within a token budget |
335
+ | \`memory.update()\` / \`forget()\` | \`function\` | Revision-safe correction and privacy deletion |`,
335
336
  usage: `\`\`\`typescript
336
337
  import { createGencowAI } from "@/gencow/ai";
337
338
  import { createMemory, memory, MEMORY_EMBEDDING_PROFILE } from "@/gencow/memory";
@@ -342,17 +343,29 @@ const customMemory = createMemory({
342
343
  embeddingProfile: MEMORY_EMBEDDING_PROFILE,
343
344
  });
344
345
 
345
- const memCtx = await memory.buildContext(ctx, userId, sessionId, query);
346
+ const receipt = await customMemory.remember(ctx, {
347
+ namespace: "assistant-memory",
348
+ scope: { conversation: conversationId },
349
+ input: [{ role: "user", content: query }],
350
+ mode: "extract",
351
+ source: { type: "message", id: messageId, revision: "1" },
352
+ idempotencyKey: \`memory:\${messageId}:1\`,
353
+ });
354
+ const matches = await customMemory.search(ctx, {
355
+ namespace: "assistant-memory",
356
+ scope: { conversation: conversationId },
357
+ query,
358
+ });
346
359
  const reply = await ai.chat({
347
- system: memCtx.toSystemPrompt(),
348
- messages: [...memCtx.recentMessages, { role: "user", content: query }],
360
+ messages: [{ role: "user", content: query }],
349
361
  });
350
362
  \`\`\``,
351
- vibePrompt: `Agent Memory API:
363
+ vibePrompt: `Memory Toolkit API:
352
364
  import { memory } from "@/gencow/memory";
353
365
  createMemory({ extractionModel, embeddingProfile }) // pure AI SDK composition with explicit model+dimensions
354
- memory.buildContext(ctx, userId, sessionId, query) // memory context
355
- memory.extract(ctx, userId, conversation) // fact extraction`,
366
+ memory.remember(ctx, input) // raw/extract durable memory
367
+ memory.search(ctx, input) // owner/scope hybrid recall
368
+ memory.selectContext(ctx, input) // app-owned prompt data`,
356
369
  },
357
370
  "analytics.ts": {
358
371
  title: "📊 Analytics",
@@ -63,11 +63,17 @@ export function handleLocalMigrationCommand({
63
63
  deps.infoImpl("Pushing schema.ts → database (no migration files)...");
64
64
  }
65
65
  try {
66
- deps.runInServer(
67
- "pnpm db:push --force",
68
- deps.buildEnv(config),
69
- jsonMode ? { infoImpl: () => {}, stdio: "pipe" } : undefined,
70
- );
66
+ const env = deps.buildEnv(config);
67
+ const childOptions = jsonMode ? { infoImpl: () => {}, stdio: "pipe" } : undefined;
68
+ if (hasDb) {
69
+ deps.runInServer("pnpm db:push --force", env, childOptions);
70
+ } else {
71
+ // Drizzle Kit cannot attach PGlite's packaged pgvector/pg_trgm modules.
72
+ // Generate the same desired-state migration, then apply it through the
73
+ // runtime connection that owns those extensions.
74
+ deps.runInServer("pnpm db:generate", env, childOptions);
75
+ deps.runInServer("bun src/local-pglite-migrate.ts", env, childOptions);
76
+ }
71
77
  } catch (error) {
72
78
  if (!jsonMode) throw error;
73
79
  emitFailure(buildLocalExecutionFailureDiagnostic(correlationId()));
@@ -259,7 +259,7 @@ ${
259
259
  ${CYAN}gencow add sso${RESET} ${DIM}← Add Google SSO login${RESET}
260
260
  ${CYAN}gencow add Agent${RESET} ${DIM}← Add workflow agent starter${RESET}
261
261
  ${CYAN}gencow add RAG${RESET} ${DIM}← Add RAG component${RESET}
262
- ${CYAN}gencow add Memory${RESET} ${DIM}← Add Agent Memory${RESET}
262
+ ${CYAN}gencow add Memory${RESET} ${DIM}← Add Memory Toolkit${RESET}
263
263
  `
264
264
  }
265
265
  `;
@@ -306,7 +306,8 @@ export function buildAiPrompt(apiObj, namespaces) {
306
306
  md += `- Use rerank({ model: createGencowAI().rerankingModel(...) }) or ai.rerank() only after retrieval authorization; do not pass private metadata as provider payload.\n`;
307
307
  md += `- createGencowAI().rerankingModel(...) is proxy-only today. Local direct mode with only OPENAI_API_KEY must fail fast for reranking.\n`;
308
308
  md += `- The generated reranker starter may use an explicit fallbackModel compatibility path, but strict providerPreference such as azure_cohere must still fail closed on auth/config errors.\n`;
309
- md += `- Recommended chat models: gpt-5.4-mini for most apps, gpt-5.4 for Startup/Enterprise highest quality, gpt-5.4-nano for high-volume extraction.\n`;
309
+ md += `- Use stable virtual profiles for every new hosted chat call: llm/economy for Hobby, llm/balanced for general Startup/Enterprise workloads, llm/quality for maximum quality, and llm/code for tool-using code work.\n`;
310
+ md += `- Direct chat model IDs are only for local direct-provider development, compatibility, or explicitly verified model-specific capabilities.\n`;
310
311
  md += `- Use ai.generateObject() with a Zod schema for structured output. Do not use ai.chat() + JSON.parse().\n`;
311
312
  md += `- Install AI with gencow add AI, RAG with gencow add RAG, Memory with gencow add Memory, and durable agents with gencow add Agent.\n`;
312
313
  md += `\`\`\`\n\n`;
@@ -315,14 +316,14 @@ export function buildAiPrompt(apiObj, namespaces) {
315
316
 
316
317
  export function buildAiUsageSection() {
317
318
  let md = `---\n\n## AI Usage\n\n`;
318
- md += `Gencow supports an Azure-first active chat catalog: gpt-5.4 on Startup/Enterprise, gpt-5.4-mini by default, gpt-5.4-nano for high volume, plus compatibility models gpt-5-mini and gpt-5-nano. Deprecated requests such as \`gpt-5.5\` and \`gpt-4o-mini\` are automatically substituted to the closest supported model before provider execution. Image and embedding models are also controlled by the platform \`model_pricing\` catalog.\n`;
319
- md += `\`OPENAI_API_KEY\` is only for local direct/fallback usage. Cloud deployments use the Gencow AI proxy with platform-managed internal credentials and service credits.\n\n`;
319
+ md += `Gencow recommends stable virtual chat profiles for every new hosted chat call: \`llm/economy\` on Hobby and \`llm/balanced\`, \`llm/quality\`, or \`llm/code\` on Startup/Enterprise. The platform can replace each profile's concrete model without requiring app changes. Direct chat model IDs remain compatibility or model-specific escape hatches, not recommended defaults. Image and embedding models use their dedicated model IDs.\n`;
320
+ md += `The stable \`llm/*\` profiles are resolved by the hosted Gencow AI proxy. \`OPENAI_API_KEY\` is only for local direct/fallback usage, where code must keep using an OpenAI concrete model ID. Cloud deployments use platform-managed internal credentials and service credits.\n\n`;
320
321
  md += `\`\`\`typescript\n`;
321
322
  md += `import { generateImage, generateText, rerank } from "ai";\n`;
322
323
  md += `import { createGencowAI, ai } from "./ai";\n\n`;
323
324
  md += `const gencow = createGencowAI();\n\n`;
324
325
  md += `const result = await generateText({\n`;
325
- md += ` model: gencow.languageModel("gpt-5.4-mini"),\n`;
326
+ md += ` model: gencow.languageModel("llm/balanced"),\n`;
326
327
  md += ` system: "You are a helpful assistant.",\n`;
327
328
  md += ` messages: [{ role: "user", content: "Hello" }],\n`;
328
329
  md += `});\n\n`;
@@ -355,12 +356,11 @@ export function buildAiUsageSection() {
355
356
  md += `\`\`\`\n\n`;
356
357
  md += `| Purpose | Recommended model |\n`;
357
358
  md += `|---|---|\n`;
358
- md += `| Highest quality / complex reasoning | \`gpt-5.4\` (Startup/Enterprise) |\n`;
359
- md += `| Most production chat, coding, and agent tasks | \`gpt-5.4-mini\` |\n`;
360
- md += `| High-volume classification and extraction | \`gpt-5.4-nano\` |\n`;
361
- md += `| Compatibility replacement for deprecated mini-class models | \`gpt-5-mini\` |\n`;
362
- md += `| Compatibility replacement for deprecated nano-class models | \`gpt-5-nano\` |\n`;
363
- md += `| Image-to-text / OCR-style extraction | \`gpt-5.4-mini\` or \`gpt-5-mini\` |\n`;
359
+ md += `| Lowest-cost chat, classification, and extraction | \`llm/economy\` |\n`;
360
+ md += `| Most production chat and agent tasks | \`llm/balanced\` (Startup/Enterprise) |\n`;
361
+ md += `| Highest quality / complex reasoning | \`llm/quality\` (Startup/Enterprise) |\n`;
362
+ md += `| Coding and function tools | \`llm/code\` (Startup/Enterprise) |\n`;
363
+ md += `| Image-to-text / OCR-style extraction | \`llm/balanced\` |\n`;
364
364
  md += `| Image generation | \`gpt-image-2\` or \`gpt-image-1-mini\` |\n\n`;
365
365
  md += `Do not wire \`@ai-sdk/openai\` or provider keys directly. Use \`createGencowAI()\` or the \`ai.*\` facade from \`./ai\`.\n\n`;
366
366
  md += `\`\`\`typescript\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.227",
3
+ "version": "0.1.228",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,11 +31,15 @@
31
31
  "zod": "^4.4.3"
32
32
  },
33
33
  "devDependencies": {
34
+ "@ai-sdk/openai": "^3.0.0",
35
+ "@ai-sdk/provider": "^3.0.0",
36
+ "@ai-sdk/provider-utils": "^4.0.0",
37
+ "ai": "^6.0.233",
34
38
  "@types/node": "^25.9.5",
35
39
  "better-auth": "^1.6.23",
36
40
  "@gencow/client": "0.2.7",
37
- "@gencow/react": "0.2.7",
38
- "@gencow/core": "0.1.43"
41
+ "@gencow/core": "0.1.44",
42
+ "@gencow/react": "0.2.7"
39
43
  },
40
44
  "scripts": {
41
45
  "prebuild": "pnpm --filter @gencow/migration-contract run build && pnpm --filter @gencow/server run build",