fix(FN-2316): harden pi session message normalization
This commit is contained in:
@@ -678,6 +678,124 @@ describe("createFnAgent", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves tool result content when extension hooks only modify metadata", async () => {
|
||||||
|
const originalAfterToolCall = vi.fn().mockResolvedValue({ isError: false });
|
||||||
|
const session = {
|
||||||
|
agent: {
|
||||||
|
afterToolCall: originalAfterToolCall,
|
||||||
|
},
|
||||||
|
prompt: vi.fn(),
|
||||||
|
subscribe: vi.fn(),
|
||||||
|
dispose: vi.fn(),
|
||||||
|
setThinkingLevel: vi.fn(),
|
||||||
|
};
|
||||||
|
createAgentSessionMock.mockResolvedValueOnce({ session });
|
||||||
|
|
||||||
|
const { createFnAgent } = await import("./pi.js");
|
||||||
|
const { session: guardedSession } = await createFnAgent({
|
||||||
|
cwd: "/tmp",
|
||||||
|
systemPrompt: "test",
|
||||||
|
tools: "readonly",
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await (guardedSession as any).agent.afterToolCall({
|
||||||
|
toolCall: { id: "tool-1", name: "read" },
|
||||||
|
args: { path: "file.txt" },
|
||||||
|
result: { content: [{ type: "text", text: "ok" }], details: { source: "tool" } },
|
||||||
|
isError: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
content: [{ type: "text", text: "ok" }],
|
||||||
|
details: { source: "tool" },
|
||||||
|
isError: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("repairs malformed persisted session messages missing content", async () => {
|
||||||
|
const rewriteFile = vi.fn();
|
||||||
|
const sessionManager = {
|
||||||
|
fileEntries: [
|
||||||
|
{ type: "message", message: { role: "toolResult", toolName: "read" } },
|
||||||
|
{ type: "message", message: { role: "assistant", stopReason: "error" } },
|
||||||
|
],
|
||||||
|
_rewriteFile: rewriteFile,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { createFnAgent } = await import("./pi.js");
|
||||||
|
await createFnAgent({
|
||||||
|
cwd: "/tmp",
|
||||||
|
systemPrompt: "test",
|
||||||
|
tools: "readonly",
|
||||||
|
sessionManager: sessionManager as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(sessionManager.fileEntries[0]?.message).toMatchObject({
|
||||||
|
role: "toolResult",
|
||||||
|
content: [],
|
||||||
|
});
|
||||||
|
expect(sessionManager.fileEntries[1]?.message).toMatchObject({
|
||||||
|
role: "assistant",
|
||||||
|
content: [],
|
||||||
|
});
|
||||||
|
expect(rewriteFile).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("normalizes malformed live tool results before persistence and replay", async () => {
|
||||||
|
const listeners: Array<(event: unknown) => void> = [];
|
||||||
|
const stateMessages = [
|
||||||
|
{ role: "toolResult", toolCallId: "call-1", toolName: "read", timestamp: 123 },
|
||||||
|
];
|
||||||
|
const originalAppendMessage = vi.fn();
|
||||||
|
const sessionManager = {
|
||||||
|
fileEntries: [],
|
||||||
|
appendMessage: originalAppendMessage,
|
||||||
|
};
|
||||||
|
const session = {
|
||||||
|
agent: {
|
||||||
|
afterToolCall: vi.fn().mockResolvedValue(undefined),
|
||||||
|
state: {
|
||||||
|
messages: stateMessages,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prompt: vi.fn(),
|
||||||
|
subscribe: vi.fn((listener: (event: unknown) => void) => {
|
||||||
|
listeners.push(listener);
|
||||||
|
return vi.fn();
|
||||||
|
}),
|
||||||
|
dispose: vi.fn(),
|
||||||
|
setThinkingLevel: vi.fn(),
|
||||||
|
};
|
||||||
|
createAgentSessionMock.mockResolvedValueOnce({ session });
|
||||||
|
|
||||||
|
const { createFnAgent } = await import("./pi.js");
|
||||||
|
await createFnAgent({
|
||||||
|
cwd: "/tmp",
|
||||||
|
systemPrompt: "test",
|
||||||
|
tools: "readonly",
|
||||||
|
sessionManager: sessionManager as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
const liveMessage = stateMessages[0]!;
|
||||||
|
listeners[0]?.({ type: "message_end", message: liveMessage });
|
||||||
|
expect(liveMessage).toMatchObject({
|
||||||
|
role: "toolResult",
|
||||||
|
content: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const persistedMessage = {
|
||||||
|
role: "toolResult",
|
||||||
|
toolCallId: "call-1",
|
||||||
|
toolName: "read",
|
||||||
|
timestamp: 123,
|
||||||
|
};
|
||||||
|
sessionManager.appendMessage(persistedMessage as any);
|
||||||
|
expect(originalAppendMessage).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
|
role: "toolResult",
|
||||||
|
content: [],
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
describe("skill selection", () => {
|
describe("skill selection", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Reset modules to ensure fresh imports for each test
|
// Reset modules to ensure fresh imports for each test
|
||||||
|
|||||||
@@ -286,6 +286,117 @@ function readJsonObject(path) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function normalizeSessionHistoryEntries(sessionManager) {
|
||||||
|
const entries = sessionManager.fileEntries;
|
||||||
|
if (!Array.isArray(entries) || entries.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let changed = false;
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry?.type !== "message" || !entry.message || typeof entry.message !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const role = entry.message.role;
|
||||||
|
if (role !== "assistant" && role !== "toolResult") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!("content" in entry.message)) {
|
||||||
|
entry.message.content = [];
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
sessionManager._rewriteFile?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function normalizeAssistantOrToolResultMessage(message) {
|
||||||
|
if (!message || typeof message !== "object") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const role = message.role;
|
||||||
|
if (role !== "assistant" && role !== "toolResult") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(message.content)) {
|
||||||
|
message.content = [];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function syncNormalizedMessageIntoAgentState(session, message) {
|
||||||
|
const messages = session.agent?.state?.messages;
|
||||||
|
if (!Array.isArray(messages) || messages.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
const candidate = messages[i];
|
||||||
|
if (!candidate || typeof candidate !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (candidate === message) {
|
||||||
|
normalizeAssistantOrToolResultMessage(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (candidate.role !== message.role) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (candidate.role === "toolResult") {
|
||||||
|
if (candidate.toolCallId === message.toolCallId && candidate.toolName === message.toolName) {
|
||||||
|
normalizeAssistantOrToolResultMessage(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (candidate.timestamp === message.timestamp) {
|
||||||
|
normalizeAssistantOrToolResultMessage(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function installToolResultContentGuard(session) {
|
||||||
|
if (session.__fusionToolResultGuardInstalled || !session.agent?.afterToolCall) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const originalAfterToolCall = session.agent.afterToolCall.bind(session.agent);
|
||||||
|
session.agent.afterToolCall = async (payload) => {
|
||||||
|
const hookResult = await originalAfterToolCall(payload);
|
||||||
|
if (!hookResult || typeof hookResult !== "object") {
|
||||||
|
return hookResult;
|
||||||
|
}
|
||||||
|
const content = hookResult.content ?? payload.result?.content ?? [];
|
||||||
|
return {
|
||||||
|
content: Array.isArray(content) ? content : [],
|
||||||
|
details: hookResult.details ?? payload.result?.details,
|
||||||
|
isError: hookResult.isError ?? payload.isError,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
session.__fusionToolResultGuardInstalled = true;
|
||||||
|
}
|
||||||
|
function installMessageContentGuard(session, sessionManager) {
|
||||||
|
if (session.__fusionMessageContentGuardInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof session.subscribe === "function") {
|
||||||
|
session.subscribe((event) => {
|
||||||
|
if (!event || typeof event !== "object" || event.type !== "message_end") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const message = event.message;
|
||||||
|
if (!normalizeAssistantOrToolResultMessage(message)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
syncNormalizedMessageIntoAgentState(session, message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (typeof sessionManager.appendMessage === "function") {
|
||||||
|
const originalAppendMessage = sessionManager.appendMessage.bind(sessionManager);
|
||||||
|
sessionManager.appendMessage = (message) => {
|
||||||
|
normalizeAssistantOrToolResultMessage(message);
|
||||||
|
syncNormalizedMessageIntoAgentState(session, message);
|
||||||
|
return originalAppendMessage(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
session.__fusionMessageContentGuardInstalled = true;
|
||||||
|
}
|
||||||
function hasPackageManagerSettings(settings) {
|
function hasPackageManagerSettings(settings) {
|
||||||
return Array.isArray(settings.packages) || Array.isArray(settings.npmCommand);
|
return Array.isArray(settings.packages) || Array.isArray(settings.npmCommand);
|
||||||
}
|
}
|
||||||
@@ -572,6 +683,7 @@ export async function createFnAgent(options) {
|
|||||||
});
|
});
|
||||||
await resourceLoader.reload();
|
await resourceLoader.reload();
|
||||||
const sessionManager = options.sessionManager ?? SessionManager.inMemory();
|
const sessionManager = options.sessionManager ?? SessionManager.inMemory();
|
||||||
|
normalizeSessionHistoryEntries(sessionManager);
|
||||||
const createSessionWithModel = async (modelOverride) => {
|
const createSessionWithModel = async (modelOverride) => {
|
||||||
return createAgentSession({
|
return createAgentSession({
|
||||||
cwd: options.cwd,
|
cwd: options.cwd,
|
||||||
@@ -602,6 +714,8 @@ export async function createFnAgent(options) {
|
|||||||
piLog.log("Fallback session created successfully");
|
piLog.log("Fallback session created successfully");
|
||||||
}
|
}
|
||||||
const { session } = sessionResult;
|
const { session } = sessionResult;
|
||||||
|
installToolResultContentGuard(session);
|
||||||
|
installMessageContentGuard(session, sessionManager);
|
||||||
session.__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
session.__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
||||||
const promptableSession = session;
|
const promptableSession = session;
|
||||||
promptableSession.promptWithFallback = async (prompt, promptOptions) => {
|
promptableSession.promptWithFallback = async (prompt, promptOptions) => {
|
||||||
@@ -657,6 +771,8 @@ export async function createFnAgent(options) {
|
|||||||
}
|
}
|
||||||
const fallbackSessionResult = await createSessionWithModel(fallbackModel);
|
const fallbackSessionResult = await createSessionWithModel(fallbackModel);
|
||||||
const fallbackSession = fallbackSessionResult.session;
|
const fallbackSession = fallbackSessionResult.session;
|
||||||
|
installToolResultContentGuard(fallbackSession);
|
||||||
|
installMessageContentGuard(fallbackSession, sessionManager);
|
||||||
fallbackSession.__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
fallbackSession.__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
||||||
if (options.defaultThinkingLevel) {
|
if (options.defaultThinkingLevel) {
|
||||||
fallbackSession.setThinkingLevel(options.defaultThinkingLevel);
|
fallbackSession.setThinkingLevel(options.defaultThinkingLevel);
|
||||||
@@ -747,4 +863,4 @@ export async function createFnAgent(options) {
|
|||||||
});
|
});
|
||||||
return { session: promptableSession, sessionFile: promptableSession.sessionFile };
|
return { session: promptableSession, sessionFile: promptableSession.sessionFile };
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=pi.js.map
|
//# sourceMappingURL=pi.js.map
|
||||||
|
|||||||
@@ -46,6 +46,36 @@ export interface PromptableSession extends AgentSession {
|
|||||||
promptWithFallback: (prompt: string, options?: unknown) => Promise<void>;
|
promptWithFallback: (prompt: string, options?: unknown) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SessionManagerLike {
|
||||||
|
fileEntries?: Array<{ type?: string; message?: Record<string, unknown> }>;
|
||||||
|
appendMessage?: (message: Record<string, unknown>) => void;
|
||||||
|
_rewriteFile?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToolHookPayload {
|
||||||
|
toolCall: unknown;
|
||||||
|
args: unknown;
|
||||||
|
result: { content?: unknown; details?: unknown };
|
||||||
|
isError: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToolHookResult {
|
||||||
|
content?: unknown;
|
||||||
|
details?: unknown;
|
||||||
|
isError?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentToolHookSession = AgentSession & {
|
||||||
|
agent?: {
|
||||||
|
afterToolCall?: (payload: ToolHookPayload) => Promise<ToolHookResult | undefined>;
|
||||||
|
state?: {
|
||||||
|
messages?: Array<Record<string, unknown>>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
__fusionToolResultGuardInstalled?: boolean;
|
||||||
|
__fusionMessageContentGuardInstalled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
function getSessionStateError(session: AgentSession): string {
|
function getSessionStateError(session: AgentSession): string {
|
||||||
const state = (session as any).state;
|
const state = (session as any).state;
|
||||||
const error = state?.errorMessage ?? state?.error;
|
const error = state?.errorMessage ?? state?.error;
|
||||||
@@ -414,6 +444,137 @@ function readJsonObject(path: string): Record<string, any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeSessionHistoryEntries(sessionManager: SessionManagerLike): void {
|
||||||
|
const entries = sessionManager.fileEntries;
|
||||||
|
if (!Array.isArray(entries) || entries.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let changed = false;
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry?.type !== "message" || !entry.message || typeof entry.message !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const role = entry.message.role;
|
||||||
|
if (role !== "assistant" && role !== "toolResult") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!("content" in entry.message)) {
|
||||||
|
entry.message.content = [];
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
sessionManager._rewriteFile?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAssistantOrToolResultMessage(message: unknown): message is Record<string, unknown> {
|
||||||
|
if (!message || typeof message !== "object") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const role = (message as Record<string, unknown>).role;
|
||||||
|
if (role !== "assistant" && role !== "toolResult") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray((message as Record<string, unknown>).content)) {
|
||||||
|
(message as Record<string, unknown>).content = [];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncNormalizedMessageIntoAgentState(session: AgentToolHookSession, message: Record<string, unknown>): void {
|
||||||
|
const messages = session.agent?.state?.messages;
|
||||||
|
if (!Array.isArray(messages) || messages.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
const candidate = messages[i];
|
||||||
|
if (!candidate || typeof candidate !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (candidate === message) {
|
||||||
|
normalizeAssistantOrToolResultMessage(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate.role !== message.role) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate.role === "toolResult") {
|
||||||
|
if (candidate.toolCallId === message.toolCallId && candidate.toolName === message.toolName) {
|
||||||
|
normalizeAssistantOrToolResultMessage(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate.timestamp === message.timestamp) {
|
||||||
|
normalizeAssistantOrToolResultMessage(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function installToolResultContentGuard(session: AgentToolHookSession): void {
|
||||||
|
if (session.__fusionToolResultGuardInstalled || !session.agent?.afterToolCall) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalAfterToolCall = session.agent.afterToolCall.bind(session.agent) as any;
|
||||||
|
(session.agent as any).afterToolCall = async (payload: ToolHookPayload) => {
|
||||||
|
const hookResult = await originalAfterToolCall(payload);
|
||||||
|
if (!hookResult || typeof hookResult !== "object") {
|
||||||
|
return hookResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = hookResult.content ?? payload.result?.content ?? [];
|
||||||
|
return {
|
||||||
|
content: Array.isArray(content) ? content : [],
|
||||||
|
details: hookResult.details ?? payload.result?.details,
|
||||||
|
isError: hookResult.isError ?? payload.isError,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
session.__fusionToolResultGuardInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function installMessageContentGuard(session: AgentToolHookSession, sessionManager: SessionManagerLike): void {
|
||||||
|
if (session.__fusionMessageContentGuardInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof session.subscribe === "function") {
|
||||||
|
session.subscribe((event: unknown) => {
|
||||||
|
if (!event || typeof event !== "object" || (event as { type?: string }).type !== "message_end") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = (event as { message?: unknown }).message;
|
||||||
|
if (!normalizeAssistantOrToolResultMessage(message)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncNormalizedMessageIntoAgentState(session, message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof sessionManager.appendMessage === "function") {
|
||||||
|
const originalAppendMessage = sessionManager.appendMessage.bind(sessionManager);
|
||||||
|
sessionManager.appendMessage = (message: Record<string, unknown>) => {
|
||||||
|
normalizeAssistantOrToolResultMessage(message);
|
||||||
|
syncNormalizedMessageIntoAgentState(session, message);
|
||||||
|
return originalAppendMessage(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
session.__fusionMessageContentGuardInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
function hasPackageManagerSettings(settings: Record<string, any>): boolean {
|
function hasPackageManagerSettings(settings: Record<string, any>): boolean {
|
||||||
return Array.isArray(settings.packages) || Array.isArray(settings.npmCommand);
|
return Array.isArray(settings.packages) || Array.isArray(settings.npmCommand);
|
||||||
}
|
}
|
||||||
@@ -760,6 +921,7 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
|
|||||||
await resourceLoader.reload();
|
await resourceLoader.reload();
|
||||||
|
|
||||||
const sessionManager = options.sessionManager ?? SessionManager.inMemory();
|
const sessionManager = options.sessionManager ?? SessionManager.inMemory();
|
||||||
|
normalizeSessionHistoryEntries(sessionManager as unknown as SessionManagerLike);
|
||||||
|
|
||||||
const createSessionWithModel = async (modelOverride?: typeof selectedModel) => {
|
const createSessionWithModel = async (modelOverride?: typeof selectedModel) => {
|
||||||
// pi-coding-agent 0.68+: `tools` is a string[] allowlist of tool names, not
|
// pi-coding-agent 0.68+: `tools` is a string[] allowlist of tool names, not
|
||||||
@@ -801,6 +963,8 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { session } = sessionResult;
|
const { session } = sessionResult;
|
||||||
|
installToolResultContentGuard(session as AgentToolHookSession);
|
||||||
|
installMessageContentGuard(session as AgentToolHookSession, sessionManager as unknown as SessionManagerLike);
|
||||||
(session as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
(session as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
||||||
const promptableSession = session as PromptableSession;
|
const promptableSession = session as PromptableSession;
|
||||||
|
|
||||||
@@ -857,6 +1021,11 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
|
|||||||
|
|
||||||
const fallbackSessionResult = await createSessionWithModel(fallbackModel);
|
const fallbackSessionResult = await createSessionWithModel(fallbackModel);
|
||||||
const fallbackSession = fallbackSessionResult.session as PromptableSession;
|
const fallbackSession = fallbackSessionResult.session as PromptableSession;
|
||||||
|
installToolResultContentGuard(fallbackSession as unknown as AgentToolHookSession);
|
||||||
|
installMessageContentGuard(
|
||||||
|
fallbackSession as unknown as AgentToolHookSession,
|
||||||
|
sessionManager as unknown as SessionManagerLike,
|
||||||
|
);
|
||||||
(fallbackSession as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
(fallbackSession as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === "memory_append") === true;
|
||||||
|
|
||||||
if (options.defaultThinkingLevel) {
|
if (options.defaultThinkingLevel) {
|
||||||
|
|||||||
Reference in New Issue
Block a user