@tidblink/server 0.3.0-rc.0 → 0.4.0-rc.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.
Files changed (124) hide show
  1. package/README.md +557 -368
  2. package/dist/audio.d.ts +9 -0
  3. package/dist/audio.d.ts.map +1 -1
  4. package/dist/audio.js +6 -1
  5. package/dist/audio.js.map +1 -1
  6. package/dist/backend-connection.d.ts +89 -0
  7. package/dist/backend-connection.d.ts.map +1 -0
  8. package/dist/backend-connection.js +300 -0
  9. package/dist/backend-connection.js.map +1 -0
  10. package/dist/backend-pool.d.ts +93 -0
  11. package/dist/backend-pool.d.ts.map +1 -0
  12. package/dist/backend-pool.js +419 -0
  13. package/dist/backend-pool.js.map +1 -0
  14. package/dist/client-tool-executor.d.ts +31 -0
  15. package/dist/client-tool-executor.d.ts.map +1 -0
  16. package/dist/client-tool-executor.js +190 -0
  17. package/dist/client-tool-executor.js.map +1 -0
  18. package/dist/client-tools.d.ts +0 -25
  19. package/dist/client-tools.d.ts.map +1 -1
  20. package/dist/client-tools.js +1 -67
  21. package/dist/client-tools.js.map +1 -1
  22. package/dist/connector-callback.d.ts +92 -0
  23. package/dist/connector-callback.d.ts.map +1 -0
  24. package/dist/connector-callback.js +155 -0
  25. package/dist/connector-callback.js.map +1 -0
  26. package/dist/connectors.d.ts +66 -0
  27. package/dist/connectors.d.ts.map +1 -0
  28. package/dist/connectors.js +71 -0
  29. package/dist/connectors.js.map +1 -0
  30. package/dist/control.js +1 -1
  31. package/dist/control.js.map +1 -1
  32. package/dist/errors.d.ts +34 -11
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js +36 -8
  35. package/dist/errors.js.map +1 -1
  36. package/dist/events.d.ts +158 -0
  37. package/dist/events.d.ts.map +1 -0
  38. package/dist/events.js +110 -0
  39. package/dist/events.js.map +1 -0
  40. package/dist/files.js +9 -9
  41. package/dist/files.js.map +1 -1
  42. package/dist/history.d.ts +38 -1
  43. package/dist/history.d.ts.map +1 -1
  44. package/dist/history.js +1 -1
  45. package/dist/history.js.map +1 -1
  46. package/dist/http.d.ts +28 -4
  47. package/dist/http.d.ts.map +1 -1
  48. package/dist/http.js +44 -24
  49. package/dist/http.js.map +1 -1
  50. package/dist/index.d.ts +26 -13
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +10 -4
  53. package/dist/index.js.map +1 -1
  54. package/dist/organization.d.ts +45 -28
  55. package/dist/organization.d.ts.map +1 -1
  56. package/dist/organization.js +67 -73
  57. package/dist/organization.js.map +1 -1
  58. package/dist/realtime.d.ts +0 -1
  59. package/dist/realtime.d.ts.map +1 -1
  60. package/dist/realtime.js +0 -1
  61. package/dist/realtime.js.map +1 -1
  62. package/dist/session-connection.d.ts +144 -0
  63. package/dist/session-connection.d.ts.map +1 -0
  64. package/dist/session-connection.js +334 -0
  65. package/dist/session-connection.js.map +1 -0
  66. package/dist/session-send.d.ts +49 -0
  67. package/dist/session-send.d.ts.map +1 -0
  68. package/dist/session-send.js +179 -0
  69. package/dist/session-send.js.map +1 -0
  70. package/dist/session.d.ts +37 -8
  71. package/dist/session.d.ts.map +1 -1
  72. package/dist/session.js +56 -29
  73. package/dist/session.js.map +1 -1
  74. package/dist/skills.d.ts +103 -0
  75. package/dist/skills.d.ts.map +1 -0
  76. package/dist/skills.js +98 -0
  77. package/dist/skills.js.map +1 -0
  78. package/dist/sse.d.ts +5 -2
  79. package/dist/sse.d.ts.map +1 -1
  80. package/dist/sse.js +7 -2
  81. package/dist/sse.js.map +1 -1
  82. package/dist/template-switch.d.ts +51 -0
  83. package/dist/template-switch.d.ts.map +1 -0
  84. package/dist/template-switch.js +81 -0
  85. package/dist/template-switch.js.map +1 -0
  86. package/dist/templates.d.ts +129 -0
  87. package/dist/templates.d.ts.map +1 -0
  88. package/dist/templates.js +92 -0
  89. package/dist/templates.js.map +1 -0
  90. package/dist/turn.d.ts +4 -0
  91. package/dist/turn.d.ts.map +1 -1
  92. package/dist/turn.js +17 -13
  93. package/dist/turn.js.map +1 -1
  94. package/dist/usage.d.ts +13 -197
  95. package/dist/usage.d.ts.map +1 -1
  96. package/dist/usage.js +5 -3
  97. package/dist/usage.js.map +1 -1
  98. package/dist/user.d.ts +10 -51
  99. package/dist/user.d.ts.map +1 -1
  100. package/dist/user.js +18 -105
  101. package/dist/user.js.map +1 -1
  102. package/examples/control-turn.mjs +9 -4
  103. package/examples/create-session.mjs +37 -24
  104. package/examples/http-connector.mjs +127 -0
  105. package/examples/lamp-backend.mjs +175 -0
  106. package/examples/prepare-realtime-connection.mjs +18 -7
  107. package/examples/read-usage.mjs +7 -25
  108. package/examples/send-message.mjs +9 -4
  109. package/examples/submit-audio.mjs +9 -4
  110. package/examples/upload-file.mjs +9 -4
  111. package/package.json +7 -13
  112. package/dist/progress.d.ts +0 -34
  113. package/dist/progress.d.ts.map +0 -1
  114. package/dist/progress.js +0 -154
  115. package/dist/progress.js.map +0 -1
  116. package/dist/schedulers.d.ts +0 -129
  117. package/dist/schedulers.d.ts.map +0 -1
  118. package/dist/schedulers.js +0 -91
  119. package/dist/schedulers.js.map +0 -1
  120. package/examples/answer-client-tool.mjs +0 -69
  121. package/examples/observe-message.mjs +0 -44
  122. package/examples/organization-session.mjs +0 -66
  123. package/examples/provision-user.mjs +0 -83
  124. package/examples/schedule-task.mjs +0 -67
