@aexhq/agentloop-pi 5.0.0 → 6.0.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/README.md CHANGED
@@ -48,10 +48,16 @@ Transcript changes and `ctx.kv.read/put/delete` use Brain's state services. KV m
48
48
  committed inline; missing keys remain distinct from stored JSON null. A later model or
49
49
  Tool failure preserves acknowledged writes; turn output contains only the result. Retained
50
50
  native model blocks pass through unchanged, and user images enter model context as media.
51
+ Version 5.1 also presents successful Tool outputs shaped as
52
+ `{ type: "aex_tool_output", version: 1, content, media: [{ type: "image", url }] }`
53
+ as Tool-result content and image media. Browser and MCP extensions use this presentation
54
+ convention; ordinary JSON results keep their existing behavior.
51
55
  Compaction explicitly resets the response format and installs a summary only after `end_turn`;
52
56
  a truncated, refused, or unknown summary leaves the original saved context intact.
53
57
 
54
- Rebuild Components against the matching Brain WIT when upgrading. Existing sessions keep their
55
- immutable loop implementation. Keep their matching server/artifacts for recovery and create
56
- new sessions explicitly when adopting Brain 0.20 / version 5 extensions; do not delete old data
57
- as an implicit upgrade step.
58
+ Version 5.1 targets Brain 0.22 and preserves the existing WIT. Existing sessions keep their
59
+ immutable loop implementation; create new sessions to adopt the updated loop. Keep matching
60
+ server/artifacts for recovery. An upgrade does not migrate or delete session data.
61
+
62
+ Image and PDF blocks remain native media in compaction requests. The JSON-length estimate used
63
+ for new context does not measure image/PDF tokens; provider context-limit failures remain explicit.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexhq/agentloop-pi",
3
- "version": "5.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "Pi-style parallel-Tool Brain extension",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,7 +35,7 @@
35
35
  "prepack": "npm run build"
36
36
  },
37
37
  "dependencies": {
38
- "@aexhq/brain": "0.20.0",
38
+ "@aexhq/brain": "0.23.0",
39
39
  "zod": "4.4.3"
40
40
  },
41
41
  "devDependencies": {}
package/src/logic.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { toolPlacement } from "../../../shared/tool-placement.mjs";
2
2
  import { observeEvents } from "../../../shared/loop-events.mjs";
3
+ import { toolResult } from "../../../shared/tool-output.mjs";
3
4
 
4
5
  const CHECKPOINT_PREFIX = "Context checkpoint from earlier in this conversation:\n\n";
5
6
 
@@ -46,9 +47,9 @@ const blockText = (block) => {
46
47
  if (block.type === "text") return block.text;
47
48
  if (block.type === "tool_use") return `[tool_use ${block.name}] ${JSON.stringify(block.input)}`;
48
49
  if (block.type === "native") return `[provider continuation state: ${block.format}]`;
49
- if (block.type === "image") return block.url.startsWith("https://") ? `[image ${block.url}]` : "[embedded image]";
50
+ if (block.type === "image" || block.type === "file") return `[${block.type} ${block.url}]`;
50
51
  const output = typeof block.content === "string" ? block.content : JSON.stringify(block.content);
51
- return `[tool_result${block.is_error ? " (error)" : ""}] ${output.length > 2000 ? `${output.slice(0, 2000)}…` : output}`;
52
+ return `[tool_result${block.is_error ? " (error)" : ""}] ${output.length > 2000 ? `${output.slice(0, 2000)}…` : output}`;
52
53
  };
53
54
 
54
55
  const serializeConversation = (messages) =>
@@ -93,7 +94,7 @@ export async function runPi(input, context) {
93
94
  const { message, stop_reason } = await context.model({
94
95
  response_format: null,
95
96
  tools: [],
96
- messages: [{ role: "user", content: [{ type: "text", text: `${previous}${serializeConversation(messages.slice(0, cut))}\n\n${prompt}` }] }],
97
+ messages: [{ role: "user", content: [{ type: "text", text: `${previous}${serializeConversation(messages.slice(0, cut))}\n\n${prompt}` }, ...messages.slice(0, cut).flatMap(message => message.content.flatMap(block => block.type === "image" || block.type === "file" ? [block] : block.type === "tool_result" ? block.media ?? [] : []))] }],
97
98
  });
98
99
  if (stop_reason !== "end_turn") throw new Error(`Compaction did not complete: ${stop_reason}`);
99
100
  checkpoint.summary = text(message);
@@ -132,15 +133,7 @@ export async function runPi(input, context) {
132
133
  const byCall = new Map(results.map((result) => [result.call_id, result]));
133
134
  transcript.push({
134
135
  role: "user",
135
- content: calls.map(({ call_id }) => {
136
- const result = byCall.get(call_id);
137
- return {
138
- type: "tool_result",
139
- tool_use_id: call_id,
140
- content: result === undefined ? "Tool produced no result." : result.output,
141
- is_error: result === undefined ? true : result.is_error,
142
- };
143
- }),
136
+ content: calls.map(({ call_id }) => toolResult(call_id, byCall.get(call_id))),
144
137
  });
145
138
  }
146
139
  }