feat(ai): add shared contentText utility (#6840)
Co-authored-by: Armin Ronacher <armin.ronacher@active-4.com>
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
import type { AssistantMessage, ImageContent, Model, Models, UserMessage } from "@earendil-works/pi-ai";
|
||||
import {
|
||||
type AssistantMessage,
|
||||
contentText,
|
||||
type ImageContent,
|
||||
type Model,
|
||||
type Models,
|
||||
type UserMessage,
|
||||
} from "@earendil-works/pi-ai";
|
||||
import { runAgentLoop } from "../agent-loop.ts";
|
||||
import type {
|
||||
AgentContext,
|
||||
@@ -781,23 +788,10 @@ export class AgentHarness<
|
||||
let newLeafId: string | null;
|
||||
if (targetEntry.type === "message" && targetEntry.message.role === "user") {
|
||||
newLeafId = targetEntry.parentId;
|
||||
const content = targetEntry.message.content;
|
||||
editorText =
|
||||
typeof content === "string"
|
||||
? content
|
||||
: content
|
||||
.filter((c): c is { readonly type: "text"; readonly text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("");
|
||||
editorText = contentText(targetEntry.message.content, "");
|
||||
} else if (targetEntry.type === "custom_message") {
|
||||
newLeafId = targetEntry.parentId;
|
||||
editorText =
|
||||
typeof targetEntry.content === "string"
|
||||
? targetEntry.content
|
||||
: targetEntry.content
|
||||
.filter((c): c is { readonly type: "text"; readonly text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("");
|
||||
editorText = contentText(targetEntry.content, "");
|
||||
} else {
|
||||
newLeafId = targetId;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Model, Models } from "@earendil-works/pi-ai";
|
||||
import { contentText, type Model, type Models } from "@earendil-works/pi-ai";
|
||||
|
||||
import type { AgentMessage } from "../../types.ts";
|
||||
import {
|
||||
@@ -245,10 +245,7 @@ export async function generateBranchSummary(
|
||||
);
|
||||
}
|
||||
|
||||
let summary = response.content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n");
|
||||
let summary = contentText(response.content);
|
||||
summary = BRANCH_SUMMARY_PREAMBLE + summary;
|
||||
const { readFiles, modifiedFiles } = computeFileLists(fileOps);
|
||||
summary += formatFileOperations(readFiles, modifiedFiles);
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import type { AssistantMessage, ImageContent, Model, Models, TextContent, Usage } from "@earendil-works/pi-ai";
|
||||
import {
|
||||
type AssistantMessage,
|
||||
contentText,
|
||||
type ImageContent,
|
||||
type Model,
|
||||
type Models,
|
||||
type TextContent,
|
||||
type Usage,
|
||||
} from "@earendil-works/pi-ai";
|
||||
import type { AgentMessage, ThinkingLevel } from "../../types.ts";
|
||||
import {
|
||||
convertToLlm,
|
||||
@@ -513,10 +521,7 @@ export async function generateSummary(
|
||||
);
|
||||
}
|
||||
|
||||
const textContent = response.content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n");
|
||||
const textContent = contentText(response.content);
|
||||
|
||||
return ok(textContent);
|
||||
}
|
||||
@@ -744,10 +749,5 @@ async function generateTurnPrefixSummary(
|
||||
);
|
||||
}
|
||||
|
||||
return ok(
|
||||
response.content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n"),
|
||||
);
|
||||
return ok(contentText(response.content));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Message } from "@earendil-works/pi-ai";
|
||||
import { contentText, type Message } from "@earendil-works/pi-ai";
|
||||
import type { AgentMessage } from "../../types.ts";
|
||||
|
||||
/** File paths touched by a session branch or compaction range. */
|
||||
@@ -93,23 +93,14 @@ export function serializeConversation(messages: Message[]): string {
|
||||
|
||||
for (const msg of messages) {
|
||||
if (msg.role === "user") {
|
||||
const content =
|
||||
typeof msg.content === "string"
|
||||
? msg.content
|
||||
: msg.content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("");
|
||||
const content = contentText(msg.content, "");
|
||||
if (content) parts.push(`[User]: ${content}`);
|
||||
} else if (msg.role === "assistant") {
|
||||
const textParts: string[] = [];
|
||||
const thinkingParts: string[] = [];
|
||||
const toolCalls: string[] = [];
|
||||
|
||||
for (const block of msg.content) {
|
||||
if (block.type === "text") {
|
||||
textParts.push(block.text);
|
||||
} else if (block.type === "thinking") {
|
||||
if (block.type === "thinking") {
|
||||
thinkingParts.push(block.thinking);
|
||||
} else if (block.type === "toolCall") {
|
||||
const args = block.arguments as Record<string, unknown>;
|
||||
@@ -123,17 +114,14 @@ export function serializeConversation(messages: Message[]): string {
|
||||
if (thinkingParts.length > 0) {
|
||||
parts.push(`[Assistant thinking]: ${thinkingParts.join("\n")}`);
|
||||
}
|
||||
if (textParts.length > 0) {
|
||||
parts.push(`[Assistant]: ${textParts.join("\n")}`);
|
||||
if (msg.content.some((block) => block.type === "text")) {
|
||||
parts.push(`[Assistant]: ${contentText(msg.content)}`);
|
||||
}
|
||||
if (toolCalls.length > 0) {
|
||||
parts.push(`[Assistant tool calls]: ${toolCalls.join("; ")}`);
|
||||
}
|
||||
} else if (msg.role === "toolResult") {
|
||||
const content = msg.content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("");
|
||||
const content = contentText(msg.content, "");
|
||||
if (content) {
|
||||
parts.push(`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user