@signalcore/ui 1.0.0-beta.1 → 1.0.0-beta.3

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.
Files changed (138) hide show
  1. package/README.md +55 -22
  2. package/dist/AgentAbout.js +11 -4
  3. package/dist/AgentAbout.js.map +1 -1
  4. package/dist/AgentChat.d.ts +7 -1
  5. package/dist/AgentChat.js +154 -2
  6. package/dist/AgentChat.js.map +1 -1
  7. package/dist/AgentSpace.d.ts +12 -3
  8. package/dist/AgentSpace.js +53 -11
  9. package/dist/AgentSpace.js.map +1 -1
  10. package/dist/AgentTasks.js +2 -1
  11. package/dist/AgentTasks.js.map +1 -1
  12. package/dist/Threads.d.ts +73 -0
  13. package/dist/Threads.js +140 -0
  14. package/dist/Threads.js.map +1 -0
  15. package/dist/VoiceCall.js +1 -1
  16. package/dist/VoiceCall.js.map +1 -1
  17. package/dist/about.d.ts +34 -144
  18. package/dist/about.js +6 -8
  19. package/dist/about.js.map +1 -1
  20. package/dist/automation/cron.d.ts +1 -1
  21. package/dist/automation/cron.js.map +1 -1
  22. package/dist/automation/marks.js +13 -5
  23. package/dist/automation/marks.js.map +1 -1
  24. package/dist/automation/messages.d.ts +6 -0
  25. package/dist/automation/messages.js +7 -1
  26. package/dist/automation/messages.js.map +1 -1
  27. package/dist/automation/types.d.ts +25 -128
  28. package/dist/automation/types.js +36 -0
  29. package/dist/automation/types.js.map +1 -0
  30. package/dist/automation/when.d.ts +1 -1
  31. package/dist/automation/when.js +13 -1
  32. package/dist/automation/when.js.map +1 -1
  33. package/dist/blocks.d.ts +23 -1
  34. package/dist/browser.js +2 -2
  35. package/dist/browser.js.map +1 -1
  36. package/dist/call.d.ts +1 -1
  37. package/dist/call.js.map +1 -1
  38. package/dist/client.d.ts +14 -4
  39. package/dist/client.js +7 -2
  40. package/dist/client.js.map +1 -1
  41. package/dist/contract.d.ts +267 -0
  42. package/dist/credentials.js.map +1 -1
  43. package/dist/dev.js +1 -1
  44. package/dist/dev.js.map +1 -1
  45. package/dist/es.d.ts +2 -0
  46. package/dist/es.js +31 -4
  47. package/dist/es.js.map +1 -1
  48. package/dist/frames.d.ts +7 -1
  49. package/dist/frames.js.map +1 -1
  50. package/dist/index.d.ts +6 -5
  51. package/dist/index.js +6 -4
  52. package/dist/kit/AudioPlayer.js +1 -1
  53. package/dist/kit/AudioPlayer.js.map +1 -1
  54. package/dist/kit/Choices.js +1 -1
  55. package/dist/kit/Choices.js.map +1 -1
  56. package/dist/kit/FileField.js +1 -1
  57. package/dist/kit/FileField.js.map +1 -1
  58. package/dist/kit/Popover.js.map +1 -1
  59. package/dist/kit/Tile.d.ts +1 -1
  60. package/dist/kit/Tile.js +1 -1
  61. package/dist/kit/Tile.js.map +1 -1
  62. package/dist/kit/messages.d.ts +13 -0
  63. package/dist/kit/messages.js +7 -1
  64. package/dist/kit/messages.js.map +1 -1
  65. package/dist/kit/uploads.d.ts +2 -1
  66. package/dist/kit/uploads.js +1 -1
  67. package/dist/kit/uploads.js.map +1 -1
  68. package/dist/kit/waveform.js.map +1 -1
  69. package/dist/markdown.js.map +1 -1
  70. package/dist/marks.js +2 -3
  71. package/dist/marks.js.map +1 -1
  72. package/dist/surface/Form.js +1 -1
  73. package/dist/surface/Markdown.js +1 -1
  74. package/dist/surface/Markdown.js.map +1 -1
  75. package/dist/surface/Surface.js +43 -4
  76. package/dist/surface/Surface.js.map +1 -1
  77. package/dist/surface/scope.d.ts +1 -1
  78. package/dist/surface/scope.js.map +1 -1
  79. package/dist/surface/values.js +1 -1
  80. package/dist/surface/values.js.map +1 -1
  81. package/dist/tint.d.ts +1 -1
  82. package/dist/tint.js +1 -1
  83. package/dist/tint.js.map +1 -1
  84. package/dist/types.d.ts +11 -0
  85. package/dist/types.js.map +1 -1
  86. package/dist/useConversation.d.ts +2 -0
  87. package/dist/useConversation.js +16 -0
  88. package/dist/useConversation.js.map +1 -1
  89. package/dist/usePolled.js +1 -1
  90. package/dist/usePolled.js.map +1 -1
  91. package/dist/voice/webgl.js +1 -1
  92. package/dist/voice/webgl.js.map +1 -1
  93. package/dist/widget.js +17 -16
  94. package/package.json +1 -1
  95. package/src/AgentAbout.tsx +14 -3
  96. package/src/AgentChat.tsx +203 -1
  97. package/src/AgentSpace.tsx +89 -13
  98. package/src/AgentTasks.tsx +2 -2
  99. package/src/Threads.tsx +218 -0
  100. package/src/VoiceCall.tsx +1 -1
  101. package/src/about.ts +42 -144
  102. package/src/automation/cron.ts +1 -1
  103. package/src/automation/marks.tsx +13 -2
  104. package/src/automation/messages.ts +12 -0
  105. package/src/automation/types.ts +58 -118
  106. package/src/automation/when.ts +7 -1
  107. package/src/blocks.ts +25 -0
  108. package/src/browser.ts +4 -4
  109. package/src/call.ts +1 -1
  110. package/src/client.ts +26 -10
  111. package/src/contract.ts +1934 -0
  112. package/src/credentials.ts +2 -2
  113. package/src/dev.ts +1 -1
  114. package/src/es.ts +29 -0
  115. package/src/frames.ts +3 -1
  116. package/src/index.ts +10 -1
  117. package/src/kit/AudioPlayer.tsx +1 -1
  118. package/src/kit/Choices.tsx +1 -1
  119. package/src/kit/FileField.tsx +1 -1
  120. package/src/kit/Popover.tsx +1 -1
  121. package/src/kit/Tile.tsx +1 -1
  122. package/src/kit/messages.ts +20 -0
  123. package/src/kit/uploads.ts +2 -2
  124. package/src/kit/waveform.ts +1 -1
  125. package/src/markdown.ts +1 -1
  126. package/src/marks.tsx +3 -123
  127. package/src/styles.css +206 -0
  128. package/src/surface/Markdown.tsx +1 -1
  129. package/src/surface/Surface.tsx +53 -4
  130. package/src/surface/scope.ts +3 -1
  131. package/src/surface/values.ts +5 -5
  132. package/src/tint.ts +1 -1
  133. package/src/types.ts +11 -0
  134. package/src/useConversation.ts +10 -0
  135. package/src/usePolled.ts +2 -2
  136. package/src/voice/webgl.ts +1 -1
  137. package/src/widget/element.tsx +13 -4
  138. package/src/widget/widget.css +13 -0
