-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
json.ts
152 lines (125 loc) Β· 4.14 KB
/
json.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
import jsonpointer from "jsonpointer";
import { Serializable } from "@langchain/core/load/serializable";
import { Tool, ToolParams } from "@langchain/core/tools";
export type Json =
| string
| number
| boolean
| null
| { [key: string]: Json }
| Json[];
export type JsonObject = { [key: string]: Json };
/**
* Represents a JSON object in the LangChain framework. Provides methods
* to get keys and values from the JSON object.
*/
export class JsonSpec extends Serializable {
lc_namespace = ["langchain", "tools", "json"];
obj: JsonObject;
maxValueLength = 4000;
constructor(obj: JsonObject, max_value_length = 4000) {
super(...arguments);
this.obj = obj;
this.maxValueLength = max_value_length;
}
/**
* Retrieves all keys at a given path in the JSON object.
* @param input The path to the keys in the JSON object, provided as a string in JSON pointer syntax.
* @returns A string containing all keys at the given path, separated by commas.
*/
public getKeys(input: string): string {
const pointer = jsonpointer.compile(input);
const res = pointer.get(this.obj) as Json;
if (typeof res === "object" && !Array.isArray(res) && res !== null) {
return Object.keys(res)
.map((i) => i.replaceAll("~", "~0").replaceAll("/", "~1"))
.join(", ");
}
throw new Error(
`Value at ${input} is not a dictionary, get the value directly instead.`
);
}
/**
* Retrieves the value at a given path in the JSON object.
* @param input The path to the value in the JSON object, provided as a string in JSON pointer syntax.
* @returns The value at the given path in the JSON object, as a string. If the value is a large dictionary or exceeds the maximum length, a message is returned instead.
*/
public getValue(input: string): string {
const pointer = jsonpointer.compile(input);
const res = pointer.get(this.obj) as Json;
if (res === null || res === undefined) {
throw new Error(`Value at ${input} is null or undefined.`);
}
const str = typeof res === "object" ? JSON.stringify(res) : res.toString();
if (
typeof res === "object" &&
!Array.isArray(res) &&
str.length > this.maxValueLength
) {
return `Value is a large dictionary, should explore its keys directly.`;
}
if (str.length > this.maxValueLength) {
return `${str.slice(0, this.maxValueLength)}...`;
}
return str;
}
}
export interface JsonToolFields extends ToolParams {
jsonSpec: JsonSpec;
}
/**
* A tool in the LangChain framework that lists all keys at a given path
* in a JSON object.
*/
export class JsonListKeysTool extends Tool {
static lc_name() {
return "JsonListKeysTool";
}
name = "json_list_keys";
jsonSpec: JsonSpec;
constructor(jsonSpec: JsonSpec);
constructor(fields: JsonToolFields);
constructor(fields: JsonSpec | JsonToolFields) {
if (!("jsonSpec" in fields)) {
// eslint-disable-next-line no-param-reassign
fields = { jsonSpec: fields };
}
super(fields);
this.jsonSpec = fields.jsonSpec;
}
/** @ignore */
async _call(input: string) {
try {
return this.jsonSpec.getKeys(input);
} catch (error) {
return `${error}`;
}
}
description = `Can be used to list all keys at a given path.
Before calling this you should be SURE that the path to this exists.
The input is a text representation of the path to the json as json pointer syntax (e.g. /key1/0/key2).`;
}
/**
* A tool in the LangChain framework that retrieves the value at a given
* path in a JSON object.
*/
export class JsonGetValueTool extends Tool {
static lc_name() {
return "JsonGetValueTool";
}
name = "json_get_value";
constructor(public jsonSpec: JsonSpec) {
super();
}
/** @ignore */
async _call(input: string) {
try {
return this.jsonSpec.getValue(input);
} catch (error) {
return `${error}`;
}
}
description = `Can be used to see value in string format at a given path.
Before calling this you should be SURE that the path to this exists.
The input is a text representation of the path to the json as json pointer syntax (e.g. /key1/0/key2).`;
}