@kokimoki/app 2.1.0 → 3.0.0
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/README.md +72 -0
- package/dist/core/kokimoki-client.d.ts +75 -15
- package/dist/core/kokimoki-client.js +137 -22
- package/dist/index.d.ts +6 -1
- package/dist/index.js +4 -0
- package/dist/kokimoki.min.d.ts +322 -2
- package/dist/kokimoki.min.js +1884 -72
- package/dist/kokimoki.min.js.map +1 -1
- package/dist/llms.txt +6 -0
- package/dist/protocol/ws-message/reader.d.ts +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/kokimoki-ai.d.ts +185 -122
- package/dist/services/kokimoki-ai.js +201 -109
- package/dist/services/kokimoki-i18n.d.ts +259 -0
- package/dist/services/kokimoki-i18n.js +325 -0
- package/dist/stores/kokimoki-local-store.d.ts +1 -1
- package/dist/types/common.d.ts +9 -0
- package/dist/types/env.d.ts +36 -0
- package/dist/types/env.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/kokimoki-client.d.ts +31 -0
- package/dist/utils/kokimoki-client.js +38 -0
- package/dist/utils/kokimoki-dev.d.ts +30 -0
- package/dist/utils/kokimoki-dev.js +75 -0
- package/dist/utils/kokimoki-env.d.ts +20 -0
- package/dist/utils/kokimoki-env.js +30 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/kokimoki-ai.instructions.md +316 -0
- package/docs/kokimoki-dynamic-stores.instructions.md +439 -0
- package/docs/kokimoki-i18n.instructions.md +285 -0
- package/docs/kokimoki-leaderboard.instructions.md +189 -0
- package/docs/kokimoki-sdk.instructions.md +221 -0
- package/docs/kokimoki-storage.instructions.md +162 -0
- package/llms.txt +43 -0
- package/package.json +9 -13
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "AI text generation and image transformation with Kokimoki SDK"
|
|
3
|
+
applyTo: "**/*.ts,**/*.tsx"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI Integration
|
|
7
|
+
|
|
8
|
+
Built-in methods for AI text generation and image transformation. No API keys required.
|
|
9
|
+
All generation methods are **async job-based** - they submit a job and return immediately with a `jobId`.
|
|
10
|
+
Use the corresponding poll method to wait for the result.
|
|
11
|
+
|
|
12
|
+
For core SDK concepts, see [Kokimoki SDK](./kokimoki-sdk.instructions.md).
|
|
13
|
+
|
|
14
|
+
Access AI API via `kmClient.ai`.
|
|
15
|
+
|
|
16
|
+
## Key Features
|
|
17
|
+
|
|
18
|
+
- Multiple AI models (GPT-4, GPT-5, Gemini variants)
|
|
19
|
+
- Text generation with configurable creativity (temperature)
|
|
20
|
+
- Structured JSON output with Zod schema validation
|
|
21
|
+
- AI-powered image generation and modification
|
|
22
|
+
- Job-based async processing with polling support
|
|
23
|
+
- Resumable after page reload (persist jobId)
|
|
24
|
+
|
|
25
|
+
## Available Models
|
|
26
|
+
|
|
27
|
+
**Text Models:**
|
|
28
|
+
|
|
29
|
+
- `gpt-4o`: OpenAI GPT-4 Optimized
|
|
30
|
+
- `gpt-4o-mini`: Smaller, faster GPT-4 variant
|
|
31
|
+
- `gpt-5`: OpenAI GPT-5 (latest)
|
|
32
|
+
- `gpt-5-mini`: Smaller GPT-5 variant
|
|
33
|
+
- `gpt-5-nano`: Smallest GPT-5 variant for lightweight tasks
|
|
34
|
+
- `gemini-2.5-flash-lite`: Google Gemini lite variant
|
|
35
|
+
- `gemini-2.5-flash`: Google Gemini fast variant
|
|
36
|
+
- `gemini-3-flash-preview`: Google Gemini 3 Flash preview
|
|
37
|
+
- `gemini-3-pro-preview`: Google Gemini 3 Pro preview
|
|
38
|
+
|
|
39
|
+
**Image Models:**
|
|
40
|
+
|
|
41
|
+
- `gemini-2.5-flash-image`: Google Gemini image generation
|
|
42
|
+
- `gemini-3-pro-image-preview`: Google Gemini 3 Pro image preview
|
|
43
|
+
|
|
44
|
+
## API Methods
|
|
45
|
+
|
|
46
|
+
### ai.generateText(req): Promise<{ jobId: string }>
|
|
47
|
+
|
|
48
|
+
Submits a text generation job. Use `pollText()` to wait for the result.
|
|
49
|
+
|
|
50
|
+
**Parameters:**
|
|
51
|
+
|
|
52
|
+
- **req.model**: `string` AI model to use (optional)
|
|
53
|
+
- **req.systemPrompt**: `string` AI role/behavior (optional)
|
|
54
|
+
- **req.prompt**: `string` The user's message or question to send to the AI
|
|
55
|
+
- **req.temperature**: `number` Creativity level from 0.0 = factual to 1.0 = creative (optional)
|
|
56
|
+
- **req.imageUrls**: `string[]` Image URLs to include with the prompt (Gemini models only) (optional)
|
|
57
|
+
|
|
58
|
+
**Example:**
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Submit text generation job
|
|
62
|
+
const { jobId } = await kmClient.ai.generateText({
|
|
63
|
+
model: "gemini-2.5-flash-lite",
|
|
64
|
+
systemPrompt: "You are a fantasy story writer",
|
|
65
|
+
prompt: "Write a short quest description",
|
|
66
|
+
temperature: 0.8,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Poll for result
|
|
70
|
+
const text = await kmClient.ai.pollText(jobId);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### ai.generateJson<T>(req): Promise<{ jobId: string }>
|
|
74
|
+
|
|
75
|
+
Submits a JSON generation job with Zod schema validation. Use `pollJson()` to wait for the result with type inference.
|
|
76
|
+
|
|
77
|
+
**Parameters:**
|
|
78
|
+
|
|
79
|
+
- **req.schema**: `ZodType` Zod schema that defines the expected JSON structure
|
|
80
|
+
- **req.model**: `string` AI model to use (optional)
|
|
81
|
+
- **req.systemPrompt**: `string` AI role/behavior (optional)
|
|
82
|
+
- **req.prompt**: `string` The user's message or question to send to the AI
|
|
83
|
+
- **req.temperature**: `number` Creativity level from 0.0 = factual to 1.0 = creative (optional)
|
|
84
|
+
- **req.imageUrls**: `string[]` Image URLs to include with the prompt (Gemini models only) (optional)
|
|
85
|
+
|
|
86
|
+
**Example:**
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { z } from "zod/v4";
|
|
90
|
+
|
|
91
|
+
// Define schema with Zod
|
|
92
|
+
const enemySchema = z.object({
|
|
93
|
+
name: z.string(),
|
|
94
|
+
health: z.number(),
|
|
95
|
+
attack: z.number(),
|
|
96
|
+
abilities: z.array(z.string()),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Submit JSON generation job
|
|
100
|
+
const { jobId } = await kmClient.ai.generateJson({
|
|
101
|
+
schema: enemySchema,
|
|
102
|
+
prompt: "Create a level 5 goblin warrior",
|
|
103
|
+
temperature: 0.7,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Save jobId to store for persistence across reloads
|
|
107
|
+
await saveJobId(jobId);
|
|
108
|
+
|
|
109
|
+
// Poll with schema for type inference and validation
|
|
110
|
+
const enemy = await kmClient.ai.pollJson(jobId, { schema: enemySchema });
|
|
111
|
+
console.log(enemy.name, enemy.health); // Fully typed!
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Generate quiz questions
|
|
116
|
+
const questionSchema = z.array(
|
|
117
|
+
z.object({
|
|
118
|
+
question: z.string(),
|
|
119
|
+
options: z.array(z.string()),
|
|
120
|
+
correctAnswer: z.number(),
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const { jobId } = await kmClient.ai.generateJson({
|
|
125
|
+
schema: questionSchema,
|
|
126
|
+
systemPrompt: "Generate quiz questions",
|
|
127
|
+
prompt: "Create 5 history quiz questions with 4 options each",
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const questions = await kmClient.ai.pollJson(jobId, { schema: questionSchema });
|
|
131
|
+
questions.forEach((q) => console.log(q.question));
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### ai.generateImage(req): Promise<{ jobId: string }>
|
|
135
|
+
|
|
136
|
+
Submits an image generation/modification job. Use `pollImage()` to wait for the result.
|
|
137
|
+
The result is stored as `Upload` object (see [Storage](./kokimoki-storage.instructions.md)).
|
|
138
|
+
|
|
139
|
+
**Parameters:**
|
|
140
|
+
|
|
141
|
+
- **req.model**: `string` Image model to use (optional, default: `gemini-2.5-flash-image`)
|
|
142
|
+
- **req.prompt**: `string` The prompt describing the image or modification
|
|
143
|
+
- **req.imageUrls**: `string[]` Source image URLs to include in the generation (optional)
|
|
144
|
+
- **req.tags**: `string[]` Tags for the result in `Upload` format (optional, default: [])
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Generate a new image
|
|
150
|
+
const { jobId } = await kmClient.ai.generateImage({
|
|
151
|
+
prompt: "A fantasy castle on a mountain at sunset",
|
|
152
|
+
tags: ["background", "ai-generated"],
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const upload = await kmClient.ai.pollImage(jobId);
|
|
156
|
+
console.log(upload.url); // CDN URL to the generated image
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Modify an existing image
|
|
161
|
+
const { jobId } = await kmClient.ai.generateImage({
|
|
162
|
+
imageUrls: ["https://static.kokimoki.com/game/image.jpg"],
|
|
163
|
+
prompt: "Make it look like pixel art",
|
|
164
|
+
tags: ["art", "ai-generated"],
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const upload: Upload = await kmClient.ai.pollImage(jobId);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### ai.getJob(jobId): Promise<AiJob>
|
|
171
|
+
|
|
172
|
+
Get the current status of an AI job without polling.
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
|
|
176
|
+
- **jobId**: `string` The job ID to check
|
|
177
|
+
|
|
178
|
+
**Returns:** `AiJob` object with status and result
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
interface AiJob {
|
|
182
|
+
jobId: string;
|
|
183
|
+
type: "text" | "json" | "image";
|
|
184
|
+
status: "processing" | "queued" | "completed" | "failed";
|
|
185
|
+
result?: unknown;
|
|
186
|
+
error?: { message: string; code?: string };
|
|
187
|
+
createdAt: number;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Example:**
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const job = await kmClient.ai.getJob(jobId);
|
|
195
|
+
if (job.status === "completed") {
|
|
196
|
+
console.log("Result:", job.result);
|
|
197
|
+
} else if (job.status === "failed") {
|
|
198
|
+
console.error("Error:", job.error?.message);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### ai.pollText(jobId, options?): Promise<string>
|
|
203
|
+
|
|
204
|
+
Poll a text generation job until completion.
|
|
205
|
+
|
|
206
|
+
**Parameters:**
|
|
207
|
+
|
|
208
|
+
- **jobId**: `string` The job ID to poll
|
|
209
|
+
- **options.pollInterval**: `number` Polling interval in ms (default: 2000, min: 1000)
|
|
210
|
+
- **options.timeout**: `number` Timeout in ms (default: 120000)
|
|
211
|
+
- **options.onProgress**: `(status: AiJobStatus) => void` Progress callback
|
|
212
|
+
|
|
213
|
+
**Example:**
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
const text = await kmClient.ai.pollText(jobId, {
|
|
217
|
+
timeout: 60000,
|
|
218
|
+
onProgress: (status) => console.log("Status:", status),
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### ai.pollJson<T>(jobId, options): Promise<T>
|
|
223
|
+
|
|
224
|
+
Poll a JSON generation job until completion with schema validation.
|
|
225
|
+
|
|
226
|
+
**Parameters:**
|
|
227
|
+
|
|
228
|
+
- **jobId**: `string` The job ID to poll
|
|
229
|
+
- **options.schema**: `ZodType` Zod schema for validation and type inference (required)
|
|
230
|
+
- **options.pollInterval**: `number` Polling interval in ms (default: 2000, min: 1000)
|
|
231
|
+
- **options.timeout**: `number` Timeout in ms (default: 120000)
|
|
232
|
+
- **options.onProgress**: `(status: AiJobStatus) => void` Progress callback
|
|
233
|
+
|
|
234
|
+
**Example:**
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const enemy = await kmClient.ai.pollJson(jobId, {
|
|
238
|
+
schema: enemySchema,
|
|
239
|
+
timeout: 60000,
|
|
240
|
+
onProgress: (status) => console.log("Status:", status),
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### ai.pollImage(jobId, options?): Promise<Upload>
|
|
245
|
+
|
|
246
|
+
Poll an image generation job until completion.
|
|
247
|
+
|
|
248
|
+
**Parameters:**
|
|
249
|
+
|
|
250
|
+
- **jobId**: `string` The job ID to poll
|
|
251
|
+
- **options.pollInterval**: `number` Polling interval in ms (default: 2000, min: 1000)
|
|
252
|
+
- **options.timeout**: `number` Timeout in ms (default: 120000)
|
|
253
|
+
- **options.onProgress**: `(status: AiJobStatus) => void` Progress callback
|
|
254
|
+
|
|
255
|
+
**Example:**
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const upload = await kmClient.ai.pollImage(jobId, {
|
|
259
|
+
timeout: 60000,
|
|
260
|
+
onProgress: (status) => console.log("Status:", status),
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Common Patterns
|
|
265
|
+
|
|
266
|
+
### Example: Persist Jobs Across Page Reloads
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Store jobId in local store for persistence
|
|
270
|
+
const { jobId } = await kmClient.ai.generateJson({
|
|
271
|
+
schema: questSchema,
|
|
272
|
+
prompt: "Generate an epic quest",
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
await kmClient.transact([localStore], ([state]) => {
|
|
276
|
+
state.pendingQuestJobId = jobId;
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// On page load, resume polling if job is pending
|
|
280
|
+
const pendingJobId = localStore.proxy.pendingQuestJobId;
|
|
281
|
+
if (pendingJobId) {
|
|
282
|
+
const quest = await kmClient.ai.pollJson(pendingJobId, {
|
|
283
|
+
schema: questSchema,
|
|
284
|
+
});
|
|
285
|
+
// Clear pending job
|
|
286
|
+
await kmClient.transact([localStore], ([state]) => {
|
|
287
|
+
state.pendingQuestJobId = null;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Example: Show Loading State
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
setLoading(true);
|
|
296
|
+
const { jobId } = await kmClient.ai.generateText({
|
|
297
|
+
prompt: "Write a story",
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const text = await kmClient.ai.pollText(jobId, {
|
|
301
|
+
onProgress: (status) => {
|
|
302
|
+
if (status === "queued") setLoadingText("Waiting in queue...");
|
|
303
|
+
if (status === "processing") setLoadingText("Generating...");
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
setLoading(false);
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Key Points
|
|
310
|
+
|
|
311
|
+
- **Job-based**: All generation methods return `{ jobId }` immediately, use poll methods for results
|
|
312
|
+
- **Resumable**: Save `jobId` to store to resume polling after page reload
|
|
313
|
+
- **Zod Schemas**: Use Zod schemas for `generateJson` to get automatic type inference and validation
|
|
314
|
+
- **Temperature**: Range 0.0 (factual) to 1.0 (creative)
|
|
315
|
+
- **Polling Options**: Configure `pollInterval`, `timeout`, and `onProgress` callback
|
|
316
|
+
- **Image URLs**: Gemini models support multimodal input via `imageUrls` parameter
|