Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: calculator tool #10

Merged
merged 43 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3be6c6e
feat: calculator tool
michael-desmond Aug 29, 2024
73e7e11
style: add quote props rule
Tomas2D Aug 30, 2024
19902d1
test: print console traces
Tomas2D Aug 30, 2024
2990b1b
feat(watsonx): add chat preset
Tomas2D Aug 30, 2024
f032712
feat(watsonx): auto load accessToken/apiKey from env
Tomas2D Aug 30, 2024
a2c37fa
feat(bam): refactor chat preset
Tomas2D Aug 30, 2024
1e968b0
test: refactor tests
Tomas2D Aug 30, 2024
565df44
chore(deps): bump ibm-generative-ai
Tomas2D Aug 30, 2024
a07b717
fix(example): fix code interpreter path
Tomas2D Aug 30, 2024
ab2437c
feat(python): add custom id support
Tomas2D Aug 30, 2024
fd512bf
chore: release 0.0.5
Tomas2D Aug 30, 2024
9d04613
feat(react): emit `toolError` event for an invalid input
Tomas2D Aug 30, 2024
64eff9d
ci: improve copyright script
Tomas2D Aug 30, 2024
20e78f1
docs: update README.md
ismaelfaro Aug 30, 2024
7a50ff1
docs: add CONTRIBUTING.md
Tomas2D Aug 30, 2024
1a22495
docs: update contribution section
Tomas2D Aug 30, 2024
ba0bad2
feat(agent): extends bee success event
Tomas2D Sep 2, 2024
2ea05fc
feat(tools): update python tool output file prefix
Tomas2D Sep 2, 2024
c80daac
feat: remove modules index file
Tomas2D Sep 2, 2024
d5cadbc
chore: release 0.0.6
Tomas2D Sep 2, 2024
6654335
ci: update actions
Tomas2D Sep 2, 2024
3ee11af
chore: remove comments
Tomas2D Sep 2, 2024
812b081
ci: update action
Tomas2D Sep 2, 2024
2f51c26
feat(agent): group iterations, add meta property
Tomas2D Sep 2, 2024
0eca2c8
chore: release 0.0.7
Tomas2D Sep 2, 2024
2ad1a60
docs: initial commit of developer information about tools (#7)
grahamwhiteuk Sep 2, 2024
26c7913
feat(tool): stop using getters in custom tool
Tomas2D Sep 3, 2024
97c9b77
feat(agent): add support for overriding templates
Tomas2D Sep 3, 2024
07ebf2c
fix(tool): handle default values in JSON/zod schema
Tomas2D Sep 3, 2024
6203322
feat(tool): improve arxiv error handling
Tomas2D Sep 3, 2024
909dd60
test(tool): add arxiv e2e test
Tomas2D Sep 3, 2024
5368e40
chore: release 0.0.8
Tomas2D Sep 3, 2024
c25bdb3
chore(emitter): remove console.log
Tomas2D Sep 3, 2024
811086f
fix(agent): make templates property partial
Tomas2D Sep 3, 2024
d6faac3
docs: add SECURITY.md
Tomas2D Sep 3, 2024
67308a6
feat(examples): use bee-agent-framework in imports
Tomas2D Sep 3, 2024
026f78c
fix: add calculator test, limit available functions
michael-desmond Sep 3, 2024
844bc91
Merge branch 'i-am-bee:main' into calculator
michael-desmond Sep 3, 2024
398297a
Merge branch 'i-am-bee:main' into calculator
michael-desmond Sep 4, 2024
a07bf7f
fix(tools): add disclaimer to calc tool, move limiting to constructor
michael-desmond Sep 5, 2024
22969d5
Merge branch 'i-am-bee:main' into calculator
michael-desmond Sep 5, 2024
c296218
fix(tools): calc tool, config options, update schema and eval type, r…
michael-desmond Sep 5, 2024
a555460
style: apply prettier
Tomas2D Sep 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"fast-xml-parser": "^4.4.1",
"header-generator": "^2.1.54",
"joplin-turndown-plugin-gfm": "^1.0.12",
"mathjs": "^13.1.1",
"mustache": "^4.2.0",
"object-hash": "^3.0.0",
"p-queue": "^8.0.1",
Expand Down
46 changes: 46 additions & 0 deletions src/tools/calculator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { CalculatorTool } from "@/tools/calculator.js";
import { beforeEach, expect } from "vitest";

describe("Calculator", () => {
let instance: CalculatorTool;

beforeEach(() => {
instance = new CalculatorTool();
});

it("Runs", async () => {
const x1 = 1;
const y1 = 1;
const x2 = 4;
const y2 = 5;

const response = await instance.run({
expression: `sqrt( (${x2}-${x1})^2 + (${y2}-${y1})^2 )`,
});
expect(response.result).toBe(5);
});

it("Throws", async () => {
await expect(
instance.run({
expression: "import",
}),
).rejects.toThrowError();
});
});
97 changes: 97 additions & 0 deletions src/tools/calculator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { StringToolOutput, Tool, ToolInput } from "@/tools/base.js";
import { z } from "zod";
import { create, all, evaluate, ImportOptions, ImportObject, ConfigOptions } from "mathjs";

export interface CalculatorToolInput {
config?: ConfigOptions;
imports?: {
entries: ImportObject | ImportObject[];
options?: ImportOptions;
};
}

/**
* Waring: The CalculatorTool enbales the agent (and by proxy the user) to execute arbirtary
* expressions via mathjs.
*
* Please consider the security and stability risks documented at
* https://mathjs.org/docs/expressions/security.html before using this tool.
*/
export class CalculatorTool extends Tool<StringToolOutput> {
name = "Calculator";
description = `A calculator tool that performs basic arithmetic operations like addition, subtraction, multiplication, and division.
Only use the calculator tool if you need to perform a calculation.`;

inputSchema() {
return z.object({
expression: z
.string()
.min(1)
.describe(
`The mathematical expression to evaluate (e.g., "2 + 3 * 4"). Use Mathjs basic expression syntax. Constants only.`,
),
});
}

protected limitedEvaluate: typeof evaluate;

constructor({ config, imports, ...options }: CalculatorToolInput = {}) {
super(options);
const math = create(all, config);
this.limitedEvaluate = math.evaluate;
// Disable use of potentially vulnerable functions
math.import(
{
// most important (hardly any functional impact)
import: function () {
throw new Error("Function import is disabled");
},
createUnit: function () {
throw new Error("Function createUnit is disabled");
},
reviver: function () {
throw new Error("Function reviver is disabled");
},

// extra (has functional impact)
evaluate: function () {
throw new Error("Function evaluate is disabled");
},
parse: function () {
throw new Error("Function parse is disabled");
},
simplify: function () {
throw new Error("Function simplify is disabled");
},
derivative: function () {
throw new Error("Function derivative is disabled");
},
resolve: function () {
throw new Error("Function resolve is disabled");
},
},
{ override: true, ...imports?.options },
);
}

protected async _run({ expression }: ToolInput<this>) {
const result = this.limitedEvaluate(expression);
return new StringToolOutput(result);
}
}
92 changes: 92 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ __metadata:
languageName: node
linkType: hard

"@babel/runtime@npm:^7.25.4":
version: 7.25.6
resolution: "@babel/runtime@npm:7.25.6"
dependencies:
regenerator-runtime: "npm:^0.14.0"
checksum: 10c0/d6143adf5aa1ce79ed374e33fdfd74fa975055a80bc6e479672ab1eadc4e4bfd7484444e17dd063a1d180e051f3ec62b357c7a2b817e7657687b47313158c3d2
languageName: node
linkType: hard

"@bufbuild/protobuf@npm:^1.10.0":
version: 1.10.0
resolution: "@bufbuild/protobuf@npm:1.10.0"
Expand Down Expand Up @@ -2539,6 +2548,7 @@ __metadata:
joplin-turndown-plugin-gfm: "npm:^1.0.12"
langchain: "npm:~0.2.16"
lint-staged: "npm:^15.2.9"
mathjs: "npm:^13.1.1"
mustache: "npm:^4.2.0"
object-hash: "npm:^3.0.0"
ollama: "npm:^0.5.8"
Expand Down Expand Up @@ -3096,6 +3106,13 @@ __metadata:
languageName: node
linkType: hard

"complex.js@npm:^2.1.1":
version: 2.1.1
resolution: "complex.js@npm:2.1.1"
checksum: 10c0/c5dbb83954b472cf7fb1aebf8d140a7eb85a00b73eeb2b4ee4d192f98f038f3800f54550747b85be1114fedcbefebb2ade709b17b3cd40ab2bd546cb8fe9121c
languageName: node
linkType: hard

"concat-map@npm:0.0.1":
version: 0.0.1
resolution: "concat-map@npm:0.0.1"
Expand Down Expand Up @@ -3417,6 +3434,13 @@ __metadata:
languageName: node
linkType: hard

"decimal.js@npm:^10.4.3":
version: 10.4.3
resolution: "decimal.js@npm:10.4.3"
checksum: 10c0/6d60206689ff0911f0ce968d40f163304a6c1bc739927758e6efc7921cfa630130388966f16bf6ef6b838cb33679fbe8e7a78a2f3c478afce841fd55ac8fb8ee
languageName: node
linkType: hard

"decode-named-character-reference@npm:^1.0.0":
version: 1.0.2
resolution: "decode-named-character-reference@npm:1.0.2"
Expand Down Expand Up @@ -3852,6 +3876,13 @@ __metadata:
languageName: node
linkType: hard

"escape-latex@npm:^1.2.0":
version: 1.2.0
resolution: "escape-latex@npm:1.2.0"
checksum: 10c0/b77ea1594a38625295793a61105222c283c1792d1b2511bbfd6338cf02cc427dcabce7e7c1e22ec2f5c40baf3eaf2eeaf229a62dbbb74c6e69bb4a4209f2544f
languageName: node
linkType: hard

"escape-string-regexp@npm:^1.0.5":
version: 1.0.5
resolution: "escape-string-regexp@npm:1.0.5"
Expand Down Expand Up @@ -4382,6 +4413,13 @@ __metadata:
languageName: node
linkType: hard

"fraction.js@npm:^4.3.7":
version: 4.3.7
resolution: "fraction.js@npm:4.3.7"
checksum: 10c0/df291391beea9ab4c263487ffd9d17fed162dbb736982dee1379b2a8cc94e4e24e46ed508c6d278aded9080ba51872f1bc5f3a5fd8d7c74e5f105b508ac28711
languageName: node
linkType: hard

"fs-extra@npm:^11.2.0":
version: 11.2.0
resolution: "fs-extra@npm:11.2.0"
Expand Down Expand Up @@ -5316,6 +5354,13 @@ __metadata:
languageName: node
linkType: hard

"javascript-natural-sort@npm:^0.7.1":
version: 0.7.1
resolution: "javascript-natural-sort@npm:0.7.1"
checksum: 10c0/340f8ffc5d30fb516e06dc540e8fa9e0b93c865cf49d791fed3eac3bdc5fc71f0066fc81d44ec1433edc87caecaf9f13eec4a1fce8c5beafc709a71eaedae6fe
languageName: node
linkType: hard

"jiti@npm:^1.19.1":
version: 1.21.6
resolution: "jiti@npm:1.21.6"
Expand Down Expand Up @@ -6042,6 +6087,25 @@ __metadata:
languageName: node
linkType: hard

"mathjs@npm:^13.1.1":
version: 13.1.1
resolution: "mathjs@npm:13.1.1"
dependencies:
"@babel/runtime": "npm:^7.25.4"
complex.js: "npm:^2.1.1"
decimal.js: "npm:^10.4.3"
escape-latex: "npm:^1.2.0"
fraction.js: "npm:^4.3.7"
javascript-natural-sort: "npm:^0.7.1"
seedrandom: "npm:^3.0.5"
tiny-emitter: "npm:^2.1.0"
typed-function: "npm:^4.2.1"
bin:
mathjs: bin/cli.js
checksum: 10c0/db0b9d822fed889fc5f2cf4a9875e3fa627a26c9f6b2efbe7e000e42bfe9c0d71c125124329d2c8fd27a9d22d08b8794681367744787ef1eb8465e8f95955fd3
languageName: node
linkType: hard

"mdast-util-find-and-replace@npm:^3.0.0":
version: 3.0.1
resolution: "mdast-util-find-and-replace@npm:3.0.1"
Expand Down Expand Up @@ -7920,6 +7984,13 @@ __metadata:
languageName: node
linkType: hard

"regenerator-runtime@npm:^0.14.0":
version: 0.14.1
resolution: "regenerator-runtime@npm:0.14.1"
checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4
languageName: node
linkType: hard

"registry-auth-token@npm:^5.0.2":
version: 5.0.2
resolution: "registry-auth-token@npm:5.0.2"
Expand Down Expand Up @@ -8260,6 +8331,13 @@ __metadata:
languageName: node
linkType: hard

"seedrandom@npm:^3.0.5":
version: 3.0.5
resolution: "seedrandom@npm:3.0.5"
checksum: 10c0/929752ac098ff4990b3f8e0ac39136534916e72879d6eb625230141d20db26e2f44c4d03d153d457682e8cbaab0fb7d58a1e7267a157cf23fd8cf34e25044e88
languageName: node
linkType: hard

"semver-diff@npm:^4.0.0":
version: 4.0.0
resolution: "semver-diff@npm:4.0.0"
Expand Down Expand Up @@ -8792,6 +8870,13 @@ __metadata:
languageName: node
linkType: hard

"tiny-emitter@npm:^2.1.0":
version: 2.1.0
resolution: "tiny-emitter@npm:2.1.0"
checksum: 10c0/459c0bd6e636e80909898220eb390e1cba2b15c430b7b06cec6ac29d87acd29ef618b9b32532283af749f5d37af3534d0e3bde29fdf6bcefbf122784333c953d
languageName: node
linkType: hard

"tiny-invariant@npm:^1.3.3":
version: 1.3.3
resolution: "tiny-invariant@npm:1.3.3"
Expand Down Expand Up @@ -9028,6 +9113,13 @@ __metadata:
languageName: node
linkType: hard

"typed-function@npm:^4.2.1":
version: 4.2.1
resolution: "typed-function@npm:4.2.1"
checksum: 10c0/0b4e9a359e456f7df50f3d7cc53e2408d23a516f27b50c2c0654f388110ecf407c0595b1bf2296d3d8667fae6aae311ec2af90c602385777d12fe724bae99156
languageName: node
linkType: hard

"typedarray-to-buffer@npm:^3.1.5":
version: 3.1.5
resolution: "typedarray-to-buffer@npm:3.1.5"
Expand Down