@frockbot/cloudflare 0.7.295 → 0.7.297

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frockbot/cloudflare",
3
- "version": "0.7.295",
3
+ "version": "0.7.297",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,12 +23,12 @@
23
23
  "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.access.json && tsc --noEmit -p test/tsconfig.json && tsc --noEmit -p e2e/tsconfig.json"
24
24
  },
25
25
  "dependencies": {
26
- "@frockbot/app": "0.7.295",
27
- "@frockbot/applets": "0.7.295",
28
- "@frockbot/computer": "0.7.295",
29
- "@frockbot/core": "0.7.295",
30
- "@frockbot/frock-compose": "0.7.295",
31
- "@frockbot/providers": "0.7.295",
26
+ "@frockbot/app": "0.7.297",
27
+ "@frockbot/applets": "0.7.297",
28
+ "@frockbot/computer": "0.7.297",
29
+ "@frockbot/core": "0.7.297",
30
+ "@frockbot/frock-compose": "0.7.297",
31
+ "@frockbot/providers": "0.7.297",
32
32
  "@rive-app/flutter-native-wasm": "44.0.0",
33
33
  "agents": "0.24.0",
34
34
  "ai": "^7.0.107",
package/src/bot-state.ts CHANGED
@@ -231,6 +231,7 @@ import {
231
231
  type ClientRunLookupQueryV1,
232
232
  type ClientRunStopCommandV1,
233
233
  } from "@frockbot/app/shell/run-protocol";
234
+ import { decodeWorkLogQueryV1 } from "@frockbot/app/shell/work-log";
234
235
  import {
235
236
  decodeBotUnreadCommandV1,
236
237
  type BotUnreadCommandV1,
@@ -364,6 +365,8 @@ import { createMemoryEmbedder } from "@frockbot/app/memory/embeddings";
364
365
  import { MemoryRecordsV1 } from "@frockbot/app/memory/owner";
365
366
  import { createVectorMemorySearchV1 } from "@frockbot/app/memory/semantic";
366
367
  import { createHostedMemoryExtractorV1 } from "@frockbot/app/memory/extraction-host";
368
+ import { hostedJevClientV1 } from "@frockbot/app/supervision";
369
+ import { judgeMemoryWriteV1 } from "@frockbot/app/supervision/memory-write";
367
370
  import {
368
371
  createBotMemoryEngineV1,
369
372
  createUserMemoryRecordsRemoteV1,
@@ -1171,12 +1174,18 @@ export class BotState
1171
1174
  : {}),
1172
1175
  ...(this.backendEnv.BILLING ? { billing: this.backendEnv.BILLING } : {}),
1173
1176
  });
1177
+ const jev = hostedJevClientV1(
1178
+ this.backendEnv as unknown as Record<string, string | undefined>,
1179
+ );
1174
1180
  await drainDurableMemoryV1(this.memoryEngine(), {
1175
1181
  ...(this.env.MEMORY_INDEX
1176
1182
  ? { vectors: this.env.MEMORY_INDEX as MemoryVectorIndex }
1177
1183
  : {}),
1178
1184
  ...(this.env.AI ? { ai: this.env.AI as MemoryAiBinding } : {}),
1179
1185
  ...(extract ? { extract } : {}),
1186
+ ...(jev
1187
+ ? { judgeWrite: (evidence) => judgeMemoryWriteV1(jev, evidence) }
1188
+ : {}),
1180
1189
  });
1181
1190
  }
1182
1191
 
@@ -3806,6 +3815,22 @@ export class BotState
3806
3815
  return shell.listRuns(request.query as ClientRunListQueryV1);
3807
3816
  }
3808
3817
 
