@pasko70/pibo 3.4.3 → 3.5.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/agent-runtime/routed-session.js +39 -12
- package/dist/agent-runtimes/codex-native/adapter.js +14 -1
- package/dist/agent-runtimes/codex-native/models.js +4 -4
- package/dist/agent-runtimes/codex-native/process.js +32 -13
- package/dist/agent-runtimes/codex-native/provider-usage.js +115 -0
- package/dist/agent-runtimes/pi/adapter.js +1 -0
- package/dist/agent-runtimes/pi/routed-session.js +4 -2
- package/dist/apps/chat/bounded-event-stream.js +98 -0
- package/dist/apps/chat/chat-settings-routes.js +3 -3
- package/dist/apps/chat/data/chat-data-mappers.js +32 -13
- package/dist/apps/chat/data/event-command-service.js +30 -21
- package/dist/apps/chat/data/history-query-service.js +34 -25
- package/dist/apps/chat/data/read-state-service.js +13 -0
- package/dist/apps/chat/data/session-query-service.js +19 -11
- package/dist/apps/chat/data/timeline-query-service.js +19 -7
- package/dist/apps/chat/message-command-dispatcher.js +134 -0
- package/dist/apps/chat/output-compactor.js +9 -0
- package/dist/apps/chat/output-event-policy.js +9 -1
- package/dist/apps/chat/stream.js +21 -3
- package/dist/apps/chat/telemetry-retention-service.js +113 -8
- package/dist/apps/chat/trace-response-cache.js +46 -0
- package/dist/apps/chat/trace-v2.js +12 -6
- package/dist/apps/chat/trace.js +1 -1
- package/dist/apps/chat/web-app.js +608 -281
- package/dist/apps/chat-ui/assets/{dist-DeMKnZR8.js → dist-BG0n7zLd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C8GzUMPk.js → dist-D6TjFhAm.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BkUu8WPA.js → dist-D79vyxSX.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-B4YhOxh0.js → dist-DFZ8cwh0.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Cyb4rVa6.js → dist-cOjokPrK.js} +1 -1
- package/dist/apps/chat-ui/assets/index-RMHUTJ62.js +229 -0
- package/dist/apps/chat-ui/assets/{index-BOceJ0jM.css → index-hEkrlRk-.css} +1 -1
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-xacbCyTx.js +44 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/compute/pool/seeds.js +25 -3
- package/dist/core/events.js +4 -0
- package/dist/core/output-render-sequence.js +2 -0
- package/dist/core/provider-capacity.js +33 -0
- package/dist/core/provider-telemetry.js +21 -6
- package/dist/core/runtime-capacity.js +174 -0
- package/dist/core/runtime-telemetry.js +40 -12
- package/dist/core/session-router.js +79 -2
- package/dist/data/async-chat-reads.js +38 -0
- package/dist/data/async-chat-storage.js +91 -0
- package/dist/data/async-telemetry-maintenance.js +9 -0
- package/dist/data/bounded-worker-client.js +256 -0
- package/dist/data/chat-read-projections.js +159 -0
- package/dist/data/chat-read-worker.js +73 -0
- package/dist/data/chat-storage-worker.js +146 -0
- package/dist/data/ingest-service.js +79 -14
- package/dist/data/message-command-store.js +148 -0
- package/dist/data/payload-store.js +92 -11
- package/dist/data/pibo-store.js +10 -8
- package/dist/data/schema.js +16 -2
- package/dist/data/session-store.js +3 -1
- package/dist/data/storage-backup.js +278 -0
- package/dist/data/telemetry-capture.js +188 -0
- package/dist/data/telemetry-command.js +3 -0
- package/dist/data/telemetry-maintenance-worker.js +40 -0
- package/dist/data/telemetry-maintenance.js +110 -0
- package/dist/data/telemetry-retention.js +16 -7
- package/dist/data/telemetry-worker.js +111 -0
- package/dist/data/telemetry-writer.js +150 -83
- package/dist/data/telemetry.js +5 -0
- package/dist/debug/index.js +52 -0
- package/dist/debug/storage-backup.js +33 -0
- package/dist/debug/telemetry-capture.js +66 -0
- package/dist/gateway/cli.js +104 -16
- package/dist/gateway/server.js +2 -0
- package/dist/providers/openai-gpt56.js +11 -6
- package/dist/session-ui/terminalRows.js +55 -13
- package/dist/sessions/pibo-data-store.js +30 -10
- package/dist/shared/debug-features.js +4 -0
- package/dist/shared/model-inference-metrics.js +23 -0
- package/dist/shared/trace-event-projection.js +59 -2
- package/dist/shared/trace-history.js +9 -0
- package/dist/shared/trace-live-reducer.js +1 -0
- package/dist/shared/trace-patch-nodes.js +19 -0
- package/dist/web/channel.js +8 -2
- package/dist/web/http.js +36 -3
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-Dk4mbXAB.js +0 -228
- package/dist/apps/chat-vscode-web/assets/index-0oTGFHni.js +0 -43
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#101d22" />
|
|
7
7
|
<title>Pibo</title>
|
|
8
|
-
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-xacbCyTx.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/apps/chat-vscode/assets/index-b18ZkEo0.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
@@ -68,7 +68,7 @@ export async function prepareDeploymentSeed(input) {
|
|
|
68
68
|
await copySeedNonDatabaseFiles(input.config.seedSourceHome, homePath, input.mode, input.config.root);
|
|
69
69
|
const copiedDatabases = await backupSeedDatabases(input.config.seedSourceHome, homePath, input.mode);
|
|
70
70
|
if (input.config.seedSourcePiHome && existsSync(input.config.seedSourcePiHome)) {
|
|
71
|
-
await
|
|
71
|
+
await copyPiRuntimeSeed(input.config.seedSourcePiHome, piHomePath);
|
|
72
72
|
}
|
|
73
73
|
if (input.mode === "full" && input.config.seedSourceWorkspace && existsSync(input.config.seedSourceWorkspace)) {
|
|
74
74
|
await cp(input.config.seedSourceWorkspace, workspacePath, { recursive: true, force: true, preserveTimestamps: true });
|
|
@@ -160,11 +160,33 @@ async function backupSeedDatabases(sourceHome, destinationHome, mode) {
|
|
|
160
160
|
}
|
|
161
161
|
return copied.sort();
|
|
162
162
|
}
|
|
163
|
-
async function
|
|
163
|
+
async function copyPiRuntimeSeed(sourcePiHome, destinationPiHome) {
|
|
164
164
|
const sourceAgent = resolve(sourcePiHome, "agent");
|
|
165
165
|
const destinationAgent = resolve(destinationPiHome, "agent");
|
|
166
166
|
await mkdir(destinationAgent, { recursive: true, mode: 0o700 });
|
|
167
|
-
|
|
167
|
+
// OAuth refresh tokens belong to one credential store. Cloning them into isolated
|
|
168
|
+
// slots makes token rotation race with the source login and other slots.
|
|
169
|
+
const authPath = resolve(sourceAgent, "auth.json");
|
|
170
|
+
if (existsSync(authPath)) {
|
|
171
|
+
let parsed;
|
|
172
|
+
try {
|
|
173
|
+
parsed = JSON.parse(await readFile(authPath, "utf8"));
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
throw new Error("Cannot read the Pi credential seed.");
|
|
177
|
+
}
|
|
178
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
179
|
+
throw new Error("Invalid Pi credential seed.");
|
|
180
|
+
const apiKeys = Object.fromEntries(Object.entries(parsed).flatMap(([provider, value]) => {
|
|
181
|
+
if (!value || typeof value !== "object" || value.type !== "api_key" || typeof value.key !== "string")
|
|
182
|
+
return [];
|
|
183
|
+
return [[provider, { type: "api_key", key: value.key }]];
|
|
184
|
+
}));
|
|
185
|
+
if (Object.keys(apiKeys).length) {
|
|
186
|
+
await writeFile(resolve(destinationAgent, "auth.json"), `${JSON.stringify(apiKeys)}\n`, { mode: 0o600 });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
for (const name of ["models-store.json"]) {
|
|
168
190
|
const source = resolve(sourceAgent, name);
|
|
169
191
|
if (!existsSync(source))
|
|
170
192
|
continue;
|
package/dist/core/events.js
CHANGED
|
@@ -4,3 +4,7 @@ export class PiboSteeringUnavailableError extends Error {
|
|
|
4
4
|
this.name = "PiboSteeringUnavailableError";
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
+
/** Only queue-clear actions can carry an already-completed ingress count. */
|
|
8
|
+
export function previouslyClearedMessages(event) {
|
|
9
|
+
return event.action === "clear_queue" && Number.isSafeInteger(event.clearedBeforeRuntime) && event.clearedBeforeRuntime > 0 ? event.clearedBeforeRuntime : 0;
|
|
10
|
+
}
|
|
@@ -383,6 +383,7 @@ function validOutputPartIndex(value) {
|
|
|
383
383
|
export function outputIdentityFingerprint(event) {
|
|
384
384
|
const payload = { ...event };
|
|
385
385
|
delete payload.renderSequence;
|
|
386
|
+
delete payload.compactionStats;
|
|
386
387
|
return createHash("sha256").update(stableJson(payload)).digest("hex");
|
|
387
388
|
}
|
|
388
389
|
export function outputPartFingerprint(event) {
|
|
@@ -393,6 +394,7 @@ export function outputPartFingerprint(event) {
|
|
|
393
394
|
delete payload.usageIndex;
|
|
394
395
|
delete payload.compactionIndex;
|
|
395
396
|
delete payload.contentIndex;
|
|
397
|
+
delete payload.compactionStats;
|
|
396
398
|
return createHash("sha256").update(stableJson(payload)).digest("hex");
|
|
397
399
|
}
|
|
398
400
|
function stableJson(value) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Pi's request boundary releases before tool work, so parents cannot pin slots while awaiting children. */
|
|
2
|
+
export function createProviderCapacityExtension(capacity, room, nested = false) {
|
|
3
|
+
return pi => {
|
|
4
|
+
let lease;
|
|
5
|
+
let removeAbort;
|
|
6
|
+
const release = () => { removeAbort?.(); removeAbort = undefined; lease?.release(); lease = undefined; };
|
|
7
|
+
pi.on("before_provider_request", async (_event, ctx) => {
|
|
8
|
+
// Retries replace a previous failed HTTP request, never overlap its reservation.
|
|
9
|
+
release();
|
|
10
|
+
const signal = ctx.signal;
|
|
11
|
+
try {
|
|
12
|
+
lease = await capacity.acquireProvider(ctx.model?.provider ?? "pi-unknown", room, signal, nested);
|
|
13
|
+
if (signal?.aborted) {
|
|
14
|
+
release();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
signal?.addEventListener("abort", release, { once: true });
|
|
18
|
+
removeAbort = () => signal?.removeEventListener("abort", release);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
// Extension errors are observational in Pi. Abort explicitly so a rejected wait cannot send anyway.
|
|
22
|
+
ctx.abort();
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
pi.on("after_provider_response", event => { if (event.status >= 400)
|
|
27
|
+
release(); });
|
|
28
|
+
pi.on("message_end", event => { if (event.message.role === "assistant")
|
|
29
|
+
release(); });
|
|
30
|
+
pi.on("agent_end", release);
|
|
31
|
+
pi.on("session_shutdown", release);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -11,7 +11,8 @@ export class PiboProviderTelemetryRecorder {
|
|
|
11
11
|
}
|
|
12
12
|
recordRequestStart(payload, options = {}) {
|
|
13
13
|
const capturedOptions = { ...options, at: options.at ?? new Date().toISOString() };
|
|
14
|
-
|
|
14
|
+
const captured = providerPayloadSnapshot(payload);
|
|
15
|
+
return this.schedule({ kind: "start", payload: captured, options: capturedOptions }, () => this.recordRequestStartNow(captured, capturedOptions));
|
|
15
16
|
}
|
|
16
17
|
recordRequestStartNow(payload, options) {
|
|
17
18
|
if (!this.options.store)
|
|
@@ -79,7 +80,7 @@ export class PiboProviderTelemetryRecorder {
|
|
|
79
80
|
}
|
|
80
81
|
recordResponse(input) {
|
|
81
82
|
const captured = { status: input.status, at: input.at ?? new Date().toISOString() };
|
|
82
|
-
return this.schedule(() => this.recordResponseNow(captured));
|
|
83
|
+
return this.schedule({ kind: "response", input: captured }, () => this.recordResponseNow(captured));
|
|
83
84
|
}
|
|
84
85
|
recordResponseNow(input) {
|
|
85
86
|
if (!this.options.store)
|
|
@@ -141,7 +142,7 @@ export class PiboProviderTelemetryRecorder {
|
|
|
141
142
|
return undefined;
|
|
142
143
|
const captured = providerAssistantMessageSnapshot(message);
|
|
143
144
|
const capturedOptions = { ...options, at: options.at ?? new Date().toISOString() };
|
|
144
|
-
return this.schedule(() => this.recordMessageEndNow(captured, capturedOptions));
|
|
145
|
+
return this.schedule({ kind: "end", message: captured, options: capturedOptions }, () => this.recordMessageEndNow(captured, capturedOptions));
|
|
145
146
|
}
|
|
146
147
|
recordMessageEndNow(message, options) {
|
|
147
148
|
if (!this.options.store)
|
|
@@ -159,11 +160,25 @@ export class PiboProviderTelemetryRecorder {
|
|
|
159
160
|
return this.finishActiveProviderRequest(status, options.at ?? new Date().toISOString(), summary, errorMessage, errorDetails?.category ?? errorDetails?.errorClass);
|
|
160
161
|
}
|
|
161
162
|
recordShutdown(reason, at = new Date().toISOString()) {
|
|
162
|
-
return this.schedule(() => this.finishActiveProviderRequest("aborted", at, reason, undefined, "runtime_abort"));
|
|
163
|
+
return this.schedule({ kind: "shutdown", at, reason }, () => this.finishActiveProviderRequest("aborted", at, reason, undefined, "runtime_abort"));
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
+
executeTelemetryCommand(command) {
|
|
166
|
+
switch (command.kind) {
|
|
167
|
+
case "start":
|
|
168
|
+
this.recordRequestStartNow(command.payload, command.options);
|
|
169
|
+
break;
|
|
170
|
+
case "response":
|
|
171
|
+
this.recordResponseNow(command.input);
|
|
172
|
+
break;
|
|
173
|
+
case "end":
|
|
174
|
+
this.recordMessageEndNow(command.message, command.options);
|
|
175
|
+
break;
|
|
176
|
+
case "shutdown": this.finishActiveProviderRequest("aborted", command.at, command.reason, undefined, "runtime_abort");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
schedule(command, write) {
|
|
165
180
|
if (this.options.writer) {
|
|
166
|
-
this.options.writer.
|
|
181
|
+
this.options.writer.record({ recorder: "provider", command, session: { ...this.options.session, metadata: { chatRoomId: this.options.session.metadata?.chatRoomId ?? null, rootSessionId: this.options.session.metadata?.rootSessionId ?? null } }, model: this.options.model }, write, this.options.onError);
|
|
167
182
|
return undefined;
|
|
168
183
|
}
|
|
169
184
|
return write();
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export function resolveRuntimeCapacityOptions(env = process.env) {
|
|
2
|
+
const read = (name, fallback) => {
|
|
3
|
+
if (!env[name]?.trim())
|
|
4
|
+
return fallback;
|
|
5
|
+
const n = Number(env[name]);
|
|
6
|
+
if (!Number.isSafeInteger(n) || n < 1)
|
|
7
|
+
throw new Error(`${name} must be a positive integer.`);
|
|
8
|
+
return n;
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
coldStarts: read("PIBO_GATEWAY_MAX_COLD_STARTS", 2), providerTurns: read("PIBO_GATEWAY_MAX_PROVIDER_TURNS", 10),
|
|
12
|
+
providerTurnsPerRoom: read("PIBO_GATEWAY_MAX_PROVIDER_TURNS_PER_ROOM", 5), maxWaiting: read("PIBO_GATEWAY_MAX_RUNTIME_WAITERS", 64),
|
|
13
|
+
maxWaitMs: read("PIBO_GATEWAY_MAX_RUNTIME_WAIT_MS", 60_000), maxRuntimes: read("PIBO_GATEWAY_MAX_ACTIVE_RUNTIMES", 32),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Bounded room round-robin. Cancellation removes a waiter without consuming a slot. */
|
|
17
|
+
export class FairCapacityPool {
|
|
18
|
+
limit;
|
|
19
|
+
perRoom;
|
|
20
|
+
maxWaiting;
|
|
21
|
+
maxWaitMs;
|
|
22
|
+
reserved;
|
|
23
|
+
rooms = new Map();
|
|
24
|
+
activeRooms = new Map();
|
|
25
|
+
active = 0;
|
|
26
|
+
generalActive = 0;
|
|
27
|
+
generalRooms = new Map();
|
|
28
|
+
waiting = 0;
|
|
29
|
+
closed = false;
|
|
30
|
+
constructor(limit, perRoom, maxWaiting, maxWaitMs, reserved = 0) {
|
|
31
|
+
this.limit = limit;
|
|
32
|
+
this.perRoom = perRoom;
|
|
33
|
+
this.maxWaiting = maxWaiting;
|
|
34
|
+
this.maxWaitMs = maxWaitMs;
|
|
35
|
+
this.reserved = reserved;
|
|
36
|
+
if (!Number.isSafeInteger(reserved) || reserved < 0 || reserved >= limit)
|
|
37
|
+
throw new Error("Reserved capacity must leave at least one normal slot.");
|
|
38
|
+
for (const n of [limit, perRoom, maxWaiting, maxWaitMs])
|
|
39
|
+
if (!Number.isSafeInteger(n) || n < 1)
|
|
40
|
+
throw new Error("Capacity limits must be positive integers.");
|
|
41
|
+
}
|
|
42
|
+
acquire(room, signal, reserved = false) {
|
|
43
|
+
if (this.closed)
|
|
44
|
+
return Promise.reject(capacityError("Runtime capacity is closed."));
|
|
45
|
+
if (signal?.aborted)
|
|
46
|
+
return Promise.reject(signal.reason ?? capacityError("Capacity wait cancelled."));
|
|
47
|
+
if (this.waiting >= this.maxWaiting - (reserved ? 0 : Math.min(this.reserved, this.maxWaiting - 1)))
|
|
48
|
+
return Promise.reject(capacityError("Runtime capacity wait queue is full."));
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
let timer;
|
|
51
|
+
const cancel = () => {
|
|
52
|
+
const queue = this.rooms.get(room);
|
|
53
|
+
const index = queue?.indexOf(waiter) ?? -1;
|
|
54
|
+
if (index < 0)
|
|
55
|
+
return;
|
|
56
|
+
queue.splice(index, 1);
|
|
57
|
+
this.waiting--;
|
|
58
|
+
if (!queue.length)
|
|
59
|
+
this.rooms.delete(room);
|
|
60
|
+
waiter.cleanup();
|
|
61
|
+
reject(signal?.aborted ? signal.reason : capacityError("Runtime capacity wait deadline exceeded."));
|
|
62
|
+
this.drain();
|
|
63
|
+
};
|
|
64
|
+
const waiter = { room, reserved, queuedAt: Date.now(), resolve, reject, cleanup: () => { clearTimeout(timer); signal?.removeEventListener("abort", cancel); } };
|
|
65
|
+
const queue = this.rooms.get(room) ?? [];
|
|
66
|
+
queue.push(waiter);
|
|
67
|
+
this.rooms.set(room, queue);
|
|
68
|
+
this.waiting++;
|
|
69
|
+
timer = setTimeout(cancel, this.maxWaitMs);
|
|
70
|
+
timer.unref?.();
|
|
71
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
72
|
+
this.drain();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
snapshot() {
|
|
76
|
+
let oldest = 0;
|
|
77
|
+
for (const queue of this.rooms.values())
|
|
78
|
+
oldest = Math.max(oldest, Date.now() - queue[0].queuedAt);
|
|
79
|
+
return { active: this.active, waiting: this.waiting, limit: this.limit, perRoom: this.perRoom, reserved: this.reserved, maxWaiting: this.maxWaiting, maxWaitMs: this.maxWaitMs, oldestWaitMs: oldest };
|
|
80
|
+
}
|
|
81
|
+
close() {
|
|
82
|
+
this.closed = true;
|
|
83
|
+
for (const queue of this.rooms.values())
|
|
84
|
+
for (const waiter of queue) {
|
|
85
|
+
waiter.cleanup();
|
|
86
|
+
waiter.reject(capacityError("Runtime capacity is closed."));
|
|
87
|
+
}
|
|
88
|
+
this.rooms.clear();
|
|
89
|
+
this.waiting = 0;
|
|
90
|
+
}
|
|
91
|
+
drain() {
|
|
92
|
+
while (!this.closed && this.active < this.limit) {
|
|
93
|
+
const eligible = (waiter) => (this.activeRooms.get(waiter.room) ?? 0) < this.perRoom && (waiter.reserved ||
|
|
94
|
+
(this.generalActive < this.limit - this.reserved && (this.generalRooms.get(waiter.room) ?? 0) < this.perRoom - Math.min(this.reserved, 1, this.perRoom - 1)));
|
|
95
|
+
const entry = [...this.rooms].find(([, queue]) => queue.some(eligible));
|
|
96
|
+
if (!entry)
|
|
97
|
+
return;
|
|
98
|
+
const [room, queue] = entry;
|
|
99
|
+
const [waiter] = queue.splice(queue.findIndex(eligible), 1);
|
|
100
|
+
this.rooms.delete(room);
|
|
101
|
+
if (queue.length)
|
|
102
|
+
this.rooms.set(room, queue);
|
|
103
|
+
if (!waiter.reserved) {
|
|
104
|
+
this.generalActive++;
|
|
105
|
+
this.generalRooms.set(room, (this.generalRooms.get(room) ?? 0) + 1);
|
|
106
|
+
}
|
|
107
|
+
this.waiting--;
|
|
108
|
+
this.active++;
|
|
109
|
+
this.activeRooms.set(room, (this.activeRooms.get(room) ?? 0) + 1);
|
|
110
|
+
waiter.cleanup();
|
|
111
|
+
let released = false;
|
|
112
|
+
waiter.resolve({ release: () => {
|
|
113
|
+
if (released)
|
|
114
|
+
return;
|
|
115
|
+
released = true;
|
|
116
|
+
this.active--;
|
|
117
|
+
if (!waiter.reserved) {
|
|
118
|
+
this.generalActive--;
|
|
119
|
+
const general = this.generalRooms.get(room) - 1;
|
|
120
|
+
if (general)
|
|
121
|
+
this.generalRooms.set(room, general);
|
|
122
|
+
else
|
|
123
|
+
this.generalRooms.delete(room);
|
|
124
|
+
}
|
|
125
|
+
const count = this.activeRooms.get(room) - 1;
|
|
126
|
+
if (count)
|
|
127
|
+
this.activeRooms.set(room, count);
|
|
128
|
+
else
|
|
129
|
+
this.activeRooms.delete(room);
|
|
130
|
+
this.drain();
|
|
131
|
+
} });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export class RuntimeCapacity {
|
|
136
|
+
starts;
|
|
137
|
+
maxRuntimes;
|
|
138
|
+
providers = new Map();
|
|
139
|
+
closed = false;
|
|
140
|
+
options;
|
|
141
|
+
constructor(options = {}) {
|
|
142
|
+
this.options = { ...resolveRuntimeCapacityOptions(), ...options };
|
|
143
|
+
for (const n of Object.values(this.options))
|
|
144
|
+
if (!Number.isSafeInteger(n) || n < 1)
|
|
145
|
+
throw new Error("Runtime capacity limits must be positive integers.");
|
|
146
|
+
this.maxRuntimes = this.options.maxRuntimes;
|
|
147
|
+
this.starts = new FairCapacityPool(this.options.coldStarts, 1, this.options.maxWaiting, this.options.maxWaitMs);
|
|
148
|
+
}
|
|
149
|
+
async acquireProvider(provider, room, signal, nested = false) {
|
|
150
|
+
if (this.closed)
|
|
151
|
+
throw capacityError("Runtime capacity is closed.");
|
|
152
|
+
let pool = this.providers.get(provider);
|
|
153
|
+
if (!pool) {
|
|
154
|
+
if (this.providers.size >= 64)
|
|
155
|
+
throw capacityError("Active provider capacity registry is full.");
|
|
156
|
+
pool = new FairCapacityPool(this.options.providerTurns, this.options.providerTurnsPerRoom, this.options.maxWaiting, this.options.maxWaitMs, Math.min(2, this.options.providerTurns - 1));
|
|
157
|
+
this.providers.set(provider, pool);
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const lease = await pool.acquire(room, signal, nested);
|
|
161
|
+
return { release: () => { lease.release(); this.removeIdleProvider(provider, pool); } };
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
this.removeIdleProvider(provider, pool);
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
snapshot() { return { coldStarts: this.starts.snapshot(), maxRuntimes: this.maxRuntimes, providers: [...this.providers].map(([provider, pool]) => ({ provider, ...pool.snapshot() })) }; }
|
|
169
|
+
close() { this.closed = true; this.starts.close(); for (const pool of this.providers.values())
|
|
170
|
+
pool.close(); this.providers.clear(); }
|
|
171
|
+
removeIdleProvider(provider, pool) { const state = pool.snapshot(); if (!state.active && !state.waiting && this.providers.get(provider) === pool)
|
|
172
|
+
this.providers.delete(provider); }
|
|
173
|
+
}
|
|
174
|
+
function capacityError(message) { return Object.assign(new Error(message), { code: "runtime_capacity_unavailable" }); }
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { BestEffortTelemetryService, } from "../data/telemetry.js";
|
|
2
2
|
import { isTerminalProviderStatus } from "./provider-telemetry.js";
|
|
3
|
+
/** Diagnostic cache only: terminal events clear their keys; the cap also contains orphaned/incomplete histories. */
|
|
4
|
+
class TelemetryProgressMap extends Map {
|
|
5
|
+
set(key, value) {
|
|
6
|
+
if (!this.has(key) && this.size >= 1024)
|
|
7
|
+
this.delete(this.keys().next().value);
|
|
8
|
+
return super.set(key, value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
3
11
|
const TERMINAL_TURN_STATUSES = new Set(["ok", "error", "aborted", "timeout"]);
|
|
4
12
|
const DEFAULT_PROGRESS_FLUSH_INTERVAL_MS = 1_000;
|
|
5
13
|
export class PiboRuntimeTelemetryRecorder {
|
|
@@ -9,10 +17,11 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
9
17
|
providerEventMode;
|
|
10
18
|
progressFlushIntervalMs;
|
|
11
19
|
writer;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
phaseSequences = new TelemetryProgressMap();
|
|
21
|
+
pendingProviderProgress = new TelemetryProgressMap();
|
|
22
|
+
providerRequestCache = new TelemetryProgressMap();
|
|
23
|
+
lastProviderFlushAtMs = new TelemetryProgressMap();
|
|
24
|
+
lastProgressWriteAtMs = new TelemetryProgressMap();
|
|
16
25
|
constructor(store, onError, options = {}) {
|
|
17
26
|
this.store = store;
|
|
18
27
|
this.onError = onError;
|
|
@@ -29,7 +38,7 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
29
38
|
return;
|
|
30
39
|
const captured = captureTelemetryContext(context);
|
|
31
40
|
const capturedEvent = telemetryOutputEventSnapshot(event);
|
|
32
|
-
this.schedule(() => this.recordOutputUnsafe(capturedEvent, captured));
|
|
41
|
+
this.schedule({ kind: "output", event: capturedEvent, context: captured }, () => this.recordOutputUnsafe(capturedEvent, captured));
|
|
33
42
|
}
|
|
34
43
|
recordPiEvent(piboSessionId, event, context = {}) {
|
|
35
44
|
if (!this.store)
|
|
@@ -38,20 +47,29 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
38
47
|
if (!summary)
|
|
39
48
|
return;
|
|
40
49
|
const captured = captureTelemetryContext(context);
|
|
41
|
-
this.schedule(() => this.recordPiEventSummaryUnsafe(piboSessionId, summary, captured));
|
|
50
|
+
this.schedule({ kind: "pi", piboSessionId, summary, context: captured }, () => this.recordPiEventSummaryUnsafe(piboSessionId, summary, captured));
|
|
42
51
|
}
|
|
43
52
|
recordMessagesInterrupted(messages, context = {}, reason = "message interrupted") {
|
|
44
53
|
if (!this.store)
|
|
45
54
|
return;
|
|
46
55
|
const captured = captureTelemetryContext(context);
|
|
47
56
|
const interrupted = messages.flatMap((message) => message.id ? [{ piboSessionId: message.piboSessionId, eventId: message.id }] : []);
|
|
48
|
-
this.schedule(() => {
|
|
57
|
+
this.schedule({ kind: "interrupted", messages: interrupted, context: captured, reason }, () => {
|
|
49
58
|
for (const message of interrupted) {
|
|
50
59
|
this.recordTurnTerminal(message, captured, "aborted", "abort", reason, "runtime_abort");
|
|
51
60
|
}
|
|
52
61
|
});
|
|
53
62
|
}
|
|
54
|
-
|
|
63
|
+
executeTelemetryCommand(command) {
|
|
64
|
+
if (command.kind === "output")
|
|
65
|
+
this.recordOutputUnsafe(command.event, command.context);
|
|
66
|
+
else if (command.kind === "pi")
|
|
67
|
+
this.recordPiEventSummaryUnsafe(command.piboSessionId, command.summary, command.context);
|
|
68
|
+
else
|
|
69
|
+
for (const message of command.messages)
|
|
70
|
+
this.recordTurnTerminal(message, command.context, "aborted", "abort", command.reason, "runtime_abort");
|
|
71
|
+
}
|
|
72
|
+
schedule(command, write) {
|
|
55
73
|
const guarded = () => {
|
|
56
74
|
try {
|
|
57
75
|
write();
|
|
@@ -61,7 +79,7 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
61
79
|
}
|
|
62
80
|
};
|
|
63
81
|
if (this.writer)
|
|
64
|
-
this.writer.
|
|
82
|
+
this.writer.record({ recorder: "runtime", command, providerEventMode: this.providerEventMode, progressFlushIntervalMs: this.progressFlushIntervalMs }, guarded, this.onError);
|
|
65
83
|
else
|
|
66
84
|
guarded();
|
|
67
85
|
}
|
|
@@ -581,6 +599,10 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
581
599
|
counters: options.counters,
|
|
582
600
|
summary,
|
|
583
601
|
});
|
|
602
|
+
if (phase && !existing) {
|
|
603
|
+
const key = phaseId(turn.turnId, phaseName);
|
|
604
|
+
this.phaseSequences.set(key, (this.phaseSequences.get(key) ?? 0) + 1);
|
|
605
|
+
}
|
|
584
606
|
if (options.updateTurn) {
|
|
585
607
|
this.telemetry.upsertTurn({
|
|
586
608
|
turnId: turn.turnId,
|
|
@@ -602,7 +624,8 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
602
624
|
}
|
|
603
625
|
nextPhaseId(turnId, phaseName) {
|
|
604
626
|
const base = phaseId(turnId, phaseName);
|
|
605
|
-
const count = this.store?.countPhasesForTurn(turnId, phaseName) ?? 0;
|
|
627
|
+
const count = this.phaseSequences.get(base) ?? this.store?.countPhasesForTurn(turnId, phaseName) ?? 0;
|
|
628
|
+
this.phaseSequences.set(base, count);
|
|
606
629
|
if (count === 0)
|
|
607
630
|
return base;
|
|
608
631
|
return `${base}:${count + 1}`;
|
|
@@ -718,6 +741,9 @@ export class PiboRuntimeTelemetryRecorder {
|
|
|
718
741
|
this.lastProviderFlushAtMs.delete(turnId);
|
|
719
742
|
}
|
|
720
743
|
clearTurnProgress(turnId) {
|
|
744
|
+
for (const key of this.phaseSequences.keys())
|
|
745
|
+
if (key.startsWith(`${turnId}:`))
|
|
746
|
+
this.phaseSequences.delete(key);
|
|
721
747
|
this.clearProviderProgress(turnId);
|
|
722
748
|
const prefix = `${turnId}:`;
|
|
723
749
|
for (const key of this.lastProgressWriteAtMs.keys()) {
|
|
@@ -1069,6 +1095,8 @@ function telemetryOutputEventSnapshot(event) {
|
|
|
1069
1095
|
return { ...event, result: event.isError ? safeErrorMessage(event.result) : undefined };
|
|
1070
1096
|
if (event.type === "execution_result")
|
|
1071
1097
|
return { ...event, result: undefined };
|
|
1098
|
+
if (event.type === "assistant_delta" || event.type === "thinking_delta" || event.type === "assistant_message" || event.type === "message_queued" || event.type === "message_started")
|
|
1099
|
+
return { ...event, text: "" };
|
|
1072
1100
|
return { ...event };
|
|
1073
1101
|
}
|
|
1074
1102
|
function captureTelemetryContext(context) {
|
|
@@ -1076,8 +1104,8 @@ function captureTelemetryContext(context) {
|
|
|
1076
1104
|
const atMs = context.atMs ?? (Number.isFinite(parsedAtMs) ? parsedAtMs : Date.now());
|
|
1077
1105
|
return {
|
|
1078
1106
|
...context,
|
|
1079
|
-
session: context.session ? { ...context.session, metadata: context.session.metadata ? {
|
|
1080
|
-
status: context.status ? { ...context.status, activeTools: [
|
|
1107
|
+
session: context.session ? { ...context.session, metadata: context.session.metadata ? { chatRoomId: context.session.metadata.chatRoomId, rootSessionId: context.session.metadata.rootSessionId } : undefined } : undefined,
|
|
1108
|
+
status: context.status ? { ...context.status, activeTools: [], enabledTools: [] } : undefined,
|
|
1081
1109
|
at: context.at ?? new Date(atMs).toISOString(),
|
|
1082
1110
|
atMs,
|
|
1083
1111
|
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { previouslyClearedMessages } from "./events.js";
|
|
2
|
+
import { createProviderCapacityExtension } from "./provider-capacity.js";
|
|
3
|
+
import { RuntimeCapacity } from "./runtime-capacity.js";
|
|
1
4
|
import { randomUUID } from "node:crypto";
|
|
2
5
|
import { isDeepStrictEqual } from "node:util";
|
|
3
6
|
import { InitialSessionContext, } from "./profiles.js";
|
|
@@ -333,6 +336,10 @@ function providerEventTelemetryModeFromEnv(env = process.env) {
|
|
|
333
336
|
export class PiboSessionRouter {
|
|
334
337
|
options;
|
|
335
338
|
sessions = new Map();
|
|
339
|
+
capacity;
|
|
340
|
+
creatingRuntimes = 0;
|
|
341
|
+
initializationTimings = [];
|
|
342
|
+
pendingStartAborts = new Map();
|
|
336
343
|
pendingSessions = new Map();
|
|
337
344
|
listeners = new Set();
|
|
338
345
|
outputRenderSequencer;
|
|
@@ -378,6 +385,7 @@ export class PiboSessionRouter {
|
|
|
378
385
|
closing = false;
|
|
379
386
|
constructor(options = {}) {
|
|
380
387
|
this.options = options;
|
|
388
|
+
this.capacity = new RuntimeCapacity(options.runtimeCapacity);
|
|
381
389
|
this.pluginRegistry = options.pluginRegistry ?? createDefaultPiboPluginRegistry();
|
|
382
390
|
// Historical custom registries supplied only actions/profiles while runtime creation was implicit.
|
|
383
391
|
// Preserve that composition contract during the adapter migration without branching on adapter ids.
|
|
@@ -450,6 +458,16 @@ export class PiboSessionRouter {
|
|
|
450
458
|
async emit(event) {
|
|
451
459
|
if (this.closing)
|
|
452
460
|
throw new Error("Pibo session router is disposed.");
|
|
461
|
+
if (event.type === "execution" && !this.sessions.has(event.piboSessionId) && (event.action === "abort" || event.action === "clear_queue")) {
|
|
462
|
+
this.resolvePiboSession(event.piboSessionId);
|
|
463
|
+
if (event.action === "abort") {
|
|
464
|
+
this.invalidateRunReminders([event.piboSessionId]);
|
|
465
|
+
this.pendingStartAborts.get(event.piboSessionId)?.abort(Object.assign(new Error("Runtime start aborted before message dispatch."), { code: "runtime_start_cancelled" }));
|
|
466
|
+
}
|
|
467
|
+
const output = { type: "execution_result", piboSessionId: event.piboSessionId, eventId: event.id, action: event.action, result: event.action === "abort" ? { aborted: true } : { cleared: previouslyClearedMessages(event) } };
|
|
468
|
+
this.emitOutput(output);
|
|
469
|
+
return output;
|
|
470
|
+
}
|
|
453
471
|
let messageSignalAccepted = false;
|
|
454
472
|
const acceptMessageSignal = () => {
|
|
455
473
|
if (event.type !== "message" || !event.id || messageSignalAccepted)
|
|
@@ -1126,6 +1144,7 @@ export class PiboSessionRouter {
|
|
|
1126
1144
|
if (this.disposePromise)
|
|
1127
1145
|
return this.disposePromise;
|
|
1128
1146
|
this.closing = true;
|
|
1147
|
+
this.capacity.close();
|
|
1129
1148
|
this.disposePromise = this.disposeAllUnsafe();
|
|
1130
1149
|
return this.disposePromise;
|
|
1131
1150
|
}
|
|
@@ -1245,16 +1264,65 @@ export class PiboSessionRouter {
|
|
|
1245
1264
|
const pending = this.pendingSessions.get(piboSessionId);
|
|
1246
1265
|
if (pending)
|
|
1247
1266
|
return pending;
|
|
1248
|
-
const
|
|
1267
|
+
const startAbort = new AbortController();
|
|
1268
|
+
this.pendingStartAborts.set(piboSessionId, startAbort);
|
|
1269
|
+
const created = this.createRoutedSessionWithinCapacity(piboSessionId, startAbort.signal);
|
|
1249
1270
|
this.pendingSessions.set(piboSessionId, created);
|
|
1250
1271
|
try {
|
|
1251
1272
|
return await created;
|
|
1252
1273
|
}
|
|
1253
1274
|
finally {
|
|
1254
1275
|
this.pendingSessions.delete(piboSessionId);
|
|
1276
|
+
if (this.pendingStartAborts.get(piboSessionId) === startAbort)
|
|
1277
|
+
this.pendingStartAborts.delete(piboSessionId);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
getRuntimeCapacityStatus() { return { ...this.capacity.snapshot(), telemetry: this.telemetryWriter?.status(), activeRuntimes: this.sessions.size, initializingRuntimes: this.creatingRuntimes, recentInitializations: this.initializationTimings.map(item => ({ ...item, phases: { ...item.phases } })) }; }
|
|
1281
|
+
async createRoutedSessionWithinCapacity(piboSessionId, signal) {
|
|
1282
|
+
const stored = this.resolvePiboSession(piboSessionId);
|
|
1283
|
+
const room = typeof stored.metadata?.chatRoomId === "string" ? stored.metadata.chatRoomId : piboSessionId;
|
|
1284
|
+
const queuedAt = performance.now();
|
|
1285
|
+
const lease = await this.capacity.starts.acquire(room, signal);
|
|
1286
|
+
const startedAt = performance.now();
|
|
1287
|
+
const phases = {};
|
|
1288
|
+
let outcome = "failed";
|
|
1289
|
+
try {
|
|
1290
|
+
signal.throwIfAborted();
|
|
1291
|
+
if (this.closing || this.quiescingSessions.has(piboSessionId))
|
|
1292
|
+
throw new Error("Runtime start cancelled during session shutdown.");
|
|
1293
|
+
if (this.sessions.size + this.creatingRuntimes >= this.capacity.maxRuntimes) {
|
|
1294
|
+
const idle = [...this.sessions].find(([id, session]) => { if (this.pendingSessions.has(id))
|
|
1295
|
+
return false; const status = session.getStatus(); return !status.disposed && !status.processing && !status.streaming && status.queuedMessages === 0; });
|
|
1296
|
+
if (idle)
|
|
1297
|
+
await this.evictIdleSession(idle[0], idle[1]);
|
|
1298
|
+
}
|
|
1299
|
+
if (this.sessions.size + this.creatingRuntimes >= this.capacity.maxRuntimes)
|
|
1300
|
+
throw Object.assign(new Error("Active runtime capacity reached."), { code: "runtime_capacity_unavailable" });
|
|
1301
|
+
this.creatingRuntimes++;
|
|
1302
|
+
try {
|
|
1303
|
+
const session = await this.createRoutedSession(piboSessionId, phases);
|
|
1304
|
+
if (signal.aborted) {
|
|
1305
|
+
if (this.sessions.get(piboSessionId) === session)
|
|
1306
|
+
this.sessions.delete(piboSessionId);
|
|
1307
|
+
await this.disposeRoutedSession(piboSessionId, session, "cold start aborted");
|
|
1308
|
+
throw signal.reason;
|
|
1309
|
+
}
|
|
1310
|
+
outcome = "ready";
|
|
1311
|
+
return session;
|
|
1312
|
+
}
|
|
1313
|
+
finally {
|
|
1314
|
+
this.creatingRuntimes--;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
finally {
|
|
1318
|
+
lease.release();
|
|
1319
|
+
this.initializationTimings.push({ sessionId: piboSessionId, waitMs: startedAt - queuedAt, totalMs: performance.now() - startedAt, phases, outcome });
|
|
1320
|
+
if (this.initializationTimings.length > 32)
|
|
1321
|
+
this.initializationTimings.shift();
|
|
1255
1322
|
}
|
|
1256
1323
|
}
|
|
1257
|
-
async createRoutedSession(piboSessionId) {
|
|
1324
|
+
async createRoutedSession(piboSessionId, phases = {}) {
|
|
1325
|
+
let phaseStarted = performance.now();
|
|
1258
1326
|
const piboSession = this.resolvePiboSession(piboSessionId);
|
|
1259
1327
|
let session;
|
|
1260
1328
|
this.signalRegistry.project({ type: "session_created", session: piboSession });
|
|
@@ -1313,6 +1381,8 @@ export class PiboSessionRouter {
|
|
|
1313
1381
|
if (invalidProfile) {
|
|
1314
1382
|
throw new Error(`Runtime profile validation failed: ${invalidProfile.message}`);
|
|
1315
1383
|
}
|
|
1384
|
+
phases.bindingAndProfileMs = performance.now() - phaseStarted;
|
|
1385
|
+
phaseStarted = performance.now();
|
|
1316
1386
|
let historyHandoff;
|
|
1317
1387
|
if (persistedHistoryHandoff?.mode === "import") {
|
|
1318
1388
|
if (!runtimeAdapter.descriptor.capabilities.historyImport) {
|
|
@@ -1336,6 +1406,8 @@ export class PiboSessionRouter {
|
|
|
1336
1406
|
else if (persistedHistoryHandoff?.mode === "fresh") {
|
|
1337
1407
|
historyHandoff = { mode: "fresh" };
|
|
1338
1408
|
}
|
|
1409
|
+
phases.portableHistoryMs = performance.now() - phaseStarted;
|
|
1410
|
+
phaseStarted = performance.now();
|
|
1339
1411
|
const initialFastMode = resolvePiboSessionInitialFastMode(piboSession) ?? selectRequestedFastMode(sessionProfile, modelDefaults) ?? false;
|
|
1340
1412
|
const agentsController = this.createAgentsController(piboSession.id);
|
|
1341
1413
|
const runToolController = this.createRunToolController(piboSession.id);
|
|
@@ -1380,6 +1452,8 @@ export class PiboSessionRouter {
|
|
|
1380
1452
|
this.portableToolSessions.delete(piboSession.id);
|
|
1381
1453
|
throw error;
|
|
1382
1454
|
}
|
|
1455
|
+
phases.resourcesAndToolsMs = performance.now() - phaseStarted;
|
|
1456
|
+
phaseStarted = performance.now();
|
|
1383
1457
|
const bindingSync = { expectedRevision: binding.revision };
|
|
1384
1458
|
const runtimeBindingPersistence = createAgentRuntimeBindingPersistence(this.sessionStore, {
|
|
1385
1459
|
piboSessionId: piboSession.id,
|
|
@@ -1423,6 +1497,7 @@ export class PiboSessionRouter {
|
|
|
1423
1497
|
thinkingLevel: initialThinkingLevel ?? this.options.thinkingLevel,
|
|
1424
1498
|
retryDefaults: resolvePiboSessionRetryDefaults(piboSession.kind, this.options.retryDefaults),
|
|
1425
1499
|
extensionFactories: [
|
|
1500
|
+
createProviderCapacityExtension(this.capacity, piboRoomIdFromMetadata(piboSession.metadata) ?? piboSession.id, Boolean(piboSession.parentId)),
|
|
1426
1501
|
...(telemetryExtension ? [telemetryExtension] : []),
|
|
1427
1502
|
...(this.options.extensionFactories ?? []),
|
|
1428
1503
|
],
|
|
@@ -1492,6 +1567,7 @@ export class PiboSessionRouter {
|
|
|
1492
1567
|
this.runtimeResourceSessions.delete(piboSession.id);
|
|
1493
1568
|
throw error;
|
|
1494
1569
|
}
|
|
1570
|
+
phases.adapterOpenAndBindingMs = performance.now() - phaseStarted;
|
|
1495
1571
|
const resourceInspection = resources.getInspection();
|
|
1496
1572
|
const statusResources = {
|
|
1497
1573
|
enabledSkills: [...new Set(resourceInspection.skills.map((skill) => skill.name))],
|
|
@@ -1533,6 +1609,7 @@ export class PiboSessionRouter {
|
|
|
1533
1609
|
this.handleInterruptedRunReminders(messages);
|
|
1534
1610
|
},
|
|
1535
1611
|
messagePreflight: this.options.messagePreflight,
|
|
1612
|
+
acquireProviderCapacity: runtimeAdapter.descriptor.id === "pi" ? undefined : (provider, signal) => this.capacity.acquireProvider(provider, typeof piboSession.metadata?.chatRoomId === "string" ? piboSession.metadata.chatRoomId : piboSession.id, signal, Boolean(piboSession.parentId)),
|
|
1536
1613
|
modelFallbacks,
|
|
1537
1614
|
getRuntimeAuthStatus: () => runtimeRegistry.getAgentRuntimeAuthStatus(binding.runtimeInstanceId),
|
|
1538
1615
|
startRuntimeAuth: async (input) => {
|