@@ -0,0 +1,218 @@
1
+ import { ArrowLeftIcon, PlusIcon } from "@phosphor-icons/react";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+
4
+ import { AgentChat, type AgentChatProps } from "./AgentChat";
5
+ import { classes } from "./classes";
6
+ import type { Client } from "./client";
7
+ import { Button } from "./kit/Button";
8
+ import type { Conversation as Thread } from "./types";
9
+
10
+ /** What the person's threads say; a host gives its own, in its language. */
11
+ export interface ThreadMessages {
12
+ /** Over the chat, to open the list; and the list's title. */
13
+ open: string;
14
+ title: string;
15
+ back: string;
16
+ /** Starts another conversation with the agent. */
17
+ new: string;
18
+ /** A thread nothing names yet. */
19
+ untitled: string;
20
+ /** Beside a thread: how many of the agent's messages are unread; that it waits on them. */
21
+ unread: (count: number) => string;
22
+ waiting: string;
23
+ empty: string;
24
+ }
25
+
26
+ export const THREAD_MESSAGES: ThreadMessages = {
27
+ open: "Conversations",
28
+ title: "Your conversations",
29
+ back: "Back to the conversation",
30
+ new: "New conversation",
31
+ untitled: "New conversation",
32
+ unread: (count) => (count === 1 ? "1 unread message" : `${count} unread messages`),
33
+ waiting: "Waiting for you",
34
+ empty: "Nothing here yet.",
35
+ };
36
+
37
+ export type ThreadPart =
38
+ | "sc-threads"
39
+ | "sc-threads__head"
40
+ | "sc-threads__title"
41
+ | "sc-threads__list"
42
+ | "sc-threads__item"
43
+ | "sc-threads__item--current"
44
+ | "sc-threads__name"
45
+ | "sc-threads__badge"
46
+ | "sc-threads__dot"
47
+ | "sc-threads__empty";
48
+
49
+ /** How often the person's threads are read again, for what is unread. */
50
+ export const THREADS_POLL_MS = 20_000;
51
+
52
+ /** The person's threads with an agent, and what of them waits on the person. */
53
+ export interface Unread {
54
+ /** Newest first; null until read, and whenever they can't be. */
55
+ threads: Thread[] | null;
56
+ /** Every unread message of the agent's, across the threads. */
57
+ unread: number;
58
+ /** Whether a thread waits on the person (a question, their yes). */
59
+ waiting: boolean;
60
+ refresh: () => Promise<void>;
61
+ }
62
+
63
+ /**
64
+ * The threads the person the client speaks for has with the agent, read now, again every
65
+ * `THREADS_POLL_MS`, when the page comes back into sight, and on `refresh`: what draws a dot on
66
+ * a launcher, a count beside a tab. `enabled` off reads nothing.
67
+ */
68
+ export function useUnread(client: Client, agentId: string, enabled = true): Unread {
69
+ const [threads, setThreads] = useState<Thread[] | null>(null);
70
+ const live = useRef(true);
71
+ const refresh = useCallback(async () => {
72
+ try {
73
+ const read = await client.conversations.list(agentId);
74
+ if (live.current) setThreads(read);
75
+ } catch {
76
+ if (live.current) setThreads(null);
77
+ }
78
+ }, [client, agentId]);
79
+ useEffect(() => {
80
+ live.current = true;
81
+ if (!enabled) return undefined;
82
+ void refresh();
83
+ const timer = setInterval(() => void refresh(), THREADS_POLL_MS);
84
+ const shown = () => {
85
+ if (document.visibilityState === "visible") void refresh();
86
+ };
87
+ document.addEventListener("visibilitychange", shown);
88
+ return () => {
89
+ live.current = false;
90
+ clearInterval(timer);
91
+ document.removeEventListener("visibilitychange", shown);
92
+ };
93
+ }, [enabled, refresh]);
94
+ const read = enabled ? threads : null;
95
+ return {
96
+ threads: read,
97
+ unread: (read ?? []).reduce((sum, thread) => sum + (thread.unread ?? 0), 0),
98
+ waiting: (read ?? []).some((thread) => thread.waiting_on_person === true),
99
+ refresh,
100
+ };
101
+ }
102
+
103
+ export interface ThreadsProps {
104
+ /** The threads, newest first (`useUnread`'s). */
105
+ threads: readonly Thread[];
106
+ /** The one open now, marked. */
107
+ current?: string | null | undefined;
108
+ onSelect: (id: string) => void;
109
+ /** Starts another; without it, no button for it. */
110
+ onNew?: (() => void) | undefined;
111
+ /** The way back to the open conversation; without it, none. */
112
+ onBack?: (() => void) | undefined;
113
+ messages?: Partial<ThreadMessages> | undefined;
114
+ classNames?: Partial<Record<ThreadPart, string>> | undefined;
115
+ }
116
+
117
+ /**
118
+ * The person's threads with the agent: each by its title, how many of the agent's messages in
119
+ * it are unread, a dot when it waits on them; the open one marked; another to start.
120
+ */
121
+ export function Threads({
122
+ threads,
123
+ current = null,
124
+ onSelect,
125
+ onNew,
126
+ onBack,
127
+ messages,
128
+ classNames,
129
+ }: ThreadsProps) {
130
+ const words = { ...THREAD_MESSAGES, ...messages };
131
+ return (
132
+ <section aria-label={words.title} part="threads" className={classes(classNames, "sc-threads")}>
133
+ <header className={classes(classNames, "sc-threads__head")}>
134
+ {onBack && (
135
+ <Button
136
+ tone="ghost"
137
+ size="sm"
138
+ icon={ArrowLeftIcon}
139
+ aria-label={words.back}
140
+ title={words.back}
141
+ onClick={onBack}
142
+ />
143
+ )}
144
+ <h3 className={classes(classNames, "sc-threads__title")}>{words.title}</h3>
145
+ {onNew && (
146
+ <Button tone="ghost" size="sm" icon={PlusIcon} onClick={onNew}>
147
+ {words.new}
148
+ </Button>
149
+ )}
150
+ </header>
151
+ {threads.length === 0 ? (
152
+ <p className={classes(classNames, "sc-threads__empty")}>{words.empty}</p>
153
+ ) : (
154
+ <ul className={classes(classNames, "sc-threads__list")}>
155
+ {threads.map((thread) => {
156
+ const unread = thread.unread ?? 0;
157
+ const open = thread.id === current;
158
+ return (
159
+ <li key={thread.id}>
160
+ <button
161
+ type="button"
162
+ aria-current={open || undefined}
163
+ className={classes(
164
+ classNames,
165
+ "sc-threads__item",
166
+ ...(open ? (["sc-threads__item--current"] as const) : []),
167
+ )}
168
+ onClick={() => {
169
+ onSelect(thread.id);
170
+ }}
171
+ >
172
+ <span className={classes(classNames, "sc-threads__name")}>
173
+ {thread.title ?? words.untitled}
174
+ </span>
175
+ {unread > 0 ? (
176
+ <span
177
+ aria-label={words.unread(unread)}
178
+ className={classes(classNames, "sc-threads__badge")}
179
+ >
180
+ {unread}
181
+ </span>
182
+ ) : (
183
+ thread.waiting_on_person === true && (
184
+ <span
185
+ role="img"
186
+ aria-label={words.waiting}
187
+ className={classes(classNames, "sc-threads__dot")}
188
+ />
189
+ )
190
+ )}
191
+ </button>
192
+ </li>
193
+ );
194
+ })}
195
+ </ul>
196
+ )}
197
+ </section>
198
+ );
199
+ }
200
+
201
+ /**
202
+ * A conversation between a person and one agent, as the API reads it (`types.ts`): one name for
203
+ * the shape and for the component that shows one.
204
+ */
205
+ export type Conversation = Thread;
206
+
207
+ export type ConversationProps = Omit<AgentChatProps, "conversationId"> & {
208
+ /** The conversation to show, by its id. */
209
+ id: string;
210
+ };
211
+
212
+ /**
213
+ * One conversation, for a host that lays out its own threads: the chat (`AgentChat`), which reads
214
+ * what comes as it shows it on a person's page, so their `unread` follows.
215
+ */
216
+ export function Conversation({ id, ...chat }: ConversationProps) {
217
+ return <AgentChat conversationId={id} {...chat} />;
218
+ }
package/src/VoiceCall.tsx CHANGED
@@ -92,7 +92,7 @@ export const VOICE_CALL_MESSAGES: VoiceCallMessages = {
92
92
  },
