@signalcore/ui 1.0.0-beta.0 → 1.0.0-beta.2

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 (114) hide show
  1. package/README.md +8 -1
  2. package/dist/AgentAbout.js +7 -4
  3. package/dist/AgentAbout.js.map +1 -1
  4. package/dist/AgentChat.js +10 -2
  5. package/dist/AgentChat.js.map +1 -1
  6. package/dist/AgentTasks.js +2 -1
  7. package/dist/AgentTasks.js.map +1 -1
  8. package/dist/VoiceCall.js +1 -1
  9. package/dist/VoiceCall.js.map +1 -1
  10. package/dist/about.d.ts +34 -144
  11. package/dist/about.js +6 -8
  12. package/dist/about.js.map +1 -1
  13. package/dist/automation/cron.d.ts +1 -1
  14. package/dist/automation/cron.js.map +1 -1
  15. package/dist/automation/marks.js +7 -3
  16. package/dist/automation/marks.js.map +1 -1
  17. package/dist/automation/messages.d.ts +2 -0
  18. package/dist/automation/messages.js +2 -0
  19. package/dist/automation/messages.js.map +1 -1
  20. package/dist/automation/types.d.ts +25 -128
  21. package/dist/automation/types.js +36 -0
  22. package/dist/automation/types.js.map +1 -0
  23. package/dist/automation/when.d.ts +1 -1
  24. package/dist/automation/when.js +5 -1
  25. package/dist/automation/when.js.map +1 -1
  26. package/dist/blocks.d.ts +23 -1
  27. package/dist/browser.js +2 -2
  28. package/dist/browser.js.map +1 -1
  29. package/dist/call.d.ts +1 -1
  30. package/dist/call.js.map +1 -1
  31. package/dist/contract.d.ts +262 -0
  32. package/dist/credentials.js.map +1 -1
  33. package/dist/dev.js +1 -1
  34. package/dist/dev.js.map +1 -1
  35. package/dist/es.js +9 -1
  36. package/dist/es.js.map +1 -1
  37. package/dist/index.d.ts +3 -3
  38. package/dist/index.js +2 -1
  39. package/dist/kit/AudioPlayer.js +1 -1
  40. package/dist/kit/AudioPlayer.js.map +1 -1
  41. package/dist/kit/Choices.js +1 -1
  42. package/dist/kit/Choices.js.map +1 -1
  43. package/dist/kit/FileField.js +1 -1
  44. package/dist/kit/FileField.js.map +1 -1
  45. package/dist/kit/Popover.js.map +1 -1
  46. package/dist/kit/Tile.d.ts +1 -1
  47. package/dist/kit/Tile.js +1 -1
  48. package/dist/kit/Tile.js.map +1 -1
  49. package/dist/kit/messages.d.ts +13 -0
  50. package/dist/kit/messages.js +7 -1
  51. package/dist/kit/messages.js.map +1 -1
  52. package/dist/kit/uploads.d.ts +2 -1
  53. package/dist/kit/uploads.js +1 -1
  54. package/dist/kit/uploads.js.map +1 -1
  55. package/dist/kit/waveform.js.map +1 -1
  56. package/dist/markdown.js.map +1 -1
  57. package/dist/marks.js +2 -3
  58. package/dist/marks.js.map +1 -1
  59. package/dist/surface/Markdown.js +1 -1
  60. package/dist/surface/Markdown.js.map +1 -1
  61. package/dist/surface/Surface.js +43 -4
  62. package/dist/surface/Surface.js.map +1 -1
  63. package/dist/surface/scope.d.ts +1 -1
  64. package/dist/surface/scope.js.map +1 -1
  65. package/dist/surface/values.js +1 -1
  66. package/dist/surface/values.js.map +1 -1
  67. package/dist/tint.d.ts +1 -1
  68. package/dist/tint.js +1 -1
  69. package/dist/tint.js.map +1 -1
  70. package/dist/types.d.ts +7 -0
  71. package/dist/types.js.map +1 -1
  72. package/dist/usePolled.js +1 -1
  73. package/dist/usePolled.js.map +1 -1
  74. package/dist/voice/webgl.js +1 -1
  75. package/dist/voice/webgl.js.map +1 -1
  76. package/dist/widget.js +14 -14
  77. package/package.json +1 -1
  78. package/src/AgentAbout.tsx +10 -3
  79. package/src/AgentChat.tsx +20 -3
  80. package/src/AgentTasks.tsx +2 -2
  81. package/src/VoiceCall.tsx +1 -1
  82. package/src/about.ts +42 -144
  83. package/src/automation/cron.ts +1 -1
  84. package/src/automation/marks.tsx +6 -2
  85. package/src/automation/messages.ts +4 -0
  86. package/src/automation/types.ts +58 -118
  87. package/src/automation/when.ts +3 -1
  88. package/src/blocks.ts +25 -0
  89. package/src/browser.ts +4 -4
  90. package/src/call.ts +1 -1
  91. package/src/contract.ts +1720 -0
  92. package/src/credentials.ts +2 -2
  93. package/src/dev.ts +1 -1
  94. package/src/es.ts +8 -0
  95. package/src/index.ts +2 -0
  96. package/src/kit/AudioPlayer.tsx +1 -1
  97. package/src/kit/Choices.tsx +1 -1
  98. package/src/kit/FileField.tsx +1 -1
  99. package/src/kit/Popover.tsx +1 -1
  100. package/src/kit/Tile.tsx +1 -1
  101. package/src/kit/messages.ts +20 -0
  102. package/src/kit/uploads.ts +2 -2
  103. package/src/kit/waveform.ts +1 -1
  104. package/src/markdown.ts +1 -1
  105. package/src/marks.tsx +3 -123
  106. package/src/styles.css +24 -0
  107. package/src/surface/Markdown.tsx +1 -1
  108. package/src/surface/Surface.tsx +53 -4
  109. package/src/surface/scope.ts +3 -1
  110. package/src/surface/values.ts +5 -5
  111. package/src/tint.ts +1 -1
  112. package/src/types.ts +8 -0
  113. package/src/usePolled.ts +2 -2
  114. package/src/voice/webgl.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signalcore/ui",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "SignalCore's components for the people an agent serves: the chat, the call, the agent's space, and the <signalcore-chat> widget.",
