@springbrand/agent-runtime 0.2.0-alpha.67 → 0.2.0-alpha.68

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": "@springbrand/agent-runtime",
3
- "version": "0.2.0-alpha.67",
3
+ "version": "0.2.0-alpha.68",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -9,7 +9,10 @@ import {
9
9
  type ProxyToolOutput,
10
10
  } from "@cloudflare/codemode";
11
11
  import { createBrowserTools } from "@cloudflare/think/tools/browser";
12
- import { createExecuteRuntime } from "@cloudflare/think/tools/execute";
12
+ import {
13
+ createExecuteRuntime,
14
+ type CreateExecuteToolOptions,
15
+ } from "@cloudflare/think/tools/execute";
13
16
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
14
17
  import type { Usage } from "@earendil-works/pi-ai";
15
18
  import type { ToolSet } from "ai";
@@ -18,7 +21,10 @@ import type {
18
21
  RuntimeCodeExecutionPort,
19
22
  WorkspacePort,
20
23
  } from "../../kernel/bindings";
21
- import { WorkspaceStateConnector } from "./workspace-state-connector";
24
+ import {
25
+ WorkspaceStateConnector,
26
+ WORKSPACE_PAGING_INSTRUCTIONS,
27
+ } from "./workspace-state-connector";
22
28
  import type { RuntimeCodeExecutionFactory } from "../../kernel/bindings";
23
29
  import { serializeOutput } from "../../lib/artifacts";
24
30
  import type { PiToolCandidate } from "./compiler";
@@ -346,7 +352,10 @@ export function createWorkspaceCodeExecutionFactory(options: {
346
352
  },
347
353
  )
348
354
  : undefined;
349
- const createPort = (innerResults: AgentToolResult<unknown>[]) => {
355
+ const createPort = (
356
+ innerResults: AgentToolResult<unknown>[],
357
+ stateOptions: Pick<CreateExecuteToolOptions, "state" | "connectors">,
358
+ ) => {
350
359
  let nestedCallOrdinal = 0;
351
360
  const { tool } = createExecuteRuntime({
352
361
  ctx: options.ctx,
@@ -358,7 +367,7 @@ export function createWorkspaceCodeExecutionFactory(options: {
358
367
  onResult: (value) => innerResults.push(value),
359
368
  }),
360
369
  timeout: CODEMODE_SANDBOX_TIMEOUT_MS,
361
- ...(workspaceState ? { connectors: [workspaceState] } : state ? { state } : {}),
370
+ ...stateOptions,
362
371
  name: "execute",
363
372
  });
364
373
  return toCodeExecutionPort(
@@ -370,10 +379,17 @@ export function createWorkspaceCodeExecutionFactory(options: {
370
379
  ),
371
380
  );
372
381
  };
373
- const description = createPort([]).description;
382
+ // Inherit the complete official state description; custom connectors otherwise lose its hints.
383
+ const description = createPort([], state ? { state } : {}).description;
374
384
  return {
375
- description: `${description}\n\n${SPRINGBRAND_CODE_MODE_POLICY}`,
376
- execute: (input) => createPort([]).execute(input),
385
+ description: [
386
+ description,
387
+ ...(workspaceState ? [WORKSPACE_PAGING_INSTRUCTIONS] : []),
388
+ SPRINGBRAND_CODE_MODE_POLICY,
389
+ ].join("\n\n"),
390
+ execute: (input) => createPort(
391
+ [], workspaceState ? { connectors: [workspaceState] } : state ? { state } : {},
392
+ ).execute(input),
377
393
  };
378
394
  },
379
395
  };
@@ -11,6 +11,20 @@ type WorkspaceFilePage =
11
11
  | { kind: "csv"; size: number; nextOffset: number | null; columns: string[] | null; rows: string[][] };
12
12
  `;
13
13
 
14
+ export const WORKSPACE_PAGING_INSTRUCTIONS = `For CSV files, do not make a separate probe read or return page contents. Inspect columns and aggregate rows in the same execution with this loop shape:
15
+
16
+ let page = await state.readFilePage({ path });
17
+ if (!page || page.kind !== "csv") throw new Error("CSV not found");
18
+ const columns = page.columns;
19
+ for (;;) {
20
+ // Aggregate page.rows here. Do not return raw rows.
21
+ if (page.nextOffset === null) break;
22
+ page = await state.readFilePage({ path, offset: page.nextOffset });
23
+ }
24
+ return summary;
25
+
26
+ CSV pages use page.columns and page.rows; never page.data or page.content. Only the first page has columns. Do not use console.log to inspect a page; explicitly return the final summary.`;
27
+
14
28
  type PagedWorkspacePort = WorkspacePort & {
15
29
  readFilePage: NonNullable<WorkspacePort["readFilePage"]>;
16
30
  };
@@ -28,19 +42,7 @@ export class WorkspaceStateConnector extends StateConnector {
28
42
  const base = super.instructions();
29
43
  return `${base}
30
44
 
31
- For CSV files, do not make a separate probe read or return page contents. Inspect columns and aggregate rows in the same execution with this loop shape:
32
-
33
- let page = await state.readFilePage({ path });
34
- if (!page || page.kind !== "csv") throw new Error("CSV not found");
35
- const columns = page.columns;
36
- for (;;) {
37
- // Aggregate page.rows here. Do not return raw rows.
38
- if (page.nextOffset === null) break;
39
- page = await state.readFilePage({ path, offset: page.nextOffset });
40
- }
41
- return summary;
42
-
43
- CSV pages use page.columns and page.rows; never page.data or page.content. Only the first page has columns. Do not use console.log to inspect a page; explicitly return the final summary.`;
45
+ ${WORKSPACE_PAGING_INSTRUCTIONS}`;
44
46
  }
45
47
 
46
48
  protected override tools(): ConnectorTools {
@@ -51,7 +53,7 @@ CSV pages use page.columns and page.rows; never page.data or page.content. Only
51
53
  readFile: {
52
54
  ...readFile,
53
55
  description:
54
- `Read a small non-CSV file as text. CSV and files over ${WORKSPACE_DIRECT_TEXT_READ_MAX_BYTES} bytes must use readFilePage.`,
56
+ `${readFile.description} CSV and files over ${WORKSPACE_DIRECT_TEXT_READ_MAX_BYTES} bytes must use readFilePage.`,
55
57
  execute: async (args, context) => {
56
58
  const path = requiredPath(args, "readFile");
57
59
  const file = await this.workspace.stat(path);