This commit is contained in:
Harivansh Rathi 2026-03-12 02:28:11 -04:00
parent 9115d5647f
commit e19f575229
2 changed files with 114 additions and 66 deletions

View file

@ -62,6 +62,7 @@ export type { HistoryPart } from "./types.js";
let activeGatewayRuntime: GatewayRuntime | null = null; let activeGatewayRuntime: GatewayRuntime | null = null;
type JsonRecord = Record<string, unknown>; type JsonRecord = Record<string, unknown>;
type AssistantAgentMessage = Extract<AgentMessage, { role: "assistant" }>;
type CompanionChannelsSettings = JsonRecord & { type CompanionChannelsSettings = JsonRecord & {
adapters?: Record<string, JsonRecord>; adapters?: Record<string, JsonRecord>;
@ -659,14 +660,15 @@ export class GatewayRuntime {
private emitStructuredParts( private emitStructuredParts(
managedSession: ManagedGatewaySession, managedSession: ManagedGatewaySession,
message: AgentMessage, message: AssistantAgentMessage,
): void { ): void {
const content = message.content; const content = message.content;
if (!Array.isArray(content)) return; if (!Array.isArray(content)) return;
for (const part of content) { for (const part of content) {
if (typeof part !== "object" || part === null) continue; const rawPart: unknown = part;
const p = part as Record<string, unknown>; if (!isRecord(rawPart)) continue;
const p = rawPart;
if (p.type === "teamActivity") { if (p.type === "teamActivity") {
const teamId = typeof p.teamId === "string" ? p.teamId : ""; const teamId = typeof p.teamId === "string" ? p.teamId : "";
@ -722,7 +724,6 @@ export class GatewayRuntime {
message: errorMessage, message: errorMessage,
}, },
}); });
continue;
} }
} }
} }

View file

@ -9,12 +9,47 @@ export interface GatewayTransientToolResult {
timestamp: number; timestamp: number;
} }
type TeamActivityMember = Extract<
HistoryPart,
{ type: "teamActivity" }
>["members"][number];
function isSupportedHistoryRole( function isSupportedHistoryRole(
role: AgentMessage["role"], role: AgentMessage["role"],
): role is "user" | "assistant" | "toolResult" { ): role is "user" | "assistant" | "toolResult" {
return role === "user" || role === "assistant" || role === "toolResult"; return role === "user" || role === "assistant" || role === "toolResult";
} }
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}
function normalizeTeamActivityMembers(value: unknown): TeamActivityMember[] {
if (!Array.isArray(value)) {
return [];
}
return value
.filter(isRecord)
.map((member) => {
const id = typeof member.id === "string" ? member.id : "";
if (!id) {
return null;
}
return {
id,
name: typeof member.name === "string" ? member.name : "Teammate",
...(typeof member.role === "string" ? { role: member.role } : {}),
status: typeof member.status === "string" ? member.status : "running",
...(typeof member.message === "string"
? { message: member.message }
: {}),
};
})
.filter((member): member is TeamActivityMember => member !== null);
}
function historyMessageId(message: AgentMessage, index: number): string { function historyMessageId(message: AgentMessage, index: number): string {
return `${message.timestamp}-${message.role}-${index}`; return `${message.timestamp}-${message.role}-${index}`;
} }
@ -53,73 +88,85 @@ export function messageContentToHistoryParts(msg: AgentMessage): HistoryPart[] {
} }
if (msg.role === "assistant") { if (msg.role === "assistant") {
const content = msg.content; const content: unknown = msg.content;
if (!Array.isArray(content)) return []; if (!Array.isArray(content)) return [];
const parts: HistoryPart[] = []; const parts: HistoryPart[] = [];
for (const contentPart of content) { for (const contentPart of content) {
if (typeof contentPart !== "object" || contentPart === null) { if (!isRecord(contentPart) || typeof contentPart.type !== "string") {
continue; continue;
} }
if (contentPart.type === "text") {
parts.push({ switch (contentPart.type) {
type: "text", case "text":
text: (contentPart as { type: "text"; text: string }).text, if (typeof contentPart.text === "string") {
}); parts.push({
} else if (contentPart.type === "thinking") { type: "text",
parts.push({ text: contentPart.text,
type: "reasoning", });
text: (contentPart as { type: "thinking"; thinking: string }) }
.thinking, break;
}); case "thinking":
} else if (contentPart.type === "toolCall") { if (typeof contentPart.thinking === "string") {
const toolCall = contentPart as { parts.push({
type: "toolCall"; type: "reasoning",
id: string; text: contentPart.thinking,
name: string; });
arguments: unknown; }
}; break;
parts.push({ case "toolCall":
type: "tool-invocation", if (
toolCallId: toolCall.id, typeof contentPart.id === "string" &&
toolName: toolCall.name, typeof contentPart.name === "string"
args: toolCall.arguments, ) {
state: "call", parts.push({
}); type: "tool-invocation",
} else if (contentPart.type === "teamActivity") { toolCallId: contentPart.id,
const activity = contentPart as { toolName: contentPart.name,
type: "teamActivity"; args: contentPart.arguments,
teamId: string; state: "call",
status: string; });
members?: Array<{ id: string; name: string; role?: string; status: string; message?: string }>; }
}; break;
parts.push({ case "teamActivity": {
type: "teamActivity", const teamId =
teamId: activity.teamId, typeof contentPart.teamId === "string" ? contentPart.teamId : "";
status: activity.status, if (!teamId) {
members: Array.isArray(activity.members) ? activity.members : [], break;
}); }
} else if (contentPart.type === "image") { parts.push({
const image = contentPart as { type: "teamActivity",
type: "image"; teamId,
url: string; status:
mimeType?: string; typeof contentPart.status === "string"
}; ? contentPart.status
parts.push({ : "running",
type: "media", members: normalizeTeamActivityMembers(contentPart.members),
url: image.url, });
mimeType: image.mimeType, break;
}); }
} else if (contentPart.type === "error") { case "image":
const error = contentPart as { if (typeof contentPart.url === "string") {
type: "error"; parts.push({
code?: string; type: "media",
message: string; url: contentPart.url,
}; ...(typeof contentPart.mimeType === "string"
parts.push({ ? { mimeType: contentPart.mimeType }
type: "error", : {}),
code: typeof error.code === "string" ? error.code : "unknown", });
message: error.message, }
}); break;
case "error":
if (typeof contentPart.message === "string") {
parts.push({
type: "error",
code:
typeof contentPart.code === "string"
? contentPart.code
: "unknown",
message: contentPart.message,
});
}
break;
} }
} }
return parts; return parts;