5
5
  "keywords": [
6
6
  "signalcore",
@@ -150,7 +150,12 @@ export const ABOUT_MESSAGES: AboutMessages = {
150
150
  does: "What it does on its own",
151
151
  noAutomations: "Nothing on its own yet: it answers when someone writes to it.",
152
152
  paused: "Paused",
153
- kinds: { schedule: "At a time", webhook: "When called", event: "On an event" },
153
+ kinds: {
154
+ schedule: "At a time",
155
+ webhook: "When called",
156
+ event: "On an event",
157
+ platform: "On a message",
158
+ },
154
159
  topics: {
155
160
  apps: "Apps",
156
161
  tools: "Tools",
@@ -934,11 +939,13 @@ function Gone({ classNames, children }: { classNames: ClassNames; children: Reac
934
939
  return <p className={classes(classNames, "sc-about__empty")}>{children}</p>;
935
940
  }
936
941
 
937
- /** An automation's mark says its kind: a time, a call from another system, an event. */
942
+ /** An automation's mark says its kind: a time, a call from another system, an event, a
943
+ * message. */
938
944
  const KIND_ICONS: Readonly<Record<AutomationKind, Icon>> = {
939
945
  schedule: "clock",
940
946
  webhook: "code",
941
947
  event: "bell",
948
+ platform: "message",
942
949
  };
943
950
 
944
951
  /** An app's mark: the host's logo when it draws one, else the provider's, bare. */
@@ -1080,7 +1087,7 @@ function Automations({
1080
1087
  <Row
1081
1088
  key={automation.id}
1082
1089
  mark={
1083
- automation.provider === undefined ? (
1090
+ automation.provider === undefined || automation.provider === null ? (
1084
1091
  <Mark icon={GLYPHS[KIND_ICONS[automation.kind]]} />
1085
1092
  ) : (
1086
1093
  appMark(
package/src/AgentChat.tsx CHANGED
@@ -59,6 +59,7 @@ import type {
59
59
  Message,
60
60
  Request,
61
61
  Step,
62
+ StepApp,
62
63
  StepState,
63
64
  } from "./types";
64
65
  import {
@@ -1294,7 +1295,12 @@ function Reply({
1294
1295
  <BuilderStep step={step} words={words} classNames={classNames} />
1295
1296
  ) : (
1296
1297
  <>
1297
- <Mark state={step.state} action={step.action} classNames={classNames} />
1298
+ <Mark
1299
+ state={step.state}
1300
+ action={step.action}
1301
+ app={step.app ?? null}
1302
+ classNames={classNames}
1303
+ />
1298
1304
  <span>{words.steps[step.action] ?? actionWords(step.action)}</span>
1299
1305
  {/* What a step answered is the model's, in its words: only why it failed. */}
1300
1306
  {step.state === "failed" && step.output !== null && <small>{step.output}</small>}
@@ -1393,7 +1399,12 @@ function BuilderStep({
1393
1399
  }) {
1394
1400
  const row = (
1395
1401
  <>
1396
- <Mark state={step.state} action={step.action} classNames={classNames} />
1402
+ <Mark
1403
+ state={step.state}
1404
+ action={step.action}
1405
+ app={step.app ?? null}
1406
+ classNames={classNames}
1407
+ />
1397
1408
  <span>{words.steps[step.action] ?? actionWords(step.action)}</span>
1398
1409
  {step.state === "failed" && <em>{words.failed}</em>}
1399
1410
  </>
@@ -1417,16 +1428,22 @@ function BuilderStep({
1417
1428
  function Mark({
1418
1429
  state,
1419
1430
  action,
1431
+ app,
1420
1432
  classNames,
1421
1433
  }: {
1422
1434
  state: StepState;
1423
1435
  action: string;
1436
+ app: StepApp | null;
1424
1437
  classNames: ClassNames;
1425
1438
  }) {
1426
1439
  const Glyph = stepGlyph(action);
1440
+ // A connected app's step wears the app's logo once done; only an https one is loaded.
1441
+ const logo = app?.icon && /^https:\/\//i.test(app.icon) ? app.icon : null;
1427
1442
  return (
1428
1443
  <span aria-hidden className={classes(classNames, "sc-chat__mark")}>
1429
- {state === "done" ? (
1444
+ {state === "done" && logo !== null ? (
1445
+ <img src={logo} alt="" loading="lazy" draggable={false} />
1446
+ ) : state === "done" ? (
1430
1447
  <Glyph />
1431
1448
  ) : state === "running" ? null : (
1432
1449
  <svg viewBox="0 0 14 14" fill="none">
@@ -2,7 +2,7 @@ import { ArrowLeftIcon, TrashIcon } from "@phosphor-icons/react";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
 
4
4
  import { Automation } from "./automation/Automation";
5
- import type { Task } from "./automation/types";
5
+ import { taskCard, type Task } from "./automation/types";
6
6
  import { classes } from "./classes";
7
7
  import type { Client } from "./client";
8
8
  import { Button } from "./kit/Button";
@@ -139,7 +139,7 @@ export function AgentTasks({
139
139
  {tasks.map((task) => (
140
140
  <Automation
141
141
  key={task.id}
142
- automation={task}
142
+ automation={taskCard(task)}
143
143
  runs={task.runs}
144
144
  switching={busy === task.id}
145
145
  onSwitch={(on) => void change(task, () => client.tasks.switch(agentId, task.id, on))}
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).
@@ -51,9 +51,11 @@ export function AppMark({
51
51
  const KINDS: Readonly<Record<Exclude<Trigger["kind"], "event">, Icon>> = {
52
52
  schedule: ClockIcon,
53
53
  webhook: WebhooksLogoIcon,
54
+ platform: ChatCircleIcon,
54
55
  };
55
56
 
56
- /** What starts an automation, as a mark: a clock, a webhook, the app whose event it waits for. */
57
+ /** What starts an automation, as a mark: a clock, a webhook, a message, the app whose event it
58
+ * waits for. */
57
59
  export function TriggerMark({
58
60
  trigger,
59
61
  size,
@@ -69,10 +71,12 @@ export function TriggerMark({
69
71
  return <AppMark name={name} icon={trigger.icon} size={size} apps={apps} />;
70
72
  }
71
73
 
72
- /** What started a run: its time, a call, its app's event, a chat with the agent, a test. */
74
+ /** What started a run: its time, a call, its app's event, a message, a chat with the agent, a
75
+ * test. */
73
76
  const BY: Readonly<Record<Exclude<RunBy, "event">, Icon>> = {
74
77
  schedule: ClockIcon,
75
78
  webhook: WebhooksLogoIcon,
79
+ platform: ChatCircleIcon,
76
80
  agent: ChatCircleIcon,
77
81
  test: FlaskIcon,
78
82
  };
@@ -66,6 +66,8 @@ 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;
69
71
  /** When it runs next, after when it runs: the day, and the time when the line doesn't say it. */
70
72
  next: (day: DayRef, time: string | null) => string;
71
73
  /** How it stands, on its pill. */
@@ -124,6 +126,7 @@ export const AUTOMATION_MESSAGES: AutomationMessages = {
124
126
  on: (often, days) => `${often}, ${days.charAt(0).toLowerCase()}${days.slice(1)}`,
125
127
  custom: "On a schedule of its own",
126
128
  webhook: "When another system calls it",
129
+ platform: "When a message arrives",
127
130
  event: (app, event) =>
128
131
  event ? `When ${event} in ${app ?? "an app"}` : `On an event in ${app ?? "an app"}`,
129
132
  next: (day, time) => {
@@ -171,6 +174,7 @@ export const AUTOMATION_MESSAGES: AutomationMessages = {
171
174
  schedule: "scheduled",
172
175
  webhook: "webhook",
173
176
  event: app ? `${app} event` : "event",
177
+ platform: "a message",
174
178
  agent: "you asked in the chat",
175
179
  test: "test",
176
180
  })[by],
@@ -1,146 +1,86 @@
1
1
  /**
2
2
  * An agent's automations and their runs, as the API gives them (v3/AUTOMATIONS.md): what starts
3
- * each one, the steps its code names, the table it moves, and every run with its record. Written
4
- * by hand, one to one with the API's answers; times are ISO 8601 in UTC.
3
+ * each one, the steps its code names, the table it moves, and every run with its record. The
4
+ * contract's own types (`contract.ts`, generated from the API's); times are ISO 8601 in UTC.
5
5
  */
6
6
 
7
+ import type * as C from "../contract";
8
+
7
9
  /**
8
10
  * What a step uses, as the manifest reads it from the code before any run: an app, the model,
9
11
  * the agent, the owner's inbox, a message to a contact on a channel (`sc.send`), a table, the web.
10
12
  */
11
- export interface Use {
12
- kind: "app" | "ai" | "agent" | "notify" | "send" | "data" | "http";
13
- /** An app's: the connection's name (its alias). */
14
- app: string | null;
15
- /** An app's: its display name. */
16
- title: string | null;
17
- /** An app's: its logo (https), when known. */
18
- icon: string | null;
19
- }
13
+ export type Use = C.Use;
20
14
 
21
15
  /** A step of the code (`sc.step("…")`), in the code's order, with what it uses. */
22
- export interface Step {
23
- name: string;
24
- uses: Use[];
25
- }
16
+ export type Step = C.Step;
26
17
 
27
- /** What starts an automation: a time (cron, on a zone's clock), a call to its URL, an app's event. */
28
- export interface Trigger {
29
- kind: "schedule" | "webhook" | "event";
30
- /** Five-field cron. */
31
- schedule: string | null;
32
- /** IANA zone. */
33
- timezone: string | null;
34
- /** The webhook's full URL. */
35
- url: string | null;
36
- /** An event's app: the connection's name, its display name, its logo. */
37
- app: string | null;
38
- app_title: string | null;
39
- /** The provider's event slug, and the event in words when the provider gives them. */
40
- event: string | null;
41
- event_title: string | null;
42
- icon: string | null;
43
- }
18
+ /** What starts an automation: a time (cron, on a zone's clock), a call to its URL, an app's
19
+ * event, one of the platform's. */
20
+ export type Trigger = C.TriggerView;
44
21
 
45
- /** The table an automation moves, as counts of its rows per value of one field. */
46
- export interface Board {
47
- table: string;
48
- /** The table's title. */
49
- title: string;
50
- /** The field the rows are counted by. */
51
- field: string;
52
- /** Per value, biggest first, at most 8. */
53
- counts: { value: string; count: number }[];
54
- }
22
+ /** The table an automation moves, as counts of its rows per value of one field (biggest first,
23
+ * at most 8). */
24
+ export type Board = C.Board;
55
25
 
56
- export type RunStatus = "running" | "waiting" | "done" | "failed" | "skipped";
26
+ export type RunStatus = C.RunOut["status"];
57
27
 
58
- /** What started a run: its time, a call, an app's event, the agent in a chat, a test. */
59
- export type RunBy = "schedule" | "webhook" | "event" | "agent" | "test";
28
+ /** What started a run: its time, a call, an app's event, the platform, the agent, a test. */
29
+ export type RunBy = C.RunOut["by"];
60
30
 
61
31
  /** One start of an automation, whatever started it. */
62
- export interface Run {
63
- id: string;
64
- agent_id: string;
65
- /** The automation's name. */
66
- automation: string;
67
- /** The automation's title when it ran. */
68
- title: string;
69
- by: RunBy;
70
- /** Started by the agent: the conversation it was asked in. */
71
- conversation_id: string | null;
72
- status: RunStatus;
73
- /** What the code returned: the run's one line. */
74
- summary: string | null;
75
- /** Why it failed, in words, naming the step: "Paró en «…»: …". */
76
- error: string | null;
77
- /** A test: what would change the world was recorded, not done. */
78
- dry: boolean;
79
- started_at: string;
80
- ended_at: string | null;
81
- tokens_in: number;
82
- tokens_out: number;
83
- /** The conversations it opened. */
84
- opened: string[];
85
- }
32
+ export type Run = C.RunOut;
86
33
 
87
34
  /** One call of a run's record, in the order it was made. */
88
- export interface RunStep {
89
- seq: number;
90
- /** The `sc.step` it ran in. */
91
- step: string | null;
92
- /**
93
- * `tool:<app>.<TOOL>` · `ai` · `notify` · `send` · `agent.start` · `data.find` · `data.add` ·
94
- * `data.update` · `http` · `files.search` · `memory.remember` · `memory.recall`.
95
- */
96
- call: string;
97
- /** Both trimmed. */
98
- input: unknown;
99
- output: unknown;
100
- error: string | null;
101
- ms: number;
102
- at: string;
103
- /** A test's write: recorded, not done. */
104
- would: boolean;
105
- }
35
+ export type RunStep = C.RunStepOut;
106
36
 
107
37
  /** A run with its record (`GET /runs/{id}`). */
108
- export type RunRecord = Run & { steps: RunStep[] };
38
+ export type RunRecord = C.RunDetailOut;
109
39
 
110
- export type AutomationState = "active" | "paused" | "failing";
40
+ export type AutomationState = C.AutomationOut["state"];
111
41
 
112
42
  /** One automation: `automations/<name>.py` in the agent's folder, with its trigger and its state. */
113
- export interface Automation {
114
- /** Its trigger's id. */
115
- id: string;
116
- agent_id: string;
117
- /** Its file's name; unique per agent. */
118
- name: string;
119
- title: string;
120
- /** What it does, in the owner's words. */
121
- summary: string;
122
- trigger: Trigger;
123
- on: boolean;
124
- next_run_at: string | null;
125
- steps: Step[];
126
- board: Board | null;
127
- /** `failing`: its last finished real run failed. */
128
- state: AutomationState;
129
- /** Its newest run, tests included. */
130
- last_run: Run | null;
131
- }
43
+ export type Automation = C.AutomationOut;
132
44
 
133
45
  /** An automation with its newest runs (`GET /agents/{id}/automations/{name}`: 20; in a block: 5). */
134
- export type AutomationView = Automation & { runs: Run[] };
46
+ export type AutomationView = C.AutomationDetailOut;
135
47
 
136
48
  /**
137
- * A task the agent runs for one contact (`GET /agents/{id}/tasks`): set up in words in a
138
- * conversation with them, read as an automation is (its instruction is its `summary`, its trigger
139
- * a schedule: a cron line, or none for a task once at `next_run_at`), with its newest five runs.
49
+ * A task the agent runs for one contact (`GET /agents/{id}/tasks`): an instance of an automation
50
+ * for contacts (`automation`), or of the platform's instruction (its words in `inputs`), on a
51
+ * schedule (a cron line, or once at `next_run_at`), with its newest five runs.
140
52
  */
141
- export type Task = AutomationView & {
142
- contact_id: string;
143
- /** The conversation it runs in: the one it was set up in. */
144
- conversation_id: string | null;
145
- created_at: string;
146
- };
53
+ export type Task = C.TaskOut;
54
+
55
+ /** A task as the automation card draws it, from what it is: its words its summary, its trigger
56
+ * its schedule, failing when its last finished real run failed. */
57
+ export function taskCard(task: Task): AutomationView {
58
+ const ended = task.runs.filter((run) => run.status !== "running" && run.status !== "waiting");
59
+ const last = ended.find((run) => !run.dry);
60
+ const words = task.inputs["instruction"];
61
+ return {
62
+ id: task.id,
63
+ agent_id: task.agent_id,
64
+ name: task.automation ?? "instruction",
65
+ title: task.title,
66
+ summary: typeof words === "string" ? words : "",
67
+ trigger: {
68
+ kind: "schedule",
69
+ schedule: task.schedule,
70
+ timezone: task.timezone,
71
+ url: null,
72
+ app: null,
73
+ app_title: null,
74
+ event: null,
75
+ event_title: null,
76
+ icon: null,
77
+ },
78
+ on: task.on,
79
+ next_run_at: task.next_run_at,
80
+ steps: [],
81
+ board: null,
82
+ state: !task.on ? "paused" : last?.status === "failed" ? "failing" : "active",
83
+ last_run: task.runs[0] ?? null,
84
+ runs: task.runs,
85
+ };
86
+ }
@@ -24,7 +24,7 @@ export interface When {
24
24
  timed: boolean;
25
25
  }
26
26
 
27
- /** A trigger in words: its schedule as a sentence, a webhook's call, an app's event. */
27
+ /** A trigger in words: its schedule as a sentence, a webhook's call, an app's event, a message. */
28
28
  export function whenOf(trigger: Trigger, words: AutomationMessages, code: string): When {
29
29
  switch (trigger.kind) {
30
30
  case "schedule":
@@ -33,6 +33,8 @@ export function whenOf(trigger: Trigger, words: AutomationMessages, code: string
33
33
  : scheduleOf(trigger.schedule, words, code);
34
34
  case "webhook":
35
35
  return { text: words.webhook, timed: false };
36
+ case "platform":
37
+ return { text: words.platform, timed: false };
36
38
  case "event":
37
39
  return {
38
40
  text: words.event(trigger.app_title ?? trigger.app, trigger.event_title),