-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
base.ts
197 lines (181 loc) Β· 5.94 KB
/
base.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import { Runnable } from "../runnables/index.js";
import type { RunnableConfig } from "../runnables/config.js";
import type { BasePromptValueInterface } from "../prompt_values.js";
import type { BaseMessage, MessageContentComplex } from "../messages/index.js";
import type { Callbacks } from "../callbacks/manager.js";
import type { Generation, ChatGeneration } from "../outputs.js";
/**
* Options for formatting instructions.
*/
export interface FormatInstructionsOptions {}
/**
* Abstract base class for parsing the output of a Large Language Model
* (LLM) call. It provides methods for parsing the result of an LLM call
* and invoking the parser with a given input.
*/
export abstract class BaseLLMOutputParser<T = unknown> extends Runnable<
string | BaseMessage,
T
> {
/**
* Parses the result of an LLM call. This method is meant to be
* implemented by subclasses to define how the output from the LLM should
* be parsed.
* @param generations The generations from an LLM call.
* @param callbacks Optional callbacks.
* @returns A promise of the parsed output.
*/
abstract parseResult(
generations: Generation[] | ChatGeneration[],
callbacks?: Callbacks
): Promise<T>;
/**
* Parses the result of an LLM call with a given prompt. By default, it
* simply calls `parseResult`.
* @param generations The generations from an LLM call.
* @param _prompt The prompt used in the LLM call.
* @param callbacks Optional callbacks.
* @returns A promise of the parsed output.
*/
parseResultWithPrompt(
generations: Generation[] | ChatGeneration[],
_prompt: BasePromptValueInterface,
callbacks?: Callbacks
): Promise<T> {
return this.parseResult(generations, callbacks);
}
protected _baseMessageToString(message: BaseMessage): string {
return typeof message.content === "string"
? message.content
: this._baseMessageContentToString(message.content);
}
protected _baseMessageContentToString(
content: MessageContentComplex[]
): string {
return JSON.stringify(content);
}
/**
* Calls the parser with a given input and optional configuration options.
* If the input is a string, it creates a generation with the input as
* text and calls `parseResult`. If the input is a `BaseMessage`, it
* creates a generation with the input as a message and the content of the
* input as text, and then calls `parseResult`.
* @param input The input to the parser, which can be a string or a `BaseMessage`.
* @param options Optional configuration options.
* @returns A promise of the parsed output.
*/
async invoke(
input: string | BaseMessage,
options?: RunnableConfig
): Promise<T> {
if (typeof input === "string") {
return this._callWithConfig(
async (input: string, options): Promise<T> =>
this.parseResult([{ text: input }], options?.callbacks),
input,
{ ...options, runType: "parser" }
);
} else {
return this._callWithConfig(
async (input: BaseMessage, options): Promise<T> =>
this.parseResult(
[
{
message: input,
text: this._baseMessageToString(input),
},
],
options?.callbacks
),
input,
{ ...options, runType: "parser" }
);
}
}
}
/**
* Class to parse the output of an LLM call.
*/
export abstract class BaseOutputParser<
T = unknown
> extends BaseLLMOutputParser<T> {
parseResult(
generations: Generation[] | ChatGeneration[],
callbacks?: Callbacks
): Promise<T> {
return this.parse(generations[0].text, callbacks);
}
/**
* Parse the output of an LLM call.
*
* @param text - LLM output to parse.
* @returns Parsed output.
*/
abstract parse(text: string, callbacks?: Callbacks): Promise<T>;
async parseWithPrompt(
text: string,
_prompt: BasePromptValueInterface,
callbacks?: Callbacks
): Promise<T> {
return this.parse(text, callbacks);
}
/**
* Return a string describing the format of the output.
* @returns Format instructions.
* @param options - Options for formatting instructions.
* @example
* ```json
* {
* "foo": "bar"
* }
* ```
*/
abstract getFormatInstructions(options?: FormatInstructionsOptions): string;
/**
* Return the string type key uniquely identifying this class of parser
*/
_type(): string {
throw new Error("_type not implemented");
}
}
/**
* Exception that output parsers should raise to signify a parsing error.
*
* This exists to differentiate parsing errors from other code or execution errors
* that also may arise inside the output parser. OutputParserExceptions will be
* available to catch and handle in ways to fix the parsing error, while other
* errors will be raised.
*
* @param message - The error that's being re-raised or an error message.
* @param llmOutput - String model output which is error-ing.
* @param observation - String explanation of error which can be passed to a
* model to try and remediate the issue.
* @param sendToLLM - Whether to send the observation and llm_output back to an Agent
* after an OutputParserException has been raised. This gives the underlying
* model driving the agent the context that the previous output was improperly
* structured, in the hopes that it will update the output to the correct
* format.
*/
export class OutputParserException extends Error {
llmOutput?: string;
observation?: string;
sendToLLM: boolean;
constructor(
message: string,
llmOutput?: string,
observation?: string,
sendToLLM = false
) {
super(message);
this.llmOutput = llmOutput;
this.observation = observation;
this.sendToLLM = sendToLLM;
if (sendToLLM) {
if (observation === undefined || llmOutput === undefined) {
throw new Error(
"Arguments 'observation' & 'llmOutput' are required if 'sendToLlm' is true"
);
}
}
}
}