mirror of
https://github.com/harivansh-afk/clanker-agent.git
synced 2026-04-16 15:02:35 +00:00
single chat sot
This commit is contained in:
parent
aa70afbd7e
commit
e4ee3e64f4
6 changed files with 443 additions and 84 deletions
195
packages/coding-agent/src/core/gateway/session-state.ts
Normal file
195
packages/coding-agent/src/core/gateway/session-state.ts
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||
import type { HistoryMessage, HistoryPart } from "./types.js";
|
||||
|
||||
export interface GatewayTransientToolResult {
|
||||
toolCallId: string;
|
||||
toolName: string;
|
||||
result: unknown;
|
||||
isError: boolean;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
function isSupportedHistoryRole(
|
||||
role: AgentMessage["role"],
|
||||
): role is "user" | "assistant" | "toolResult" {
|
||||
return role === "user" || role === "assistant" || role === "toolResult";
|
||||
}
|
||||
|
||||
function historyMessageId(message: AgentMessage, index: number): string {
|
||||
return `${message.timestamp}-${message.role}-${index}`;
|
||||
}
|
||||
|
||||
function transientAssistantId(
|
||||
sessionKey: string,
|
||||
message: AgentMessage | null,
|
||||
): string {
|
||||
return `draft:${sessionKey}:${message?.timestamp ?? 0}`;
|
||||
}
|
||||
|
||||
function transientToolResultId(sessionKey: string, toolCallId: string): string {
|
||||
return `draft-tool:${sessionKey}:${toolCallId}`;
|
||||
}
|
||||
|
||||
export function messageContentToHistoryParts(msg: AgentMessage): HistoryPart[] {
|
||||
if (msg.role === "user") {
|
||||
const content = msg.content;
|
||||
if (typeof content === "string") {
|
||||
return [{ type: "text", text: content }];
|
||||
}
|
||||
if (Array.isArray(content)) {
|
||||
return content
|
||||
.filter(
|
||||
(contentPart): contentPart is { type: "text"; text: string } =>
|
||||
typeof contentPart === "object" &&
|
||||
contentPart !== null &&
|
||||
contentPart.type === "text",
|
||||
)
|
||||
.map((contentPart) => ({
|
||||
type: "text" as const,
|
||||
text: contentPart.text,
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
if (msg.role === "assistant") {
|
||||
const content = msg.content;
|
||||
if (!Array.isArray(content)) return [];
|
||||
const parts: HistoryPart[] = [];
|
||||
for (const contentPart of content) {
|
||||
if (typeof contentPart !== "object" || contentPart === null) {
|
||||
continue;
|
||||
}
|
||||
if (contentPart.type === "text") {
|
||||
parts.push({
|
||||
type: "text",
|
||||
text: (contentPart as { type: "text"; text: string }).text,
|
||||
});
|
||||
} else if (contentPart.type === "thinking") {
|
||||
parts.push({
|
||||
type: "reasoning",
|
||||
text: (contentPart as { type: "thinking"; thinking: string })
|
||||
.thinking,
|
||||
});
|
||||
} else if (contentPart.type === "toolCall") {
|
||||
const toolCall = contentPart as {
|
||||
type: "toolCall";
|
||||
id: string;
|
||||
name: string;
|
||||
arguments: unknown;
|
||||
};
|
||||
parts.push({
|
||||
type: "tool-invocation",
|
||||
toolCallId: toolCall.id,
|
||||
toolName: toolCall.name,
|
||||
args: toolCall.arguments,
|
||||
state: "call",
|
||||
});
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
if (msg.role === "toolResult") {
|
||||
const toolResult = msg as {
|
||||
role: "toolResult";
|
||||
toolCallId: string;
|
||||
toolName: string;
|
||||
content: unknown;
|
||||
isError: boolean;
|
||||
};
|
||||
const textParts = Array.isArray(toolResult.content)
|
||||
? (toolResult.content as { type: string; text?: string }[])
|
||||
.filter((contentPart) => {
|
||||
return (
|
||||
contentPart.type === "text" &&
|
||||
typeof contentPart.text === "string"
|
||||
);
|
||||
})
|
||||
.map((contentPart) => contentPart.text as string)
|
||||
.join("")
|
||||
: "";
|
||||
|
||||
return [
|
||||
{
|
||||
type: "tool-invocation",
|
||||
toolCallId: toolResult.toolCallId,
|
||||
toolName: toolResult.toolName,
|
||||
args: undefined,
|
||||
state: toolResult.isError ? "error" : "result",
|
||||
result: textParts,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export function buildGatewaySessionStateMessages(params: {
|
||||
sessionKey: string;
|
||||
rawMessages: AgentMessage[];
|
||||
activeAssistantMessage: AgentMessage | null;
|
||||
pendingToolResults: GatewayTransientToolResult[];
|
||||
}): HistoryMessage[] {
|
||||
const {
|
||||
sessionKey,
|
||||
rawMessages,
|
||||
activeAssistantMessage,
|
||||
pendingToolResults,
|
||||
} = params;
|
||||
const messages: HistoryMessage[] = [];
|
||||
const persistedToolCallIds = new Set<string>();
|
||||
|
||||
for (const [index, message] of rawMessages.entries()) {
|
||||
if (!isSupportedHistoryRole(message.role)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
message.role === "toolResult" &&
|
||||
typeof (message as { toolCallId?: unknown }).toolCallId === "string"
|
||||
) {
|
||||
persistedToolCallIds.add((message as { toolCallId: string }).toolCallId);
|
||||
}
|
||||
|
||||
messages.push({
|
||||
id: historyMessageId(message, index),
|
||||
role: message.role,
|
||||
parts: messageContentToHistoryParts(message),
|
||||
timestamp: message.timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
if (activeAssistantMessage?.role === "assistant") {
|
||||
messages.push({
|
||||
id: transientAssistantId(sessionKey, activeAssistantMessage),
|
||||
role: "assistant",
|
||||
parts: messageContentToHistoryParts(activeAssistantMessage),
|
||||
timestamp: activeAssistantMessage.timestamp ?? Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
for (const pendingToolResult of pendingToolResults) {
|
||||
if (persistedToolCallIds.has(pendingToolResult.toolCallId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
messages.push({
|
||||
id: transientToolResultId(sessionKey, pendingToolResult.toolCallId),
|
||||
role: "toolResult",
|
||||
parts: [
|
||||
{
|
||||
type: "tool-invocation",
|
||||
toolCallId: pendingToolResult.toolCallId,
|
||||
toolName: pendingToolResult.toolName,
|
||||
args: undefined,
|
||||
state: pendingToolResult.isError ? "error" : "result",
|
||||
result: pendingToolResult.result,
|
||||
},
|
||||
],
|
||||
timestamp: pendingToolResult.timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue