@hanzo/build 0.2.79 → 0.2.81
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 +22 -4
- package/lib/activity.d.ts +3 -7
- package/lib/activity.js +18 -5
- package/lib/api/agents.d.ts +36 -35
- package/lib/api/agents.js +66 -29
- package/lib/api/auto.d.ts +3 -23
- package/lib/api/auto.js +39 -22
- package/lib/api/billing.d.ts +0 -35
- package/lib/api/billing.js +6 -5
- package/lib/api/call.d.ts +16 -8
- package/lib/api/call.js +32 -1
- package/lib/api/capabilities.d.ts +0 -11
- package/lib/api/capabilities.js +2 -1
- package/lib/api/codebases.d.ts +0 -10
- package/lib/api/codebases.js +3 -2
- package/lib/api/coding.d.ts +3 -32
- package/lib/api/coding.js +13 -7
- package/lib/api/connectors.d.ts +1 -17
- package/lib/api/connectors.js +5 -4
- package/lib/api/environment.d.ts +6 -20
- package/lib/api/environment.js +22 -19
- package/lib/api/github.d.ts +0 -22
- package/lib/api/github.js +3 -2
- package/lib/api/keys.d.ts +0 -14
- package/lib/api/keys.js +4 -3
- package/lib/api/library.d.ts +3 -17
- package/lib/api/library.js +23 -22
- package/lib/api/machines.d.ts +0 -15
- package/lib/api/machines.js +6 -5
- package/lib/api/mcp.d.ts +0 -9
- package/lib/api/mcp.js +3 -2
- package/lib/api/members.d.ts +0 -15
- package/lib/api/members.js +4 -3
- package/lib/api/memory.d.ts +0 -11
- package/lib/api/memory.js +2 -1
- package/lib/api/places.d.ts +1 -9
- package/lib/api/places.js +12 -1
- package/lib/api/plugins.d.ts +1 -16
- package/lib/api/plugins.js +4 -3
- package/lib/api/profile.d.ts +0 -10
- package/lib/api/profile.js +5 -4
- package/lib/api/projects.d.ts +0 -14
- package/lib/api/projects.js +2 -1
- package/lib/api/provider.d.ts +2 -14
- package/lib/api/provider.js +12 -10
- package/lib/api/sandbox.d.ts +0 -17
- package/lib/api/sandbox.js +5 -4
- package/lib/api/sessions.d.ts +0 -17
- package/lib/api/sessions.js +5 -4
- package/lib/api/skills.d.ts +1 -15
- package/lib/api/skills.js +5 -4
- package/lib/api/studio.d.ts +0 -14
- package/lib/api/studio.js +6 -5
- package/lib/api/turn.d.ts +6 -28
- package/lib/api/turn.js +105 -49
- package/lib/api/verdict.d.ts +0 -9
- package/lib/api/verdict.js +2 -1
- package/lib/api/webhooks.d.ts +1 -14
- package/lib/api/webhooks.js +5 -4
- package/lib/ask.js +7 -4
- package/lib/automations.d.ts +5 -4
- package/lib/automations.js +95 -74
- package/lib/back.js +10 -4
- package/lib/builder.js +7 -5
- package/lib/carry.js +20 -16
- package/lib/customize/agents.d.ts +3 -0
- package/lib/customize/agents.js +152 -55
- package/lib/customize/connectors.js +62 -48
- package/lib/customize/index.js +45 -14
- package/lib/customize/plugins.js +34 -22
- package/lib/customize/say.d.ts +13 -1
- package/lib/customize/say.js +15 -21
- package/lib/customize/skills.js +31 -22
- package/lib/customize/ui.d.ts +5 -9
- package/lib/customize/ui.js +26 -16
- package/lib/data.d.ts +1 -1
- package/lib/data.js +3 -2
- package/lib/desk.js +45 -33
- package/lib/door.js +35 -10
- package/lib/environment.js +25 -19
- package/lib/files.js +43 -34
- package/lib/find.js +12 -9
- package/lib/foot.js +7 -4
- package/lib/forge.js +61 -40
- package/lib/gear.d.ts +2 -1
- package/lib/gear.js +6 -4
- package/lib/git.js +29 -19
- package/lib/host.d.ts +3 -1
- package/lib/landing.d.ts +5 -5
- package/lib/landing.js +52 -44
- package/lib/library.js +73 -51
- package/lib/meter.d.ts +1 -1
- package/lib/meter.js +14 -5
- package/lib/mic.js +12 -5
- package/lib/mind.d.ts +1 -0
- package/lib/mind.js +5 -3
- package/lib/nav.d.ts +6 -5
- package/lib/nav.js +37 -30
- package/lib/panel.d.ts +2 -1
- package/lib/panel.js +52 -36
- package/lib/plan.d.ts +4 -20
- package/lib/plan.js +26 -10
- package/lib/plans.js +49 -30
- package/lib/plugins/design.js +3 -2
- package/lib/plugins/index.d.ts +23 -4
- package/lib/plugins/index.js +11 -26
- package/lib/plugins/pdf.js +2 -1
- package/lib/plugins/project.js +6 -3
- package/lib/plugins/research.js +3 -2
- package/lib/plugins/sketch.js +6 -3
- package/lib/plugins/slides.js +3 -2
- package/lib/plugins/template.js +6 -3
- package/lib/plus.js +25 -13
- package/lib/prefs.d.ts +0 -14
- package/lib/prefs.js +2 -1
- package/lib/project.js +69 -62
- package/lib/prompt.d.ts +12 -11
- package/lib/prompt.js +38 -20
- package/lib/publish.js +17 -12
- package/lib/reply.js +6 -3
- package/lib/run.js +72 -54
- package/lib/say.d.ts +2 -0
- package/lib/say.js +7 -0
- package/lib/scheduled.js +54 -43
- package/lib/section.d.ts +1 -0
- package/lib/section.js +8 -2
- package/lib/settings/account.d.ts +1 -0
- package/lib/settings/account.js +31 -21
- package/lib/settings/billing.js +55 -28
- package/lib/settings/capabilities.js +26 -15
- package/lib/settings/card.js +19 -12
- package/lib/settings/code.js +22 -11
- package/lib/settings/credits.d.ts +4 -4
- package/lib/settings/credits.js +34 -21
- package/lib/settings/environments.js +21 -14
- package/lib/settings/general.js +26 -14
- package/lib/settings/index.js +6 -3
- package/lib/settings/integrations.js +42 -28
- package/lib/settings/keys.js +37 -19
- package/lib/settings/list.d.ts +0 -5
- package/lib/settings/list.js +24 -15
- package/lib/settings/machines.d.ts +3 -0
- package/lib/settings/machines.js +63 -38
- package/lib/settings/members.js +23 -14
- package/lib/settings/memory.js +12 -6
- package/lib/settings/notifications.js +32 -19
- package/lib/settings/plan.d.ts +1 -1
- package/lib/settings/plan.js +40 -17
- package/lib/settings/privacy.js +26 -13
- package/lib/settings/ui.d.ts +3 -2
- package/lib/settings/ui.js +9 -3
- package/lib/settings/usage.js +7 -3
- package/lib/shelf.js +18 -15
- package/lib/side.d.ts +1 -26
- package/lib/side.js +11 -5
- package/lib/standing.d.ts +2 -10
- package/lib/standing.js +5 -3
- package/lib/suggest.d.ts +8 -28
- package/lib/suggest.js +39 -4
- package/lib/suggestions.js +14 -5
- package/lib/summary.d.ts +1 -1
- package/lib/summary.js +4 -1
- package/lib/sync.js +22 -12
- package/lib/tools.d.ts +4 -3
- package/lib/tools.js +10 -7
- package/lib/transcript.js +10 -8
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -100,6 +100,19 @@ nothing behind a More; `useSessions(host)` is the runs — the org's coding runs
|
|
|
100
100
|
kept live by the org's feed — for a host that draws the rows itself. `administers(token, org)` reads the org-admin bit off a
|
|
101
101
|
hanzo.id token for `Host.admin`. One left column, never two.
|
|
102
102
|
|
|
103
|
+
## Words
|
|
104
|
+
|
|
105
|
+
Every word the builder authors is said through @hanzo/i18n, a required peer
|
|
106
|
+
(`>=0.4.0`): the host's `I18nProvider` is the one asked, and without one the
|
|
107
|
+
builder reads in English, unchanged. A component asks `useI18n()`; copy held as
|
|
108
|
+
data is `phrase()` where it is written and drawn through `t`; a helper outside a
|
|
109
|
+
render (`nav()`, `own()`, `tabs()`, `library()`, turn.ts, the plan sentences)
|
|
110
|
+
takes the caller's `t` last and falls back to `say.ts`'s `english`. Names, model
|
|
111
|
+
ids, what a person typed, what the platform said and figures are drawn as given;
|
|
112
|
+
prompts sent to a model stay in English. `src/e2e/language*.spec.ts` and
|
|
113
|
+
`translated.spec.ts` hold the composer, Projects, Skills and the Library in
|
|
114
|
+
French and right to left in Arabic.
|
|
115
|
+
|
|
103
116
|
## The model, the composer, the panel
|
|
104
117
|
|
|
105
118
|
One of each, shared with Chat (@hanzo/rooms imports them):
|
|
@@ -226,10 +239,15 @@ are any member's.
|
|
|
226
239
|
- Plugins: TypeScript connectors built on the platform, from source or from a
|
|
227
240
|
description of an API; a failed build says why. Browse offers building one and
|
|
228
241
|
lists what the deployment mounts.
|
|
229
|
-
- Agents: Browse is
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
242
|
+
- Agents: Browse is every agent to start from — the host's default agents
|
|
243
|
+
(`cast`) and personas (`personas`), and the platform's presets whose tool
|
|
244
|
+
calls run on the platform — searched by name and filtered by category. Use
|
|
245
|
+
makes one agent of the org's own from one template (a name taken becomes
|
|
246
|
+
`-2`, `-3`), with its face, model and instructions, and opens its profile;
|
|
247
|
+
nothing is added in bulk. Start from scratch, Clone yourself (the person
|
|
248
|
+
signed in, with writing pasted or uploaded) and Create from a person make one
|
|
249
|
+
too. Yours is the org's own — model, instructions, tools, budget — created,
|
|
250
|
+
edited (only what changed is sent) and deleted.
|
|
233
251
|
|
|
234
252
|
**New.** "What's up next?", and at the foot the composer: where the run runs
|
|
235
253
|
(Cloud is the platform's sandbox with the codebase's environment; the org's
|
package/lib/activity.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Activity's words: what a run's state is called and drawn as, how long it
|
|
3
|
-
* took, what it cost, and the one line under its title. Pure, so the screen and
|
|
4
|
-
* its tests read the same sentences.
|
|
5
|
-
*/
|
|
1
|
+
import type { Say } from '@hanzo/i18n/react';
|
|
6
2
|
import type { SessionStatus } from '@hanzo/ui/chat';
|
|
7
3
|
import type { Job, State } from './api/auto.ts';
|
|
8
4
|
/** A job's state as the rail's dot draws it, and in words. */
|
|
@@ -12,8 +8,8 @@ export declare const SAID: Record<State, string>;
|
|
|
12
8
|
export declare function lasted(started: string, finished: string | null, now?: number): string;
|
|
13
9
|
/** Cents as dollars. */
|
|
14
10
|
export declare const dollars: (cents: number) => string;
|
|
15
|
-
/** One line about a job: when it started, how long, what it cost, what it made. */
|
|
16
|
-
export declare function about(j: Job, now?: number): string;
|
|
11
|
+
/** One line about a job: when it started, how long, what it cost, what it made. Its words in the language of `t`. */
|
|
12
|
+
export declare function about(j: Job, now?: number, t?: Say): string;
|
|
17
13
|
/** The jobs, newest first, with `j` in its place. */
|
|
18
14
|
export declare function merged(list: Job[], j: Job): Job[];
|
|
19
15
|
/** A task's name from what it does: its first line, short. */
|
package/lib/activity.js
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity's words: what a run's state is called and drawn as, how long it
|
|
3
|
+
* took, what it cost, and the one line under its title. Pure, so the screen and
|
|
4
|
+
* its tests read the same sentences.
|
|
5
|
+
*/
|
|
6
|
+
import { phrase } from '@hanzo/i18n';
|
|
1
7
|
import { ago } from './ago.js';
|
|
2
8
|
import { SOURCE } from './api/library.js';
|
|
9
|
+
import { english } from './say.js';
|
|
3
10
|
/** A job's state as the rail's dot draws it, and in words. */
|
|
4
11
|
export const DOTS = { scheduled: 'idle', running: 'running', succeeded: 'done', failed: 'error', cancelled: 'stopped' };
|
|
5
|
-
export const SAID = {
|
|
12
|
+
export const SAID = {
|
|
13
|
+
scheduled: phrase('Scheduled'),
|
|
14
|
+
running: phrase('Running'),
|
|
15
|
+
succeeded: phrase('Succeeded'),
|
|
16
|
+
failed: phrase('Failed'),
|
|
17
|
+
cancelled: phrase('Cancelled'),
|
|
18
|
+
};
|
|
6
19
|
/** How long a run took, or has taken so far. */
|
|
7
20
|
export function lasted(started, finished, now = Date.now()) {
|
|
8
21
|
const a = Date.parse(started);
|
|
@@ -20,10 +33,10 @@ export function lasted(started, finished, now = Date.now()) {
|
|
|
20
33
|
}
|
|
21
34
|
/** Cents as dollars. */
|
|
22
35
|
export const dollars = (cents) => `$${(cents / 100).toFixed(2)}`;
|
|
23
|
-
/** One line about a job: when it started, how long, what it cost, what it made. */
|
|
24
|
-
export function about(j, now = Date.now()) {
|
|
25
|
-
const made = j.outputs.length ?
|
|
26
|
-
return [SOURCE[j.product], j.started ? ago(j.started) : '', lasted(j.started, j.finished, now), j.cost !== null ? dollars(j.cost) : '', made].filter(Boolean).join(' · ');
|
|
36
|
+
/** One line about a job: when it started, how long, what it cost, what it made. Its words in the language of `t`. */
|
|
37
|
+
export function about(j, now = Date.now(), t = english) {
|
|
38
|
+
const made = j.outputs.length ? (j.outputs.length === 1 ? t('{n} output', { n: 1 }) : t('{n} outputs', { n: j.outputs.length })) : '';
|
|
39
|
+
return [SOURCE[j.product] ? t(SOURCE[j.product]) : '', j.started ? ago(j.started) : '', lasted(j.started, j.finished, now), j.cost !== null ? dollars(j.cost) : '', made].filter(Boolean).join(' · ');
|
|
27
40
|
}
|
|
28
41
|
/** The jobs, newest first, with `j` in its place. */
|
|
29
42
|
export function merged(list, j) {
|
package/lib/api/agents.d.ts
CHANGED
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agents: the org's own — a model, instructions, the tools it may call and a
|
|
3
|
-
* budget — and the presets one can start from.
|
|
4
|
-
*
|
|
5
|
-
* GET /v1/agent {agents: [agent]}, without instructions
|
|
6
|
-
* POST /v1/agent create → 201 agent
|
|
7
|
-
* GET /v1/agent/{ref} one, with its instructions
|
|
8
|
-
* PATCH /v1/agent/{ref} the fields sent change, the rest stay → agent
|
|
9
|
-
* DELETE /v1/agent/{ref} removes it and every run recorded against it → 204
|
|
10
|
-
* GET /v1/agent/chat/presets {presets: [{id, title, systemPrompt, serverExecuted}]}
|
|
11
|
-
*
|
|
12
|
-
* A ref is the agent's id or its name. A budget is required: the most it may
|
|
13
|
-
* spend in a period and in one run, in micro-USD, and the period — day, week or
|
|
14
|
-
* month. Tools are names from the tool plane; none grants none, and `*` is
|
|
15
|
-
* whatever the fleet's MCP server serves when it runs. An omitted model is the
|
|
16
|
-
* deployment's default. A preset whose tool calls run on the platform
|
|
17
|
-
* (`serverExecuted`) makes a working agent; the others hand their calls back to
|
|
18
|
-
* the client that asked, so they are not offered here.
|
|
19
|
-
*/
|
|
20
1
|
import { type Target } from './call.ts';
|
|
21
2
|
export type Period = 'day' | 'week' | 'month';
|
|
22
3
|
export declare const PERIODS: readonly Period[];
|
|
@@ -35,6 +16,8 @@ export interface Agent {
|
|
|
35
16
|
task: number;
|
|
36
17
|
spent: number;
|
|
37
18
|
period: Period | '';
|
|
19
|
+
/** Its picture: an https link or a data URL; '' draws its emoji or initial. */
|
|
20
|
+
avatar: string;
|
|
38
21
|
emoji: string;
|
|
39
22
|
}
|
|
40
23
|
export interface Preset {
|
|
@@ -52,6 +35,8 @@ export interface Draft {
|
|
|
52
35
|
cap: string;
|
|
53
36
|
task: string;
|
|
54
37
|
period: Period;
|
|
38
|
+
/** Sent on create only: an https link or a data URL. */
|
|
39
|
+
avatar: string;
|
|
55
40
|
}
|
|
56
41
|
/** An agent's name, as the handler takes it. */
|
|
57
42
|
export declare const NAME: RegExp;
|
|
@@ -65,7 +50,7 @@ export declare function agent(raw: unknown): Agent;
|
|
|
65
50
|
/** A draft of an agent as it stands, to edit. */
|
|
66
51
|
export declare function draft(a: Agent): Draft;
|
|
67
52
|
export declare const EMPTY: Draft;
|
|
68
|
-
/** Why a draft cannot be saved as it stands, or '' when it can
|
|
53
|
+
/** Why a draft cannot be saved as it stands, or '' when it can: English, marked (`phrase`), so a screen says it through `t`. */
|
|
69
54
|
export declare function refuse(d: Draft): string;
|
|
70
55
|
export declare function agents(t: Target): Promise<Agent[]>;
|
|
71
56
|
export declare function one(t: Target, ref: string): Promise<Agent>;
|
|
@@ -86,29 +71,45 @@ export declare function profile(t: Target, ref: string): Promise<{
|
|
|
86
71
|
agent: Agent;
|
|
87
72
|
runs: Run[];
|
|
88
73
|
}>;
|
|
89
|
-
/**
|
|
74
|
+
/** An agent to start from: a default agent, a persona or a preset. */
|
|
90
75
|
export interface Cast {
|
|
76
|
+
/** The name it is made under. */
|
|
91
77
|
name: string;
|
|
78
|
+
/** What Browse calls it. */
|
|
79
|
+
title: string;
|
|
92
80
|
description: string;
|
|
81
|
+
/** What Browse lists it under. */
|
|
82
|
+
category: string;
|
|
93
83
|
model: string;
|
|
94
84
|
instructions: string;
|
|
95
|
-
/**
|
|
85
|
+
/** Reads the instructions, where they are a file the host serves. */
|
|
86
|
+
read?: () => Promise<string>;
|
|
87
|
+
/** Its face, an address of the host. */
|
|
96
88
|
avatar?: string;
|
|
89
|
+
tools?: string[];
|
|
97
90
|
}
|
|
98
|
-
/** What a
|
|
91
|
+
/** What an agent made from a template may spend until its owner says otherwise, in dollars: each month, and one run. */
|
|
99
92
|
export declare const CAST_CAP = "10";
|
|
100
93
|
export declare const CAST_TASK = "1";
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
94
|
+
/**
|
|
95
|
+
* A name the API takes: accents dropped, any other run of characters a dash,
|
|
96
|
+
* from a letter or digit, up to 64. "Spärck Jones" is Sparck-Jones.
|
|
97
|
+
*/
|
|
98
|
+
export declare const handle: (name: string) => string;
|
|
99
|
+
/** `name`, or `name-2`, `name-3`… : the first the org has no agent called, in any case. */
|
|
100
|
+
export declare function free(name: string, have: readonly {
|
|
107
101
|
name: string;
|
|
108
|
-
}[]):
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
}[]): string;
|
|
103
|
+
/** An address of the page as an https link the API keeps, or '' (a page served over http has none). */
|
|
104
|
+
export declare const link: (at: string | undefined, base: string) => string;
|
|
105
|
+
/**
|
|
106
|
+
* Make the org's own agent from a template: under the first name the org has
|
|
107
|
+
* free (read now, so it is never one that exists), with its instructions read
|
|
108
|
+
* and its face linked. The template is not touched.
|
|
109
|
+
*/
|
|
110
|
+
export declare function use(t: Target, c: Cast, base: string): Promise<Agent>;
|
|
111
|
+
/** Anyone as a template: their name, who they are, and writing of theirs to take the voice from. */
|
|
112
|
+
export declare function person(name: string, about: string, writing: string, avatar?: string): Cast;
|
|
112
113
|
export declare function create(t: Target, d: Draft): Promise<Agent>;
|
|
113
114
|
/** The fields that differ from `was`, and nothing else: an omitted field keeps its value. */
|
|
114
115
|
export declare function changes(was: Agent, d: Draft): Record<string, unknown>;
|
|
@@ -116,5 +117,5 @@ export declare function update(t: Target, was: Agent, d: Draft): Promise<Agent>;
|
|
|
116
117
|
export declare function remove(t: Target, ref: string): Promise<void>;
|
|
117
118
|
/** The presets that make a working agent. */
|
|
118
119
|
export declare function presets(t: Target): Promise<Preset[]>;
|
|
119
|
-
/** A
|
|
120
|
-
export declare function fromPreset(p: Preset):
|
|
120
|
+
/** A preset as a template. */
|
|
121
|
+
export declare function fromPreset(p: Preset): Cast;
|
package/lib/api/agents.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agents: the org's own — a model, instructions, the tools it may call
|
|
3
|
-
* budget — and the
|
|
2
|
+
* Agents: the org's own — a model, instructions, the tools it may call, a
|
|
3
|
+
* budget and a face — and the templates one is made from.
|
|
4
4
|
*
|
|
5
5
|
* GET /v1/agent {agents: [agent]}, without instructions
|
|
6
6
|
* POST /v1/agent create → 201 agent
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* (`serverExecuted`) makes a working agent; the others hand their calls back to
|
|
18
18
|
* the client that asked, so they are not offered here.
|
|
19
19
|
*/
|
|
20
|
+
import { phrase } from '@hanzo/i18n';
|
|
20
21
|
import { call, seg } from './call.js';
|
|
21
22
|
export const PERIODS = ['day', 'week', 'month'];
|
|
22
23
|
/** An agent's name, as the handler takes it. */
|
|
@@ -47,6 +48,7 @@ export function agent(raw) {
|
|
|
47
48
|
task: num(o.max_task_micro_usd),
|
|
48
49
|
spent: num(o.consumed_micro_usd),
|
|
49
50
|
period: PERIODS.includes(period) ? period : '',
|
|
51
|
+
avatar: str(o.avatar),
|
|
50
52
|
emoji: str(o.emoji),
|
|
51
53
|
};
|
|
52
54
|
}
|
|
@@ -61,23 +63,31 @@ export function draft(a) {
|
|
|
61
63
|
cap: dollars(a.cap),
|
|
62
64
|
task: dollars(a.task),
|
|
63
65
|
period: a.period || 'month',
|
|
66
|
+
avatar: a.avatar,
|
|
64
67
|
};
|
|
65
68
|
}
|
|
66
|
-
export const EMPTY = { name: '', description: '', model: '', instructions: '', tools: [], cap: '', task: '', period: 'month' };
|
|
67
|
-
/**
|
|
69
|
+
export const EMPTY = { name: '', description: '', model: '', instructions: '', tools: [], cap: '', task: '', period: 'month', avatar: '' };
|
|
70
|
+
/** What a budget left unset says, and one run that outspends its period, by the period: whole sentences, so a language says the period its own way. */
|
|
71
|
+
const UNSET = { day: phrase('Set what it may spend each day'), week: phrase('Set what it may spend each week'), month: phrase('Set what it may spend each month') };
|
|
72
|
+
const OVER = {
|
|
73
|
+
day: phrase('One run cannot spend more than the whole day'),
|
|
74
|
+
week: phrase('One run cannot spend more than the whole week'),
|
|
75
|
+
month: phrase('One run cannot spend more than the whole month'),
|
|
76
|
+
};
|
|
77
|
+
/** Why a draft cannot be saved as it stands, or '' when it can: English, marked (`phrase`), so a screen says it through `t`. */
|
|
68
78
|
export function refuse(d) {
|
|
69
79
|
if (!NAME.test(d.name))
|
|
70
|
-
return 'A name is letters, digits, . _ or -, starting with a letter or digit';
|
|
80
|
+
return phrase('A name is letters, digits, . _ or -, starting with a letter or digit');
|
|
71
81
|
if (new TextEncoder().encode(d.instructions).length > MAX)
|
|
72
|
-
return 'Instructions are at most 32 KB';
|
|
82
|
+
return phrase('Instructions are at most 32 KB');
|
|
73
83
|
const cap = micros(d.cap);
|
|
74
84
|
const task = micros(d.task);
|
|
75
85
|
if (!(cap > 0))
|
|
76
|
-
return
|
|
86
|
+
return UNSET[d.period];
|
|
77
87
|
if (!(task > 0))
|
|
78
|
-
return 'Set what one run may spend';
|
|
88
|
+
return phrase('Set what one run may spend');
|
|
79
89
|
if (task > cap)
|
|
80
|
-
return
|
|
90
|
+
return OVER[d.period];
|
|
81
91
|
return '';
|
|
82
92
|
}
|
|
83
93
|
export async function agents(t) {
|
|
@@ -95,27 +105,52 @@ export async function profile(t, ref) {
|
|
|
95
105
|
const raw = await call(t, 'GET', `/v1/agent/${seg(ref)}`);
|
|
96
106
|
return { agent: agent(raw), runs: rows(obj(raw).recentRuns).map(run).filter((r) => r.id) };
|
|
97
107
|
}
|
|
98
|
-
/** What a
|
|
108
|
+
/** What an agent made from a template may spend until its owner says otherwise, in dollars: each month, and one run. */
|
|
99
109
|
export const CAST_CAP = '10';
|
|
100
110
|
export const CAST_TASK = '1';
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
/**
|
|
112
|
+
* A name the API takes: accents dropped, any other run of characters a dash,
|
|
113
|
+
* from a letter or digit, up to 64. "Spärck Jones" is Sparck-Jones.
|
|
114
|
+
*/
|
|
115
|
+
export const handle = (name) => name
|
|
116
|
+
.normalize('NFD')
|
|
117
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
118
|
+
.replace(/[^A-Za-z0-9._-]+/g, '-')
|
|
119
|
+
.replace(/^[^A-Za-z0-9]+/, '')
|
|
120
|
+
.slice(0, 64)
|
|
121
|
+
.replace(/-+$/, '');
|
|
122
|
+
/** `name`, or `name-2`, `name-3`… : the first the org has no agent called, in any case. */
|
|
123
|
+
export function free(name, have) {
|
|
124
|
+
const taken = new Set(have.map((a) => a.name.toLowerCase()));
|
|
125
|
+
if (!taken.has(name.toLowerCase()))
|
|
126
|
+
return name;
|
|
127
|
+
for (let i = 2;; i++) {
|
|
128
|
+
const next = `${name.slice(0, 63 - String(i).length)}-${i}`;
|
|
129
|
+
if (!taken.has(next.toLowerCase()))
|
|
130
|
+
return next;
|
|
117
131
|
}
|
|
118
|
-
|
|
132
|
+
}
|
|
133
|
+
/** An address of the page as an https link the API keeps, or '' (a page served over http has none). */
|
|
134
|
+
export const link = (at, base) => {
|
|
135
|
+
if (!at)
|
|
136
|
+
return '';
|
|
137
|
+
const url = new URL(at, base).href;
|
|
138
|
+
return url.startsWith('https://') || url.startsWith('data:') ? url : '';
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Make the org's own agent from a template: under the first name the org has
|
|
142
|
+
* free (read now, so it is never one that exists), with its instructions read
|
|
143
|
+
* and its face linked. The template is not touched.
|
|
144
|
+
*/
|
|
145
|
+
export async function use(t, c, base) {
|
|
146
|
+
const [have, instructions] = await Promise.all([agents(t), c.read ? c.read() : c.instructions]);
|
|
147
|
+
return create(t, { ...EMPTY, name: free(handle(c.name), have), description: c.description, model: c.model, instructions, tools: c.tools ?? [], cap: CAST_CAP, task: CAST_TASK, avatar: link(c.avatar, base) });
|
|
148
|
+
}
|
|
149
|
+
/** Anyone as a template: their name, who they are, and writing of theirs to take the voice from. */
|
|
150
|
+
export function person(name, about, writing, avatar = '') {
|
|
151
|
+
const who = name.trim();
|
|
152
|
+
const lines = [`You are ${who}.`, about.trim(), writing.trim() && `Writing by ${who}:\n\n${writing.trim()}`];
|
|
153
|
+
return { name: who, title: who, description: about.trim(), category: phrase('Person'), model: '', instructions: lines.filter(Boolean).join('\n\n'), avatar };
|
|
119
154
|
}
|
|
120
155
|
export async function create(t, d) {
|
|
121
156
|
const why = refuse(d);
|
|
@@ -132,6 +167,8 @@ export async function create(t, d) {
|
|
|
132
167
|
};
|
|
133
168
|
if (d.model)
|
|
134
169
|
body.model = d.model;
|
|
170
|
+
if (d.avatar)
|
|
171
|
+
body.avatar = d.avatar;
|
|
135
172
|
return agent(await call(t, 'POST', '/v1/agent', body));
|
|
136
173
|
}
|
|
137
174
|
/** The fields that differ from `was`, and nothing else: an omitted field keeps its value. */
|
|
@@ -173,7 +210,7 @@ export async function presets(t) {
|
|
|
173
210
|
.map((p) => ({ id: str(p.id), title: str(p.title), prompt: str(p.systemPrompt) }))
|
|
174
211
|
.filter((p) => p.id);
|
|
175
212
|
}
|
|
176
|
-
/** A
|
|
213
|
+
/** A preset as a template. */
|
|
177
214
|
export function fromPreset(p) {
|
|
178
|
-
return {
|
|
215
|
+
return { name: p.id, title: p.title || p.id, description: p.title, category: phrase('Preset'), model: '', instructions: p.prompt };
|
|
179
216
|
}
|
package/lib/api/auto.d.ts
CHANGED
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Automations: a task that runs itself, on a schedule or when asked.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/auto/automations {data: [automation]}
|
|
5
|
-
* POST /v1/auto/automations create one: name and instructions
|
|
6
|
-
* GET /v1/auto/automations/{id} one
|
|
7
|
-
* PATCH /v1/auto/automations/{id} change it, or switch it on or off
|
|
8
|
-
* DELETE /v1/auto/automations/{id} delete it, its schedule and its runs
|
|
9
|
-
* POST /v1/auto/automations/{id}/run {run: {id, status}} one run, now
|
|
10
|
-
* GET /v1/auto/automations/{id}/runs {data: [run]} newest first
|
|
11
|
-
* POST /v1/auto/automations/{id}/runs/{run}/review {post} post a held post, or discard it
|
|
12
|
-
* GET /v1/auto/templates {data: [starter]} to start a new one from
|
|
13
|
-
* POST /v1/auto/cron {schedule, says, next} a schedule from a person's words
|
|
14
|
-
* GET /v1/auto/jobs {data: [job]} what runs without you, across products
|
|
15
|
-
* GET /v1/auto/jobs/{id} one job
|
|
16
|
-
* GET /v1/auto/events text/event-stream: `job` and `automation`, the reader's own
|
|
17
|
-
*
|
|
18
|
-
* Each run is one Dev run in this organization, started as the person who last
|
|
19
|
-
* saved what it does. A draft is a flow named and not yet told what to do: it
|
|
20
|
-
* runs once its instructions are saved.
|
|
21
|
-
*/
|
|
1
|
+
import type { Say } from '@hanzo/i18n/react';
|
|
22
2
|
import { type Target } from './call.ts';
|
|
23
3
|
import { type Source } from './library.ts';
|
|
24
4
|
export type { Source };
|
|
@@ -107,8 +87,8 @@ export declare function start(t: Target, id: string): Promise<{
|
|
|
107
87
|
export declare function runs(t: Target, id: string): Promise<Run[]>;
|
|
108
88
|
/** Post a held post to the automation's accounts, or discard it. */
|
|
109
89
|
export declare function review(t: Target, id: string, runId: string, post: boolean): Promise<Run>;
|
|
110
|
-
/** A schedule the way a person says it. */
|
|
111
|
-
export declare function words(s: Schedule): string;
|
|
90
|
+
/** A schedule the way a person says it, in the words of the `t` handed (English without one). */
|
|
91
|
+
export declare function words(s: Schedule, t?: Say): string;
|
|
112
92
|
/** A ready-made automation to start a new one from. Its schedule names no zone: the page fills in the person's. */
|
|
113
93
|
export interface Starter {
|
|
114
94
|
key: string;
|
package/lib/api/auto.js
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* saved what it does. A draft is a flow named and not yet told what to do: it
|
|
20
20
|
* runs once its instructions are saved.
|
|
21
21
|
*/
|
|
22
|
+
import { phrase } from '@hanzo/i18n';
|
|
23
|
+
import { english } from '../say.js';
|
|
22
24
|
import { call, headers, query, reason, Refusal, seg } from './call.js';
|
|
23
25
|
import { inApp } from './library.js';
|
|
24
26
|
import { read as stream } from './sse.js';
|
|
@@ -78,13 +80,13 @@ export async function automations(t) {
|
|
|
78
80
|
export async function automation(t, id) {
|
|
79
81
|
const a = read(await call(t, 'GET', `/v1/auto/automations/${seg(id)}`));
|
|
80
82
|
if (!a)
|
|
81
|
-
throw new Error('The automation came back without an id');
|
|
83
|
+
throw new Error(phrase('The automation came back without an id'));
|
|
82
84
|
return a;
|
|
83
85
|
}
|
|
84
86
|
export async function create(t, d) {
|
|
85
87
|
const a = read(await call(t, 'POST', '/v1/auto/automations', d));
|
|
86
88
|
if (!a)
|
|
87
|
-
throw new Error('The automation was created and came back without an id');
|
|
89
|
+
throw new Error(phrase('The automation was created and came back without an id'));
|
|
88
90
|
return a;
|
|
89
91
|
}
|
|
90
92
|
/** What changed between two drafts, field by field: what a save sends. */
|
|
@@ -100,7 +102,7 @@ export function changes(was, now) {
|
|
|
100
102
|
export async function save(t, id, change) {
|
|
101
103
|
const a = read(await call(t, 'PATCH', `/v1/auto/automations/${seg(id)}`, change));
|
|
102
104
|
if (!a)
|
|
103
|
-
throw new Error('The automation was saved and came back without an id');
|
|
105
|
+
throw new Error(phrase('The automation was saved and came back without an id'));
|
|
104
106
|
return a;
|
|
105
107
|
}
|
|
106
108
|
export async function remove(t, id) {
|
|
@@ -130,40 +132,55 @@ function run(o) {
|
|
|
130
132
|
export async function review(t, id, runId, post) {
|
|
131
133
|
return run(obj(await call(t, 'POST', `/v1/auto/automations/${seg(id)}/runs/${seg(runId)}/review`, { post })));
|
|
132
134
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
/** A weekly schedule's sentence by its day: one sentence each, so a language says the day its own way. */
|
|
136
|
+
const DAYS = {
|
|
137
|
+
mon: phrase('Mondays at {time} · {zone}'),
|
|
138
|
+
tue: phrase('Tuesdays at {time} · {zone}'),
|
|
139
|
+
wed: phrase('Wednesdays at {time} · {zone}'),
|
|
140
|
+
thu: phrase('Thursdays at {time} · {zone}'),
|
|
141
|
+
fri: phrase('Fridays at {time} · {zone}'),
|
|
142
|
+
sat: phrase('Saturdays at {time} · {zone}'),
|
|
143
|
+
sun: phrase('Sundays at {time} · {zone}'),
|
|
144
|
+
};
|
|
145
|
+
/** A once schedule's local date, as a person reads it, and its time. */
|
|
135
146
|
function once(at) {
|
|
136
147
|
const m = at.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/);
|
|
137
148
|
if (!m)
|
|
138
|
-
return
|
|
149
|
+
return null;
|
|
139
150
|
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]), Number(m[4]), Number(m[5]));
|
|
140
|
-
return
|
|
151
|
+
return { date: d.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' }), time: `${m[4]}:${m[5]}` };
|
|
141
152
|
}
|
|
142
|
-
/** A schedule the way a person says it. */
|
|
143
|
-
export function words(s) {
|
|
144
|
-
const zone =
|
|
153
|
+
/** A schedule the way a person says it, in the words of the `t` handed (English without one). */
|
|
154
|
+
export function words(s, t = english) {
|
|
155
|
+
const zone = s.tz || 'UTC';
|
|
145
156
|
switch (s.kind) {
|
|
146
157
|
case 'manual':
|
|
147
|
-
return 'When you run it';
|
|
148
|
-
case 'once':
|
|
149
|
-
|
|
158
|
+
return t('When you run it');
|
|
159
|
+
case 'once': {
|
|
160
|
+
if (!s.at)
|
|
161
|
+
return t('Once, now');
|
|
162
|
+
const when = once(s.at);
|
|
163
|
+
return when ? t('Once, {date} at {time} · {zone}', { ...when, zone }) : t('Once, {at} · {zone}', { at: s.at, zone });
|
|
164
|
+
}
|
|
150
165
|
case 'hourly':
|
|
151
|
-
return
|
|
166
|
+
return t('Every hour at :{minute}', { minute: (s.at ?? '00:00').slice(3) || '00' });
|
|
152
167
|
case 'daily':
|
|
153
|
-
return
|
|
168
|
+
return t('Every day at {time} · {zone}', { time: s.at ?? '', zone });
|
|
154
169
|
case 'weekdays':
|
|
155
|
-
return
|
|
156
|
-
case 'weekly':
|
|
157
|
-
|
|
170
|
+
return t('Weekdays at {time} · {zone}', { time: s.at ?? '', zone });
|
|
171
|
+
case 'weekly': {
|
|
172
|
+
const day = DAYS[s.day ?? ''];
|
|
173
|
+
return day ? t(day, { time: s.at ?? '', zone }) : t('{day} at {time} · {zone}', { day: s.day ?? '', time: s.at ?? '', zone });
|
|
174
|
+
}
|
|
158
175
|
case 'cron': {
|
|
159
176
|
// The two a person says most, in their words; any other expression as written.
|
|
160
177
|
const minutes = (s.cron ?? '').match(/^\*\/(\d+) \* \* \* \*$/);
|
|
161
178
|
if (minutes)
|
|
162
|
-
return
|
|
179
|
+
return t('Every {n} minutes · {zone}', { n: minutes[1], zone });
|
|
163
180
|
const hours = (s.cron ?? '').match(/^0 \*\/(\d+) \* \* \*$/);
|
|
164
181
|
if (hours)
|
|
165
|
-
return
|
|
166
|
-
return
|
|
182
|
+
return t('Every {n} hours · {zone}', { n: hours[1], zone });
|
|
183
|
+
return t('Cron {cron} · {zone}', { cron: s.cron ?? '', zone });
|
|
167
184
|
}
|
|
168
185
|
}
|
|
169
186
|
}
|
|
@@ -241,7 +258,7 @@ export async function jobs(t, f = {}) {
|
|
|
241
258
|
export async function one(t, id) {
|
|
242
259
|
const j = job(await call(t, 'GET', `/v1/auto/jobs/${seg(id)}`));
|
|
243
260
|
if (!j)
|
|
244
|
-
throw new Error('The job came back without an id');
|
|
261
|
+
throw new Error(phrase('The job came back without an id'));
|
|
245
262
|
return j;
|
|
246
263
|
}
|
|
247
264
|
/** One frame of /v1/auto/events, or null for one this page does not read. */
|
package/lib/api/billing.d.ts
CHANGED
|
@@ -1,38 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The organization's money: its plan, the cards it pays with, its invoices, its
|
|
3
|
-
* balance and credits, what it has spent this month, and the caps on that spend.
|
|
4
|
-
*
|
|
5
|
-
* GET /v1/billing/plans the catalog the serving brand sells (public)
|
|
6
|
-
* GET /v1/billing/subscriptions {count, subscriptions}
|
|
7
|
-
* POST /v1/billing/subscribe/card buy a plan with a saved card; one paid plan at a time (409)
|
|
8
|
-
* POST /v1/billing/subscriptions/{id}/cancel at the end of the paid period
|
|
9
|
-
* POST /v1/billing/subscriptions/{id}/reactivate
|
|
10
|
-
* GET /v1/billing/methods saved cards, newest first
|
|
11
|
-
* POST /v1/billing/methods save a card from the processor's single-use token
|
|
12
|
-
* DELETE /v1/billing/methods/{id}
|
|
13
|
-
* GET /v1/billing/settings the processor a browser tokenizes a card against
|
|
14
|
-
* GET /v1/billing/invoices {count, cursor, invoices}
|
|
15
|
-
* GET /v1/billing/invoices/{id}/pdf the invoice as a PDF
|
|
16
|
-
* GET /v1/billing/balance prepaid balance, whole cents
|
|
17
|
-
* GET /v1/billing/credit-balance granted credit, per currency
|
|
18
|
-
* GET /v1/billing/credits {grants}: every grant, spent and lapsed included
|
|
19
|
-
* GET /v1/billing/tier the rung served and its tier class
|
|
20
|
-
* GET /v1/billing/recharge the auto-reload rule
|
|
21
|
-
* PUT /v1/billing/recharge arm it (a card on file) or disarm it
|
|
22
|
-
* POST /v1/billing/topup charge a saved card into the balance
|
|
23
|
-
* GET /v1/billing/usage/rollup the plan's month: included spend and request windows
|
|
24
|
-
* GET /v1/usage/summary?range=month this month's spend, by category
|
|
25
|
-
* GET /v1/allowance the Free plan's allowance, and the pool it is served from
|
|
26
|
-
* GET /v1/billing/alerts spend caps (bare array)
|
|
27
|
-
* POST /v1/billing/alerts open a cap (org admin)
|
|
28
|
-
* PATCH /v1/billing/alerts/{id} change one (org admin)
|
|
29
|
-
* DELETE /v1/billing/alerts/{id} lift one (org admin)
|
|
30
|
-
*
|
|
31
|
-
* Every figure is whole cents. The wallet, the caps and the cards are the
|
|
32
|
-
* caller's own, resolved by the platform from the credential; nothing here names
|
|
33
|
-
* an org or a subject. No card number passes through this file: a card is saved
|
|
34
|
-
* from the token the processor's own form returns.
|
|
35
|
-
*/
|
|
36
1
|
import { type Target } from './call.ts';
|
|
37
2
|
/** `$1,234.56` from whole cents; whole dollars drop the cents. */
|
|
38
3
|
export declare function money(cents: number, currency?: string): string;
|
package/lib/api/billing.js
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
* an org or a subject. No card number passes through this file: a card is saved
|
|
34
34
|
* from the token the processor's own form returns.
|
|
35
35
|
*/
|
|
36
|
+
import { phrase } from '@hanzo/i18n';
|
|
36
37
|
import { call, headers, reason, Refusal, seg } from './call.js';
|
|
37
38
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
38
39
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
@@ -115,7 +116,7 @@ export async function subscriptions(t) {
|
|
|
115
116
|
/** Buy a plan. No amount is sent: the catalog prices it, and the platform charges that. */
|
|
116
117
|
export async function subscribe(t, p) {
|
|
117
118
|
if (!p.method)
|
|
118
|
-
throw new Error('Add a card before choosing a paid plan');
|
|
119
|
+
throw new Error(phrase('Add a card before choosing a paid plan'));
|
|
119
120
|
const raw = obj(await call(t, 'POST', '/v1/billing/subscribe/card', { planId: p.plan, paymentMethodId: p.method, interval: p.interval }));
|
|
120
121
|
return { subscription: str(raw.subscriptionId), charged: num(raw.amountCents) };
|
|
121
122
|
}
|
|
@@ -183,7 +184,7 @@ export function chosen(list) {
|
|
|
183
184
|
/** Save a card from the single-use token the processor's form returned, optionally with billing info. */
|
|
184
185
|
export async function save(t, token, billingAddress) {
|
|
185
186
|
if (!token)
|
|
186
|
-
throw new Error('The card form returned no token');
|
|
187
|
+
throw new Error(phrase('The card form returned no token'));
|
|
187
188
|
const body = { type: 'card', providerRef: token };
|
|
188
189
|
if (billingAddress && Object.values(billingAddress).some(Boolean)) {
|
|
189
190
|
body.billingAddress = billingAddress;
|
|
@@ -299,9 +300,9 @@ export async function arm(t, rule) {
|
|
|
299
300
|
/** Charge a saved card and add the amount to the balance; answers the balance after. */
|
|
300
301
|
export async function topup(t, amount, card) {
|
|
301
302
|
if (!Number.isInteger(amount) || amount <= 0)
|
|
302
|
-
throw new Error('Enter an amount to add');
|
|
303
|
+
throw new Error(phrase('Enter an amount to add'));
|
|
303
304
|
if (!card)
|
|
304
|
-
throw new Error('Add a card before buying more');
|
|
305
|
+
throw new Error(phrase('Add a card before buying more'));
|
|
305
306
|
const r = obj(await call(t, 'POST', '/v1/billing/topup', { amountCents: amount, paymentMethodId: card }));
|
|
306
307
|
return num(r.balanceCents);
|
|
307
308
|
}
|
|
@@ -371,7 +372,7 @@ export function monthly(list) {
|
|
|
371
372
|
/** Set the org's monthly cap: change the one there is, or open one that refuses spend past it. */
|
|
372
373
|
export async function limit(t, list, threshold) {
|
|
373
374
|
if (!Number.isInteger(threshold) || threshold <= 0)
|
|
374
|
-
throw new Error('Enter a monthly limit');
|
|
375
|
+
throw new Error(phrase('Enter a monthly limit'));
|
|
375
376
|
const was = monthly(list);
|
|
376
377
|
if (was)
|
|
377
378
|
return cap(await call(t, 'PATCH', `/v1/billing/alerts/${seg(was.id)}`, { threshold }));
|