@elizaos/plugin-inbox 2.0.3-beta.6 → 2.0.3-beta.7
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/actions/inbox.d.ts +69 -0
- package/dist/actions/inbox.d.ts.map +1 -0
- package/dist/actions/inbox.js +345 -0
- package/dist/actions/inbox.js.map +1 -0
- package/dist/components/inbox/InboxSpatialView.d.ts +54 -0
- package/dist/components/inbox/InboxSpatialView.d.ts.map +1 -0
- package/dist/components/inbox/InboxSpatialView.js +171 -0
- package/dist/components/inbox/InboxSpatialView.js.map +1 -0
- package/dist/components/inbox/InboxView.d.ts +64 -0
- package/dist/components/inbox/InboxView.d.ts.map +1 -0
- package/dist/components/inbox/InboxView.js +169 -0
- package/dist/components/inbox/InboxView.js.map +1 -0
- package/dist/components/inbox/inbox-view-bundle.d.ts +2 -0
- package/dist/components/inbox/inbox-view-bundle.d.ts.map +1 -0
- package/dist/components/inbox/inbox-view-bundle.js +5 -0
- package/dist/components/inbox/inbox-view-bundle.js.map +1 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +3 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +1729 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +79 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sql.d.ts +32 -0
- package/dist/db/sql.d.ts.map +1 -0
- package/dist/db/sql.js +130 -0
- package/dist/db/sql.js.map +1 -0
- package/dist/inbox/channel-deep-links.d.ts +7 -0
- package/dist/inbox/channel-deep-links.d.ts.map +1 -0
- package/dist/inbox/channel-deep-links.js +97 -0
- package/dist/inbox/channel-deep-links.js.map +1 -0
- package/dist/inbox/config.d.ts +7 -0
- package/dist/inbox/config.d.ts.map +1 -0
- package/dist/inbox/config.js +61 -0
- package/dist/inbox/config.js.map +1 -0
- package/dist/inbox/email-curation.d.ts +174 -0
- package/dist/inbox/email-curation.d.ts.map +1 -0
- package/dist/inbox/email-curation.js +1056 -0
- package/dist/inbox/email-curation.js.map +1 -0
- package/dist/inbox/email-unsubscribe-types.d.ts +71 -0
- package/dist/inbox/email-unsubscribe-types.d.ts.map +1 -0
- package/dist/inbox/email-unsubscribe-types.js +1 -0
- package/dist/inbox/email-unsubscribe-types.js.map +1 -0
- package/dist/inbox/gmail-normalize.d.ts +99 -0
- package/dist/inbox/gmail-normalize.d.ts.map +1 -0
- package/dist/inbox/gmail-normalize.js +937 -0
- package/dist/inbox/gmail-normalize.js.map +1 -0
- package/dist/inbox/google-gmail-seam.d.ts +52 -0
- package/dist/inbox/google-gmail-seam.d.ts.map +1 -0
- package/dist/inbox/google-gmail-seam.js +263 -0
- package/dist/inbox/google-gmail-seam.js.map +1 -0
- package/dist/inbox/message-fetcher.d.ts +47 -0
- package/dist/inbox/message-fetcher.d.ts.map +1 -0
- package/dist/inbox/message-fetcher.js +461 -0
- package/dist/inbox/message-fetcher.js.map +1 -0
- package/dist/inbox/migration.d.ts +46 -0
- package/dist/inbox/migration.d.ts.map +1 -0
- package/dist/inbox/migration.js +114 -0
- package/dist/inbox/migration.js.map +1 -0
- package/dist/inbox/reflection.d.ts +40 -0
- package/dist/inbox/reflection.d.ts.map +1 -0
- package/dist/inbox/reflection.js +142 -0
- package/dist/inbox/reflection.js.map +1 -0
- package/dist/inbox/repository.d.ts +58 -0
- package/dist/inbox/repository.d.ts.map +1 -0
- package/dist/inbox/repository.js +376 -0
- package/dist/inbox/repository.js.map +1 -0
- package/dist/inbox/service.d.ts +149 -0
- package/dist/inbox/service.d.ts.map +1 -0
- package/dist/inbox/service.js +247 -0
- package/dist/inbox/service.js.map +1 -0
- package/dist/inbox/triage-classifier.d.ts +28 -0
- package/dist/inbox/triage-classifier.d.ts.map +1 -0
- package/dist/inbox/triage-classifier.js +306 -0
- package/dist/inbox/triage-classifier.js.map +1 -0
- package/dist/inbox/types.d.ts +124 -0
- package/dist/inbox/types.d.ts.map +1 -0
- package/dist/inbox/types.js +1 -0
- package/dist/inbox/types.js.map +1 -0
- package/dist/inbox/unsubscribe-repository.d.ts +14 -0
- package/dist/inbox/unsubscribe-repository.d.ts.map +1 -0
- package/dist/inbox/unsubscribe-repository.js +112 -0
- package/dist/inbox/unsubscribe-repository.js.map +1 -0
- package/dist/inbox/unsubscribe-service.d.ts +41 -0
- package/dist/inbox/unsubscribe-service.d.ts.map +1 -0
- package/dist/inbox/unsubscribe-service.js +351 -0
- package/dist/inbox/unsubscribe-service.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +38 -0
- package/dist/plugin.js.map +1 -0
- package/dist/providers/cross-channel-context.d.ts +21 -0
- package/dist/providers/cross-channel-context.d.ts.map +1 -0
- package/dist/providers/cross-channel-context.js +96 -0
- package/dist/providers/cross-channel-context.js.map +1 -0
- package/dist/providers/inbox-triage.d.ts +12 -0
- package/dist/providers/inbox-triage.d.ts.map +1 -0
- package/dist/providers/inbox-triage.js +98 -0
- package/dist/providers/inbox-triage.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +21 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +9 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +5 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/dist/views/bundle.js +315 -0
- package/dist/views/bundle.js.map +1 -0
- package/package.json +9 -9
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `INBOX` umbrella action — cross-channel inbox.
|
|
3
|
+
*
|
|
4
|
+
* The agent's `MESSAGE` umbrella triages per-channel inboxes; INBOX fans out to
|
|
5
|
+
* every connected platform (Gmail, Slack, Discord, Telegram, Signal, iMessage,
|
|
6
|
+
* WhatsApp) and produces a single merged feed for "show me my inbox" style
|
|
7
|
+
* intents.
|
|
8
|
+
*
|
|
9
|
+
* Subactions:
|
|
10
|
+
* - `list` — list recent messages across selected platforms
|
|
11
|
+
* - `search` — search across selected platforms by `query`
|
|
12
|
+
* - `summarize` — return a per-platform count + a single rolled-up summary
|
|
13
|
+
*
|
|
14
|
+
* Behavior: fan out to each platform's adapter via the injectable fetcher hook,
|
|
15
|
+
* dedupe by `id` and thread topic, merge into a single result list ordered by
|
|
16
|
+
* recency.
|
|
17
|
+
*
|
|
18
|
+
* Owner-only. Ported verbatim from the LifeOps INBOX action; the per-platform
|
|
19
|
+
* default fetchers read through the shared MESSAGE triage service, and tests
|
|
20
|
+
* inject deterministic fetchers via {@link setInboxFetchers}.
|
|
21
|
+
*/
|
|
22
|
+
import type { Action, IAgentRuntime } from "@elizaos/core";
|
|
23
|
+
declare const SUBACTIONS: readonly ["list", "search", "summarize"];
|
|
24
|
+
type Subaction = (typeof SUBACTIONS)[number];
|
|
25
|
+
declare const PLATFORMS: readonly ["gmail", "slack", "discord", "telegram", "signal", "imessage", "whatsapp"];
|
|
26
|
+
export type InboxPlatform = (typeof PLATFORMS)[number];
|
|
27
|
+
export interface InboxItem {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly platform: InboxPlatform;
|
|
30
|
+
readonly channel: string;
|
|
31
|
+
readonly senderName: string;
|
|
32
|
+
readonly snippet: string;
|
|
33
|
+
readonly receivedAt: string;
|
|
34
|
+
readonly threadTopic?: string;
|
|
35
|
+
readonly deepLink?: string;
|
|
36
|
+
readonly unread?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface InboxSummaryEntry {
|
|
39
|
+
readonly platform: InboxPlatform;
|
|
40
|
+
readonly count: number;
|
|
41
|
+
readonly latestAt: string | null;
|
|
42
|
+
}
|
|
43
|
+
export interface InboxResult {
|
|
44
|
+
readonly subaction: Subaction;
|
|
45
|
+
readonly platforms: readonly InboxPlatform[];
|
|
46
|
+
readonly items: readonly InboxItem[];
|
|
47
|
+
readonly summary?: readonly InboxSummaryEntry[];
|
|
48
|
+
readonly query?: string;
|
|
49
|
+
readonly since?: string;
|
|
50
|
+
readonly totalBeforeDedupe: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Per-platform fetcher hook. Defaults read through the shared MESSAGE triage
|
|
54
|
+
* service; tests can still inject deterministic scenario data.
|
|
55
|
+
*/
|
|
56
|
+
export type InboxFetcher = (args: {
|
|
57
|
+
runtime: IAgentRuntime;
|
|
58
|
+
since?: string;
|
|
59
|
+
limit: number;
|
|
60
|
+
query?: string;
|
|
61
|
+
}) => Promise<readonly InboxItem[]>;
|
|
62
|
+
export type InboxFetchers = Record<InboxPlatform, InboxFetcher>;
|
|
63
|
+
export declare function setInboxFetchers(next: Partial<InboxFetchers>): void;
|
|
64
|
+
export declare function __resetInboxFetchersForTests(): void;
|
|
65
|
+
export declare const inboxAction: Action & {
|
|
66
|
+
suppressPostActionContinuation?: boolean;
|
|
67
|
+
};
|
|
68
|
+
export default inboxAction;
|
|
69
|
+
//# sourceMappingURL=inbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/actions/inbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EACV,MAAM,EAKN,aAAa,EAId,MAAM,eAAe,CAAC;AAKvB,QAAA,MAAM,UAAU,0CAA2C,CAAC;AAE5D,KAAK,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAS7C,QAAA,MAAM,SAAS,sFAQL,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAYD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAChD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;AAEpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;AAmFhE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAEnE;AAED,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD;AAsJD,eAAO,MAAM,WAAW,EAAE,MAAM,GAAG;IACjC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAuK1C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { hasOwnerAccess } from "@elizaos/agent/security/access";
|
|
2
|
+
import { getDefaultTriageService, logger } from "@elizaos/core";
|
|
3
|
+
const ACTION_NAME = "INBOX";
|
|
4
|
+
const SUBACTIONS = ["list", "search", "summarize"];
|
|
5
|
+
const SIMILE_NAMES = [
|
|
6
|
+
"INBOX",
|
|
7
|
+
"CROSS_CHANNEL_INBOX",
|
|
8
|
+
"ALL_MESSAGES",
|
|
9
|
+
"INBOX_TRIAGE_PRIORITY"
|
|
10
|
+
];
|
|
11
|
+
const PLATFORMS = [
|
|
12
|
+
"gmail",
|
|
13
|
+
"slack",
|
|
14
|
+
"discord",
|
|
15
|
+
"telegram",
|
|
16
|
+
"signal",
|
|
17
|
+
"imessage",
|
|
18
|
+
"whatsapp"
|
|
19
|
+
];
|
|
20
|
+
const noopFetcher = async () => [];
|
|
21
|
+
const PLATFORM_TO_MESSAGE_SOURCE = {
|
|
22
|
+
gmail: "gmail",
|
|
23
|
+
discord: "discord",
|
|
24
|
+
telegram: "telegram",
|
|
25
|
+
signal: "signal",
|
|
26
|
+
imessage: "imessage",
|
|
27
|
+
whatsapp: "whatsapp"
|
|
28
|
+
};
|
|
29
|
+
function mapMessageRefToInboxItem(ref) {
|
|
30
|
+
const platform = normalizePlatform(ref.source);
|
|
31
|
+
if (!platform) return null;
|
|
32
|
+
return {
|
|
33
|
+
id: ref.id,
|
|
34
|
+
platform,
|
|
35
|
+
channel: ref.channelId ?? ref.worldId ?? "default",
|
|
36
|
+
senderName: ref.from.displayName ?? ref.from.identifier,
|
|
37
|
+
snippet: ref.snippet,
|
|
38
|
+
receivedAt: new Date(ref.receivedAtMs).toISOString(),
|
|
39
|
+
...ref.subject ? { threadTopic: ref.subject } : {},
|
|
40
|
+
...typeof ref.metadata?.htmlLink === "string" ? { deepLink: ref.metadata.htmlLink } : {},
|
|
41
|
+
unread: !ref.isRead
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function parseSinceMs(since) {
|
|
45
|
+
if (!since) return void 0;
|
|
46
|
+
const parsed = Date.parse(since);
|
|
47
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
48
|
+
}
|
|
49
|
+
function createDefaultPlatformFetcher(platform) {
|
|
50
|
+
const source = PLATFORM_TO_MESSAGE_SOURCE[platform];
|
|
51
|
+
if (!source) return noopFetcher;
|
|
52
|
+
return async ({ runtime, since, limit, query }) => {
|
|
53
|
+
if (typeof runtime.getService !== "function") return [];
|
|
54
|
+
try {
|
|
55
|
+
const service = getDefaultTriageService();
|
|
56
|
+
const refs = query ? await service.search(runtime, {
|
|
57
|
+
sources: [source],
|
|
58
|
+
content: query,
|
|
59
|
+
sinceMs: parseSinceMs(since),
|
|
60
|
+
limit
|
|
61
|
+
}) : await service.triage(runtime, {
|
|
62
|
+
sources: [source],
|
|
63
|
+
sinceMs: parseSinceMs(since),
|
|
64
|
+
limit
|
|
65
|
+
});
|
|
66
|
+
return refs.flatMap((ref) => {
|
|
67
|
+
const item = mapMessageRefToInboxItem(ref);
|
|
68
|
+
return item ? [item] : [];
|
|
69
|
+
});
|
|
70
|
+
} catch (error) {
|
|
71
|
+
logger.warn(
|
|
72
|
+
`[INBOX] ${platform} fetch failed: ${error instanceof Error ? error.message : String(error)}`
|
|
73
|
+
);
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const defaultFetchers = {
|
|
79
|
+
gmail: createDefaultPlatformFetcher("gmail"),
|
|
80
|
+
slack: noopFetcher,
|
|
81
|
+
discord: createDefaultPlatformFetcher("discord"),
|
|
82
|
+
telegram: createDefaultPlatformFetcher("telegram"),
|
|
83
|
+
signal: createDefaultPlatformFetcher("signal"),
|
|
84
|
+
imessage: createDefaultPlatformFetcher("imessage"),
|
|
85
|
+
whatsapp: createDefaultPlatformFetcher("whatsapp")
|
|
86
|
+
};
|
|
87
|
+
let activeFetchers = { ...defaultFetchers };
|
|
88
|
+
function setInboxFetchers(next) {
|
|
89
|
+
activeFetchers = { ...activeFetchers, ...next };
|
|
90
|
+
}
|
|
91
|
+
function __resetInboxFetchersForTests() {
|
|
92
|
+
activeFetchers = { ...defaultFetchers };
|
|
93
|
+
}
|
|
94
|
+
function getParams(options) {
|
|
95
|
+
const raw = options?.parameters;
|
|
96
|
+
if (raw && typeof raw === "object") {
|
|
97
|
+
return raw;
|
|
98
|
+
}
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
function normalizeSubaction(value) {
|
|
102
|
+
if (typeof value !== "string") return null;
|
|
103
|
+
const trimmed = value.trim();
|
|
104
|
+
if (trimmed.length === 0) return null;
|
|
105
|
+
const lower = trimmed.toLowerCase();
|
|
106
|
+
return SUBACTIONS.includes(lower) ? lower : null;
|
|
107
|
+
}
|
|
108
|
+
function resolveSubaction(params) {
|
|
109
|
+
return normalizeSubaction(params.subaction) ?? normalizeSubaction(params.action) ?? normalizeSubaction(params.op);
|
|
110
|
+
}
|
|
111
|
+
function normalizePlatform(value) {
|
|
112
|
+
if (typeof value !== "string") return null;
|
|
113
|
+
const lower = value.trim().toLowerCase();
|
|
114
|
+
return PLATFORMS.includes(lower) ? lower : null;
|
|
115
|
+
}
|
|
116
|
+
function resolvePlatforms(input) {
|
|
117
|
+
if (!input || input.length === 0) {
|
|
118
|
+
return [...PLATFORMS];
|
|
119
|
+
}
|
|
120
|
+
const seen = /* @__PURE__ */ new Set();
|
|
121
|
+
for (const raw of input) {
|
|
122
|
+
const normalized = normalizePlatform(raw);
|
|
123
|
+
if (normalized) seen.add(normalized);
|
|
124
|
+
}
|
|
125
|
+
return [...seen];
|
|
126
|
+
}
|
|
127
|
+
function dedupeKey(item) {
|
|
128
|
+
if (item.threadTopic && item.threadTopic.length > 0) {
|
|
129
|
+
return `topic:${item.threadTopic.toLowerCase()}::${item.platform}::${item.channel}`;
|
|
130
|
+
}
|
|
131
|
+
return `id:${item.platform}::${item.id}`;
|
|
132
|
+
}
|
|
133
|
+
function dedupeAndOrder(items) {
|
|
134
|
+
const seen = /* @__PURE__ */ new Map();
|
|
135
|
+
for (const item of items) {
|
|
136
|
+
const key = dedupeKey(item);
|
|
137
|
+
const existing = seen.get(key);
|
|
138
|
+
if (!existing) {
|
|
139
|
+
seen.set(key, item);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const a = Date.parse(item.receivedAt);
|
|
143
|
+
const b = Date.parse(existing.receivedAt);
|
|
144
|
+
if (Number.isNaN(a)) continue;
|
|
145
|
+
if (Number.isNaN(b) || a > b) {
|
|
146
|
+
seen.set(key, item);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return [...seen.values()].sort((a, b) => {
|
|
150
|
+
const aTime = Date.parse(a.receivedAt);
|
|
151
|
+
const bTime = Date.parse(b.receivedAt);
|
|
152
|
+
if (Number.isNaN(aTime) && Number.isNaN(bTime)) return 0;
|
|
153
|
+
if (Number.isNaN(aTime)) return 1;
|
|
154
|
+
if (Number.isNaN(bTime)) return -1;
|
|
155
|
+
return bTime - aTime;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function buildSummary(items, platforms) {
|
|
159
|
+
return platforms.map((platform) => {
|
|
160
|
+
const platformItems = items.filter((item) => item.platform === platform);
|
|
161
|
+
let latestAt = null;
|
|
162
|
+
for (const item of platformItems) {
|
|
163
|
+
if (!latestAt || Date.parse(item.receivedAt) > Date.parse(latestAt)) {
|
|
164
|
+
latestAt = item.receivedAt;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
platform,
|
|
169
|
+
count: platformItems.length,
|
|
170
|
+
latestAt
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
async function hasInboxAccess(runtime, message) {
|
|
175
|
+
if (!runtime || typeof runtime.agentId !== "string" || !message || typeof message.entityId !== "string" || message.entityId.length === 0) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
return hasOwnerAccess(runtime, message);
|
|
179
|
+
}
|
|
180
|
+
const examples = [
|
|
181
|
+
[
|
|
182
|
+
{ name: "{{name1}}", content: { text: "Show me my inbox." } },
|
|
183
|
+
{
|
|
184
|
+
name: "{{agentName}}",
|
|
185
|
+
content: {
|
|
186
|
+
text: "Pulled your inbox.",
|
|
187
|
+
action: ACTION_NAME
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
[
|
|
192
|
+
{
|
|
193
|
+
name: "{{name1}}",
|
|
194
|
+
content: { text: "Search every channel for messages about the launch." }
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "{{agentName}}",
|
|
198
|
+
content: {
|
|
199
|
+
text: "Searched every connected inbox.",
|
|
200
|
+
action: ACTION_NAME
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
];
|
|
205
|
+
const inboxAction = {
|
|
206
|
+
name: ACTION_NAME,
|
|
207
|
+
similes: SIMILE_NAMES.slice(),
|
|
208
|
+
tags: [
|
|
209
|
+
"domain:inbox",
|
|
210
|
+
"capability:read",
|
|
211
|
+
"capability:search",
|
|
212
|
+
"capability:summarize",
|
|
213
|
+
"surface:internal"
|
|
214
|
+
],
|
|
215
|
+
description: "Inbox: Gmail, Slack, Discord, Telegram, Signal, iMessage, WhatsApp. Merge recency feed. Subactions: list, search, summarize.",
|
|
216
|
+
descriptionCompressed: "INBOX list|search|summarize gmail|slack|discord|telegram|signal|imessage|whatsapp",
|
|
217
|
+
routingHint: 'cross-channel inbox ("show inbox", "all messages", "search every channel", "summarize inboxes") -> INBOX; per-channel -> MESSAGE',
|
|
218
|
+
contexts: ["inbox", "messaging", "cross-channel"],
|
|
219
|
+
roleGate: { minRole: "OWNER" },
|
|
220
|
+
suppressPostActionContinuation: true,
|
|
221
|
+
validate: async (runtime, message) => hasInboxAccess(runtime, message),
|
|
222
|
+
parameters: [
|
|
223
|
+
{
|
|
224
|
+
name: "action",
|
|
225
|
+
description: "Inbox op: list | search | summarize.",
|
|
226
|
+
schema: { type: "string", enum: [...SUBACTIONS] }
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "platforms",
|
|
230
|
+
description: "Optional platform filter: gmail | slack | discord | telegram | signal | imessage | whatsapp. Default all.",
|
|
231
|
+
schema: { type: "array", items: { type: "string" } }
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: "since",
|
|
235
|
+
description: "receivedAt lower bound. ISO-8601.",
|
|
236
|
+
schema: { type: "string" }
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: "limit",
|
|
240
|
+
description: "Limit per platform. Default 50.",
|
|
241
|
+
schema: { type: "number" }
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "query",
|
|
245
|
+
description: "Required for search. Free-form query.",
|
|
246
|
+
schema: { type: "string" }
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
examples,
|
|
250
|
+
handler: async (runtime, message, _state, options, callback) => {
|
|
251
|
+
if (!await hasInboxAccess(runtime, message)) {
|
|
252
|
+
const text2 = "The inbox is restricted to the owner.";
|
|
253
|
+
await callback?.({ text: text2 });
|
|
254
|
+
return { text: text2, success: false, data: { error: "PERMISSION_DENIED" } };
|
|
255
|
+
}
|
|
256
|
+
const params = getParams(options);
|
|
257
|
+
const subaction = resolveSubaction(params);
|
|
258
|
+
if (!subaction) {
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
text: "Tell me which operation: list, search, or summarize.",
|
|
262
|
+
data: { error: "MISSING_SUBACTION" }
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const platforms = resolvePlatforms(params.platforms);
|
|
266
|
+
if (platforms.length === 0) {
|
|
267
|
+
return {
|
|
268
|
+
success: false,
|
|
269
|
+
text: "No supported platforms were specified.",
|
|
270
|
+
data: { subaction, error: "NO_PLATFORMS" }
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const limit = typeof params.limit === "number" && params.limit > 0 ? Math.floor(params.limit) : 50;
|
|
274
|
+
let query;
|
|
275
|
+
if (subaction === "search") {
|
|
276
|
+
const trimmed = typeof params.query === "string" ? params.query.trim() : "";
|
|
277
|
+
if (trimmed.length === 0) {
|
|
278
|
+
return {
|
|
279
|
+
success: false,
|
|
280
|
+
text: "I need a non-empty query to search.",
|
|
281
|
+
data: { subaction, error: "MISSING_QUERY" }
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
query = trimmed;
|
|
285
|
+
}
|
|
286
|
+
const since = typeof params.since === "string" && params.since.trim().length > 0 ? params.since.trim() : void 0;
|
|
287
|
+
const fetched = await Promise.all(
|
|
288
|
+
platforms.map(async (platform) => {
|
|
289
|
+
const fetcher = activeFetchers[platform];
|
|
290
|
+
const items2 = await fetcher({
|
|
291
|
+
runtime,
|
|
292
|
+
...since ? { since } : {},
|
|
293
|
+
limit,
|
|
294
|
+
...query ? { query } : {}
|
|
295
|
+
});
|
|
296
|
+
return items2;
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
const flat = fetched.flat();
|
|
300
|
+
const merged = dedupeAndOrder(flat);
|
|
301
|
+
const items = subaction === "summarize" ? [] : merged;
|
|
302
|
+
const summary = subaction === "summarize" ? buildSummary(merged, platforms) : void 0;
|
|
303
|
+
logger.info(
|
|
304
|
+
`[INBOX] ${subaction} platforms=${platforms.join(",")} pre=${flat.length} post=${merged.length}`
|
|
305
|
+
);
|
|
306
|
+
let text;
|
|
307
|
+
switch (subaction) {
|
|
308
|
+
case "list":
|
|
309
|
+
text = merged.length === 0 ? "Your inbox is empty for this window." : `Pulled ${merged.length} messages across ${platforms.length} platforms.`;
|
|
310
|
+
break;
|
|
311
|
+
case "search":
|
|
312
|
+
text = merged.length === 0 ? `No matches for "${query}".` : `Found ${merged.length} matches for "${query}".`;
|
|
313
|
+
break;
|
|
314
|
+
case "summarize":
|
|
315
|
+
text = `Summarized ${platforms.length} platforms (${merged.length} unique messages).`;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
await callback?.({
|
|
319
|
+
text,
|
|
320
|
+
source: "action",
|
|
321
|
+
action: ACTION_NAME
|
|
322
|
+
});
|
|
323
|
+
return {
|
|
324
|
+
success: true,
|
|
325
|
+
text,
|
|
326
|
+
data: {
|
|
327
|
+
subaction,
|
|
328
|
+
platforms,
|
|
329
|
+
items,
|
|
330
|
+
...summary ? { summary } : {},
|
|
331
|
+
...query ? { query } : {},
|
|
332
|
+
...since ? { since } : {},
|
|
333
|
+
totalBeforeDedupe: flat.length
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
var inbox_default = inboxAction;
|
|
339
|
+
export {
|
|
340
|
+
__resetInboxFetchersForTests,
|
|
341
|
+
inbox_default as default,
|
|
342
|
+
inboxAction,
|
|
343
|
+
setInboxFetchers
|
|
344
|
+
};
|
|
345
|
+
//# sourceMappingURL=inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/actions/inbox.ts"],"sourcesContent":["/**\n * `INBOX` umbrella action — cross-channel inbox.\n *\n * The agent's `MESSAGE` umbrella triages per-channel inboxes; INBOX fans out to\n * every connected platform (Gmail, Slack, Discord, Telegram, Signal, iMessage,\n * WhatsApp) and produces a single merged feed for \"show me my inbox\" style\n * intents.\n *\n * Subactions:\n * - `list` — list recent messages across selected platforms\n * - `search` — search across selected platforms by `query`\n * - `summarize` — return a per-platform count + a single rolled-up summary\n *\n * Behavior: fan out to each platform's adapter via the injectable fetcher hook,\n * dedupe by `id` and thread topic, merge into a single result list ordered by\n * recency.\n *\n * Owner-only. Ported verbatim from the LifeOps INBOX action; the per-platform\n * default fetchers read through the shared MESSAGE triage service, and tests\n * inject deterministic fetchers via {@link setInboxFetchers}.\n */\n\nimport { hasOwnerAccess } from \"@elizaos/agent/security/access\";\nimport type {\n Action,\n ActionExample,\n ActionResult,\n HandlerCallback,\n HandlerOptions,\n IAgentRuntime,\n Memory,\n MessageRef,\n MessageSource,\n} from \"@elizaos/core\";\nimport { getDefaultTriageService, logger } from \"@elizaos/core\";\n\nconst ACTION_NAME = \"INBOX\";\n\nconst SUBACTIONS = [\"list\", \"search\", \"summarize\"] as const;\n\ntype Subaction = (typeof SUBACTIONS)[number];\n\nconst SIMILE_NAMES: readonly string[] = [\n \"INBOX\",\n \"CROSS_CHANNEL_INBOX\",\n \"ALL_MESSAGES\",\n \"INBOX_TRIAGE_PRIORITY\",\n];\n\nconst PLATFORMS = [\n \"gmail\",\n \"slack\",\n \"discord\",\n \"telegram\",\n \"signal\",\n \"imessage\",\n \"whatsapp\",\n] as const;\n\nexport type InboxPlatform = (typeof PLATFORMS)[number];\n\nexport interface InboxItem {\n readonly id: string;\n readonly platform: InboxPlatform;\n readonly channel: string;\n readonly senderName: string;\n readonly snippet: string;\n readonly receivedAt: string;\n readonly threadTopic?: string;\n readonly deepLink?: string;\n readonly unread?: boolean;\n}\n\ninterface InboxActionParameters {\n subaction?: Subaction | string;\n action?: Subaction | string;\n op?: Subaction | string;\n platforms?: readonly string[];\n since?: string;\n limit?: number;\n query?: string;\n}\n\nexport interface InboxSummaryEntry {\n readonly platform: InboxPlatform;\n readonly count: number;\n readonly latestAt: string | null;\n}\n\nexport interface InboxResult {\n readonly subaction: Subaction;\n readonly platforms: readonly InboxPlatform[];\n readonly items: readonly InboxItem[];\n readonly summary?: readonly InboxSummaryEntry[];\n readonly query?: string;\n readonly since?: string;\n readonly totalBeforeDedupe: number;\n}\n\n/**\n * Per-platform fetcher hook. Defaults read through the shared MESSAGE triage\n * service; tests can still inject deterministic scenario data.\n */\nexport type InboxFetcher = (args: {\n runtime: IAgentRuntime;\n since?: string;\n limit: number;\n query?: string;\n}) => Promise<readonly InboxItem[]>;\n\nexport type InboxFetchers = Record<InboxPlatform, InboxFetcher>;\n\nconst noopFetcher: InboxFetcher = async () => [];\n\nconst PLATFORM_TO_MESSAGE_SOURCE: Partial<\n Record<InboxPlatform, MessageSource>\n> = {\n gmail: \"gmail\",\n discord: \"discord\",\n telegram: \"telegram\",\n signal: \"signal\",\n imessage: \"imessage\",\n whatsapp: \"whatsapp\",\n};\n\nfunction mapMessageRefToInboxItem(ref: MessageRef): InboxItem | null {\n const platform = normalizePlatform(ref.source);\n if (!platform) return null;\n return {\n id: ref.id,\n platform,\n channel: ref.channelId ?? ref.worldId ?? \"default\",\n senderName: ref.from.displayName ?? ref.from.identifier,\n snippet: ref.snippet,\n receivedAt: new Date(ref.receivedAtMs).toISOString(),\n ...(ref.subject ? { threadTopic: ref.subject } : {}),\n ...(typeof ref.metadata?.htmlLink === \"string\"\n ? { deepLink: ref.metadata.htmlLink }\n : {}),\n unread: !ref.isRead,\n };\n}\n\nfunction parseSinceMs(since: string | undefined): number | undefined {\n if (!since) return undefined;\n const parsed = Date.parse(since);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction createDefaultPlatformFetcher(platform: InboxPlatform): InboxFetcher {\n const source = PLATFORM_TO_MESSAGE_SOURCE[platform];\n if (!source) return noopFetcher;\n return async ({ runtime, since, limit, query }) => {\n if (typeof runtime.getService !== \"function\") return [];\n try {\n const service = getDefaultTriageService();\n const refs = query\n ? await service.search(runtime, {\n sources: [source],\n content: query,\n sinceMs: parseSinceMs(since),\n limit,\n })\n : await service.triage(runtime, {\n sources: [source],\n sinceMs: parseSinceMs(since),\n limit,\n });\n return refs.flatMap((ref) => {\n const item = mapMessageRefToInboxItem(ref);\n return item ? [item] : [];\n });\n } catch (error) {\n logger.warn(\n `[INBOX] ${platform} fetch failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n return [];\n }\n };\n}\n\nconst defaultFetchers: InboxFetchers = {\n gmail: createDefaultPlatformFetcher(\"gmail\"),\n slack: noopFetcher,\n discord: createDefaultPlatformFetcher(\"discord\"),\n telegram: createDefaultPlatformFetcher(\"telegram\"),\n signal: createDefaultPlatformFetcher(\"signal\"),\n imessage: createDefaultPlatformFetcher(\"imessage\"),\n whatsapp: createDefaultPlatformFetcher(\"whatsapp\"),\n};\n\nlet activeFetchers: InboxFetchers = { ...defaultFetchers };\n\nexport function setInboxFetchers(next: Partial<InboxFetchers>): void {\n activeFetchers = { ...activeFetchers, ...next };\n}\n\nexport function __resetInboxFetchersForTests(): void {\n activeFetchers = { ...defaultFetchers };\n}\n\nfunction getParams(options: HandlerOptions | undefined): InboxActionParameters {\n const raw = (options as HandlerOptions | undefined)?.parameters;\n if (raw && typeof raw === \"object\") {\n return raw as InboxActionParameters;\n }\n return {};\n}\n\nfunction normalizeSubaction(value: unknown): Subaction | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n if (trimmed.length === 0) return null;\n const lower = trimmed.toLowerCase();\n return (SUBACTIONS as readonly string[]).includes(lower)\n ? (lower as Subaction)\n : null;\n}\n\nfunction resolveSubaction(params: InboxActionParameters): Subaction | null {\n return (\n normalizeSubaction(params.subaction) ??\n normalizeSubaction(params.action) ??\n normalizeSubaction(params.op)\n );\n}\n\nfunction normalizePlatform(value: unknown): InboxPlatform | null {\n if (typeof value !== \"string\") return null;\n const lower = value.trim().toLowerCase();\n return (PLATFORMS as readonly string[]).includes(lower)\n ? (lower as InboxPlatform)\n : null;\n}\n\nfunction resolvePlatforms(\n input: readonly string[] | undefined,\n): readonly InboxPlatform[] {\n if (!input || input.length === 0) {\n return [...PLATFORMS];\n }\n const seen = new Set<InboxPlatform>();\n for (const raw of input) {\n const normalized = normalizePlatform(raw);\n if (normalized) seen.add(normalized);\n }\n return [...seen];\n}\n\nfunction dedupeKey(item: InboxItem): string {\n if (item.threadTopic && item.threadTopic.length > 0) {\n return `topic:${item.threadTopic.toLowerCase()}::${item.platform}::${item.channel}`;\n }\n return `id:${item.platform}::${item.id}`;\n}\n\nfunction dedupeAndOrder(items: readonly InboxItem[]): readonly InboxItem[] {\n const seen = new Map<string, InboxItem>();\n for (const item of items) {\n const key = dedupeKey(item);\n const existing = seen.get(key);\n if (!existing) {\n seen.set(key, item);\n continue;\n }\n const a = Date.parse(item.receivedAt);\n const b = Date.parse(existing.receivedAt);\n if (Number.isNaN(a)) continue;\n if (Number.isNaN(b) || a > b) {\n seen.set(key, item);\n }\n }\n return [...seen.values()].sort((a, b) => {\n const aTime = Date.parse(a.receivedAt);\n const bTime = Date.parse(b.receivedAt);\n if (Number.isNaN(aTime) && Number.isNaN(bTime)) return 0;\n if (Number.isNaN(aTime)) return 1;\n if (Number.isNaN(bTime)) return -1;\n return bTime - aTime;\n });\n}\n\nfunction buildSummary(\n items: readonly InboxItem[],\n platforms: readonly InboxPlatform[],\n): readonly InboxSummaryEntry[] {\n return platforms.map<InboxSummaryEntry>((platform) => {\n const platformItems = items.filter((item) => item.platform === platform);\n let latestAt: string | null = null;\n for (const item of platformItems) {\n if (!latestAt || Date.parse(item.receivedAt) > Date.parse(latestAt)) {\n latestAt = item.receivedAt;\n }\n }\n return {\n platform,\n count: platformItems.length,\n latestAt,\n };\n });\n}\n\n/**\n * Owner-access guard for INBOX. Mirrors the LifeOps `hasLifeOpsAccess`\n * predicate exactly: reject when the runtime agent id or the message entity id\n * is missing/empty, then defer to the shared owner-access check.\n */\nasync function hasInboxAccess(\n runtime: IAgentRuntime,\n message: Memory,\n): Promise<boolean> {\n if (\n !runtime ||\n typeof runtime.agentId !== \"string\" ||\n !message ||\n typeof message.entityId !== \"string\" ||\n message.entityId.length === 0\n ) {\n return false;\n }\n return hasOwnerAccess(runtime, message);\n}\n\nconst examples: ActionExample[][] = [\n [\n { name: \"{{name1}}\", content: { text: \"Show me my inbox.\" } },\n {\n name: \"{{agentName}}\",\n content: {\n text: \"Pulled your inbox.\",\n action: ACTION_NAME,\n },\n },\n ],\n [\n {\n name: \"{{name1}}\",\n content: { text: \"Search every channel for messages about the launch.\" },\n },\n {\n name: \"{{agentName}}\",\n content: {\n text: \"Searched every connected inbox.\",\n action: ACTION_NAME,\n },\n },\n ],\n];\n\nexport const inboxAction: Action & {\n suppressPostActionContinuation?: boolean;\n} = {\n name: ACTION_NAME,\n similes: SIMILE_NAMES.slice(),\n tags: [\n \"domain:inbox\",\n \"capability:read\",\n \"capability:search\",\n \"capability:summarize\",\n \"surface:internal\",\n ],\n description:\n \"Inbox: Gmail, Slack, Discord, Telegram, Signal, iMessage, WhatsApp. Merge recency feed. Subactions: list, search, summarize.\",\n descriptionCompressed:\n \"INBOX list|search|summarize gmail|slack|discord|telegram|signal|imessage|whatsapp\",\n routingHint:\n 'cross-channel inbox (\"show inbox\", \"all messages\", \"search every channel\", \"summarize inboxes\") -> INBOX; per-channel -> MESSAGE',\n contexts: [\"inbox\", \"messaging\", \"cross-channel\"],\n roleGate: { minRole: \"OWNER\" },\n suppressPostActionContinuation: true,\n validate: async (runtime, message) => hasInboxAccess(runtime, message),\n parameters: [\n {\n name: \"action\",\n description: \"Inbox op: list | search | summarize.\",\n schema: { type: \"string\" as const, enum: [...SUBACTIONS] },\n },\n {\n name: \"platforms\",\n description:\n \"Optional platform filter: gmail | slack | discord | telegram | signal | imessage | whatsapp. Default all.\",\n schema: { type: \"array\" as const, items: { type: \"string\" as const } },\n },\n {\n name: \"since\",\n description: \"receivedAt lower bound. ISO-8601.\",\n schema: { type: \"string\" as const },\n },\n {\n name: \"limit\",\n description: \"Limit per platform. Default 50.\",\n schema: { type: \"number\" as const },\n },\n {\n name: \"query\",\n description: \"Required for search. Free-form query.\",\n schema: { type: \"string\" as const },\n },\n ],\n examples,\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state,\n options,\n callback: HandlerCallback | undefined,\n ): Promise<ActionResult> => {\n if (!(await hasInboxAccess(runtime, message))) {\n const text = \"The inbox is restricted to the owner.\";\n await callback?.({ text });\n return { text, success: false, data: { error: \"PERMISSION_DENIED\" } };\n }\n\n const params = getParams(options);\n const subaction = resolveSubaction(params);\n if (!subaction) {\n return {\n success: false,\n text: \"Tell me which operation: list, search, or summarize.\",\n data: { error: \"MISSING_SUBACTION\" },\n };\n }\n\n const platforms = resolvePlatforms(params.platforms);\n if (platforms.length === 0) {\n return {\n success: false,\n text: \"No supported platforms were specified.\",\n data: { subaction, error: \"NO_PLATFORMS\" },\n };\n }\n\n const limit =\n typeof params.limit === \"number\" && params.limit > 0\n ? Math.floor(params.limit)\n : 50;\n\n let query: string | undefined;\n if (subaction === \"search\") {\n const trimmed =\n typeof params.query === \"string\" ? params.query.trim() : \"\";\n if (trimmed.length === 0) {\n return {\n success: false,\n text: \"I need a non-empty query to search.\",\n data: { subaction, error: \"MISSING_QUERY\" },\n };\n }\n query = trimmed;\n }\n\n const since =\n typeof params.since === \"string\" && params.since.trim().length > 0\n ? params.since.trim()\n : undefined;\n\n const fetched = await Promise.all(\n platforms.map(async (platform) => {\n const fetcher = activeFetchers[platform];\n const items = await fetcher({\n runtime,\n ...(since ? { since } : {}),\n limit,\n ...(query ? { query } : {}),\n });\n return items;\n }),\n );\n const flat = fetched.flat();\n const merged = dedupeAndOrder(flat);\n const items: readonly InboxItem[] = subaction === \"summarize\" ? [] : merged;\n const summary: readonly InboxSummaryEntry[] | undefined =\n subaction === \"summarize\" ? buildSummary(merged, platforms) : undefined;\n\n logger.info(\n `[INBOX] ${subaction} platforms=${platforms.join(\",\")} pre=${flat.length} post=${merged.length}`,\n );\n\n let text: string;\n switch (subaction) {\n case \"list\":\n text =\n merged.length === 0\n ? \"Your inbox is empty for this window.\"\n : `Pulled ${merged.length} messages across ${platforms.length} platforms.`;\n break;\n case \"search\":\n text =\n merged.length === 0\n ? `No matches for \"${query}\".`\n : `Found ${merged.length} matches for \"${query}\".`;\n break;\n case \"summarize\":\n text = `Summarized ${platforms.length} platforms (${merged.length} unique messages).`;\n break;\n }\n\n await callback?.({\n text,\n source: \"action\",\n action: ACTION_NAME,\n });\n\n return {\n success: true,\n text,\n data: {\n subaction,\n platforms,\n items,\n ...(summary ? { summary } : {}),\n ...(query ? { query } : {}),\n ...(since ? { since } : {}),\n totalBeforeDedupe: flat.length,\n },\n };\n },\n};\n\nexport default inboxAction;\n"],"mappings":"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","names":["text","items"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InboxSpatialView — the cross-channel inbox authored once with the spatial
|
|
3
|
+
* vocabulary so it renders correctly wherever it is displayed:
|
|
4
|
+
*
|
|
5
|
+
* - GUI / XR — mounted in `<SpatialSurface>` (DOM; XR scales up).
|
|
6
|
+
* - TUI — rendered to real terminal lines by the agent terminal, via
|
|
7
|
+
* `registerSpatialTerminalView` (see `register-terminal-view.tsx`).
|
|
8
|
+
*
|
|
9
|
+
* It is purely presentational (a snapshot + an action callback in, primitives
|
|
10
|
+
* out) and imports ONLY the cross-modality primitives plus the view's local
|
|
11
|
+
* display types, so it is safe to render in the Node agent process where the
|
|
12
|
+
* terminal lives (no `@elizaos/ui` renderer barrel, no fetch).
|
|
13
|
+
*
|
|
14
|
+
* The live data wrapper {@link InboxView} owns the `/api/lifeops/inbox` fetch,
|
|
15
|
+
* the background poll, and the channel-filter state; it builds an
|
|
16
|
+
* {@link InboxSnapshot} and dispatches user intent back through `onAction`.
|
|
17
|
+
*/
|
|
18
|
+
import { type InboxChannel, type InboxItem } from "../../types.js";
|
|
19
|
+
/** Which fetch state the inbox surface is currently in. */
|
|
20
|
+
export type InboxStatus = "loading" | "error" | "empty" | "ready";
|
|
21
|
+
/** One channel chip's display state in the filter row. */
|
|
22
|
+
export interface InboxChannelFilter {
|
|
23
|
+
channel: InboxChannel;
|
|
24
|
+
label: string;
|
|
25
|
+
active: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface InboxSnapshot {
|
|
28
|
+
/** Current fetch state. */
|
|
29
|
+
status: InboxStatus;
|
|
30
|
+
/** Triage items (already filtered to the active channel selection). */
|
|
31
|
+
items: InboxItem[];
|
|
32
|
+
/** Channel filter chips in display order. */
|
|
33
|
+
filters: InboxChannelFilter[];
|
|
34
|
+
/** Number of active channel filters (drives the empty-state copy). */
|
|
35
|
+
activeFilterCount: number;
|
|
36
|
+
/** True when at least one channel reported messages in the payload. */
|
|
37
|
+
hasConnectedChannels: boolean;
|
|
38
|
+
/** Proactive one-liner ("N threads still need a reply"); absent when zero. */
|
|
39
|
+
nudge?: string | null;
|
|
40
|
+
/** Error text for the error state. */
|
|
41
|
+
error?: string | null;
|
|
42
|
+
}
|
|
43
|
+
/** A snapshot every surface can render before live data arrives. */
|
|
44
|
+
export declare const EMPTY_INBOX_SNAPSHOT: InboxSnapshot;
|
|
45
|
+
export interface InboxSpatialViewProps {
|
|
46
|
+
snapshot: InboxSnapshot;
|
|
47
|
+
/**
|
|
48
|
+
* Dispatch by agent id: `retry`, `connect`, `channel:<id>` (toggle a channel
|
|
49
|
+
* filter), and `open:<messageId>` (open a triage item).
|
|
50
|
+
*/
|
|
51
|
+
onAction?: (action: string) => void;
|
|
52
|
+
}
|
|
53
|
+
export declare function InboxSpatialView({ snapshot, onAction, }: InboxSpatialViewProps): import("react/jsx-runtime").JSX.Element;
|
|
54
|
+
//# sourceMappingURL=InboxSpatialView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InboxSpatialView.d.ts","sourceRoot":"","sources":["../../../src/components/inbox/InboxSpatialView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,2DAA2D;AAC3D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAElE,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,2BAA2B;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,uEAAuE;IACvE,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,sEAAsE;IACtE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,oBAAoB,EAAE,OAAO,CAAC;IAC9B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAQD,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,EAAE,aAQlC,CAAC;AAkCF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,aAAa,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,QAAQ,GACT,EAAE,qBAAqB,2CASvB"}
|