93
93
  builder: {
94
94
  title: (name) => `${name} doesn't take calls`,
95
- help: "A squad's builder only writes. Call one of the squad's agents.",
95
+ help: "The builder only writes. Call one of the agents.",
96
96
  },
97
97
  refused: {
98
98
  title: (name) => `${name} can't take this call`,
package/src/about.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  /**
2
2
  * Qué puede: what an agent says about itself and the facts it rests on (`GET /agents/{id}/about`,
3
3
  * `POST /agents/{id}/describe`). The words are the model's, written from the agent's folder and
4
- * stale the moment it changes; the facts are the platform's, read each time.
4
+ * stale the moment it changes; the facts are the platform's, read each time. Their types are the
5
+ * contract's (`contract.ts`).
5
6
  */
6
7
 
8
+ import type * as C from "./contract";
9
+
7
10
  /** The marks the package draws (a topic's, an automation's kind, a note's tone). */
8
11
  export const ICONS = [
9
12
  "message",
@@ -30,89 +33,33 @@ export const ICONS = [
30
33
 
31
34
  export type Icon = (typeof ICONS)[number];
32
35
 
33
- /** One automation as the agent tells it: what it does then, and when. */
34
- export interface Does {
35
- /** The automation's id. */
36
- automation: string;
37
- text: string;
38
- /** When it runs, the way a person says it: "Cada día a las 8:00". */
39
- when: string;
40
- }
36
+ /** One automation as the agent tells it: what it does then, and when ("Cada día a las 8:00"). */
37
+ export type Does = C.Does;
41
38
 
42
39
  /** What the agent says about itself: a lead, what it does, what it asks leave for. */
43
- export interface About {
44
- /** Two or three sentences, first person, in the owner's language. */
45
- summary: string;
46
- does: Does[];
47
- asks: string[];
48
- }
40
+ export type About = C.About;
49
41
 
50
- export type ActionSource = "default" | "library" | "own";
51
-
52
- export interface ActionFact {
53
- name: string;
54
- description: string;
55
- source: ActionSource;
56
- on: boolean;
57
- needs_approval: boolean;
58
- destructive: boolean;
59
- /** Its input as the model gets it (JSON Schema); left out by an API from before. */
60
- input_schema?: Readonly<Record<string, unknown>> | undefined;
61
- }
42
+ export type ActionSource = C.ActionRowOut["source"];
62
43
 
63
- export type AutomationKind = "schedule" | "webhook" | "event";
64
-
65
- /** Something the agent does on its own: at a time, when another system calls, on an event. */
66
- export interface AutomationFact {
67
- id: string;
68
- /** Its file's name, `automations/<name>.py`: how its page is reached. */
69
- name: string;
70
- kind: AutomationKind;
71
- title: string;
72
- /** What it does, in the owner's words. */
73
- summary: string;
74
- /** The same words, for a reader of the older shape. */
75
- say: string;
76
- /** A cron line and its time zone, for one that runs at a time. */
77
- schedule?: string | null | undefined;
78
- timezone?: string | null | undefined;
79
- /** Where another system calls it, for a webhook (a path on the API). */
80
- url?: string | null | undefined;
81
- /** For one on an app's event: the app (the connection's name), the event as its provider
82
- * names it, and the app as its mark is drawn (`composio:gmail`, the provider's logo). */
83
- app?: string | null | undefined;
84
- /** The app as people write it (`Google Calendar`). */
85
- app_title?: string | null | undefined;
86
- event?: string | null | undefined;
87
- provider?: string | undefined;
88
- icon?: string | null | undefined;
89
- /** Off: declared, but it doesn't run. */
90
- on: boolean;
91
- next_run_at?: string | null | undefined;
92
- }
44
+ /** One of its actions: where it comes from, whether it is on and asks first, its input. */
45
+ export type ActionFact = C.ActionRowOut;
93
46
 
47
+ export type AutomationKind = C.FactAutomation["kind"];
48
+
49
+ /** Something the agent does on its own: at a time, when another system calls, on an app's event
50
+ * (with the app's name and mark), on a message. */
51
+ export type AutomationFact = C.FactAutomation;
52
+
53
+ /** Who brings an app: one of the providers, an MCP server, the business's own API. */
94
54
  export type Provider = "arcade" | "composio" | "mcp" | "api";
95
55
 
96
- export interface ConnectionFact {
97
- provider: Provider;
98
- name: string;
99
- /** The app, as the provider names it (`gmail`). */
100
- toolkit?: string | undefined;
101
- /** The app as people write it (`Google Calendar`). */
102
- title?: string | undefined;
103
- /** pending · active · error · disconnected */
104
- status?: string | undefined;
105
- /** The provider's names of what the agent may do in it (`Gmail.SendEmail`). */
106
- actions: string[];
107
- /** What the provider calls each of them for people (`List Events`), when it says. */
108
- titles?: Readonly<Record<string, string>> | undefined;
109
- /** A URL to the app's own mark, when the provider gives one. */
110
- icon?: string | null | undefined;
111
- }
56
+ /** An app it was given: its name and mark, and its tools, with their names for people
57
+ * (`titles`) and as the model calls them (`called`). */
58
+ export type ConnectionFact = C.FactConnection;
112
59
 
113
60
  /** An app of the agent's as people write it: its provider's name, else its alias made words. */
114
61
  export const appTitle = (connection: ConnectionFact): string =>
115
- connection.title ?? toolName(connection.name);
62
+ connection.title || toolName(connection.name);
116
63
 
117
64
  /** A tool of an app as people read it: its provider's name for it, else its own made words. */
118
65
  export const toolTitle = (connection: ConnectionFact, action: string): string =>
@@ -143,7 +90,10 @@ export function actionWords(name: string): string {
143
90
  /** The longest name the model takes for a tool (`app/connections` cuts there too). */
144
91
  const MAX_TOOL_NAME = 64;
145
92
 
146
- /** `gmail` + `Gmail.SendEmail` → `gmail__Gmail_SendEmail`: the tool the model is given. */
93
+ /**
94
+ * `gmail` + `Gmail.SendEmail` → `gmail__Gmail_SendEmail`: the tool the model is given.
95
+ * @deprecated The facts say it: `ConnectionFact.called`.
96
+ */
147
97
  export const generatedName = (alias: string, action: string): string =>
148
98
  `${alias}__${action.replace(/[^A-Za-z0-9_]/g, "_")}`.slice(0, MAX_TOOL_NAME);
149
99
 
@@ -156,7 +106,7 @@ export function appSteps(connections: readonly ConnectionFact[]): Record<string,
156
106
  return Object.fromEntries(
157
107
  connections.flatMap((connection) =>
158
108
  connection.actions.map((action) => [
159
- generatedName(connection.name, action),
109
+ connection.called[action] ?? generatedName(connection.name, action),
160
110
  `${toolTitle(connection, action)} (${appTitle(connection)})`,
161
111
  ]),
162
112
  ),
@@ -165,85 +115,33 @@ export function appSteps(connections: readonly ConnectionFact[]): Record<string,
165
115
 
166
116
  export type ChannelKind = "whatsapp" | "instagram" | "email" | "sms" | "web" | "phone";
167
117
 
168
- export interface ChannelFact {
169
- kind: ChannelKind;
170
- name: string;
171
- status: string;
172
- }
118
+ export type ChannelFact = C.FactChannel;
173
119
 
174
120
  /** A file the agent can read: its own, or one of the organization's, shared with every agent. */
175
- export interface FileFact {
176
- path: string;
177
- size: number;
178
- /** Text, Markdown, JSON, YAML or PDF, read by `search_files`; anything else is only kept. */
179
- searchable: boolean;
180
- /** The organization's, not the agent's own. */
181
- shared: boolean;
182
- }
121
+ export type FileFact = C.FactFile;
183
122
 
184
- /** A line the agent kept with `remember`. */
185
- export interface MemoryFact {
186
- id: string;
187
- /** The agent that keeps it; the contact it is about, when it is about one. */
188
- agent_id?: string | undefined;
189
- contact_id?: string | null | undefined;
190
- text: string;
191
- created_at: string;
192
- }
123
+ /** A line the agent kept with `remember`: its own, or about the contact it names. */
124
+ export type MemoryFact = C.MemoryOut;
193
125
 
194
- /** A key the agent may use: its own, or one of the organization's, shared with every agent. */
195
- export interface VaultFact {
196
- name: string;
197
- /** The hosts it may be sent to. */
198
- hosts?: string[] | undefined;
199
- /** The organization's, not the agent's own. */
200
- shared?: boolean | undefined;
201
- }
126
+ /** A key the agent may use: its own, or one of the organization's its access gives it. */
127
+ export type VaultFact = C.FactKey;
202
128
 
203
129
  /** A table of the organization's the agent may read or write (an agenda, the clients). */
204
- export interface DataFact {
205
- table: string;
206
- /** Its name for people, when it has one. */
207
- title?: string | null | undefined;
208
- can: string[];
209
- }
130
+ export type DataFact = C.FactTable;
210
131
 
211
- export interface AskFact {
212
- agent_id: string;
213
- name: string;
214
- }
132
+ export type AskFact = C.FactAsk;
215
133
 
216
- export type DeviceKind = "extension" | "installer";
134
+ export type DeviceKind = C.FactDevice["kind"];
217
135
 
218
- export interface DeviceFact {
219
- kind: DeviceKind;
220
- name: string;
221
- status: string;
222
- }
136
+ export type DeviceFact = C.FactDevice;
223
137
 
224
- /** What the agent has, every list present from day one; one whose phase has not come is empty. */
225
- export interface Facts {
226
- actions: ActionFact[];
227
- automations: AutomationFact[];
228
- connections: ConnectionFact[];
229
- channels: ChannelFact[];
230
- /** Its own first, then the organization's shared. */
231
- files: FileFact[];
232
- /** Newest first. */
233
- memories: MemoryFact[];
234
- vault: VaultFact[];
235
- data: DataFact[];
236
- asks: AskFact[];
237
- devices: DeviceFact[];
238
- }
138
+ /** What the agent has, every list present from day one; one whose phase has not come is empty:
139
+ * its files its own first, its memories newest first. */
140
+ export type Facts = C.Facts;
239
141
 
240
- export interface AboutOut {
241
- /** Null until the agent has written about itself once. */
242
- about: About | null;
243
- /** When the words were written; null when the folder changed since, so they are stale. */
244
- about_at: string | null;
245
- facts: Facts;
246
- }
142
+ /** What it says (null until written once; `about_at` null when the folder changed since, so the
143
+ * words are stale) and the facts. */
144
+ export type AboutOut = C.AboutOut;
247
145
 
248
146
  /**
249
147
  * What the panel lists of the facts beside what the agent does on its own, gathered into a few
@@ -1,5 +1,5 @@
1
1
  /**
2
- * A schedule's cron line, read into what it fires at: the moments of a day (a squad's day, an
2
+ * A schedule's cron line, read into what it fires at: the moments of a day (the agents' day, an
3
3
  * automation's next runs) and the sentence that says it (`whenOf`). Five fields (minute, hour,
4
4
  * day of the month, month, day of the week) with `*`, lists, ranges, steps and English names, as
5
5
  * the API's croniter reads them; anything past that is not read (null).
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ArrowBendDownRightIcon,
2
3
  BellIcon,
3
4
  BrainIcon,
4
5
  ChatCircleIcon,
@@ -8,7 +9,9 @@ import {
8
9
  FileTextIcon,
9
10
  FlaskIcon,
10
11
  GlobeIcon,
12
+ HandTapIcon,
11
13
  LightningIcon,
14
+ PlugsConnectedIcon,
12
15
  SparkleIcon,
13
16
  TableIcon,
14
17
  WebhooksLogoIcon,
@@ -51,9 +54,13 @@ export function AppMark({
51
54
  const KINDS: Readonly<Record<Exclude<Trigger["kind"], "event">, Icon>> = {
52
55
  schedule: ClockIcon,
53
56
  webhook: WebhooksLogoIcon,
57
+ platform: ChatCircleIcon,
58
+ manual: HandTapIcon,
59
+ after: ArrowBendDownRightIcon,
54
60
  };
55
61
 
56
- /** What starts an automation, as a mark: a clock, a webhook, the app whose event it waits for. */
62
+ /** What starts an automation, as a mark: a clock, a webhook, a message, the app whose event it
63
+ * waits for. */
57
64
  export function TriggerMark({
58
65
  trigger,
59
66
  size,
@@ -69,12 +76,16 @@ export function TriggerMark({
69
76
  return <AppMark name={name} icon={trigger.icon} size={size} apps={apps} />;
70
77
  }
71
78
 
72
- /** What started a run: its time, a call, its app's event, a chat with the agent, a test. */
79
+ /** What started a run: its time, a call, its app's event, a message, a chat with the agent, a
80
+ * test. */
73
81
  const BY: Readonly<Record<Exclude<RunBy, "event">, Icon>> = {
74
82
  schedule: ClockIcon,
75
83
  webhook: WebhooksLogoIcon,
84
+ platform: ChatCircleIcon,
76
85
  agent: ChatCircleIcon,
77
86
  test: FlaskIcon,
87
+ api: PlugsConnectedIcon,
88
+ after: ArrowBendDownRightIcon,
78
89
  };
79
90
 
80
91
  export function ByMark({
@@ -66,6 +66,12 @@ export interface AutomationMessages {
66
66
  /** What another kind of trigger waits for. */
67
67
  webhook: string;
68
68
  event: (app: string | null, event: string | null) => string;
69
+ /** One of the platform's events: a contact's message stored on a channel. */
70
+ platform: string;
71
+ /** Only started by hand: the agent, the business's app, a button. */
72
+ manual: string;
73
+ /** When another of the agent's automations ends well, by its name. */
74
+ after: (automation: string | null) => string;
69
75
  /** When it runs next, after when it runs: the day, and the time when the line doesn't say it. */
70
76
  next: (day: DayRef, time: string | null) => string;
71
77
  /** How it stands, on its pill. */
@@ -124,6 +130,9 @@ export const AUTOMATION_MESSAGES: AutomationMessages = {
124
130
  on: (often, days) => `${often}, ${days.charAt(0).toLowerCase()}${days.slice(1)}`,
125
131
  custom: "On a schedule of its own",
126
132
  webhook: "When another system calls it",
133
+ platform: "When a message arrives",
134
+ manual: "When someone starts it",
135
+ after: (automation) => (automation ? `After “${automation}”` : "After another automation"),
127
136
  event: (app, event) =>
128
137
  event ? `When ${event} in ${app ?? "an app"}` : `On an event in ${app ?? "an app"}`,
129
138
  next: (day, time) => {
@@ -171,8 +180,11 @@ export const AUTOMATION_MESSAGES: AutomationMessages = {
171
180
  schedule: "scheduled",
172
181
  webhook: "webhook",
173
182
  event: app ? `${app} event` : "event",
183
+ platform: "a message",
174
184
  agent: "you asked in the chat",
175
185
  test: "test",
186
+ api: "your app",
187
+ after: "after another",
176
188
  })[by],
177
189
  statuses: {
178
190
  running: "Running",