@llui/agent 0.0.32 → 0.0.35
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 +82 -1
- package/dist/client/agentConfirm.d.ts +48 -18
- package/dist/client/agentConfirm.d.ts.map +1 -1
- package/dist/client/agentConfirm.js +28 -25
- package/dist/client/agentConfirm.js.map +1 -1
- package/dist/client/agentConnect.d.ts +95 -34
- package/dist/client/agentConnect.d.ts.map +1 -1
- package/dist/client/agentConnect.js +85 -47
- package/dist/client/agentConnect.js.map +1 -1
- package/dist/client/agentLog.d.ts +31 -14
- package/dist/client/agentLog.d.ts.map +1 -1
- package/dist/client/agentLog.js +39 -20
- package/dist/client/agentLog.js.map +1 -1
- package/dist/client/effect-handler.d.ts +23 -0
- package/dist/client/effect-handler.d.ts.map +1 -1
- package/dist/client/effect-handler.js +185 -126
- package/dist/client/effect-handler.js.map +1 -1
- package/dist/client/effects.d.ts +13 -2
- package/dist/client/effects.d.ts.map +1 -1
- package/dist/client/effects.js.map +1 -1
- package/dist/client/factory.d.ts +55 -3
- package/dist/client/factory.d.ts.map +1 -1
- package/dist/client/factory.js +30 -5
- package/dist/client/factory.js.map +1 -1
- package/dist/client/rpc/describe-visible-content.d.ts +18 -5
- package/dist/client/rpc/describe-visible-content.d.ts.map +1 -1
- package/dist/client/rpc/describe-visible-content.js +112 -7
- package/dist/client/rpc/describe-visible-content.js.map +1 -1
- package/dist/client/rpc/list-actions.d.ts +52 -2
- package/dist/client/rpc/list-actions.d.ts.map +1 -1
- package/dist/client/rpc/list-actions.js +187 -5
- package/dist/client/rpc/list-actions.js.map +1 -1
- package/dist/client/rpc/query-state.d.ts +32 -0
- package/dist/client/rpc/query-state.d.ts.map +1 -0
- package/dist/client/rpc/query-state.js +82 -0
- package/dist/client/rpc/query-state.js.map +1 -0
- package/dist/client/rpc/send-message.d.ts +2 -0
- package/dist/client/rpc/send-message.d.ts.map +1 -1
- package/dist/client/rpc/send-message.js +119 -9
- package/dist/client/rpc/send-message.js.map +1 -1
- package/dist/client/rpc/would-dispatch.d.ts +66 -0
- package/dist/client/rpc/would-dispatch.d.ts.map +1 -0
- package/dist/client/rpc/would-dispatch.js +21 -0
- package/dist/client/rpc/would-dispatch.js.map +1 -0
- package/dist/client/ws-client.d.ts +3 -1
- package/dist/client/ws-client.d.ts.map +1 -1
- package/dist/client/ws-client.js +29 -0
- package/dist/client/ws-client.js.map +1 -1
- package/dist/codecs.d.ts +107 -0
- package/dist/codecs.d.ts.map +1 -0
- package/dist/codecs.js +166 -0
- package/dist/codecs.js.map +1 -0
- package/dist/protocol.d.ts +172 -12
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +7 -1
- package/dist/protocol.js.map +1 -1
- package/dist/server/cloudflare/durable-object.d.ts +11 -4
- package/dist/server/cloudflare/durable-object.d.ts.map +1 -1
- package/dist/server/cloudflare/durable-object.js.map +1 -1
- package/dist/server/cloudflare/index.d.ts +8 -4
- package/dist/server/cloudflare/index.d.ts.map +1 -1
- package/dist/server/cloudflare/index.js +8 -4
- package/dist/server/cloudflare/index.js.map +1 -1
- package/dist/server/cloudflare/worker.d.ts +10 -2
- package/dist/server/cloudflare/worker.d.ts.map +1 -1
- package/dist/server/cloudflare/worker.js +13 -6
- package/dist/server/cloudflare/worker.js.map +1 -1
- package/dist/server/core-entry.d.ts +2 -2
- package/dist/server/core-entry.d.ts.map +1 -1
- package/dist/server/core-entry.js +1 -1
- package/dist/server/core-entry.js.map +1 -1
- package/dist/server/core.d.ts +1 -3
- package/dist/server/core.d.ts.map +1 -1
- package/dist/server/core.js +13 -12
- package/dist/server/core.js.map +1 -1
- package/dist/server/factory.d.ts +1 -1
- package/dist/server/factory.d.ts.map +1 -1
- package/dist/server/factory.js +1 -2
- package/dist/server/factory.js.map +1 -1
- package/dist/server/http/mint.d.ts +6 -1
- package/dist/server/http/mint.d.ts.map +1 -1
- package/dist/server/http/mint.js +14 -6
- package/dist/server/http/mint.js.map +1 -1
- package/dist/server/http/resume.d.ts +3 -1
- package/dist/server/http/resume.d.ts.map +1 -1
- package/dist/server/http/resume.js +9 -7
- package/dist/server/http/resume.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/lap/confirm-result.d.ts +0 -1
- package/dist/server/lap/confirm-result.d.ts.map +1 -1
- package/dist/server/lap/confirm-result.js +1 -1
- package/dist/server/lap/confirm-result.js.map +1 -1
- package/dist/server/lap/describe.d.ts +13 -2
- package/dist/server/lap/describe.d.ts.map +1 -1
- package/dist/server/lap/describe.js +23 -6
- package/dist/server/lap/describe.js.map +1 -1
- package/dist/server/lap/forward.d.ts +13 -1
- package/dist/server/lap/forward.d.ts.map +1 -1
- package/dist/server/lap/forward.js +75 -1
- package/dist/server/lap/forward.js.map +1 -1
- package/dist/server/lap/message.d.ts +0 -1
- package/dist/server/lap/message.d.ts.map +1 -1
- package/dist/server/lap/message.js +1 -1
- package/dist/server/lap/message.js.map +1 -1
- package/dist/server/lap/observe.d.ts +0 -1
- package/dist/server/lap/observe.d.ts.map +1 -1
- package/dist/server/lap/observe.js +1 -1
- package/dist/server/lap/observe.js.map +1 -1
- package/dist/server/lap/router.d.ts.map +1 -1
- package/dist/server/lap/router.js +7 -1
- package/dist/server/lap/router.js.map +1 -1
- package/dist/server/lap/wait.d.ts +0 -1
- package/dist/server/lap/wait.d.ts.map +1 -1
- package/dist/server/lap/wait.js +1 -1
- package/dist/server/lap/wait.js.map +1 -1
- package/dist/server/options.d.ts +7 -5
- package/dist/server/options.d.ts.map +1 -1
- package/dist/server/options.js.map +1 -1
- package/dist/server/token-store.d.ts +22 -0
- package/dist/server/token-store.d.ts.map +1 -1
- package/dist/server/token-store.js +24 -0
- package/dist/server/token-store.js.map +1 -1
- package/dist/server/token.d.ts +32 -17
- package/dist/server/token.d.ts.map +1 -1
- package/dist/server/token.js +40 -103
- package/dist/server/token.js.map +1 -1
- package/dist/server/web/upgrade.d.ts +1 -1
- package/dist/server/web/upgrade.js +1 -1
- package/dist/server/web/upgrade.js.map +1 -1
- package/dist/server/ws/pairing-registry.d.ts +22 -6
- package/dist/server/ws/pairing-registry.d.ts.map +1 -1
- package/dist/server/ws/pairing-registry.js +49 -0
- package/dist/server/ws/pairing-registry.js.map +1 -1
- package/dist/server/ws/upgrade.d.ts +0 -1
- package/dist/server/ws/upgrade.d.ts.map +1 -1
- package/dist/server/ws/upgrade.js +12 -4
- package/dist/server/ws/upgrade.js.map +1 -1
- package/dist/state-diff.d.ts +52 -0
- package/dist/state-diff.d.ts.map +1 -0
- package/dist/state-diff.js +119 -0
- package/dist/state-diff.js.map +1 -0
- package/package.json +7 -3
|
@@ -1,132 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level dispatcher. The switch is intentionally thin — each
|
|
3
|
+
* `case` delegates to a per-effect function below. Splitting was
|
|
4
|
+
* motivated by the previous 150-line monolith mixing HTTP, WS, and
|
|
5
|
+
* browser-only side effects in one switch; per-effect handlers are
|
|
6
|
+
* directly unit-testable and the dispatcher reads as a flat catalogue
|
|
7
|
+
* of supported effect types.
|
|
8
|
+
*/
|
|
1
9
|
export function createEffectHandler(host) {
|
|
2
10
|
const doFetch = host.fetch ?? fetch.bind(globalThis);
|
|
3
11
|
return async function handle(effect) {
|
|
4
12
|
switch (effect.type) {
|
|
5
|
-
case 'AgentMintRequest':
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
expiresAt: body.expiresAt,
|
|
24
|
-
}));
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
host.send(host.wrapAgentConnect({
|
|
28
|
-
type: 'MintFailed',
|
|
29
|
-
error: { code: 'network', detail: String(e) },
|
|
30
|
-
}));
|
|
31
|
-
}
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
case 'AgentOpenWS': {
|
|
35
|
-
host.openWs(effect.token, effect.wsUrl);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
case 'AgentCloseWS': {
|
|
39
|
-
host.closeWs();
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
case 'AgentResumeCheck': {
|
|
43
|
-
// For v1 we call /agent/resume/list via the mint URL's origin; the mintUrl is a POST
|
|
44
|
-
// endpoint at `/agent/mint`, so we derive the origin and hit `/agent/resume/list`.
|
|
45
|
-
const origin = deriveOrigin(host);
|
|
46
|
-
if (!origin)
|
|
47
|
-
return;
|
|
48
|
-
try {
|
|
49
|
-
const res = await doFetch(`${origin}/agent/resume/list`, {
|
|
50
|
-
method: 'POST',
|
|
51
|
-
credentials: 'include',
|
|
52
|
-
headers: { 'content-type': 'application/json' },
|
|
53
|
-
body: JSON.stringify({ tids: effect.tids }),
|
|
54
|
-
});
|
|
55
|
-
if (!res.ok)
|
|
56
|
-
return;
|
|
57
|
-
const body = (await res.json());
|
|
58
|
-
host.send(host.wrapAgentConnect({ type: 'ResumeListLoaded', sessions: body.sessions }));
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
/* quiet failure; user can retry */
|
|
62
|
-
}
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
case 'AgentResumeClaim': {
|
|
66
|
-
const origin = deriveOrigin(host);
|
|
67
|
-
if (!origin)
|
|
68
|
-
return;
|
|
69
|
-
try {
|
|
70
|
-
const res = await doFetch(`${origin}/agent/resume/claim`, {
|
|
71
|
-
method: 'POST',
|
|
72
|
-
credentials: 'include',
|
|
73
|
-
headers: { 'content-type': 'application/json' },
|
|
74
|
-
body: JSON.stringify({ tid: effect.tid }),
|
|
75
|
-
});
|
|
76
|
-
if (!res.ok)
|
|
77
|
-
return;
|
|
78
|
-
const body = (await res.json());
|
|
79
|
-
host.openWs(body.token, body.wsUrl);
|
|
80
|
-
host.send(host.wrapAgentConnect({ type: 'WsOpened' }));
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
/* quiet */
|
|
84
|
-
}
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
case 'AgentRevoke': {
|
|
88
|
-
const origin = deriveOrigin(host);
|
|
89
|
-
if (!origin)
|
|
90
|
-
return;
|
|
91
|
-
try {
|
|
92
|
-
await doFetch(`${origin}/agent/revoke`, {
|
|
93
|
-
method: 'POST',
|
|
94
|
-
credentials: 'include',
|
|
95
|
-
headers: { 'content-type': 'application/json' },
|
|
96
|
-
body: JSON.stringify({ tid: effect.tid }),
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
/* quiet */
|
|
101
|
-
}
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
case 'AgentSessionsList': {
|
|
105
|
-
const origin = deriveOrigin(host);
|
|
106
|
-
if (!origin)
|
|
107
|
-
return;
|
|
108
|
-
try {
|
|
109
|
-
const res = await doFetch(`${origin}/agent/sessions`, {
|
|
110
|
-
method: 'GET',
|
|
111
|
-
credentials: 'include',
|
|
112
|
-
});
|
|
113
|
-
if (!res.ok)
|
|
114
|
-
return;
|
|
115
|
-
const body = (await res.json());
|
|
116
|
-
host.send(host.wrapAgentConnect({ type: 'SessionsLoaded', sessions: body.sessions }));
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
/* quiet */
|
|
120
|
-
}
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
case 'AgentForwardMsg': {
|
|
124
|
-
host.forward(effect.payload);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
13
|
+
case 'AgentMintRequest':
|
|
14
|
+
return handleMintRequest(host, effect, doFetch);
|
|
15
|
+
case 'AgentOpenWS':
|
|
16
|
+
return handleOpenWs(host, effect);
|
|
17
|
+
case 'AgentCloseWS':
|
|
18
|
+
return handleCloseWs(host);
|
|
19
|
+
case 'AgentResumeCheck':
|
|
20
|
+
return handleResumeCheck(host, effect, doFetch);
|
|
21
|
+
case 'AgentResumeClaim':
|
|
22
|
+
return handleResumeClaim(host, effect, doFetch);
|
|
23
|
+
case 'AgentRevoke':
|
|
24
|
+
return handleRevoke(host, effect, doFetch);
|
|
25
|
+
case 'AgentSessionsList':
|
|
26
|
+
return handleSessionsList(host, doFetch);
|
|
27
|
+
case 'AgentForwardMsg':
|
|
28
|
+
return handleForwardMsg(host, effect);
|
|
29
|
+
case 'AgentClipboardWrite':
|
|
30
|
+
return handleClipboardWrite(effect);
|
|
127
31
|
}
|
|
128
32
|
};
|
|
129
33
|
}
|
|
34
|
+
// ── HTTP-bound handlers ─────────────────────────────────────────────
|
|
35
|
+
async function handleMintRequest(host, effect, doFetch) {
|
|
36
|
+
// Derive a default `mintUrl` from `agentBasePath` so consumers can
|
|
37
|
+
// change the base path in one place (the effect handler) without
|
|
38
|
+
// also having to keep the `agentConnect` opts in sync. `agentBase`
|
|
39
|
+
// accepts both absolute paths and full URLs.
|
|
40
|
+
const base = agentBase(host);
|
|
41
|
+
if (!base)
|
|
42
|
+
return;
|
|
43
|
+
const mintUrl = effect.mintUrl ?? `${base}/mint`;
|
|
44
|
+
try {
|
|
45
|
+
const res = await doFetch(mintUrl, { method: 'POST', credentials: 'include' });
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const detail = await safeText(res);
|
|
48
|
+
host.send(host.wrapAgentConnect({
|
|
49
|
+
type: 'MintFailed',
|
|
50
|
+
error: { code: `http-${res.status}`, detail },
|
|
51
|
+
}));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const body = (await res.json());
|
|
55
|
+
host.send(host.wrapAgentConnect({
|
|
56
|
+
type: 'MintSucceeded',
|
|
57
|
+
token: body.token,
|
|
58
|
+
tid: body.tid,
|
|
59
|
+
lapUrl: body.lapUrl,
|
|
60
|
+
wsUrl: body.wsUrl,
|
|
61
|
+
expiresAt: body.expiresAt,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
host.send(host.wrapAgentConnect({
|
|
66
|
+
type: 'MintFailed',
|
|
67
|
+
error: { code: 'network', detail: String(e) },
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function handleResumeCheck(host, effect, doFetch) {
|
|
72
|
+
const base = agentBase(host);
|
|
73
|
+
if (!base)
|
|
74
|
+
return;
|
|
75
|
+
try {
|
|
76
|
+
const res = await doFetch(`${base}/resume/list`, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
credentials: 'include',
|
|
79
|
+
headers: { 'content-type': 'application/json' },
|
|
80
|
+
body: JSON.stringify({ tids: effect.tids }),
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok)
|
|
83
|
+
return;
|
|
84
|
+
const body = (await res.json());
|
|
85
|
+
host.send(host.wrapAgentConnect({ type: 'ResumeListLoaded', sessions: body.sessions }));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
/* quiet failure; user can retry */
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function handleResumeClaim(host, effect, doFetch) {
|
|
92
|
+
const base = agentBase(host);
|
|
93
|
+
if (!base)
|
|
94
|
+
return;
|
|
95
|
+
try {
|
|
96
|
+
const res = await doFetch(`${base}/resume/claim`, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
credentials: 'include',
|
|
99
|
+
headers: { 'content-type': 'application/json' },
|
|
100
|
+
body: JSON.stringify({ tid: effect.tid }),
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok)
|
|
103
|
+
return;
|
|
104
|
+
const body = (await res.json());
|
|
105
|
+
host.openWs(body.token, body.wsUrl);
|
|
106
|
+
host.send(host.wrapAgentConnect({ type: 'WsOpened' }));
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
/* quiet */
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function handleRevoke(host, effect, doFetch) {
|
|
113
|
+
const base = agentBase(host);
|
|
114
|
+
if (!base)
|
|
115
|
+
return;
|
|
116
|
+
try {
|
|
117
|
+
await doFetch(`${base}/revoke`, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
credentials: 'include',
|
|
120
|
+
headers: { 'content-type': 'application/json' },
|
|
121
|
+
body: JSON.stringify({ tid: effect.tid }),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
/* quiet */
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function handleSessionsList(host, doFetch) {
|
|
129
|
+
const base = agentBase(host);
|
|
130
|
+
if (!base)
|
|
131
|
+
return;
|
|
132
|
+
try {
|
|
133
|
+
const res = await doFetch(`${base}/sessions`, {
|
|
134
|
+
method: 'GET',
|
|
135
|
+
credentials: 'include',
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok)
|
|
138
|
+
return;
|
|
139
|
+
const body = (await res.json());
|
|
140
|
+
host.send(host.wrapAgentConnect({ type: 'SessionsLoaded', sessions: body.sessions }));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
/* quiet */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// ── WS-bound handlers ───────────────────────────────────────────────
|
|
147
|
+
function handleOpenWs(host, effect) {
|
|
148
|
+
host.openWs(effect.token, effect.wsUrl);
|
|
149
|
+
}
|
|
150
|
+
function handleCloseWs(host) {
|
|
151
|
+
host.closeWs();
|
|
152
|
+
}
|
|
153
|
+
// ── Local handlers (no network) ─────────────────────────────────────
|
|
154
|
+
function handleForwardMsg(host, effect) {
|
|
155
|
+
host.forward(effect.payload);
|
|
156
|
+
}
|
|
157
|
+
async function handleClipboardWrite(effect) {
|
|
158
|
+
// Browser-only — `navigator.clipboard` is undefined in Node/jsdom
|
|
159
|
+
// test environments. Silently no-op rather than throw, matching the
|
|
160
|
+
// rest of the agent effect handlers' failure-quiet pattern.
|
|
161
|
+
if (typeof navigator === 'undefined' || !('clipboard' in navigator))
|
|
162
|
+
return;
|
|
163
|
+
try {
|
|
164
|
+
await navigator.clipboard.writeText(effect.text);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* quiet — clipboard permission denied or document not focused */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
130
171
|
async function safeText(res) {
|
|
131
172
|
try {
|
|
132
173
|
return await res.text();
|
|
@@ -135,12 +176,30 @@ async function safeText(res) {
|
|
|
135
176
|
return '';
|
|
136
177
|
}
|
|
137
178
|
}
|
|
138
|
-
function deriveOrigin(
|
|
139
|
-
// When running in the browser, `location.origin` is correct
|
|
140
|
-
//
|
|
141
|
-
//
|
|
179
|
+
function deriveOrigin() {
|
|
180
|
+
// When running in the browser, `location.origin` is correct for
|
|
181
|
+
// same-origin agent endpoints. Tests override `host.fetch` and
|
|
182
|
+
// short-circuit before this is reached.
|
|
142
183
|
if (typeof location !== 'undefined')
|
|
143
184
|
return location.origin;
|
|
144
185
|
return null;
|
|
145
186
|
}
|
|
187
|
+
const ABSOLUTE_URL_RE = /^https?:\/\//i;
|
|
188
|
+
/**
|
|
189
|
+
* Resolve the absolute base URL for agent HTTP endpoints. Accepts both
|
|
190
|
+
* absolute paths (`/agent`) and full URLs (`https://api.example/agent`)
|
|
191
|
+
* — the absolute URL form lets consumers point at a cross-origin agent
|
|
192
|
+
* server without pre-composing every endpoint URL. Trailing slashes
|
|
193
|
+
* are normalized so callers can always concatenate `${base}/mint`.
|
|
194
|
+
*/
|
|
195
|
+
function agentBase(host) {
|
|
196
|
+
const raw = host.agentBasePath ?? '/agent';
|
|
197
|
+
const trimmed = raw.endsWith('/') ? raw.slice(0, -1) : raw;
|
|
198
|
+
if (ABSOLUTE_URL_RE.test(trimmed))
|
|
199
|
+
return trimmed;
|
|
200
|
+
const origin = deriveOrigin();
|
|
201
|
+
if (!origin)
|
|
202
|
+
return null;
|
|
203
|
+
return `${origin}${trimmed}`;
|
|
204
|
+
}
|
|
146
205
|
//# sourceMappingURL=effect-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect-handler.js","sourceRoot":"","sources":["../../src/client/effect-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentEffect } from './effects.js'\nimport type {\n MintResponse,\n ResumeListResponse,\n ResumeClaimResponse,\n SessionsResponse,\n} from '../protocol.js'\n\nexport type EffectHandlerHost = {\n send(msg: unknown): void // root app send; wraps agent sub-msgs into the app Msg envelope\n /** Wraps an agentConnect msg into an app-Msg. */\n wrapAgentConnect(m: unknown): unknown\n /** Called for AgentForwardMsg — the payload is re-dispatched via send. */\n forward(payload: unknown): void\n /** fetch for HTTP effects; override in tests. */\n fetch?: typeof fetch\n /** Called before opening WS / on WS lifecycle events. */\n openWs(token: string, wsUrl: string): void\n closeWs(): void\n}\n\nexport function createEffectHandler(host: EffectHandlerHost) {\n const doFetch = host.fetch ?? fetch.bind(globalThis)\n\n return async function handle(effect: AgentEffect): Promise<void> {\n switch (effect.type) {\n case 'AgentMintRequest': {\n try {\n const res = await doFetch(effect.mintUrl, { method: 'POST', credentials: 'include' })\n if (!res.ok) {\n const detail = await safeText(res)\n host.send(\n host.wrapAgentConnect({\n type: 'MintFailed',\n error: { code: `http-${res.status}`, detail },\n }),\n )\n return\n }\n const body = (await res.json()) as MintResponse\n host.send(\n host.wrapAgentConnect({\n type: 'MintSucceeded',\n token: body.token,\n tid: body.tid,\n lapUrl: body.lapUrl,\n wsUrl: body.wsUrl,\n expiresAt: body.expiresAt,\n }),\n )\n } catch (e) {\n host.send(\n host.wrapAgentConnect({\n type: 'MintFailed',\n error: { code: 'network', detail: String(e) },\n }),\n )\n }\n return\n }\n case 'AgentOpenWS': {\n host.openWs(effect.token, effect.wsUrl)\n return\n }\n case 'AgentCloseWS': {\n host.closeWs()\n return\n }\n case 'AgentResumeCheck': {\n // For v1 we call /agent/resume/list via the mint URL's origin; the mintUrl is a POST\n // endpoint at `/agent/mint`, so we derive the origin and hit `/agent/resume/list`.\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n const res = await doFetch(`${origin}/agent/resume/list`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tids: effect.tids }),\n })\n if (!res.ok) return\n const body = (await res.json()) as ResumeListResponse\n host.send(host.wrapAgentConnect({ type: 'ResumeListLoaded', sessions: body.sessions }))\n } catch {\n /* quiet failure; user can retry */\n }\n return\n }\n case 'AgentResumeClaim': {\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n const res = await doFetch(`${origin}/agent/resume/claim`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tid: effect.tid }),\n })\n if (!res.ok) return\n const body = (await res.json()) as ResumeClaimResponse\n host.openWs(body.token, body.wsUrl)\n host.send(host.wrapAgentConnect({ type: 'WsOpened' }))\n } catch {\n /* quiet */\n }\n return\n }\n case 'AgentRevoke': {\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n await doFetch(`${origin}/agent/revoke`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tid: effect.tid }),\n })\n } catch {\n /* quiet */\n }\n return\n }\n case 'AgentSessionsList': {\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n const res = await doFetch(`${origin}/agent/sessions`, {\n method: 'GET',\n credentials: 'include',\n })\n if (!res.ok) return\n const body = (await res.json()) as SessionsResponse\n host.send(host.wrapAgentConnect({ type: 'SessionsLoaded', sessions: body.sessions }))\n } catch {\n /* quiet */\n }\n return\n }\n case 'AgentForwardMsg': {\n host.forward(effect.payload)\n return\n }\n }\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return ''\n }\n}\n\nfunction deriveOrigin(_host: EffectHandlerHost): string | null {\n // When running in the browser, `location.origin` is correct (the agent endpoints\n // are same-origin with the app per spec §6.2). When not in a browser (tests),\n // the test-side host can override by monkeypatching in its own effect handler.\n if (typeof location !== 'undefined') return location.origin\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"file":"effect-handler.js","sourceRoot":"","sources":["../../src/client/effect-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentEffect } from './effects.js'\nimport type {\n MintResponse,\n ResumeListResponse,\n ResumeClaimResponse,\n SessionsResponse,\n} from '../protocol.js'\n\nexport type EffectHandlerHost = {\n send(msg: unknown): void // root app send; wraps agent sub-msgs into the app Msg envelope\n /** Wraps an agentConnect msg into an app-Msg. */\n wrapAgentConnect(m: unknown): unknown\n /** Called for AgentForwardMsg — the payload is re-dispatched via send. */\n forward(payload: unknown): void\n /** fetch for HTTP effects; override in tests. */\n fetch?: typeof fetch\n /** Called before opening WS / on WS lifecycle events. */\n openWs(token: string, wsUrl: string): void\n closeWs(): void\n /**\n * Base path for agent HTTP endpoints. Default: `'/agent'` (matches\n * the canonical paths in `@llui/vite-plugin`'s dev middleware and\n * `@llui/agent/server/http/router.ts`).\n *\n * Override when the consumer ships `@cloudflare/vite-plugin` in\n * dev — that plugin routes every non-`/cdn-cgi/*` path to the\n * worker, shadowing canonical `/agent/*` URLs. The vite-plugin\n * registers a parallel handler at `/cdn-cgi/agent/*`; pass\n * `agentBasePath: '/cdn-cgi/agent'` here so the client hits that.\n *\n * Production deployments without cloudflare-vite leave this\n * unset; the agent server's router serves the canonical paths.\n */\n agentBasePath?: string\n}\n\ntype Fetch = typeof fetch\n\n/**\n * Top-level dispatcher. The switch is intentionally thin — each\n * `case` delegates to a per-effect function below. Splitting was\n * motivated by the previous 150-line monolith mixing HTTP, WS, and\n * browser-only side effects in one switch; per-effect handlers are\n * directly unit-testable and the dispatcher reads as a flat catalogue\n * of supported effect types.\n */\nexport function createEffectHandler(host: EffectHandlerHost) {\n const doFetch = host.fetch ?? fetch.bind(globalThis)\n\n return async function handle(effect: AgentEffect): Promise<void> {\n switch (effect.type) {\n case 'AgentMintRequest':\n return handleMintRequest(host, effect, doFetch)\n case 'AgentOpenWS':\n return handleOpenWs(host, effect)\n case 'AgentCloseWS':\n return handleCloseWs(host)\n case 'AgentResumeCheck':\n return handleResumeCheck(host, effect, doFetch)\n case 'AgentResumeClaim':\n return handleResumeClaim(host, effect, doFetch)\n case 'AgentRevoke':\n return handleRevoke(host, effect, doFetch)\n case 'AgentSessionsList':\n return handleSessionsList(host, doFetch)\n case 'AgentForwardMsg':\n return handleForwardMsg(host, effect)\n case 'AgentClipboardWrite':\n return handleClipboardWrite(effect)\n }\n }\n}\n\n// ── HTTP-bound handlers ─────────────────────────────────────────────\n\nasync function handleMintRequest(\n host: EffectHandlerHost,\n effect: Extract<AgentEffect, { type: 'AgentMintRequest' }>,\n doFetch: Fetch,\n): Promise<void> {\n // Derive a default `mintUrl` from `agentBasePath` so consumers can\n // change the base path in one place (the effect handler) without\n // also having to keep the `agentConnect` opts in sync. `agentBase`\n // accepts both absolute paths and full URLs.\n const base = agentBase(host)\n if (!base) return\n const mintUrl = effect.mintUrl ?? `${base}/mint`\n try {\n const res = await doFetch(mintUrl, { method: 'POST', credentials: 'include' })\n if (!res.ok) {\n const detail = await safeText(res)\n host.send(\n host.wrapAgentConnect({\n type: 'MintFailed',\n error: { code: `http-${res.status}`, detail },\n }),\n )\n return\n }\n const body = (await res.json()) as MintResponse\n host.send(\n host.wrapAgentConnect({\n type: 'MintSucceeded',\n token: body.token,\n tid: body.tid,\n lapUrl: body.lapUrl,\n wsUrl: body.wsUrl,\n expiresAt: body.expiresAt,\n }),\n )\n } catch (e) {\n host.send(\n host.wrapAgentConnect({\n type: 'MintFailed',\n error: { code: 'network', detail: String(e) },\n }),\n )\n }\n}\n\nasync function handleResumeCheck(\n host: EffectHandlerHost,\n effect: Extract<AgentEffect, { type: 'AgentResumeCheck' }>,\n doFetch: Fetch,\n): Promise<void> {\n const base = agentBase(host)\n if (!base) return\n try {\n const res = await doFetch(`${base}/resume/list`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tids: effect.tids }),\n })\n if (!res.ok) return\n const body = (await res.json()) as ResumeListResponse\n host.send(host.wrapAgentConnect({ type: 'ResumeListLoaded', sessions: body.sessions }))\n } catch {\n /* quiet failure; user can retry */\n }\n}\n\nasync function handleResumeClaim(\n host: EffectHandlerHost,\n effect: Extract<AgentEffect, { type: 'AgentResumeClaim' }>,\n doFetch: Fetch,\n): Promise<void> {\n const base = agentBase(host)\n if (!base) return\n try {\n const res = await doFetch(`${base}/resume/claim`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tid: effect.tid }),\n })\n if (!res.ok) return\n const body = (await res.json()) as ResumeClaimResponse\n host.openWs(body.token, body.wsUrl)\n host.send(host.wrapAgentConnect({ type: 'WsOpened' }))\n } catch {\n /* quiet */\n }\n}\n\nasync function handleRevoke(\n host: EffectHandlerHost,\n effect: Extract<AgentEffect, { type: 'AgentRevoke' }>,\n doFetch: Fetch,\n): Promise<void> {\n const base = agentBase(host)\n if (!base) return\n try {\n await doFetch(`${base}/revoke`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tid: effect.tid }),\n })\n } catch {\n /* quiet */\n }\n}\n\nasync function handleSessionsList(host: EffectHandlerHost, doFetch: Fetch): Promise<void> {\n const base = agentBase(host)\n if (!base) return\n try {\n const res = await doFetch(`${base}/sessions`, {\n method: 'GET',\n credentials: 'include',\n })\n if (!res.ok) return\n const body = (await res.json()) as SessionsResponse\n host.send(host.wrapAgentConnect({ type: 'SessionsLoaded', sessions: body.sessions }))\n } catch {\n /* quiet */\n }\n}\n\n// ── WS-bound handlers ───────────────────────────────────────────────\n\nfunction handleOpenWs(\n host: EffectHandlerHost,\n effect: Extract<AgentEffect, { type: 'AgentOpenWS' }>,\n): void {\n host.openWs(effect.token, effect.wsUrl)\n}\n\nfunction handleCloseWs(host: EffectHandlerHost): void {\n host.closeWs()\n}\n\n// ── Local handlers (no network) ─────────────────────────────────────\n\nfunction handleForwardMsg(\n host: EffectHandlerHost,\n effect: Extract<AgentEffect, { type: 'AgentForwardMsg' }>,\n): void {\n host.forward(effect.payload)\n}\n\nasync function handleClipboardWrite(\n effect: Extract<AgentEffect, { type: 'AgentClipboardWrite' }>,\n): Promise<void> {\n // Browser-only — `navigator.clipboard` is undefined in Node/jsdom\n // test environments. Silently no-op rather than throw, matching the\n // rest of the agent effect handlers' failure-quiet pattern.\n if (typeof navigator === 'undefined' || !('clipboard' in navigator)) return\n try {\n await navigator.clipboard.writeText(effect.text)\n } catch {\n /* quiet — clipboard permission denied or document not focused */\n }\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return ''\n }\n}\n\nfunction deriveOrigin(): string | null {\n // When running in the browser, `location.origin` is correct for\n // same-origin agent endpoints. Tests override `host.fetch` and\n // short-circuit before this is reached.\n if (typeof location !== 'undefined') return location.origin\n return null\n}\n\nconst ABSOLUTE_URL_RE = /^https?:\\/\\//i\n\n/**\n * Resolve the absolute base URL for agent HTTP endpoints. Accepts both\n * absolute paths (`/agent`) and full URLs (`https://api.example/agent`)\n * — the absolute URL form lets consumers point at a cross-origin agent\n * server without pre-composing every endpoint URL. Trailing slashes\n * are normalized so callers can always concatenate `${base}/mint`.\n */\nfunction agentBase(host: EffectHandlerHost): string | null {\n const raw = host.agentBasePath ?? '/agent'\n const trimmed = raw.endsWith('/') ? raw.slice(0, -1) : raw\n if (ABSOLUTE_URL_RE.test(trimmed)) return trimmed\n const origin = deriveOrigin()\n if (!origin) return null\n return `${origin}${trimmed}`\n}\n"]}
|
package/dist/client/effects.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { AgentToken } from '../protocol.js';
|
|
2
|
-
export type AgentEffect =
|
|
2
|
+
export type AgentEffect =
|
|
3
|
+
/**
|
|
4
|
+
* Mint a fresh agent token. `mintUrl` is optional — when omitted the
|
|
5
|
+
* effect handler derives it from `EffectHandlerHost.agentBasePath`
|
|
6
|
+
* (default `/agent`), producing `<agentBasePath>/mint`. Pass an
|
|
7
|
+
* explicit value when the mint endpoint lives outside the configured
|
|
8
|
+
* base path.
|
|
9
|
+
*/
|
|
10
|
+
{
|
|
3
11
|
type: 'AgentMintRequest';
|
|
4
|
-
mintUrl
|
|
12
|
+
mintUrl?: string;
|
|
5
13
|
} | {
|
|
6
14
|
type: 'AgentOpenWS';
|
|
7
15
|
token: AgentToken;
|
|
@@ -22,6 +30,9 @@ export type AgentEffect = {
|
|
|
22
30
|
} | {
|
|
23
31
|
type: 'AgentForwardMsg';
|
|
24
32
|
payload: unknown;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'AgentClipboardWrite';
|
|
35
|
+
text: string;
|
|
25
36
|
};
|
|
26
37
|
export type AgentEffectHandler = (effect: AgentEffect) => Promise<void>;
|
|
27
38
|
//# sourceMappingURL=effects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../../src/client/effects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEhD,MAAM,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../../src/client/effects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEhD,MAAM,MAAM,WAAW;AACrB;;;;;;GAMG;AACD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAK7C;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAGjD,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../../src/client/effects.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentToken } from '../protocol.js'\n\nexport type AgentEffect =\n | { type: 'AgentMintRequest'; mintUrl
|
|
1
|
+
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../../src/client/effects.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentToken } from '../protocol.js'\n\nexport type AgentEffect =\n /**\n * Mint a fresh agent token. `mintUrl` is optional — when omitted the\n * effect handler derives it from `EffectHandlerHost.agentBasePath`\n * (default `/agent`), producing `<agentBasePath>/mint`. Pass an\n * explicit value when the mint endpoint lives outside the configured\n * base path.\n */\n | { type: 'AgentMintRequest'; mintUrl?: string }\n | { type: 'AgentOpenWS'; token: AgentToken; wsUrl: string }\n | { type: 'AgentCloseWS' }\n | { type: 'AgentResumeCheck'; tids: string[] }\n | { type: 'AgentResumeClaim'; tid: string }\n | { type: 'AgentRevoke'; tid: string }\n | { type: 'AgentSessionsList' }\n | { type: 'AgentForwardMsg'; payload: unknown }\n // Handler reads `text` (no state lookup needed at handler time —\n // update() resolved it from the current state.pendingToken). Lets\n // the static-bag `connect()` shape avoid leaking state-reads into\n // event handlers.\n | { type: 'AgentClipboardWrite'; text: string }\n\n// Handler implementation lands in Plan 7 alongside the WS client.\nexport type AgentEffectHandler = (effect: AgentEffect) => Promise<void>\n"]}
|
package/dist/client/factory.d.ts
CHANGED
|
@@ -2,13 +2,44 @@ import type { AppHandle } from '@llui/dom';
|
|
|
2
2
|
import type { AgentEffect } from './effects.js';
|
|
3
3
|
import type { AgentConfirmState } from './agentConfirm.js';
|
|
4
4
|
import type { AgentDocs, AgentContext, MessageAnnotations } from '../protocol.js';
|
|
5
|
+
import { type CodecRegistry } from '../codecs.js';
|
|
6
|
+
/**
|
|
7
|
+
* The shape the compiler emits as `__msgSchema`. Mirrors `MsgField`
|
|
8
|
+
* from `@llui/vite-plugin/src/msg-schema.ts`. Three coexisting forms:
|
|
9
|
+
*
|
|
10
|
+
* 1. Bare primitive: `'string' | 'number' | 'boolean' | 'unknown'`
|
|
11
|
+
* and bare enum: `{enum: [...]}`. Compact form for unannotated
|
|
12
|
+
* required fields.
|
|
13
|
+
* 2. Bare nested types: `{kind: 'object', shape}` for inline /
|
|
14
|
+
* followed-via-typeIndex shapes; `{kind: 'array', element}` for
|
|
15
|
+
* `T[]` / `readonly T[]` / `Array<T>`. The synthesizer recurses
|
|
16
|
+
* to build copy-paste-ready nested examples.
|
|
17
|
+
* 3. Rich descriptor: wraps any of the above with `{optional?,
|
|
18
|
+
* priority?, hint?}` carrying TS optionality and `@should` hints.
|
|
19
|
+
*/
|
|
20
|
+
export type MsgSchemaBareType = string | {
|
|
21
|
+
enum: string[];
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'object';
|
|
24
|
+
shape: Record<string, MsgSchemaField>;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'array';
|
|
27
|
+
element: MsgSchemaBareType;
|
|
28
|
+
};
|
|
29
|
+
export type MsgSchemaField = MsgSchemaBareType | {
|
|
30
|
+
type: MsgSchemaBareType;
|
|
31
|
+
optional?: boolean;
|
|
32
|
+
priority?: 'should';
|
|
33
|
+
hint?: string;
|
|
34
|
+
};
|
|
35
|
+
export type MsgSchemaShape = {
|
|
36
|
+
discriminant: string;
|
|
37
|
+
variants: Record<string, Record<string, MsgSchemaField>>;
|
|
38
|
+
};
|
|
5
39
|
type ComponentMetadata = {
|
|
6
40
|
__msgSchema?: unknown;
|
|
7
41
|
__stateSchema?: unknown;
|
|
8
42
|
__msgAnnotations?: Record<string, MessageAnnotations>;
|
|
9
|
-
__bindingDescriptors?: Array<{
|
|
10
|
-
variant: string;
|
|
11
|
-
}>;
|
|
12
43
|
__schemaHash?: string;
|
|
13
44
|
name: string;
|
|
14
45
|
agentAffordances?: (state: unknown) => Array<{
|
|
@@ -36,6 +67,27 @@ export type CreateAgentClientOpts<State, Msg> = {
|
|
|
36
67
|
*/
|
|
37
68
|
wrapLogMsg?: (m: unknown) => Msg;
|
|
38
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Codec registry for non-JSON-safe values (Date, Blob, Map, …)
|
|
72
|
+
* crossing the LAP boundary. Defaults to `makeDefaultCodecs()`
|
|
73
|
+
* which ships `iso-date` and `epoch-millis`. Provide a custom
|
|
74
|
+
* registry to register additional codecs (e.g. `base64-blob` for
|
|
75
|
+
* file uploads). See `@llui/agent/codecs` for the convention.
|
|
76
|
+
*/
|
|
77
|
+
codecs?: CodecRegistry;
|
|
78
|
+
/**
|
|
79
|
+
* Base path for agent HTTP endpoints. Default: `'/agent'` (matches
|
|
80
|
+
* the canonical paths in `@llui/vite-plugin`'s dev middleware and
|
|
81
|
+
* `@llui/agent/server`). The mint URL, resume URLs, and revoke URL
|
|
82
|
+
* derive from this so consumers don't have to keep them in sync.
|
|
83
|
+
*
|
|
84
|
+
* Override when:
|
|
85
|
+
* - **Cross-origin agent server**: pass the full base, e.g.
|
|
86
|
+
* `'https://api.example.com/agent'` or `'http://localhost:8787/agent'`.
|
|
87
|
+
* - **`@cloudflare/vite-plugin` in dev**: pass `'/cdn-cgi/agent'`
|
|
88
|
+
* because cloudflare-vite shadows non-`/cdn-cgi/*` routes.
|
|
89
|
+
*/
|
|
90
|
+
agentBasePath?: string;
|
|
39
91
|
};
|
|
40
92
|
export type AgentClient = {
|
|
41
93
|
effectHandler: (effect: AgentEffect) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EAEZ,kBAAkB,EAEnB,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"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"}
|
package/dist/client/factory.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { attachWsClient } from './ws-client.js';
|
|
2
2
|
import { createEffectHandler } from './effect-handler.js';
|
|
3
|
+
import { makeDefaultCodecs, encodeForWire, decodeFromWire } from '../codecs.js';
|
|
3
4
|
export function createAgentClient(opts) {
|
|
4
5
|
let ws = null;
|
|
5
6
|
let wsClient = null;
|
|
@@ -52,14 +53,34 @@ export function createAgentClient(opts) {
|
|
|
52
53
|
onRejectionEvt = null;
|
|
53
54
|
errorListenersInstalled = false;
|
|
54
55
|
}
|
|
56
|
+
// Codec registry handles non-JSON-safe values (Date, etc.) crossing
|
|
57
|
+
// the LAP boundary. `getState` encodes outgoing snapshots; `send`
|
|
58
|
+
// decodes incoming agent messages before they hit the reducer. The
|
|
59
|
+
// tagged-value convention is documented in `@llui/agent/codecs`.
|
|
60
|
+
const codecs = opts.codecs ?? makeDefaultCodecs();
|
|
55
61
|
const rpcHost = {
|
|
56
|
-
getState: () => opts.handle.getState(),
|
|
57
|
-
send: (m) => opts.handle.send(m),
|
|
62
|
+
getState: () => encodeForWire(opts.handle.getState(), codecs),
|
|
63
|
+
send: (m) => opts.handle.send(decodeFromWire(m, codecs)),
|
|
58
64
|
flush: () => opts.handle.flush(),
|
|
59
65
|
subscribe: (listener) => opts.handle.subscribe(() => listener()),
|
|
60
66
|
getAndClearDrainErrors: () => drainErrors.splice(0, drainErrors.length),
|
|
61
67
|
getMsgAnnotations: () => opts.def.__msgAnnotations ?? null,
|
|
62
|
-
|
|
68
|
+
// The compiler-injected message schema. Used by `list_actions` to
|
|
69
|
+
// synthesize payload examples for `@agentOnly` variants that have
|
|
70
|
+
// no live UI binding — the agent should still see them as
|
|
71
|
+
// affordances even though no human can click them.
|
|
72
|
+
getMsgSchema: () => opts.def.__msgSchema ?? null,
|
|
73
|
+
// Run the reducer in isolation for `would_dispatch`. Wraps the
|
|
74
|
+
// AppHandle's same-named method so the host doesn't need a direct
|
|
75
|
+
// reference to the live ComponentInstance.
|
|
76
|
+
runReducer: (msg) => opts.handle.runReducer(msg),
|
|
77
|
+
// Live binding descriptors: read from the runtime registry that
|
|
78
|
+
// tracks which Msg variants are dispatchable from currently-mounted
|
|
79
|
+
// event handlers. Empty array when the app wasn't compiled with
|
|
80
|
+
// agent metadata (no tagger pass) or has no view bindings yet —
|
|
81
|
+
// both produce the same "no live affordances" signal at the agent
|
|
82
|
+
// layer.
|
|
83
|
+
getBindingDescriptors: () => opts.handle.getBindingDescriptors(),
|
|
63
84
|
getAgentAffordances: () => opts.def.agentAffordances ?? null,
|
|
64
85
|
getAgentContext: () => opts.def.agentContext ?? null,
|
|
65
86
|
getRootElement: () => opts.rootElement,
|
|
@@ -83,6 +104,7 @@ export function createAgentClient(opts) {
|
|
|
83
104
|
send: (m) => opts.handle.send(m),
|
|
84
105
|
wrapAgentConnect: (m) => opts.slices.wrapConnectMsg(m),
|
|
85
106
|
forward: (payload) => opts.handle.send(payload),
|
|
107
|
+
agentBasePath: opts.agentBasePath,
|
|
86
108
|
openWs: (token, wsUrl) => {
|
|
87
109
|
if (ws)
|
|
88
110
|
ws.close();
|
|
@@ -120,7 +142,7 @@ export function createAgentClient(opts) {
|
|
|
120
142
|
continue;
|
|
121
143
|
resolvedConfirms.add(entry.id);
|
|
122
144
|
if (entry.status === 'approved') {
|
|
123
|
-
wsClient?.resolveConfirm(entry.id, 'confirmed', opts.handle.getState());
|
|
145
|
+
wsClient?.resolveConfirm(entry.id, 'confirmed', encodeForWire(opts.handle.getState(), codecs));
|
|
124
146
|
}
|
|
125
147
|
else if (entry.status === 'rejected') {
|
|
126
148
|
wsClient?.resolveConfirm(entry.id, 'user-cancelled');
|
|
@@ -134,7 +156,10 @@ export function createAgentClient(opts) {
|
|
|
134
156
|
confirmPollTimer = setInterval(pollConfirms, 200);
|
|
135
157
|
if (!stateSubscription) {
|
|
136
158
|
stateSubscription = opts.handle.subscribe((state) => {
|
|
137
|
-
|
|
159
|
+
// Same codec convention as `getState`: outgoing snapshots
|
|
160
|
+
// pass through the encoder so non-JSON-safe values (Date,
|
|
161
|
+
// etc.) become tagged-wire form.
|
|
162
|
+
wsClient?.emitStateUpdate('/', encodeForWire(state, codecs));
|
|
138
163
|
});
|
|
139
164
|
}
|
|
140
165
|
installErrorListeners();
|