@frockbot/plugin-shell 0.3.14 → 0.3.16
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/package.json +32 -32
- package/src/backend-completion.test.ts +22 -5
- package/src/backend-configuration.test.ts +7 -5
- package/src/backend-debug.test.ts +49 -0
- package/src/backend-memory.ts +6 -0
- package/src/backend-recovery-integration.test.ts +16 -2
- package/src/backend.ts +41 -12
- package/src/client/voice-microphone.ts +4 -4
- package/src/debug-protocol.ts +4 -3
- package/src/run-failure-copy.test.ts +9 -0
- package/src/run-failure-copy.ts +15 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/plugin-shell",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -51,42 +51,42 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@cordisjs/plugin-webui": "0.8.2",
|
|
54
|
-
"@frockbot/agent-runtime": "0.3.
|
|
55
|
-
"@frockbot/application-foundation": "0.3.
|
|
56
|
-
"@frockbot/catalog-core": "0.3.
|
|
57
|
-
"@frockbot/client-core": "0.3.
|
|
58
|
-
"@frockbot/client-ui": "0.3.
|
|
59
|
-
"@frockbot/computer-core": "0.3.
|
|
60
|
-
"@frockbot/computer-host-protocol": "0.3.
|
|
61
|
-
"@frockbot/configuration-core": "0.3.
|
|
62
|
-
"@frockbot/connection-core": "0.3.
|
|
63
|
-
"@frockbot/kernel-agent-loop": "0.3.
|
|
64
|
-
"@frockbot/kernel-composition": "0.3.
|
|
65
|
-
"@frockbot/kernel-contracts": "0.3.
|
|
66
|
-
"@frockbot/kernel-do": "0.3.
|
|
67
|
-
"@frockbot/machine-protocol": "0.3.
|
|
68
|
-
"@frockbot/plugin-applets": "0.3.
|
|
69
|
-
"@frockbot/plugin-authoring": "0.3.
|
|
70
|
-
"@frockbot/plugin-bot-template": "0.3.
|
|
71
|
-
"@frockbot/plugin-computer": "0.3.
|
|
72
|
-
"@frockbot/plugin-flock": "0.3.
|
|
73
|
-
"@frockbot/plugin-image": "0.3.
|
|
74
|
-
"@frockbot/plugin-machine-messages": "0.3.
|
|
75
|
-
"@frockbot/plugin-mcp": "0.3.
|
|
76
|
-
"@frockbot/plugin-memory": "0.3.
|
|
77
|
-
"@frockbot/plugin-package-catalog": "0.3.
|
|
78
|
-
"@frockbot/plugin-routines": "0.3.
|
|
79
|
-
"@frockbot/plugin-skills": "0.3.
|
|
80
|
-
"@frockbot/plugin-subagents": "0.3.
|
|
81
|
-
"@frockbot/plugin-user-machine": "0.3.
|
|
82
|
-
"@frockbot/protocol": "0.3.
|
|
54
|
+
"@frockbot/agent-runtime": "0.3.16",
|
|
55
|
+
"@frockbot/application-foundation": "0.3.16",
|
|
56
|
+
"@frockbot/catalog-core": "0.3.16",
|
|
57
|
+
"@frockbot/client-core": "0.3.16",
|
|
58
|
+
"@frockbot/client-ui": "0.3.16",
|
|
59
|
+
"@frockbot/computer-core": "0.3.16",
|
|
60
|
+
"@frockbot/computer-host-protocol": "0.3.16",
|
|
61
|
+
"@frockbot/configuration-core": "0.3.16",
|
|
62
|
+
"@frockbot/connection-core": "0.3.16",
|
|
63
|
+
"@frockbot/kernel-agent-loop": "0.3.16",
|
|
64
|
+
"@frockbot/kernel-composition": "0.3.16",
|
|
65
|
+
"@frockbot/kernel-contracts": "0.3.16",
|
|
66
|
+
"@frockbot/kernel-do": "0.3.16",
|
|
67
|
+
"@frockbot/machine-protocol": "0.3.16",
|
|
68
|
+
"@frockbot/plugin-applets": "0.3.16",
|
|
69
|
+
"@frockbot/plugin-authoring": "0.3.16",
|
|
70
|
+
"@frockbot/plugin-bot-template": "0.3.16",
|
|
71
|
+
"@frockbot/plugin-computer": "0.3.16",
|
|
72
|
+
"@frockbot/plugin-flock": "0.3.16",
|
|
73
|
+
"@frockbot/plugin-image": "0.3.16",
|
|
74
|
+
"@frockbot/plugin-machine-messages": "0.3.16",
|
|
75
|
+
"@frockbot/plugin-mcp": "0.3.16",
|
|
76
|
+
"@frockbot/plugin-memory": "0.3.16",
|
|
77
|
+
"@frockbot/plugin-package-catalog": "0.3.16",
|
|
78
|
+
"@frockbot/plugin-routines": "0.3.16",
|
|
79
|
+
"@frockbot/plugin-skills": "0.3.16",
|
|
80
|
+
"@frockbot/plugin-subagents": "0.3.16",
|
|
81
|
+
"@frockbot/plugin-user-machine": "0.3.16",
|
|
82
|
+
"@frockbot/protocol": "0.3.16",
|
|
83
83
|
"cordis": "4.0.0-rc.8",
|
|
84
84
|
"vue": "3.5.41"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@cloudflare/workers-types": "latest",
|
|
88
|
-
"@frockbot/plugin-prompt": "0.3.
|
|
89
|
-
"@frockbot/plugin-tools": "0.3.
|
|
88
|
+
"@frockbot/plugin-prompt": "0.3.16",
|
|
89
|
+
"@frockbot/plugin-tools": "0.3.16",
|
|
90
90
|
"@types/bun": "1.3.6",
|
|
91
91
|
"@types/node": "26.2.0",
|
|
92
92
|
"@vitejs/plugin-vue": "6.0.8",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { type SessionEvent } from "@frockbot/kernel-contracts";
|
|
3
3
|
import { initializeBotSettingsV1 } from "@frockbot/configuration-core";
|
|
4
|
+
import { SessionEventLog } from "@frockbot/kernel-do";
|
|
4
5
|
import {
|
|
5
6
|
botTurnCommandFingerprintV1,
|
|
6
7
|
type BotTurnCompletion,
|
|
@@ -81,11 +82,15 @@ class MemoryRunStorage implements RunTerminalStorage {
|
|
|
81
82
|
return Promise.resolve(this.values.get(key) as T | undefined);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
put(
|
|
85
|
-
|
|
86
|
-
if (this.putFailure) return Promise.reject(this.putFailure);
|
|
87
|
-
for (const [key, value] of Object.entries(entries)) {
|
|
85
|
+
put(key: string | Record<string, unknown>, value?: unknown): Promise<void> {
|
|
86
|
+
if (typeof key === "string") {
|
|
88
87
|
this.values.set(key, structuredClone(value));
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
this.putBatches.push(structuredClone(key));
|
|
91
|
+
if (this.putFailure) return Promise.reject(this.putFailure);
|
|
92
|
+
for (const [entry, item] of Object.entries(key)) {
|
|
93
|
+
this.values.set(entry, structuredClone(item));
|
|
89
94
|
}
|
|
90
95
|
return Promise.resolve();
|
|
91
96
|
}
|
|
@@ -93,6 +98,16 @@ class MemoryRunStorage implements RunTerminalStorage {
|
|
|
93
98
|
delete(key: string): Promise<boolean> {
|
|
94
99
|
return Promise.resolve(this.values.delete(key));
|
|
95
100
|
}
|
|
101
|
+
|
|
102
|
+
list<T>(options: { prefix: string }): Promise<Map<string, T>> {
|
|
103
|
+
return Promise.resolve(
|
|
104
|
+
new Map(
|
|
105
|
+
[...this.values.entries()].filter(([key]) =>
|
|
106
|
+
key.startsWith(options.prefix),
|
|
107
|
+
) as Array<[string, T]>,
|
|
108
|
+
),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
96
111
|
}
|
|
97
112
|
|
|
98
113
|
describe("Bot run terminal persistence", () => {
|
|
@@ -284,6 +299,8 @@ describe("Bot run terminal persistence", () => {
|
|
|
284
299
|
failure: "provider-bound retrieval unavailable",
|
|
285
300
|
});
|
|
286
301
|
expect(storage.values.get(keys.activeRun)).toBe("run-1");
|
|
287
|
-
expect(storage.
|
|
302
|
+
expect(await new SessionEventLog(storage).read("user:primary")).toEqual([
|
|
303
|
+
request,
|
|
304
|
+
]);
|
|
288
305
|
});
|
|
289
306
|
});
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
UserSettingsViewV1,
|
|
7
7
|
} from "@frockbot/configuration-core";
|
|
8
8
|
import type { PackageSettingDefinition } from "@frockbot/kernel-composition";
|
|
9
|
+
import { SessionEventLog } from "@frockbot/kernel-do";
|
|
9
10
|
import { createShellBotBackendContribution } from "./backend.js";
|
|
10
11
|
import { createIsolateCapabilityHost } from "./backend-isolate.js";
|
|
11
12
|
import { notificationIdV1 } from "./notification-id.js";
|
|
@@ -549,11 +550,12 @@ describe("generic per-Turn model resolution", () => {
|
|
|
549
550
|
});
|
|
550
551
|
|
|
551
552
|
expect(result.text).toBe("Cordis runtime: hello");
|
|
552
|
-
const durableEvents = storage.
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
expect(durableEvents
|
|
556
|
-
|
|
553
|
+
const durableEvents = await new SessionEventLog(storage).read(
|
|
554
|
+
"user-1:primary",
|
|
555
|
+
);
|
|
556
|
+
expect(durableEvents.length).toBeGreaterThan(0);
|
|
557
|
+
expect(durableEvents.map((event) => event.seq)).toEqual(
|
|
558
|
+
durableEvents.map((_, index) => index),
|
|
557
559
|
);
|
|
558
560
|
const settings = await contribution.getSettings(identity);
|
|
559
561
|
expect(settings).toMatchObject({ revision: 0, packageValues: {} });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { initializeBotSettingsV1 } from "@frockbot/configuration-core";
|
|
3
|
+
import { SessionEventLog, storedRunRecordV2 } from "@frockbot/kernel-do";
|
|
3
4
|
import { createShellBotBackendContribution } from "./backend.js";
|
|
4
5
|
import type { StoredRun } from "./backend-contracts.js";
|
|
5
6
|
|
|
@@ -154,6 +155,54 @@ describe("Bot debug snapshot", () => {
|
|
|
154
155
|
expect(snapshot.activeRunId).toBeUndefined();
|
|
155
156
|
});
|
|
156
157
|
|
|
158
|
+
test("reads bounded projections instead of hydrating full model prompts", async () => {
|
|
159
|
+
const storage = new MemoryStorage();
|
|
160
|
+
const event = {
|
|
161
|
+
type: "model/request",
|
|
162
|
+
turn: 1,
|
|
163
|
+
step: 1,
|
|
164
|
+
request: {
|
|
165
|
+
requestId: "request-large",
|
|
166
|
+
provider: "fake",
|
|
167
|
+
model: "large-context",
|
|
168
|
+
system: "s".repeat(80_000),
|
|
169
|
+
messages: [{ role: "user", content: "last question" }],
|
|
170
|
+
tools: [],
|
|
171
|
+
},
|
|
172
|
+
seq: 0,
|
|
173
|
+
timestamp: "2026-08-28T00:00:01.000Z",
|
|
174
|
+
} as StoredRun["events"][number];
|
|
175
|
+
const run = storedRun({ events: [event] });
|
|
176
|
+
await new SessionEventLog(storage).rewrite(run.sessionId, [event]);
|
|
177
|
+
await storage.put({
|
|
178
|
+
identity: IDENTITY,
|
|
179
|
+
[`run:${run.runId}`]: storedRunRecordV2(run),
|
|
180
|
+
[`run-index:${run.acceptedAt}:${run.runId}`]: run.runId,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const snapshot = await contributionOver(storage).debugSnapshot(IDENTITY, {
|
|
184
|
+
schemaVersion: 1,
|
|
185
|
+
runId: run.runId,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(snapshot.runs[0]?.eventCount).toBe(1);
|
|
189
|
+
expect(snapshot.runs[0]?.events?.[0]).toMatchObject({
|
|
190
|
+
type: "model/request",
|
|
191
|
+
cut: { marker: "content-cut", originalBytes: expect.any(Number) },
|
|
192
|
+
request: {
|
|
193
|
+
requestId: "request-large",
|
|
194
|
+
messageCount: 1,
|
|
195
|
+
toolCount: 0,
|
|
196
|
+
sha256: expect.stringMatching(/^[0-9a-f]{64}$/),
|
|
197
|
+
truncated: true,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
expect(JSON.stringify(snapshot)).not.toContain("s".repeat(10_000));
|
|
201
|
+
expect(
|
|
202
|
+
new TextEncoder().encode(JSON.stringify(snapshot)).byteLength,
|
|
203
|
+
).toBeLessThan(20_000);
|
|
204
|
+
});
|
|
205
|
+
|
|
157
206
|
test("includes an active run older than the page it would otherwise fall off", async () => {
|
|
158
207
|
const storage = new MemoryStorage();
|
|
159
208
|
const stale = storedRun({
|
package/src/backend-memory.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
MemoryRuntimeHostV1,
|
|
26
26
|
} from "@frockbot/plugin-memory/agent";
|
|
27
27
|
import { MemoryStore } from "@frockbot/plugin-memory/store";
|
|
28
|
+
import type { MemoryChunkIndexWriterV1 } from "@frockbot/plugin-memory/chunk-index";
|
|
28
29
|
|
|
29
30
|
/** The Bot and User whose Memory a Turn may read and write. */
|
|
30
31
|
export interface BotMemoryIdentity {
|
|
@@ -50,6 +51,8 @@ export interface BotMemoryEnv {
|
|
|
50
51
|
MEMORY_PROJECTS?: MemoryProjectsV1;
|
|
51
52
|
/** Display names per Bot id, for the `[via …]` tag on a shared fact. */
|
|
52
53
|
MEMORY_BOT_NAMES?: Readonly<Record<string, string>>;
|
|
54
|
+
/** Bot-scoped vector-id ledger supplied by the Durable Object host. */
|
|
55
|
+
MEMORY_CHUNK_INDEX?: MemoryChunkIndexWriterV1;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
/**
|
|
@@ -85,5 +88,8 @@ export function createBotMemoryHost(
|
|
|
85
88
|
runId: turn.runId,
|
|
86
89
|
},
|
|
87
90
|
...(bindings.MEMORY_PROJECTS ? { projects: bindings.MEMORY_PROJECTS } : {}),
|
|
91
|
+
...(bindings.MEMORY_CHUNK_INDEX
|
|
92
|
+
? { chunkIndex: bindings.MEMORY_CHUNK_INDEX }
|
|
93
|
+
: {}),
|
|
88
94
|
};
|
|
89
95
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type UserSettingsViewV1,
|
|
10
10
|
} from "@frockbot/configuration-core";
|
|
11
11
|
import { compileFoundationApplication } from "@frockbot/application-foundation/runtime";
|
|
12
|
+
import { SessionEventLog } from "@frockbot/kernel-do";
|
|
12
13
|
import { createShellBotBackendContribution } from "./backend.js";
|
|
13
14
|
import {
|
|
14
15
|
botTurnCommandFingerprintV1,
|
|
@@ -291,10 +292,23 @@ describe("Bot recovery", () => {
|
|
|
291
292
|
},
|
|
292
293
|
]);
|
|
293
294
|
expect(settledEffects).toHaveLength(2);
|
|
295
|
+
const eventLog = new SessionEventLog(storage);
|
|
294
296
|
for (const runId of ["ollama-run-1", "ollama-run-2"]) {
|
|
295
|
-
const run = await storage.get<
|
|
297
|
+
const run = await storage.get<
|
|
298
|
+
Omit<StoredRun, "events"> & {
|
|
299
|
+
eventRange: { startSeq: number; endSeq: number };
|
|
300
|
+
}
|
|
301
|
+
>(`run:${runId}`);
|
|
302
|
+
expect(run).not.toHaveProperty("events");
|
|
303
|
+
const events = run
|
|
304
|
+
? await eventLog.readRange(
|
|
305
|
+
"user-1:primary",
|
|
306
|
+
run.eventRange.startSeq,
|
|
307
|
+
run.eventRange.endSeq,
|
|
308
|
+
)
|
|
309
|
+
: [];
|
|
296
310
|
expect(
|
|
297
|
-
|
|
311
|
+
events.find((event) => event.type === "model/request"),
|
|
298
312
|
).toMatchObject({
|
|
299
313
|
request: {
|
|
300
314
|
provider: "ollama-cloud",
|
package/src/backend.ts
CHANGED
|
@@ -46,12 +46,13 @@ import {
|
|
|
46
46
|
ACTIVE_RUN_KEY,
|
|
47
47
|
BotDurableAuthority,
|
|
48
48
|
IDENTITY_KEY,
|
|
49
|
-
LATEST_EVENTS_KEY,
|
|
50
49
|
NOTIFICATION_PREFIX,
|
|
51
50
|
RECOVERY_ALARM_DELAY_MS,
|
|
52
51
|
RUN_ADMISSION_FENCE_PREFIX,
|
|
53
52
|
RUN_INDEX_PREFIX,
|
|
54
53
|
RUN_PREFIX,
|
|
54
|
+
SessionEventLog,
|
|
55
|
+
storedRunRecordV2,
|
|
55
56
|
CONVERSATION_BUSY_MESSAGE_V1,
|
|
56
57
|
isConversationBusyV1,
|
|
57
58
|
type BotIdentity,
|
|
@@ -589,7 +590,8 @@ export interface BotStateEnv {
|
|
|
589
590
|
* Bot authoring still compiles; `package_author` then refuses visibly.
|
|
590
591
|
*/
|
|
591
592
|
PACKAGE_BUNDLER?: PackageBundlerBinding;
|
|
592
|
-
|
|
593
|
+
/** Optional in local and workerd hosts, which have no Vectorize simulator. */
|
|
594
|
+
MEMORY_INDEX?: VectorizeIndex;
|
|
593
595
|
/** The native AI binding consumed through the image Package adapter. */
|
|
594
596
|
AI?: NativeAiBindingV1;
|
|
595
597
|
/** The Frock AI Gateway adapter constructed by the Cloudflare host. */
|
|
@@ -1155,8 +1157,10 @@ export class ShellBotBackendContribution {
|
|
|
1155
1157
|
const announcements = [...stored.entries()]
|
|
1156
1158
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
1157
1159
|
.map(([, value]) => decodeSessionEvent(value));
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
+
const sessionId = await this.authority.readConversationSessionId();
|
|
1161
|
+
const session = sessionId
|
|
1162
|
+
? await this.authority.readSessionEvents(sessionId)
|
|
1163
|
+
: [];
|
|
1160
1164
|
for (const event of session) {
|
|
1161
1165
|
if (event.type === "conversation/compacted") announcements.push(event);
|
|
1162
1166
|
}
|
|
@@ -1170,8 +1174,10 @@ export class ShellBotBackendContribution {
|
|
|
1170
1174
|
* timestamp of the place it belongs rather than the moment it was written.
|
|
1171
1175
|
*/
|
|
1172
1176
|
private async projectAnnouncementPage() {
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1177
|
+
const sessionId = await this.authority.readConversationSessionId();
|
|
1178
|
+
const session = sessionId
|
|
1179
|
+
? await this.authority.readSessionEvents(sessionId)
|
|
1180
|
+
: [];
|
|
1175
1181
|
return projectClientAnnouncementsV1(
|
|
1176
1182
|
await this.listAnnouncements(),
|
|
1177
1183
|
session,
|
|
@@ -5950,10 +5956,13 @@ export class ShellBotBackendContribution {
|
|
|
5950
5956
|
let budget = BOT_DEBUG_EVENT_BYTES_V1;
|
|
5951
5957
|
const runs: BotDebugRunV1[] = [];
|
|
5952
5958
|
for (const candidate of candidates) {
|
|
5953
|
-
const
|
|
5954
|
-
|
|
5959
|
+
const projected = await this.authority.readRunEventProjections(
|
|
5960
|
+
candidate.runId,
|
|
5961
|
+
);
|
|
5962
|
+
if (!projected) continue;
|
|
5963
|
+
const { run: stored } = projected;
|
|
5955
5964
|
const bounded = includeEvents
|
|
5956
|
-
? boundDebugEventsV1(
|
|
5965
|
+
? boundDebugEventsV1(projected.events, budget)
|
|
5957
5966
|
: undefined;
|
|
5958
5967
|
if (bounded) budget = Math.max(0, budget - bounded.spent);
|
|
5959
5968
|
runs.push({
|
|
@@ -5966,7 +5975,7 @@ export class ShellBotBackendContribution {
|
|
|
5966
5975
|
commandFingerprint: stored.commandFingerprint,
|
|
5967
5976
|
compositionGenerationId: stored.compositionGenerationId,
|
|
5968
5977
|
previousEventCount: stored.previousEventCount,
|
|
5969
|
-
eventCount:
|
|
5978
|
+
eventCount: projected.eventCount,
|
|
5970
5979
|
...(stored.responseText === undefined
|
|
5971
5980
|
? {}
|
|
5972
5981
|
: { responseText: stored.responseText }),
|
|
@@ -6327,7 +6336,24 @@ export class ShellBotBackendContribution {
|
|
|
6327
6336
|
transaction.get<BotIdentity>(IDENTITY_KEY),
|
|
6328
6337
|
transaction.get<unknown>(`${RUN_PREFIX}${runId}`),
|
|
6329
6338
|
]);
|
|
6330
|
-
const
|
|
6339
|
+
const storedRun = optionalStoredRun(candidate);
|
|
6340
|
+
let run = storedRun;
|
|
6341
|
+
if (storedRun?.eventRange) {
|
|
6342
|
+
const events = await new SessionEventLog(transaction).readRange(
|
|
6343
|
+
storedRun.sessionId,
|
|
6344
|
+
storedRun.eventRange.startSeq,
|
|
6345
|
+
storedRun.eventRange.endSeq,
|
|
6346
|
+
);
|
|
6347
|
+
if (
|
|
6348
|
+
events.length !==
|
|
6349
|
+
storedRun.eventRange.endSeq - storedRun.eventRange.startSeq
|
|
6350
|
+
) {
|
|
6351
|
+
throw new Error(
|
|
6352
|
+
`run "${storedRun.runId}" has an incomplete event range`,
|
|
6353
|
+
);
|
|
6354
|
+
}
|
|
6355
|
+
run = requireStoredRunV1({ ...storedRun, events });
|
|
6356
|
+
}
|
|
6331
6357
|
if (
|
|
6332
6358
|
activeRunId !== runId ||
|
|
6333
6359
|
!run ||
|
|
@@ -6387,7 +6413,10 @@ export class ShellBotBackendContribution {
|
|
|
6387
6413
|
{ kind: effect.kind, effectId: effect.effectId, outcome },
|
|
6388
6414
|
],
|
|
6389
6415
|
} satisfies StoredRun);
|
|
6390
|
-
await transaction.put(
|
|
6416
|
+
await transaction.put(
|
|
6417
|
+
`${RUN_PREFIX}${runId}`,
|
|
6418
|
+
structuredClone(storedRunRecordV2(next)),
|
|
6419
|
+
);
|
|
6391
6420
|
return outcome === "admitted";
|
|
6392
6421
|
});
|
|
6393
6422
|
}
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
} from "./voice-worklet.js";
|
|
12
12
|
|
|
13
13
|
/** What the upstream is told to expect, and therefore what leaves here. */
|
|
14
|
-
export const VOICE_CAPTURE_SAMPLE_RATE_V1 =
|
|
14
|
+
export const VOICE_CAPTURE_SAMPLE_RATE_V1 = 24_000;
|
|
15
15
|
|
|
16
|
-
/** Samples per frame at
|
|
17
|
-
const FRAME_SAMPLES =
|
|
16
|
+
/** Samples per frame at 24 kHz: 32 ms, small enough to feel live. */
|
|
17
|
+
const FRAME_SAMPLES = 768;
|
|
18
18
|
|
|
19
19
|
export interface VoiceMicrophoneV1 {
|
|
20
20
|
stop(): Promise<void>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface VoiceMicrophoneOptionsV1 {
|
|
24
|
-
/** One frame of PCM16, little-endian, mono,
|
|
24
|
+
/** One frame of PCM16, little-endian, mono, 24 kHz. */
|
|
25
25
|
audio(pcm16: ArrayBuffer): void;
|
|
26
26
|
/** Peak amplitude of the frame, 0…1, for the capture animation. */
|
|
27
27
|
level(value: number): void;
|
package/src/debug-protocol.ts
CHANGED
|
@@ -20,9 +20,10 @@ export const BOT_DEBUG_RUN_LIMIT_V1 = 20;
|
|
|
20
20
|
export const BOT_DEBUG_DEFAULT_RUN_LIMIT_V1 = 5;
|
|
21
21
|
export const BOT_DEBUG_GENERATION_LIMIT_V1 = 5;
|
|
22
22
|
/**
|
|
23
|
-
* The event budget one snapshot spends.
|
|
24
|
-
* a handful of runs can
|
|
25
|
-
*
|
|
23
|
+
* The event budget one snapshot spends. Large durable events are already
|
|
24
|
+
* bounded diagnostic projections, but a handful of runs can still accumulate
|
|
25
|
+
* many of them; past this the *oldest* events of a run are dropped, because a
|
|
26
|
+
* failure is described by the tail of its log.
|
|
26
27
|
*/
|
|
27
28
|
export const BOT_DEBUG_EVENT_BYTES_V1 = 512_000;
|
|
28
29
|
|
|
@@ -3,6 +3,7 @@ import type { SessionEvent } from "@frockbot/kernel-contracts";
|
|
|
3
3
|
import { MODEL_FIRST_BYTE_DEADLINE_REASON_V1 } from "@frockbot/kernel-contracts";
|
|
4
4
|
import {
|
|
5
5
|
knownFailureCopyV1,
|
|
6
|
+
MODEL_PROVIDER_FAILURE_COPY_V1,
|
|
6
7
|
RUN_FAILURE_COPY_V1,
|
|
7
8
|
RUN_FAILURE_FALLBACK_COPY_V1,
|
|
8
9
|
runFailureCopyV1,
|
|
@@ -75,6 +76,14 @@ function failedRun(failure: string, events: SessionEvent[]): StoredRun {
|
|
|
75
76
|
describe("runFailureCopyV1", () => {
|
|
76
77
|
test("every mapped sentence is written for a person", () => {
|
|
77
78
|
for (const copy of Object.values(RUN_FAILURE_COPY_V1)) assertPlainV1(copy);
|
|
79
|
+
expect(Object.keys(MODEL_PROVIDER_FAILURE_COPY_V1).sort()).toEqual([
|
|
80
|
+
"permanent",
|
|
81
|
+
"transient",
|
|
82
|
+
"unknown",
|
|
83
|
+
]);
|
|
84
|
+
for (const copy of Object.values(MODEL_PROVIDER_FAILURE_COPY_V1)) {
|
|
85
|
+
assertPlainV1(copy);
|
|
86
|
+
}
|
|
78
87
|
assertPlainV1(RUN_FAILURE_FALLBACK_COPY_V1);
|
|
79
88
|
for (const reason of USER_FACING_FAILURE_REASONS_V1) assertPlainV1(reason);
|
|
80
89
|
});
|
package/src/run-failure-copy.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ModelProviderFailureClassV1,
|
|
3
|
+
SessionEvent,
|
|
4
|
+
TurnOutcome,
|
|
5
|
+
} from "@frockbot/kernel-contracts";
|
|
2
6
|
import {
|
|
3
7
|
MODEL_FIRST_BYTE_DEADLINE_REASON_V1,
|
|
4
8
|
MODEL_IDLE_DEADLINE_REASON_V1,
|
|
@@ -59,6 +63,16 @@ export const RUN_FAILURE_COPY_V1: Record<TurnOutcome, string> = {
|
|
|
59
63
|
"tool-error": "Something the Bot was using didn't work. Try again.",
|
|
60
64
|
};
|
|
61
65
|
|
|
66
|
+
/** Every provider class reaches the same intentionally plain model-error copy. */
|
|
67
|
+
export const MODEL_PROVIDER_FAILURE_COPY_V1: Record<
|
|
68
|
+
ModelProviderFailureClassV1,
|
|
69
|
+
string
|
|
70
|
+
> = {
|
|
71
|
+
transient: RUN_FAILURE_COPY_V1["model-error"],
|
|
72
|
+
permanent: RUN_FAILURE_COPY_V1["model-error"],
|
|
73
|
+
unknown: RUN_FAILURE_COPY_V1["model-error"],
|
|
74
|
+
};
|
|
75
|
+
|
|
62
76
|
/** What a Turn says when nothing more specific is known about how it ended. */
|
|
63
77
|
export const RUN_FAILURE_FALLBACK_COPY_V1 =
|
|
64
78
|
"This Bot couldn't finish its reply. Try again.";
|