-
Notifications
You must be signed in to change notification settings - Fork 2k
/
output_parser.ts
122 lines (114 loc) Β· 3.85 KB
/
output_parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import type { OpenAIClient } from "@langchain/openai";
import { AgentAction, AgentFinish, AgentStep } from "@langchain/core/agents";
import { BaseMessage, isBaseMessage } from "@langchain/core/messages";
import { ChatGeneration } from "@langchain/core/outputs";
import { OutputParserException } from "@langchain/core/output_parsers";
import { AgentMultiActionOutputParser } from "../types.js";
/**
* Type that represents an agent action with an optional message log.
*/
export type ToolsAgentAction = AgentAction & {
toolCallId: string;
messageLog?: BaseMessage[];
};
export type ToolsAgentStep = AgentStep & {
action: ToolsAgentAction;
};
/**
* @example
* ```typescript
*
* const prompt = ChatPromptTemplate.fromMessages([
* ["ai", "You are a helpful assistant"],
* ["human", "{input}"],
* new MessagesPlaceholder("agent_scratchpad"),
* ]);
*
* const runnableAgent = RunnableSequence.from([
* {
* input: (i: { input: string; steps: ToolsAgentStep[] }) => i.input,
* agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) =>
* formatToOpenAIToolMessages(i.steps),
* },
* prompt,
* new ChatOpenAI({
* modelName: "gpt-3.5-turbo-1106",
* temperature: 0,
* }).bind({ tools: tools.map(convertToOpenAITool) }),
* new OpenAIToolsAgentOutputParser(),
* ]).withConfig({ runName: "OpenAIToolsAgent" });
*
* const result = await runnableAgent.invoke({
* input:
* "What is the sum of the current temperature in San Francisco, New York, and Tokyo?",
* });
*
* ```
*/
export class OpenAIToolsAgentOutputParser extends AgentMultiActionOutputParser {
lc_namespace = ["langchain", "agents", "openai"];
static lc_name() {
return "OpenAIToolsAgentOutputParser";
}
async parse(text: string): Promise<AgentAction[] | AgentFinish> {
throw new Error(
`OpenAIFunctionsAgentOutputParser can only parse messages.\nPassed input: ${text}`
);
}
async parseResult(generations: ChatGeneration[]) {
if ("message" in generations[0] && isBaseMessage(generations[0].message)) {
return this.parseAIMessage(generations[0].message);
}
throw new Error(
"parseResult on OpenAIFunctionsAgentOutputParser only works on ChatGeneration output"
);
}
/**
* Parses the output message into a ToolsAgentAction[] or AgentFinish
* object.
* @param message The BaseMessage to parse.
* @returns A ToolsAgentAction[] or AgentFinish object.
*/
parseAIMessage(message: BaseMessage): ToolsAgentAction[] | AgentFinish {
if (message.content && typeof message.content !== "string") {
throw new Error("This agent cannot parse non-string model responses.");
}
if (message.additional_kwargs.tool_calls) {
const toolCalls: OpenAIClient.Chat.ChatCompletionMessageToolCall[] =
message.additional_kwargs.tool_calls;
try {
return toolCalls.map((toolCall, i) => {
const toolInput = toolCall.function.arguments
? JSON.parse(toolCall.function.arguments)
: {};
const messageLog = i === 0 ? [message] : [];
return {
tool: toolCall.function.name as string,
toolInput,
toolCallId: toolCall.id,
log: `Invoking "${toolCall.function.name}" with ${
toolCall.function.arguments ?? "{}"
}\n${message.content}`,
messageLog,
};
});
} catch (error) {
throw new OutputParserException(
`Failed to parse tool arguments from chat model response. Text: "${JSON.stringify(
toolCalls
)}". ${error}`
);
}
} else {
return {
returnValues: { output: message.content },
log: message.content,
};
}
}
getFormatInstructions(): string {
throw new Error(
"getFormatInstructions not implemented inside OpenAIToolsAgentOutputParser."
);
}
}