docs: Updated docs to talk about the new TypeScript-based tool support
This commit is contained in:
@@ -10,6 +10,8 @@ into your Loki setup. This document provides a guide on how to create and use cu
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [Custom Bash-Based Tools](#custom-bash-based-tools)
|
||||
- [Custom Python-Based Tools](#custom-python-based-tools)
|
||||
- [Custom TypeScript-Based Tools](#custom-typescript-based-tools)
|
||||
- [Custom Runtime](#custom-runtime)
|
||||
<!--toc:end-->
|
||||
|
||||
---
|
||||
@@ -19,9 +21,10 @@ Loki supports custom tools written in the following programming languages:
|
||||
|
||||
* Python
|
||||
* Bash
|
||||
* TypeScript
|
||||
|
||||
## Creating a Custom Tool
|
||||
All tools are created as scripts in either Python or Bash. They should be placed in the `functions/tools` directory.
|
||||
All tools are created as scripts in either Python, Bash, or TypeScript. They should be placed in the `functions/tools` directory.
|
||||
The location of the `functions` directory varies between systems, so you can use the following command to locate
|
||||
your `functions` directory:
|
||||
|
||||
@@ -81,6 +84,7 @@ Loki and demonstrates how to create a Python-based tool:
|
||||
import os
|
||||
from typing import List, Literal, Optional
|
||||
|
||||
|
||||
def run(
|
||||
string: str,
|
||||
string_enum: Literal["foo", "bar"],
|
||||
@@ -89,26 +93,38 @@ def run(
|
||||
number: float,
|
||||
array: List[str],
|
||||
string_optional: Optional[str] = None,
|
||||
integer_with_default: int = 42,
|
||||
boolean_with_default: bool = True,
|
||||
number_with_default: float = 3.14,
|
||||
string_with_default: str = "hello",
|
||||
array_optional: Optional[List[str]] = None,
|
||||
):
|
||||
"""Demonstrates how to create a tool using Python and how to use comments.
|
||||
"""Demonstrates all supported Python parameter types and variations.
|
||||
Args:
|
||||
string: Define a required string property
|
||||
string_enum: Define a required string property with enum
|
||||
boolean: Define a required boolean property
|
||||
integer: Define a required integer property
|
||||
number: Define a required number property
|
||||
array: Define a required string array property
|
||||
string_optional: Define an optional string property
|
||||
array_optional: Define an optional string array property
|
||||
string: A required string property
|
||||
string_enum: A required string property constrained to specific values
|
||||
boolean: A required boolean property
|
||||
integer: A required integer property
|
||||
number: A required number (float) property
|
||||
array: A required string array property
|
||||
string_optional: An optional string property (Optional[str] with None default)
|
||||
integer_with_default: An optional integer with a non-None default value
|
||||
boolean_with_default: An optional boolean with a default value
|
||||
number_with_default: An optional number with a default value
|
||||
string_with_default: An optional string with a default value
|
||||
array_optional: An optional string array property
|
||||
"""
|
||||
output = f"""string: {string}
|
||||
string_enum: {string_enum}
|
||||
string_optional: {string_optional}
|
||||
boolean: {boolean}
|
||||
integer: {integer}
|
||||
number: {number}
|
||||
array: {array}
|
||||
string_optional: {string_optional}
|
||||
integer_with_default: {integer_with_default}
|
||||
boolean_with_default: {boolean_with_default}
|
||||
number_with_default: {number_with_default}
|
||||
string_with_default: {string_with_default}
|
||||
array_optional: {array_optional}"""
|
||||
|
||||
for key, value in os.environ.items():
|
||||
@@ -117,3 +133,150 @@ array_optional: {array_optional}"""
|
||||
|
||||
return output
|
||||
```
|
||||
|
||||
### Custom TypeScript-Based Tools
|
||||
Loki supports tools written in TypeScript. TypeScript tools require [Node.js](https://nodejs.org/) and
|
||||
[tsx](https://tsx.is/) (`npx tsx` is used as the default runtime).
|
||||
|
||||
Each TypeScript-based tool must follow a specific structure in order for Loki to properly compile and execute it:
|
||||
|
||||
* The tool must be a TypeScript file with a `.ts` file extension.
|
||||
* The tool must have an `export function run(...)` that serves as the entry point for the tool.
|
||||
* Non-exported functions are ignored by the compiler and can be used as private helpers.
|
||||
* The `run` function must accept flat parameters that define the inputs for the tool.
|
||||
* Always use type annotations to specify the data type of each parameter.
|
||||
* Use `param?: type` or `type | null` to indicate optional parameters.
|
||||
* Use `param: type = value` for parameters with default values.
|
||||
* The `run` function must return a `string` (or `Promise<string>` for async functions).
|
||||
* For TypeScript, the return value is automatically written to the `LLM_OUTPUT` environment variable, so there's
|
||||
no need to explicitly write to the environment variable within the function.
|
||||
* The function must have a JSDoc comment that describes the tool and its parameters.
|
||||
* Each parameter should be documented using `@param name - description` tags.
|
||||
* These descriptions are passed to the LLM as the tool description, letting the LLM know what the tool does and
|
||||
how to use it.
|
||||
* Async functions (`export async function run(...)`) are fully supported and handled transparently.
|
||||
|
||||
**Supported Parameter Types:**
|
||||
|
||||
| TypeScript Type | JSON Schema | Notes |
|
||||
|-------------------|--------------------------------------------------|-----------------------------|
|
||||
| `string` | `{"type": "string"}` | Required string |
|
||||
| `number` | `{"type": "number"}` | Required number |
|
||||
| `boolean` | `{"type": "boolean"}` | Required boolean |
|
||||
| `string[]` | `{"type": "array", "items": {"type": "string"}}` | Array (bracket syntax) |
|
||||
| `Array<string>` | `{"type": "array", "items": {"type": "string"}}` | Array (generic syntax) |
|
||||
| `"foo" \| "bar"` | `{"type": "string", "enum": ["foo", "bar"]}` | String enum (literal union) |
|
||||
| `param?: string` | `{"type": "string"}` (not required) | Optional via question mark |
|
||||
| `string \| null` | `{"type": "string"}` (not required) | Optional via null union |
|
||||
| `param = "value"` | `{"type": "string"}` (not required) | Optional via default value |
|
||||
|
||||
**Unsupported Patterns (will produce a compile error):**
|
||||
|
||||
* Rest parameters (`...args: string[]`)
|
||||
* Destructured object parameters (`{ a, b }: { a: string, b: string }`)
|
||||
* Arrow functions (`const run = (x: string) => ...`)
|
||||
* Function expressions (`const run = function(x: string) { ... }`)
|
||||
|
||||
Only `export function` declarations are recognized. Non-exported functions are invisible to the compiler.
|
||||
|
||||
Below is the [`demo_ts.ts`](../../assets/functions/tools/demo_ts.ts) tool definition that comes pre-packaged with
|
||||
Loki and demonstrates how to create a TypeScript-based tool:
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Demonstrates all supported TypeScript parameter types and variations.
|
||||
*
|
||||
* @param string - A required string property
|
||||
* @param string_enum - A required string property constrained to specific values
|
||||
* @param boolean - A required boolean property
|
||||
* @param number - A required number property
|
||||
* @param array_bracket - A required string array using bracket syntax
|
||||
* @param array_generic - A required string array using generic syntax
|
||||
* @param string_optional - An optional string using the question mark syntax
|
||||
* @param string_nullable - An optional string using the union-with-null syntax
|
||||
* @param number_with_default - An optional number with a default value
|
||||
* @param boolean_with_default - An optional boolean with a default value
|
||||
* @param string_with_default - An optional string with a default value
|
||||
* @param array_optional - An optional string array using the question mark syntax
|
||||
*/
|
||||
export function run(
|
||||
string: string,
|
||||
string_enum: "foo" | "bar",
|
||||
boolean: boolean,
|
||||
number: number,
|
||||
array_bracket: string[],
|
||||
array_generic: Array<string>,
|
||||
string_optional?: string,
|
||||
string_nullable: string | null = null,
|
||||
number_with_default: number = 42,
|
||||
boolean_with_default: boolean = true,
|
||||
string_with_default: string = "hello",
|
||||
array_optional?: string[],
|
||||
): string {
|
||||
const parts = [
|
||||
`string: ${string}`,
|
||||
`string_enum: ${string_enum}`,
|
||||
`boolean: ${boolean}`,
|
||||
`number: ${number}`,
|
||||
`array_bracket: ${JSON.stringify(array_bracket)}`,
|
||||
`array_generic: ${JSON.stringify(array_generic)}`,
|
||||
`string_optional: ${string_optional}`,
|
||||
`string_nullable: ${string_nullable}`,
|
||||
`number_with_default: ${number_with_default}`,
|
||||
`boolean_with_default: ${boolean_with_default}`,
|
||||
`string_with_default: ${string_with_default}`,
|
||||
`array_optional: ${JSON.stringify(array_optional)}`,
|
||||
];
|
||||
|
||||
for (const [key, value] of Object.entries(process.env)) {
|
||||
if (key.startsWith("LLM_")) {
|
||||
parts.push(`${key}: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join("\n");
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Runtime
|
||||
By default, Loki uses the following runtimes to execute tools:
|
||||
|
||||
| Language | Default Runtime | Requirement |
|
||||
|------------|-----------------|--------------------------------|
|
||||
| Python | `python` | Python 3 on `$PATH` |
|
||||
| TypeScript | `npx tsx` | Node.js + tsx (`npm i -g tsx`) |
|
||||
| Bash | `bash` | Bash on `$PATH` |
|
||||
|
||||
You can override the runtime for Python and TypeScript tools using a **shebang line** (`#!`) at the top of your
|
||||
script. Loki reads the first line of each tool file; if it starts with `#!`, the specified interpreter is used instead
|
||||
of the default.
|
||||
|
||||
**Examples:**
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3.11
|
||||
# This Python tool will be executed with python3.11 instead of the default `python`
|
||||
|
||||
def run(name: str):
|
||||
"""Greet someone.
|
||||
Args:
|
||||
name: The name to greet
|
||||
"""
|
||||
return f"Hello, {name}!"
|
||||
```
|
||||
|
||||
```typescript
|
||||
#!/usr/bin/env bun
|
||||
// This TypeScript tool will be executed with Bun instead of the default `npx tsx`
|
||||
|
||||
/**
|
||||
* Greet someone.
|
||||
* @param name - The name to greet
|
||||
*/
|
||||
export function run(name: string): string {
|
||||
return `Hello, ${name}!`;
|
||||
}
|
||||
```
|
||||
|
||||
This is useful for pinning a specific Python version, using an alternative TypeScript runtime like
|
||||
[Bun](https://bun.sh/) or [Deno](https://deno.com/), or working with virtual environments.
|
||||
|
||||
@@ -32,6 +32,7 @@ be enabled/disabled can be found in the [Configuration](#configuration) section
|
||||
|-------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
|
||||
| [`demo_py.py`](../../assets/functions/tools/demo_py.py) | Demonstrates how to create a tool using Python and how to use comments. | 🔴 |
|
||||
| [`demo_sh.sh`](../../assets/functions/tools/demo_sh.sh) | Demonstrate how to create a tool using Bash and how to use comment tags. | 🔴 |
|
||||
| [`demo_ts.ts`](../../assets/functions/tools/demo_ts.ts) | Demonstrates how to create a tool using TypeScript and how to use JSDoc comments. | 🔴 |
|
||||
| [`execute_command.sh`](../../assets/functions/tools/execute_command.sh) | Execute the shell command. | 🟢 |
|
||||
| [`execute_py_code.py`](../../assets/functions/tools/execute_py_code.py) | Execute the given Python code. | 🔴 |
|
||||
| [`execute_sql_code.sh`](../../assets/functions/tools/execute_sql_code.sh) | Execute SQL code. | 🔴 |
|
||||
@@ -49,6 +50,7 @@ be enabled/disabled can be found in the [Configuration](#configuration) section
|
||||
| [`get_current_time.sh`](../../assets/functions/tools/get_current_time.sh) | Get the current time. | 🟢 |
|
||||
| [`get_current_weather.py`](../../assets/functions/tools/get_current_weather.py) | Get the current weather in a given location (Python implementation) | 🔴 |
|
||||
| [`get_current_weather.sh`](../../assets/functions/tools/get_current_weather.sh) | Get the current weather in a given location. | 🟢 |
|
||||
| [`get_current_weather.ts`](../../assets/functions/tools/get_current_weather.ts) | Get the current weather in a given location (TypeScript implementation) | 🔴 |
|
||||
| [`query_jira_issues.sh`](../../assets/functions/tools/query_jira_issues.sh) | Query for jira issues using a Jira Query Language (JQL) query. | 🟢 |
|
||||
| [`search_arxiv.sh`](../../assets/functions/tools/search_arxiv.sh) | Search arXiv using the given search query and return the top papers. | 🔴 |
|
||||
| [`search_wikipedia.sh`](../../assets/functions/tools/search_wikipedia.sh) | Search Wikipedia using the given search query. <br>Use it to get detailed information about a public figure, interpretation of a <br>complex scientific concept or in-depth connectivity of a significant historical <br>event, etc. | 🔴 |
|
||||
|
||||
Reference in New Issue
Block a user