@hanzo/rooms 0.1.38 → 0.1.40
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 +2 -2
- package/dist/Account.js +18 -9
- package/dist/Chat.js +125 -202
- package/dist/Column.js +16 -15
- package/dist/Directory.d.ts +4 -9
- package/dist/Directory.js +60 -155
- package/dist/Me.js +20 -16
- package/dist/Prose.js +5 -4
- package/dist/RightPane.d.ts +20 -28
- package/dist/RightPane.js +107 -327
- package/dist/Settings.js +42 -28
- package/dist/Shell.js +19 -22
- package/dist/dev.js +42 -26
- package/dist/host.d.ts +5 -9
- package/dist/host.js +5 -6
- package/dist/lib/destination.d.ts +6 -6
- package/dist/lib/destination.js +6 -6
- package/dist/lib/host.d.ts +50 -31
- package/dist/lib/host.js +98 -48
- package/dist/lib/limits.d.ts +13 -9
- package/dist/lib/limits.js +20 -0
- package/dist/lib/plans.d.ts +2 -13
- package/dist/lib/plans.js +2 -19
- package/dist/lib/session.d.ts +9 -12
- package/dist/lib/session.js +7 -19
- package/dist/lib/web.d.ts +46 -38
- package/dist/lib/web.js +480 -213
- package/dist/pane.d.ts +4 -57
- package/dist/pane.js +13 -159
- package/package.json +3 -5
- package/dist/Billing.d.ts +0 -1
- package/dist/Billing.js +0 -32
- package/dist/enso.d.ts +0 -72
- package/dist/enso.js +0 -112
- package/dist/model.d.ts +0 -4
- package/dist/model.js +0 -44
package/dist/lib/host.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which host this export is read on,
|
|
2
|
+
* Which host this export is read on, what that host keeps, and the app's
|
|
3
|
+
* addresses — the one module that writes and reads them.
|
|
3
4
|
*
|
|
4
5
|
* hanzo.ai is the site for a stranger and the app for a member: the web app is
|
|
5
|
-
*
|
|
6
|
-
* workspace, its own app (hanzo-apps/team) with Home
|
|
7
|
-
* still carries the rooms, so a room asked for on the
|
|
8
|
-
* room on hanzo.team, and `output: 'export'` has no
|
|
9
|
-
* decided in the browser off the hostname, here.
|
|
6
|
+
* /chat and /dev once signed in, and `/` takes a member to the mode they were
|
|
7
|
+
* last in. hanzo.team is the workspace, its own app (hanzo-apps/team) with Home
|
|
8
|
+
* at its root. This export still carries the rooms, so a room asked for on the
|
|
9
|
+
* apex is sent to the same room on hanzo.team, and `output: 'export'` has no
|
|
10
|
+
* server to do that, so it is decided in the browser off the hostname, here.
|
|
10
11
|
*
|
|
11
12
|
* Two predicates, one per product: `apex()` for the app, `team()` for the
|
|
12
13
|
* workspace. Every host that is neither (localhost, a preview) draws the whole
|
|
13
14
|
* workspace and admits the way the apex does.
|
|
14
15
|
*/
|
|
15
16
|
import APP from './rooms.json' with { type: 'json' };
|
|
17
|
+
import { href, parse, path, route, SESSION, SLUG } from '@hanzo/build/route';
|
|
16
18
|
import { site } from '../where.js';
|
|
17
19
|
/** The workspace's own address. */
|
|
18
20
|
export const WORKSPACE = 'https://hanzo.team';
|
|
@@ -32,59 +34,107 @@ export const ENTRY = `${WORKSPACE}/?signin`;
|
|
|
32
34
|
*/
|
|
33
35
|
export const START = `${WORKSPACE}/start`;
|
|
34
36
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
37
|
+
* THE APP'S ADDRESSES ARE PATHS, in two modes at two roots. Chat is /chat, a
|
|
38
|
+
* new conversation, and /chat/<id> one of the reader's. Dev is /dev, Dev's New,
|
|
39
|
+
* and every place of @hanzo/build's builder is a path under it, written and
|
|
40
|
+
* read by `href`/`parse` (@hanzo/build/route): /dev/run/<id>, /dev/projects,
|
|
41
|
+
* /dev/projects/<org>/<repo> a repository, /dev/projects/<slug> a deployed
|
|
42
|
+
* site, /dev/issues, /dev/artifacts, /dev/templates, /dev/automations[/<id>],
|
|
43
|
+
* /dev/machines, /dev/environments, /dev/customize[/<tab>],
|
|
44
|
+
* /dev/settings[/<section>], /dev/plans. The export holds one page per root,
|
|
45
|
+
* /chat and /dev, and the edge serves it for every path under it (hanzo.ai's
|
|
46
|
+
* lib/edge.ts `APP`), so every address reloads.
|
|
43
47
|
*/
|
|
48
|
+
export const CHAT = '/chat';
|
|
44
49
|
export const DEV = '/dev';
|
|
45
|
-
/**
|
|
46
|
-
export const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
/** Chat on a conversation, or /chat itself for a new one. */
|
|
51
|
+
export const talk = (id) => (id ? `${CHAT}/${encodeURIComponent(id)}` : CHAT);
|
|
52
|
+
/** Dev at a builder address (`route` in @hanzo/build); '' is New, /dev. What is not an address is New. */
|
|
53
|
+
export const app = (at) => DEV + href(route(at));
|
|
54
|
+
/** /chat/shared is a page of its own, where a chat shared by link is read (lib/share.ts). */
|
|
55
|
+
const SHARED = 'shared';
|
|
56
|
+
/** The place a path names, or null when it names none of the app's. */
|
|
57
|
+
export function place(pathname) {
|
|
58
|
+
const p = pathname.replace(/\/+$/, '') || '/';
|
|
59
|
+
if (p === CHAT)
|
|
60
|
+
return { mode: 'chat', thread: null };
|
|
61
|
+
if (p === DEV || p.startsWith(`${DEV}/`))
|
|
62
|
+
return { mode: 'dev', at: path(parse(p.slice(DEV.length))) };
|
|
63
|
+
if (!p.startsWith(`${CHAT}/`))
|
|
53
64
|
return null;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!pathname.startsWith(`${DEV}/`))
|
|
65
|
+
const id = p.slice(CHAT.length + 1);
|
|
66
|
+
if (id.includes('/') || id === SHARED)
|
|
57
67
|
return null;
|
|
58
68
|
try {
|
|
59
|
-
return decodeURIComponent(
|
|
69
|
+
return { mode: 'chat', thread: decodeURIComponent(id) };
|
|
60
70
|
}
|
|
61
71
|
catch {
|
|
62
|
-
return
|
|
72
|
+
return null;
|
|
63
73
|
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
}
|
|
75
|
+
/** An address as analytics counts it: a record folded to its kind, so every conversation is one page. */
|
|
76
|
+
export function page(pathname) {
|
|
77
|
+
const at = place(pathname);
|
|
78
|
+
if (!at)
|
|
79
|
+
return pathname;
|
|
80
|
+
if (at.mode === 'chat')
|
|
81
|
+
return at.thread ? `${CHAT}/:id` : CHAT;
|
|
82
|
+
const r = route(at.at);
|
|
83
|
+
if (r.kind === 'run')
|
|
84
|
+
return `${DEV}/run/:id`;
|
|
85
|
+
if (r.kind === 'repo')
|
|
86
|
+
return `${DEV}/projects/:org/:repo`;
|
|
87
|
+
if (r.kind === 'project')
|
|
88
|
+
return `${DEV}/projects/:slug`;
|
|
89
|
+
if (r.kind === 'automation' && r.id !== 'new')
|
|
90
|
+
return `${DEV}/automations/:id`;
|
|
91
|
+
return DEV + href(r);
|
|
92
|
+
}
|
|
77
93
|
/** A repository on the forge, `<org>/<name>`. */
|
|
78
94
|
const REPO = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}\/[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
79
95
|
/**
|
|
80
|
-
* Dev opened on one run,
|
|
81
|
-
* link, a room's Dev, the console's "open in the builder". It signs a
|
|
82
|
-
* in on the way (app/(app)/dev/_door.tsx), and is reached through
|
|
83
|
-
* here on hanzo.ai, across to hanzo.ai from hanzo.team. Only a value
|
|
84
|
-
* exactly a session id, a repository or a site's slug is carried;
|
|
85
|
-
* opens /dev itself, so no caller can make this name another
|
|
96
|
+
* Dev opened on one run, repository or site, from anywhere: every "Try Hanzo
|
|
97
|
+
* Dev" link, a room's Dev, the console's "open in the builder". It signs a
|
|
98
|
+
* stranger in on the way (app/(app)/dev/_door.tsx), and is reached through
|
|
99
|
+
* `site()`: here on hanzo.ai, across to hanzo.ai from hanzo.team. Only a value
|
|
100
|
+
* that is exactly a session id, a repository or a site's slug is carried;
|
|
101
|
+
* anything else opens /dev itself, so no caller can make this name another
|
|
102
|
+
* address.
|
|
86
103
|
*/
|
|
87
|
-
export const dev = (ref) => site(ref && (SESSION.test(ref) || REPO.test(ref) || SLUG.test(ref)) ?
|
|
104
|
+
export const dev = (ref) => site(app(ref && (SESSION.test(ref) || REPO.test(ref) || SLUG.test(ref)) ? ref : ''));
|
|
105
|
+
/**
|
|
106
|
+
* Move the app to an address of this page: a history entry, or in place of this
|
|
107
|
+
* one. No document load and no route change — the Next router folds a native
|
|
108
|
+
* history entry into `usePathname`, so the app follows the path it reads.
|
|
109
|
+
*/
|
|
110
|
+
export function go(address, replace = false) {
|
|
111
|
+
if (`${window.location.pathname}${window.location.search}` === address)
|
|
112
|
+
return;
|
|
113
|
+
if (replace)
|
|
114
|
+
window.history.replaceState(null, '', address);
|
|
115
|
+
else
|
|
116
|
+
window.history.pushState(null, '', address);
|
|
117
|
+
}
|
|
118
|
+
/** Where this browser keeps the mode its reader was last in. */
|
|
119
|
+
const MODE = 'hanzo.app.mode';
|
|
120
|
+
/** Keep the mode the reader is in, for `resume`. */
|
|
121
|
+
export function remember(mode) {
|
|
122
|
+
try {
|
|
123
|
+
window.localStorage.setItem(MODE, mode);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
/* no store: `/` opens Chat */
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Where `/` takes a member: the mode they were last in, Chat when none is kept. */
|
|
130
|
+
export function resume() {
|
|
131
|
+
try {
|
|
132
|
+
return window.localStorage.getItem(MODE) === 'dev' ? DEV : CHAT;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return CHAT;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
88
138
|
/** The routes under app/(app) the apex keeps: the app — /chat, a chat shared by link, and /dev. */
|
|
89
139
|
const KEPT = new Set(['/chat', '/chat/shared', '/dev']);
|
|
90
140
|
/** Settings, and every page under it: the person's and the organization's, served wherever the app is. */
|
|
@@ -135,7 +185,7 @@ export const GET = 'https://hanzo.app';
|
|
|
135
185
|
* is signed out is asked to sign in there, on hanzo.ai's own page, and lands
|
|
136
186
|
* back in the chat.
|
|
137
187
|
*/
|
|
138
|
-
export const WEB = `${SIGNIN}
|
|
188
|
+
export const WEB = `${SIGNIN}${CHAT}`;
|
|
139
189
|
/**
|
|
140
190
|
* Whether a host serves this export and signs nobody in: hanzo.app, whose root
|
|
141
191
|
* is the page above; every `<slug>.hanzo.app` alias the Sites plane serves it
|
package/dist/lib/limits.d.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The plan's usage, as @hanzo/ui holds it: `GET /v1/ai/limits` read as whoever
|
|
3
|
-
* holds the bearer in this browser's organization, kept current by every AI
|
|
4
|
-
* call `observed` (lib/served.ts) hands to `observe`. Shares only.
|
|
5
|
-
*
|
|
6
|
-
* Same base URL and headers as every billing read (lib/hanzo/tier.ts): the
|
|
7
|
-
* bearer is the subject and `X-Org-Id` the organization this browser works in.
|
|
8
|
-
*/
|
|
9
1
|
import { type UseLimits } from '@hanzo/ui/product/useLimits';
|
|
10
|
-
import { paidPlan } from '@hanzo/ui/product/limits';
|
|
2
|
+
import { paidPlan, type LimitAction, type LimitNotice } from '@hanzo/ui/product/limits';
|
|
11
3
|
/** Reads the limits as whoever holds the bearer, in this browser's organization. */
|
|
12
4
|
export declare function readLimits(signal: AbortSignal): Promise<unknown>;
|
|
13
5
|
/**
|
|
@@ -28,6 +20,18 @@ export declare const useLimits: (enabled?: boolean, org?: string | null, name?:
|
|
|
28
20
|
*/
|
|
29
21
|
export declare const spendShown: ({ limits, answered }: Pick<UseLimits, 'limits' | 'answered'>) => boolean;
|
|
30
22
|
export { paidPlan };
|
|
23
|
+
/**
|
|
24
|
+
* What the banner over the composer says once the reader is turned away, and
|
|
25
|
+
* the ways on. A spent allowance is said by the plan's name and when it comes
|
|
26
|
+
* back — `Your Max 20x plan’s included premium model usage is used until 5:00
|
|
27
|
+
* PM.` — and a spent request window the same way; any other refusal in the
|
|
28
|
+
* server's own words. The ways are @hanzo/build's `ways`: continue with credits
|
|
29
|
+
* where the org holds some, else add credits; then the upgrade.
|
|
30
|
+
*/
|
|
31
|
+
export declare function paused(n: LimitNotice, plan: string, name?: (id: string) => string, now?: number): {
|
|
32
|
+
message: string;
|
|
33
|
+
actions: LimitAction[];
|
|
34
|
+
};
|
|
31
35
|
/** Whether a catalog family is one of Hanzo's chat families, Enso or Zen, whose turns carry the live web. */
|
|
32
36
|
export declare const house: (family: string | undefined) => boolean;
|
|
33
37
|
/**
|
package/dist/lib/limits.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Same base URL and headers as every billing read (lib/hanzo/tier.ts): the
|
|
8
8
|
* bearer is the subject and `X-Org-Id` the organization this browser works in.
|
|
9
9
|
*/
|
|
10
|
+
import { label, said, spent, ways, when } from '@hanzo/build/plan';
|
|
10
11
|
import { useLimits as useHeld } from '@hanzo/ui/product/useLimits';
|
|
11
12
|
import { paidPlan } from '@hanzo/ui/product/limits';
|
|
12
13
|
import { api } from './api.js';
|
|
@@ -47,6 +48,25 @@ export const useLimits = (enabled = true, org = null, name) => useHeld(enabled ?
|
|
|
47
48
|
*/
|
|
48
49
|
export const spendShown = ({ limits, answered }) => answered && !paidPlan(limits);
|
|
49
50
|
export { paidPlan };
|
|
51
|
+
/**
|
|
52
|
+
* What the banner over the composer says once the reader is turned away, and
|
|
53
|
+
* the ways on. A spent allowance is said by the plan's name and when it comes
|
|
54
|
+
* back — `Your Max 20x plan’s included premium model usage is used until 5:00
|
|
55
|
+
* PM.` — and a spent request window the same way; any other refusal in the
|
|
56
|
+
* server's own words. The ways are @hanzo/build's `ways`: continue with credits
|
|
57
|
+
* where the org holds some, else add credits; then the upgrade.
|
|
58
|
+
*/
|
|
59
|
+
export function paused(n, plan, name = (id) => id, now = Date.now()) {
|
|
60
|
+
const l = label(plan);
|
|
61
|
+
const until = when(n.resets_at ?? '', now);
|
|
62
|
+
const on = n.fallback ? ` You’re chatting on ${name(n.fallback)}.` : '';
|
|
63
|
+
const message = n.reason === 'plan_allowance_used' || (!n.reason && n.classes.length > 0)
|
|
64
|
+
? spent(l, n.classes, n.resets_at ?? '', now) + on
|
|
65
|
+
: n.reason === 'usage_cap_exceeded'
|
|
66
|
+
? `Your ${l ? `${said(l)} plan’s` : 'plan’s'} requests are used${until ? ` until ${until}` : ''}.${on}`
|
|
67
|
+
: n.message;
|
|
68
|
+
return { message, actions: ways(n.actions) };
|
|
69
|
+
}
|
|
50
70
|
/** Whether a catalog family is one of Hanzo's chat families, Enso or Zen, whose turns carry the live web. */
|
|
51
71
|
export const house = (family) => family === 'enso' || family === 'zen';
|
|
52
72
|
/**
|
package/dist/lib/plans.d.ts
CHANGED
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
* A SuperAdmin edits these rows at admin.hanzo.ai (/v1/commerce/plans/entries),
|
|
27
27
|
* and every reader here follows: the build bakes the authority's answer into the
|
|
28
28
|
* pricing snapshot for the first paint, and the page replaces it with the live
|
|
29
|
-
* read. No price in this repo is typed
|
|
30
|
-
*
|
|
29
|
+
* read. No price in this repo is typed, and no plan's name: a slug is named by
|
|
30
|
+
* @hanzo/build's `label` (`max-20x` reads Max, with 20x beside it).
|
|
31
31
|
*/
|
|
32
32
|
/** A row exactly as GET /v1/billing/plans returns it. */
|
|
33
33
|
export interface BillingPlan {
|
|
@@ -150,17 +150,6 @@ export declare function charge(plan: SubscriptionPlan, interval: Interval): numb
|
|
|
150
150
|
export declare function quote(plan: SubscriptionPlan, interval: Interval): string | null;
|
|
151
151
|
/** What a year saves against twelve months, as a whole percent: 1 − year ÷ (12 × month). Null where it saves nothing. */
|
|
152
152
|
export declare function saving(plan: SubscriptionPlan): number | null;
|
|
153
|
-
/**
|
|
154
|
-
* The catalog's own name for a plan slug — "max-20x" reads as "Max 20x" —
|
|
155
|
-
* or null where the slug is empty or the catalog does not carry it.
|
|
156
|
-
*
|
|
157
|
-
* Read off the published package: a plan's name does not move between a build and the next release the way
|
|
158
|
-
* its price can, so the bundled copy is not a stale answer here the way it
|
|
159
|
-
* would be for money. A reader of `GET /v1/billing/tier`'s `plan` field
|
|
160
|
-
* needs a name and nothing else, so no live fetch is spent proving what the
|
|
161
|
-
* package already states.
|
|
162
|
-
*/
|
|
163
|
-
export declare function planName(slug: string | null | undefined): string | null;
|
|
164
153
|
/**
|
|
165
154
|
* A usage rate as money. A sub-dollar rate needs at least two decimals to read as
|
|
166
155
|
* a price at all — 0.1 is $0.10, not $0.1 — while keeping the precision the
|
package/dist/lib/plans.js
CHANGED
|
@@ -26,11 +26,10 @@
|
|
|
26
26
|
* A SuperAdmin edits these rows at admin.hanzo.ai (/v1/commerce/plans/entries),
|
|
27
27
|
* and every reader here follows: the build bakes the authority's answer into the
|
|
28
28
|
* pricing snapshot for the first paint, and the page replaces it with the live
|
|
29
|
-
* read. No price in this repo is typed
|
|
30
|
-
*
|
|
29
|
+
* read. No price in this repo is typed, and no plan's name: a slug is named by
|
|
30
|
+
* @hanzo/build's `label` (`max-20x` reads Max, with 20x beside it).
|
|
31
31
|
*/
|
|
32
32
|
import { useEffect, useMemo, useState } from "react";
|
|
33
|
-
import { subscriptionPlans } from "@hanzo/plans";
|
|
34
33
|
import { where } from "../where.js";
|
|
35
34
|
import { api } from "./api.js";
|
|
36
35
|
import { BILLING_URL, checkoutUrl, dollars, money, payUrl } from "./pay.js";
|
|
@@ -222,22 +221,6 @@ export function saving(plan) {
|
|
|
222
221
|
return null;
|
|
223
222
|
return Math.round((1 - year / (12 * month)) * 100);
|
|
224
223
|
}
|
|
225
|
-
/**
|
|
226
|
-
* The catalog's own name for a plan slug — "max-20x" reads as "Max 20x" —
|
|
227
|
-
* or null where the slug is empty or the catalog does not carry it.
|
|
228
|
-
*
|
|
229
|
-
* Read off the published package: a plan's name does not move between a build and the next release the way
|
|
230
|
-
* its price can, so the bundled copy is not a stale answer here the way it
|
|
231
|
-
* would be for money. A reader of `GET /v1/billing/tier`'s `plan` field
|
|
232
|
-
* needs a name and nothing else, so no live fetch is spent proving what the
|
|
233
|
-
* package already states.
|
|
234
|
-
*/
|
|
235
|
-
export function planName(slug) {
|
|
236
|
-
if (!slug)
|
|
237
|
-
return null;
|
|
238
|
-
const row = subscriptionPlans.find((p) => p.id === slug);
|
|
239
|
-
return row?.name ?? null;
|
|
240
|
-
}
|
|
241
224
|
/**
|
|
242
225
|
* A usage rate as money. A sub-dollar rate needs at least two decimals to read as
|
|
243
226
|
* a price at all — 0.1 is $0.10, not $0.1 — while keeping the precision the
|
package/dist/lib/session.d.ts
CHANGED
|
@@ -31,18 +31,15 @@ export declare function bearer(): string | null;
|
|
|
31
31
|
export declare function live(): boolean;
|
|
32
32
|
/** The attribute on `<html>` that says `/` is showing the app, not the landing. */
|
|
33
33
|
export declare const APP = "data-app";
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
* this is decided before any stylesheet or component has run.
|
|
44
|
-
*/
|
|
45
|
-
export declare const BOOT: string;
|
|
34
|
+
/**
|
|
35
|
+
* `live()`, as the script `/` runs as the first child of its landing
|
|
36
|
+
* (app/_apex.tsx `[data-landing]`), before the rest of the landing is parsed
|
|
37
|
+
* (app/page.tsx). A live token marks the document with `APP` and takes the
|
|
38
|
+
* landing off the page at once, so a signed-in reader is never shown the pitch
|
|
39
|
+
* on the way to the app. Same keys, same test. An inline style, because this is
|
|
40
|
+
* decided before any stylesheet or component has run.
|
|
41
|
+
*/
|
|
42
|
+
export declare const BOOT = "try{var t=localStorage.getItem('hanzo_iam_access_token'),e=localStorage.getItem('hanzo_iam_expires_at');if(t&&(!e||Date.now()<Number(e))){document.documentElement.setAttribute('data-app','');var l=document.currentScript&&document.currentScript.parentElement;if(l&&l.hasAttribute('data-landing'))l.style.display='none'}}catch(_){}";
|
|
46
43
|
/**
|
|
47
44
|
* Whether this tab may still ask: a person's browser, and not asked in this tab
|
|
48
45
|
* yet. A browser that refuses storage cannot remember having asked, so it never
|
package/dist/lib/session.js
CHANGED
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
* who was signed in, which reads as a permissions problem rather than a typo.
|
|
15
15
|
* Two derivations of one name never agree; this is the one derivation.
|
|
16
16
|
*/
|
|
17
|
-
import { TALK } from './host.js';
|
|
18
17
|
import { api } from './api.js';
|
|
19
18
|
/** The SDK's own keys, `hanzo_iam_`-prefixed. The far side of a boundary. */
|
|
20
19
|
const PREFIX = 'hanzo_iam_';
|
|
@@ -59,25 +58,14 @@ export function live() {
|
|
|
59
58
|
/** The attribute on `<html>` that says `/` is showing the app, not the landing. */
|
|
60
59
|
export const APP = 'data-app';
|
|
61
60
|
/**
|
|
62
|
-
*
|
|
63
|
-
* (
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
61
|
+
* `live()`, as the script `/` runs as the first child of its landing
|
|
62
|
+
* (app/_apex.tsx `[data-landing]`), before the rest of the landing is parsed
|
|
63
|
+
* (app/page.tsx). A live token marks the document with `APP` and takes the
|
|
64
|
+
* landing off the page at once, so a signed-in reader is never shown the pitch
|
|
65
|
+
* on the way to the app. Same keys, same test. An inline style, because this is
|
|
66
|
+
* decided before any stylesheet or component has run.
|
|
67
67
|
*/
|
|
68
|
-
const
|
|
69
|
-
/** Whether `search` names a place in the app. */
|
|
70
|
-
export const place = (search) => PLACE.test(search);
|
|
71
|
-
/**
|
|
72
|
-
* `live()`, and a place in the app, as the script `/` runs as the first child
|
|
73
|
-
* of its landing (app/_apex.tsx `[data-landing]`), before the rest of the
|
|
74
|
-
* landing is parsed (app/page.tsx). Either marks the document with `APP` and
|
|
75
|
-
* takes the landing off the page at once: a signed-in reader is never shown the
|
|
76
|
-
* pitch while the app loads, and a reader on their way to sign in to a place is
|
|
77
|
-
* not shown it while they leave. Same keys, same test. An inline style, because
|
|
78
|
-
* this is decided before any stylesheet or component has run.
|
|
79
|
-
*/
|
|
80
|
-
export const BOOT = `try{var t=localStorage.getItem('${ACCESS}'),e=localStorage.getItem('${EXPIRES}');if((t&&(!e||Date.now()<Number(e)))||${PLACE}.test(location.search)){document.documentElement.setAttribute('${APP}','');var l=document.currentScript&&document.currentScript.parentElement;if(l&&l.hasAttribute('data-landing'))l.style.display='none'}}catch(_){}`;
|
|
68
|
+
export const BOOT = `try{var t=localStorage.getItem('${ACCESS}'),e=localStorage.getItem('${EXPIRES}');if(t&&(!e||Date.now()<Number(e))){document.documentElement.setAttribute('${APP}','');var l=document.currentScript&&document.currentScript.parentElement;if(l&&l.hasAttribute('data-landing'))l.style.display='none'}}catch(_){}`;
|
|
81
69
|
/**
|
|
82
70
|
* A RETURNING PERSON IS RECOGNISED WITHOUT GOING ANYWHERE.
|
|
83
71
|
*
|
package/dist/lib/web.d.ts
CHANGED
|
@@ -1,48 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* THE LIVE WEB, IN A CHAT TURN.
|
|
3
3
|
*
|
|
4
|
-
* A turn on an Enso or Zen model
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* A turn on an Enso or Zen model carries the two web tools (`WEB`) as its mark
|
|
5
|
+
* that it may use the web. `researched` is the client's fetch that acts on the
|
|
6
|
+
* mark: it looks the turn up BEFORE the model is asked — POST /v1/websearch and
|
|
7
|
+
* POST /v1/crawl, the platform's own operations, run with the reader's own
|
|
8
|
+
* credential so they are admitted, metered and refused exactly as for every
|
|
9
|
+
* other caller — and then asks the model once, WITHOUT tools, with what was
|
|
10
|
+
* found in its system turn.
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* above the fetch changes: `useChat` streams the answer it always streamed.
|
|
12
|
+
* Without tools because the gateway answers a request that offers tools whole,
|
|
13
|
+
* checking its calls against their schemas before the first byte, so its first
|
|
14
|
+
* word waits for its last. Asked without them, every turn streams. The model
|
|
15
|
+
* therefore never asks for a lookup of its own: the client's one lookup is the
|
|
16
|
+
* turn's web.
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Which turns: every question about the world, in any language. The web is
|
|
19
|
+
* skipped only for a turn that plainly needs none (`needs`) — code, arithmetic,
|
|
20
|
+
* a passage supplied to work on, a greeting — and for a turn about the person's
|
|
21
|
+
* own files or picture, whose words never leave for a search engine. The test
|
|
22
|
+
* reads the shape of the text, never a list of topics. A turn that names a page
|
|
23
|
+
* reads it, and searches too when it asks something. The query is the person's
|
|
24
|
+
* own words, each address said as its host and path words, and the language narrows
|
|
25
|
+
* the search (`language`), so a question asked in Russian is searched in Russian.
|
|
21
26
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
27
|
+
* WHERE WHAT WAS FOUND GOES: the end of the leading system turn, between two
|
|
28
|
+
* markers no page can know. Not a system turn of its own, because the gateway's
|
|
29
|
+
* text pipeline keeps only the last system turn it reads, and that would drop
|
|
30
|
+
* the room's own; not the person's turn, because the router chooses the model
|
|
31
|
+
* from the last user turn and would read the web pages as the question.
|
|
26
32
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* once more.
|
|
31
|
-
*
|
|
32
|
-
* A page is read only when the conversation or one of this turn's searches
|
|
33
|
-
* named it. Page text is written by strangers and can tell a model to fetch an
|
|
34
|
-
* address carrying the conversation in its query; an address nobody named is
|
|
35
|
-
* never fetched.
|
|
33
|
+
* A page is read only when the person points at it — never an address that
|
|
34
|
+
* signs in, confirms, unsubscribes or spends a token (`opened`) — or this turn's
|
|
35
|
+
* search found it. A reply of no words is asked for once more.
|
|
36
36
|
*/
|
|
37
37
|
import { type ChatCompletionTool } from '@hanzo/ai';
|
|
38
|
-
/**
|
|
39
|
-
export declare const
|
|
40
|
-
/**
|
|
41
|
-
export declare const CALLS = 3;
|
|
42
|
-
/** The two tools a turn is offered. */
|
|
38
|
+
/** Pages a turn that names them reads. */
|
|
39
|
+
export declare const PAGES = 3;
|
|
40
|
+
/** The two tools that mark a turn as one that may use the web. */
|
|
43
41
|
export declare const WEB: ChatCompletionTool[];
|
|
44
|
-
/**
|
|
45
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Whether a turn's words need the web. Every question about the world does, in
|
|
44
|
+
* any language; the turns that plainly do not are code, arithmetic, a passage
|
|
45
|
+
* supplied to work on, a greeting, and a turn of no words at all.
|
|
46
|
+
*/
|
|
47
|
+
export declare function needs(text: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The language a question is written in, as /v1/websearch reads it ("ru",
|
|
50
|
+
* "en", "ja"), or '' when its words do not say. `spoken` is the reader's own
|
|
51
|
+
* languages, which pick among the languages a script is shared by.
|
|
52
|
+
*/
|
|
53
|
+
export declare function language(text: string, spoken?: readonly string[]): string;
|
|
46
54
|
/**
|
|
47
55
|
* The part of a page that answers, within `max` characters: the lines that
|
|
48
56
|
* carry the question's words or a reading — a figure, a unit — kept in the
|
|
@@ -50,7 +58,7 @@ export declare const current: (text: string) => boolean;
|
|
|
50
58
|
*/
|
|
51
59
|
export declare function excerpt(markdown: string, words: string[], max: number): string;
|
|
52
60
|
/**
|
|
53
|
-
* A fetch that
|
|
54
|
-
* file). Every other request passes through untouched.
|
|
61
|
+
* A fetch that looks up the turns a completion marks with the web tools (see
|
|
62
|
+
* the head of this file). Every other request passes through untouched.
|
|
55
63
|
*/
|
|
56
|
-
export declare function researched(base: typeof fetch, clock?: () => Date): typeof fetch;
|
|
64
|
+
export declare function researched(base: typeof fetch, clock?: () => Date, spoken?: () => readonly string[]): typeof fetch;
|