@volter/teams 0.1.48 → 0.1.50
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/browser-channel.d.ts +6 -0
- package/package.json +1 -1
- package/session-follow.d.ts +1 -1
- package/session-follow.mjs +12 -8
package/browser-channel.d.ts
CHANGED
|
@@ -55,6 +55,12 @@ export function sendBrowserTurn(channel: BrowserChannel, text: string, options?:
|
|
|
55
55
|
export interface MailHistoryEntry {
|
|
56
56
|
id: string; from: string; fromName: string; to: string; text: string; at: number;
|
|
57
57
|
direction: 'in' | 'out'; inReplyTo: string | null; delivery: string;
|
|
58
|
+
fromActor?: MailActor; toActor?: MailActor;
|
|
59
|
+
}
|
|
60
|
+
/** The existing native identity resolved by supercode, not the return mailbox. */
|
|
61
|
+
export interface MailActor {
|
|
62
|
+
id: string; name: string; kind: 'agent' | 'automation' | 'person'; self: boolean; via?: 'voice';
|
|
63
|
+
session?: { machine: string; harness: string; id: string };
|
|
58
64
|
}
|
|
59
65
|
/** Read mailbox history without marking messages read. Requires observe on the bound session. */
|
|
60
66
|
export function readBrowserMail(channel: BrowserChannel): Promise<MailHistoryEntry[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/teams",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Volter Teams, the neutral team plane: machine identity and daemon core, the local door and server link, admission from machine grants, product doors, and the Teams server's neutral routes (company RFC 0008).",
|
|
6
6
|
"license": "MIT",
|
package/session-follow.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export function followTeamSession(options: FollowTeamSessionOptions): { stop():
|
|
|
34
34
|
export function peerMessage(text: string): { name: string; address: string; body: string } | null;
|
|
35
35
|
|
|
36
36
|
/** Overlay actual envelopes, deduplicating copies already delivered into the native transcript. */
|
|
37
|
-
export function withMail<Entry extends { id: string; ts: number | null; mail?: { id: string } }>(transcript: Entry[], rows: import('./browser-channel.js').MailHistoryEntry[], options?: { agentName?: string }): Array<Entry | { id: string; role: 'notice'; text: string; ts: number; truncated: boolean; mail: { id: string; from: string; to: string; direction: 'in' | 'out'; inReplyTo?: string | null } }>;
|
|
37
|
+
export function withMail<Entry extends { id: string; ts: number | null; mail?: { id: string } }>(transcript: Entry[], rows: import('./browser-channel.js').MailHistoryEntry[], options?: { agentName?: string; agentId?: string; agentImage?(seed: string): string }): Array<Entry | { id: string; role: 'notice'; text: string; ts: number; truncated: boolean; mail: { id: string; from: string; to: string; direction: 'in' | 'out'; inReplyTo?: string | null; image?: string; via?: 'voice' } }>;
|
|
38
38
|
|
|
39
39
|
export function personImage(seed?: string): string;
|
|
40
40
|
export function agentImage(seed: string): string;
|
package/session-follow.mjs
CHANGED
|
@@ -86,8 +86,8 @@ export function peerMessage(text) {
|
|
|
86
86
|
return { id: own.id || outer.id || null, name: own['from-name'] || outer['from-name'] || own.from || outer.from || 'Another session', address: own.from || outer.from || '', body };
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
/** A person's picture
|
|
90
|
-
export const personImage = (seed = '') => `https://brand.volter.ai/runner/svg?seed=${encodeURIComponent(seed)}&size=36&radius=18
|
|
89
|
+
/** A known person's picture; an unnamed sender gets the neutral brand user icon. */
|
|
90
|
+
export const personImage = (seed = '') => seed ? `https://brand.volter.ai/runner/svg?seed=${encodeURIComponent(seed)}&size=36&radius=18` : 'https://brand.volter.ai/icon/user-round/svg?size=24';
|
|
91
91
|
/** An agent's picture (this session's own, a peer session's): the brand's agent mark, a rounded square, never a face. */
|
|
92
92
|
export const agentImage = (seed) => `https://brand.volter.ai/agent/svg?seed=${encodeURIComponent(seed)}&size=36&radius=7`;
|
|
93
93
|
|
|
@@ -124,13 +124,15 @@ export function withPeople(transcript, messages, { agentName = null, sessionId =
|
|
|
124
124
|
const metadata = byTime.get(entry.ts) ?? {};
|
|
125
125
|
const name = metadata.source_name || null;
|
|
126
126
|
const seed = name ? (metadata.source_principal_id || name) : '';
|
|
127
|
-
|
|
127
|
+
const via = typeof metadata.source_via === 'string' ? metadata.source_via.trim() : '';
|
|
128
|
+
const source = ({ room: 'Room', app: 'App', terminal: 'Terminal', api: 'API' })[via] || via || 'Session';
|
|
129
|
+
return { ...entry, actor: { ...(seed ? { id: seed } : {}), name: name ?? 'Anonymous', anonymous: !name, source, image: person(seed), kind: 'person' } };
|
|
128
130
|
});
|
|
129
131
|
let last = null;
|
|
130
132
|
return people.map((entry) => {
|
|
131
133
|
if (!entry.actor) return entry;
|
|
132
|
-
const author = `${entry.actor.kind ?? ''}:${entry.actor.name ?? entry.role}`;
|
|
133
|
-
const continued = last !== null && last.author === author && Number.isFinite(entry.ts) && Number.isFinite(last.ts) && entry.ts - last.ts < 5 * 60_000;
|
|
134
|
+
const author = `${entry.actor.kind ?? ''}:${entry.actor.id ?? entry.actor.name ?? entry.role}:${entry.actor.source ?? ''}`;
|
|
135
|
+
const continued = !entry.actor.anonymous && last !== null && last.author === author && Number.isFinite(entry.ts) && Number.isFinite(last.ts) && entry.ts - last.ts < 5 * 60_000;
|
|
134
136
|
last = { author, ts: entry.ts };
|
|
135
137
|
const timeLabel = Number.isFinite(entry.ts) ? new Date(entry.ts).toLocaleTimeString(locale, { hour: 'numeric', minute: '2-digit' }) : undefined;
|
|
136
138
|
return { ...entry, actor: { ...entry.actor, ...(continued ? { continued: true } : {}), ...(timeLabel ? { timeLabel } : {}) } };
|
|
@@ -140,14 +142,16 @@ export function withPeople(transcript, messages, { agentName = null, sessionId =
|
|
|
140
142
|
/** Overlay real mail on the native transcript without rewriting native messages.
|
|
141
143
|
* Stable envelope IDs deduplicate harness-delivered copies. Neither rendering
|
|
142
144
|
* nor expanding an envelope changes its mailbox state. */
|
|
143
|
-
export function withMail(transcript, rows, { agentName = 'This session' } = {}) {
|
|
145
|
+
export function withMail(transcript, rows, { agentName = 'This session', agentId = '', agentImage: picture = agentImage } = {}) {
|
|
144
146
|
// An older mailbox must not jump ahead of the page of history being viewed.
|
|
145
147
|
// Its envelopes become visible when the person loads that earlier history.
|
|
146
148
|
const times = transcript.map(entry => entry.ts).filter(Number.isFinite);
|
|
147
149
|
if (times.length) rows = rows.filter(row => row.at >= Math.min(...times));
|
|
150
|
+
const nameOf = actor => actor?.self ? agentName : actor?.name || 'Unknown sender';
|
|
148
151
|
const mail = rows.map(row => ({ id: `mail:${row.id}`, role: 'notice', text: row.text, ts: row.at, truncated: false,
|
|
149
|
-
mail: { id: row.id, from: row.
|
|
150
|
-
|
|
152
|
+
mail: { id: row.id, from: nameOf(row.fromActor), to: row.toActor ? nameOf(row.toActor) : row.direction === 'in' ? agentName : 'Another session',
|
|
153
|
+
image: row.fromActor?.kind === 'agent' ? picture(row.fromActor.self ? agentId : row.fromActor.id) : `https://brand.volter.ai/bot/svg?seed=${encodeURIComponent(row.fromActor?.id || row.from)}&size=24&radius=4`,
|
|
154
|
+
via: row.fromActor?.via, direction: row.direction, inReplyTo: row.inReplyTo } }));
|
|
151
155
|
const result = transcript.filter(entry => !entry.mail || !rows.some(row => row.id === entry.mail.id || row.id.startsWith(entry.mail.id)));
|
|
152
156
|
// Keep native tool/result ordering intact (some native entries have no time).
|
|
153
157
|
for (const entry of mail.sort((a, b) => a.ts - b.ts)) {
|