@economic/agents 2.6.0 → 2.6.1
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/index.d.mts +1 -4
- package/dist/index.mjs +87 -70
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -225,10 +225,7 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
|
|
|
225
225
|
private _getExchangedToken;
|
|
226
226
|
/**
|
|
227
227
|
* Swaps the client-sent token for the exchanged one in a copy of the turn
|
|
228
|
-
* body. No-op when token exchange is not configured.
|
|
229
|
-
* token is missing or expired the turn cannot run: only a reconnect can
|
|
230
|
-
* deliver a fresh subject token, so the current connection (if any) is
|
|
231
|
-
* closed to force one, and the turn fails.
|
|
228
|
+
* body. No-op when token exchange is not configured.
|
|
232
229
|
*/
|
|
233
230
|
private _applyTokenExchange;
|
|
234
231
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,37 @@ import { Think, skills } from "@cloudflare/think";
|
|
|
4
4
|
import { Output, convertToModelMessages, generateText, jsonSchema, pruneMessages, tool as tool$1 } from "ai";
|
|
5
5
|
import { nanoid } from "nanoid";
|
|
6
6
|
import { createCompactFunction } from "agents/experimental/memory/utils";
|
|
7
|
+
//#region src/server/util/agent.ts
|
|
8
|
+
function sendConnectionStatus(connection, status) {
|
|
9
|
+
connection.send(JSON.stringify({
|
|
10
|
+
type: "connection_status",
|
|
11
|
+
status
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
function sendAgentType(connection, agentType) {
|
|
15
|
+
connection.send(JSON.stringify({
|
|
16
|
+
type: "agent_type",
|
|
17
|
+
agentType
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
function sendSubAgentName(connection, subAgentName) {
|
|
21
|
+
connection.send(JSON.stringify({
|
|
22
|
+
type: "sub_agent_name",
|
|
23
|
+
subAgentName
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Close code for a getUserContext failure. Subclasses signal an intentional
|
|
28
|
+
* auth-style rejection by throwing an Error carrying a numeric `closeCode`
|
|
29
|
+
* in the WebSocket application range (4000-4999); anything else is treated
|
|
30
|
+
* as an internal error (1011).
|
|
31
|
+
*/
|
|
32
|
+
function getConnectCloseCode(error) {
|
|
33
|
+
const closeCode = error?.closeCode;
|
|
34
|
+
if (typeof closeCode === "number" && closeCode >= 4e3 && closeCode <= 4999) return closeCode;
|
|
35
|
+
return 1011;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
7
38
|
//#region src/server/features/auth/tokenExchange.ts
|
|
8
39
|
/**
|
|
9
40
|
* OAuth 2.0 Token Exchange (RFC 8693) against an identity server.
|
|
@@ -94,6 +125,56 @@ function withExchangedToken(body, tokenHeader, accessToken) {
|
|
|
94
125
|
}
|
|
95
126
|
};
|
|
96
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Connect-time exchange. On failure, signals the client and closes the
|
|
130
|
+
* connection — `unauthorized`/4001 when the session token itself was rejected
|
|
131
|
+
* (only a re-login fixes that), `error`/1011 for identity-server or
|
|
132
|
+
* configuration faults — and returns undefined so the caller abandons the
|
|
133
|
+
* connect.
|
|
134
|
+
*/
|
|
135
|
+
async function exchangeConnectToken(subjectToken, config, connection) {
|
|
136
|
+
let result;
|
|
137
|
+
try {
|
|
138
|
+
result = await exchangeToken(subjectToken, config);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
sendConnectionStatus(connection, "error");
|
|
141
|
+
console.error(`[Agent] Token exchange error - ${error}`);
|
|
142
|
+
connection.close(1011, "Token exchange failed");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!result.success) {
|
|
146
|
+
console.error(`[Agent] Token exchange failed - ${result.message}`);
|
|
147
|
+
if (result.subjectTokenRejected) {
|
|
148
|
+
sendConnectionStatus(connection, "unauthorized");
|
|
149
|
+
connection.close(4001, "Unauthorized");
|
|
150
|
+
} else {
|
|
151
|
+
sendConnectionStatus(connection, "error");
|
|
152
|
+
connection.close(1011, "Token exchange failed");
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
accessToken: result.accessToken,
|
|
158
|
+
expiresAt: result.expiresAt
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Turn-time injection: returns a body copy with the held token under
|
|
163
|
+
* `tokens[config.tokenHeader]`. When the held token is missing or expired the
|
|
164
|
+
* turn cannot run — only a re-authenticating reconnect delivers a fresh
|
|
165
|
+
* subject token — so the current connection (if any) is closed to force one,
|
|
166
|
+
* and this throws to fail the turn.
|
|
167
|
+
*/
|
|
168
|
+
function injectExchangedToken(body, config, token, connection) {
|
|
169
|
+
if (!token || token.expiresAt <= Date.now()) {
|
|
170
|
+
if (connection) {
|
|
171
|
+
sendConnectionStatus(connection, "unauthorized");
|
|
172
|
+
connection.close(4001, "Unauthorized");
|
|
173
|
+
}
|
|
174
|
+
throw new Error("Exchanged token missing or expired - the client must reconnect");
|
|
175
|
+
}
|
|
176
|
+
return withExchangedToken(body, config.tokenHeader ?? "X-EconomicToken", token.accessToken);
|
|
177
|
+
}
|
|
97
178
|
//#endregion
|
|
98
179
|
//#region src/server/util/tools.ts
|
|
99
180
|
function tool(tool) {
|
|
@@ -183,26 +264,6 @@ async function touchAgentInstance(db, input) {
|
|
|
183
264
|
WHERE agent_name = ? AND durable_object_name = ?`).bind(input.updatedAt, input.agentName, input.durableObjectName).run();
|
|
184
265
|
}
|
|
185
266
|
//#endregion
|
|
186
|
-
//#region src/server/util/agent.ts
|
|
187
|
-
function sendConnectionStatus(connection, status) {
|
|
188
|
-
connection.send(JSON.stringify({
|
|
189
|
-
type: "connection_status",
|
|
190
|
-
status
|
|
191
|
-
}));
|
|
192
|
-
}
|
|
193
|
-
function sendAgentType(connection, agentType) {
|
|
194
|
-
connection.send(JSON.stringify({
|
|
195
|
-
type: "agent_type",
|
|
196
|
-
agentType
|
|
197
|
-
}));
|
|
198
|
-
}
|
|
199
|
-
function sendSubAgentName(connection, subAgentName) {
|
|
200
|
-
connection.send(JSON.stringify({
|
|
201
|
-
type: "sub_agent_name",
|
|
202
|
-
subAgentName
|
|
203
|
-
}));
|
|
204
|
-
}
|
|
205
|
-
//#endregion
|
|
206
267
|
//#region src/server/util/llm.ts
|
|
207
268
|
/**
|
|
208
269
|
* Convention: tools can include a `sources` array in their return value to surface
|
|
@@ -240,17 +301,6 @@ function buildSourcesTransform(additional) {
|
|
|
240
301
|
//#endregion
|
|
241
302
|
//#region src/server/agents/Agent.ts
|
|
242
303
|
const EXCHANGED_TOKEN_STORAGE_KEY = "economic:exchangedToken";
|
|
243
|
-
/**
|
|
244
|
-
* Close code for a getUserContext failure. Subclasses signal an intentional
|
|
245
|
-
* auth-style rejection by throwing an Error carrying a numeric `closeCode`
|
|
246
|
-
* in the WebSocket application range (4000-4999); anything else is treated
|
|
247
|
-
* as an internal error (1011).
|
|
248
|
-
*/
|
|
249
|
-
function getConnectCloseCode(error) {
|
|
250
|
-
const closeCode = error?.closeCode;
|
|
251
|
-
if (typeof closeCode === "number" && closeCode >= 4e3 && closeCode <= 4999) return closeCode;
|
|
252
|
-
return 1011;
|
|
253
|
-
}
|
|
254
304
|
var Agent = class extends Think {
|
|
255
305
|
agentType = "agent";
|
|
256
306
|
clientIp;
|
|
@@ -314,31 +364,10 @@ var Agent = class extends Think {
|
|
|
314
364
|
const getTokenExchangeConfig = this.constructor.getTokenExchangeConfig;
|
|
315
365
|
const exchangeConfig = getTokenExchangeConfig?.(this.env);
|
|
316
366
|
if (token && exchangeConfig) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
sendConnectionStatus(connection, "error");
|
|
322
|
-
console.error(`[Agent] Token exchange error - ${error}`);
|
|
323
|
-
connection.close(1011, "Token exchange failed");
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
if (!result.success) {
|
|
327
|
-
console.error(`[Agent] Token exchange failed - ${result.message}`);
|
|
328
|
-
if (result.subjectTokenRejected) {
|
|
329
|
-
sendConnectionStatus(connection, "unauthorized");
|
|
330
|
-
connection.close(4001, "Unauthorized");
|
|
331
|
-
} else {
|
|
332
|
-
sendConnectionStatus(connection, "error");
|
|
333
|
-
connection.close(1011, "Token exchange failed");
|
|
334
|
-
}
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
await this._storeExchangedToken({
|
|
338
|
-
accessToken: result.accessToken,
|
|
339
|
-
expiresAt: result.expiresAt
|
|
340
|
-
});
|
|
341
|
-
effectiveToken = result.accessToken;
|
|
367
|
+
const exchanged = await exchangeConnectToken(token, exchangeConfig, connection);
|
|
368
|
+
if (!exchanged) return;
|
|
369
|
+
await this._storeExchangedToken(exchanged);
|
|
370
|
+
effectiveToken = exchanged.accessToken;
|
|
342
371
|
}
|
|
343
372
|
if (effectiveToken && this.getUserContext) try {
|
|
344
373
|
connection.setState({ userContext: await this.getUserContext(effectiveToken) });
|
|
@@ -587,25 +616,13 @@ var Agent = class extends Think {
|
|
|
587
616
|
}
|
|
588
617
|
/**
|
|
589
618
|
* Swaps the client-sent token for the exchanged one in a copy of the turn
|
|
590
|
-
* body. No-op when token exchange is not configured.
|
|
591
|
-
* token is missing or expired the turn cannot run: only a reconnect can
|
|
592
|
-
* deliver a fresh subject token, so the current connection (if any) is
|
|
593
|
-
* closed to force one, and the turn fails.
|
|
619
|
+
* body. No-op when token exchange is not configured.
|
|
594
620
|
*/
|
|
595
621
|
async _applyTokenExchange(body) {
|
|
596
622
|
const getTokenExchangeConfig = this.constructor.getTokenExchangeConfig;
|
|
597
623
|
const exchangeConfig = getTokenExchangeConfig?.(this.env);
|
|
598
624
|
if (!exchangeConfig) return body;
|
|
599
|
-
|
|
600
|
-
if (!token) {
|
|
601
|
-
const { connection } = getCurrentAgent();
|
|
602
|
-
if (connection) {
|
|
603
|
-
sendConnectionStatus(connection, "unauthorized");
|
|
604
|
-
connection.close(4001, "Unauthorized");
|
|
605
|
-
}
|
|
606
|
-
throw new Error("Exchanged token missing or expired - the client must reconnect");
|
|
607
|
-
}
|
|
608
|
-
return withExchangedToken(body, exchangeConfig.tokenHeader ?? "X-EconomicToken", token.accessToken);
|
|
625
|
+
return injectExchangedToken(body, exchangeConfig, await this._getExchangedToken(), getCurrentAgent().connection);
|
|
609
626
|
}
|
|
610
627
|
/**
|
|
611
628
|
* The user context for the session.
|