gencow 0.1.169 → 0.1.171

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.
@@ -20,7 +20,7 @@ export function resolveBackupAppId(restArgs, gencowJson = null) {
20
20
  export function resolveBackupFilePath(restArgs) {
21
21
  for (let i = 0; i < restArgs.length; i++) {
22
22
  const arg = restArgs[i];
23
- if (arg === "--app" || arg === "-a") {
23
+ if (arg === "--app" || arg === "-a" || arg === "--limit" || arg === "--cursor") {
24
24
  i++;
25
25
  continue;
26
26
  }
@@ -45,10 +45,34 @@ export function formatBackupDate(value) {
45
45
  });
46
46
  }
47
47
 
48
+ export function parseBackupListOptions(restArgs) {
49
+ const options = { all: false, cursor: null, limit: 20 };
50
+ for (let i = 0; i < restArgs.length; i++) {
51
+ const arg = restArgs[i];
52
+ if (arg === "--all") {
53
+ options.all = true;
54
+ continue;
55
+ }
56
+ if (arg === "--limit") {
57
+ const next = Number(restArgs[i + 1]);
58
+ if (Number.isFinite(next)) options.limit = Math.min(100, Math.max(1, Math.trunc(next)));
59
+ i++;
60
+ continue;
61
+ }
62
+ if (arg === "--cursor") {
63
+ options.cursor = restArgs[i + 1] || null;
64
+ i++;
65
+ }
66
+ }
67
+ return options;
68
+ }
69
+
48
70
  function renderBackupHelp(logImpl = log, errorImpl = error, subCmd = null) {
49
71
  if (subCmd) errorImpl(`Unknown sub-command: ${subCmd}`);
50
72
  logImpl(`\n ${BOLD}Usage:${RESET}`);
51
- logImpl(` gencow backup list List all backups`);
73
+ logImpl(` gencow backup list List recent backups`);
74
+ logImpl(` gencow backup list --all List all backups by following cursors`);
75
+ logImpl(` gencow backup list --limit 50 List a page with up to 50 backups`);
52
76
  logImpl(` gencow backup create [note] Create a manual backup`);
53
77
  logImpl(` gencow backup restore <id> Restore from backup`);
54
78
  logImpl(` gencow backup restore-file <path> Restore from a downloaded dump file`);
@@ -56,18 +80,23 @@ function renderBackupHelp(logImpl = log, errorImpl = error, subCmd = null) {
56
80
  logImpl(` gencow backup download <id> Download backup file (Pro+)\n`);
57
81
  }
58
82
 
59
- async function promptRestoreConfirm(sourceLabel, { createInterfaceImpl }) {
83
+ export function buildRestoreConfirmPrompt(sourceLabel, { includeStorageRisk = false } = {}) {
84
+ const storageRisk = includeStorageRisk
85
+ ? `\n ${YELLOW}⚠ 백업 파일 복원은 DB만 교체하며 storage object/blob는 함께 이동하지 않습니다.${RESET}` +
86
+ `\n ${DIM}기본 용도는 같은 환경 복원(prod→prod, dev→dev)입니다. 다른 환경의 dump를 복원하면 이미지/파일 참조가 깨질 수 있습니다.${RESET}`
87
+ : "";
88
+ return `\n ${YELLOW}⚠ 현재 데이터베이스가 ${sourceLabel}로 교체됩니다.${RESET}${storageRisk}\n 계속하시겠습니까? (y/N): `;
89
+ }
90
+
91
+ async function promptRestoreConfirm(sourceLabel, { createInterfaceImpl, includeStorageRisk = false }) {
60
92
  const createInterface = createInterfaceImpl ?? (await import("readline")).createInterface;
61
93
  const rl = createInterface({ input: process.stdin, output: process.stdout });
62
94
  return await new Promise((resolveAnswer) => {
63
- rl.question(
64
- `\n ${YELLOW}⚠ 현재 데이터베이스가 ${sourceLabel}로 교체됩니다. 계속하시겠습니까? (y/N): ${RESET}`,
65
- (answer) => {
66
- rl.close();
67
- const normalized = answer.trim().toLowerCase();
68
- resolveAnswer(normalized === "y" || normalized === "yes");
69
- },
70
- );
95
+ rl.question(buildRestoreConfirmPrompt(sourceLabel, { includeStorageRisk }), (answer) => {
96
+ rl.close();
97
+ const normalized = answer.trim().toLowerCase();
98
+ resolveAnswer(normalized === "y" || normalized === "yes");
99
+ });
71
100
  });
72
101
  }
73
102
 
@@ -108,19 +137,39 @@ export function createBackupCommand({
108
137
  switch (subCmd) {
109
138
  case "list":
110
139
  case "ls": {
111
- const response = await rpcQueryImpl(creds, "backup.list", { appName: appId });
112
- if (!response.ok) {
113
- errorImpl(
114
- `Failed to fetch backup list: ${(await response.json().catch(() => ({}))).error || response.statusText}`,
115
- );
116
- return;
140
+ const options = parseBackupListOptions(restArgs);
141
+ const backups = [];
142
+ let data = null;
143
+ let cursor = options.cursor;
144
+ for (let page = 0; page < 1000; page++) {
145
+ const response = await rpcQueryImpl(creds, "backup.list", {
146
+ appName: appId,
147
+ limit: options.limit,
148
+ cursor,
149
+ });
150
+ if (!response.ok) {
151
+ errorImpl(
152
+ `Failed to fetch backup list: ${(await response.json().catch(() => ({}))).error || response.statusText}`,
153
+ );
154
+ return;
155
+ }
156
+ data = await response.json();
157
+ backups.push(...(data.backups || []));
158
+ cursor = data.pageInfo?.nextCursor || null;
159
+ if (options.all && cursor && page === 999) {
160
+ errorImpl(
161
+ "Backup list is too large to fetch with --all. Resume with --cursor from the previous page.",
162
+ );
163
+ return;
164
+ }
165
+ if (!options.all || !cursor) break;
117
166
  }
118
- const data = await response.json();
119
- const backups = data.backups || [];
120
- const limits = data.limits || {};
167
+ const limits = data?.limits || {};
168
+ const summary = data?.summary || {};
169
+ const pageInfo = data?.pageInfo || {};
121
170
 
122
171
  logImpl(
123
- `\n${BOLD}${CYAN}Database Backups${RESET} — ${appId} ${DIM}(Plan: ${data.plan || "free"})${RESET}\n`,
172
+ `\n${BOLD}${CYAN}Database Backups${RESET} — ${appId} ${DIM}(Plan: ${data?.plan || "free"})${RESET}\n`,
124
173
  );
125
174
 
126
175
  if (backups.length === 0) {
@@ -136,6 +185,16 @@ export function createBackupCommand({
136
185
  }
137
186
  }
138
187
 
188
+ const totalCount = summary.totalCount ?? backups.length;
189
+ const pendingCount = summary.pendingCount ?? 0;
190
+ const shownLabel = options.all
191
+ ? `${backups.length}/${totalCount}`
192
+ : `${backups.length} of ${totalCount}`;
193
+ logImpl(`\n ${DIM}Showing: ${shownLabel} | Pending: ${pendingCount}${RESET}`);
194
+ if (!options.all && pageInfo.nextCursor) {
195
+ logImpl(` ${DIM}Next page: gencow backup list --cursor ${pageInfo.nextCursor}${RESET}`);
196
+ logImpl(` ${DIM}Full history: gencow backup list --all${RESET}`);
197
+ }
139
198
  logImpl(
140
199
  `\n ${DIM}Limits: ${limits.maxManualBackups || "?"} manual | ${limits.retentionDays || "?"} days | Auto: ${limits.autoBackupEnabled ? "ON" : "OFF"}${RESET}\n`,
141
200
  );
@@ -198,7 +257,10 @@ export function createBackupCommand({
198
257
  return;
199
258
  }
200
259
 
201
- const confirmed = await promptRestoreConfirm(`파일 ${filePath}`, { createInterfaceImpl });
260
+ const confirmed = await promptRestoreConfirm(`파일 ${filePath}`, {
261
+ createInterfaceImpl,
262
+ includeStorageRisk: true,
263
+ });
202
264
  if (!confirmed) {
203
265
  infoImpl("Restore cancelled.");
204
266
  return;
@@ -209,14 +271,10 @@ export function createBackupCommand({
209
271
  const buffer = await readFileAsync(filePath);
210
272
  const form = new FormData();
211
273
  form.append("file", new Blob([buffer]), filePath.split(/[\\/]/).pop() || "backup.dump");
212
- const response = await platformFetchImpl(
213
- creds,
214
- `/platform/apps/${appId}/backups/restore-file`,
215
- {
216
- method: "POST",
217
- body: form,
218
- },
219
- );
274
+ const response = await platformFetchImpl(creds, `/platform/apps/${appId}/backups/restore-file`, {
275
+ method: "POST",
276
+ body: form,
277
+ });
220
278
  if (!response.ok) {
221
279
  errorImpl(
222
280
  `Restore failed: ${(await response.json?.().catch(() => ({}))).error || response.statusText}`,
@@ -48,9 +48,18 @@ export function LoginPage() {
48
48
  | \`ai.estimateTokens()\` | \`function\` | Lightweight token estimate |
49
49
  | \`ai.trimMessages()\` | \`function\` | Trim messages to a token budget |`,
50
50
  usage: `\`\`\`typescript
51
- import { ai } from "@/gencow/ai";
51
+ import { generateText, rerank } from "ai";
52
+ import { ai, createGencowAI } from "@/gencow/ai";
52
53
 
53
- // Text generation
54
+ const gencow = createGencowAI();
55
+
56
+ // Pure AI SDK text generation
57
+ const sdkReply = await generateText({
58
+ model: gencow.languageModel("gpt-5.4-mini"),
59
+ messages: [{ role: "user", content: "Hello" }],
60
+ });
61
+
62
+ // Legacy facade text generation
54
63
  const reply = await ai.chat({
55
64
  system: "You are a helpful assistant.",
56
65
  messages: [{ role: "user", content: "Hello" }],
@@ -77,6 +86,14 @@ const ranked = await ai.rerank({
77
86
  topK: 5,
78
87
  });
79
88
 
89
+ // Pure AI SDK rerank path
90
+ const sdkRanked = await rerank({
91
+ model: gencow.rerankingModel("Cohere-rerank-v4.0-fast"),
92
+ documents: candidates.map((candidate) => candidate.text),
93
+ query: "refund policy",
94
+ topN: 5,
95
+ });
96
+
80
97
  // Image generation
81
98
  const image = await ai.image.generate({
82
99
  prompt: "A clean app icon for a todo product",
@@ -91,7 +108,9 @@ const receipt = await ai.vision.extractText({
91
108
  });
92
109
  \`\`\``,
93
110
  vibePrompt: `AI Engine API:
94
- import { ai } from "@/gencow/ai";
111
+ import { ai, createGencowAI } from "@/gencow/ai";
112
+ createGencowAI().languageModel("gpt-5.4-mini") // pure AI SDK model
113
+ createGencowAI().rerankingModel("Cohere-rerank-v4.0-fast") // pure rerank model
95
114
  ai.chat({ messages }) // text generation
96
115
  ai.stream({ messages }) // streaming
97
116
  ai.embed("text") // embedding
@@ -108,6 +127,7 @@ const receipt = await ai.vision.extractText({
108
127
  title: "🤖 Workflow Agent",
109
128
  table: `| Function | Type | Description |
110
129
  | :--- | :--- | :--- |
130
+ | \`createWorkflowAgent()\` | \`factory\` | Compose the starter with an injected AI SDK language model |
111
131
  | \`runAgent\` | \`workflow\` | Durable multi-step agent entrypoint |
112
132
  | \`wf.step()\` | \`runtime\` | Memoized checkpoint step |
113
133
  | \`wf.parallel()\` | \`runtime\` | Branch fan-out with partial progress retention |
@@ -115,8 +135,15 @@ const receipt = await ai.vision.extractText({
115
135
  | \`workflows.signal()\` | \`mutation\` | Wake waiting workflow with payload |`,
116
136
  usage: `\`\`\`typescript
117
137
  import { api } from "@/gencow/api";
138
+ import { createGencowAI } from "@/gencow/ai";
139
+ import { createWorkflowAgent } from "@/gencow/agent";
118
140
  import { useMutation, useWorkflow } from "@gencow/react";
119
141
 
142
+ const gencow = createGencowAI();
143
+ export const customRunAgent = createWorkflowAgent({
144
+ model: gencow.languageModel("gpt-5.4-mini"),
145
+ });
146
+
120
147
  const { mutate: start } = useMutation(api.agents.run);
121
148
  const { mutate: signal } = useMutation(api.workflows.signal);
122
149
 
@@ -131,6 +158,7 @@ await signal({
131
158
  \`\`\``,
132
159
  vibePrompt: `Workflow Agent Starter:
133
160
  workflow("agents.run", { args, handler }) // durable start entrypoint
161
+ createWorkflowAgent({ model }) // pure AI SDK composition
134
162
  wf.step("plan", fn) // memoized checkpoint
135
163
  wf.parallel([taskA, taskB]) // branch fan-out
136
164
  wf.waitForEvent("approval") // human approval checkpoint
@@ -141,6 +169,7 @@ await signal({
141
169
  title: "🔍 RAG Engine",
142
170
  table: `| Function | Type | Description |
143
171
  | :--- | :--- | :--- |
172
+ | \`createRag()\` | \`factory\` | Compose RAG with injected embedding and answer models |
144
173
  | \`rag.ingest()\` | \`function\` | Document chunking plus embedding storage |
145
174
  | \`rag.retrieve()\` | \`function\` | Relevant document retrieval; currently vector search, hybrid-ready |
146
175
  | \`rag.search()\` | \`function\` | \`rag.retrieve()\` compatibility alias |
@@ -150,7 +179,14 @@ await signal({
150
179
  | \`rag.extractTopics()\` | \`function\` | Topic extraction grounded answer |
151
180
  | \`rag.delete()\` | \`function\` | Delete documents by source |`,
152
181
  usage: `\`\`\`typescript
153
- import { rag } from "@/gencow/rag";
182
+ import { createGencowAI } from "@/gencow/ai";
183
+ import { createRag, rag } from "@/gencow/rag";
184
+
185
+ const gencow = createGencowAI();
186
+ const customRag = createRag({
187
+ embeddingModel: gencow.embeddingModel("text-embedding-3-small"),
188
+ answerModel: gencow.languageModel("gpt-5.4-mini"),
189
+ });
154
190
 
155
191
  // Legacy local RAG path: ingest documents into rag_documents.
156
192
  await rag.ingest(ctx, "manual.pdf", documentText, { strategy: "markdown" });
@@ -175,6 +211,7 @@ await rag.delete(ctx, "old-manual.pdf");
175
211
  \`\`\``,
176
212
  vibePrompt: `RAG Engine API:
177
213
  import { rag } from "@/gencow/rag";
214
+ createRag({ embeddingModel, answerModel }) // pure AI SDK composition
178
215
  rag.ingest(ctx, source, text) // document ingest with smart chunking
179
216
  rag.retrieve(ctx, query, { filter }) // relevant document retrieval
180
217
  rag.search(ctx, query, { filter }) // compatibility alias
@@ -237,6 +274,8 @@ const hybrid = await hybridSearchRecords(ctx, "searchable_docs", "refund", {
237
274
  | \`defineTools()\` | \`function\` | Define AI tools with ctx injection |`,
238
275
  usage: `\`\`\`typescript
239
276
  import { defineTools } from "@/gencow/tools";
277
+ import { generateText } from "ai";
278
+ import { createGencowAI } from "@/gencow/ai";
240
279
 
241
280
  const tools = defineTools(ctx, {
242
281
  getOrderStatus: {
@@ -250,21 +289,35 @@ const tools = defineTools(ctx, {
250
289
  });
251
290
 
252
291
  const reply = await ai.chat({ messages, tools });
292
+ const sdkReply = await generateText({
293
+ model: createGencowAI().languageModel("gpt-5.4-mini"),
294
+ messages,
295
+ tools,
296
+ });
253
297
  \`\`\``,
254
298
  vibePrompt: `Tool Calling API:
255
299
  import { defineTools } from "@/gencow/tools";
256
300
  const tools = defineTools(ctx, { ... }) // define AI tools
301
+ generateText({ model, messages, tools }) // pure AI SDK tool call
257
302
  ai.chat({ messages, tools }) // respond with tool calls`,
258
303
  },
259
304
  "memory.ts": {
260
305
  title: "🧠 Agent Memory",
261
306
  table: `| Function | Type | Description |
262
307
  | :--- | :--- | :--- |
308
+ | \`createMemory()\` | \`factory\` | Compose memory with injected extraction and embedding models |
263
309
  | \`memory.extract()\` | \`function\` | Automatically extract facts from conversations |
264
310
  | \`memory.search()\` | \`function\` | Semantic search over related memories |
265
311
  | \`memory.buildContext()\` | \`function\` | Compose memory context for agents |`,
266
312
  usage: `\`\`\`typescript
267
- import { memory } from "@/gencow/memory";
313
+ import { createGencowAI } from "@/gencow/ai";
314
+ import { createMemory, memory } from "@/gencow/memory";
315
+
316
+ const gencow = createGencowAI();
317
+ const customMemory = createMemory({
318
+ extractionModel: gencow.languageModel("gpt-5.4-mini"),
319
+ embeddingModel: gencow.embeddingModel("text-embedding-3-small"),
320
+ });
268
321
 
269
322
  const memCtx = await memory.buildContext(ctx, userId, sessionId, query);
270
323
  const reply = await ai.chat({
@@ -274,6 +327,7 @@ const reply = await ai.chat({
274
327
  \`\`\``,
275
328
  vibePrompt: `Agent Memory API:
276
329
  import { memory } from "@/gencow/memory";
330
+ createMemory({ extractionModel, embeddingModel }) // pure AI SDK composition
277
331
  memory.buildContext(ctx, userId, sessionId, query) // memory context
278
332
  memory.extract(ctx, userId, conversation) // fact extraction`,
279
333
  },
@@ -293,14 +347,23 @@ const reply = await ai.chat({
293
347
  title: "🎯 Reranker",
294
348
  table: `| Function | Type | Description |
295
349
  | :--- | :--- | :--- |
296
- | \`reranker.rerank()\` | \`function\` | LLM-based search result reranking |
350
+ | \`createReranker()\` | \`factory\` | Compose reranking with an injected AI SDK reranking model |
351
+ | \`reranker.rerank()\` | \`function\` | AI SDK rerank primary path with explicit LLM compatibility fallback |
297
352
  | \`reranker.searchAndRerank()\` | \`function\` | Integrated RAG search plus rerank |
298
353
  | \`reranker.answerGrounded()\` | \`function\` | Phase 3 grounded answer helper |`,
299
354
  usage: `\`\`\`typescript
300
- import { reranker } from "@/gencow/reranker";
355
+ import { createGencowAI } from "@/gencow/ai";
356
+ import { createReranker, reranker } from "@/gencow/reranker";
301
357
  import { rag } from "@/gencow/rag";
302
358
 
303
- // Rerank vector search results with an LLM.
359
+ const gencow = createGencowAI();
360
+ const customReranker = createReranker({
361
+ rerankingModel: gencow.rerankingModel("Cohere-rerank-v4.0-fast"),
362
+ fallbackModel: gencow.languageModel("gpt-5.4-mini"),
363
+ });
364
+
365
+ // Rerank vector search results with the proxy-backed AI SDK rerank path.
366
+ // In local direct mode, the generated starter can use the fallback model path.
304
367
  const results = await rag.retrieve(ctx, query, { limit: 20 });
305
368
  const reranked = await reranker.rerank(query, results, { topK: 5 });
306
369
 
@@ -312,7 +375,8 @@ const grounded = await reranker.answerGrounded(ctx, query, { corpus: "default" }
312
375
  \`\`\``,
313
376
  vibePrompt: `Reranker API:
314
377
  import { reranker } from "@/gencow/reranker";
315
- reranker.rerank(query, docs, { topK: 5 }) // LLM rerank
378
+ createReranker({ rerankingModel, fallbackModel }) // pure AI SDK + compat fallback
379
+ reranker.rerank(query, docs, { topK: 5 }) // SDK rerank primary, compat fallback secondary
316
380
  reranker.searchAndRerank(ctx, rag, query) // integrated pipeline
317
381
  reranker.answerGrounded(ctx, query, opts) // grounded answer`,
318
382
  },
@@ -320,11 +384,18 @@ const grounded = await reranker.answerGrounded(ctx, query, { corpus: "default" }
320
384
  title: "🛡️ Guardrails",
321
385
  table: `| Function | Type | Description |
322
386
  | :--- | :--- | :--- |
387
+ | \`createGuardrails()\` | \`factory\` | Compose guardrails with an injected AI SDK language model |
323
388
  | \`guardrails.validateInput()\` | \`function\` | Input validation for PII, topics, and length |
324
389
  | \`guardrails.validateOutput()\` | \`function\` | Output validation for length, patterns, and custom checks |
325
390
  | \`guardrails.wrap()\` | \`function\` | Wrap input, AI call, and output validation in one helper |`,
326
391
  usage: `\`\`\`typescript
327
- import { guardrails } from "@/gencow/guardrails";
392
+ import { createGencowAI } from "@/gencow/ai";
393
+ import { createGuardrails, guardrails } from "@/gencow/guardrails";
394
+
395
+ const gencow = createGencowAI();
396
+ const customGuardrails = createGuardrails({
397
+ model: gencow.languageModel("gpt-5.4-mini"),
398
+ });
328
399
 
329
400
  // Mask PII and block disallowed topics.
330
401
  const safe = await guardrails.validateInput(userMsg, {
@@ -343,6 +414,7 @@ const result = await guardrails.wrap(
343
414
  \`\`\``,
344
415
  vibePrompt: `Guardrails API:
345
416
  import { guardrails } from "@/gencow/guardrails";
417
+ createGuardrails({ model }) // pure AI SDK composition
346
418
  guardrails.validateInput(text, { maskPII: true }) // PII masking
347
419
  guardrails.validateInput(text, { blockTopics }) // topic blocking
348
420
  guardrails.wrap(fn, input, inputOpts, outputOpts) // one-call wrapper`,
@@ -291,11 +291,13 @@ export function buildAiPrompt(apiObj, namespaces) {
291
291
  md += `- Prefer SHA-256 with node:crypto or Web Crypto API instead of custom 32-bit hashes.\n`;
292
292
  md += ` const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));\n\n`;
293
293
  md += `AI rules:\n`;
294
- md += `- New AI SDK-native code can use createGencowAI() from "./ai" with generateText(), embed(), and generateImage().\n`;
294
+ md += `- New AI SDK-native code can use createGencowAI() from "./ai" with generateText(), embed(), rerank(), and generateImage().\n`;
295
295
  md += `- Existing generated components can use ai.chat(), ai.rerank(), ai.vision.extractText(), ai.image.generate(), and ai.generateObject() through the Gencow facade.\n`;
296
296
  md += `- Do not import @ai-sdk/openai/createOpenAI directly, call provider APIs directly, or create wrapper files such as openai-direct.ts.\n`;
297
297
  md += `- Do not log image base64, prompts, provider tokens, or raw private document snippets.\n`;
298
- md += `- Use ai.rerank() only after retrieval authorization; do not pass private metadata as provider payload.\n`;
298
+ md += `- Use rerank({ model: createGencowAI().rerankingModel(...) }) or ai.rerank() only after retrieval authorization; do not pass private metadata as provider payload.\n`;
299
+ md += `- createGencowAI().rerankingModel(...) is proxy-only today. Local direct mode with only OPENAI_API_KEY must fail fast for reranking.\n`;
300
+ 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`;
299
301
  md += `- Recommended chat models: gpt-5.4-mini for most apps, gpt-5.4 for Pro/Scale highest quality, gpt-5.4-nano for high-volume extraction.\n`;
300
302
  md += `- Use ai.generateObject() with a Zod schema for structured output. Do not use ai.chat() + JSON.parse().\n`;
301
303
  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`;
@@ -308,7 +310,7 @@ export function buildAiUsageSection() {
308
310
  md += `Gencow supports an Azure-first active chat catalog: gpt-5.4 on Pro/Scale, 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`;
309
311
  md += `Local development uses \`OPENAI_API_KEY\`; cloud deployments automatically use the Gencow AI proxy and service credits.\n\n`;
310
312
  md += `\`\`\`typescript\n`;
311
- md += `import { generateImage, generateText } from "ai";\n`;
313
+ md += `import { generateImage, generateText, rerank } from "ai";\n`;
312
314
  md += `import { createGencowAI, ai } from "./ai";\n\n`;
313
315
  md += `const gencow = createGencowAI();\n\n`;
314
316
  md += `const result = await generateText({\n`;
@@ -320,6 +322,12 @@ export function buildAiUsageSection() {
320
322
  md += ` model: gencow.imageModel("gpt-image-2"),\n`;
321
323
  md += ` prompt: "A clean app icon for a project management product",\n`;
322
324
  md += `});\n\n`;
325
+ md += `const ranked = await rerank({\n`;
326
+ md += ` model: gencow.rerankingModel("Cohere-rerank-v4.0-fast"),\n`;
327
+ md += ` documents: ["Refunds are available within 7 days.", "Shipping takes 2 days."],\n`;
328
+ md += ` query: "refund policy",\n`;
329
+ md += ` topN: 1,\n`;
330
+ md += `});\n\n`;
323
331
  md += `const icon = await ai.image.generate({\n`;
324
332
  md += ` prompt: "A clean app icon for a project management product",\n`;
325
333
  md += ` model: "gpt-image-2",\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.169",
3
+ "version": "0.1.171",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {