@volter/teams 0.1.49 → 0.1.51

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.
@@ -54,7 +54,7 @@ export function sendBrowserTurn(channel: BrowserChannel, text: string, options?:
54
54
 
55
55
  export interface MailHistoryEntry {
56
56
  id: string; from: string; fromName: string; to: string; text: string; at: number;
57
- direction: 'in' | 'out'; inReplyTo: string | null; delivery: string;
57
+ subject?: string | null; direction: 'in' | 'out'; inReplyTo: string | null; delivery: string;
58
58
  fromActor?: MailActor; toActor?: MailActor;
59
59
  }
60
60
  /** The existing native identity resolved by supercode, not the return mailbox. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/teams",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
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",
@@ -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: the brand's person placeholder, seeded; an empty seed is its one standard anonymous face. */
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
- return { ...entry, actor: { ...(seed ? { id: seed } : {}), name: name ?? 'Someone in the session', image: person(seed), kind: 'person' } };
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 } : {}) } };
@@ -149,7 +151,7 @@ export function withMail(transcript, rows, { agentName = 'This session', agentId
149
151
  const mail = rows.map(row => ({ id: `mail:${row.id}`, role: 'notice', text: row.text, ts: row.at, truncated: false,
150
152
  mail: { id: row.id, from: nameOf(row.fromActor), to: row.toActor ? nameOf(row.toActor) : row.direction === 'in' ? agentName : 'Another session',
151
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`,
152
- via: row.fromActor?.via, direction: row.direction, inReplyTo: row.inReplyTo } }));
154
+ subject: row.subject || undefined, via: row.fromActor?.via, direction: row.direction, inReplyTo: row.inReplyTo } }));
153
155
  const result = transcript.filter(entry => !entry.mail || !rows.some(row => row.id === entry.mail.id || row.id.startsWith(entry.mail.id)));
154
156
  // Keep native tool/result ordering intact (some native entries have no time).
155
157
  for (const entry of mail.sort((a, b) => a.ts - b.ts)) {