mirror of
https://github.com/ONLYOFFICE/desktop-sdk.git
synced 2026-02-10 18:15:05 +08:00
AIAgent: update anthropic thinking mode
This commit is contained in:
@ -1,11 +1,16 @@
|
||||
import type Anthropic from "@anthropic-ai/sdk";
|
||||
import type {
|
||||
ReasoningMessagePart,
|
||||
TextMessagePart,
|
||||
ThreadMessageLike,
|
||||
ToolCallMessagePart,
|
||||
} from "@assistant-ui/react";
|
||||
|
||||
type ContentArray = (TextMessagePart | ToolCallMessagePart)[];
|
||||
type ContentArray = (
|
||||
| TextMessagePart
|
||||
| ToolCallMessagePart
|
||||
| ReasoningMessagePart
|
||||
)[];
|
||||
|
||||
// ============================================================================
|
||||
// Helpers
|
||||
@ -51,7 +56,10 @@ const handleThinkingBlockStart = (
|
||||
block: { thinking: string },
|
||||
content: ContentArray
|
||||
): void => {
|
||||
content.push(createTextPart(`<think>\n${block.thinking}`));
|
||||
content.push({
|
||||
type: "reasoning",
|
||||
text: block.thinking,
|
||||
});
|
||||
};
|
||||
|
||||
const handleToolUseBlockStart = (
|
||||
@ -80,9 +88,12 @@ const handleThinkingDelta = (
|
||||
content: ContentArray
|
||||
): void => {
|
||||
const last = getLastContent(content);
|
||||
if (last?.type !== "text") return;
|
||||
if (last?.type !== "reasoning") return;
|
||||
|
||||
content[content.length - 1] = createTextPart(last.text + delta.thinking);
|
||||
content[content.length - 1] = {
|
||||
...last,
|
||||
text: last.text + delta.thinking,
|
||||
};
|
||||
};
|
||||
|
||||
const handleSignatureDelta = (
|
||||
@ -90,14 +101,13 @@ const handleSignatureDelta = (
|
||||
content: ContentArray
|
||||
): void => {
|
||||
const last = getLastContent(content);
|
||||
if (last?.type !== "text" || !last.text.startsWith("<think>")) return;
|
||||
|
||||
console.log(delta);
|
||||
if (last?.type !== "reasoning") return;
|
||||
|
||||
// Append signature to the thinking block (will be closed later)
|
||||
content[content.length - 1] = createTextPart(
|
||||
`${last.text}<!--sig:${delta.signature}-->`
|
||||
);
|
||||
content[content.length - 1] = {
|
||||
...last,
|
||||
parentId: delta.signature,
|
||||
};
|
||||
};
|
||||
|
||||
const tryParseJson = (text: string): ToolCallMessagePart["args"] => {
|
||||
|
||||
@ -136,50 +136,16 @@ const convertSystemMessage = (message: ThreadMessageLike): MessageParam[] => {
|
||||
return [{ role: "user", content }];
|
||||
};
|
||||
|
||||
/**
|
||||
* Strips <think> tags from text and returns the thinking content, signature, and non-thinking text.
|
||||
* Format: <think>content<!--sig:SIGNATURE--></think>
|
||||
*/
|
||||
const stripThinkingFromText = (
|
||||
text: string
|
||||
): { thinkBlock: string; signature: string; text: string } => {
|
||||
const thinkMatch = text.match(/<think>([\s\S]*?)<\/think>/);
|
||||
let thinkBlock = "";
|
||||
let signature = "";
|
||||
|
||||
if (thinkMatch) {
|
||||
const thinkContent = thinkMatch[1];
|
||||
const sigMatch = thinkContent.match(/<!--sig:([\s\S]*?)-->/);
|
||||
if (sigMatch) {
|
||||
signature = sigMatch[1];
|
||||
thinkBlock = thinkContent.replace(/<!--sig:[\s\S]*?-->/, "").trim();
|
||||
} else {
|
||||
thinkBlock = thinkContent.trim();
|
||||
}
|
||||
}
|
||||
|
||||
const strippedText = text.replace(/<think>[\s\S]*?<\/think>\n*/g, "").trim();
|
||||
return { thinkBlock, signature, text: strippedText };
|
||||
};
|
||||
|
||||
const convertAssistantMessage = (
|
||||
message: ThreadMessageLike
|
||||
): MessageParam[] => {
|
||||
const result: MessageParam[] = [];
|
||||
|
||||
if (typeof message.content === "string") {
|
||||
const { text, thinkBlock, signature } = stripThinkingFromText(
|
||||
message.content
|
||||
);
|
||||
const content: ContentBlockParam[] = [
|
||||
{ type: "text", text: message.content },
|
||||
];
|
||||
|
||||
const content: ContentBlockParam[] = [];
|
||||
|
||||
if (thinkBlock && signature) {
|
||||
content.push({ type: "thinking", thinking: thinkBlock, signature });
|
||||
}
|
||||
if (text) {
|
||||
content.push({ type: "text", text });
|
||||
}
|
||||
return [{ role: "assistant", content }];
|
||||
}
|
||||
|
||||
@ -187,16 +153,19 @@ const convertAssistantMessage = (
|
||||
let toolResults: ToolResultBlockParam[] = [];
|
||||
|
||||
for (const part of message.content) {
|
||||
if (part.type === "text") {
|
||||
// Strip thinking blocks - they require signature to be sent back
|
||||
const { text, thinkBlock, signature } = stripThinkingFromText(part.text);
|
||||
if (part.type === "reasoning") {
|
||||
content.push({
|
||||
type: "thinking",
|
||||
thinking: part.text,
|
||||
signature: part.parentId ?? "",
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.type === "text") {
|
||||
content.push({ type: "text", text: part.text });
|
||||
|
||||
if (thinkBlock && signature) {
|
||||
content.push({ type: "thinking", thinking: thinkBlock, signature });
|
||||
}
|
||||
if (text) {
|
||||
content.push({ type: "text", text });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user