141 lines
4.3 KiB
TypeScript
141 lines
4.3 KiB
TypeScript
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).`
|
|
}
|