@@ -0,0 +1,419 @@
1
+ import { BackendTransport, backendConnectionUrl, } from "./backend-connection.js";
2
+ import { BackendConnectionClosedError, BackendRequestError, TiDBLinkError, } from "./errors.js";
3
+ import { sleep } from "./http.js";
4
+ const DEFAULT_IDLE_CLOSE_MS = 5_000;
5
+ /** Attempts of a first attach before its caller sees the failure. */
6
+ const FIRST_ATTACH_ATTEMPTS = 3;
7
+ /** Attaches in flight across the pool; the rest wait their turn. */
8
+ const ATTACH_CONCURRENCY = 32;
9
+ const MAX_BACKOFF_MS = 30_000;
10
+ /** Spread of re-attaches after a lost connection, so that peers do not arrive at once. */
11
+ const RECOVERY_JITTER_MS = 1_000;
12
+ /** How long `close()` waits for detach answers before closing the sockets. */
13
+ const CLOSE_GRACE_MS = 2_000;
14
+ const backoff = (failures) => {
15
+ const base = Math.min(MAX_BACKOFF_MS, 250 * 2 ** Math.min(failures, 10));
16
+ return Math.round(base / 2 + (Math.random() * base) / 2);
17
+ };
18
+ /** Failures a later attempt, possibly on another connection, can fix. */
19
+ const isTransient = (error) => (error instanceof BackendConnectionClosedError && error.retryable) ||
20
+ (error instanceof BackendRequestError && error.code === -32603);
21
+ const isAttachResult = (value) => typeof value === "object" &&
22
+ value !== null &&
23
+ Number.isSafeInteger(value.generation) &&
24
+ value.generation >= 0 &&
25
+ typeof value.cursor === "string" &&
26
+ value.cursor !== "";
27
+ /**
28
+ * The Backend Connections of one OrganizationClient. Connections open on
29
+ * demand and hold up to the `maxSessions` the core announces; further
30
+ * attachments open another connection, which the load balancer may place on
31
+ * another replica. A lost connection's attachments re-attach elsewhere with
32
+ * their latest parameters; `connection.drain` moves them before the core
33
+ * closes the connection. Connections that hold nothing close after a short
34
+ * idle period.
35
+ */
36
+ export class BackendConnectionPool {
37
+ #url;
38
+ #apiKey;
39
+ #WebSocket;
40
+ #idleCloseMs;
41
+ #openTimeoutMs;
42
+ #slots = new Set();
43
+ /** Attachments the application keeps, attached or being re-attached. */
44
+ #wanted = new Map();
45
+ /** The connection currently routing each attachment. */
46
+ #where = new Map();
47
+ #opening;
48
+ #openFailures = 0;
49
+ #attaching = 0;
50
+ #attachQueue = [];
51
+ #closed = false;
52
+ constructor(options) {
53
+ this.#url = backendConnectionUrl(options.baseUrl);
54
+ this.#apiKey = options.apiKey;
55
+ this.#WebSocket = options.WebSocket;
56
+ this.#idleCloseMs = options.idleCloseMs ?? DEFAULT_IDLE_CLOSE_MS;
57
+ this.#openTimeoutMs = options.openTimeoutMs;
58
+ }
59
+ /** Open Backend Connections, for diagnostics and tests. */
60
+ get connections() {
61
+ return this.#slots.size;
62
+ }
63
+ /**
64
+ * Attach a Session and keep it attached until `detach()` or until the pool
65
+ * gives it up through `ended()`. Rejects when the first attach fails; one
66
+ * attachment per Session is allowed at a time.
67
+ */
68
+ async attach(attachment) {
69
+ if (this.#closed)
70
+ throw new TiDBLinkError("This OrganizationClient is closed");
71
+ if (this.#wanted.has(attachment.sessionId))
72
+ throw new TiDBLinkError(`Session ${attachment.sessionId} is already connected through this OrganizationClient; reuse that connection or close it first`);
73
+ this.#wanted.set(attachment.sessionId, attachment);
74
+ try {
75
+ return await this.#attach(attachment, FIRST_ATTACH_ATTEMPTS);
76
+ }
77
+ catch (error) {
78
+ if (this.#wanted.get(attachment.sessionId) === attachment)
79
+ this.#wanted.delete(attachment.sessionId);
80
+ throw error;
81
+ }
82
+ }
83
+ /** Release an attachment. Best effort: a lost connection releases it anyway. */
84
+ async detach(attachment) {
85
+ if (this.#wanted.get(attachment.sessionId) !== attachment)
86
+ return;
87
+ this.#wanted.delete(attachment.sessionId);
88
+ const slot = this.#where.get(attachment);
89
+ this.#where.delete(attachment);
90
+ if (!slot || slot.held.get(attachment.sessionId) !== attachment)
91
+ return;
92
+ this.#release(slot, attachment.sessionId);
93
+ try {
94
+ await slot.transport.request("session.detach", { sessionId: attachment.sessionId });
95
+ }
96
+ catch {
97
+ // The attachment lapses with its connection.
98
+ }
99
+ finally {
100
+ this.#maybeIdle(slot);
101
+ }
102
+ }
103
+ /**
104
+ * Send a request that any connection of the Organization may carry, such as
105
+ * `tool.result`, retrying on another connection after transient failures
106
+ * until `retryUntil` (epoch milliseconds). Only idempotent requests belong here.
107
+ */
108
+ async request(method, params, options = {}) {
109
+ const until = options.retryUntil ?? 0;
110
+ for (let failures = 0;; failures++) {
111
+ let slot;
112
+ try {
113
+ slot = await this.#anySlot();
114
+ }
115
+ catch (error) {
116
+ if (!isTransient(error) || Date.now() >= until)
117
+ throw error;
118
+ await sleep(Math.min(backoff(failures), Math.max(0, until - Date.now())));
119
+ continue;
120
+ }
121
+ this.#cancelIdle(slot);
122
+ try {
123
+ return await slot.transport.request(method, params);
124
+ }
125
+ catch (error) {
126
+ if (!isTransient(error) || Date.now() >= until)
127
+ throw error;
128
+ if (error instanceof BackendRequestError)
129
+ await sleep(Math.min(backoff(failures), Math.max(0, until - Date.now())));
130
+ }
131
+ finally {
132
+ this.#maybeIdle(slot);
133
+ }
134
+ }
135
+ }
136
+ /**
137
+ * End every attachment with reason `closed`, release them and close the
138
+ * connections. Later attaches are refused.
139
+ */
140
+ async close() {
141
+ if (this.#closed)
142
+ return;
143
+ this.#closed = true;
144
+ const attachments = [...this.#wanted.values()];
145
+ this.#wanted.clear();
146
+ const detaches = [];
147
+ for (const attachment of attachments) {
148
+ const slot = this.#where.get(attachment);
149
+ this.#where.delete(attachment);
150
+ if (slot && slot.held.get(attachment.sessionId) === attachment) {
151
+ this.#release(slot, attachment.sessionId);
152
+ detaches.push(slot.transport
153
+ .request("session.detach", { sessionId: attachment.sessionId })
154
+ .catch(() => undefined));
155
+ }
156
+ safely(() => attachment.ended({ reason: "closed" }));
157
+ }
158
+ const grace = new AbortController();
159
+ await Promise.race([
160
+ Promise.allSettled(detaches),
161
+ sleep(CLOSE_GRACE_MS, grace.signal).catch(() => undefined),
162
+ ]);
163
+ grace.abort();
164
+ for (const slot of this.#slots) {
165
+ clearTimeout(slot.idleTimer);
166
+ slot.transport.close(1000, "client closed");
167
+ }
168
+ this.#slots.clear();
169
+ }
170
+ async #attach(attachment, attempts) {
171
+ for (let failures = 0;;) {
172
+ if (this.#wanted.get(attachment.sessionId) !== attachment)
173
+ throw new TiDBLinkError("The Session connection was closed while attaching");
174
+ let slot;
175
+ try {
176
+ slot = await this.#reserveSlot();
177
+ const result = await this.#limited(() => slot.transport.request("session.attach", attachment.attachParams()));
178
+ if (!isAttachResult(result))
179
+ throw new TiDBLinkError("session.attach returned an invalid result");
180
+ if (this.#wanted.get(attachment.sessionId) !== attachment) {
181
+ // Closed while the attach was in flight: release what it took.
182
+ slot.transport
183
+ .request("session.detach", { sessionId: attachment.sessionId })
184
+ .catch(() => undefined);
185
+ throw new TiDBLinkError("The Session connection was closed while attaching");
186
+ }
187
+ slot.held.set(attachment.sessionId, attachment);
188
+ this.#where.set(attachment, slot);
189
+ attachment.attached(result, slot.transport);
190
+ return result;
191
+ }
192
+ catch (error) {
193
+ failures += 1;
194
+ if (error instanceof BackendRequestError &&
195
+ slot &&
196
+ (error.reason === "connection_full" || error.reason === "connection_draining")) {
197
+ // Try another connection at once; a core that refuses every one still ends the loop.
198
+ if (error.reason === "connection_full")
199
+ slot.full = true;
200
+ else
201
+ slot.draining = true;
202
+ if (failures >= attempts)
203
+ throw error;
204
+ if (failures > 2)
205
+ await sleep(backoff(failures));
206
+ continue;
207
+ }
208
+ if (!isTransient(error) || failures >= attempts)
209
+ throw error;
210
+ await sleep(backoff(failures));
211
+ }
212
+ finally {
213
+ if (slot) {
214
+ slot.reserved -= 1;
215
+ this.#maybeIdle(slot);
216
+ }
217
+ }
218
+ }
219
+ }
220
+ /** Re-attach after a lost or draining connection, until it works or is given up. */
221
+ async #recover(attachment, jitterMs) {
222
+ try {
223
+ if (jitterMs)
224
+ await sleep(Math.round(Math.random() * jitterMs));
225
+ await this.#attach(attachment, Number.POSITIVE_INFINITY);
226
+ }
227
+ catch (error) {
228
+ if (this.#wanted.get(attachment.sessionId) !== attachment)
229
+ return;
230
+ this.#wanted.delete(attachment.sessionId);
231
+ safely(() => attachment.ended({ reason: "error", error }));
232
+ }
233
+ }
234
+ async #limited(task) {
235
+ if (this.#attaching >= ATTACH_CONCURRENCY)
236
+ await new Promise((resolve) => this.#attachQueue.push(resolve));
237
+ this.#attaching += 1;
238
+ try {
239
+ return await task();
240
+ }
241
+ finally {
242
+ this.#attaching -= 1;
243
+ this.#attachQueue.shift()?.();
244
+ }
245
+ }
246
+ /** A connection with room for one more attachment, reserved for the caller. */
247
+ async #reserveSlot() {
248
+ for (;;) {
249
+ for (const slot of this.#slots)
250
+ if (slot.transport.open &&
251
+ !slot.draining &&
252
+ !slot.full &&
253
+ slot.held.size + slot.reserved < slot.transport.hello.maxSessions) {
254
+ // Reserve before yielding, so that concurrent attaches count each other.
255
+ slot.reserved += 1;
256
+ this.#cancelIdle(slot);
257
+ return slot;
258
+ }
259
+ await this.#openShared();
260
+ }
261
+ }
262
+ async #anySlot() {
263
+ let fallback;
264
+ for (const slot of this.#slots) {
265
+ if (!slot.transport.open)
266
+ continue;
267
+ if (!slot.draining)
268
+ return slot;
269
+ fallback ??= slot;
270
+ }
271
+ return fallback ?? (await this.#openShared());
272
+ }
273
+ /** One connection opens at a time; concurrent callers share it. */
274
+ #openShared() {
275
+ if (this.#closed)
276
+ return Promise.reject(new TiDBLinkError("This OrganizationClient is closed"));
277
+ this.#opening ??= this.#open().finally(() => {
278
+ this.#opening = undefined;
279
+ });
280
+ return this.#opening;
281
+ }
282
+ async #open() {
283
+ if (this.#openFailures)
284
+ await sleep(backoff(this.#openFailures));
285
+ let slot;
286
+ let transport;
287
+ try {
288
+ transport = await BackendTransport.open({
289
+ url: this.#url,
290
+ apiKey: this.#apiKey,
291
+ WebSocket: this.#WebSocket,
292
+ ...(this.#openTimeoutMs === undefined ? {} : { openTimeoutMs: this.#openTimeoutMs }),
293
+ onNotification: (method, params) => {
294
+ if (slot)
295
+ this.#notify(slot, method, params);
296
+ },
297
+ });
298
+ }
299
+ catch (error) {
300
+ this.#openFailures += 1;
301
+ throw error;
302
+ }
303
+ this.#openFailures = 0;
304
+ slot = {
305
+ transport,
306
+ held: new Map(),
307
+ reserved: 0,
308
+ full: false,
309
+ draining: false,
310
+ idleTimer: undefined,
311
+ };
312
+ if (this.#closed) {
313
+ transport.close(1000, "client closed");
314
+ throw new TiDBLinkError("This OrganizationClient is closed");
315
+ }
316
+ this.#slots.add(slot);
317
+ const opened = slot;
318
+ void transport.closed.then((error) => this.#lost(opened, error));
319
+ this.#maybeIdle(slot);
320
+ return slot;
321
+ }
322
+ #notify(slot, method, params) {
323
+ if (method === "connection.drain") {
324
+ const closeAfterMs = Number(params.closeAfterMs);
325
+ this.#drain(slot, Number.isFinite(closeAfterMs) ? closeAfterMs : 0);
326
+ return;
327
+ }
328
+ const sessionId = params.sessionId;
329
+ if (typeof sessionId !== "string")
330
+ return;
331
+ const attachment = slot.held.get(sessionId);
332
+ if (!attachment)
333
+ return;
334
+ if (method === "session.detached") {
335
+ this.#release(slot, sessionId);
336
+ this.#where.delete(attachment);
337
+ if (this.#wanted.get(sessionId) === attachment)
338
+ this.#wanted.delete(sessionId);
339
+ safely(() => attachment.ended({
340
+ reason: params.reason === "session_deleted" ? "session_deleted" : "superseded",
341
+ }));
342
+ this.#maybeIdle(slot);
343
+ return;
344
+ }
345
+ safely(() => attachment.notify(method, params, slot.transport));
346
+ }
347
+ /** Move every attachment to another connection, then close this one. */
348
+ #drain(slot, closeAfterMs) {
349
+ if (slot.draining && slot.held.size === 0)
350
+ return;
351
+ slot.draining = true;
352
+ const deadline = Date.now() + closeAfterMs;
353
+ const moving = [...slot.held.values()];
354
+ // Stop routing now: each re-attach resumes from what its Session processed.
355
+ slot.held.clear();
356
+ const moves = moving.map((attachment) => {
357
+ this.#where.delete(attachment);
358
+ return this.#recover(attachment, 0);
359
+ });
360
+ void (async () => {
361
+ await Promise.allSettled(moves);
362
+ // Let claims and results in flight finish, then close before the core does.
363
+ while (slot.transport.open && slot.transport.pendingRequests > 0 && Date.now() < deadline)
364
+ await sleep(50);
365
+ slot.transport.close(1000, "drained");
366
+ })();
367
+ }
368
+ #lost(slot, error) {
369
+ this.#slots.delete(slot);
370
+ clearTimeout(slot.idleTimer);
371
+ const held = [...slot.held.values()];
372
+ slot.held.clear();
373
+ for (const attachment of held) {
374
+ this.#where.delete(attachment);
375
+ if (this.#wanted.get(attachment.sessionId) !== attachment)
376
+ continue;
377
+ if (error.retryable && !this.#closed) {
378
+ void this.#recover(attachment, RECOVERY_JITTER_MS);
379
+ }
380
+ else {
381
+ this.#wanted.delete(attachment.sessionId);
382
+ safely(() => attachment.ended({ reason: "error", error }));
383
+ }
384
+ }
385
+ }
386
+ #release(slot, sessionId) {
387
+ slot.held.delete(sessionId);
388
+ slot.full = false;
389
+ }
390
+ #cancelIdle(slot) {
391
+ clearTimeout(slot.idleTimer);
392
+ slot.idleTimer = undefined;
393
+ }
394
+ #maybeIdle(slot) {
395
+ if (slot.idleTimer || !this.#slots.has(slot) || slot.held.size || slot.reserved)
396
+ return;
397
+ slot.idleTimer = setTimeout(() => {
398
+ slot.idleTimer = undefined;
399
+ if (!this.#slots.has(slot) || slot.held.size || slot.reserved)
400
+ return;
401
+ // Claims and results may still be in flight; look again later.
402
+ if (slot.transport.pendingRequests)
403
+ return this.#maybeIdle(slot);
404
+ this.#slots.delete(slot);
405
+ slot.transport.close(1000, "idle");
406
+ }, this.#idleCloseMs);
407
+ }
408
+ }
409
+ function safely(callback) {
410
+ try {
411
+ callback();
412
+ }
413
+ catch (error) {
414
+ queueMicrotask(() => {
415
+ throw error;
416
+ });
417
+ }
418
+ }
419
+ //# sourceMappingURL=backend-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-pool.js","sourceRoot":"","sources":["../src/backend-pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { BackendConnectionPool, BackendLink } from "./backend-pool.js";
2
+ import { TiDBLinkError } from "./errors.js";
3
+ import type { ClientToolHandlers } from "./session-connection.js";
4
+ /**
5
+ * Raised through `onError` when the core did not accept a Client Tool
6
+ * result. `reason` is the core's: `call_settled` (the call already had an
7
+ * outcome, for example its deadline passed), `not_claimed` or
8
+ * `call_not_found`.
9
+ */
10
+ export declare class ClientToolResultRefusedError extends TiDBLinkError {
11
+ readonly callId: string;
12
+ readonly reason: string;
13
+ constructor(callId: string, reason: string);
14
+ }
15
+ /**
16
+ * Executes the Client Tool calls an executing Session connection receives:
17
+ * claim first, run only after `claimed: true`, then submit the result over any
18
+ * Backend Connection until the call's deadline. Each callId runs at most once.
19
+ */
20
+ export declare class ClientToolExecutor {
21
+ #private;
22
+ constructor(input: {
23
+ pool: BackendConnectionPool;
24
+ sessionId: string;
25
+ handlers: ClientToolHandlers;
26
+ report: (error: unknown) => void;
27
+ });
28
+ /** Handle one `tool.call` from the connection that delivered it. */
29
+ receive(params: Record<string, unknown>, link: BackendLink): void;
30
+ }
31
+ //# sourceMappingURL=client-tool-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-tool-executor.d.ts","sourceRoot":"","sources":["../src/client-tool-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAGL,aAAa,EACd,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAkCjC;;;;;GAKG;AACH,qBAAa,4BAA6B,SAAQ,aAAa;IAE3D,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;CAI1B;AA4CD;;;;GAIG;AACH,qBAAa,kBAAkB;;gBAOjB,KAAK,EAAE;QACjB,IAAI,EAAE,qBAAqB,CAAC;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,kBAAkB,CAAC;QAC7B,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;KAClC;IAOD,oEAAoE;IACpE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI;CA6HlE"}
@@ -0,0 +1,190 @@
1
+ import { BackendConnectionClosedError, BackendRequestError, TiDBLinkError, } from "./errors.js";
2
+ const OUTPUT_MAX = 65_536;
3
+ const ERROR_MAX = 4_096;
4
+ /** How long a settled callId is remembered to ignore late duplicates. */
5
+ const SETTLED_MEMORY_MS = 60_000;
6
+ /**
7
+ * Raised through `onError` when the core did not accept a Client Tool
8
+ * result. `reason` is the core's: `call_settled` (the call already had an
9
+ * outcome, for example its deadline passed), `not_claimed` or
10
+ * `call_not_found`.
11
+ */
12
+ export class ClientToolResultRefusedError extends TiDBLinkError {
13
+ callId;
14
+ reason;
15
+ constructor(callId, reason) {
16
+ super(`The core did not accept the result of Client Tool call ${callId}: ${reason}`);
17
+ this.callId = callId;
18
+ this.reason = reason;
19
+ }
20
+ }
21
+ const isString = (value) => typeof value === "string" && value !== "";
22
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
23
+ const parseCall = (params) => isString(params.callId) &&
24
+ isString(params.sessionId) &&
25
+ isString(params.userId) &&
26
+ isString(params.turnId) &&
27
+ isString(params.name) &&
28
+ isObject(params.arguments) &&
29
+ isString(params.claimBy) &&
30
+ isString(params.deadlineAt) &&
31
+ Number.isFinite(Date.parse(params.deadlineAt))
32
+ ? params
33
+ : undefined;
34
+ const truncate = (text, max) => text.length <= max ? text : `${text.slice(0, max - 1)}…`;
35
+ /** The text the model receives for a handler's return value. */
36
+ const outputOf = (value) => {
37
+ let output;
38
+ try {
39
+ output = typeof value === "string" ? value : value === undefined ? "" : JSON.stringify(value);
40
+ }
41
+ catch (cause) {
42
+ return { error: { message: `The tool returned a value that is not JSON: ${String(cause)}` } };
43
+ }
44
+ if (output === undefined)
45
+ return { error: { message: "The tool returned a value that is not JSON" } };
46
+ if (output.length > OUTPUT_MAX)
47
+ return {
48
+ error: { message: `The tool output exceeds ${OUTPUT_MAX} characters` },
49
+ };
50
+ return { output };
51
+ };
52
+ const errorOf = (error) => {
53
+ const message = error instanceof Error ? error.message : String(error);
54
+ return { error: { message: truncate(message || "The tool failed", ERROR_MAX) } };
55
+ };
56
+ /**
57
+ * Executes the Client Tool calls an executing Session connection receives:
58
+ * claim first, run only after `claimed: true`, then submit the result over any
59
+ * Backend Connection until the call's deadline. Each callId runs at most once.
60
+ */
61
+ export class ClientToolExecutor {
62
+ #pool;
63
+ #sessionId;
64
+ #handlers;
65
+ #report;
66
+ #calls = new Map();
67
+ constructor(input) {
68
+ this.#pool = input.pool;
69
+ this.#sessionId = input.sessionId;
70
+ this.#handlers = input.handlers;
71
+ this.#report = input.report;
72
+ }
73
+ /** Handle one `tool.call` from the connection that delivered it. */
74
+ receive(params, link) {
75
+ const call = parseCall(params);
76
+ if (!call || call.sessionId !== this.#sessionId) {
77
+ this.#report(new TiDBLinkError("Received an invalid Client Tool call"));
78
+ return;
79
+ }
80
+ // The core may send a call again after a reconnect; it runs once.
81
+ if (this.#calls.has(call.callId))
82
+ return;
83
+ // Never sent: the core sends it again to the next attachment while unclaimed.
84
+ if (!link.open)
85
+ return;
86
+ this.#calls.set(call.callId, "claiming");
87
+ void this.#claimAndRun(call, link);
88
+ }
89
+ async #claimAndRun(call, link) {
90
+ let answer;
91
+ try {
92
+ answer = await link.request("tool.claim", { callId: call.callId });
93
+ }
94
+ catch (error) {
95
+ if (error instanceof BackendConnectionClosedError ||
96
+ (error instanceof BackendRequestError && error.code === -32603)) {
97
+ // The claim may have been granted; the call must not run, so close it as failed.
98
+ await this.#submit(call, {
99
+ error: {
100
+ message: "The Application Server lost the claim's answer and did not execute the call",
101
+ },
102
+ });
103
+ return;
104
+ }
105
+ this.#calls.set(call.callId, "settled");
106
+ this.#forget(call);
107
+ this.#report(error);
108
+ return;
109
+ }
110
+ if (!answer || answer.claimed !== true) {
111
+ if (answer?.reason === "superseded") {
112
+ // Another generation holds the Session; this process may receive it again there.
113
+ this.#calls.delete(call.callId);
114
+ }
115
+ else {
116
+ this.#calls.set(call.callId, "settled");
117
+ this.#forget(call);
118
+ }
119
+ return;
120
+ }
121
+ this.#calls.set(call.callId, "running");
122
+ await this.#submit(call, await this.#execute(call));
123
+ }
124
+ async #execute(call) {
125
+ const handler = Object.hasOwn(this.#handlers, call.name)
126
+ ? this.#handlers[call.name]
127
+ : undefined;
128
+ if (!handler)
129
+ return {
130
+ error: {
131
+ message: `Client Tool ${call.name} has no handler in this Application Server`,
132
+ },
133
+ };
134
+ const deadlineAt = new Date(call.deadlineAt);
135
+ const controller = new AbortController();
136
+ let timer;
137
+ const expired = new Promise((resolve) => {
138
+ timer = setTimeout(() => {
139
+ controller.abort(new TiDBLinkError("The Client Tool call reached its deadline"));
140
+ resolve({ error: { message: "The tool did not finish before its deadline" } });
141
+ }, Math.max(0, deadlineAt.getTime() - Date.now()));
142
+ });
143
+ const context = {
144
+ callId: call.callId,
145
+ sessionId: call.sessionId,
146
+ userId: call.userId,
147
+ turnId: call.turnId,
148
+ name: call.name,
149
+ deadlineAt,
150
+ signal: controller.signal,
151
+ };
152
+ const run = (async () => {
153
+ try {
154
+ return outputOf(await handler.run(call.arguments, context));
155
+ }
156
+ catch (error) {
157
+ return errorOf(error);
158
+ }
159
+ })();
160
+ try {
161
+ return await Promise.race([run, expired]);
162
+ }
163
+ finally {
164
+ clearTimeout(timer);
165
+ }
166
+ }
167
+ async #submit(call, result) {
168
+ try {
169
+ const answer = await this.#pool.request("tool.result", { callId: call.callId, ...result }, { retryUntil: Date.parse(call.deadlineAt) });
170
+ if (answer?.accepted !== true) {
171
+ if (answer?.reason === "not_claimed") {
172
+ // The lost claim never took effect: the call may arrive again and run then.
173
+ this.#calls.delete(call.callId);
174
+ return;
175
+ }
176
+ this.#report(new ClientToolResultRefusedError(call.callId, answer?.reason ?? "unknown"));
177
+ }
178
+ }
179
+ catch (error) {
180
+ this.#report(error);
181
+ }
182
+ this.#calls.set(call.callId, "settled");
183
+ this.#forget(call);
184
+ }
185
+ #forget(call) {
186
+ const timer = setTimeout(() => this.#calls.delete(call.callId), Math.max(0, Date.parse(call.deadlineAt) - Date.now()) + SETTLED_MEMORY_MS);
187
+ timer.unref?.();
188
+ }
189
+ }
190
+ //# sourceMappingURL=client-tool-executor.js.map