3818
+ /** The Work log: a page of this Bot's Turns, every step of each. */
3819
+ async workLog(input: unknown) {
3820
+ const request = decodeRpcEnvelopeV1(input, {
3821
+ userId: rpcIdentifier,
3822
+ botId: rpcBotId,
3823
+ query: rpcDecoded(decodeWorkLogQueryV1),
3824
+ });
3825
+ const identity = {
3826
+ userId: request.userId as string,
3827
+ botId: request.botId as string,
3828
+ };
3829
+ const { shell } = await this.materialized(identity);
3830
+ await shell.validateIdentity(identity);
3831
+ return shell.workLog(request.query);
3832
+ }
3833
+
3809
3834
  /**
3810
3835
  * The operator snapshot behind `/api/debug`. Bot-scoped like every other
3811
3836
  * Bot RPC — the debug token authorizes the *caller*, it does not widen what
package/src/contracts.ts CHANGED
@@ -20,6 +20,7 @@ import type {
20
20
  SettingsFrame,
21
21
  ConnectionsFrame,
22
22
  SettingsChangeCommand,
23
+ WorkLogPage,
23
24
  } from "@frockbot/core/protocol-schemas";
24
25
  import {
25
26
  type AuthPackageV1,
@@ -28,6 +29,7 @@ import {
28
29
  type SessionEvent,
29
30
  } from "@frockbot/core/contracts";
30
31
  import type { MachineResultDeliveryV1 } from "@frockbot/app/machine/delivery";
32
+ import type { WorkLogQueryV1 } from "@frockbot/app/shell/work-log";
31
33
  import type { DebugGatewaySurface } from "./debug.js";
32
34
  import type { BotTurnCommandRequestV1 } from "./durable-rpc.js";
33
35
  import type {
@@ -275,6 +277,12 @@ export interface UserBotStateBinding {
275
277
  botId: string;
276
278
  query: ClientRunListQueryV1;
277
279
  }): Promise<ClientRunListV1>;
280
+ /** Everything the Bot did, a page of Turns at a time. */
281
+ workLog(input: {
282
+ schemaVersion: 1;
283
+ botId: string;
284
+ query: WorkLogQueryV1;
285
+ }): Promise<WorkLogPage>;
278
286
  lookupRun(input: {
279
287
  schemaVersion: 1;
280
288
  botId: string;
package/src/index.ts CHANGED
@@ -59,6 +59,11 @@ import {
59
59
  type ClientRunStopCommandV1,
60
60
  type ClientRunStopReceiptV1,
61
61
  } from "@frockbot/app/shell/run-protocol";
62
+ import {
63
+ decodeWorkLogQueryV1,
64
+ type WorkLogQueryV1,
65
+ } from "@frockbot/app/shell/work-log";
66
+ import type { WorkLogPage } from "@frockbot/core/protocol-schemas";
62
67
  import {
63
68
  decodeBotNotificationDirectoryViewV1,
64
69
  decodeBotUnreadDirectoryViewV1,
@@ -504,6 +509,7 @@ interface BotStateRpc extends BotConfigurationBinding {
504
509
  command: BotTurnCommandRequestV1<OwnedBotTurnCommand>,
505
510
  ): Promise<{ schemaVersion: 1; runId: string }>;
506
511
  listRuns(query: ClientRunListQueryV1): Promise<ClientRunListV1>;
512
+ workLog(query: WorkLogQueryV1): Promise<WorkLogPage>;
507
513
  debugSnapshot(query: BotDebugQueryV1): Promise<unknown>;
508
514
  lookupRun(query: ClientRunLookupQueryV1): Promise<ClientRunLookupV1>;
509
515
  runQuestions(query: ClientRunLookupQueryV1): Promise<ClientRunQuestionsV1>;
@@ -691,6 +697,7 @@ function botStateStub(env: Env, userId: string, botId: string): BotStateRpc {
691
697
  admitRun: (command) => rpc.admitRun(botTurnRpcV1(command)),
692
698
  listRuns: (query) =>
693
699
  rpc.listRuns({ schemaVersion: 1, userId, botId, query }),
700
+ workLog: (query) => rpc.workLog({ schemaVersion: 1, userId, botId, query }),
694
701
  debugSnapshot: (query) =>
695
702
  rpc.debugSnapshot({ schemaVersion: 1, userId, botId, query }),
696
703
  lookupRun: (query) =>
@@ -1296,6 +1303,18 @@ export class UserBotState extends WorkerEntrypoint<Env, UserScopedProps> {
1296
1303
  ).listRuns(request.query as ClientRunListQueryV1);
1297
1304
  }
1298
1305
 
1306
+ async workLog(input: unknown): Promise<WorkLogPage> {
1307
+ const request = decodeRpcEnvelopeV1(input, {
1308
+ botId: rpcBotId,
1309
+ query: rpcDecoded(decodeWorkLogQueryV1),
1310
+ });
1311
+ return botStateStub(
1312
+ this.env,
1313
+ this.ctx.props.userId,
1314
+ request.botId as string,
1315
+ ).workLog(request.query as WorkLogQueryV1);
1316
+ }
1317
+
1299
1318
  async lookupRun(input: unknown): Promise<ClientRunLookupV1> {
1300
1319
  const request = decodeUserBotRunLookupRpcV1(input);
1301
1320
  return botStateStub(
@@ -167,6 +167,8 @@ export interface DurableMemoryIndexBindingsV1 {
167
167
  ai?: MemoryAiBinding;
168
168
  /** What a Turn's words hold worth remembering; absent, extraction waits. */
169
169
  extract?: MemoryProcessingAdaptersV1["extract"];
170
+ /** The write judgment each extracted fact goes through. */
171
+ judgeWrite?: MemoryProcessingAdaptersV1["judgeWrite"];
170
172
  }
171
173
 
172
174
  export async function drainDurableMemoryV1(
@@ -177,5 +179,6 @@ export async function drainDurableMemoryV1(
177
179
  if (bindings.vectors) adapters.vectors = bindings.vectors;
178
180
  if (bindings.ai) adapters.embed = createMemoryEmbedder(bindings.ai);
179
181
  if (bindings.extract) adapters.extract = bindings.extract;
182
+ if (bindings.judgeWrite) adapters.judgeWrite = bindings.judgeWrite;
180
183
  return drainMemoryProcessingV1(engine, adapters);
181
184
  }
@@ -29,6 +29,10 @@ import {
29
29
  type ClientTurnRefusalV1,
30
30
  } from "@frockbot/app/shell/run-protocol";
31
31
  import { decodeApprovalDecisionCommandV1 } from "@frockbot/app/shell/approvals";
32
+ import {
33
+ decodeWorkLogQueryV1,
34
+ type WorkLogQueryV1,
35
+ } from "@frockbot/app/shell/work-log";
32
36
  import {
33
37
  decodeSecretSubmitCommandV1,
34
38
  isSecretRequestIdV1,
@@ -726,6 +730,7 @@ function createUserApplicationRoute() {
726
730
  }
727
731
 
728
732
  const skillsMatch = url.pathname.match(/^\/api\/bots\/([^/]+)\/skills$/);
733
+ const workLogMatch = url.pathname.match(/^\/api\/bots\/([^/]+)\/work-log$/);
729
734
  const workspaceFileMatch = url.pathname.match(
730
735
  /^\/api\/bots\/([^/]+)\/workspace\/file$/,
731
736
  );
@@ -744,6 +749,7 @@ function createUserApplicationRoute() {
744
749
  );
745
750
  if (
746
751
  !skillsMatch &&
752
+ !workLogMatch &&
747
753
  !workspaceFileMatch &&
748
754
  !turnMatch &&
749
755
  !lookupMatch &&
@@ -757,6 +763,7 @@ function createUserApplicationRoute() {
757
763
  try {
758
764
  const matched =
759
765
  skillsMatch ??
766
+ workLogMatch ??
760
767
  workspaceFileMatch ??
761
768
  turnMatch ??
762
769
  lookupMatch ??
@@ -776,7 +783,7 @@ function createUserApplicationRoute() {
776
783
  env,
777
784
  botId,
778
785
  request.method === "GET" &&
779
- Boolean(turnMatch || lookupMatch || questionsMatch),
786
+ Boolean(turnMatch || lookupMatch || questionsMatch || workLogMatch),
780
787
  );
781
788
  if (missingBot) return missingBot;
782
789
  // An installed client older than protocol 3 refuses a Run it does not
@@ -800,6 +807,37 @@ function createUserApplicationRoute() {
800
807
  }
801
808
  }
802
809
 
810
+ if (workLogMatch) {
811
+ if (request.method !== "GET") return jsonError(405, "method not allowed");
812
+ let query: WorkLogQueryV1;
813
+ try {
814
+ const keys = [...url.searchParams.keys()];
815
+ if (
816
+ keys.some((key) => key !== "before") ||
817
+ url.searchParams.getAll("before").length > 1
818
+ ) {
819
+ throw new Error("work log query is invalid");
820
+ }
821
+ const before = url.searchParams.get("before");
822
+ query = decodeWorkLogQueryV1({
823
+ schemaVersion: 1,
824
+ ...(before === null ? {} : { before }),
825
+ });
826
+ } catch (error) {
827
+ return jsonError(
828
+ 400,
829
+ error instanceof Error ? error.message : "invalid work log page",
830
+ );
831
+ }
832
+ try {
833
+ return Response.json(
834
+ await env.BOT_STATE.workLog({ schemaVersion: 1, botId, query }),
835
+ );
836
+ } catch (error) {
837
+ return botFailure(error, "work log failed");
838
+ }
839
+ }
840
+
803
841
  if (workspaceFileMatch) {
804
842
  // Read-only, and the durable root and path arrive as one encoded
805
843
  // `WorkspacePathV1` so the route cannot assemble a root the decoder