@oratis/lisa 0.11.1 → 0.14.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/dist/agent.d.ts +2 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +20 -1
- package/dist/agent.js.map +1 -1
- package/dist/agents/pty.d.ts.map +1 -1
- package/dist/agents/pty.js +13 -2
- package/dist/agents/pty.js.map +1 -1
- package/dist/autonomy/state.d.ts +14 -0
- package/dist/autonomy/state.d.ts.map +1 -0
- package/dist/autonomy/state.js +54 -0
- package/dist/autonomy/state.js.map +1 -0
- package/dist/cli/mail.d.ts +2 -0
- package/dist/cli/mail.d.ts.map +1 -0
- package/dist/cli/mail.js +209 -0
- package/dist/cli/mail.js.map +1 -0
- package/dist/cli/pair.d.ts +15 -0
- package/dist/cli/pair.d.ts.map +1 -0
- package/dist/cli/pair.js +152 -0
- package/dist/cli/pair.js.map +1 -0
- package/dist/cli.js +22 -14
- package/dist/cli.js.map +1 -1
- package/dist/consent/store.d.ts +2 -2
- package/dist/consent/store.d.ts.map +1 -1
- package/dist/consent/store.js +3 -2
- package/dist/consent/store.js.map +1 -1
- package/dist/edition.d.ts +24 -0
- package/dist/edition.d.ts.map +1 -0
- package/dist/edition.js +19 -0
- package/dist/edition.js.map +1 -0
- package/dist/heartbeat/runner.d.ts.map +1 -1
- package/dist/heartbeat/runner.js +8 -0
- package/dist/heartbeat/runner.js.map +1 -1
- package/dist/idle/runner.d.ts.map +1 -1
- package/dist/idle/runner.js +7 -0
- package/dist/idle/runner.js.map +1 -1
- package/dist/mail/accounts.d.ts +20 -0
- package/dist/mail/accounts.d.ts.map +1 -0
- package/dist/mail/accounts.js +113 -0
- package/dist/mail/accounts.js.map +1 -0
- package/dist/mail/alerts.d.ts +29 -0
- package/dist/mail/alerts.d.ts.map +1 -0
- package/dist/mail/alerts.js +40 -0
- package/dist/mail/alerts.js.map +1 -0
- package/dist/mail/classify.d.ts +26 -0
- package/dist/mail/classify.d.ts.map +1 -0
- package/dist/mail/classify.js +191 -0
- package/dist/mail/classify.js.map +1 -0
- package/dist/mail/connectors/gmail.d.ts +55 -0
- package/dist/mail/connectors/gmail.d.ts.map +1 -0
- package/dist/mail/connectors/gmail.js +87 -0
- package/dist/mail/connectors/gmail.js.map +1 -0
- package/dist/mail/connectors/imap.d.ts +13 -0
- package/dist/mail/connectors/imap.d.ts.map +1 -0
- package/dist/mail/connectors/imap.js +136 -0
- package/dist/mail/connectors/imap.js.map +1 -0
- package/dist/mail/digest.d.ts +21 -0
- package/dist/mail/digest.d.ts.map +1 -0
- package/dist/mail/digest.js +89 -0
- package/dist/mail/digest.js.map +1 -0
- package/dist/mail/google-oauth.d.ts +50 -0
- package/dist/mail/google-oauth.d.ts.map +1 -0
- package/dist/mail/google-oauth.js +74 -0
- package/dist/mail/google-oauth.js.map +1 -0
- package/dist/mail/hosts.d.ts +3 -0
- package/dist/mail/hosts.d.ts.map +1 -0
- package/dist/mail/hosts.js +19 -0
- package/dist/mail/hosts.js.map +1 -0
- package/dist/mail/scheduler.d.ts +9 -0
- package/dist/mail/scheduler.d.ts.map +1 -0
- package/dist/mail/scheduler.js +21 -0
- package/dist/mail/scheduler.js.map +1 -0
- package/dist/mail/service.d.ts +32 -0
- package/dist/mail/service.d.ts.map +1 -0
- package/dist/mail/service.js +129 -0
- package/dist/mail/service.js.map +1 -0
- package/dist/mail/store.d.ts +7 -0
- package/dist/mail/store.d.ts.map +1 -0
- package/dist/mail/store.js +58 -0
- package/dist/mail/store.js.map +1 -0
- package/dist/mail/types.d.ts +114 -0
- package/dist/mail/types.d.ts.map +1 -0
- package/dist/mail/types.js +26 -0
- package/dist/mail/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +43 -21
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +67 -64
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +77 -71
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/registry.d.ts +10 -0
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +26 -0
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/stream-retry.d.ts +37 -0
- package/dist/providers/stream-retry.d.ts.map +1 -0
- package/dist/providers/stream-retry.js +92 -0
- package/dist/providers/stream-retry.js.map +1 -0
- package/dist/providers/types.d.ts +3 -0
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/subagent.d.ts +2 -0
- package/dist/subagent.d.ts.map +1 -1
- package/dist/subagent.js +1 -0
- package/dist/subagent.js.map +1 -1
- package/dist/web/cloudAuth.d.ts +57 -0
- package/dist/web/cloudAuth.d.ts.map +1 -0
- package/dist/web/cloudAuth.js +139 -0
- package/dist/web/cloudAuth.js.map +1 -0
- package/dist/web/island.d.ts.map +1 -1
- package/dist/web/island.js +1 -0
- package/dist/web/island.js.map +1 -1
- package/dist/web/lisa-client.d.ts +1 -1
- package/dist/web/lisa-client.d.ts.map +1 -1
- package/dist/web/lisa-client.js +703 -40
- package/dist/web/lisa-client.js.map +1 -1
- package/dist/web/lisa-css.d.ts +1 -1
- package/dist/web/lisa-css.d.ts.map +1 -1
- package/dist/web/lisa-css.js +568 -43
- package/dist/web/lisa-css.js.map +1 -1
- package/dist/web/lisa-html.d.ts +1 -1
- package/dist/web/lisa-html.d.ts.map +1 -1
- package/dist/web/lisa-html.js +71 -21
- package/dist/web/lisa-html.js.map +1 -1
- package/dist/web/pairing.d.ts +37 -0
- package/dist/web/pairing.d.ts.map +1 -0
- package/dist/web/pairing.js +79 -0
- package/dist/web/pairing.js.map +1 -0
- package/dist/web/push.d.ts +91 -0
- package/dist/web/push.d.ts.map +1 -1
- package/dist/web/push.js +250 -9
- package/dist/web/push.js.map +1 -1
- package/dist/web/qr-svg.d.ts +11 -0
- package/dist/web/qr-svg.d.ts.map +1 -0
- package/dist/web/qr-svg.js +41 -0
- package/dist/web/qr-svg.js.map +1 -0
- package/dist/web/server.d.ts +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +378 -14
- package/dist/web/server.js.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail sweep service — the once-a-day (or on-demand) pipeline:
|
|
3
|
+
* consent gate → per account: connect → list (metadata+snippet) → classify →
|
|
4
|
+
* dedup vs seen → build digest → persist.
|
|
5
|
+
*
|
|
6
|
+
* Connector + classify provider are injectable so the whole pipeline is
|
|
7
|
+
* unit-testable without a real mailbox or a live model.
|
|
8
|
+
*/
|
|
9
|
+
import { isGranted } from "../consent/store.js";
|
|
10
|
+
import { loadAccounts, getSecret, markSwept, setSecret } from "./accounts.js";
|
|
11
|
+
import { classifyMail } from "./classify.js";
|
|
12
|
+
import { buildDigest } from "./digest.js";
|
|
13
|
+
import { saveDigest, loadSeen, markSeen } from "./store.js";
|
|
14
|
+
import { ImapConnector } from "./connectors/imap.js";
|
|
15
|
+
import { GmailConnector } from "./connectors/gmail.js";
|
|
16
|
+
function defaultConnector(account, secret) {
|
|
17
|
+
if (account.provider === "imap")
|
|
18
|
+
return new ImapConnector(account, secret);
|
|
19
|
+
if (account.provider === "gmail") {
|
|
20
|
+
// Persist refreshed access tokens back to the 0600 secrets file.
|
|
21
|
+
return new GmailConnector(account, secret, { onTokenRefresh: (t) => setSecret(account.id, t) });
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`unknown mail provider: ${account.provider}`);
|
|
24
|
+
}
|
|
25
|
+
/** Local YYYY-MM-DD for a timestamp. */
|
|
26
|
+
export function localDate(ms) {
|
|
27
|
+
const d = new Date(ms);
|
|
28
|
+
return new Date(d.getTime() - d.getTimezoneOffset() * 60000).toISOString().slice(0, 10);
|
|
29
|
+
}
|
|
30
|
+
export async function sweepAll(opts = {}) {
|
|
31
|
+
const now = opts.now ?? Date.now;
|
|
32
|
+
const sinceMs = opts.sinceMs ?? now() - 24 * 60 * 60 * 1000;
|
|
33
|
+
const limit = opts.limit ?? 200;
|
|
34
|
+
const factory = opts.connectorFactory ?? defaultConnector;
|
|
35
|
+
if (!isGranted("mail")) {
|
|
36
|
+
return {
|
|
37
|
+
items: [],
|
|
38
|
+
digest: buildDigest([], { date: localDate(now()), accountIds: [], now }),
|
|
39
|
+
newItems: [],
|
|
40
|
+
blocked: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const accounts = loadAccounts().filter((a) => a.enabled);
|
|
44
|
+
const allItems = [];
|
|
45
|
+
const allNew = [];
|
|
46
|
+
let unread = 0;
|
|
47
|
+
for (const account of accounts) {
|
|
48
|
+
const secret = getSecret(account.id);
|
|
49
|
+
if (!secret)
|
|
50
|
+
continue;
|
|
51
|
+
let connector = null;
|
|
52
|
+
try {
|
|
53
|
+
connector = factory(account, secret);
|
|
54
|
+
const raws = (await connector.listSince({ sinceMs, limit })).map((r) => ({ ...r, accountId: account.id }));
|
|
55
|
+
if (raws.length === 0) {
|
|
56
|
+
markSwept(account.id, now());
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const seen = loadSeen(account.id);
|
|
60
|
+
const freshUids = new Set(raws.filter((r) => !seen.has(r.uid)).map((r) => r.uid));
|
|
61
|
+
unread += raws.filter((r) => !(r.flags ?? []).includes("\\Seen")).length;
|
|
62
|
+
const items = await classifyMail(raws, {
|
|
63
|
+
provider: opts.provider,
|
|
64
|
+
model: opts.model,
|
|
65
|
+
now,
|
|
66
|
+
signal: opts.signal,
|
|
67
|
+
});
|
|
68
|
+
allItems.push(...items);
|
|
69
|
+
allNew.push(...items.filter((i) => freshUids.has(i.uid)));
|
|
70
|
+
markSeen(account.id, raws.map((r) => r.uid));
|
|
71
|
+
markSwept(account.id, now());
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// one bad account (auth error, network) must not sink the whole sweep
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
if (connector)
|
|
78
|
+
await connector.close().catch(() => { });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const digest = buildDigest(allItems, {
|
|
82
|
+
date: localDate(now()),
|
|
83
|
+
accountIds: accounts.map((a) => a.id),
|
|
84
|
+
unread,
|
|
85
|
+
now,
|
|
86
|
+
});
|
|
87
|
+
saveDigest(digest);
|
|
88
|
+
return { items: allItems, digest, newItems: allNew };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Lightweight intraday poll: fetch, classify ONLY the unseen messages, mark seen.
|
|
92
|
+
* Returns just the freshly-classified items (for important-mail alerts). Does NOT
|
|
93
|
+
* rebuild/save the digest — that stays a daily artifact (or a manual sweep).
|
|
94
|
+
*/
|
|
95
|
+
export async function pollNewMail(opts = {}) {
|
|
96
|
+
const now = opts.now ?? Date.now;
|
|
97
|
+
const sinceMs = opts.sinceMs ?? now() - 24 * 60 * 60 * 1000;
|
|
98
|
+
const limit = opts.limit ?? 200;
|
|
99
|
+
const factory = opts.connectorFactory ?? defaultConnector;
|
|
100
|
+
if (!isGranted("mail"))
|
|
101
|
+
return [];
|
|
102
|
+
const out = [];
|
|
103
|
+
for (const account of loadAccounts().filter((a) => a.enabled)) {
|
|
104
|
+
const secret = getSecret(account.id);
|
|
105
|
+
if (!secret)
|
|
106
|
+
continue;
|
|
107
|
+
let connector = null;
|
|
108
|
+
try {
|
|
109
|
+
connector = factory(account, secret);
|
|
110
|
+
const raws = (await connector.listSince({ sinceMs, limit })).map((r) => ({ ...r, accountId: account.id }));
|
|
111
|
+
const seen = loadSeen(account.id);
|
|
112
|
+
const fresh = raws.filter((r) => !seen.has(r.uid));
|
|
113
|
+
if (fresh.length) {
|
|
114
|
+
out.push(...(await classifyMail(fresh, { provider: opts.provider, model: opts.model, now, signal: opts.signal })));
|
|
115
|
+
}
|
|
116
|
+
markSeen(account.id, raws.map((r) => r.uid));
|
|
117
|
+
markSwept(account.id, now());
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// skip a failing account
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
if (connector)
|
|
124
|
+
await connector.close().catch(() => { });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/mail/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DailyDigest } from "./types.js";
|
|
2
|
+
export declare function saveDigest(d: DailyDigest): void;
|
|
3
|
+
export declare function latestDigest(): DailyDigest | null;
|
|
4
|
+
export declare function loadSeen(accountId: string): Set<string>;
|
|
5
|
+
/** Record uids as seen; keeps the most recent SEEN_CAP. */
|
|
6
|
+
export declare function markSeen(accountId: string, uids: string[]): void;
|
|
7
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/mail/store.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAc9C,wBAAgB,UAAU,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,CAK/C;AAED,wBAAgB,YAAY,IAAI,WAAW,GAAG,IAAI,CAMjD;AAUD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAOvD;AAED,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAQhE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail persistence: the latest/dated digests + per-account seen-UID tracking
|
|
3
|
+
* (for incremental sweeps and alert dedup). All under ~/.lisa/mail/, mode 0600.
|
|
4
|
+
*/
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
function lisaHome() {
|
|
9
|
+
return process.env.LISA_HOME ?? path.join(os.homedir(), ".lisa");
|
|
10
|
+
}
|
|
11
|
+
function mailDir() {
|
|
12
|
+
return path.join(lisaHome(), "mail");
|
|
13
|
+
}
|
|
14
|
+
function ensure(dir) {
|
|
15
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
// ── digests ──
|
|
18
|
+
export function saveDigest(d) {
|
|
19
|
+
const dir = path.join(mailDir(), "digests");
|
|
20
|
+
ensure(dir);
|
|
21
|
+
fs.writeFileSync(path.join(dir, `${d.date}.json`), JSON.stringify(d, null, 2), { mode: 0o600 });
|
|
22
|
+
fs.writeFileSync(path.join(mailDir(), "latest-digest.json"), JSON.stringify(d, null, 2), { mode: 0o600 });
|
|
23
|
+
}
|
|
24
|
+
export function latestDigest() {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(fs.readFileSync(path.join(mailDir(), "latest-digest.json"), "utf8"));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// ── seen UIDs (dedup) ──
|
|
33
|
+
const SEEN_CAP = 5000;
|
|
34
|
+
function seenPath(accountId) {
|
|
35
|
+
return path.join(mailDir(), "seen", `${accountId}.json`);
|
|
36
|
+
}
|
|
37
|
+
export function loadSeen(accountId) {
|
|
38
|
+
try {
|
|
39
|
+
const arr = JSON.parse(fs.readFileSync(seenPath(accountId), "utf8"));
|
|
40
|
+
return new Set(Array.isArray(arr) ? arr : []);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return new Set();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Record uids as seen; keeps the most recent SEEN_CAP. */
|
|
47
|
+
export function markSeen(accountId, uids) {
|
|
48
|
+
if (uids.length === 0)
|
|
49
|
+
return;
|
|
50
|
+
const dir = path.join(mailDir(), "seen");
|
|
51
|
+
ensure(dir);
|
|
52
|
+
const existing = loadSeen(accountId);
|
|
53
|
+
for (const u of uids)
|
|
54
|
+
existing.add(u);
|
|
55
|
+
const trimmed = [...existing].slice(-SEEN_CAP);
|
|
56
|
+
fs.writeFileSync(seenPath(accountId), JSON.stringify(trimmed), { mode: 0o600 });
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/mail/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail module — shared types.
|
|
3
|
+
*
|
|
4
|
+
* v1 is READ-ONLY: connect mailboxes, read, classify, grade, digest, alert. No
|
|
5
|
+
* send / archive / delete.
|
|
6
|
+
*
|
|
7
|
+
* PRIVACY: classification runs on METADATA + a BOUNDED SNIPPET only — never full
|
|
8
|
+
* bodies. Full bodies are not persisted and not sent to the model. Secrets
|
|
9
|
+
* (IMAP password / OAuth refresh token) live in a separate 0600 file, never in
|
|
10
|
+
* the accounts list. Everything is gated on the `mail` consent signal.
|
|
11
|
+
*/
|
|
12
|
+
export type MailProvider = "imap" | "gmail";
|
|
13
|
+
/** A connected mailbox. NO secrets here (see MailSecret + the 0600 secrets file). */
|
|
14
|
+
export interface MailAccount {
|
|
15
|
+
/** Stable slug, e.g. "qq-3f9a1c". */
|
|
16
|
+
id: string;
|
|
17
|
+
provider: MailProvider;
|
|
18
|
+
/** The address, e.g. "me@qq.com". */
|
|
19
|
+
email: string;
|
|
20
|
+
/** User-facing label; defaults to the address. */
|
|
21
|
+
label?: string;
|
|
22
|
+
/** IMAP host (imap provider only), e.g. "imap.qq.com". */
|
|
23
|
+
host?: string;
|
|
24
|
+
/** IMAP port; default 993 (implicit TLS). */
|
|
25
|
+
port?: number;
|
|
26
|
+
addedAt: number;
|
|
27
|
+
lastSweepAt?: number;
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Per-account secret, stored only in ~/.lisa/mail/secrets.json (mode 0600). */
|
|
31
|
+
export interface MailSecret {
|
|
32
|
+
/** IMAP app-password / authorization code. */
|
|
33
|
+
password?: string;
|
|
34
|
+
/** OAuth (gmail). */
|
|
35
|
+
refreshToken?: string;
|
|
36
|
+
accessToken?: string;
|
|
37
|
+
/** Access-token expiry, epoch ms. */
|
|
38
|
+
expiry?: number;
|
|
39
|
+
clientId?: string;
|
|
40
|
+
clientSecret?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Raw, minimally-fetched message: METADATA + a bounded snippet. Never the full
|
|
44
|
+
* body. This is the most that ever leaves the mailbox into LISA.
|
|
45
|
+
*/
|
|
46
|
+
export interface RawMail {
|
|
47
|
+
/** Account-scoped UID (stable per mailbox). */
|
|
48
|
+
uid: string;
|
|
49
|
+
accountId: string;
|
|
50
|
+
/** Display form, e.g. "Jane Doe <jane@x.com>". */
|
|
51
|
+
from: string;
|
|
52
|
+
fromAddress: string;
|
|
53
|
+
to?: string;
|
|
54
|
+
subject: string;
|
|
55
|
+
/** Epoch ms. */
|
|
56
|
+
date: number;
|
|
57
|
+
/** First ~N chars of the text body, bounded + whitespace-collapsed. */
|
|
58
|
+
snippet: string;
|
|
59
|
+
/** IMAP flags, e.g. ["\\Seen"]. */
|
|
60
|
+
flags?: string[];
|
|
61
|
+
mailbox: string;
|
|
62
|
+
}
|
|
63
|
+
export type MailCategory = "urgent" | "personal" | "work" | "finance" | "calendar" | "security" | "newsletter" | "promotion" | "social" | "notification" | "spam" | "other";
|
|
64
|
+
export declare const MAIL_CATEGORIES: MailCategory[];
|
|
65
|
+
/** 0 ignore · 1 fyi · 2 should-read · 3 needs-you-now. */
|
|
66
|
+
export type MailImportance = 0 | 1 | 2 | 3;
|
|
67
|
+
/** A classified message — the unit the digest + alerts operate on. */
|
|
68
|
+
export interface MailItem {
|
|
69
|
+
uid: string;
|
|
70
|
+
accountId: string;
|
|
71
|
+
from: string;
|
|
72
|
+
fromAddress: string;
|
|
73
|
+
subject: string;
|
|
74
|
+
date: number;
|
|
75
|
+
snippet: string;
|
|
76
|
+
category: MailCategory;
|
|
77
|
+
importance: MailImportance;
|
|
78
|
+
/** One-line model-written reason / summary. */
|
|
79
|
+
reason: string;
|
|
80
|
+
/** Heuristic signals that informed the grade (transparency). */
|
|
81
|
+
signals: string[];
|
|
82
|
+
classifiedAt: number;
|
|
83
|
+
}
|
|
84
|
+
export interface DigestBucket {
|
|
85
|
+
category: MailCategory;
|
|
86
|
+
count: number;
|
|
87
|
+
/** A few representative items (capped). */
|
|
88
|
+
items: MailItem[];
|
|
89
|
+
}
|
|
90
|
+
export interface DailyDigest {
|
|
91
|
+
/** Local YYYY-MM-DD the digest covers. */
|
|
92
|
+
date: string;
|
|
93
|
+
generatedAt: number;
|
|
94
|
+
accountIds: string[];
|
|
95
|
+
total: number;
|
|
96
|
+
unread: number;
|
|
97
|
+
/** importance >= 2, newest first. */
|
|
98
|
+
needsYou: MailItem[];
|
|
99
|
+
buckets: DigestBucket[];
|
|
100
|
+
/** Short narrative (templated, or model-written by the service). */
|
|
101
|
+
summary: string;
|
|
102
|
+
}
|
|
103
|
+
/** Fetches raw mail for one account. Injectable so the service is unit-testable. */
|
|
104
|
+
export interface MailConnector {
|
|
105
|
+
/** Messages received since `sinceMs` (capped at `limit`), metadata + snippet
|
|
106
|
+
* only, newest first. */
|
|
107
|
+
listSince(opts: {
|
|
108
|
+
sinceMs: number;
|
|
109
|
+
limit: number;
|
|
110
|
+
}): Promise<RawMail[]>;
|
|
111
|
+
/** Close any open connection. Idempotent. */
|
|
112
|
+
close(): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mail/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail module — shared types.
|
|
3
|
+
*
|
|
4
|
+
* v1 is READ-ONLY: connect mailboxes, read, classify, grade, digest, alert. No
|
|
5
|
+
* send / archive / delete.
|
|
6
|
+
*
|
|
7
|
+
* PRIVACY: classification runs on METADATA + a BOUNDED SNIPPET only — never full
|
|
8
|
+
* bodies. Full bodies are not persisted and not sent to the model. Secrets
|
|
9
|
+
* (IMAP password / OAuth refresh token) live in a separate 0600 file, never in
|
|
10
|
+
* the accounts list. Everything is gated on the `mail` consent signal.
|
|
11
|
+
*/
|
|
12
|
+
export const MAIL_CATEGORIES = [
|
|
13
|
+
"urgent",
|
|
14
|
+
"personal",
|
|
15
|
+
"work",
|
|
16
|
+
"finance",
|
|
17
|
+
"calendar",
|
|
18
|
+
"security",
|
|
19
|
+
"newsletter",
|
|
20
|
+
"promotion",
|
|
21
|
+
"social",
|
|
22
|
+
"notification",
|
|
23
|
+
"spam",
|
|
24
|
+
"other",
|
|
25
|
+
];
|
|
26
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mail/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAuEH,MAAM,CAAC,MAAM,eAAe,GAAmB;IAC7C,QAAQ;IACR,UAAU;IACV,MAAM;IACN,SAAS;IACT,UAAU;IACV,UAAU;IACV,YAAY;IACZ,WAAW;IACX,QAAQ;IACR,cAAc;IACd,MAAM;IACN,OAAO;CACR,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAQpB,qBAAa,iBAAkB,YAAW,QAAQ;IAChD,QAAQ,CAAC,IAAI,eAAe;IAC5B,OAAO,CAAC,MAAM,CAAY;gBAEd,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAmB1E,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CA+F9D"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { proxyAwareFetch } from "../proxy-bootstrap.js";
|
|
3
|
+
import { withStreamRetry } from "./stream-retry.js";
|
|
3
4
|
export class AnthropicProvider {
|
|
4
5
|
name = "anthropic";
|
|
5
6
|
client;
|
|
@@ -28,11 +29,20 @@ export class AnthropicProvider {
|
|
|
28
29
|
description: t.description,
|
|
29
30
|
input_schema: t.inputSchema,
|
|
30
31
|
}));
|
|
32
|
+
// Cache the large, stable system prefix (soul + skills + memory) for 1h so it
|
|
33
|
+
// stays warm across normal think-time gaps in a bursty personal session,
|
|
34
|
+
// instead of paying a cold re-write every time the 5-min default expires. The
|
|
35
|
+
// conversational tail (withCacheBreakpoint) stays at the cheaper 5-min default.
|
|
36
|
+
// Heavy-continuous users can opt back to 5-min writes via LISA_CACHE_TTL=5m.
|
|
37
|
+
// GA on Sonnet 4.6 / Opus 4.x — see docs/PLAN_MODEL_TUNING_v1.0.md.
|
|
38
|
+
const systemCache = process.env.LISA_CACHE_TTL === "5m"
|
|
39
|
+
? { type: "ephemeral" }
|
|
40
|
+
: { type: "ephemeral", ttl: "1h" };
|
|
31
41
|
const params = {
|
|
32
42
|
model: opts.model,
|
|
33
43
|
max_tokens: opts.maxTokens ?? 16_000,
|
|
34
44
|
system: [
|
|
35
|
-
{ type: "text", text: opts.systemPrompt, cache_control:
|
|
45
|
+
{ type: "text", text: opts.systemPrompt, cache_control: systemCache },
|
|
36
46
|
],
|
|
37
47
|
tools,
|
|
38
48
|
messages,
|
|
@@ -41,6 +51,15 @@ export class AnthropicProvider {
|
|
|
41
51
|
if (opts.thinking) {
|
|
42
52
|
params.thinking = { type: "adaptive" };
|
|
43
53
|
}
|
|
54
|
+
// Optional thinking-depth / token-spend lever (GA on Sonnet 4.6). Omitted ⇒
|
|
55
|
+
// the API default of "high". Dispatched subagents pass "low" for cheap
|
|
56
|
+
// parallel work; a global LISA_EFFORT can override for power users.
|
|
57
|
+
if (opts.effort) {
|
|
58
|
+
params.output_config = {
|
|
59
|
+
...params.output_config,
|
|
60
|
+
effort: opts.effort,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
44
63
|
const extras = {};
|
|
45
64
|
if (opts.compaction) {
|
|
46
65
|
extras.betas = ["compact-2026-01-12"];
|
|
@@ -51,26 +70,29 @@ export class AnthropicProvider {
|
|
|
51
70
|
// Second argument is the SDK's per-request options; `signal` aborts the
|
|
52
71
|
// in-flight HTTP stream (the SDK then throws APIUserAbortError).
|
|
53
72
|
const requestOpts = { signal: opts.signal };
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
stream
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
// Retry transient empty-stream failures ("request ended without sending any
|
|
74
|
+
// chunks" and proxy-induced connection drops). The SDK's request-level
|
|
75
|
+
// retries don't cover these — they're thrown while iterating a 200 stream —
|
|
76
|
+
// so without this a momentary proxy/network blip surfaces as a hard error.
|
|
77
|
+
// Safe because we only retry while no delta has been forwarded yet.
|
|
78
|
+
const message = await withStreamRetry({ signal: opts.signal }, async (markEmitted) => {
|
|
79
|
+
const stream = opts.compaction
|
|
80
|
+
? this.client.beta.messages.stream({ ...params, ...extras }, requestOpts)
|
|
81
|
+
: this.client.messages.stream(params, requestOpts);
|
|
82
|
+
if (opts.handlers?.onTextDelta) {
|
|
83
|
+
stream.on("text", (t) => {
|
|
84
|
+
markEmitted();
|
|
85
|
+
onText(t);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (opts.handlers?.onThinkingDelta) {
|
|
89
|
+
stream.on("thinking", (t) => {
|
|
90
|
+
markEmitted();
|
|
91
|
+
onThinking(t);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return (await stream.finalMessage());
|
|
95
|
+
});
|
|
74
96
|
return {
|
|
75
97
|
content: message.content,
|
|
76
98
|
stopReason: message.stop_reason ?? "end_turn",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE5E,qBAAa,cAAe,YAAW,QAAQ;IAC7C,QAAQ,CAAC,IAAI,YAAY;IAGzB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwC;gBAEvD,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;YAI9C,SAAS;IAgBjB,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CA4F9D"}
|