fauna-api 1.0.783 → 1.0.785

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.
@@ -1,5 +1,7 @@
1
- import { ApiKey, Credentials, Profile } from "./authentification.js";
2
- import { LastMessage } from "./parrot/chat.js";
1
+ import { Fauna } from "../index.js";
2
+ import { ApiKey, Credentials } from "./authentification.js";
3
+ import { ChatSummary } from "./parrot/chat.js";
4
+ import { Author } from "./parrot/generative.js";
3
5
  /** Whose chat it is: one of your groups, a friendship, or a partnership of one of your groups. */
4
6
  export type OwnerKind = 'group' | 'friend' | 'partnership';
5
7
  /** Who a chat belongs to, and how much you trust it. */
@@ -17,27 +19,19 @@ export type Owner = {
17
19
  name: string;
18
20
  };
19
21
  };
20
- /** A chat you share with others. */
21
- export type Chat = {
22
- id: string;
23
- name: string;
24
- /** People only: sends never start a model reply. */
25
- human: boolean;
22
+ /** A chat you share with others: the Parrot chat, and whose it is. Signed in with an API key, its `unread` is the key's own place. */
23
+ export type Chat = ChatSummary & {
26
24
  owner: Owner;
27
- /** Messages you haven't read. Signed in with an API key, the key keeps its own place. */
28
- unread: number;
29
- /** Milliseconds since the epoch. */
30
- updated: number;
31
- last: LastMessage | null;
25
+ };
26
+ export declare const Chat: {
27
+ fromJSON(json: any): Chat;
32
28
  };
33
29
  /** A message as plain text: mentions as names, files as `[file: name]`. */
34
30
  export type Message = {
35
31
  position: number;
36
32
  role: string;
37
33
  text: string;
38
- author?: Profile;
39
- /** The name of the API key an agent posted it with. */
40
- via?: string;
34
+ author?: Author;
41
35
  /** Milliseconds since the epoch. */
42
36
  created: number;
43
37
  };
@@ -107,7 +101,7 @@ export declare function search(authorization: Credentials | ApiKey, query: strin
107
101
  /**
108
102
  * Post `text` in a chat, as you. Everyone in it sees it live, its webhooks fire
109
103
  * and it counts toward memories, like any message. Signed in with an API key,
110
- * the message records the key's name (`via`) and never moves trust. In a chat
104
+ * the message is authored by the key, by its name, and never moves trust. In a chat
111
105
  * that isn't people only, it starts a model reply as any message does.
112
106
  */
113
107
  export declare function post(authorization: Credentials | ApiKey, chat: string, text: string): Promise<void>;
package/dist/src/chats.js CHANGED
@@ -1,5 +1,11 @@
1
1
  import { Fauna } from "../index.js";
2
2
  import { Parrot } from "./parrot/index.js";
3
+ import { ChatSummary } from "./parrot/chat.js";
4
+ export const Chat = {
5
+ fromJSON(json) {
6
+ return { ...ChatSummary.fromJSON(json), owner: json.owner };
7
+ },
8
+ };
3
9
  /**
4
10
  * Every chat you share with others, newest first: your groups', your friends'
5
11
  * and your groups' partnerships', each with its owner, your trust in it and what
@@ -14,7 +20,7 @@ export async function list(authorization) {
14
20
  });
15
21
  if (!response.ok)
16
22
  throw new Error(await response.text());
17
- return await response.json();
23
+ return (await response.json()).map(Chat.fromJSON);
18
24
  }
19
25
  /**
20
26
  * What you haven't read in chats you trust at least `minTrust` (default 0.1).
@@ -30,7 +36,8 @@ export async function unread(authorization, options = {}) {
30
36
  });
31
37
  if (!response.ok)
32
38
  throw new Error(await response.text());
33
- return await response.json();
39
+ const json = await response.json();
40
+ return { total: json.total, chats: (json.chats ?? []).map(Chat.fromJSON) };
34
41
  }
35
42
  /**
36
43
  * Everything you haven't read in chats you trust at least `minTrust` (default
@@ -72,7 +79,7 @@ export async function search(authorization, query, options = {}) {
72
79
  /**
73
80
  * Post `text` in a chat, as you. Everyone in it sees it live, its webhooks fire
74
81
  * and it counts toward memories, like any message. Signed in with an API key,
75
- * the message records the key's name (`via`) and never moves trust. In a chat
82
+ * the message is authored by the key, by its name, and never moves trust. In a chat
76
83
  * that isn't people only, it starts a model reply as any message does.
77
84
  */
78
85
  export async function post(authorization, chat, text) {
@@ -0,0 +1,98 @@
1
+ import { Cicada } from "./index.js";
2
+ import { Contact, Owner } from "./contacts.js";
3
+ import { Platform } from "../integrations.js";
4
+ import { Credentials, ApiKey } from "../authentification.js";
5
+ import { ChatSummary } from "../parrot/chat.js";
6
+ /** A line under one of a chat's messages, by its position: why it never arrived, or that it waits for an owner's approval. */
7
+ export type Note = {
8
+ position: number;
9
+ text: string;
10
+ };
11
+ /**
12
+ * One of an inbox's chats: the Parrot chat the inbox owns, with who it's with and how they're
13
+ * reached. Its messages are the chat's: open its room with `Parrot.Chat.openRoom` and
14
+ * `{ chatId: id }`. What the inbox's members and its agent write there goes out to its people.
15
+ */
16
+ export type Chat = ChatSummary & {
17
+ inboxId: string;
18
+ participants: (Contact | Owner | string)[];
19
+ /** The Discord or Slack channel it is, when it's one. */
20
+ channel?: {
21
+ platform?: Platform;
22
+ name?: string;
23
+ guildName?: string;
24
+ };
25
+ /** The platform it's reached on. */
26
+ platform?: Platform;
27
+ archived: boolean;
28
+ remindAt?: Date;
29
+ notes: Note[];
30
+ };
31
+ export declare const Chat: {
32
+ fromJSON(json: any): Chat;
33
+ };
34
+ /** A chat paired with the time its reminder is due. */
35
+ export type Reminder = {
36
+ chat: Chat;
37
+ remindAt: Date;
38
+ };
39
+ /**
40
+ * A queued outbound message the server sends at `sendAt`: a reply in a chat, or a fresh
41
+ * compose to a set of recipients (hydrated to contacts so the client can render them).
42
+ */
43
+ export type ScheduledSend = {
44
+ id: string;
45
+ sendAt: Date;
46
+ createdAt: Date;
47
+ message: string;
48
+ context: {
49
+ chatId: string;
50
+ platform?: Platform;
51
+ } | {
52
+ recipients: (Contact | Owner | string)[];
53
+ mode: 'broadcast' | 'group';
54
+ platform: Platform;
55
+ };
56
+ };
57
+ /** The inbox working set: everything except archived chats and chats parked for a future reminder. */
58
+ export declare function listInbox(authorization: Credentials | ApiKey, inboxId?: string): Promise<Chat[]>;
59
+ /** The archive. */
60
+ export declare function listArchived(authorization: Credentials | ApiKey, inboxId?: string): Promise<Chat[]>;
61
+ /** Chats with a future reminder, each with its due time. */
62
+ export declare function listReminders(authorization: Credentials | ApiKey, inboxId?: string): Promise<Reminder[]>;
63
+ /** One chat, or null once it's gone. */
64
+ export declare function get(authorization: Credentials | ApiKey, chatId: string): Promise<Chat | null>;
65
+ /** Deletes a chat and its messages. A history pull never brings them back. */
66
+ export declare function remove(authorization: Credentials | ApiKey, chatId: string): Promise<void>;
67
+ /**
68
+ * Starts (or appends to) chats with picked contacts on a platform. `recipients` are contact
69
+ * keys (email, handle or phone). `broadcast` sends a separate one to each; `group` sends one
70
+ * shared thread (one each on platforms without a real group). Resolves to the chats it wrote in.
71
+ */
72
+ export declare function compose(authorization: Credentials | ApiKey, options: {
73
+ recipients: string[];
74
+ platform: Platform;
75
+ text: string;
76
+ mode: 'broadcast' | 'group';
77
+ inboxId?: string;
78
+ accountId?: string;
79
+ }): Promise<string[]>;
80
+ /** Moves a chat in or out of the archive. */
81
+ export declare function archive(authorization: Credentials | ApiKey, chatId: string, archived: boolean): Promise<void>;
82
+ /** Sets (or clears, with null) a reminder; when it's due the chat comes back to the top of the inbox. */
83
+ export declare function remind(authorization: Credentials | ApiKey, chatId: string, at: Date | null): Promise<void>;
84
+ /** Queues an outbound message: a reply in `chatId`, or `compose` for fresh chats. Resolves to its id. */
85
+ export declare function schedule(authorization: Credentials | ApiKey, options: {
86
+ sendAt: Date;
87
+ text: string;
88
+ platform?: Platform;
89
+ chatId?: string;
90
+ compose?: {
91
+ recipients: string[];
92
+ mode: 'broadcast' | 'group';
93
+ };
94
+ inboxId?: string;
95
+ accountId?: string;
96
+ }): Promise<string>;
97
+ export declare function listScheduled(authorization: Credentials | ApiKey, inboxId?: string): Promise<ScheduledSend[]>;
98
+ export declare function cancelScheduled(authorization: Credentials | ApiKey, scheduled: string): Promise<void>;
@@ -0,0 +1,92 @@
1
+ import { Cicada } from "./index.js";
2
+ import { ChatSummary } from "../parrot/chat.js";
3
+ export const Chat = {
4
+ fromJSON(json) {
5
+ return {
6
+ ...ChatSummary.fromJSON(json),
7
+ inboxId: String(json.inboxId),
8
+ participants: json.participants ?? [],
9
+ ...(json.channel ? { channel: json.channel } : {}),
10
+ ...(json.platform ? { platform: json.platform } : {}),
11
+ archived: json.archived === true,
12
+ ...(json.remindAt ? { remindAt: new Date(json.remindAt) } : {}),
13
+ notes: Array.isArray(json.notes) ? json.notes : [],
14
+ };
15
+ },
16
+ };
17
+ async function post(authorization, path, body) {
18
+ const response = await fetch(`${Cicada.getURL()}${path}`, {
19
+ method: "POST",
20
+ headers: {
21
+ "Content-Type": "application/json",
22
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`
23
+ },
24
+ body: JSON.stringify(body)
25
+ });
26
+ if (!response.ok)
27
+ throw new Error(await response.text());
28
+ return response;
29
+ }
30
+ /** The inbox working set: everything except archived chats and chats parked for a future reminder. */
31
+ export async function listInbox(authorization, inboxId) {
32
+ const response = await post(authorization, '/cicada/inbox', inboxId ? { inboxId } : {});
33
+ return (await response.json()).map(Chat.fromJSON);
34
+ }
35
+ /** The archive. */
36
+ export async function listArchived(authorization, inboxId) {
37
+ const response = await post(authorization, '/cicada/archived', inboxId ? { inboxId } : {});
38
+ return (await response.json()).map(Chat.fromJSON);
39
+ }
40
+ /** Chats with a future reminder, each with its due time. */
41
+ export async function listReminders(authorization, inboxId) {
42
+ const response = await post(authorization, '/cicada/reminders', inboxId ? { inboxId } : {});
43
+ return (await response.json()).map((raw) => ({
44
+ chat: Chat.fromJSON(raw.chat),
45
+ remindAt: new Date(raw.remindAt)
46
+ }));
47
+ }
48
+ /** One chat, or null once it's gone. */
49
+ export async function get(authorization, chatId) {
50
+ const response = await post(authorization, '/cicada/chats/get', { chatId });
51
+ const json = await response.json();
52
+ return json ? Chat.fromJSON(json) : null;
53
+ }
54
+ /** Deletes a chat and its messages. A history pull never brings them back. */
55
+ export async function remove(authorization, chatId) {
56
+ await post(authorization, '/cicada/chats/delete', { chatId });
57
+ }
58
+ /**
59
+ * Starts (or appends to) chats with picked contacts on a platform. `recipients` are contact
60
+ * keys (email, handle or phone). `broadcast` sends a separate one to each; `group` sends one
61
+ * shared thread (one each on platforms without a real group). Resolves to the chats it wrote in.
62
+ */
63
+ export async function compose(authorization, options) {
64
+ const response = await post(authorization, '/cicada/compose', options);
65
+ const json = await response.json();
66
+ return json.chatIds;
67
+ }
68
+ /** Moves a chat in or out of the archive. */
69
+ export async function archive(authorization, chatId, archived) {
70
+ await post(authorization, '/cicada/chats/archive', { chatId, archived });
71
+ }
72
+ /** Sets (or clears, with null) a reminder; when it's due the chat comes back to the top of the inbox. */
73
+ export async function remind(authorization, chatId, at) {
74
+ await post(authorization, '/cicada/chats/remind', { chatId, at: at ? at.toISOString() : null });
75
+ }
76
+ /** Queues an outbound message: a reply in `chatId`, or `compose` for fresh chats. Resolves to its id. */
77
+ export async function schedule(authorization, options) {
78
+ const response = await post(authorization, '/cicada/schedule', { ...options, sendAt: options.sendAt.toISOString() });
79
+ const json = await response.json();
80
+ return json.id;
81
+ }
82
+ export async function listScheduled(authorization, inboxId) {
83
+ const response = await post(authorization, '/cicada/scheduled/list', inboxId ? { inboxId } : {});
84
+ return (await response.json()).map((raw) => ({
85
+ ...raw,
86
+ sendAt: new Date(raw.sendAt),
87
+ createdAt: new Date(raw.createdAt)
88
+ }));
89
+ }
90
+ export async function cancelScheduled(authorization, scheduled) {
91
+ await post(authorization, '/cicada/scheduled/cancel', { scheduled });
92
+ }
@@ -1,4 +1,5 @@
1
1
  import { Cicada } from "./index.js";
2
+ import type { Repository } from "../termite/versioning.js";
2
3
  import { Platform } from "../integrations.js";
3
4
  import { Credentials, ApiKey } from "../authentification.js";
4
5
  import type { Text, Voice } from "../parrot/generative.js";
@@ -14,6 +15,8 @@ export type Inbox = {
14
15
  group?: InboxGroup;
15
16
  /** An agent is on for this inbox. */
16
17
  agent?: boolean;
18
+ /** The Termite repository its agent's desktop works in. */
19
+ repository?: string;
17
20
  };
18
21
  export type InboxAccount = {
19
22
  platform: Platform;
@@ -23,6 +26,8 @@ export declare function list(authorization: Credentials | ApiKey): Promise<Inbox
23
26
  export declare function create(authorization: Credentials | ApiKey, name: string): Promise<Inbox>;
24
27
  export declare function rename(authorization: Credentials | ApiKey, inboxId: string, name: string): Promise<Inbox>;
25
28
  export declare function remove(authorization: Credentials | ApiKey, inboxId: string): Promise<void>;
29
+ /** Attaches a Termite repository, where the inbox's agent's desktop works, or detaches it with null. It must be the inbox owner's. */
30
+ export declare function setRepository(authorization: Credentials | ApiKey, inboxId: string, repository: Repository | null): Promise<Inbox>;
26
31
  export declare function moveToGroup(authorization: Credentials | ApiKey, inboxId: string, groupId: string): Promise<Inbox>;
27
32
  export declare function assign(authorization: Credentials | ApiKey, inboxId: string, account: {
28
33
  platform: Platform;
@@ -26,6 +26,7 @@ function wrapInbox(raw) {
26
26
  createdAt: new Date(raw.createdAt),
27
27
  ...(group ? { group } : {}),
28
28
  ...(raw.agent ? { agent: true } : {}),
29
+ ...(raw.repository ? { repository: String(raw.repository) } : {}),
29
30
  };
30
31
  }
31
32
  export async function list(authorization) {
@@ -43,6 +44,11 @@ export async function rename(authorization, inboxId, name) {
43
44
  export async function remove(authorization, inboxId) {
44
45
  await post(authorization, '/cicada/inboxes/delete', { inbox: inboxId });
45
46
  }
47
+ /** Attaches a Termite repository, where the inbox's agent's desktop works, or detaches it with null. It must be the inbox owner's. */
48
+ export async function setRepository(authorization, inboxId, repository) {
49
+ const response = await post(authorization, '/cicada/inboxes/repository', { inbox: inboxId, repository: repository ? repository.id : null });
50
+ return wrapInbox(await response.json());
51
+ }
46
52
  export async function moveToGroup(authorization, inboxId, groupId) {
47
53
  const response = await post(authorization, '/cicada/inboxes/move', { inbox: inboxId, group: groupId });
48
54
  return wrapInbox(await response.json());
@@ -1,5 +1,5 @@
1
+ import * as ChatsAPI from "./chats.js";
1
2
  import * as ContactsAPI from "./contacts.js";
2
- import * as ConversationsAPI from "./conversations.js";
3
3
  import * as InboxesAPI from "./inboxes.js";
4
4
  import * as PhoneAPI from "./phone.js";
5
5
  export declare namespace Cicada {
@@ -9,8 +9,8 @@ export declare namespace Cicada {
9
9
  function getRoute(): string;
10
10
  function getURL(): string;
11
11
  function ping(): Promise<number>;
12
+ export import Chats = ChatsAPI;
12
13
  export import Contacts = ContactsAPI;
13
- export import Conversations = ConversationsAPI;
14
14
  export import Inboxes = InboxesAPI;
15
15
  export import Phone = PhoneAPI;
16
16
  }
@@ -1,5 +1,5 @@
1
+ import * as ChatsAPI from "./chats.js";
1
2
  import * as ContactsAPI from "./contacts.js";
2
- import * as ConversationsAPI from "./conversations.js";
3
3
  import * as InboxesAPI from "./inboxes.js";
4
4
  import * as PhoneAPI from "./phone.js";
5
5
  export var Cicada;
@@ -54,8 +54,8 @@ export var Cicada;
54
54
  return Date.now() - start;
55
55
  }
56
56
  Cicada.ping = ping;
57
+ Cicada.Chats = ChatsAPI;
57
58
  Cicada.Contacts = ContactsAPI;
58
- Cicada.Conversations = ConversationsAPI;
59
59
  Cicada.Inboxes = InboxesAPI;
60
60
  Cicada.Phone = PhoneAPI;
61
61
  })(Cicada || (Cicada = {}));
@@ -1,10 +1,7 @@
1
1
  import { Fauna } from "../index.js";
2
- import { LastMessage } from "./parrot/chat.js";
3
- function hydrateChats(raw) {
4
- return (raw ?? []).map((row) => ({ ...row, human: row.human === true, locked: row.locked === true, last: LastMessage.fromJSON(row.last), unread: typeof row.unread === 'number' ? row.unread : 0 }));
5
- }
2
+ import { ChatSummary } from "./parrot/chat.js";
6
3
  function hydrate(raw) {
7
- return { ...raw, chats: hydrateChats(raw.chats), created: new Date(raw.created) };
4
+ return { ...raw, chats: (raw.chats ?? []).map(ChatSummary.fromJSON), created: new Date(raw.created) };
8
5
  }
9
6
  /** Your friends, each with your chats together and what you haven't read. An API key reads them too. */
10
7
  export async function list(authorization) {
@@ -1,5 +1,5 @@
1
1
  import { Fauna } from "../index.js";
2
- import { LastMessage } from "./parrot/chat.js";
2
+ import { ChatSummary } from "./parrot/chat.js";
3
3
  export const GroupRef = {
4
4
  fromJSON(json) {
5
5
  return {
@@ -501,7 +501,7 @@ export async function unnest(credentials, id, child) {
501
501
  function hydratePartnership(raw) {
502
502
  return {
503
503
  ...raw,
504
- chats: (raw.chats ?? []).map((row) => ({ ...row, human: row.human === true, locked: row.locked === true, last: LastMessage.fromJSON(row.last), unread: typeof row.unread === 'number' ? row.unread : 0 })),
504
+ chats: (raw.chats ?? []).map(ChatSummary.fromJSON),
505
505
  created: new Date(raw.created),
506
506
  };
507
507
  }
@@ -1,6 +1,6 @@
1
1
  import { Parrot } from "./index.js";
2
2
  import { Content } from "./generative.js";
3
- import { Credentials, ApiKey, Profile } from "../authentification.js";
3
+ import { Credentials, ApiKey } from "../authentification.js";
4
4
  import { Group } from "../groups.js";
5
5
  import { ChatRoom, RoomHooks } from "./room.js";
6
6
  import { Presence } from "../shared/server.js";
@@ -40,17 +40,6 @@ export declare function createChat(authorization: Credentials | ApiKey, name?: s
40
40
  repository?: Repository;
41
41
  }): Promise<string>;
42
42
  export declare function deleteChat(authorization: Credentials | ApiKey, id: string, group?: Group): Promise<void>;
43
- export type LastMessage = {
44
- parts: unknown[];
45
- role: string;
46
- createdAt: Date;
47
- position: number;
48
- author?: Profile;
49
- model?: string;
50
- };
51
- export declare const LastMessage: {
52
- fromJSON(json: unknown): LastMessage | null;
53
- };
54
43
  export type ChatSummary = {
55
44
  id: string;
56
45
  name: string;
@@ -63,11 +52,14 @@ export type ChatSummary = {
63
52
  repository: number | null;
64
53
  created: number;
65
54
  updated: number;
66
- last: LastMessage | null;
55
+ last: Content | null;
67
56
  /** Messages the caller hasn't read. A person and each of their API keys keep
68
57
  * their own place; one that never marked the chat sees only its newest 20. */
69
58
  unread: number;
70
59
  };
60
+ export declare const ChatSummary: {
61
+ fromJSON(json: any): ChatSummary;
62
+ };
71
63
  export declare function listChats(authorization: Credentials | ApiKey, group?: Group): Promise<ChatSummary[]>;
72
64
  export declare function renameChat(authorization: Credentials | ApiKey, id: string, name: string, group?: Group): Promise<void>;
73
65
  /**
@@ -76,6 +68,11 @@ export declare function renameChat(authorization: Credentials | ApiKey, id: stri
76
68
  * person. Sending a message reads the chat for its sender. Returns what's left unread.
77
69
  */
78
70
  export declare function markRead(authorization: Credentials | ApiKey, id: string, position?: number, group?: Group): Promise<number>;
71
+ /**
72
+ * The rest of a draft reply in a chat, from its newest messages and how you write to the
73
+ * same people in its owner's other chats. Empty when the draft needs nothing more.
74
+ */
75
+ export declare function autocomplete(authorization: Credentials | ApiKey, id: string, text: string, group?: Group): Promise<string>;
79
76
  /** One page of a chat, newest first. */
80
77
  export declare function readChat(authorization: Credentials | ApiKey, id: string, group: Group | undefined, query: {
81
78
  cursor: number;
@@ -1,5 +1,5 @@
1
1
  import { Parrot } from "./index.js";
2
- import { Profile } from "../authentification.js";
2
+ import { Content } from "./generative.js";
3
3
  import * as Drive from "../drive.js";
4
4
  import { openRoom } from "./share.js";
5
5
  import { connectRoom } from "./room.js";
@@ -64,21 +64,19 @@ export async function deleteChat(authorization, id, group) {
64
64
  if (!response.ok)
65
65
  throw new Error(await response.text());
66
66
  }
67
- export const LastMessage = {
67
+ export const ChatSummary = {
68
68
  fromJSON(json) {
69
- if (!json || typeof json !== "object")
70
- return null;
71
- const row = json;
72
- const createdAt = row.createdAt instanceof Date ? row.createdAt : new Date(row.createdAt);
73
- if (Number.isNaN(createdAt.getTime()) || typeof row.position !== "number")
74
- return null;
75
69
  return {
76
- parts: Array.isArray(row.parts) ? row.parts : [],
77
- role: String(row.role ?? ""),
78
- createdAt,
79
- position: row.position,
80
- author: Profile.fromJSON(row.author),
81
- model: row.model ? String(row.model) : undefined,
70
+ id: String(json.id),
71
+ name: typeof json.name === 'string' ? json.name : '',
72
+ principalId: typeof json.principalId === 'string' ? json.principalId : '',
73
+ human: json.human === true,
74
+ locked: json.locked === true,
75
+ repository: typeof json.repository === 'number' && json.repository > 0 ? json.repository : null,
76
+ created: Number(json.created ?? 0),
77
+ updated: Number(json.updated ?? 0),
78
+ last: json.last ? Content.fromJSON(json.last) : null,
79
+ unread: typeof json.unread === 'number' ? json.unread : 0,
82
80
  };
83
81
  },
84
82
  };
@@ -94,14 +92,7 @@ export async function listChats(authorization, group) {
94
92
  if (!response.ok)
95
93
  throw new Error(await response.text());
96
94
  const rows = await response.json();
97
- return (Array.isArray(rows) ? rows : []).map((row) => ({
98
- ...row,
99
- human: row.human === true,
100
- locked: row.locked === true,
101
- repository: typeof row.repository === 'number' && row.repository > 0 ? row.repository : null,
102
- last: LastMessage.fromJSON(row.last),
103
- unread: typeof row.unread === 'number' ? row.unread : 0,
104
- }));
95
+ return (Array.isArray(rows) ? rows : []).map(ChatSummary.fromJSON);
105
96
  }
106
97
  export async function renameChat(authorization, id, name, group) {
107
98
  const response = await fetch(`${Parrot.getURL()}/chat/rename`, {
@@ -136,6 +127,24 @@ export async function markRead(authorization, id, position, group) {
136
127
  const json = await response.json();
137
128
  return typeof json.unread === 'number' ? json.unread : 0;
138
129
  }
130
+ /**
131
+ * The rest of a draft reply in a chat, from its newest messages and how you write to the
132
+ * same people in its owner's other chats. Empty when the draft needs nothing more.
133
+ */
134
+ export async function autocomplete(authorization, id, text, group) {
135
+ const response = await fetch(`${Parrot.getURL()}/chat/autocomplete`, {
136
+ method: "POST",
137
+ headers: {
138
+ "Content-Type": "application/json",
139
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
140
+ ...(group ? { "Group": group.id } : {})
141
+ },
142
+ body: JSON.stringify({ id, text })
143
+ });
144
+ if (!response.ok)
145
+ throw new Error(await response.text());
146
+ return await response.text();
147
+ }
139
148
  function fileRef(file) {
140
149
  const authorization = file.authorization;
141
150
  if ('accessCode' in authorization) {
@@ -174,27 +183,7 @@ export async function readChat(authorization, id, group, query) {
174
183
  if (!response.ok)
175
184
  throw new Error(await response.text());
176
185
  const json = await response.json();
177
- const messages = [];
178
- for (const message of Array.isArray(json) ? json : []) {
179
- const parts = [];
180
- for (const part of message.parts ?? []) {
181
- if (part.type === 'FILE') {
182
- parts.push(hydrateFilePart(authorization, part, group));
183
- }
184
- else {
185
- parts.push(part);
186
- }
187
- }
188
- messages.push({
189
- parts,
190
- role: message.role,
191
- author: message.author,
192
- model: message.model,
193
- createdAt: new Date(message.createdAt),
194
- ...(message.via ? { via: String(message.via) } : {}),
195
- });
196
- }
197
- return messages;
186
+ return (Array.isArray(json) ? json : []).map((message) => Content.fromJSON(message, (part) => hydrateFilePart(authorization, part, group)));
198
187
  }
199
188
  export async function writeChat(authorization, id, messages, group) {
200
189
  const serializedMessages = [];
@@ -1,3 +1,4 @@
1
+ import { Parrot } from "./index.js";
1
2
  import { Credentials, ApiKey, Profile } from "../authentification.js";
2
3
  import type { File as FaunaFile } from "../drive.js";
3
4
  import type { Demographic } from "../ant/persona.js";
@@ -89,6 +90,11 @@ export type TextPart = {
89
90
  type: 'TEXT';
90
91
  text: string;
91
92
  };
93
+ /** A body written in HTML, such as an email's. Chat UIs draw it as it is; models read its text. */
94
+ export type HtmlPart = {
95
+ type: 'HTML';
96
+ html: string;
97
+ };
92
98
  export type File = {
93
99
  type: 'FILE';
94
100
  file: FaunaFile;
@@ -118,7 +124,7 @@ export type Reaction = {
118
124
  position: number;
119
125
  on: boolean;
120
126
  };
121
- export type Part = TextPart | File | Invocation | Result | Reaction;
127
+ export type Part = TextPart | HtmlPart | File | Invocation | Result | Reaction;
122
128
  export type Function = {
123
129
  name: string;
124
130
  parameters: Schema;
@@ -132,15 +138,28 @@ export type Tool = {
132
138
  evaluate: (params: any) => Promise<string>;
133
139
  instruction?: (params: any) => string;
134
140
  };
141
+ /**
142
+ * Who wrote a message: a person, an agent posting with an API key (only its `name`, never
143
+ * its id), an app's own agent (`'MODEL'`, such as an inbox agent), or an outside address
144
+ * such as a phone number or an email. Parrot's own model replies have none; their `model`
145
+ * says which model wrote them.
146
+ */
147
+ export type Author = Profile | Partial<ApiKey> | 'MODEL' | string;
148
+ export declare const Author: {
149
+ fromJSON(json: unknown): Author | undefined;
150
+ };
135
151
  export type Content = {
136
152
  parts: Part[];
137
153
  role: Role;
138
154
  createdAt: Date;
139
- author?: Profile;
140
- /** Text model id that produced a MODEL turn (for UI avatar / rehydrate). */
141
- model?: string;
142
- /** The name of the API key an agent posted this with, for its author. */
143
- via?: string;
155
+ author?: Author;
156
+ /** The model that wrote a MODEL turn. */
157
+ model?: Text;
158
+ };
159
+ export declare const Content: {
160
+ /** A message off the wire. `file` turns each FILE part into a `FaunaFile`; without it
161
+ * parts pass through as sent. */
162
+ fromJSON(json: any, file?: (part: any) => Part): Content;
144
163
  };
145
164
  export type TextResponse = {
146
165
  content: Content;
@@ -1,4 +1,5 @@
1
1
  import { Parrot } from "./index.js";
2
+ import { Profile } from "../authentification.js";
2
3
  import { collectText, collectVoice, generateMedia, prepareMessages, streamText, streamVoice } from "./socket.js";
3
4
  // Text Clients
4
5
  export var Text;
@@ -111,6 +112,32 @@ export var Role;
111
112
  Role["SYSTEM"] = "SYSTEM";
112
113
  Role["TOOL"] = "TOOL";
113
114
  })(Role || (Role = {}));
115
+ export const Author = {
116
+ fromJSON(json) {
117
+ if (typeof json === 'string')
118
+ return json || undefined;
119
+ if (!json || typeof json !== 'object')
120
+ return undefined;
121
+ const profile = Profile.fromJSON(json);
122
+ if (profile)
123
+ return profile;
124
+ const name = json.name;
125
+ return typeof name === 'string' ? { name } : undefined;
126
+ },
127
+ };
128
+ export const Content = {
129
+ /** A message off the wire. `file` turns each FILE part into a `FaunaFile`; without it
130
+ * parts pass through as sent. */
131
+ fromJSON(json, file) {
132
+ return {
133
+ parts: (Array.isArray(json?.parts) ? json.parts : []).map((part) => part?.type === 'FILE' && file ? file(part) : part),
134
+ role: json?.role,
135
+ createdAt: new Date(json?.createdAt),
136
+ author: Author.fromJSON(json?.author),
137
+ model: json?.model ? json.model : undefined,
138
+ };
139
+ },
140
+ };
114
141
  // Streaming Text Generation. A singular Tool forces it; an array lets the model choose.
115
142
  export async function* generateText(authorization, model, options = {}) {
116
143
  yield* streamText(authorization, '/generative/text', model, options);