openmates 0.28.0-alpha.0 → 0.28.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 +61 -8
- package/dist/{chunk-F2U6KIMR.js → chunk-5OCI636P.js} +29 -3
- package/dist/{chunk-BL6IFPFM.js → chunk-FN4LSYMI.js} +22933 -29212
- package/dist/{chunk-W5Q6FXNZ.js → chunk-QRCAXXAL.js} +5 -0
- package/dist/{cli-D5UofdbI.d.ts → cli-fJnu1wIs.d.ts} +20 -3
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +3 -3
- package/dist/index.d.ts +802 -185
- package/dist/index.js +7 -3
- package/dist/{privacyScan-MLX3RPGA.js → privacyScan-DJCR2FTA.js} +1 -1
- package/dist/{tasksCli-VEBWWQW4.js → tasksCli-NXIDMIL6.js} +1 -1
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/manifest.json +9 -9
- package/package.json +3 -3
- package/templates/core/docker-compose.selfhost.yml +13 -1
package/README.md
CHANGED
|
@@ -121,8 +121,13 @@ openmates chats share last --expires 604800
|
|
|
121
121
|
openmates chats delete <chat-id> --yes
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
Exports include YAML and Markdown. When present, code embeds
|
|
125
|
-
|
|
124
|
+
Exports include YAML and Markdown. When present, code embeds, video transcripts,
|
|
125
|
+
and calendar events are written as separate files. Calendar files appear in
|
|
126
|
+
`calendar/` as `.ics` files, each containing only its primary event.
|
|
127
|
+
|
|
128
|
+
The TypeScript SDK also supports local calendar export from decrypted embed
|
|
129
|
+
content. `buildCalendarEventFile(embedId, content)` returns an RFC 5545 string;
|
|
130
|
+
it requires a valid finished calendar event and does not contact a calendar provider.
|
|
126
131
|
|
|
127
132
|
### Use apps and typed commands
|
|
128
133
|
|
|
@@ -337,13 +342,14 @@ Treat these files like account credentials.
|
|
|
337
342
|
|
|
338
343
|
## Node.js SDK
|
|
339
344
|
|
|
340
|
-
The npm package also exports
|
|
341
|
-
|
|
345
|
+
The npm package also exports a Node.js SDK. Without an API key, supported app
|
|
346
|
+
skills and `chats.send()` use the shared free allowance without an account.
|
|
347
|
+
A configured `OPENMATES_API_KEY` automatically uses your account instead.
|
|
342
348
|
|
|
343
|
-
```
|
|
349
|
+
```typescript
|
|
344
350
|
import { OpenMates } from "openmates";
|
|
345
351
|
|
|
346
|
-
const om = new OpenMates(
|
|
352
|
+
const om = new OpenMates();
|
|
347
353
|
|
|
348
354
|
const search = await om.apps.web.search({
|
|
349
355
|
requests: [{ query: "OpenMates SDK examples" }],
|
|
@@ -352,8 +358,22 @@ const search = await om.apps.web.search({
|
|
|
352
358
|
const response = await om.chats.send("Summarize this release note draft.");
|
|
353
359
|
```
|
|
354
360
|
|
|
355
|
-
|
|
356
|
-
|
|
361
|
+
Check the allowance with `await om.anonymous.status()`. No identity setup is
|
|
362
|
+
needed. Free usage is limited by public IP and a shared daily, weekly, and monthly
|
|
363
|
+
service allowance; people on the same network may share the IP limit.
|
|
364
|
+
When the allowance is used or unavailable, `OpenMatesSignupRequiredError` exposes
|
|
365
|
+
`signupRequired`, `code`, and `reason`, with a message directing users to create
|
|
366
|
+
an account. Provider and network failures remain separate errors.
|
|
367
|
+
|
|
368
|
+
Pass `apiKey` or set `OPENMATES_API_KEY` to use an account. Invalid or exhausted
|
|
369
|
+
keys never fall back to free usage. For advanced free-only use, `anonymous: true`
|
|
370
|
+
ignores an environment key; it cannot be combined with an explicit `apiKey`.
|
|
371
|
+
|
|
372
|
+
SDK chats are non-persistent by default. Account-only options, including saved
|
|
373
|
+
chats, Memories, Teams, focus modes, and model overrides, require an API key.
|
|
374
|
+
Use `chats.send()` for anonymous AI chat with automatic routing; `apps.ai.ask()`
|
|
375
|
+
requires an account. With an API key, use `saveToAccount: true` when you want the
|
|
376
|
+
chat saved to the OpenMates account.
|
|
357
377
|
|
|
358
378
|
## Versioning
|
|
359
379
|
|
|
@@ -374,3 +394,36 @@ Install stable releases with `npm install -g openmates`. Install prereleases wit
|
|
|
374
394
|
- [SDK guide](https://openmates.org/docs/user-guide/developers/sdk)
|
|
375
395
|
- [Source code](https://github.com/glowingkitty/OpenMates/tree/dev/frontend/packages/openmates-cli)
|
|
376
396
|
- [Issue tracker](https://github.com/glowingkitty/OpenMates/issues)
|
|
397
|
+
## Experimental image decisions
|
|
398
|
+
|
|
399
|
+
`apps.ai.decide` supports Jev 1.14 decisions over inline PNG/JPEG images:
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
import { readFile } from "node:fs/promises";
|
|
403
|
+
import { randomUUID } from "node:crypto";
|
|
404
|
+
import { OpenMates } from "openmates";
|
|
405
|
+
|
|
406
|
+
const om = new OpenMates();
|
|
407
|
+
const ref = randomUUID();
|
|
408
|
+
const result = await om.apps.ai.decide({
|
|
409
|
+
state: { board: ref },
|
|
410
|
+
questions: { clear: { type: "noul", instructions: "Is the path to the exit clear?" } },
|
|
411
|
+
assets: {
|
|
412
|
+
[ref]: { type: "image", format: "png", data_base64: (await readFile("board.png")).toString("base64") }
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
console.log(result);
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Every asset needs a canonical lowercase UUID key referenced in a string value
|
|
419
|
+
in state, instructions, or criteria. OpenMates validates up to four still images,
|
|
420
|
+
1 MiB decoded per image and 4 MiB total, with both dimensions 280–1568 pixels.
|
|
421
|
+
State/questions remain limited to 16 KiB; the complete JSON body is limited to
|
|
422
|
+
6 MiB. Use `jpg` or `jpeg` for JPEG bytes. CLI callers can pass the same JSON
|
|
423
|
+
shape with `openmates apps ai decide --input '<JSON>' --json`.
|
|
424
|
+
|
|
425
|
+
This prototype feature calls TypeSafe directly, never OpenRouter fallback.
|
|
426
|
+
Image tokens use the same applicable free allowance or account credits. No
|
|
427
|
+
provider key or image header is required from the caller. It does not fetch
|
|
428
|
+
remote images or create stored uploads; account upload flows still need signup.
|
|
429
|
+
See [REST image decisions](https://github.com/glowingkitty/OpenMates/blob/dev/docs/architecture/apps/rest-api.md#experimental-image-decisions).
|
|
@@ -181,22 +181,47 @@ async function recoveryEnvelopeKey(sharedSecret, associatedData) {
|
|
|
181
181
|
const salt = await sha256(new TextEncoder().encode("openmates:chat-recovery-envelope:v1"));
|
|
182
182
|
return hkdfSha256(sharedSecret, salt, await sha256(associatedData));
|
|
183
183
|
}
|
|
184
|
+
async function openChatMetadataRecoveryEnvelope(envelope, options) {
|
|
185
|
+
if (options.stage !== "initial" && options.stage !== "postprocessing") throw new Error("unsupported metadata stage");
|
|
186
|
+
const aad = concatBytes(
|
|
187
|
+
new TextEncoder().encode("OMCM1"),
|
|
188
|
+
...[options.ownerId, options.chatId, options.taskId, options.jobId].map((value) => lengthPrefix(canonicalUuid(value, "metadata_identity"))),
|
|
189
|
+
lengthPrefix(new TextEncoder().encode(options.stage)),
|
|
190
|
+
recoveryKeyVersion(options.keyVersion)
|
|
191
|
+
);
|
|
192
|
+
const bytes = await openRecoveryEnvelopeWithAssociatedData(envelope, options.recoveryPrivateKey, aad, 64 * 1024);
|
|
193
|
+
const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
194
|
+
const identity = {
|
|
195
|
+
owner_id: options.ownerId,
|
|
196
|
+
chat_id: options.chatId,
|
|
197
|
+
task_id: options.taskId,
|
|
198
|
+
job_id: options.jobId,
|
|
199
|
+
stage: options.stage,
|
|
200
|
+
key_version: options.keyVersion
|
|
201
|
+
};
|
|
202
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload) || Object.keys(payload).sort().join(",") !== [...Object.keys(identity), "metadata"].sort().join(",") || Object.entries(identity).some(([key, value]) => payload[key] !== value)) throw new Error("metadata identity mismatch");
|
|
203
|
+
const metadata = payload.metadata;
|
|
204
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata) || !Object.keys(metadata).length || Object.entries(metadata).some(([key, value]) => !["title", "summary", "category", "icon"].includes(key) || typeof value !== "string" || !value.length)) throw new Error("invalid metadata fields");
|
|
205
|
+
return metadata;
|
|
206
|
+
}
|
|
184
207
|
async function openChatCompletionRecoveryEnvelope(envelope, options) {
|
|
208
|
+
return openRecoveryEnvelopeWithAssociatedData(envelope, options.recoveryPrivateKey, recoveryAssociatedData(options), CHAT_RECOVERY_MAX_PAYLOAD_BYTES);
|
|
209
|
+
}
|
|
210
|
+
async function openRecoveryEnvelopeWithAssociatedData(envelope, recoveryPrivateKeyEncoded, associatedData, maxPayloadBytes) {
|
|
185
211
|
if (!envelope || Object.keys(envelope).sort().join(",") !== "ciphertext,epk,nonce,v" || envelope.v !== CHAT_RECOVERY_PROTOCOL_VERSION) {
|
|
186
212
|
throw new Error("invalid recovery envelope fields or version");
|
|
187
213
|
}
|
|
188
214
|
const recoveryPrivateKey = base64UrlToBytes(
|
|
189
|
-
|
|
215
|
+
recoveryPrivateKeyEncoded,
|
|
190
216
|
"recovery_private_key",
|
|
191
217
|
CHAT_RECOVERY_KEY_BYTES
|
|
192
218
|
);
|
|
193
219
|
const ephemeralPublicKey = base64UrlToBytes(envelope.epk, "epk", CHAT_RECOVERY_KEY_BYTES);
|
|
194
220
|
const nonce = base64UrlToBytes(envelope.nonce, "nonce", CHAT_RECOVERY_NONCE_BYTES);
|
|
195
221
|
const ciphertext = base64UrlToBytes(envelope.ciphertext, "ciphertext");
|
|
196
|
-
if (ciphertext.length < 16 || ciphertext.length - 16 >
|
|
222
|
+
if (ciphertext.length < 16 || ciphertext.length - 16 > maxPayloadBytes) {
|
|
197
223
|
throw new Error("ciphertext payload size is invalid");
|
|
198
224
|
}
|
|
199
|
-
const associatedData = recoveryAssociatedData(options);
|
|
200
225
|
const sharedSecret = nacl.scalarMult(recoveryPrivateKey, ephemeralPublicKey);
|
|
201
226
|
const envelopeKeyBytes = await recoveryEnvelopeKey(sharedSecret, associatedData);
|
|
202
227
|
const envelopeKey = await cryptoApi.subtle.importKey(
|
|
@@ -1289,6 +1314,7 @@ export {
|
|
|
1289
1314
|
bytesToBase64Url,
|
|
1290
1315
|
deriveTeamInviteKey,
|
|
1291
1316
|
deriveChatCompletionRecoveryKeypair,
|
|
1317
|
+
openChatMetadataRecoveryEnvelope,
|
|
1292
1318
|
openChatCompletionRecoveryEnvelope,
|
|
1293
1319
|
openRecoveryOutputEnvelope,
|
|
1294
1320
|
hashEmail,
|