@webless/agent 0.11.0 → 0.12.0
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/dist/{chunk-NW37MHU7.js → chunk-EVWZF34F.js} +1103 -477
- package/dist/chunk-EVWZF34F.js.map +1 -0
- package/dist/embed.cjs +1132 -506
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +64 -0
- package/dist/embed.css.map +1 -1
- package/dist/embed.d.cts +3 -2
- package/dist/embed.d.ts +3 -2
- package/dist/embed.js +1 -1
- package/dist/index.cjs +283 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +277 -6
- package/dist/index.js.map +1 -1
- package/dist/{panel-controller-rxR75tRa.d.cts → panel-controller-CYoivbYB.d.cts} +173 -1
- package/dist/{panel-controller-rxR75tRa.d.ts → panel-controller-CYoivbYB.d.ts} +173 -1
- package/dist/presentation.d.cts +2 -1
- package/dist/presentation.d.ts +2 -1
- package/dist/react.cjs +1131 -505
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +64 -0
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +126 -4
- package/dist/react.d.ts +126 -4
- package/dist/react.js +1 -1
- package/dist/{types-B2j6hbI5.d.cts → types-4lTJW5mp.d.cts} +133 -1
- package/dist/{types-B2j6hbI5.d.ts → types-4lTJW5mp.d.ts} +133 -1
- package/package.json +3 -2
- package/scripts/sync-handoff-contract.mjs +18 -0
- package/dist/chunk-NW37MHU7.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { d as AgentClientOptions, c as AgentClient,
|
|
2
|
-
export { A as AGENT_STRUCTURED_TOOL_INPUT_HEADER, a as AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION, b as AGENT_TOOL_UI_SCHEMA_VERSION,
|
|
1
|
+
import { d as AgentClientOptions, c as AgentClient, h as AgentIndexVersion, n as AgentRuntimeConfig, g as AgentHealthResult, P as PersistedAgentSession } from './types-4lTJW5mp.js';
|
|
2
|
+
export { A as AGENT_STRUCTURED_TOOL_INPUT_HEADER, a as AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION, b as AGENT_TOOL_UI_SCHEMA_VERSION, e as AgentHandoffClient, f as AgentHandoffCommand, o as AgentHandoffEvent, p as AgentHandoffPage, q as AgentHandoffStatus, i as AgentInputOption, j as AgentInputRequest, k as AgentInputResponse, l as AgentRespondTurnOptions, m as AgentResumeTurnOptions, r as AgentSendTurnOptions, s as AgentStreamHandlers, t as AgentStructuredToolInput, u as AgentToolResult, v as AgentToolResultEnvelope, w as AgentToolResultJsonValue, x as AgentToolUiAction, y as AgentToolUiField, z as AgentToolUiFieldKind, B as AgentToolUiOption, C as AgentToolUiStep, D as AgentToolUiSurface, E as AgentWorkItem, F as formatAgentStructuredToolInput, G as parseAgentToolResultEnvelope, H as parseAgentToolUiSurface } from './types-4lTJW5mp.js';
|
|
3
|
+
import 'zod';
|
|
3
4
|
|
|
4
5
|
declare function createAgentClient(options: AgentClientOptions): AgentClient;
|
|
5
6
|
|
package/dist/index.js
CHANGED
|
@@ -12,9 +12,204 @@ import {
|
|
|
12
12
|
// src/runtime/client.ts
|
|
13
13
|
import {
|
|
14
14
|
Client,
|
|
15
|
-
ClientError as
|
|
15
|
+
ClientError as ClientError3
|
|
16
16
|
} from "eve/client";
|
|
17
17
|
|
|
18
|
+
// src/runtime/handoff.ts
|
|
19
|
+
import { ClientError as ClientError2 } from "eve/client";
|
|
20
|
+
|
|
21
|
+
// src/runtime/generated/handoff-contract.ts
|
|
22
|
+
import { z } from "zod";
|
|
23
|
+
var id = z.string().min(1).max(200);
|
|
24
|
+
var sequence = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
25
|
+
var text = z.string().trim().min(1).max(16e3);
|
|
26
|
+
var agentRuntimeHandoffVersion = "webless.ai/agent-runtime-handoff/v1";
|
|
27
|
+
var agentRuntimeHandoffStatusSchema = z.enum([
|
|
28
|
+
"ai",
|
|
29
|
+
"requesting",
|
|
30
|
+
"queued",
|
|
31
|
+
"human",
|
|
32
|
+
"resolved",
|
|
33
|
+
"failed"
|
|
34
|
+
]);
|
|
35
|
+
var agentRuntimeHandoffActorSchema = z.strictObject({
|
|
36
|
+
id,
|
|
37
|
+
name: z.string().trim().min(1).max(200)
|
|
38
|
+
});
|
|
39
|
+
var eventBase = {
|
|
40
|
+
id,
|
|
41
|
+
sequence: sequence.refine((value) => value > 0),
|
|
42
|
+
handoffId: id,
|
|
43
|
+
epoch: sequence.refine((value) => value > 0),
|
|
44
|
+
createdAt: z.iso.datetime()
|
|
45
|
+
};
|
|
46
|
+
var agentRuntimeHandoffEventSchema = z.discriminatedUnion("type", [
|
|
47
|
+
z.strictObject({
|
|
48
|
+
...eventBase,
|
|
49
|
+
type: z.literal("status"),
|
|
50
|
+
status: agentRuntimeHandoffStatusSchema,
|
|
51
|
+
actor: agentRuntimeHandoffActorSchema.nullable()
|
|
52
|
+
}),
|
|
53
|
+
z.strictObject({
|
|
54
|
+
...eventBase,
|
|
55
|
+
type: z.literal("visitor.message"),
|
|
56
|
+
message: text,
|
|
57
|
+
operationId: id
|
|
58
|
+
}),
|
|
59
|
+
z.strictObject({
|
|
60
|
+
...eventBase,
|
|
61
|
+
type: z.literal("human.message"),
|
|
62
|
+
message: text,
|
|
63
|
+
actor: agentRuntimeHandoffActorSchema
|
|
64
|
+
})
|
|
65
|
+
]);
|
|
66
|
+
var agentRuntimeHandoffReadRequestSchema = z.strictObject({
|
|
67
|
+
after: sequence.default(0)
|
|
68
|
+
});
|
|
69
|
+
var agentRuntimeHandoffPageSchema = z.strictObject({
|
|
70
|
+
apiVersion: z.literal(agentRuntimeHandoffVersion),
|
|
71
|
+
sessionId: id,
|
|
72
|
+
enabled: z.boolean(),
|
|
73
|
+
status: agentRuntimeHandoffStatusSchema,
|
|
74
|
+
handoffId: id.nullable(),
|
|
75
|
+
epoch: sequence,
|
|
76
|
+
after: sequence,
|
|
77
|
+
cursor: sequence,
|
|
78
|
+
hasMore: z.boolean(),
|
|
79
|
+
events: z.array(agentRuntimeHandoffEventSchema).max(100)
|
|
80
|
+
}).superRefine((page, ctx) => {
|
|
81
|
+
let cursor = page.after;
|
|
82
|
+
let previousEpoch = 0;
|
|
83
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
84
|
+
const ids = /* @__PURE__ */ new Set();
|
|
85
|
+
const handoffs = /* @__PURE__ */ new Map();
|
|
86
|
+
const terminalEpochs = /* @__PURE__ */ new Set();
|
|
87
|
+
let currentStatus;
|
|
88
|
+
for (const event of page.events) {
|
|
89
|
+
if (event.epoch < previousEpoch)
|
|
90
|
+
ctx.addIssue({
|
|
91
|
+
code: "custom",
|
|
92
|
+
message: "Handoff epochs cannot decrease."
|
|
93
|
+
});
|
|
94
|
+
previousEpoch = event.epoch;
|
|
95
|
+
if (ids.has(event.id))
|
|
96
|
+
ctx.addIssue({
|
|
97
|
+
code: "custom",
|
|
98
|
+
message: "Duplicate handoff event ID."
|
|
99
|
+
});
|
|
100
|
+
ids.add(event.id);
|
|
101
|
+
const handoffId = handoffs.get(event.epoch);
|
|
102
|
+
if (handoffId !== void 0 && handoffId !== event.handoffId || event.epoch === page.epoch && event.handoffId !== page.handoffId)
|
|
103
|
+
ctx.addIssue({
|
|
104
|
+
code: "custom",
|
|
105
|
+
message: "Inconsistent handoff epoch identity."
|
|
106
|
+
});
|
|
107
|
+
handoffs.set(event.epoch, event.handoffId);
|
|
108
|
+
if (terminalEpochs.has(event.epoch) && (event.type !== "status" || event.status !== "ai"))
|
|
109
|
+
ctx.addIssue({
|
|
110
|
+
code: "custom",
|
|
111
|
+
message: "Handoff event follows resolution."
|
|
112
|
+
});
|
|
113
|
+
if (event.type === "status") {
|
|
114
|
+
if (event.status === "human" && event.actor === null)
|
|
115
|
+
ctx.addIssue({
|
|
116
|
+
code: "custom",
|
|
117
|
+
message: "Human ownership requires a representative."
|
|
118
|
+
});
|
|
119
|
+
const previous = statuses.get(event.epoch);
|
|
120
|
+
const transitions = {
|
|
121
|
+
ai: [],
|
|
122
|
+
requesting: ["queued", "resolved", "failed"],
|
|
123
|
+
queued: ["human", "resolved", "failed"],
|
|
124
|
+
human: ["resolved", "failed"],
|
|
125
|
+
resolved: ["ai"],
|
|
126
|
+
failed: []
|
|
127
|
+
};
|
|
128
|
+
if (previous !== void 0 && !transitions[previous].includes(event.status))
|
|
129
|
+
ctx.addIssue({
|
|
130
|
+
code: "custom",
|
|
131
|
+
message: "Invalid handoff ownership transition."
|
|
132
|
+
});
|
|
133
|
+
statuses.set(event.epoch, event.status);
|
|
134
|
+
if (["resolved", "failed", "ai"].includes(event.status))
|
|
135
|
+
terminalEpochs.add(event.epoch);
|
|
136
|
+
if (event.epoch === page.epoch) currentStatus = event.status;
|
|
137
|
+
}
|
|
138
|
+
if (event.sequence !== cursor + 1) {
|
|
139
|
+
ctx.addIssue({
|
|
140
|
+
code: "custom",
|
|
141
|
+
message: "Handoff event gap or replay."
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
cursor = event.sequence;
|
|
145
|
+
if (event.epoch > page.epoch) {
|
|
146
|
+
ctx.addIssue({
|
|
147
|
+
code: "custom",
|
|
148
|
+
message: "Event exceeds current epoch."
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!page.hasMore && currentStatus !== void 0 && currentStatus !== page.status)
|
|
153
|
+
ctx.addIssue({
|
|
154
|
+
code: "custom",
|
|
155
|
+
message: "Handoff ownership contradicts its final status event."
|
|
156
|
+
});
|
|
157
|
+
if (page.cursor !== cursor || page.hasMore && page.events.length === 0) {
|
|
158
|
+
ctx.addIssue({ code: "custom", message: "Invalid handoff page cursor." });
|
|
159
|
+
}
|
|
160
|
+
if (page.epoch === 0 !== (page.handoffId === null)) {
|
|
161
|
+
ctx.addIssue({ code: "custom", message: "Invalid handoff identity." });
|
|
162
|
+
}
|
|
163
|
+
if (page.handoffId === null && page.status !== "ai") {
|
|
164
|
+
ctx.addIssue({
|
|
165
|
+
code: "custom",
|
|
166
|
+
message: "Handoff identity is required."
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
var agentRuntimeHandoffStartSchema = z.strictObject({
|
|
171
|
+
operationId: id
|
|
172
|
+
});
|
|
173
|
+
var agentRuntimeHandoffCommandSchema = z.strictObject({
|
|
174
|
+
operationId: id,
|
|
175
|
+
handoffId: id,
|
|
176
|
+
epoch: sequence.refine((value) => value > 0)
|
|
177
|
+
});
|
|
178
|
+
var agentRuntimeHandoffMessageSchema = agentRuntimeHandoffCommandSchema.extend({ message: text });
|
|
179
|
+
var agentRuntimeHandoffBindingSchema = z.strictObject({
|
|
180
|
+
tenantId: id,
|
|
181
|
+
indexId: id,
|
|
182
|
+
visitorSubject: id,
|
|
183
|
+
sessionId: id,
|
|
184
|
+
handoffId: id,
|
|
185
|
+
epoch: sequence.refine((value) => value > 0)
|
|
186
|
+
});
|
|
187
|
+
var providerEventBase = {
|
|
188
|
+
apiVersion: z.literal(agentRuntimeHandoffVersion),
|
|
189
|
+
binding: agentRuntimeHandoffBindingSchema,
|
|
190
|
+
eventId: id,
|
|
191
|
+
sequence: sequence.refine((value) => value > 0)
|
|
192
|
+
};
|
|
193
|
+
var agentRuntimeHandoffProviderEventSchema = z.discriminatedUnion(
|
|
194
|
+
"type",
|
|
195
|
+
[
|
|
196
|
+
z.strictObject({ ...providerEventBase, type: z.literal("queued") }),
|
|
197
|
+
z.strictObject({
|
|
198
|
+
...providerEventBase,
|
|
199
|
+
type: z.literal("assigned"),
|
|
200
|
+
actor: agentRuntimeHandoffActorSchema
|
|
201
|
+
}),
|
|
202
|
+
z.strictObject({
|
|
203
|
+
...providerEventBase,
|
|
204
|
+
type: z.literal("human.message"),
|
|
205
|
+
actor: agentRuntimeHandoffActorSchema,
|
|
206
|
+
message: text
|
|
207
|
+
}),
|
|
208
|
+
z.strictObject({ ...providerEventBase, type: z.literal("resolved") }),
|
|
209
|
+
z.strictObject({ ...providerEventBase, type: z.literal("failed") })
|
|
210
|
+
]
|
|
211
|
+
);
|
|
212
|
+
|
|
18
213
|
// src/runtime/capability.ts
|
|
19
214
|
import { ClientError } from "eve/client";
|
|
20
215
|
var MAX_REFRESH_SKEW_MS = 3e4;
|
|
@@ -169,6 +364,75 @@ async function withCapabilityRefresh(capability, request) {
|
|
|
169
364
|
}
|
|
170
365
|
}
|
|
171
366
|
|
|
367
|
+
// src/runtime/handoff.ts
|
|
368
|
+
function createHandoffClient(options) {
|
|
369
|
+
const target = () => {
|
|
370
|
+
const sessionId = options.getSessionId();
|
|
371
|
+
if (!sessionId)
|
|
372
|
+
throw new Error(
|
|
373
|
+
"Start a conversation before requesting a representative."
|
|
374
|
+
);
|
|
375
|
+
return {
|
|
376
|
+
sessionId,
|
|
377
|
+
path: `/webless/v1/session/${encodeURIComponent(sessionId)}/handoff`
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
const request = (path, init) => withCapabilityRefresh(options.capability, async () => {
|
|
381
|
+
const response = await options.getClient().fetch(path, {
|
|
382
|
+
...init,
|
|
383
|
+
cache: "no-store",
|
|
384
|
+
redirect: "error"
|
|
385
|
+
});
|
|
386
|
+
if (!response.ok) {
|
|
387
|
+
throw new ClientError2(
|
|
388
|
+
response.status,
|
|
389
|
+
await response.text(),
|
|
390
|
+
response.headers
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return response;
|
|
394
|
+
});
|
|
395
|
+
const command = async (suffix, body, signal) => {
|
|
396
|
+
const { path } = target();
|
|
397
|
+
await request(path + suffix, {
|
|
398
|
+
method: "POST",
|
|
399
|
+
headers: { "content-type": "application/json" },
|
|
400
|
+
body: JSON.stringify(body),
|
|
401
|
+
signal
|
|
402
|
+
});
|
|
403
|
+
};
|
|
404
|
+
return {
|
|
405
|
+
async read(input = {}) {
|
|
406
|
+
const { after } = agentRuntimeHandoffReadRequestSchema.parse({
|
|
407
|
+
after: input.after
|
|
408
|
+
});
|
|
409
|
+
const { sessionId, path } = target();
|
|
410
|
+
const response = await request(`${path}?after=${after}`, {
|
|
411
|
+
signal: input.signal
|
|
412
|
+
});
|
|
413
|
+
const value = await response.json();
|
|
414
|
+
const page = agentRuntimeHandoffPageSchema.parse(value);
|
|
415
|
+
if (page.sessionId !== sessionId || page.after !== after) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
"The handoff response does not belong to this conversation or cursor."
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
return page;
|
|
421
|
+
},
|
|
422
|
+
start: (operationId, signal) => command(
|
|
423
|
+
"",
|
|
424
|
+
agentRuntimeHandoffStartSchema.parse({ operationId }),
|
|
425
|
+
signal
|
|
426
|
+
),
|
|
427
|
+
send: (input, signal) => command(
|
|
428
|
+
"/messages",
|
|
429
|
+
agentRuntimeHandoffMessageSchema.parse(input),
|
|
430
|
+
signal
|
|
431
|
+
),
|
|
432
|
+
returnToAI: (input, signal) => command("/return", agentRuntimeHandoffCommandSchema.parse(input), signal)
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
172
436
|
// src/runtime/config.ts
|
|
173
437
|
var DEFAULT_RUNTIME_ORIGIN = "https://runtime.staging.webless.ai";
|
|
174
438
|
var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
|
|
@@ -768,6 +1032,11 @@ var AgentSession = class {
|
|
|
768
1032
|
version,
|
|
769
1033
|
visitorSessionId
|
|
770
1034
|
});
|
|
1035
|
+
this.handoff = createHandoffClient({
|
|
1036
|
+
getClient: () => this.ensureClient(),
|
|
1037
|
+
getSessionId: () => this.getActiveSessionId(),
|
|
1038
|
+
capability: this.capability
|
|
1039
|
+
});
|
|
771
1040
|
}
|
|
772
1041
|
indexId;
|
|
773
1042
|
version;
|
|
@@ -780,6 +1049,7 @@ var AgentSession = class {
|
|
|
780
1049
|
activeResponse;
|
|
781
1050
|
childStreams;
|
|
782
1051
|
capability;
|
|
1052
|
+
handoff;
|
|
783
1053
|
getActiveSessionId() {
|
|
784
1054
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
785
1055
|
}
|
|
@@ -890,7 +1160,7 @@ var AgentSession = class {
|
|
|
890
1160
|
() => activeSession.send(message, { signal })
|
|
891
1161
|
);
|
|
892
1162
|
} catch (error) {
|
|
893
|
-
if (error instanceof
|
|
1163
|
+
if (error instanceof ClientError3 && error.status === 409 && error.code === "session_not_active") {
|
|
894
1164
|
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
895
1165
|
this.session = void 0;
|
|
896
1166
|
session = void 0;
|
|
@@ -1064,10 +1334,10 @@ var AgentSession = class {
|
|
|
1064
1334
|
}
|
|
1065
1335
|
this.session = session;
|
|
1066
1336
|
const inputResponses = responses.map(
|
|
1067
|
-
({ requestId, optionId, text }) => ({
|
|
1337
|
+
({ requestId, optionId, text: text2 }) => ({
|
|
1068
1338
|
requestId,
|
|
1069
1339
|
...optionId ? { optionId } : {},
|
|
1070
|
-
...
|
|
1340
|
+
...text2 ? { text: text2 } : {}
|
|
1071
1341
|
})
|
|
1072
1342
|
);
|
|
1073
1343
|
const response = await withCapabilityRefresh(
|
|
@@ -1157,6 +1427,7 @@ function createAgentClient(options) {
|
|
|
1157
1427
|
);
|
|
1158
1428
|
return {
|
|
1159
1429
|
indexId,
|
|
1430
|
+
handoff: session.handoff,
|
|
1160
1431
|
version,
|
|
1161
1432
|
runtimeOrigin,
|
|
1162
1433
|
visitorSessionId,
|
|
@@ -1188,7 +1459,7 @@ function createAgentClient(options) {
|
|
|
1188
1459
|
}
|
|
1189
1460
|
|
|
1190
1461
|
// src/runtime/errors.ts
|
|
1191
|
-
import { ClientError as
|
|
1462
|
+
import { ClientError as ClientError4 } from "eve/client";
|
|
1192
1463
|
var TRANSIENT_AGENT_ERROR_MESSAGE = "The agent run stopped before the action finished. Please try again.";
|
|
1193
1464
|
var PREVIEW_AUTHORIZATION_ERROR_MESSAGE = "This preview could not be authorized. Open the latest preview from Webless.";
|
|
1194
1465
|
function isTransientRuntimeMessage(message) {
|
|
@@ -1200,7 +1471,7 @@ function isPreviewAuthorizationMessage(message) {
|
|
|
1200
1471
|
return normalized.includes("unpublished preview authorization") || normalized.includes("unpublished preview grant") || normalized.includes("agent studio preview grant") || normalized.includes("preview authorization");
|
|
1201
1472
|
}
|
|
1202
1473
|
function formatAgentError(error) {
|
|
1203
|
-
if (error instanceof
|
|
1474
|
+
if (error instanceof ClientError4) {
|
|
1204
1475
|
if (error.status === 401 && error.code === "index_required") {
|
|
1205
1476
|
return "Missing indexId \u2014 pass a published index id to createAgentClient().";
|
|
1206
1477
|
}
|