@mindstudio-ai/remy 0.1.227 → 0.1.229
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/dist/headless.js
CHANGED
|
@@ -6362,7 +6362,9 @@ var SESSION_FILE = ".remy-session.json";
|
|
|
6362
6362
|
var ARCHIVE_DIR = ".logs/sessions";
|
|
6363
6363
|
var ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
|
|
6364
6364
|
var RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
|
|
6365
|
+
var ARCHIVE_RETENTION_BYTES = 64 * 1024 * 1024;
|
|
6365
6366
|
function loadSession(state) {
|
|
6367
|
+
pruneArchives();
|
|
6366
6368
|
try {
|
|
6367
6369
|
const raw = fs22.readFileSync(SESSION_FILE, "utf-8");
|
|
6368
6370
|
const data = JSON.parse(raw);
|
|
@@ -6450,8 +6452,50 @@ function archiveMessages(messages, label, models) {
|
|
|
6450
6452
|
}
|
|
6451
6453
|
fs22.writeFileSync(dest, JSON.stringify(payload), "utf-8");
|
|
6452
6454
|
log12.info("Session archived", { label, dest, messageCount: messages.length });
|
|
6455
|
+
pruneArchives();
|
|
6453
6456
|
return dest;
|
|
6454
6457
|
}
|
|
6458
|
+
function pruneArchives() {
|
|
6459
|
+
try {
|
|
6460
|
+
const entries = fs22.readdirSync(ARCHIVE_DIR).filter((name) => /^(cleared|rotated)-.*\.json$/.test(name));
|
|
6461
|
+
if (entries.length <= 1) {
|
|
6462
|
+
return;
|
|
6463
|
+
}
|
|
6464
|
+
const sortKey = (name) => name.replace(/^(cleared|rotated)-/, "");
|
|
6465
|
+
const archives = entries.map((name) => ({
|
|
6466
|
+
name,
|
|
6467
|
+
size: fs22.statSync(path11.join(ARCHIVE_DIR, name)).size
|
|
6468
|
+
})).sort((a, b) => sortKey(b.name).localeCompare(sortKey(a.name)));
|
|
6469
|
+
let kept = 0;
|
|
6470
|
+
let cut = archives.length;
|
|
6471
|
+
for (let i = 0; i < archives.length; i++) {
|
|
6472
|
+
if (i === 0 || kept + archives[i].size <= ARCHIVE_RETENTION_BYTES) {
|
|
6473
|
+
kept += archives[i].size;
|
|
6474
|
+
} else {
|
|
6475
|
+
cut = i;
|
|
6476
|
+
break;
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6479
|
+
let removed = 0;
|
|
6480
|
+
let freed = 0;
|
|
6481
|
+
for (let i = cut; i < archives.length; i++) {
|
|
6482
|
+
try {
|
|
6483
|
+
fs22.unlinkSync(path11.join(ARCHIVE_DIR, archives[i].name));
|
|
6484
|
+
freed += archives[i].size;
|
|
6485
|
+
removed++;
|
|
6486
|
+
} catch {
|
|
6487
|
+
}
|
|
6488
|
+
}
|
|
6489
|
+
if (removed > 0) {
|
|
6490
|
+
log12.info("Session archives pruned", {
|
|
6491
|
+
removed,
|
|
6492
|
+
freedBytes: freed,
|
|
6493
|
+
keptBytes: kept
|
|
6494
|
+
});
|
|
6495
|
+
}
|
|
6496
|
+
} catch {
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6455
6499
|
function rotate(state) {
|
|
6456
6500
|
const messages = state.messages;
|
|
6457
6501
|
if (messages.length === 0) {
|
package/dist/index.js
CHANGED
|
@@ -6717,6 +6717,7 @@ var init_toolResultCap = __esm({
|
|
|
6717
6717
|
import fs20 from "fs";
|
|
6718
6718
|
import path9 from "path";
|
|
6719
6719
|
function loadSession(state) {
|
|
6720
|
+
pruneArchives();
|
|
6720
6721
|
try {
|
|
6721
6722
|
const raw = fs20.readFileSync(SESSION_FILE, "utf-8");
|
|
6722
6723
|
const data = JSON.parse(raw);
|
|
@@ -6804,8 +6805,50 @@ function archiveMessages(messages, label, models) {
|
|
|
6804
6805
|
}
|
|
6805
6806
|
fs20.writeFileSync(dest, JSON.stringify(payload), "utf-8");
|
|
6806
6807
|
log9.info("Session archived", { label, dest, messageCount: messages.length });
|
|
6808
|
+
pruneArchives();
|
|
6807
6809
|
return dest;
|
|
6808
6810
|
}
|
|
6811
|
+
function pruneArchives() {
|
|
6812
|
+
try {
|
|
6813
|
+
const entries = fs20.readdirSync(ARCHIVE_DIR).filter((name) => /^(cleared|rotated)-.*\.json$/.test(name));
|
|
6814
|
+
if (entries.length <= 1) {
|
|
6815
|
+
return;
|
|
6816
|
+
}
|
|
6817
|
+
const sortKey = (name) => name.replace(/^(cleared|rotated)-/, "");
|
|
6818
|
+
const archives = entries.map((name) => ({
|
|
6819
|
+
name,
|
|
6820
|
+
size: fs20.statSync(path9.join(ARCHIVE_DIR, name)).size
|
|
6821
|
+
})).sort((a, b) => sortKey(b.name).localeCompare(sortKey(a.name)));
|
|
6822
|
+
let kept = 0;
|
|
6823
|
+
let cut = archives.length;
|
|
6824
|
+
for (let i = 0; i < archives.length; i++) {
|
|
6825
|
+
if (i === 0 || kept + archives[i].size <= ARCHIVE_RETENTION_BYTES) {
|
|
6826
|
+
kept += archives[i].size;
|
|
6827
|
+
} else {
|
|
6828
|
+
cut = i;
|
|
6829
|
+
break;
|
|
6830
|
+
}
|
|
6831
|
+
}
|
|
6832
|
+
let removed = 0;
|
|
6833
|
+
let freed = 0;
|
|
6834
|
+
for (let i = cut; i < archives.length; i++) {
|
|
6835
|
+
try {
|
|
6836
|
+
fs20.unlinkSync(path9.join(ARCHIVE_DIR, archives[i].name));
|
|
6837
|
+
freed += archives[i].size;
|
|
6838
|
+
removed++;
|
|
6839
|
+
} catch {
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6842
|
+
if (removed > 0) {
|
|
6843
|
+
log9.info("Session archives pruned", {
|
|
6844
|
+
removed,
|
|
6845
|
+
freedBytes: freed,
|
|
6846
|
+
keptBytes: kept
|
|
6847
|
+
});
|
|
6848
|
+
}
|
|
6849
|
+
} catch {
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6809
6852
|
function rotate(state) {
|
|
6810
6853
|
const messages = state.messages;
|
|
6811
6854
|
if (messages.length === 0) {
|
|
@@ -6865,7 +6908,7 @@ function clearSession(state) {
|
|
|
6865
6908
|
});
|
|
6866
6909
|
}
|
|
6867
6910
|
}
|
|
6868
|
-
var log9, SESSION_FILE, ARCHIVE_DIR, ROTATE_THRESHOLD_BYTES, RETAIN_TAIL_BYTES;
|
|
6911
|
+
var log9, SESSION_FILE, ARCHIVE_DIR, ROTATE_THRESHOLD_BYTES, RETAIN_TAIL_BYTES, ARCHIVE_RETENTION_BYTES;
|
|
6869
6912
|
var init_session = __esm({
|
|
6870
6913
|
"src/session.ts"() {
|
|
6871
6914
|
"use strict";
|
|
@@ -6878,6 +6921,7 @@ var init_session = __esm({
|
|
|
6878
6921
|
ARCHIVE_DIR = ".logs/sessions";
|
|
6879
6922
|
ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
|
|
6880
6923
|
RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
|
|
6924
|
+
ARCHIVE_RETENTION_BYTES = 64 * 1024 * 1024;
|
|
6881
6925
|
}
|
|
6882
6926
|
});
|
|
6883
6927
|
|
|
@@ -357,15 +357,24 @@ A verified custom domain (and the app's `madewithremy.com` subdomain) also **sen
|
|
|
357
357
|
|
|
358
358
|
```ts
|
|
359
359
|
{
|
|
360
|
-
to: string;
|
|
361
|
-
from: string;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
360
|
+
to: string; // full recipient address; localpart is arbitrary on catchall tiers
|
|
361
|
+
from: string; // bare sender address, extracted from "Name <a@b>" form
|
|
362
|
+
fromName: string | null; // sender display name, or null
|
|
363
|
+
subject: string; // 'No Subject' if missing
|
|
364
|
+
message: string; // plain-text body, falls back to HTML if text is missing; 'No Body' if neither was sent
|
|
365
|
+
html: string; // HTML body, or '' when text-only
|
|
366
|
+
attachments: string[]; // CDN URLs — already uploaded by the platform
|
|
367
|
+
messageId: string | null; // this email's Message-ID, angle-bracketed (<id@host>)
|
|
368
|
+
inReplyTo: string | null; // Message-ID this email is replying to, if any
|
|
369
|
+
references: string[]; // prior Message-IDs in the thread (angle-bracketed); [] if none
|
|
370
|
+
replyTo: string | null; // Reply-To address — reply here, not `from`, when set
|
|
371
|
+
cc: string[]; // Cc recipient addresses
|
|
372
|
+
date: string | null; // original send time, ISO-8601
|
|
366
373
|
}
|
|
367
374
|
```
|
|
368
375
|
|
|
376
|
+
To reply in-thread, feed these into `sendEmail`: set `inReplyTo` to the incoming `messageId` and `references` to `[...references, messageId]`. Send to `replyTo` when it's set, otherwise `from`. `sendEmail` returns `{ recipients, cc, bcc, from }` (who it sent to + the sender used); it does not return the sent message's own `Message-ID`, so thread off *inbound* mail, not off messages you sent.
|
|
377
|
+
|
|
369
378
|
### Attachments and size limits
|
|
370
379
|
|
|
371
380
|
`attachments[]` is an array of CDN URLs — the platform has already received and uploaded the files. Fetch them server-side via the URL when you need the bytes; pass them through as URLs to UI or downstream services.
|
|
@@ -80,11 +80,21 @@ const { imageUrl } = await mindstudio.generateImage({
|
|
|
80
80
|
prompt: 'A professional headshot placeholder',
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
// Send email
|
|
83
|
+
// Send email — own-brand sender auto-selected (custom domain / subdomain / Remy default)
|
|
84
84
|
await mindstudio.sendEmail({
|
|
85
85
|
to: 'user@example.com',
|
|
86
86
|
subject: 'Your invoice',
|
|
87
|
-
body: content,
|
|
87
|
+
body: content, // markdown or HTML, auto-detected; bodyType overrides. cc/bcc/replyTo/attachments also supported
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Reply in-thread to an inbound email (fields come from the email interface's input)
|
|
91
|
+
await mindstudio.sendEmail({
|
|
92
|
+
to: input.replyTo ?? input.from,
|
|
93
|
+
subject: `Re: ${input.subject}`,
|
|
94
|
+
body: reply,
|
|
95
|
+
inReplyTo: input.messageId ?? undefined,
|
|
96
|
+
references: input.messageId ? [...input.references, input.messageId] : input.references,
|
|
97
|
+
cc: input.cc, // reply-all
|
|
88
98
|
});
|
|
89
99
|
|
|
90
100
|
// Upload files
|
|
@@ -61,7 +61,7 @@ result.$billingCost; // cost in credits (if applicable)
|
|
|
61
61
|
|
|
62
62
|
| Action | What it does | Key input | Key output |
|
|
63
63
|
|--------|-------------|-----------|------------|
|
|
64
|
-
| `sendEmail` | Send an email | `to`, `subject`, `body` | `
|
|
64
|
+
| `sendEmail` | Send an email (own-brand sender auto-selected) | `to`, `subject`, `body`, `cc?`, `bcc?`, `from?`, `replyTo?`, `inReplyTo?`, `references?`, `bodyType?`, `attachments?` | `recipients`, `cc`, `bcc`, `from` |
|
|
65
65
|
| `sendSMS` | Send a text message | `to`, `message` | `messageId` |
|
|
66
66
|
| `postToSlackChannel` | Post to Slack | `channel`, `message` | — |
|
|
67
67
|
|