@signalcore/ui 1.0.0-beta.2 → 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.
- package/README.md +47 -21
- package/dist/AgentAbout.js +6 -2
- package/dist/AgentAbout.js.map +1 -1
- package/dist/AgentChat.d.ts +7 -1
- package/dist/AgentChat.js +154 -2
- package/dist/AgentChat.js.map +1 -1
- package/dist/AgentSpace.d.ts +12 -3
- package/dist/AgentSpace.js +53 -11
- package/dist/AgentSpace.js.map +1 -1
- package/dist/Threads.d.ts +73 -0
- package/dist/Threads.js +140 -0
- package/dist/Threads.js.map +1 -0
- package/dist/automation/marks.js +7 -3
- package/dist/automation/marks.js.map +1 -1
- package/dist/automation/messages.d.ts +4 -0
- package/dist/automation/messages.js +5 -1
- package/dist/automation/messages.js.map +1 -1
- package/dist/automation/when.js +8 -0
- package/dist/automation/when.js.map +1 -1
- package/dist/client.d.ts +14 -4
- package/dist/client.js +7 -2
- package/dist/client.js.map +1 -1
- package/dist/contract.d.ts +9 -4
- package/dist/es.d.ts +2 -0
- package/dist/es.js +22 -3
- package/dist/es.js.map +1 -1
- package/dist/frames.d.ts +7 -1
- package/dist/frames.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +5 -4
- package/dist/surface/Form.js +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.js.map +1 -1
- package/dist/useConversation.d.ts +2 -0
- package/dist/useConversation.js +16 -0
- package/dist/useConversation.js.map +1 -1
- package/dist/widget.js +17 -16
- package/package.json +1 -1
- package/src/AgentAbout.tsx +4 -0
- package/src/AgentChat.tsx +203 -1
- package/src/AgentSpace.tsx +89 -13
- package/src/Threads.tsx +218 -0
- package/src/automation/marks.tsx +7 -0
- package/src/automation/messages.ts +8 -0
- package/src/automation/when.ts +4 -0
- package/src/client.ts +26 -10
- package/src/contract.ts +240 -26
- package/src/es.ts +21 -0
- package/src/frames.ts +3 -1
- package/src/index.ts +9 -1
- package/src/styles.css +191 -0
- package/src/types.ts +11 -0
- package/src/useConversation.ts +10 -0
- package/src/widget/element.tsx +13 -4
- package/src/widget/widget.css +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","names":[],"sources":["../../src/automation/messages.ts"],"sourcesContent":["import type { AutomationState, RunBy, RunStatus, Use } from \"./types\";\n\n/**\n * A day as a person says it beside a time: today, yesterday, tomorrow, a weekday within the\n * week (`name` as the locale names it, short or long), or a date further away.\n */\nexport type DayRef =\n { kind: \"today\" | \"yesterday\" | \"tomorrow\" } | { kind: \"weekday\" | \"date\"; name: string };\n\n/** A tool's call by what it does, read from its name: what a run's record says it did. */\nexport type Verb = \"search\" | \"send\" | \"create\" | \"update\" | \"remove\" | \"use\";\n\n/** What a run did, call by call, in words; `would` is a test's write, recorded and not done. */\nexport interface CallMessages {\n /** An app's tool, by what its name says it does, with the app's name. */\n tool: (verb: Verb, app: string, would: boolean) => string;\n /** One model call: it reads and writes for real in a test too. */\n ai: string;\n /** A line in the owner's inbox. */\n notify: (would: boolean) => string;\n /**\n * A message to a contact on one of the agent's channels: the channel's kind when the record\n * says it (`whatsapp`, `instagram`, `sms`), and who to (a number; \"\" for a contact by its id).\n */\n send: (channel: string | null, to: string, would: boolean) => string;\n /** A conversation of the agent opened for what needs judgement or a person. */\n start: (would: boolean) => string;\n /** A table's rows looked up, added, changed, by the table's title. */\n find: (table: string) => string;\n add: (table: string, would: boolean) => string;\n change: (table: string, would: boolean) => string;\n /** A call to another system, by its host. */\n http: (host: string, would: boolean) => string;\n /** The organization's files searched. */\n files: string;\n /** One of its files read, kept, or its files listed, by the file's name. */\n read: (file: string) => string;\n wrote: (file: string, would: boolean) => string;\n listed: string;\n /** A line kept in, and one looked up from, what the agent learned. */\n remember: (would: boolean) => string;\n recall: string;\n}\n\n/** The words of an automation and its runs: the trigger in words, its state, its runs. */\nexport interface AutomationMessages {\n /** When it runs, from its cron line (`whenOf`): the days, then the times. */\n daily: string;\n /** Monday to Friday. */\n weekdays: string;\n /** Saturday and Sunday. */\n weekends: string;\n /** Some days of the week, by their names. */\n weekly: (days: string[]) => string;\n /** Some days of the month. */\n monthly: (days: number[]) => string;\n /** The times it runs at, after the days (\"9:00\", as the locale writes it). */\n at: (times: string[]) => string;\n /** Every few minutes or hours, all day or `between` two times. */\n every: (count: number, unit: \"minute\" | \"hour\") => string;\n between: (from: string, to: string) => string;\n /** A frequency on some days only: \"every 15 minutes\" and \"on weekdays\". */\n on: (often: string, days: string) => string;\n /** A schedule the sentence can't say. */\n custom: string;\n /** What another kind of trigger waits for. */\n webhook: string;\n event: (app: string | null, event: string | null) => string;\n /** One of the platform's events: a contact's message stored on a channel. */\n platform: string;\n /** When it runs next, after when it runs: the day, and the time when the line doesn't say it. */\n next: (day: DayRef, time: string | null) => string;\n /** How it stands, on its pill. */\n states: Readonly<Record<AutomationState, string>>;\n /** Its switch, for screen readers. */\n switchLabel: string;\n /** Over its steps, the table it moves, its runs. */\n steps: string;\n runs: string;\n /** In the place of its runs, when there are none yet. */\n noRuns: string;\n /** What a step uses, other than an app (which goes by its name). */\n uses: Readonly<Record<Exclude<Use[\"kind\"], \"app\">, string>>;\n /** The values of the table past the ones shown: \"+3\". */\n more: (count: number) => string;\n /** An automation the agent named that is not there (removed, renamed). */\n gone: string;\n /** When a run started, beside what started it. */\n moment: (day: DayRef, time: string) => string;\n /** What started a run; an event's by its app's name, when known. */\n by: (by: RunBy, app: string | null) => string;\n /** How a run stands. */\n statuses: Readonly<Record<RunStatus, string>>;\n /** A test's line: what the run returned, though it changed nothing. */\n dry: (summary: string) => string;\n /** How long a run took. */\n took: (ms: number) => string;\n /** Over the conversations a run opened, and each one's link. */\n opened: string;\n conversation: (index: number) => string;\n /** The conversation the agent was asked in, for a run it started. */\n askedIn: string;\n /** A run that called nothing. */\n noCalls: string;\n /** Over the calls made outside any step. */\n outside: string;\n /** A call made several times in a row: \"×12\". */\n times: (count: number) => string;\n calls: CallMessages;\n}\n\nconst plural = (count: number, one: string, many: string) =>\n count === 1 ? one : `${count} ${many}`;\n\n/** English: what the package says until a host gives its own words. */\nexport const AUTOMATION_MESSAGES: AutomationMessages = {\n daily: \"Every day\",\n weekdays: \"Every weekday\",\n weekends: \"Every weekend\",\n weekly: (days) =>\n days.length === 1 ? `Every ${days[0] ?? \"\"}` : `On ${new Intl.ListFormat(\"en\").format(days)}`,\n monthly: (days) => `On day ${new Intl.ListFormat(\"en\").format(days.map(String))} of every month`,\n at: (times) => `at ${new Intl.ListFormat(\"en\").format(times)}`,\n every: (count, unit) => `Every ${plural(count, unit, `${unit}s`)}`,\n between: (from, to) => `from ${from} to ${to}`,\n on: (often, days) => `${often}, ${days.charAt(0).toLowerCase()}${days.slice(1)}`,\n custom: \"On a schedule of its own\",\n webhook: \"When another system calls it\",\n platform: \"When a message arrives\",\n event: (app, event) =>\n event ? `When ${event} in ${app ?? \"an app\"}` : `On an event in ${app ?? \"an app\"}`,\n next: (day, time) => {\n const at = time === null ? \"\" : ` at ${time}`;\n switch (day.kind) {\n case \"today\":\n return `next today${at}`;\n case \"tomorrow\":\n return `next tomorrow${at}`;\n case \"yesterday\":\n return `next${at}`;\n default:\n return `next on ${day.name}${at}`;\n }\n },\n states: { active: \"On\", paused: \"Paused\", failing: \"Last run failed\" },\n switchLabel: \"On\",\n steps: \"Steps\",\n runs: \"Runs\",\n noRuns: \"It hasn't run yet.\",\n uses: {\n ai: \"AI\",\n agent: \"Agent\",\n notify: \"Inbox\",\n send: \"Message\",\n data: \"Table\",\n http: \"Web\",\n },\n more: (count) => `+${count}`,\n gone: \"This automation is no longer there.\",\n moment: (day, time) => {\n switch (day.kind) {\n case \"today\":\n return `Today ${time}`;\n case \"yesterday\":\n return `Yesterday ${time}`;\n case \"tomorrow\":\n return `Tomorrow ${time}`;\n default:\n return `${day.name} ${time}`;\n }\n },\n by: (by, app) =>\n ({\n schedule: \"scheduled\",\n webhook: \"webhook\",\n event: app ? `${app} event` : \"event\",\n platform: \"a message\",\n agent: \"you asked in the chat\",\n test: \"test\",\n })[by],\n statuses: {\n running: \"Running\",\n waiting: \"Waiting\",\n done: \"Done\",\n failed: \"Failed\",\n skipped: \"Skipped\",\n },\n dry: (summary) => `Test: ${summary}`,\n took: (ms) =>\n ms < 60_000 ? `${Math.max(1, Math.round(ms / 1000))} s` : `${Math.round(ms / 60_000)} min`,\n opened: \"Conversations it opened\",\n conversation: (index) => `Conversation ${index}`,\n askedIn: \"The conversation you asked in\",\n noCalls: \"It didn't call anything.\",\n outside: \"Outside the steps\",\n times: (count) => `×${count}`,\n calls: {\n tool: (verb, app, would) => {\n const done = {\n search: `Searched ${app}`,\n send: `Sent with ${app}`,\n create: `Created in ${app}`,\n update: `Changed in ${app}`,\n remove: `Removed in ${app}`,\n use: `Used ${app}`,\n }[verb];\n return would && verb !== \"search\"\n ? `Would have ${done.charAt(0).toLowerCase()}${done.slice(1)}`\n : done;\n },\n ai: \"Used AI\",\n notify: (would) => (would ? \"Would have told you in the inbox\" : \"Told you in the inbox\"),\n send: (channel, to, would) => {\n const what =\n { whatsapp: \"a WhatsApp\", sms: \"an SMS\", instagram: \"an Instagram message\" }[\n channel ?? \"\"\n ] ?? \"a message\";\n const sent = `${what} to ${to || \"a contact\"}`;\n return would ? `Would have sent ${sent}` : `Sent ${sent}`;\n },\n start: (would) => (would ? \"Would have opened a conversation\" : \"Opened a conversation\"),\n find: (table) => `Looked up ${table}`,\n add: (table, would) =>\n would ? `Would have added a row to ${table}` : `Added a row to ${table}`,\n change: (table, would) =>\n would ? `Would have changed a row of ${table}` : `Changed a row of ${table}`,\n http: (host, would) => (would ? `Would have called ${host}` : `Called ${host}`),\n files: \"Searched the files\",\n read: (file) => `Read ${file}`,\n wrote: (file, would) => (would ? `Would have saved ${file}` : `Saved ${file}`),\n listed: \"Looked through its files\",\n remember: (would) => (would ? \"Would have kept a memory\" : \"Kept a memory\"),\n recall: \"Searched what it learned\",\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"messages.js","names":[],"sources":["../../src/automation/messages.ts"],"sourcesContent":["import type { AutomationState, RunBy, RunStatus, Use } from \"./types\";\n\n/**\n * A day as a person says it beside a time: today, yesterday, tomorrow, a weekday within the\n * week (`name` as the locale names it, short or long), or a date further away.\n */\nexport type DayRef =\n { kind: \"today\" | \"yesterday\" | \"tomorrow\" } | { kind: \"weekday\" | \"date\"; name: string };\n\n/** A tool's call by what it does, read from its name: what a run's record says it did. */\nexport type Verb = \"search\" | \"send\" | \"create\" | \"update\" | \"remove\" | \"use\";\n\n/** What a run did, call by call, in words; `would` is a test's write, recorded and not done. */\nexport interface CallMessages {\n /** An app's tool, by what its name says it does, with the app's name. */\n tool: (verb: Verb, app: string, would: boolean) => string;\n /** One model call: it reads and writes for real in a test too. */\n ai: string;\n /** A line in the owner's inbox. */\n notify: (would: boolean) => string;\n /**\n * A message to a contact on one of the agent's channels: the channel's kind when the record\n * says it (`whatsapp`, `instagram`, `sms`), and who to (a number; \"\" for a contact by its id).\n */\n send: (channel: string | null, to: string, would: boolean) => string;\n /** A conversation of the agent opened for what needs judgement or a person. */\n start: (would: boolean) => string;\n /** A table's rows looked up, added, changed, by the table's title. */\n find: (table: string) => string;\n add: (table: string, would: boolean) => string;\n change: (table: string, would: boolean) => string;\n /** A call to another system, by its host. */\n http: (host: string, would: boolean) => string;\n /** The organization's files searched. */\n files: string;\n /** One of its files read, kept, or its files listed, by the file's name. */\n read: (file: string) => string;\n wrote: (file: string, would: boolean) => string;\n listed: string;\n /** A line kept in, and one looked up from, what the agent learned. */\n remember: (would: boolean) => string;\n recall: string;\n}\n\n/** The words of an automation and its runs: the trigger in words, its state, its runs. */\nexport interface AutomationMessages {\n /** When it runs, from its cron line (`whenOf`): the days, then the times. */\n daily: string;\n /** Monday to Friday. */\n weekdays: string;\n /** Saturday and Sunday. */\n weekends: string;\n /** Some days of the week, by their names. */\n weekly: (days: string[]) => string;\n /** Some days of the month. */\n monthly: (days: number[]) => string;\n /** The times it runs at, after the days (\"9:00\", as the locale writes it). */\n at: (times: string[]) => string;\n /** Every few minutes or hours, all day or `between` two times. */\n every: (count: number, unit: \"minute\" | \"hour\") => string;\n between: (from: string, to: string) => string;\n /** A frequency on some days only: \"every 15 minutes\" and \"on weekdays\". */\n on: (often: string, days: string) => string;\n /** A schedule the sentence can't say. */\n custom: string;\n /** What another kind of trigger waits for. */\n webhook: string;\n event: (app: string | null, event: string | null) => string;\n /** One of the platform's events: a contact's message stored on a channel. */\n platform: string;\n /** Only started by hand: the agent, the business's app, a button. */\n manual: string;\n /** When another of the agent's automations ends well, by its name. */\n after: (automation: string | null) => string;\n /** When it runs next, after when it runs: the day, and the time when the line doesn't say it. */\n next: (day: DayRef, time: string | null) => string;\n /** How it stands, on its pill. */\n states: Readonly<Record<AutomationState, string>>;\n /** Its switch, for screen readers. */\n switchLabel: string;\n /** Over its steps, the table it moves, its runs. */\n steps: string;\n runs: string;\n /** In the place of its runs, when there are none yet. */\n noRuns: string;\n /** What a step uses, other than an app (which goes by its name). */\n uses: Readonly<Record<Exclude<Use[\"kind\"], \"app\">, string>>;\n /** The values of the table past the ones shown: \"+3\". */\n more: (count: number) => string;\n /** An automation the agent named that is not there (removed, renamed). */\n gone: string;\n /** When a run started, beside what started it. */\n moment: (day: DayRef, time: string) => string;\n /** What started a run; an event's by its app's name, when known. */\n by: (by: RunBy, app: string | null) => string;\n /** How a run stands. */\n statuses: Readonly<Record<RunStatus, string>>;\n /** A test's line: what the run returned, though it changed nothing. */\n dry: (summary: string) => string;\n /** How long a run took. */\n took: (ms: number) => string;\n /** Over the conversations a run opened, and each one's link. */\n opened: string;\n conversation: (index: number) => string;\n /** The conversation the agent was asked in, for a run it started. */\n askedIn: string;\n /** A run that called nothing. */\n noCalls: string;\n /** Over the calls made outside any step. */\n outside: string;\n /** A call made several times in a row: \"×12\". */\n times: (count: number) => string;\n calls: CallMessages;\n}\n\nconst plural = (count: number, one: string, many: string) =>\n count === 1 ? one : `${count} ${many}`;\n\n/** English: what the package says until a host gives its own words. */\nexport const AUTOMATION_MESSAGES: AutomationMessages = {\n daily: \"Every day\",\n weekdays: \"Every weekday\",\n weekends: \"Every weekend\",\n weekly: (days) =>\n days.length === 1 ? `Every ${days[0] ?? \"\"}` : `On ${new Intl.ListFormat(\"en\").format(days)}`,\n monthly: (days) => `On day ${new Intl.ListFormat(\"en\").format(days.map(String))} of every month`,\n at: (times) => `at ${new Intl.ListFormat(\"en\").format(times)}`,\n every: (count, unit) => `Every ${plural(count, unit, `${unit}s`)}`,\n between: (from, to) => `from ${from} to ${to}`,\n on: (often, days) => `${often}, ${days.charAt(0).toLowerCase()}${days.slice(1)}`,\n custom: \"On a schedule of its own\",\n webhook: \"When another system calls it\",\n platform: \"When a message arrives\",\n manual: \"When someone starts it\",\n after: (automation) => (automation ? `After “${automation}”` : \"After another automation\"),\n event: (app, event) =>\n event ? `When ${event} in ${app ?? \"an app\"}` : `On an event in ${app ?? \"an app\"}`,\n next: (day, time) => {\n const at = time === null ? \"\" : ` at ${time}`;\n switch (day.kind) {\n case \"today\":\n return `next today${at}`;\n case \"tomorrow\":\n return `next tomorrow${at}`;\n case \"yesterday\":\n return `next${at}`;\n default:\n return `next on ${day.name}${at}`;\n }\n },\n states: { active: \"On\", paused: \"Paused\", failing: \"Last run failed\" },\n switchLabel: \"On\",\n steps: \"Steps\",\n runs: \"Runs\",\n noRuns: \"It hasn't run yet.\",\n uses: {\n ai: \"AI\",\n agent: \"Agent\",\n notify: \"Inbox\",\n send: \"Message\",\n data: \"Table\",\n http: \"Web\",\n },\n more: (count) => `+${count}`,\n gone: \"This automation is no longer there.\",\n moment: (day, time) => {\n switch (day.kind) {\n case \"today\":\n return `Today ${time}`;\n case \"yesterday\":\n return `Yesterday ${time}`;\n case \"tomorrow\":\n return `Tomorrow ${time}`;\n default:\n return `${day.name} ${time}`;\n }\n },\n by: (by, app) =>\n ({\n schedule: \"scheduled\",\n webhook: \"webhook\",\n event: app ? `${app} event` : \"event\",\n platform: \"a message\",\n agent: \"you asked in the chat\",\n test: \"test\",\n api: \"your app\",\n after: \"after another\",\n })[by],\n statuses: {\n running: \"Running\",\n waiting: \"Waiting\",\n done: \"Done\",\n failed: \"Failed\",\n skipped: \"Skipped\",\n },\n dry: (summary) => `Test: ${summary}`,\n took: (ms) =>\n ms < 60_000 ? `${Math.max(1, Math.round(ms / 1000))} s` : `${Math.round(ms / 60_000)} min`,\n opened: \"Conversations it opened\",\n conversation: (index) => `Conversation ${index}`,\n askedIn: \"The conversation you asked in\",\n noCalls: \"It didn't call anything.\",\n outside: \"Outside the steps\",\n times: (count) => `×${count}`,\n calls: {\n tool: (verb, app, would) => {\n const done = {\n search: `Searched ${app}`,\n send: `Sent with ${app}`,\n create: `Created in ${app}`,\n update: `Changed in ${app}`,\n remove: `Removed in ${app}`,\n use: `Used ${app}`,\n }[verb];\n return would && verb !== \"search\"\n ? `Would have ${done.charAt(0).toLowerCase()}${done.slice(1)}`\n : done;\n },\n ai: \"Used AI\",\n notify: (would) => (would ? \"Would have told you in the inbox\" : \"Told you in the inbox\"),\n send: (channel, to, would) => {\n const what =\n { whatsapp: \"a WhatsApp\", sms: \"an SMS\", instagram: \"an Instagram message\" }[\n channel ?? \"\"\n ] ?? \"a message\";\n const sent = `${what} to ${to || \"a contact\"}`;\n return would ? `Would have sent ${sent}` : `Sent ${sent}`;\n },\n start: (would) => (would ? \"Would have opened a conversation\" : \"Opened a conversation\"),\n find: (table) => `Looked up ${table}`,\n add: (table, would) =>\n would ? `Would have added a row to ${table}` : `Added a row to ${table}`,\n change: (table, would) =>\n would ? `Would have changed a row of ${table}` : `Changed a row of ${table}`,\n http: (host, would) => (would ? `Would have called ${host}` : `Called ${host}`),\n files: \"Searched the files\",\n read: (file) => `Read ${file}`,\n wrote: (file, would) => (would ? `Would have saved ${file}` : `Saved ${file}`),\n listed: \"Looked through its files\",\n remember: (would) => (would ? \"Would have kept a memory\" : \"Kept a memory\"),\n recall: \"Searched what it learned\",\n },\n};\n"],"mappings":"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"}
|
package/dist/automation/when.js
CHANGED
|
@@ -29,6 +29,14 @@ function whenOf(trigger, words, code) {
|
|
|
29
29
|
text: words.platform,
|
|
30
30
|
timed: false
|
|
31
31
|
};
|
|
32
|
+
case "manual": return {
|
|
33
|
+
text: words.manual,
|
|
34
|
+
timed: false
|
|
35
|
+
};
|
|
36
|
+
case "after": return {
|
|
37
|
+
text: words.after(trigger.after ?? null),
|
|
38
|
+
timed: false
|
|
39
|
+
};
|
|
32
40
|
case "event": return {
|
|
33
41
|
text: words.event(trigger.app_title ?? trigger.app, trigger.event_title),
|
|
34
42
|
timed: false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"when.js","names":[],"sources":["../../src/automation/when.ts"],"sourcesContent":["/**\n * When an automation runs, and when one ran, as a person says it: its trigger in a sentence\n * (\"Cada día laborable a las 9:00\"), its next run (\"próxima mañana\"), the moment a run started\n * (\"Ayer 16:12\"), how long it took. The words are the host's (`AutomationMessages`); the locale's\n * code writes the times, the days and the lists. Pure, so it is tested without a page.\n */\n\nimport { parseCron, type Cron } from \"./cron\";\nimport type { AutomationMessages, DayRef } from \"./messages\";\nimport type { Automation, Trigger } from \"./types\";\n\n/** A time of day as the locale writes it (\"9:00\", \"9:00 AM\"), from a cron line's hour and minute. */\nexport function clockOf(hour: number, minute: number, code: string): string {\n return new Intl.DateTimeFormat(code, {\n hour: \"numeric\",\n minute: \"2-digit\",\n timeZone: \"UTC\",\n }).format(new Date(Date.UTC(2026, 0, 1, hour, minute)));\n}\n\n/** A trigger in words, and whether it names the one time of day it runs (so the next needs none). */\nexport interface When {\n text: string;\n timed: boolean;\n}\n\n/** A trigger in words: its schedule as a sentence, a webhook's call, an app's event, a message. */\nexport function whenOf(trigger: Trigger, words: AutomationMessages, code: string): When {\n switch (trigger.kind) {\n case \"schedule\":\n return trigger.schedule === null\n ? { text: words.custom, timed: false }\n : scheduleOf(trigger.schedule, words, code);\n case \"webhook\":\n return { text: words.webhook, timed: false };\n case \"platform\":\n return { text: words.platform, timed: false };\n case \"event\":\n return {\n text: words.event(trigger.app_title ?? trigger.app, trigger.event_title),\n timed: false,\n };\n }\n}\n\nconst sorted = (values: ReadonlySet<number>): number[] => [...values].sort((a, b) => a - b);\n\n/** Whether the values are every `step`-th one from `from` up to `to`: 0, 15, 30, 45. */\nfunction stepOf(values: number[]): number | null {\n if (values.length < 2) return null;\n const step = (values[1] ?? 0) - (values[0] ?? 0);\n return values.every((value, at) => value === (values[0] ?? 0) + at * step) ? step : null;\n}\n\n/** Monday first, as a week is read; Sunday is 0 in cron. */\nconst weekOrder = (day: number) => (day + 6) % 7;\n\nfunction weekdayName(day: number, code: string): string {\n // 4 January 2026 is a Sunday.\n return new Intl.DateTimeFormat(code, { weekday: \"long\", timeZone: \"UTC\" }).format(\n new Date(Date.UTC(2026, 0, 4 + day)),\n );\n}\n\n/** The days a line runs on, in words; null for what a sentence can't say. */\nfunction daysOf(cron: Cron, words: AutomationMessages, code: string): string | null {\n if (cron.months.size !== 12) return null;\n if (cron.anyDay && cron.anyWeekday) return words.daily;\n if (cron.anyDay) {\n const days = [...cron.weekdays].sort((a, b) => weekOrder(a) - weekOrder(b));\n const key = days.join(\",\");\n if (days.length === 7) return words.daily;\n if (key === \"1,2,3,4,5\") return words.weekdays;\n if (key === \"6,0\") return words.weekends;\n return words.weekly(days.map((day) => weekdayName(day, code)));\n }\n if (cron.anyWeekday) return words.monthly(sorted(cron.days));\n return null;\n}\n\n/** At most this many times are listed one by one; more read as a frequency. */\nconst LISTED = 4;\n\n/** The times a line runs at in a day: listed (\"a las 9:00\"), or how often (\"cada hora\"). */\nfunction timesOf(\n cron: Cron,\n words: AutomationMessages,\n code: string,\n): { text: string; listed: number } | null {\n const hours = sorted(cron.hours);\n const minutes = sorted(cron.minutes);\n const first = hours[0] ?? 0;\n const last = hours[hours.length - 1] ?? 0;\n if (hours.length * minutes.length <= LISTED) {\n const times = hours.flatMap((hour) => minutes.map((minute) => clockOf(hour, minute, code)));\n return { text: words.at(times), listed: times.length };\n }\n // Once in each of its hours, every few hours; or every few minutes through its hours.\n const minuteStep = minutes.length === 60 ? 1 : stepOf(minutes);\n const hourStep = hours.length === 24 || hours.length === 1 ? 1 : stepOf(hours);\n let often: string;\n if (minutes.length === 1 && hourStep !== null) {\n often = words.every(hourStep, \"hour\");\n } else if (minuteStep !== null && minutes[0] === 0 && 60 % minuteStep === 0 && hourStep === 1) {\n often = words.every(minuteStep, \"minute\");\n } else {\n return null;\n }\n // The whole day (\"cada 2 horas\"), or a part of it (\"cada hora de 8:00 a 18:00\").\n const whole = hourStep !== null && hours.length * hourStep === 24 && first < hourStep;\n if (whole) return { text: often, listed: 0 };\n const from = clockOf(first, minutes[0] ?? 0, code);\n const to = clockOf(last, minutes[minutes.length - 1] ?? 0, code);\n return { text: `${often} ${words.between(from, to)}`, listed: 0 };\n}\n\n/** A cron line as a sentence: its days, then its times or how often. */\nexport function scheduleOf(line: string, words: AutomationMessages, code: string): When {\n const cron = parseCron(line);\n const days = cron && daysOf(cron, words, code);\n const times = cron && timesOf(cron, words, code);\n if (!days || !times) return { text: words.custom, timed: false };\n if (times.listed > 0) return { text: `${days} ${times.text}`, timed: times.listed === 1 };\n return { text: days === words.daily ? times.text : words.on(times.text, days), timed: false };\n}\n\n/** A calendar day where the person is, as a count of days from the epoch's. */\nconst dayNumber = (moment: Date): number =>\n Math.round(\n (new Date(moment.getFullYear(), moment.getMonth(), moment.getDate()).getTime() -\n new Date(1970, 0, 1).getTime()) /\n 86_400_000,\n );\n\n/**\n * A moment's day beside `now`, where the person is: today, yesterday, tomorrow, a weekday within\n * the week, else its date (with its year when not this one).\n */\nexport function dayRefOf(\n moment: Date,\n now: Date,\n code: string,\n weekday: \"short\" | \"long\" = \"short\",\n): DayRef {\n const days = dayNumber(moment) - dayNumber(now);\n if (days === 0) return { kind: \"today\" };\n if (days === -1) return { kind: \"yesterday\" };\n if (days === 1) return { kind: \"tomorrow\" };\n if (Math.abs(days) < 7) {\n return { kind: \"weekday\", name: new Intl.DateTimeFormat(code, { weekday }).format(moment) };\n }\n return {\n kind: \"date\",\n name: new Intl.DateTimeFormat(code, {\n day: \"numeric\",\n month: \"short\",\n ...(moment.getFullYear() === now.getFullYear() ? {} : { year: \"numeric\" }),\n }).format(moment),\n };\n}\n\n/** A moment's time of day where the person is: \"9:00\". */\nexport const timeOf = (moment: Date, code: string): string =>\n new Intl.DateTimeFormat(code, { hour: \"numeric\", minute: \"2-digit\" }).format(moment);\n\n/** When a run started: \"Hoy 9:00\", \"Ayer 16:12\", \"Lun 9:00\", \"3 oct 9:00\". */\nexport function momentOf(at: Date, now: Date, words: AutomationMessages, code: string): string {\n return words.moment(dayRefOf(at, now, code), timeOf(at, code));\n}\n\n/**\n * The line under an automation's title: when it runs and, while it is on and has a next run,\n * when that is (\"Cada día laborable a las 9:00, próxima mañana\"). The next run's time is said\n * when the sentence doesn't already say it, and always when it is today.\n */\nexport function lineOf(\n automation: Pick<Automation, \"trigger\" | \"on\" | \"next_run_at\">,\n now: Date,\n words: AutomationMessages,\n code: string,\n): string {\n const when = whenOf(automation.trigger, words, code);\n if (!automation.on || automation.next_run_at === null) return when.text;\n const next = new Date(automation.next_run_at);\n const day = dayRefOf(next, now, code, \"long\");\n const time = when.timed && day.kind !== \"today\" ? null : timeOf(next, code);\n return `${when.text}, ${words.next(day, time)}`;\n}\n\n/** How long a run took, once it ended. */\nexport function tookOf(\n run: { started_at: string; ended_at: string | null },\n words: AutomationMessages,\n): string | null {\n if (run.ended_at === null) return null;\n return words.took(Math.max(0, Date.parse(run.ended_at) - Date.parse(run.started_at)));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"when.js","names":[],"sources":["../../src/automation/when.ts"],"sourcesContent":["/**\n * When an automation runs, and when one ran, as a person says it: its trigger in a sentence\n * (\"Cada día laborable a las 9:00\"), its next run (\"próxima mañana\"), the moment a run started\n * (\"Ayer 16:12\"), how long it took. The words are the host's (`AutomationMessages`); the locale's\n * code writes the times, the days and the lists. Pure, so it is tested without a page.\n */\n\nimport { parseCron, type Cron } from \"./cron\";\nimport type { AutomationMessages, DayRef } from \"./messages\";\nimport type { Automation, Trigger } from \"./types\";\n\n/** A time of day as the locale writes it (\"9:00\", \"9:00 AM\"), from a cron line's hour and minute. */\nexport function clockOf(hour: number, minute: number, code: string): string {\n return new Intl.DateTimeFormat(code, {\n hour: \"numeric\",\n minute: \"2-digit\",\n timeZone: \"UTC\",\n }).format(new Date(Date.UTC(2026, 0, 1, hour, minute)));\n}\n\n/** A trigger in words, and whether it names the one time of day it runs (so the next needs none). */\nexport interface When {\n text: string;\n timed: boolean;\n}\n\n/** A trigger in words: its schedule as a sentence, a webhook's call, an app's event, a message. */\nexport function whenOf(trigger: Trigger, words: AutomationMessages, code: string): When {\n switch (trigger.kind) {\n case \"schedule\":\n return trigger.schedule === null\n ? { text: words.custom, timed: false }\n : scheduleOf(trigger.schedule, words, code);\n case \"webhook\":\n return { text: words.webhook, timed: false };\n case \"platform\":\n return { text: words.platform, timed: false };\n case \"manual\":\n return { text: words.manual, timed: false };\n case \"after\":\n return { text: words.after(trigger.after ?? null), timed: false };\n case \"event\":\n return {\n text: words.event(trigger.app_title ?? trigger.app, trigger.event_title),\n timed: false,\n };\n }\n}\n\nconst sorted = (values: ReadonlySet<number>): number[] => [...values].sort((a, b) => a - b);\n\n/** Whether the values are every `step`-th one from `from` up to `to`: 0, 15, 30, 45. */\nfunction stepOf(values: number[]): number | null {\n if (values.length < 2) return null;\n const step = (values[1] ?? 0) - (values[0] ?? 0);\n return values.every((value, at) => value === (values[0] ?? 0) + at * step) ? step : null;\n}\n\n/** Monday first, as a week is read; Sunday is 0 in cron. */\nconst weekOrder = (day: number) => (day + 6) % 7;\n\nfunction weekdayName(day: number, code: string): string {\n // 4 January 2026 is a Sunday.\n return new Intl.DateTimeFormat(code, { weekday: \"long\", timeZone: \"UTC\" }).format(\n new Date(Date.UTC(2026, 0, 4 + day)),\n );\n}\n\n/** The days a line runs on, in words; null for what a sentence can't say. */\nfunction daysOf(cron: Cron, words: AutomationMessages, code: string): string | null {\n if (cron.months.size !== 12) return null;\n if (cron.anyDay && cron.anyWeekday) return words.daily;\n if (cron.anyDay) {\n const days = [...cron.weekdays].sort((a, b) => weekOrder(a) - weekOrder(b));\n const key = days.join(\",\");\n if (days.length === 7) return words.daily;\n if (key === \"1,2,3,4,5\") return words.weekdays;\n if (key === \"6,0\") return words.weekends;\n return words.weekly(days.map((day) => weekdayName(day, code)));\n }\n if (cron.anyWeekday) return words.monthly(sorted(cron.days));\n return null;\n}\n\n/** At most this many times are listed one by one; more read as a frequency. */\nconst LISTED = 4;\n\n/** The times a line runs at in a day: listed (\"a las 9:00\"), or how often (\"cada hora\"). */\nfunction timesOf(\n cron: Cron,\n words: AutomationMessages,\n code: string,\n): { text: string; listed: number } | null {\n const hours = sorted(cron.hours);\n const minutes = sorted(cron.minutes);\n const first = hours[0] ?? 0;\n const last = hours[hours.length - 1] ?? 0;\n if (hours.length * minutes.length <= LISTED) {\n const times = hours.flatMap((hour) => minutes.map((minute) => clockOf(hour, minute, code)));\n return { text: words.at(times), listed: times.length };\n }\n // Once in each of its hours, every few hours; or every few minutes through its hours.\n const minuteStep = minutes.length === 60 ? 1 : stepOf(minutes);\n const hourStep = hours.length === 24 || hours.length === 1 ? 1 : stepOf(hours);\n let often: string;\n if (minutes.length === 1 && hourStep !== null) {\n often = words.every(hourStep, \"hour\");\n } else if (minuteStep !== null && minutes[0] === 0 && 60 % minuteStep === 0 && hourStep === 1) {\n often = words.every(minuteStep, \"minute\");\n } else {\n return null;\n }\n // The whole day (\"cada 2 horas\"), or a part of it (\"cada hora de 8:00 a 18:00\").\n const whole = hourStep !== null && hours.length * hourStep === 24 && first < hourStep;\n if (whole) return { text: often, listed: 0 };\n const from = clockOf(first, minutes[0] ?? 0, code);\n const to = clockOf(last, minutes[minutes.length - 1] ?? 0, code);\n return { text: `${often} ${words.between(from, to)}`, listed: 0 };\n}\n\n/** A cron line as a sentence: its days, then its times or how often. */\nexport function scheduleOf(line: string, words: AutomationMessages, code: string): When {\n const cron = parseCron(line);\n const days = cron && daysOf(cron, words, code);\n const times = cron && timesOf(cron, words, code);\n if (!days || !times) return { text: words.custom, timed: false };\n if (times.listed > 0) return { text: `${days} ${times.text}`, timed: times.listed === 1 };\n return { text: days === words.daily ? times.text : words.on(times.text, days), timed: false };\n}\n\n/** A calendar day where the person is, as a count of days from the epoch's. */\nconst dayNumber = (moment: Date): number =>\n Math.round(\n (new Date(moment.getFullYear(), moment.getMonth(), moment.getDate()).getTime() -\n new Date(1970, 0, 1).getTime()) /\n 86_400_000,\n );\n\n/**\n * A moment's day beside `now`, where the person is: today, yesterday, tomorrow, a weekday within\n * the week, else its date (with its year when not this one).\n */\nexport function dayRefOf(\n moment: Date,\n now: Date,\n code: string,\n weekday: \"short\" | \"long\" = \"short\",\n): DayRef {\n const days = dayNumber(moment) - dayNumber(now);\n if (days === 0) return { kind: \"today\" };\n if (days === -1) return { kind: \"yesterday\" };\n if (days === 1) return { kind: \"tomorrow\" };\n if (Math.abs(days) < 7) {\n return { kind: \"weekday\", name: new Intl.DateTimeFormat(code, { weekday }).format(moment) };\n }\n return {\n kind: \"date\",\n name: new Intl.DateTimeFormat(code, {\n day: \"numeric\",\n month: \"short\",\n ...(moment.getFullYear() === now.getFullYear() ? {} : { year: \"numeric\" }),\n }).format(moment),\n };\n}\n\n/** A moment's time of day where the person is: \"9:00\". */\nexport const timeOf = (moment: Date, code: string): string =>\n new Intl.DateTimeFormat(code, { hour: \"numeric\", minute: \"2-digit\" }).format(moment);\n\n/** When a run started: \"Hoy 9:00\", \"Ayer 16:12\", \"Lun 9:00\", \"3 oct 9:00\". */\nexport function momentOf(at: Date, now: Date, words: AutomationMessages, code: string): string {\n return words.moment(dayRefOf(at, now, code), timeOf(at, code));\n}\n\n/**\n * The line under an automation's title: when it runs and, while it is on and has a next run,\n * when that is (\"Cada día laborable a las 9:00, próxima mañana\"). The next run's time is said\n * when the sentence doesn't already say it, and always when it is today.\n */\nexport function lineOf(\n automation: Pick<Automation, \"trigger\" | \"on\" | \"next_run_at\">,\n now: Date,\n words: AutomationMessages,\n code: string,\n): string {\n const when = whenOf(automation.trigger, words, code);\n if (!automation.on || automation.next_run_at === null) return when.text;\n const next = new Date(automation.next_run_at);\n const day = dayRefOf(next, now, code, \"long\");\n const time = when.timed && day.kind !== \"today\" ? null : timeOf(next, code);\n return `${when.text}, ${words.next(day, time)}`;\n}\n\n/** How long a run took, once it ended. */\nexport function tookOf(\n run: { started_at: string; ended_at: string | null },\n words: AutomationMessages,\n): string | null {\n if (run.ended_at === null) return null;\n return words.took(Math.max(0, Date.parse(run.ended_at) - Date.parse(run.started_at)));\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,QAAQ,MAAc,QAAgB,MAAsB;CAC1E,OAAO,IAAI,KAAK,eAAe,MAAM;EACnC,MAAM;EACN,QAAQ;EACR,UAAU;CACZ,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,CAAC;AACxD;;AASA,SAAgB,OAAO,SAAkB,OAA2B,MAAoB;CACtF,QAAQ,QAAQ,MAAhB;EACE,KAAK,YACH,OAAO,QAAQ,aAAa,OACxB;GAAE,MAAM,MAAM;GAAQ,OAAO;EAAM,IACnC,WAAW,QAAQ,UAAU,OAAO,IAAI;EAC9C,KAAK,WACH,OAAO;GAAE,MAAM,MAAM;GAAS,OAAO;EAAM;EAC7C,KAAK,YACH,OAAO;GAAE,MAAM,MAAM;GAAU,OAAO;EAAM;EAC9C,KAAK,UACH,OAAO;GAAE,MAAM,MAAM;GAAQ,OAAO;EAAM;EAC5C,KAAK,SACH,OAAO;GAAE,MAAM,MAAM,MAAM,QAAQ,SAAS,IAAI;GAAG,OAAO;EAAM;EAClE,KAAK,SACH,OAAO;GACL,MAAM,MAAM,MAAM,QAAQ,aAAa,QAAQ,KAAK,QAAQ,WAAW;GACvE,OAAO;EACT;CACJ;AACF;AAEA,MAAM,UAAU,WAA0C,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;;AAG1F,SAAS,OAAO,QAAiC;CAC/C,IAAI,OAAO,SAAS,GAAG,OAAO;CAC9B,MAAM,QAAQ,OAAO,MAAM,MAAM,OAAO,MAAM;CAC9C,OAAO,OAAO,OAAO,OAAO,OAAO,WAAW,OAAO,MAAM,KAAK,KAAK,IAAI,IAAI,OAAO;AACtF;;AAGA,MAAM,aAAa,SAAiB,MAAM,KAAK;AAE/C,SAAS,YAAY,KAAa,MAAsB;CAEtD,OAAO,IAAI,KAAK,eAAe,MAAM;EAAE,SAAS;EAAQ,UAAU;CAAM,CAAC,CAAC,CAAC,OACzE,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,IAAI,GAAG,CAAC,CACrC;AACF;;AAGA,SAAS,OAAO,MAAY,OAA2B,MAA6B;CAClF,IAAI,KAAK,OAAO,SAAS,IAAI,OAAO;CACpC,IAAI,KAAK,UAAU,KAAK,YAAY,OAAO,MAAM;CACjD,IAAI,KAAK,QAAQ;EACf,MAAM,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC;EAC1E,MAAM,MAAM,KAAK,KAAK,GAAG;EACzB,IAAI,KAAK,WAAW,GAAG,OAAO,MAAM;EACpC,IAAI,QAAQ,aAAa,OAAO,MAAM;EACtC,IAAI,QAAQ,OAAO,OAAO,MAAM;EAChC,OAAO,MAAM,OAAO,KAAK,KAAK,QAAQ,YAAY,KAAK,IAAI,CAAC,CAAC;CAC/D;CACA,IAAI,KAAK,YAAY,OAAO,MAAM,QAAQ,OAAO,KAAK,IAAI,CAAC;CAC3D,OAAO;AACT;;AAGA,MAAM,SAAS;;AAGf,SAAS,QACP,MACA,OACA,MACyC;CACzC,MAAM,QAAQ,OAAO,KAAK,KAAK;CAC/B,MAAM,UAAU,OAAO,KAAK,OAAO;CACnC,MAAM,QAAQ,MAAM,MAAM;CAC1B,MAAM,OAAO,MAAM,MAAM,SAAS,MAAM;CACxC,IAAI,MAAM,SAAS,QAAQ,UAAU,QAAQ;EAC3C,MAAM,QAAQ,MAAM,SAAS,SAAS,QAAQ,KAAK,WAAW,QAAQ,MAAM,QAAQ,IAAI,CAAC,CAAC;EAC1F,OAAO;GAAE,MAAM,MAAM,GAAG,KAAK;GAAG,QAAQ,MAAM;EAAO;CACvD;CAEA,MAAM,aAAa,QAAQ,WAAW,KAAK,IAAI,OAAO,OAAO;CAC7D,MAAM,WAAW,MAAM,WAAW,MAAM,MAAM,WAAW,IAAI,IAAI,OAAO,KAAK;CAC7E,IAAI;CACJ,IAAI,QAAQ,WAAW,KAAK,aAAa,MACvC,QAAQ,MAAM,MAAM,UAAU,MAAM;MAC/B,IAAI,eAAe,QAAQ,QAAQ,OAAO,KAAK,KAAK,eAAe,KAAK,aAAa,GAC1F,QAAQ,MAAM,MAAM,YAAY,QAAQ;MAExC,OAAO;CAIT,IADc,aAAa,QAAQ,MAAM,SAAS,aAAa,MAAM,QAAQ,UAClE,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAE;CAC3C,MAAM,OAAO,QAAQ,OAAO,QAAQ,MAAM,GAAG,IAAI;CACjD,MAAM,KAAK,QAAQ,MAAM,QAAQ,QAAQ,SAAS,MAAM,GAAG,IAAI;CAC/D,OAAO;EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,QAAQ,MAAM,EAAE;EAAK,QAAQ;CAAE;AAClE;;AAGA,SAAgB,WAAW,MAAc,OAA2B,MAAoB;CACtF,MAAM,OAAO,UAAU,IAAI;CAC3B,MAAM,OAAO,QAAQ,OAAO,MAAM,OAAO,IAAI;CAC7C,MAAM,QAAQ,QAAQ,QAAQ,MAAM,OAAO,IAAI;CAC/C,IAAI,CAAC,QAAQ,CAAC,OAAO,OAAO;EAAE,MAAM,MAAM;EAAQ,OAAO;CAAM;CAC/D,IAAI,MAAM,SAAS,GAAG,OAAO;EAAE,MAAM,GAAG,KAAK,GAAG,MAAM;EAAQ,OAAO,MAAM,WAAW;CAAE;CACxF,OAAO;EAAE,MAAM,SAAS,MAAM,QAAQ,MAAM,OAAO,MAAM,GAAG,MAAM,MAAM,IAAI;EAAG,OAAO;CAAM;AAC9F;;AAGA,MAAM,aAAa,WACjB,KAAK,OACF,IAAI,KAAK,OAAO,YAAY,GAAG,OAAO,SAAS,GAAG,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,IAC3E,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,KAC7B,KACJ;;;;;AAMF,SAAgB,SACd,QACA,KACA,MACA,UAA4B,SACpB;CACR,MAAM,OAAO,UAAU,MAAM,IAAI,UAAU,GAAG;CAC9C,IAAI,SAAS,GAAG,OAAO,EAAE,MAAM,QAAQ;CACvC,IAAI,SAAS,IAAI,OAAO,EAAE,MAAM,YAAY;CAC5C,IAAI,SAAS,GAAG,OAAO,EAAE,MAAM,WAAW;CAC1C,IAAI,KAAK,IAAI,IAAI,IAAI,GACnB,OAAO;EAAE,MAAM;EAAW,MAAM,IAAI,KAAK,eAAe,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,MAAM;CAAE;CAE5F,OAAO;EACL,MAAM;EACN,MAAM,IAAI,KAAK,eAAe,MAAM;GAClC,KAAK;GACL,OAAO;GACP,GAAI,OAAO,YAAY,MAAM,IAAI,YAAY,IAAI,CAAC,IAAI,EAAE,MAAM,UAAU;EAC1E,CAAC,CAAC,CAAC,OAAO,MAAM;CAClB;AACF;;AAGA,MAAa,UAAU,QAAc,SACnC,IAAI,KAAK,eAAe,MAAM;CAAE,MAAM;CAAW,QAAQ;AAAU,CAAC,CAAC,CAAC,OAAO,MAAM;;AAGrF,SAAgB,SAAS,IAAU,KAAW,OAA2B,MAAsB;CAC7F,OAAO,MAAM,OAAO,SAAS,IAAI,KAAK,IAAI,GAAG,OAAO,IAAI,IAAI,CAAC;AAC/D;;;;;;AAOA,SAAgB,OACd,YACA,KACA,OACA,MACQ;CACR,MAAM,OAAO,OAAO,WAAW,SAAS,OAAO,IAAI;CACnD,IAAI,CAAC,WAAW,MAAM,WAAW,gBAAgB,MAAM,OAAO,KAAK;CACnE,MAAM,OAAO,IAAI,KAAK,WAAW,WAAW;CAC5C,MAAM,MAAM,SAAS,MAAM,KAAK,MAAM,MAAM;CAC5C,MAAM,OAAO,KAAK,SAAS,IAAI,SAAS,UAAU,OAAO,OAAO,MAAM,IAAI;CAC1E,OAAO,GAAG,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI;AAC9C;;AAGA,SAAgB,OACd,KACA,OACe;CACf,IAAI,IAAI,aAAa,MAAM,OAAO;CAClC,OAAO,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,QAAQ,IAAI,KAAK,MAAM,IAAI,UAAU,CAAC,CAAC;AACtF"}
|
package/dist/client.d.ts
CHANGED
|
@@ -74,8 +74,10 @@ export interface Client {
|
|
|
74
74
|
/** Takes one memory from it. */
|
|
75
75
|
forget: (id: string, memoryId: string) => Promise<void>;
|
|
76
76
|
/**
|
|
77
|
-
* The owner's call with the agent, from
|
|
78
|
-
* conversation (a test) made now, and where to join it (`VoiceCall`'s `connect`).
|
|
77
|
+
* The owner's call with the agent, from our own app (v3/VOICE.md): the call and its
|
|
78
|
+
* conversation (a test) made now, and where to join it (`VoiceCall`'s `connect`). App only:
|
|
79
|
+
* it is `/api`'s, signed in by the owner's cookie, and 404s on `/v1`; a host's page calls with
|
|
80
|
+
* `conversations.call(agentId)`.
|
|
79
81
|
*/
|
|
80
82
|
call: (id: string) => Promise<CallToken>;
|
|
81
83
|
};
|
|
@@ -116,8 +118,16 @@ export interface Client {
|
|
|
116
118
|
conversations: {
|
|
117
119
|
/** One conversation with its messages. */
|
|
118
120
|
get: (id: string) => Promise<ConversationDetail>;
|
|
119
|
-
/**
|
|
120
|
-
|
|
121
|
+
/** The agent's conversations, newest first: a person's own only, each with what is unread. */
|
|
122
|
+
list: (agentId: string) => Promise<Conversation[]>;
|
|
123
|
+
/** A new conversation with an agent, titled when given. */
|
|
124
|
+
start: (agentId: string, options?: {
|
|
125
|
+
title?: string | undefined;
|
|
126
|
+
}) => Promise<Conversation>;
|
|
127
|
+
/** How far the person has read it: all of it, now. */
|
|
128
|
+
read: (id: string) => Promise<Conversation>;
|
|
129
|
+
/** Its title, as the person gives it. */
|
|
130
|
+
rename: (id: string, title: string) => Promise<Conversation>;
|
|
121
131
|
/** The files that arrived in a conversation: attached, sent through a form. */
|
|
122
132
|
files: (id: string) => Promise<ConversationFile[]>;
|
|
123
133
|
/**
|
package/dist/client.js
CHANGED
|
@@ -42,6 +42,8 @@ function readJson(text) {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
const seg = encodeURIComponent;
|
|
45
|
+
/** A request's JSON body. */
|
|
46
|
+
const body = (value) => new Blob([JSON.stringify(value)], { type: "application/json" });
|
|
45
47
|
/** A file's path in a URL: each name of it encoded, the slashes between them kept. */
|
|
46
48
|
const filePath = (path) => path.split("/").map(seg).join("/");
|
|
47
49
|
/** Where a file's preview is read: under its conversation, its agent or the organization. */
|
|
@@ -175,13 +177,16 @@ function createClient(options) {
|
|
|
175
177
|
runs: { get: (id) => json("GET", `/runs/${seg(id)}`) },
|
|
176
178
|
tasks: {
|
|
177
179
|
list: (agentId) => json("GET", `/agents/${seg(agentId)}/tasks`),
|
|
178
|
-
switch: (agentId, taskId, on) => json("PATCH", `/agents/${seg(agentId)}/tasks/${seg(taskId)}`,
|
|
180
|
+
switch: (agentId, taskId, on) => json("PATCH", `/agents/${seg(agentId)}/tasks/${seg(taskId)}`, body({ on })),
|
|
179
181
|
remove: (agentId, taskId) => run("DELETE", `/agents/${seg(agentId)}/tasks/${seg(taskId)}`)
|
|
180
182
|
},
|
|
181
183
|
channels: { list: (agentId) => json("GET", agentId === void 0 ? "/channels" : `/channels?agent=${seg(agentId)}`) },
|
|
182
184
|
conversations: {
|
|
183
185
|
get: (id) => json("GET", `/conversations/${seg(id)}`),
|
|
184
|
-
|
|
186
|
+
list: (agentId) => json("GET", `/agents/${seg(agentId)}/conversations`),
|
|
187
|
+
start: (agentId, { title } = {}) => json("POST", `/agents/${seg(agentId)}/conversations`, title === void 0 ? void 0 : body({ title })),
|
|
188
|
+
read: (id) => json("POST", `/conversations/${seg(id)}/read`, body({})),
|
|
189
|
+
rename: (id, title) => json("PATCH", `/conversations/${seg(id)}`, body({ title })),
|
|
185
190
|
files: (id) => json("GET", `/conversations/${seg(id)}/files`),
|
|
186
191
|
upload: (id, file, options) => sendFile(`/conversations/${seg(id)}/files`, file, options),
|
|
187
192
|
play: async (id, fileId) => {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type { AboutOut, MemoryFact } from \"./about\";\nimport type { Automation, AutomationView, RunRecord, Task } from \"./automation/types\";\nimport { signerOf, type Credentials, type Speaker } from \"./credentials\";\nimport type {\n AgentFace,\n WidgetConfig,\n CallToken,\n Channel,\n Conversation,\n ConversationDetail,\n ConversationFile,\n FileAt,\n FileLink,\n FilePreview,\n StoredFile,\n} from \"./types\";\n\n/**\n * What the API answered when it was not a success: its status, its sentence (`detail`, written\n * to be shown) and its `code`, for a host to word in its own language.\n */\nexport class ApiError extends Error {\n readonly status: number;\n readonly detail: string;\n /** What went wrong, by name (`not_found`, `no_calls`); null when the answer named nothing. */\n readonly code: string | null;\n\n constructor(status: number, detail: string, code: string | null = null) {\n super(detail);\n this.name = \"ApiError\";\n this.status = status;\n this.detail = detail;\n this.code = code;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nconst isIssue = (value: unknown): value is { msg: string } =>\n isRecord(value) && typeof value.msg === \"string\";\n\n/**\n * Reads an error body: `{code, detail: \"message\"}`, or FastAPI's 422 `{detail: [{msg, …}, …]}`\n * (the first issue speaks for all). A body with neither is named by its status alone.\n */\nexport function parseError(status: number, body: unknown): ApiError {\n const detail = isRecord(body) ? body.detail : undefined;\n const code = isRecord(body) && typeof body.code === \"string\" ? body.code : null;\n if (typeof detail === \"string\" && detail !== \"\") return new ApiError(status, detail, code);\n if (Array.isArray(detail)) {\n const issue = detail.find(isIssue);\n if (issue) return new ApiError(status, issue.msg);\n }\n return new ApiError(status, `HTTP ${status}`);\n}\n\n/** A body read as JSON, or null when it is not. */\nfunction readJson(text: string): unknown {\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * Where the API is, and who calls it (`Credentials`: the cookie, a person's token, a token asked\n * of the host's backend, or a publishable key and its visitor).\n */\nexport type ClientOptions = Credentials & {\n /**\n * The API's origin and prefix: `/api` in our own app (the cookie's, on the page's origin), the\n * public `https://…/v1` from a host's page.\n */\n baseUrl: string;\n /** A host's own `fetch`, when the global one is not the right one. */\n fetch?: typeof fetch | undefined;\n};\n\n/** The files under one owner: the organization's, or an agent's own. */\nexport interface Files {\n /** Every file, by path. */\n list: () => Promise<StoredFile[]>;\n /**\n * Stores the bytes under the path (replacing a file of the same name), with the blob's type\n * as the file's; `searchable` makes it knowledge `search_files` reads (text, PDF).\n */\n put: (path: string, blob: Blob, searchable: boolean) => Promise<StoredFile>;\n delete: (path: string) => Promise<void>;\n}\n\n/** How an upload goes: how much of it has gone, and how to let it go. */\nexport interface UploadOptions {\n /** Hears the share sent so far, from 0 to 1, as it goes. */\n onProgress?: ((share: number) => void) | undefined;\n /** Aborting it stops the upload, and the promise rejects with an `AbortError`. */\n signal?: AbortSignal | undefined;\n}\n\n/** The API, as far as this package reaches it. */\nexport interface Client {\n /**\n * The widget's agent and look, by the publishable key it speaks with (a web channel's key).\n */\n widget: () => Promise<WidgetConfig>;\n /**\n * Who the page speaks for, by its credentials: the business (our own app's cookie) or a person\n * it serves (a token, a publishable key's visitor). What waits for the business's yes is\n * answered by the business alone.\n */\n who: Speaker;\n agents: {\n /** What a person may know of the agent: its name, role, mark, and whether it takes calls. */\n face: (id: string) => Promise<AgentFace>;\n /** What the agent says about itself (null until it has written it) and the facts it rests on. */\n about: (id: string) => Promise<AboutOut>;\n /** Has the agent write about itself anew (a model call, a few seconds); answers like `about`. */\n describe: (id: string) => Promise<AboutOut>;\n /** The agent's own files, by path. */\n files: (id: string) => Promise<StoredFile[]>;\n /** Stores a file of the agent's own; see `Files.put`. */\n putFile: (id: string, path: string, blob: Blob, searchable: boolean) => Promise<StoredFile>;\n deleteFile: (id: string, path: string) => Promise<void>;\n /** What the agent remembered, newest first. */\n memories: (id: string) => Promise<MemoryFact[]>;\n /** Takes one memory from it. */\n forget: (id: string, memoryId: string) => Promise<void>;\n /**\n * The owner's call with the agent, from the browser (v3/VOICE.md): the call and its\n * conversation (a test) made now, and where to join it (`VoiceCall`'s `connect`).\n */\n call: (id: string) => Promise<CallToken>;\n };\n /**\n * The organization's files, shared by every agent; and the preview of any file the caller may\n * read, the organization's, an agent's own or a conversation's (`preview`).\n */\n files: Files & {\n /** What a viewer draws of the file, by its `kind` (v3/FILES.md, Preview). */\n preview: (at: FileAt) => Promise<FilePreview>;\n };\n /** What an agent does on its own (v3/AUTOMATIONS.md). */\n automations: {\n /** The agent's automations, each as it stands now with its newest run. */\n list: (agentId: string) => Promise<Automation[]>;\n /** One of them by its name, with its newest runs. */\n get: (agentId: string, name: string) => Promise<AutomationView>;\n };\n runs: {\n /** One run of an automation with its record: every call it made, step by step. */\n get: (id: string) => Promise<RunRecord>;\n };\n /**\n * The tasks an agent runs for contacts, each with its newest runs: a person's own only (what\n * they asked the agent for in their conversations); the business's, every one.\n */\n tasks: {\n list: (agentId: string) => Promise<Task[]>;\n /** Pauses it, or turns it on again; answers it as it stands. */\n switch: (agentId: string, taskId: string, on: boolean) => Promise<Task>;\n remove: (agentId: string, taskId: string) => Promise<void>;\n };\n /** Where people write to the organization's agents (v3/CHANNELS.md). */\n channels: {\n /** The organization's channels, or one agent's: the disconnected ones too. */\n list: (agentId?: string) => Promise<Channel[]>;\n };\n conversations: {\n /** One conversation with its messages. */\n get: (id: string) => Promise<ConversationDetail>;\n /** A new conversation with an agent. */\n start: (agentId: string) => Promise<Conversation>;\n /** The files that arrived in a conversation: attached, sent through a form. */\n files: (id: string) => Promise<ConversationFile[]>;\n /**\n * Stores a file in the conversation as the person picks it, to say it or send it through a\n * form by its id: its bytes as they are, under its type and name.\n */\n upload: (id: string, file: File, options?: UploadOptions) => Promise<ConversationFile>;\n /**\n * Where a picture, a video or a sound of the conversation plays from in the page's own\n * player: an address that needs no credential, for an hour, streamed as the player seeks.\n */\n play: (id: string, fileId: string) => Promise<string>;\n /**\n * A call with the agent from the browser, for whoever may talk to it (a person, as theirs):\n * the call and its own conversation made now, where what is said lands, and where to join it\n * (`VoiceCall`'s `connect`).\n */\n call: (agentId: string) => Promise<CallToken>;\n };\n /**\n * The conversation's socket address, signed in: `ws:` beside `http:`, `wss:` beside `https:`,\n * with the token (and the visitor) in its query, since a browser's socket takes no header.\n * `fresh` asks the host's backend for a new token first (`getToken`), for a socket that could\n * not open with the last one.\n */\n liveUrl: (conversationId: string, options?: { fresh?: boolean | undefined }) => Promise<string>;\n}\n\nconst seg = encodeURIComponent;\n\n/** A file's path in a URL: each name of it encoded, the slashes between them kept. */\nconst filePath = (path: string): string => path.split(\"/\").map(seg).join(\"/\");\n\n/** Where a file's preview is read: under its conversation, its agent or the organization. */\nconst previewPath = (at: FileAt): string => {\n if (\"conversationId\" in at) {\n return `/conversations/${seg(at.conversationId)}/files/${seg(at.fileId)}/preview`;\n }\n const owner = \"agentId\" in at ? `/agents/${seg(at.agentId)}` : \"\";\n return `${owner}/files/${filePath(at.path)}/preview`;\n};\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\n/**\n * The API under `baseUrl`: JSON in and out, an `ApiError` for anything but a success, signed in\n * the one way `options` gives. A token asked of the host's backend (`getToken`) that the API\n * refuses (401: it expired) is asked for once more, and the request sent again with it.\n */\nexport function createClient(options: ClientOptions): Client {\n const { baseUrl, fetch: call = fetch } = options;\n const signer = signerOf(options);\n\n /** One request with the cookie or the credential's headers; a body goes as it is, typed. */\n async function attempt(method: Method, path: string, body: Blob | undefined) {\n const signed = await signer.sign();\n const response = await call(`${baseUrl}${path}`, {\n method,\n credentials: signer.credentials,\n headers:\n body === undefined ? signed.headers : { ...signed.headers, \"Content-Type\": body.type },\n ...(body === undefined ? {} : { body }),\n });\n return { response, signed };\n }\n\n async function send(method: Method, path: string, body?: Blob): Promise<Response> {\n let { response, signed } = await attempt(method, path, body);\n if (response.status === 401 && signed.renew !== null) {\n signed.renew();\n ({ response } = await attempt(method, path, body));\n }\n if (!response.ok) {\n const answer: unknown = await response.json().catch(() => null);\n throw parseError(response.status, answer);\n }\n return response;\n }\n\n async function json<T>(method: Method, path: string, body?: Blob): Promise<T> {\n return (await (await send(method, path, body)).json()) as T;\n }\n\n /** A request whose answer has no body (204). */\n async function run(method: Method, path: string): Promise<void> {\n await send(method, path);\n }\n\n /** The four of `Files` under a prefix: `/files`, or `/agents/{id}/files`. */\n const filesUnder = (prefix: string): Files => ({\n list: () => json(\"GET\", prefix),\n put: (path, blob, searchable) =>\n json(\"PUT\", `${prefix}/${filePath(path)}?searchable=${searchable}`, blob),\n delete: (path) => run(\"DELETE\", `${prefix}/${filePath(path)}`),\n });\n\n const own = (id: string) => filesUnder(`/agents/${seg(id)}/files`);\n\n /**\n * A file sent by XMLHttpRequest, the one way a browser tells how much of a body has gone; the\n * cookie goes as with `fetch` on the same origin, any other credential as its headers. Refused\n * with a token asked of the host's backend, it is sent once more with a new one.\n */\n async function sendFile(\n path: string,\n file: File,\n options: UploadOptions = {},\n ): Promise<ConversationFile> {\n const signed = await signer.sign();\n try {\n return await post(path, file, signed.headers, options);\n } catch (error) {\n const expired = error instanceof ApiError && error.status === 401;\n if (!expired || signed.renew === null) throw error;\n signed.renew();\n return post(path, file, (await signer.sign()).headers, options);\n }\n }\n\n function post(\n path: string,\n file: File,\n headers: Readonly<Record<string, string>>,\n { onProgress, signal }: UploadOptions,\n ): Promise<ConversationFile> {\n return new Promise((resolve, reject) => {\n const aborted = () => new DOMException(\"The upload was aborted\", \"AbortError\");\n if (signal?.aborted) {\n reject(aborted());\n return;\n }\n const request = new XMLHttpRequest();\n const abort = () => {\n request.abort();\n };\n request.open(\"POST\", `${baseUrl}${path}`);\n for (const [name, value] of Object.entries(headers)) request.setRequestHeader(name, value);\n request.setRequestHeader(\"Content-Type\", file.type || \"application/octet-stream\");\n request.setRequestHeader(\"X-File-Name\", encodeURIComponent(file.name));\n request.upload.addEventListener(\"progress\", (event) => {\n if (event.lengthComputable && event.total > 0) onProgress?.(event.loaded / event.total);\n });\n request.addEventListener(\"loadend\", () => {\n signal?.removeEventListener(\"abort\", abort);\n });\n request.addEventListener(\"load\", () => {\n const body = readJson(request.responseText);\n if (request.status >= 200 && request.status < 300) resolve(body as ConversationFile);\n else reject(parseError(request.status, body));\n });\n request.addEventListener(\"error\", () => {\n reject(new ApiError(0, \"The upload could not reach the server\"));\n });\n request.addEventListener(\"abort\", () => {\n reject(aborted());\n });\n signal?.addEventListener(\"abort\", abort, { once: true });\n request.send(file);\n });\n }\n\n return {\n widget: () => json(\"GET\", \"/channels/web/widget\"),\n who: signer.who,\n agents: {\n face: (id) => json(\"GET\", `/agents/${seg(id)}/face`),\n about: (id) => json(\"GET\", `/agents/${seg(id)}/about`),\n describe: (id) => json(\"POST\", `/agents/${seg(id)}/describe`),\n files: (id) => own(id).list(),\n putFile: (id, path, blob, searchable) => own(id).put(path, blob, searchable),\n deleteFile: (id, path) => own(id).delete(path),\n memories: (id) => json(\"GET\", `/agents/${seg(id)}/memories`),\n forget: (id, memoryId) => run(\"DELETE\", `/agents/${seg(id)}/memories/${seg(memoryId)}`),\n call: (id) => json(\"POST\", `/agents/${seg(id)}/voice/token`),\n },\n files: { ...filesUnder(\"/files\"), preview: (at) => json(\"GET\", previewPath(at)) },\n automations: {\n list: (agentId) => json(\"GET\", `/agents/${seg(agentId)}/automations`),\n get: (agentId, name) => json(\"GET\", `/agents/${seg(agentId)}/automations/${seg(name)}`),\n },\n runs: {\n get: (id) => json(\"GET\", `/runs/${seg(id)}`),\n },\n tasks: {\n list: (agentId) => json(\"GET\", `/agents/${seg(agentId)}/tasks`),\n switch: (agentId, taskId, on) =>\n json(\n \"PATCH\",\n `/agents/${seg(agentId)}/tasks/${seg(taskId)}`,\n new Blob([JSON.stringify({ on })], { type: \"application/json\" }),\n ),\n remove: (agentId, taskId) => run(\"DELETE\", `/agents/${seg(agentId)}/tasks/${seg(taskId)}`),\n },\n channels: {\n list: (agentId) =>\n json(\"GET\", agentId === undefined ? \"/channels\" : `/channels?agent=${seg(agentId)}`),\n },\n conversations: {\n get: (id) => json(\"GET\", `/conversations/${seg(id)}`),\n start: (agentId) => json(\"POST\", `/agents/${seg(agentId)}/conversations`),\n files: (id) => json(\"GET\", `/conversations/${seg(id)}/files`),\n upload: (id, file, options) => sendFile(`/conversations/${seg(id)}/files`, file, options),\n play: async (id, fileId) => {\n const link = await json<FileLink>(\n \"GET\",\n `/conversations/${seg(id)}/files/${seg(fileId)}/link`,\n );\n return new URL(`${baseUrl}${link.path}`, window.location.href).href;\n },\n call: (agentId) => json(\"POST\", `/agents/${seg(agentId)}/calls`),\n },\n liveUrl: async (conversationId, { fresh = false } = {}) => {\n const url = new URL(\n `${baseUrl}/conversations/${seg(conversationId)}/live`,\n window.location.href,\n );\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n for (const [name, value] of Object.entries(await signer.query(fresh))) {\n url.searchParams.set(name, value);\n }\n return url.href;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type { AboutOut, MemoryFact } from \"./about\";\nimport type { Automation, AutomationView, RunRecord, Task } from \"./automation/types\";\nimport { signerOf, type Credentials, type Speaker } from \"./credentials\";\nimport type {\n AgentFace,\n WidgetConfig,\n CallToken,\n Channel,\n Conversation,\n ConversationDetail,\n ConversationFile,\n FileAt,\n FileLink,\n FilePreview,\n StoredFile,\n} from \"./types\";\n\n/**\n * What the API answered when it was not a success: its status, its sentence (`detail`, written\n * to be shown) and its `code`, for a host to word in its own language.\n */\nexport class ApiError extends Error {\n readonly status: number;\n readonly detail: string;\n /** What went wrong, by name (`not_found`, `no_calls`); null when the answer named nothing. */\n readonly code: string | null;\n\n constructor(status: number, detail: string, code: string | null = null) {\n super(detail);\n this.name = \"ApiError\";\n this.status = status;\n this.detail = detail;\n this.code = code;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nconst isIssue = (value: unknown): value is { msg: string } =>\n isRecord(value) && typeof value.msg === \"string\";\n\n/**\n * Reads an error body: `{code, detail: \"message\"}`, or FastAPI's 422 `{detail: [{msg, …}, …]}`\n * (the first issue speaks for all). A body with neither is named by its status alone.\n */\nexport function parseError(status: number, body: unknown): ApiError {\n const detail = isRecord(body) ? body.detail : undefined;\n const code = isRecord(body) && typeof body.code === \"string\" ? body.code : null;\n if (typeof detail === \"string\" && detail !== \"\") return new ApiError(status, detail, code);\n if (Array.isArray(detail)) {\n const issue = detail.find(isIssue);\n if (issue) return new ApiError(status, issue.msg);\n }\n return new ApiError(status, `HTTP ${status}`);\n}\n\n/** A body read as JSON, or null when it is not. */\nfunction readJson(text: string): unknown {\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * Where the API is, and who calls it (`Credentials`: the cookie, a person's token, a token asked\n * of the host's backend, or a publishable key and its visitor).\n */\nexport type ClientOptions = Credentials & {\n /**\n * The API's origin and prefix: `/api` in our own app (the cookie's, on the page's origin), the\n * public `https://…/v1` from a host's page.\n */\n baseUrl: string;\n /** A host's own `fetch`, when the global one is not the right one. */\n fetch?: typeof fetch | undefined;\n};\n\n/** The files under one owner: the organization's, or an agent's own. */\nexport interface Files {\n /** Every file, by path. */\n list: () => Promise<StoredFile[]>;\n /**\n * Stores the bytes under the path (replacing a file of the same name), with the blob's type\n * as the file's; `searchable` makes it knowledge `search_files` reads (text, PDF).\n */\n put: (path: string, blob: Blob, searchable: boolean) => Promise<StoredFile>;\n delete: (path: string) => Promise<void>;\n}\n\n/** How an upload goes: how much of it has gone, and how to let it go. */\nexport interface UploadOptions {\n /** Hears the share sent so far, from 0 to 1, as it goes. */\n onProgress?: ((share: number) => void) | undefined;\n /** Aborting it stops the upload, and the promise rejects with an `AbortError`. */\n signal?: AbortSignal | undefined;\n}\n\n/** The API, as far as this package reaches it. */\nexport interface Client {\n /**\n * The widget's agent and look, by the publishable key it speaks with (a web channel's key).\n */\n widget: () => Promise<WidgetConfig>;\n /**\n * Who the page speaks for, by its credentials: the business (our own app's cookie) or a person\n * it serves (a token, a publishable key's visitor). What waits for the business's yes is\n * answered by the business alone.\n */\n who: Speaker;\n agents: {\n /** What a person may know of the agent: its name, role, mark, and whether it takes calls. */\n face: (id: string) => Promise<AgentFace>;\n /** What the agent says about itself (null until it has written it) and the facts it rests on. */\n about: (id: string) => Promise<AboutOut>;\n /** Has the agent write about itself anew (a model call, a few seconds); answers like `about`. */\n describe: (id: string) => Promise<AboutOut>;\n /** The agent's own files, by path. */\n files: (id: string) => Promise<StoredFile[]>;\n /** Stores a file of the agent's own; see `Files.put`. */\n putFile: (id: string, path: string, blob: Blob, searchable: boolean) => Promise<StoredFile>;\n deleteFile: (id: string, path: string) => Promise<void>;\n /** What the agent remembered, newest first. */\n memories: (id: string) => Promise<MemoryFact[]>;\n /** Takes one memory from it. */\n forget: (id: string, memoryId: string) => Promise<void>;\n /**\n * The owner's call with the agent, from our own app (v3/VOICE.md): the call and its\n * conversation (a test) made now, and where to join it (`VoiceCall`'s `connect`). App only:\n * it is `/api`'s, signed in by the owner's cookie, and 404s on `/v1`; a host's page calls with\n * `conversations.call(agentId)`.\n */\n call: (id: string) => Promise<CallToken>;\n };\n /**\n * The organization's files, shared by every agent; and the preview of any file the caller may\n * read, the organization's, an agent's own or a conversation's (`preview`).\n */\n files: Files & {\n /** What a viewer draws of the file, by its `kind` (v3/FILES.md, Preview). */\n preview: (at: FileAt) => Promise<FilePreview>;\n };\n /** What an agent does on its own (v3/AUTOMATIONS.md). */\n automations: {\n /** The agent's automations, each as it stands now with its newest run. */\n list: (agentId: string) => Promise<Automation[]>;\n /** One of them by its name, with its newest runs. */\n get: (agentId: string, name: string) => Promise<AutomationView>;\n };\n runs: {\n /** One run of an automation with its record: every call it made, step by step. */\n get: (id: string) => Promise<RunRecord>;\n };\n /**\n * The tasks an agent runs for contacts, each with its newest runs: a person's own only (what\n * they asked the agent for in their conversations); the business's, every one.\n */\n tasks: {\n list: (agentId: string) => Promise<Task[]>;\n /** Pauses it, or turns it on again; answers it as it stands. */\n switch: (agentId: string, taskId: string, on: boolean) => Promise<Task>;\n remove: (agentId: string, taskId: string) => Promise<void>;\n };\n /** Where people write to the organization's agents (v3/CHANNELS.md). */\n channels: {\n /** The organization's channels, or one agent's: the disconnected ones too. */\n list: (agentId?: string) => Promise<Channel[]>;\n };\n conversations: {\n /** One conversation with its messages. */\n get: (id: string) => Promise<ConversationDetail>;\n /** The agent's conversations, newest first: a person's own only, each with what is unread. */\n list: (agentId: string) => Promise<Conversation[]>;\n /** A new conversation with an agent, titled when given. */\n start: (agentId: string, options?: { title?: string | undefined }) => Promise<Conversation>;\n /** How far the person has read it: all of it, now. */\n read: (id: string) => Promise<Conversation>;\n /** Its title, as the person gives it. */\n rename: (id: string, title: string) => Promise<Conversation>;\n /** The files that arrived in a conversation: attached, sent through a form. */\n files: (id: string) => Promise<ConversationFile[]>;\n /**\n * Stores a file in the conversation as the person picks it, to say it or send it through a\n * form by its id: its bytes as they are, under its type and name.\n */\n upload: (id: string, file: File, options?: UploadOptions) => Promise<ConversationFile>;\n /**\n * Where a picture, a video or a sound of the conversation plays from in the page's own\n * player: an address that needs no credential, for an hour, streamed as the player seeks.\n */\n play: (id: string, fileId: string) => Promise<string>;\n /**\n * A call with the agent from the browser, for whoever may talk to it (a person, as theirs):\n * the call and its own conversation made now, where what is said lands, and where to join it\n * (`VoiceCall`'s `connect`).\n */\n call: (agentId: string) => Promise<CallToken>;\n };\n /**\n * The conversation's socket address, signed in: `ws:` beside `http:`, `wss:` beside `https:`,\n * with the token (and the visitor) in its query, since a browser's socket takes no header.\n * `fresh` asks the host's backend for a new token first (`getToken`), for a socket that could\n * not open with the last one.\n */\n liveUrl: (conversationId: string, options?: { fresh?: boolean | undefined }) => Promise<string>;\n}\n\nconst seg = encodeURIComponent;\n\n/** A request's JSON body. */\nconst body = (value: unknown): Blob =>\n new Blob([JSON.stringify(value)], { type: \"application/json\" });\n\n/** A file's path in a URL: each name of it encoded, the slashes between them kept. */\nconst filePath = (path: string): string => path.split(\"/\").map(seg).join(\"/\");\n\n/** Where a file's preview is read: under its conversation, its agent or the organization. */\nconst previewPath = (at: FileAt): string => {\n if (\"conversationId\" in at) {\n return `/conversations/${seg(at.conversationId)}/files/${seg(at.fileId)}/preview`;\n }\n const owner = \"agentId\" in at ? `/agents/${seg(at.agentId)}` : \"\";\n return `${owner}/files/${filePath(at.path)}/preview`;\n};\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\n/**\n * The API under `baseUrl`: JSON in and out, an `ApiError` for anything but a success, signed in\n * the one way `options` gives. A token asked of the host's backend (`getToken`) that the API\n * refuses (401: it expired) is asked for once more, and the request sent again with it.\n */\nexport function createClient(options: ClientOptions): Client {\n const { baseUrl, fetch: call = fetch } = options;\n const signer = signerOf(options);\n\n /** One request with the cookie or the credential's headers; a body goes as it is, typed. */\n async function attempt(method: Method, path: string, body: Blob | undefined) {\n const signed = await signer.sign();\n const response = await call(`${baseUrl}${path}`, {\n method,\n credentials: signer.credentials,\n headers:\n body === undefined ? signed.headers : { ...signed.headers, \"Content-Type\": body.type },\n ...(body === undefined ? {} : { body }),\n });\n return { response, signed };\n }\n\n async function send(method: Method, path: string, body?: Blob): Promise<Response> {\n let { response, signed } = await attempt(method, path, body);\n if (response.status === 401 && signed.renew !== null) {\n signed.renew();\n ({ response } = await attempt(method, path, body));\n }\n if (!response.ok) {\n const answer: unknown = await response.json().catch(() => null);\n throw parseError(response.status, answer);\n }\n return response;\n }\n\n async function json<T>(method: Method, path: string, body?: Blob): Promise<T> {\n return (await (await send(method, path, body)).json()) as T;\n }\n\n /** A request whose answer has no body (204). */\n async function run(method: Method, path: string): Promise<void> {\n await send(method, path);\n }\n\n /** The four of `Files` under a prefix: `/files`, or `/agents/{id}/files`. */\n const filesUnder = (prefix: string): Files => ({\n list: () => json(\"GET\", prefix),\n put: (path, blob, searchable) =>\n json(\"PUT\", `${prefix}/${filePath(path)}?searchable=${searchable}`, blob),\n delete: (path) => run(\"DELETE\", `${prefix}/${filePath(path)}`),\n });\n\n const own = (id: string) => filesUnder(`/agents/${seg(id)}/files`);\n\n /**\n * A file sent by XMLHttpRequest, the one way a browser tells how much of a body has gone; the\n * cookie goes as with `fetch` on the same origin, any other credential as its headers. Refused\n * with a token asked of the host's backend, it is sent once more with a new one.\n */\n async function sendFile(\n path: string,\n file: File,\n options: UploadOptions = {},\n ): Promise<ConversationFile> {\n const signed = await signer.sign();\n try {\n return await post(path, file, signed.headers, options);\n } catch (error) {\n const expired = error instanceof ApiError && error.status === 401;\n if (!expired || signed.renew === null) throw error;\n signed.renew();\n return post(path, file, (await signer.sign()).headers, options);\n }\n }\n\n function post(\n path: string,\n file: File,\n headers: Readonly<Record<string, string>>,\n { onProgress, signal }: UploadOptions,\n ): Promise<ConversationFile> {\n return new Promise((resolve, reject) => {\n const aborted = () => new DOMException(\"The upload was aborted\", \"AbortError\");\n if (signal?.aborted) {\n reject(aborted());\n return;\n }\n const request = new XMLHttpRequest();\n const abort = () => {\n request.abort();\n };\n request.open(\"POST\", `${baseUrl}${path}`);\n for (const [name, value] of Object.entries(headers)) request.setRequestHeader(name, value);\n request.setRequestHeader(\"Content-Type\", file.type || \"application/octet-stream\");\n request.setRequestHeader(\"X-File-Name\", encodeURIComponent(file.name));\n request.upload.addEventListener(\"progress\", (event) => {\n if (event.lengthComputable && event.total > 0) onProgress?.(event.loaded / event.total);\n });\n request.addEventListener(\"loadend\", () => {\n signal?.removeEventListener(\"abort\", abort);\n });\n request.addEventListener(\"load\", () => {\n const body = readJson(request.responseText);\n if (request.status >= 200 && request.status < 300) resolve(body as ConversationFile);\n else reject(parseError(request.status, body));\n });\n request.addEventListener(\"error\", () => {\n reject(new ApiError(0, \"The upload could not reach the server\"));\n });\n request.addEventListener(\"abort\", () => {\n reject(aborted());\n });\n signal?.addEventListener(\"abort\", abort, { once: true });\n request.send(file);\n });\n }\n\n return {\n widget: () => json(\"GET\", \"/channels/web/widget\"),\n who: signer.who,\n agents: {\n face: (id) => json(\"GET\", `/agents/${seg(id)}/face`),\n about: (id) => json(\"GET\", `/agents/${seg(id)}/about`),\n describe: (id) => json(\"POST\", `/agents/${seg(id)}/describe`),\n files: (id) => own(id).list(),\n putFile: (id, path, blob, searchable) => own(id).put(path, blob, searchable),\n deleteFile: (id, path) => own(id).delete(path),\n memories: (id) => json(\"GET\", `/agents/${seg(id)}/memories`),\n forget: (id, memoryId) => run(\"DELETE\", `/agents/${seg(id)}/memories/${seg(memoryId)}`),\n call: (id) => json(\"POST\", `/agents/${seg(id)}/voice/token`),\n },\n files: { ...filesUnder(\"/files\"), preview: (at) => json(\"GET\", previewPath(at)) },\n automations: {\n list: (agentId) => json(\"GET\", `/agents/${seg(agentId)}/automations`),\n get: (agentId, name) => json(\"GET\", `/agents/${seg(agentId)}/automations/${seg(name)}`),\n },\n runs: {\n get: (id) => json(\"GET\", `/runs/${seg(id)}`),\n },\n tasks: {\n list: (agentId) => json(\"GET\", `/agents/${seg(agentId)}/tasks`),\n switch: (agentId, taskId, on) =>\n json(\"PATCH\", `/agents/${seg(agentId)}/tasks/${seg(taskId)}`, body({ on })),\n remove: (agentId, taskId) => run(\"DELETE\", `/agents/${seg(agentId)}/tasks/${seg(taskId)}`),\n },\n channels: {\n list: (agentId) =>\n json(\"GET\", agentId === undefined ? \"/channels\" : `/channels?agent=${seg(agentId)}`),\n },\n conversations: {\n get: (id) => json(\"GET\", `/conversations/${seg(id)}`),\n list: (agentId) => json(\"GET\", `/agents/${seg(agentId)}/conversations`),\n start: (agentId, { title } = {}) =>\n json(\n \"POST\",\n `/agents/${seg(agentId)}/conversations`,\n title === undefined ? undefined : body({ title }),\n ),\n read: (id) => json(\"POST\", `/conversations/${seg(id)}/read`, body({})),\n rename: (id, title) => json(\"PATCH\", `/conversations/${seg(id)}`, body({ title })),\n files: (id) => json(\"GET\", `/conversations/${seg(id)}/files`),\n upload: (id, file, options) => sendFile(`/conversations/${seg(id)}/files`, file, options),\n play: async (id, fileId) => {\n const link = await json<FileLink>(\n \"GET\",\n `/conversations/${seg(id)}/files/${seg(fileId)}/link`,\n );\n return new URL(`${baseUrl}${link.path}`, window.location.href).href;\n },\n call: (agentId) => json(\"POST\", `/agents/${seg(agentId)}/calls`),\n },\n liveUrl: async (conversationId, { fresh = false } = {}) => {\n const url = new URL(\n `${baseUrl}/conversations/${seg(conversationId)}/live`,\n window.location.href,\n );\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n for (const [name, value] of Object.entries(await signer.query(fresh))) {\n url.searchParams.set(name, value);\n }\n return url.href;\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/contract.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export interface FactAsk {
|
|
|
76
76
|
export interface FactAutomation {
|
|
77
77
|
id: string;
|
|
78
78
|
name: string;
|
|
79
|
-
kind: "schedule" | "webhook" | "event" | "platform";
|
|
79
|
+
kind: "schedule" | "webhook" | "event" | "platform" | "manual" | "after";
|
|
80
80
|
title: string;
|
|
81
81
|
summary: string;
|
|
82
82
|
schedule: string | null;
|
|
@@ -156,7 +156,7 @@ export interface RunDetailOut {
|
|
|
156
156
|
agent_id: string;
|
|
157
157
|
automation: string;
|
|
158
158
|
title: string;
|
|
159
|
-
by: "schedule" | "webhook" | "event" | "platform" | "agent" | "test";
|
|
159
|
+
by: "schedule" | "webhook" | "event" | "platform" | "agent" | "test" | "api" | "after";
|
|
160
160
|
conversation_id: string | null;
|
|
161
161
|
status: "running" | "waiting" | "done" | "failed" | "skipped";
|
|
162
162
|
summary: string | null;
|
|
@@ -168,6 +168,8 @@ export interface RunDetailOut {
|
|
|
168
168
|
tokens_out: number;
|
|
169
169
|
opened: Array<string>;
|
|
170
170
|
decision?: RunsDecisionOut | null;
|
|
171
|
+
result?: unknown;
|
|
172
|
+
contact_id?: string | null;
|
|
171
173
|
steps: Array<RunStepOut>;
|
|
172
174
|
}
|
|
173
175
|
export interface RunOut {
|
|
@@ -175,7 +177,7 @@ export interface RunOut {
|
|
|
175
177
|
agent_id: string;
|
|
176
178
|
automation: string;
|
|
177
179
|
title: string;
|
|
178
|
-
by: "schedule" | "webhook" | "event" | "platform" | "agent" | "test";
|
|
180
|
+
by: "schedule" | "webhook" | "event" | "platform" | "agent" | "test" | "api" | "after";
|
|
179
181
|
conversation_id: string | null;
|
|
180
182
|
status: "running" | "waiting" | "done" | "failed" | "skipped";
|
|
181
183
|
summary: string | null;
|
|
@@ -187,6 +189,8 @@ export interface RunOut {
|
|
|
187
189
|
tokens_out: number;
|
|
188
190
|
opened: Array<string>;
|
|
189
191
|
decision?: RunsDecisionOut | null;
|
|
192
|
+
result?: unknown;
|
|
193
|
+
contact_id?: string | null;
|
|
190
194
|
}
|
|
191
195
|
export interface RunStepOut {
|
|
192
196
|
seq: number;
|
|
@@ -240,7 +244,7 @@ export interface TaskOut {
|
|
|
240
244
|
last_run: RunOut | null;
|
|
241
245
|
}
|
|
242
246
|
export interface TriggerView {
|
|
243
|
-
kind: "schedule" | "webhook" | "event" | "platform";
|
|
247
|
+
kind: "schedule" | "webhook" | "event" | "platform" | "manual" | "after";
|
|
244
248
|
schedule: string | null;
|
|
245
249
|
timezone: string | null;
|
|
246
250
|
url: string | null;
|
|
@@ -251,6 +255,7 @@ export interface TriggerView {
|
|
|
251
255
|
icon: string | null;
|
|
252
256
|
decides?: boolean;
|
|
253
257
|
channels?: Array<string>;
|
|
258
|
+
after?: string | null;
|
|
254
259
|
}
|
|
255
260
|
export interface Use {
|
|
256
261
|
kind: "app" | "ai" | "agent" | "notify" | "send" | "data" | "http";
|
package/dist/es.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { KitMessages } from "./kit/messages.js";
|
|
|
3
3
|
import { TaskMessages } from "./AgentTasks.js";
|
|
4
4
|
import { BrowserMessages } from "./BrowserView.js";
|
|
5
5
|
import { ChatMessages } from "./AgentChat.js";
|
|
6
|
+
import { ThreadMessages } from "./Threads.js";
|
|
6
7
|
import { VoiceCallMessages } from "./VoiceCall.js";
|
|
7
8
|
import { SpaceMessages } from "./AgentSpace.js";
|
|
8
9
|
//#region src/es.d.ts
|
|
@@ -12,6 +13,7 @@ export declare const BROWSER_MESSAGES_ES: BrowserMessages;
|
|
|
12
13
|
export declare const CHAT_MESSAGES_ES: ChatMessages;
|
|
13
14
|
export declare const VOICE_CALL_MESSAGES_ES: VoiceCallMessages;
|
|
14
15
|
export declare const TASK_MESSAGES_ES: TaskMessages;
|
|
16
|
+
export declare const THREAD_MESSAGES_ES: ThreadMessages;
|
|
15
17
|
export declare const SPACE_MESSAGES_ES: SpaceMessages;
|
|
16
18
|
//#endregion
|
|
17
19
|
//# sourceMappingURL=es.d.ts.map
|
package/dist/es.js
CHANGED
|
@@ -41,6 +41,8 @@ const AUTOMATION_MESSAGES_ES = {
|
|
|
41
41
|
on: (often, when) => `${often}, ${when.charAt(0).toLowerCase()}${when.slice(1)}`,
|
|
42
42
|
custom: "Con un horario propio",
|
|
43
43
|
webhook: "Cuando otro sistema la llama",
|
|
44
|
+
manual: "Cuando alguien la inicia",
|
|
45
|
+
after: (automation) => automation ? `Tras «${automation}»` : "Tras otra automatización",
|
|
44
46
|
platform: "Cuando llega un mensaje",
|
|
45
47
|
event: (app, event) => event ? `Cuando pasa «${event}» en ${app ?? "una app"}` : `Cuando pasa algo en ${app ?? "una app"}`,
|
|
46
48
|
next: (day, time) => [
|
|
@@ -81,7 +83,9 @@ const AUTOMATION_MESSAGES_ES = {
|
|
|
81
83
|
event: app ? `evento de ${app}` : "evento",
|
|
82
84
|
platform: "un mensaje",
|
|
83
85
|
agent: "se lo pidieron en el chat",
|
|
84
|
-
test: "prueba"
|
|
86
|
+
test: "prueba",
|
|
87
|
+
api: "tu app",
|
|
88
|
+
after: "tras otra"
|
|
85
89
|
})[by],
|
|
86
90
|
statuses: {
|
|
87
91
|
running: "En curso",
|
|
@@ -267,6 +271,10 @@ const CHAT_MESSAGES_ES = {
|
|
|
267
271
|
inputs: {},
|
|
268
272
|
allow: "Aprobar",
|
|
269
273
|
decline: "Rechazar",
|
|
274
|
+
approvals: (count) => `${count} acciones esperan tu aprobación`,
|
|
275
|
+
approveAll: "Aprobar todo",
|
|
276
|
+
approveSome: (count) => `Aprobar ${count}`,
|
|
277
|
+
declineAll: "Rechazar todo",
|
|
270
278
|
confirming: "Esperando la confirmación del negocio",
|
|
271
279
|
handedOff: "Pasada a una persona",
|
|
272
280
|
handover: (holder, by, name) => {
|
|
@@ -368,6 +376,16 @@ const TASK_MESSAGES_ES = {
|
|
|
368
376
|
empty: "No hay nada programado. Pídele que te recuerde algo, o que te escriba más adelante.",
|
|
369
377
|
failed: "No se ha podido cambiar. Inténtalo de nuevo."
|
|
370
378
|
};
|
|
379
|
+
const THREAD_MESSAGES_ES = {
|
|
380
|
+
open: "Conversaciones",
|
|
381
|
+
title: "Tus conversaciones",
|
|
382
|
+
back: "Volver a la conversación",
|
|
383
|
+
new: "Nueva conversación",
|
|
384
|
+
untitled: "Conversación nueva",
|
|
385
|
+
unread: (count) => count === 1 ? "1 mensaje sin leer" : `${count} mensajes sin leer`,
|
|
386
|
+
waiting: "Te espera",
|
|
387
|
+
empty: "Aún no hay nada aquí."
|
|
388
|
+
};
|
|
371
389
|
const SPACE_MESSAGES_ES = {
|
|
372
390
|
modes: {
|
|
373
391
|
label: "Modo",
|
|
@@ -382,9 +400,10 @@ const SPACE_MESSAGES_ES = {
|
|
|
382
400
|
retry: "Reintentar",
|
|
383
401
|
chat: CHAT_MESSAGES_ES,
|
|
384
402
|
voice: VOICE_CALL_MESSAGES_ES,
|
|
385
|
-
tasks: TASK_MESSAGES_ES
|
|
403
|
+
tasks: TASK_MESSAGES_ES,
|
|
404
|
+
threads: THREAD_MESSAGES_ES
|
|
386
405
|
};
|
|
387
406
|
//#endregion
|
|
388
|
-
export { AUTOMATION_MESSAGES_ES, BROWSER_MESSAGES_ES, CHAT_MESSAGES_ES, KIT_MESSAGES_ES, SPACE_MESSAGES_ES, TASK_MESSAGES_ES, VOICE_CALL_MESSAGES_ES };
|
|
407
|
+
export { AUTOMATION_MESSAGES_ES, BROWSER_MESSAGES_ES, CHAT_MESSAGES_ES, KIT_MESSAGES_ES, SPACE_MESSAGES_ES, TASK_MESSAGES_ES, THREAD_MESSAGES_ES, VOICE_CALL_MESSAGES_ES };
|
|
389
408
|
|
|
390
409
|
//# sourceMappingURL=es.js.map
|
package/dist/es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"es.js","names":[],"sources":["../src/es.ts"],"sourcesContent":["/**\n * The package's words in Spanish, for the people an agent serves: the chat, the browser it drives,\n * the kit's controls (with an automation's and its runs'), a call and the agent's space. English\n * is every component's default; a host in Spanish passes these as `messages`, the calendar's\n * language as `locale` (`import { es } from \"@signalcore/ui/locale\"`).\n */\nimport type { ChatMessages } from \"./AgentChat\";\nimport type { SpaceMessages } from \"./AgentSpace\";\nimport type { TaskMessages } from \"./AgentTasks\";\nimport type { AutomationMessages, DayRef } from \"./automation/messages\";\nimport type { BrowserMessages } from \"./BrowserView\";\nimport type { KitMessages } from \"./kit/messages\";\nimport type { VoiceCallMessages } from \"./VoiceCall\";\n\n/** The article before a time: \"la 1:00\", \"las 8:00\". */\nconst at = (time: string): string => `a ${time.startsWith(\"1:\") ? \"la\" : \"las\"} ${time}`;\n\nconst list = (items: readonly string[]): string => new Intl.ListFormat(\"es\").format(items);\n\n/** A weekday as the plural says it: \"los lunes\", \"los sábados\". */\nconst days = (name: string): string => (name.endsWith(\"s\") ? name : `${name}s`);\n\nconst capital = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);\n\n/** A day said after \"próxima\": \"hoy\", \"mañana\", \"el lunes\", \"el 3 nov\". */\nfunction nextDay(day: DayRef): string {\n switch (day.kind) {\n case \"today\":\n return \"hoy\";\n case \"tomorrow\":\n return \"mañana\";\n case \"yesterday\":\n return \"\";\n default:\n return `el ${day.name}`;\n }\n}\n\n/** A message sent on a channel, by the channel's kind: \"un WhatsApp\", \"un SMS\". */\nconst SENT: Readonly<Record<string, string>> = {\n whatsapp: \"un WhatsApp\",\n instagram: \"un mensaje de Instagram\",\n sms: \"un SMS\",\n};\n\n/** What an automation's tool call did, by what the tool's name says, done or (a test) not. */\nconst TOOL = {\n search: [(app: string) => `Buscó en ${app}`, (app: string) => `Buscó en ${app}`],\n send: [(app: string) => `Envió por ${app}`, (app: string) => `Habría enviado por ${app}`],\n create: [(app: string) => `Creó en ${app}`, (app: string) => `Habría creado en ${app}`],\n update: [(app: string) => `Cambió en ${app}`, (app: string) => `Habría cambiado en ${app}`],\n remove: [(app: string) => `Borró en ${app}`, (app: string) => `Habría borrado en ${app}`],\n use: [(app: string) => `Usó ${app}`, (app: string) => `Habría usado ${app}`],\n} as const;\n\nexport const AUTOMATION_MESSAGES_ES: AutomationMessages = {\n daily: \"Cada día\",\n weekdays: \"Cada día laborable\",\n weekends: \"Los fines de semana\",\n weekly: (names) =>\n names.length === 1 ? `Cada ${names[0] ?? \"\"}` : `Los ${list(names.map(days))}`,\n monthly: (numbers) =>\n numbers.length === 1\n ? `El día ${numbers[0] ?? \"\"} de cada mes`\n : `Los días ${list(numbers.map(String))} de cada mes`,\n at: (times) => list(times.map(at)),\n every: (count, unit) =>\n unit === \"minute\"\n ? count === 1\n ? \"Cada minuto\"\n : `Cada ${count} minutos`\n : count === 1\n ? \"Cada hora\"\n : `Cada ${count} horas`,\n between: (from, to) => `de ${from} a ${to}`,\n on: (often, when) => `${often}, ${when.charAt(0).toLowerCase()}${when.slice(1)}`,\n custom: \"Con un horario propio\",\n webhook: \"Cuando otro sistema la llama\",\n platform: \"Cuando llega un mensaje\",\n event: (app, event) =>\n event\n ? `Cuando pasa «${event}» en ${app ?? \"una app\"}`\n : `Cuando pasa algo en ${app ?? \"una app\"}`,\n next: (day, time) =>\n [\"próxima\", nextDay(day), time === null ? \"\" : at(time)].filter(Boolean).join(\" \"),\n states: { active: \"Activa\", paused: \"En pausa\", failing: \"Falló la última\" },\n switchLabel: \"Activa\",\n steps: \"Pasos\",\n runs: \"Ejecuciones\",\n noRuns: \"Aún no se ha ejecutado.\",\n uses: {\n ai: \"IA\",\n agent: \"Agente\",\n notify: \"Aviso\",\n send: \"Mensaje\",\n data: \"Tabla\",\n http: \"Web\",\n },\n more: (count) => `+${count}`,\n gone: \"Esta automatización ya no existe.\",\n moment: (day, time) => {\n switch (day.kind) {\n case \"today\":\n return `Hoy ${time}`;\n case \"yesterday\":\n return `Ayer ${time}`;\n case \"tomorrow\":\n return `Mañana ${time}`;\n default:\n return `${capital(day.name)} ${time}`;\n }\n },\n by: (by, app) =>\n ({\n schedule: \"horario\",\n webhook: \"webhook\",\n event: app ? `evento de ${app}` : \"evento\",\n platform: \"un mensaje\",\n agent: \"se lo pidieron en el chat\",\n test: \"prueba\",\n })[by],\n statuses: {\n running: \"En curso\",\n waiting: \"Esperando\",\n done: \"Hecha\",\n failed: \"Falló\",\n skipped: \"Omitida\",\n },\n dry: (summary) => `Prueba: ${summary}`,\n took: (ms) => {\n if (ms < 1000) return \"menos de 1 s\";\n const seconds = Math.round(ms / 1000);\n return seconds < 60 ? `${seconds} s` : `${Math.floor(seconds / 60)} min ${seconds % 60} s`;\n },\n opened: \"Conversaciones que abrió\",\n conversation: (index) => `Conversación ${index}`,\n askedIn: \"La conversación donde se lo pidieron\",\n noCalls: \"No llegó a hacer nada.\",\n outside: \"Fuera de los pasos\",\n times: (count) => `×${count}`,\n calls: {\n tool: (verb, app, would) => TOOL[verb][would ? 1 : 0](app),\n ai: \"Usó la IA\",\n notify: (would) => (would ? \"Habría avisado en la bandeja\" : \"Avisó en la bandeja\"),\n send: (channel, to, would) => {\n const sent = `${SENT[channel ?? \"\"] ?? \"un mensaje\"} a ${to || \"un contacto\"}`;\n return would ? `Habría enviado ${sent}` : `Envió ${sent}`;\n },\n start: (would) => (would ? \"Habría abierto una conversación\" : \"Abrió una conversación\"),\n find: (table) => `Consultó ${table}`,\n add: (table, would) =>\n would ? `Habría añadido una fila a ${table}` : `Añadió una fila a ${table}`,\n change: (table, would) =>\n would ? `Habría cambiado una fila de ${table}` : `Cambió una fila de ${table}`,\n http: (host, would) => (would ? `Habría llamado a ${host}` : `Llamó a ${host}`),\n files: \"Buscó en los archivos\",\n read: (file) => `Leyó ${file}`,\n wrote: (file, would) => (would ? `Habría guardado ${file}` : `Guardó ${file}`),\n listed: \"Miró sus archivos\",\n remember: (would) => (would ? \"Habría guardado un recuerdo\" : \"Guardó un recuerdo\"),\n recall: \"Buscó en lo aprendido\",\n },\n};\n\nconst FAMILIES: Readonly<Record<string, string>> = {\n image: \"imágenes\",\n video: \"vídeos\",\n audio: \"audios\",\n text: \"textos\",\n};\n\nexport const KIT_MESSAGES_ES: KitMessages = {\n required: \"Este campo es obligatorio\",\n chooseDate: \"Elige un día\",\n chooseTime: \"Elige una hora\",\n chooseMoment: \"Elige día y hora\",\n chooseOption: \"Elige una opción\",\n other: \"Otra respuesta\",\n otherPlaceholder: \"Escribe tu respuesta\",\n chooseRating: \"Elige una puntuación\",\n check: \"Marca la casilla para seguir\",\n invalidEmail: \"Correo no válido\",\n invalidPhone: \"Teléfono no válido\",\n invalidUrl: \"Dirección no válida\",\n invalidNumber: \"Escribe un número\",\n invalidTime: \"Escribe la hora así: 9:30\",\n atLeast: (min) => `Como mínimo ${min}`,\n atMost: (max) => `Como máximo ${max}`,\n unavailableDate: \"Ese día no está disponible\",\n unavailableTime: \"Esa hora no está disponible\",\n optional: \"Opcional\",\n pick: \"Elige…\",\n search: \"Buscar…\",\n noResults: \"Sin resultados\",\n show: \"Mostrar\",\n hide: \"Ocultar\",\n increase: \"Sumar\",\n decrease: \"Restar\",\n remove: (label) => `Quitar ${label}`,\n yes: \"Sí\",\n no: \"No\",\n rated: (value, max) => `${value} de ${max}`,\n stars: (count) => (count === 1 ? \"1 estrella\" : `${count} estrellas`),\n send: \"Enviar\",\n sent: \"Enviado\",\n chooseFile: \"Falta el archivo\",\n upload: (multiple) => (multiple ? \"Sube archivos\" : \"Sube un archivo\"),\n drop: \"Suelta aquí o elige\",\n limits: (kinds, size) => (kinds ? `${kinds}, hasta ${size}` : `Hasta ${size}`),\n anyOf: (family) => FAMILIES[family] ?? family,\n uploading: \"Subiendo\",\n tooBig: (size) => `Pasa de ${size}`,\n wrongType: \"Aquí no vale este tipo de archivo\",\n tooMany: (max) => `Como máximo ${max} archivos`,\n uploadFailed: \"No se ha podido subir\",\n retry: \"Reintentar\",\n stillUploading: \"Espera a que termine de subir\",\n fixFiles: \"Quita o reintenta los archivos con error\",\n open: (name) => `Abrir ${name}`,\n file: \"Archivo\",\n play: \"Reproducir\",\n pause: \"Pausar\",\n position: \"Posición\",\n automation: AUTOMATION_MESSAGES_ES,\n connect: {\n authorize: (app) => `Autorizar en ${app}`,\n connected: \"Conectada\",\n failed: \"No se ha podido conectar\",\n preparing: \"Preparando la conexión\",\n },\n};\n\nexport const BROWSER_MESSAGES_ES: BrowserMessages = {\n agent: (name) => `Lo controla ${name}`,\n agentMine: (name) => `${name}, en tu Chrome`,\n person: \"Lo controlas tú\",\n take: \"Tomar el control\",\n giveBack: \"Devolver\",\n handedOver: (name) => `${name} te pasa el navegador`,\n done: \"Listo, sigue\",\n closed: \"El navegador se cerró mientras te esperaba.\",\n close: \"Cerrar el navegador\",\n expand: \"Ampliar\",\n shrink: \"Reducir\",\n blank: \"Página en blanco\",\n screen: (where) => `Navegador: ${where}`,\n};\n\nexport const CHAT_MESSAGES_ES: ChatMessages = {\n placeholder: (name) => `Escribe a ${name}…`,\n connecting: \"Conectando…\",\n awaiting: \"Responde arriba para seguir…\",\n thinking: (name) => `${name} está pensando`,\n typing: \"Escribiendo\",\n working: \"Trabajando\",\n writing: \"Escribiendo\",\n elapsed: (seconds) => `${seconds} s`,\n escape: \"esc para detener\",\n done: (seconds) =>\n `Listo en ${seconds < 60 ? `${seconds} s` : `${Math.floor(seconds / 60)} min ${seconds % 60} s`}`,\n empty: (name) => `Habla con ${name}`,\n intro: () => \"\",\n send: \"Enviar\",\n attach: \"Adjuntar archivos\",\n drop: \"Suelta para adjuntar\",\n dictate: \"Dictar\",\n dictateStop: \"Parar y escribirlo\",\n dictation: {\n listening: \"Escuchando…\",\n writing: \"Escribiéndolo…\",\n failed: \"No te he oído: permite el micrófono e inténtalo otra vez\",\n },\n stop: \"Detener\",\n log: \"Conversación\",\n steps: {\n show: \"Muestra\",\n ask_person: \"Pregunta\",\n search_files: \"Busca en archivos\",\n read_file: \"Lee un archivo\",\n keep_file: \"Guarda un archivo\",\n remember: \"Recuerda\",\n recall: \"Busca en lo aprendido\",\n escalate: \"Pasa a una persona\",\n notify: \"Avisa\",\n data_find: \"Consulta una tabla\",\n data_add: \"Añade una fila\",\n data_update: \"Cambia una fila\",\n browser_open: \"Abre una página\",\n browser_read: \"Lee la página\",\n browser_click: \"Hace clic\",\n browser_fill: \"Rellena un campo\",\n browser_scroll: \"Desplaza la página\",\n browser_back: \"Vuelve atrás\",\n browser_submit: \"Envía en la web\",\n browser_hand_over: \"Te pasa el navegador\",\n browser_attach: \"Sube un archivo a la web\",\n browser_download: \"Guarda un archivo de la web\",\n browser_screenshot: \"Hace una captura de la web\",\n browser_record: \"Graba la web en vídeo\",\n browser_fill_key: \"Escribe una clave en la web\",\n ask_builder: \"Se lo pide al builder\",\n send_message: \"Envía un mensaje\",\n voice_note: \"Manda una nota de voz\",\n ai: \"Usa la IA\",\n call: \"Llama\",\n },\n failed: \"falló\",\n approval: \"Necesita tu aprobación\",\n request: (name, action) => `${name} quiere hacer «${action}»`,\n inputs: {},\n allow: \"Aprobar\",\n decline: \"Rechazar\",\n confirming: \"Esperando la confirmación del negocio\",\n handedOff: \"Pasada a una persona\",\n handover: (holder, by, name) => {\n const automation = by.kind === \"automation\" ? ` por «${by.title}»` : \"\";\n switch (holder) {\n case \"agent\":\n if (by.kind === \"owner\") return `Devolviste la conversación a ${name}`;\n return `Se devolvió a ${name}${automation}`;\n case \"person\":\n if (by.kind === \"owner\") return `Pausaste a ${name}`;\n if (by.kind === \"agent\") return `${name} la pasó a una persona`;\n return `Pasó a una persona${automation}`;\n case \"nobody\":\n return `Ignorada${automation}`;\n }\n },\n skipped: \"No respondió\",\n cut: (heard) =>\n heard === \"\" ? \"Interrumpida antes de que se oyera nada\" : `Interrumpida tras «${heard}»`,\n write: \"Responde como el negocio…\",\n business: \"Tú\",\n voiceNote: \"Nota de voz\",\n delivery: {\n queued: \"Esperando para salir\",\n sent: \"Enviado\",\n delivered: \"Entregado\",\n read: \"Leído\",\n failed: \"No entregado\",\n },\n undelivered: (error) => (error ? `No entregado: ${error}` : \"No entregado\"),\n noTool: \"Esta página no puede hacer eso\",\n kit: KIT_MESSAGES_ES,\n browser: BROWSER_MESSAGES_ES,\n};\n\nexport const VOICE_CALL_MESSAGES_ES: VoiceCallMessages = {\n call: (name) => `Llamada con ${name}`,\n states: {\n connecting: \"Conectando…\",\n listening: \"Escuchando\",\n thinking: \"Pensando\",\n speaking: \"Hablando\",\n reconnecting: \"Reconectando…\",\n ended: \"Llamada terminada\",\n },\n calling: (name) => `Llamando a ${name}`,\n ended: {\n person: () => \"Has colgado\",\n agent: (name) => `${name} ha colgado`,\n limit: () => \"Se alcanzó la duración máxima\",\n dropped: () => \"Se cortó la llamada\",\n },\n problems: {\n denied: {\n title: () => \"Sin permiso para el micrófono\",\n help: \"Permite el micrófono a esta página (en el icono junto a la dirección) y vuelve a llamar.\",\n },\n nomic: {\n title: () => \"No hay ningún micrófono\",\n help: \"Conecta uno, o elige otro en los ajustes de sonido del sistema, y vuelve a llamar.\",\n },\n inuse: {\n title: () => \"El micrófono está ocupado\",\n help: \"Otra aplicación lo está usando. Ciérrala y vuelve a llamar.\",\n },\n unsupported: {\n title: () => \"Este navegador no puede llamar\",\n help: \"Abre la página por https en un Chrome, Edge, Safari o Firefox actual.\",\n },\n off: {\n title: () => \"Las llamadas no están activadas\",\n help: \"Este servicio aún no atiende llamadas. Escríbele mientras tanto.\",\n },\n builder: {\n title: (name) => `${name} no atiende llamadas`,\n help: \"Escríbele en el chat.\",\n },\n refused: {\n title: (name) => `${name} no puede atender la llamada`,\n help: \"Inténtalo de nuevo en un momento.\",\n },\n failed: {\n title: (name) => `No se ha podido llamar a ${name}`,\n help: \"Comprueba tu conexión y vuelve a intentarlo.\",\n },\n unanswered: {\n title: (name) => `${name} no contesta`,\n help: \"Ahora mismo no atiende llamadas. Inténtalo de nuevo en un momento.\",\n },\n },\n mute: \"Silenciar\",\n hangUp: \"Colgar\",\n keys: \"Espacio silencia y activa el micrófono\",\n muted: \"Tu micrófono está silenciado\",\n hear: (name) => `Oír a ${name}`,\n};\n\nexport const TASK_MESSAGES_ES: TaskMessages = {\n open: (count) =>\n count === 1 ? \"Tienes 1 tarea programada\" : `Tienes ${count} tareas programadas`,\n title: \"Tus tareas\",\n back: \"Volver a la conversación\",\n remove: \"Quitar\",\n empty: \"No hay nada programado. Pídele que te recuerde algo, o que te escriba más adelante.\",\n failed: \"No se ha podido cambiar. Inténtalo de nuevo.\",\n};\n\nexport const SPACE_MESSAGES_ES: SpaceMessages = {\n modes: { label: \"Modo\", text: \"Texto\", voice: \"Voz\" },\n again: \"Volver a llamar\",\n close: \"Cerrar\",\n agent: \"Agente\",\n opening: \"Abriendo la conversación…\",\n failed: \"No se ha podido abrir la conversación.\",\n retry: \"Reintentar\",\n chat: CHAT_MESSAGES_ES,\n voice: VOICE_CALL_MESSAGES_ES,\n tasks: TASK_MESSAGES_ES,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"es.js","names":[],"sources":["../src/es.ts"],"sourcesContent":["/**\n * The package's words in Spanish, for the people an agent serves: the chat, the browser it drives,\n * the kit's controls (with an automation's and its runs'), a call and the agent's space. English\n * is every component's default; a host in Spanish passes these as `messages`, the calendar's\n * language as `locale` (`import { es } from \"@signalcore/ui/locale\"`).\n */\nimport type { ChatMessages } from \"./AgentChat\";\nimport type { SpaceMessages } from \"./AgentSpace\";\nimport type { TaskMessages } from \"./AgentTasks\";\nimport type { AutomationMessages, DayRef } from \"./automation/messages\";\nimport type { BrowserMessages } from \"./BrowserView\";\nimport type { KitMessages } from \"./kit/messages\";\nimport type { ThreadMessages } from \"./Threads\";\nimport type { VoiceCallMessages } from \"./VoiceCall\";\n\n/** The article before a time: \"la 1:00\", \"las 8:00\". */\nconst at = (time: string): string => `a ${time.startsWith(\"1:\") ? \"la\" : \"las\"} ${time}`;\n\nconst list = (items: readonly string[]): string => new Intl.ListFormat(\"es\").format(items);\n\n/** A weekday as the plural says it: \"los lunes\", \"los sábados\". */\nconst days = (name: string): string => (name.endsWith(\"s\") ? name : `${name}s`);\n\nconst capital = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);\n\n/** A day said after \"próxima\": \"hoy\", \"mañana\", \"el lunes\", \"el 3 nov\". */\nfunction nextDay(day: DayRef): string {\n switch (day.kind) {\n case \"today\":\n return \"hoy\";\n case \"tomorrow\":\n return \"mañana\";\n case \"yesterday\":\n return \"\";\n default:\n return `el ${day.name}`;\n }\n}\n\n/** A message sent on a channel, by the channel's kind: \"un WhatsApp\", \"un SMS\". */\nconst SENT: Readonly<Record<string, string>> = {\n whatsapp: \"un WhatsApp\",\n instagram: \"un mensaje de Instagram\",\n sms: \"un SMS\",\n};\n\n/** What an automation's tool call did, by what the tool's name says, done or (a test) not. */\nconst TOOL = {\n search: [(app: string) => `Buscó en ${app}`, (app: string) => `Buscó en ${app}`],\n send: [(app: string) => `Envió por ${app}`, (app: string) => `Habría enviado por ${app}`],\n create: [(app: string) => `Creó en ${app}`, (app: string) => `Habría creado en ${app}`],\n update: [(app: string) => `Cambió en ${app}`, (app: string) => `Habría cambiado en ${app}`],\n remove: [(app: string) => `Borró en ${app}`, (app: string) => `Habría borrado en ${app}`],\n use: [(app: string) => `Usó ${app}`, (app: string) => `Habría usado ${app}`],\n} as const;\n\nexport const AUTOMATION_MESSAGES_ES: AutomationMessages = {\n daily: \"Cada día\",\n weekdays: \"Cada día laborable\",\n weekends: \"Los fines de semana\",\n weekly: (names) =>\n names.length === 1 ? `Cada ${names[0] ?? \"\"}` : `Los ${list(names.map(days))}`,\n monthly: (numbers) =>\n numbers.length === 1\n ? `El día ${numbers[0] ?? \"\"} de cada mes`\n : `Los días ${list(numbers.map(String))} de cada mes`,\n at: (times) => list(times.map(at)),\n every: (count, unit) =>\n unit === \"minute\"\n ? count === 1\n ? \"Cada minuto\"\n : `Cada ${count} minutos`\n : count === 1\n ? \"Cada hora\"\n : `Cada ${count} horas`,\n between: (from, to) => `de ${from} a ${to}`,\n on: (often, when) => `${often}, ${when.charAt(0).toLowerCase()}${when.slice(1)}`,\n custom: \"Con un horario propio\",\n webhook: \"Cuando otro sistema la llama\",\n manual: \"Cuando alguien la inicia\",\n after: (automation) => (automation ? `Tras «${automation}»` : \"Tras otra automatización\"),\n platform: \"Cuando llega un mensaje\",\n event: (app, event) =>\n event\n ? `Cuando pasa «${event}» en ${app ?? \"una app\"}`\n : `Cuando pasa algo en ${app ?? \"una app\"}`,\n next: (day, time) =>\n [\"próxima\", nextDay(day), time === null ? \"\" : at(time)].filter(Boolean).join(\" \"),\n states: { active: \"Activa\", paused: \"En pausa\", failing: \"Falló la última\" },\n switchLabel: \"Activa\",\n steps: \"Pasos\",\n runs: \"Ejecuciones\",\n noRuns: \"Aún no se ha ejecutado.\",\n uses: {\n ai: \"IA\",\n agent: \"Agente\",\n notify: \"Aviso\",\n send: \"Mensaje\",\n data: \"Tabla\",\n http: \"Web\",\n },\n more: (count) => `+${count}`,\n gone: \"Esta automatización ya no existe.\",\n moment: (day, time) => {\n switch (day.kind) {\n case \"today\":\n return `Hoy ${time}`;\n case \"yesterday\":\n return `Ayer ${time}`;\n case \"tomorrow\":\n return `Mañana ${time}`;\n default:\n return `${capital(day.name)} ${time}`;\n }\n },\n by: (by, app) =>\n ({\n schedule: \"horario\",\n webhook: \"webhook\",\n event: app ? `evento de ${app}` : \"evento\",\n platform: \"un mensaje\",\n agent: \"se lo pidieron en el chat\",\n test: \"prueba\",\n api: \"tu app\",\n after: \"tras otra\",\n })[by],\n statuses: {\n running: \"En curso\",\n waiting: \"Esperando\",\n done: \"Hecha\",\n failed: \"Falló\",\n skipped: \"Omitida\",\n },\n dry: (summary) => `Prueba: ${summary}`,\n took: (ms) => {\n if (ms < 1000) return \"menos de 1 s\";\n const seconds = Math.round(ms / 1000);\n return seconds < 60 ? `${seconds} s` : `${Math.floor(seconds / 60)} min ${seconds % 60} s`;\n },\n opened: \"Conversaciones que abrió\",\n conversation: (index) => `Conversación ${index}`,\n askedIn: \"La conversación donde se lo pidieron\",\n noCalls: \"No llegó a hacer nada.\",\n outside: \"Fuera de los pasos\",\n times: (count) => `×${count}`,\n calls: {\n tool: (verb, app, would) => TOOL[verb][would ? 1 : 0](app),\n ai: \"Usó la IA\",\n notify: (would) => (would ? \"Habría avisado en la bandeja\" : \"Avisó en la bandeja\"),\n send: (channel, to, would) => {\n const sent = `${SENT[channel ?? \"\"] ?? \"un mensaje\"} a ${to || \"un contacto\"}`;\n return would ? `Habría enviado ${sent}` : `Envió ${sent}`;\n },\n start: (would) => (would ? \"Habría abierto una conversación\" : \"Abrió una conversación\"),\n find: (table) => `Consultó ${table}`,\n add: (table, would) =>\n would ? `Habría añadido una fila a ${table}` : `Añadió una fila a ${table}`,\n change: (table, would) =>\n would ? `Habría cambiado una fila de ${table}` : `Cambió una fila de ${table}`,\n http: (host, would) => (would ? `Habría llamado a ${host}` : `Llamó a ${host}`),\n files: \"Buscó en los archivos\",\n read: (file) => `Leyó ${file}`,\n wrote: (file, would) => (would ? `Habría guardado ${file}` : `Guardó ${file}`),\n listed: \"Miró sus archivos\",\n remember: (would) => (would ? \"Habría guardado un recuerdo\" : \"Guardó un recuerdo\"),\n recall: \"Buscó en lo aprendido\",\n },\n};\n\nconst FAMILIES: Readonly<Record<string, string>> = {\n image: \"imágenes\",\n video: \"vídeos\",\n audio: \"audios\",\n text: \"textos\",\n};\n\nexport const KIT_MESSAGES_ES: KitMessages = {\n required: \"Este campo es obligatorio\",\n chooseDate: \"Elige un día\",\n chooseTime: \"Elige una hora\",\n chooseMoment: \"Elige día y hora\",\n chooseOption: \"Elige una opción\",\n other: \"Otra respuesta\",\n otherPlaceholder: \"Escribe tu respuesta\",\n chooseRating: \"Elige una puntuación\",\n check: \"Marca la casilla para seguir\",\n invalidEmail: \"Correo no válido\",\n invalidPhone: \"Teléfono no válido\",\n invalidUrl: \"Dirección no válida\",\n invalidNumber: \"Escribe un número\",\n invalidTime: \"Escribe la hora así: 9:30\",\n atLeast: (min) => `Como mínimo ${min}`,\n atMost: (max) => `Como máximo ${max}`,\n unavailableDate: \"Ese día no está disponible\",\n unavailableTime: \"Esa hora no está disponible\",\n optional: \"Opcional\",\n pick: \"Elige…\",\n search: \"Buscar…\",\n noResults: \"Sin resultados\",\n show: \"Mostrar\",\n hide: \"Ocultar\",\n increase: \"Sumar\",\n decrease: \"Restar\",\n remove: (label) => `Quitar ${label}`,\n yes: \"Sí\",\n no: \"No\",\n rated: (value, max) => `${value} de ${max}`,\n stars: (count) => (count === 1 ? \"1 estrella\" : `${count} estrellas`),\n send: \"Enviar\",\n sent: \"Enviado\",\n chooseFile: \"Falta el archivo\",\n upload: (multiple) => (multiple ? \"Sube archivos\" : \"Sube un archivo\"),\n drop: \"Suelta aquí o elige\",\n limits: (kinds, size) => (kinds ? `${kinds}, hasta ${size}` : `Hasta ${size}`),\n anyOf: (family) => FAMILIES[family] ?? family,\n uploading: \"Subiendo\",\n tooBig: (size) => `Pasa de ${size}`,\n wrongType: \"Aquí no vale este tipo de archivo\",\n tooMany: (max) => `Como máximo ${max} archivos`,\n uploadFailed: \"No se ha podido subir\",\n retry: \"Reintentar\",\n stillUploading: \"Espera a que termine de subir\",\n fixFiles: \"Quita o reintenta los archivos con error\",\n open: (name) => `Abrir ${name}`,\n file: \"Archivo\",\n play: \"Reproducir\",\n pause: \"Pausar\",\n position: \"Posición\",\n automation: AUTOMATION_MESSAGES_ES,\n connect: {\n authorize: (app) => `Autorizar en ${app}`,\n connected: \"Conectada\",\n failed: \"No se ha podido conectar\",\n preparing: \"Preparando la conexión\",\n },\n};\n\nexport const BROWSER_MESSAGES_ES: BrowserMessages = {\n agent: (name) => `Lo controla ${name}`,\n agentMine: (name) => `${name}, en tu Chrome`,\n person: \"Lo controlas tú\",\n take: \"Tomar el control\",\n giveBack: \"Devolver\",\n handedOver: (name) => `${name} te pasa el navegador`,\n done: \"Listo, sigue\",\n closed: \"El navegador se cerró mientras te esperaba.\",\n close: \"Cerrar el navegador\",\n expand: \"Ampliar\",\n shrink: \"Reducir\",\n blank: \"Página en blanco\",\n screen: (where) => `Navegador: ${where}`,\n};\n\nexport const CHAT_MESSAGES_ES: ChatMessages = {\n placeholder: (name) => `Escribe a ${name}…`,\n connecting: \"Conectando…\",\n awaiting: \"Responde arriba para seguir…\",\n thinking: (name) => `${name} está pensando`,\n typing: \"Escribiendo\",\n working: \"Trabajando\",\n writing: \"Escribiendo\",\n elapsed: (seconds) => `${seconds} s`,\n escape: \"esc para detener\",\n done: (seconds) =>\n `Listo en ${seconds < 60 ? `${seconds} s` : `${Math.floor(seconds / 60)} min ${seconds % 60} s`}`,\n empty: (name) => `Habla con ${name}`,\n intro: () => \"\",\n send: \"Enviar\",\n attach: \"Adjuntar archivos\",\n drop: \"Suelta para adjuntar\",\n dictate: \"Dictar\",\n dictateStop: \"Parar y escribirlo\",\n dictation: {\n listening: \"Escuchando…\",\n writing: \"Escribiéndolo…\",\n failed: \"No te he oído: permite el micrófono e inténtalo otra vez\",\n },\n stop: \"Detener\",\n log: \"Conversación\",\n steps: {\n show: \"Muestra\",\n ask_person: \"Pregunta\",\n search_files: \"Busca en archivos\",\n read_file: \"Lee un archivo\",\n keep_file: \"Guarda un archivo\",\n remember: \"Recuerda\",\n recall: \"Busca en lo aprendido\",\n escalate: \"Pasa a una persona\",\n notify: \"Avisa\",\n data_find: \"Consulta una tabla\",\n data_add: \"Añade una fila\",\n data_update: \"Cambia una fila\",\n browser_open: \"Abre una página\",\n browser_read: \"Lee la página\",\n browser_click: \"Hace clic\",\n browser_fill: \"Rellena un campo\",\n browser_scroll: \"Desplaza la página\",\n browser_back: \"Vuelve atrás\",\n browser_submit: \"Envía en la web\",\n browser_hand_over: \"Te pasa el navegador\",\n browser_attach: \"Sube un archivo a la web\",\n browser_download: \"Guarda un archivo de la web\",\n browser_screenshot: \"Hace una captura de la web\",\n browser_record: \"Graba la web en vídeo\",\n browser_fill_key: \"Escribe una clave en la web\",\n ask_builder: \"Se lo pide al builder\",\n send_message: \"Envía un mensaje\",\n voice_note: \"Manda una nota de voz\",\n ai: \"Usa la IA\",\n call: \"Llama\",\n },\n failed: \"falló\",\n approval: \"Necesita tu aprobación\",\n request: (name, action) => `${name} quiere hacer «${action}»`,\n inputs: {},\n allow: \"Aprobar\",\n decline: \"Rechazar\",\n approvals: (count) => `${count} acciones esperan tu aprobación`,\n approveAll: \"Aprobar todo\",\n approveSome: (count) => `Aprobar ${count}`,\n declineAll: \"Rechazar todo\",\n confirming: \"Esperando la confirmación del negocio\",\n handedOff: \"Pasada a una persona\",\n handover: (holder, by, name) => {\n const automation = by.kind === \"automation\" ? ` por «${by.title}»` : \"\";\n switch (holder) {\n case \"agent\":\n if (by.kind === \"owner\") return `Devolviste la conversación a ${name}`;\n return `Se devolvió a ${name}${automation}`;\n case \"person\":\n if (by.kind === \"owner\") return `Pausaste a ${name}`;\n if (by.kind === \"agent\") return `${name} la pasó a una persona`;\n return `Pasó a una persona${automation}`;\n case \"nobody\":\n return `Ignorada${automation}`;\n }\n },\n skipped: \"No respondió\",\n cut: (heard) =>\n heard === \"\" ? \"Interrumpida antes de que se oyera nada\" : `Interrumpida tras «${heard}»`,\n write: \"Responde como el negocio…\",\n business: \"Tú\",\n voiceNote: \"Nota de voz\",\n delivery: {\n queued: \"Esperando para salir\",\n sent: \"Enviado\",\n delivered: \"Entregado\",\n read: \"Leído\",\n failed: \"No entregado\",\n },\n undelivered: (error) => (error ? `No entregado: ${error}` : \"No entregado\"),\n noTool: \"Esta página no puede hacer eso\",\n kit: KIT_MESSAGES_ES,\n browser: BROWSER_MESSAGES_ES,\n};\n\nexport const VOICE_CALL_MESSAGES_ES: VoiceCallMessages = {\n call: (name) => `Llamada con ${name}`,\n states: {\n connecting: \"Conectando…\",\n listening: \"Escuchando\",\n thinking: \"Pensando\",\n speaking: \"Hablando\",\n reconnecting: \"Reconectando…\",\n ended: \"Llamada terminada\",\n },\n calling: (name) => `Llamando a ${name}`,\n ended: {\n person: () => \"Has colgado\",\n agent: (name) => `${name} ha colgado`,\n limit: () => \"Se alcanzó la duración máxima\",\n dropped: () => \"Se cortó la llamada\",\n },\n problems: {\n denied: {\n title: () => \"Sin permiso para el micrófono\",\n help: \"Permite el micrófono a esta página (en el icono junto a la dirección) y vuelve a llamar.\",\n },\n nomic: {\n title: () => \"No hay ningún micrófono\",\n help: \"Conecta uno, o elige otro en los ajustes de sonido del sistema, y vuelve a llamar.\",\n },\n inuse: {\n title: () => \"El micrófono está ocupado\",\n help: \"Otra aplicación lo está usando. Ciérrala y vuelve a llamar.\",\n },\n unsupported: {\n title: () => \"Este navegador no puede llamar\",\n help: \"Abre la página por https en un Chrome, Edge, Safari o Firefox actual.\",\n },\n off: {\n title: () => \"Las llamadas no están activadas\",\n help: \"Este servicio aún no atiende llamadas. Escríbele mientras tanto.\",\n },\n builder: {\n title: (name) => `${name} no atiende llamadas`,\n help: \"Escríbele en el chat.\",\n },\n refused: {\n title: (name) => `${name} no puede atender la llamada`,\n help: \"Inténtalo de nuevo en un momento.\",\n },\n failed: {\n title: (name) => `No se ha podido llamar a ${name}`,\n help: \"Comprueba tu conexión y vuelve a intentarlo.\",\n },\n unanswered: {\n title: (name) => `${name} no contesta`,\n help: \"Ahora mismo no atiende llamadas. Inténtalo de nuevo en un momento.\",\n },\n },\n mute: \"Silenciar\",\n hangUp: \"Colgar\",\n keys: \"Espacio silencia y activa el micrófono\",\n muted: \"Tu micrófono está silenciado\",\n hear: (name) => `Oír a ${name}`,\n};\n\nexport const TASK_MESSAGES_ES: TaskMessages = {\n open: (count) =>\n count === 1 ? \"Tienes 1 tarea programada\" : `Tienes ${count} tareas programadas`,\n title: \"Tus tareas\",\n back: \"Volver a la conversación\",\n remove: \"Quitar\",\n empty: \"No hay nada programado. Pídele que te recuerde algo, o que te escriba más adelante.\",\n failed: \"No se ha podido cambiar. Inténtalo de nuevo.\",\n};\n\nexport const THREAD_MESSAGES_ES: ThreadMessages = {\n open: \"Conversaciones\",\n title: \"Tus conversaciones\",\n back: \"Volver a la conversación\",\n new: \"Nueva conversación\",\n untitled: \"Conversación nueva\",\n unread: (count) => (count === 1 ? \"1 mensaje sin leer\" : `${count} mensajes sin leer`),\n waiting: \"Te espera\",\n empty: \"Aún no hay nada aquí.\",\n};\n\nexport const SPACE_MESSAGES_ES: SpaceMessages = {\n modes: { label: \"Modo\", text: \"Texto\", voice: \"Voz\" },\n again: \"Volver a llamar\",\n close: \"Cerrar\",\n agent: \"Agente\",\n opening: \"Abriendo la conversación…\",\n failed: \"No se ha podido abrir la conversación.\",\n retry: \"Reintentar\",\n chat: CHAT_MESSAGES_ES,\n voice: VOICE_CALL_MESSAGES_ES,\n tasks: TASK_MESSAGES_ES,\n threads: THREAD_MESSAGES_ES,\n};\n"],"mappings":"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"}
|