GigaChat: preserve TLS overrides and tool results
This commit is contained in:
parent
c8e449f5c8
commit
e909e4e926
@ -641,6 +641,73 @@ describe("createGigachatStreamFn tool calling", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves historical tool results as plain text when functions are disabled", async () => {
|
||||
vi.stubEnv("GIGACHAT_DISABLE_FUNCTIONS", "1");
|
||||
request.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: createSseStream(['data: {"choices":[{"delta":{"content":"done"}}]}', "data: [DONE]"]),
|
||||
});
|
||||
|
||||
const streamFn = createGigachatStreamFn({
|
||||
baseUrl: "https://gigachat.devices.sberbank.ru/api/v1",
|
||||
authMode: "oauth",
|
||||
});
|
||||
|
||||
const stream = await streamFn(
|
||||
{ api: "gigachat", provider: "gigachat", id: "GigaChat-2-Max" } as never,
|
||||
{
|
||||
messages: [
|
||||
{
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "toolCall",
|
||||
id: "call_1",
|
||||
name: "llm-task",
|
||||
arguments: { prompt: "hi" },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "toolResult",
|
||||
toolName: "llm-task",
|
||||
content: '{"summary":"tool output"}',
|
||||
},
|
||||
],
|
||||
tools: [
|
||||
{
|
||||
name: "llm-task",
|
||||
description: "Run a task",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
prompt: { type: "string" },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
} as never,
|
||||
{ apiKey: "token" } as never,
|
||||
);
|
||||
|
||||
await expect(stream.result()).resolves.toMatchObject({
|
||||
content: [{ type: "text", text: "done" }],
|
||||
});
|
||||
|
||||
const requestPayload = request.mock.calls[0]?.[0]?.data as {
|
||||
messages?: Array<{ role: string; content?: string }>;
|
||||
functions?: unknown;
|
||||
};
|
||||
expect(requestPayload.functions).toBeUndefined();
|
||||
expect(requestPayload.messages).toEqual([
|
||||
expect.objectContaining({ role: "assistant", content: "[Called llm-task]" }),
|
||||
expect.objectContaining({
|
||||
role: "user",
|
||||
content: '[Tool Result: llm-task]\n{"summary":"tool output"}',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("preserves all historical tool calls from a single assistant turn", async () => {
|
||||
request.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
|
||||
@ -296,6 +296,24 @@ function sanitizeContent(content: string | null | undefined): string {
|
||||
);
|
||||
}
|
||||
|
||||
function extractToolResultTextContent(content: unknown): string {
|
||||
if (Array.isArray(content)) {
|
||||
return content
|
||||
.filter((c): c is TextContent => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n");
|
||||
}
|
||||
if (typeof content === "string") {
|
||||
return content;
|
||||
}
|
||||
return JSON.stringify(content ?? {});
|
||||
}
|
||||
|
||||
function formatToolResultReplayText(toolName: string | undefined, content: unknown): string {
|
||||
const replayContent = extractToolResultTextContent(content) || "ok";
|
||||
return `[Tool Result: ${toolName?.trim() || "unknown"}]\n${replayContent}`;
|
||||
}
|
||||
|
||||
function tryParseJsonObjectString(content: string): string | null {
|
||||
const trimmed = content.trim();
|
||||
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
||||
@ -776,24 +794,27 @@ export function createGigachatStreamFn(opts: GigachatStreamOptions): StreamFn {
|
||||
content: toolCalls.map((toolCall) => `[Called ${toolCall.name}]`).join(" "),
|
||||
});
|
||||
}
|
||||
} else if (msg.role === "toolResult" && functionsEnabled) {
|
||||
} else if (msg.role === "toolResult") {
|
||||
const toolName = msg.toolName ?? "unknown";
|
||||
const msgContent = msg.content;
|
||||
const resultContent = Array.isArray(msgContent)
|
||||
? msgContent
|
||||
.filter((c): c is TextContent => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n")
|
||||
: typeof msgContent === "string"
|
||||
? msgContent
|
||||
: JSON.stringify(msgContent ?? {});
|
||||
const coercedContent = ensureJsonObjectStr(resultContent || "ok", toolName);
|
||||
const gigaToolName = rememberToolNameMapping(toolNameToGiga, gigaToToolName, toolName);
|
||||
messages.push({
|
||||
role: "function",
|
||||
content: coercedContent,
|
||||
name: gigaToolName,
|
||||
});
|
||||
if (functionsEnabled) {
|
||||
const resultContent = extractToolResultTextContent(msg.content);
|
||||
const coercedContent = ensureJsonObjectStr(resultContent || "ok", toolName);
|
||||
const gigaToolName = rememberToolNameMapping(
|
||||
toolNameToGiga,
|
||||
gigaToToolName,
|
||||
toolName,
|
||||
);
|
||||
messages.push({
|
||||
role: "function",
|
||||
content: coercedContent,
|
||||
name: gigaToolName,
|
||||
});
|
||||
} else {
|
||||
messages.push({
|
||||
role: "user",
|
||||
content: sanitizeContent(formatToolResultReplayText(toolName, msg.content)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -165,7 +165,6 @@ export async function applyAuthChoiceApiProviders(
|
||||
{ secretInputMode: mode ?? requestedSecretInputMode },
|
||||
{
|
||||
authMode: "oauth",
|
||||
insecureTls: "false",
|
||||
scope: gigachatScope,
|
||||
},
|
||||
);
|
||||
@ -248,7 +247,6 @@ export async function applyAuthChoiceApiProviders(
|
||||
|
||||
const basicMetadata: Record<string, string> = {
|
||||
authMode: "basic",
|
||||
insecureTls: "false",
|
||||
...(gigachatBasicScope ? { scope: gigachatBasicScope } : {}),
|
||||
};
|
||||
|
||||
|
||||
@ -342,10 +342,10 @@ describe("applyAuthChoice", () => {
|
||||
key: "basic-user:basic-pass",
|
||||
metadata: {
|
||||
authMode: "basic",
|
||||
insecureTls: "false",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
},
|
||||
});
|
||||
expect((await readAuthProfile("gigachat:default"))?.metadata).not.toHaveProperty("insecureTls");
|
||||
expect((await readAuthProfile("gigachat:default"))?.keyRef).toBeUndefined();
|
||||
});
|
||||
|
||||
@ -376,7 +376,6 @@ describe("applyAuthChoice", () => {
|
||||
expect(await readAuthProfile("gigachat:default")).toMatchObject({
|
||||
metadata: {
|
||||
authMode: "basic",
|
||||
insecureTls: "false",
|
||||
scope: "GIGACHAT_API_B2B",
|
||||
},
|
||||
});
|
||||
@ -447,9 +446,9 @@ describe("applyAuthChoice", () => {
|
||||
metadata: {
|
||||
authMode: "oauth",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
insecureTls: "false",
|
||||
},
|
||||
});
|
||||
expect(profile?.metadata).not.toHaveProperty("insecureTls");
|
||||
});
|
||||
|
||||
it("resets a custom Basic GigaChat base URL when switching to OAuth", async () => {
|
||||
@ -497,7 +496,6 @@ describe("applyAuthChoice", () => {
|
||||
metadata: {
|
||||
authMode: "oauth",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
insecureTls: "false",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@ -377,9 +377,12 @@ describe("onboard (non-interactive): provider auth", () => {
|
||||
metadata: {
|
||||
authMode: "oauth",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
insecureTls: "false",
|
||||
},
|
||||
});
|
||||
const gigachatProfile = cfg.auth?.profiles?.["gigachat:default"] as
|
||||
| { metadata?: Record<string, string> }
|
||||
| undefined;
|
||||
expect(gigachatProfile?.metadata).not.toHaveProperty("insecureTls");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -168,7 +168,6 @@ describe("applySimpleNonInteractiveApiKeyChoice", () => {
|
||||
undefined,
|
||||
{
|
||||
authMode: "oauth",
|
||||
insecureTls: "false",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
},
|
||||
);
|
||||
@ -282,7 +281,6 @@ describe("applySimpleNonInteractiveApiKeyChoice", () => {
|
||||
undefined,
|
||||
{
|
||||
authMode: "oauth",
|
||||
insecureTls: "false",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
},
|
||||
);
|
||||
|
||||
@ -98,7 +98,6 @@ async function applyGigachatNonInteractiveApiKeyChoice(params: {
|
||||
!(await params.maybeSetResolvedApiKey(resolved, (value) =>
|
||||
setGigachatApiKey(value, params.agentDir, params.apiKeyStorageOptions, {
|
||||
authMode: "oauth",
|
||||
insecureTls: "false",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
}),
|
||||
))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user