Skip to content

Commit

Permalink
refactor!: Change the Advanced Script Invocation Formatting Spec from…
Browse files Browse the repository at this point in the history
… `@script` to `[[@script]]`
  • Loading branch information
snowyu committed Dec 17, 2024
1 parent 541e49d commit a6bb6f2
Show file tree
Hide file tree
Showing 18 changed files with 108 additions and 121 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ $ npm install -g @offline-ai/cli
$ ai COMMAND
running command...
$ ai (--version)
@offline-ai/cli/0.5.18 linux-x64 node-v20.18.0
@offline-ai/cli/0.5.19 linux-x64 node-v20.18.0
$ ai --help [COMMAND]
USAGE
$ ai COMMAND
Expand Down Expand Up @@ -415,7 +415,7 @@ EXAMPLES
$ ai agent publish <agent-name>
```

_See code: [src/commands/agent/index.ts](https://github.com/offline-ai/cli/blob/v0.5.18/src/commands/agent/index.ts)_
_See code: [src/commands/agent/index.ts](https://github.com/offline-ai/cli/blob/v0.5.19/src/commands/agent/index.ts)_

## `ai autocomplete [SHELL]`

Expand Down
13 changes: 12 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@ features:
`ai brain run brain-name --provider llama.cpp --fg` fg: foreground
`ai provider `
☐ [feat]: ai-agent: 根据IP决定是否用NPM Mirror 进行升级.
☐ 需要一个好的方法导入js函数包.供内置js函数使用.以及脚本使用?
✔ import 配置, 用于导入文件函数供脚本使用. `string|string[]` 如果没有扩展名则为js. @done(24-09-12 16:10)
* `string|string[]` 导入所有的函数
* {filename: string|string[]} `导入指定的函数`
```yaml
import:#
'path':#
- basename
- dirname: getDirname
```
✔ `import`(`_$initImport`) 约定模板函数名: `template$funcName` @done(24-10-21 20:36)
✔ 新增 `->` 字符串指令,简化调用外部智能体脚本 @done(24-06-26 14:35)
✔ 新增`backup-chat`(`-k`)参数,在启动的时候备份history file @done(24-07-18 08:56)
☐ use github action create release package
Expand All @@ -29,6 +38,8 @@ features:
✔ refactor!: execString for push/replace message return content string only @done(24-08-21 20:38)
✔ add "userPreferredLanguage" option to translate the ai string result automatically @done(24-08-22 14:26)
✔ add "aiPreferredLanguage" option to translate the user input string automatically @done(24-08-23 21:27)
refactor:
✔ **Broken Change**: Change the Advanced Script Invocation Formatting Spec from `@script` to `[[@script]]` @done(24-12-17 19:59)
bugs:
glitch 当ctrl+c中断后的文字不会被clear,应ctrl+c会新起两行一行是单独一个ctrl+c
✔ 提示消息被过滤掉了空行 @done(24-06-16 17:58)
Expand Down
47 changes: 35 additions & 12 deletions lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

This directory contains a collection of Programmable Prompt Engine (PPE) Script Runtime Library files.

**NOTE**:

The Current PPE Script Runtime Libraries Directory has been moved to the `@offline-ai/cli-plugin-core` package.

## char type

**Introduction:**
Expand Down Expand Up @@ -48,13 +44,13 @@ assistant: I am Dobby. Dobby is happy.
**Introduction:**
This file defines a simple text file loader library for the Programmable Prompt Engine (PPE).
This file defines a simple text file/url loader library for the Programmable Prompt Engine (PPE).
**Key Functionality:**
* **Loads text files:** Reads the contents of text files specified by a file path.
* **Loads text files:** Reads the contents of text files specified by a file path or url.
* **Environment Variable Support:** Allows use of environment variables within file paths (e.g., "$HOME/documents/document.md").
* **Prompt Integration:** Designed to be integrated into PPE prompts, allowing users to reference file content directly within prompts (e.g., `user: summary the following file content: @file(document.md)`).
* **Prompt Integration:** Designed to be integrated into PPE prompts, allowing users to reference file content directly within prompts (e.g., `user: summary the following file content: [[@file(document.md)]]`).

**Input Configuration:**

Expand All @@ -67,14 +63,14 @@ This file defines a simple text file loader library for the Programmable Prompt
**Usage Example:**

```yaml
user: summary the following file content: @file(document.md)
user: summary the following file content: [[@file(document.md)]]
```

This prompt instructs the PPE to load the content of "document.md" and then summarize the loaded text.

**Workflow:**

1. The PPE encounters the `@file(document.md)` directive in the prompt.
1. The PPE encounters the `[[@file(document.md)]]` directive in the prompt.
2. The PPE invokes the `file.ai.yaml` library.
3. The library uses the `loadFile()` function to read the file content from "document.md" (resolving any environment variables in the path).
4. The loaded content is returned as a string, formatted with the filename and content.
Expand Down Expand Up @@ -188,7 +184,7 @@ The library provides two usage examples:

**Usage Example:**

* **Inline Prompt:** `Title: @titleify(file=document.md)`
* **Inline Prompt:** `Title: [[@titleify(file=document.md)]]`
* **Command-Line Execution:**

```bash
Expand All @@ -197,7 +193,7 @@ The library provides two usage examples:

**Workflow:**

1. **Input Processing:** The script first checks if a "file" input is provided. If so, it loads the content from the specified file path using the `@file()` function.
1. **Input Processing:** The script first checks if a "file" input is provided. If so, it loads the content from the specified file path using the `[[@file()]]` function.
2. **Summarization:** The loaded content is then passed to a summarization engine (represented by `[[titles:max_tokens=len]]`). This engine likely utilizes a large language model to generate several potential titles based on the input text and the desired length.
3. **Title Selection:** The script interacts with the user (in an interactive mode) to select the best title from the generated options.
4. **Output:** Finally, the chosen title is returned as the output of the "titleify" function.
Expand Down Expand Up @@ -242,7 +238,7 @@ $ai run --no-chats -f translator "{content:'我爱我的祖国和故乡.', targe
- **Integration within a prompt:**

```yaml
assistant: "Translate: @translator(file='document.md', target='English')"
assistant: "Translate: [[@translator(file='document.md', target='English')]]"
```
**Workflow:**
Expand All @@ -251,3 +247,30 @@ assistant: "Translate: @translator(file='document.md', target='English')"
2. If the source language is not specified, it attempts to automatically detect it.
3. It then constructs a prompt for a language model, instructing it to translate the input text into the target language.
4. The translated text, along with the original text, source language, and target language, are returned as an object.
## url
**Introduction:**
This file defines a simple fetch url library for the Programmable Prompt Engine (PPE).
**Key Functionality:**
* **Loads web content from url:** Reads the content specified by a url path.
* **Prompt Integration:** Designed to be integrated into PPE prompts, allowing users to reference url content directly within prompts (e.g., `user: summary the following web page: [[@url("https://example.com/page.html")]]`).

**Input Configuration:**

* **`content`:** (Required) A string representing the url to fetch.

**Output Configuration:**

* **`type: "string"`:** Returns the loaded web content as a string. The output is formatted with the `web url` and `web content` separated by a newline.

**Usage Example:**

```yaml
user: summary the following web content: [[@url("https://example.com/page.html")]]
```

This prompt instructs the PPE to load the content from "https://example.com/page.html" and then summarize the loaded text.
33 changes: 6 additions & 27 deletions lib/file.ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,21 @@ type: lib
description: |-
the simple text file loader. You can use environment variables in file path, eg, "$HOME/documents/document.md".
It can be used in prompt. eg, `user: "think about the following file content: @file(document.md)"`
It can be used in prompt. eg, `user: "think about the following file content: [[@file(document.md)]]"`
tag:
- file
- url
- loader
- prompt
- lib
input:
- 0 # The file path passed by the prompt(position argument)
- content # The file path passed by the prompt
- content: {index: 0} # The file path passed by the prompt, index: the position argument
- maxSize: {type: "number"} # truncate the file content to this size if exists
- sslVerify: {type: "boolean"}
- onlyContent: {type: "boolean"} # Only return the content
output: # the file content
type: "string"
import:
'./load-file.js': ['loadFile']
---
!fn |-
async function loadFile() {
const fs = await import('fs');
const path = await import('path');
let filepath = this.content || this[0]
if (!filepath) {throw new Error('No file path provided.')}
if (filepath.startsWith('https://') || filepath.startsWith('http://')) {
let options = {}
if (!this.sslVerify && filepath.startsWith('https://')) {
const https = await import('https');
const agent = new https.Agent({ rejectUnauthorized: false })
options.agent = agent
}
const content = await fetch(filepath, options).then(res => res.text());
if (this.onlyContent) return content;
return `url: ${filepath}\nfile content:\n${content}`
} else {
const filename = path.basename(filepath);
filepath = expandPath(filepath)
const content = fs.readFileSync(filepath, 'utf8');
if (this.onlyContent) return content;
return `filename: ${filename}\nfile content:\n${content}`
}
}
$loadFile
6 changes: 3 additions & 3 deletions lib/guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ The role messages can be formatted using Jinja2 templates and advanced replaceme

* **Jinja2 Templates:** Reference variables from input configuration or prompt settings using double curly braces (e.g., `{{name}}`).
* **Advanced AI Replacement:** As described above, triggers AI execution and stores the response.
* **External Script Replacement:** Invoke external scripts using the `@` symbol (e.g., `@say_hi_script(param1=value1)`).
* **Internal Instruction Replacement:** Call internal instructions similarly (e.g., `@$instruction(param1=value1)`).
* **External Script Replacement:** Invoke external scripts using the `@` symbol (e.g., `[[@say_hi_script(param1=value1)]]`).
* **Internal Instruction Replacement:** Call internal instructions similarly (e.g., `[[@$instruction(param1=value1)]]`).
* **Regular Expression Replacement:** Use `/RegExp/[RegOpts]:Answer[:index_or_group_name]` for pattern-based replacement on the `Answer` variable.

### [Programmable Prompt Engine Language - Script Capabilities](./lang-script.md)

* **Chaining Outputs:** The `->` operator connect script outputs to subsequent instructions or scripts, creating complex workflows.
* **Instruction Invocation:** The `$` prefix calls script instructions (e.g., `$fn: {param1:value1}`).
* **Control Flow:** Directives like `$if`, `$pipe`, `$set`, `$get`, `$print`, `$echo` provide control flow mechanisms.
* **Control Flow:** Directives like `$if`, `$while`, `$for`, `$match` provide control flow mechanisms.
* **Event-Driven Architecture:** Functions like `$on`, `$once`, `$emit` and `$off` enable event-based programming for flexible script behavior.
* **JavaScript Extension:** The `!fn` directive allows declaring JavaScript functions to extend script functionality.

Expand Down
6 changes: 3 additions & 3 deletions lib/guide/guide.ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ IsServerRunning: Please make sure the brain(LLM) server has been started. Are yo
}
return result
}
- $if: "@input(inputType='confirm', content={{Welcome+'\n'+IsServerRunning}}, value=true, format=(answer) => answer ? 'Yes' : 'No')"
- $if: "[[@input(inputType='confirm', content={{Welcome+'\n'+IsServerRunning}}, value=true, format=(answer) => answer ? 'Yes' : 'No')]]"
then:
# call support_langs to get the supported languages from LLM and assign it to the languages variable.
- $set:
languages: "@support_langs"
languages: "[[@support_langs]]"
- $set:
# call input to get the preferLang from user and assign it to the preferLang variable.
preferLang: "@input(inputType='AutoComplete', content='Which language do you prefer?', choices=languages, limit=10)"
preferLang: "[[@input(inputType='AutoComplete', content='Which language do you prefer?', choices=languages, limit=10)]]"
# `#` prefix means format the template string immediately and assign it to the variable.
GiveMeGoodBrain: "\n[Start Guide]An expert should have a good brain(LLM)."
- $if: "preferLang !== 'en'"
Expand Down
6 changes: 3 additions & 3 deletions lib/guide/guide_lib_explain_file.ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ file: "README.md"
- -> trans(lang) -> $ret
- user: |-
{%if file != 'README.md'%}
@file({{__dirname+file}})
[[@file({{__dirname+file}})]]
---
{%endif%}
Summarize the content in detail, capturing the key points and essence of it.
Expand All @@ -29,12 +29,12 @@ file: "README.md"
# - -> titleify(content=summary) -> trans(lang) -> $set('title')
- -> extract_title(content=summary) -> trans(lang) -> $set('title')
- -> trans(content="Do you have any questions about this file?", lang) -> $set('anyQuestion')
- $while: "@input(inputType='confirm', content=anyQuestion + ' ' + title, memoized=false, format=(answer) => answer ? 'Yes' : 'No')"
- $while: "[[@input(inputType='confirm', content=anyQuestion + ' ' + title, memoized=false, format=(answer) => answer ? 'Yes' : 'No')]]"
do:
- ---
- -> trans(content="What do you want to know?", lang) -> input(memoized=false) -> $set('question') -> $print()
- user: "{{question}}"
- assistant: "Let me explain it more clearly: [[answer:temperature=0.01]]"
- -> trans(lang) -> $print(content)
# call guide.ai.yaml lib to return main entry point
# - $echo: "@guide"
# - $echo: "[[@guide]]"
6 changes: 3 additions & 3 deletions lib/guide/guide_lib_list.ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ output:
type: 'string'
description: the description for the link
instruction: |-
- Summary the key points and essence of it
- Extract all links with title and description base on the markdown links from it
- Output summary and links list
file: "README.md"
---
# - system: |-
Expand All @@ -36,10 +36,10 @@ file: "README.md"
# - Output JSON format, following the JSON schema:
# {{output}}
# ---
# @file({{__dirname + file}})
# [[@file({{__dirname + file}})]]
# - user: Output all urls with title in markdown format from the README.md
# - assistant: "[[urls:temperature=0.01]]"
# - -> summary(file={{__dirname + file}}, content)
- -> summary(file={{__dirname + file}}, content=instruction) -> json(output=output)
- -> summary(file={{__dirname + file}}, instruction) -> json(output=output)
# - $|echo: ["summary", "links[0]"]

2 changes: 1 addition & 1 deletion lib/guide/instructor.ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ description: |-
- system: |-
You are an expert Programmable Prompt Engine(PPE) Language Script instructor, good at writing and communication.
---
@file({{__dirname+"README.md"}}, onlyContent=true)
[[@file({{__dirname+"README.md"}}, onlyContent=true)]]
10 changes: 5 additions & 5 deletions lib/guide/lang-formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,34 +103,34 @@ If you want to select one randomly from the list using the computer's local rand
In messages, we support content substitution by invoking scripts or instructions. The script or instructions must return a string value. For example:

```yaml
user: "#five plus two equals @calculator(5+2)"
user: "#five plus two equals [[@calculator(5+2)]]"
```
Notes:
* The prefix `#` indicates immediate formatting of the string.
* The prefix `@` indicates calling an external script with the ID `calculator`. if there are no parameters, you must omit the parentheses.
* The Invocation formatting should be placed within two square brackets. The prefix `@` indicates calling an external script with the ID `calculator`. if there are no parameters, you must omit the parentheses.
* If placed within text, ensure there is at least one space before and after. Extra spaces will be removed after substitution.

Here’s an example of how to load a file and generate a summary using this method:

```yaml
user: |-
Generate a summary for the following file:
@file(file.txt)
[[@file(file.txt)]]
```

## Internal Instruction Invocation Formatting

Internal Instruction Invocation Formatting similarly External Script Invocation Formatting. just add `$` prefix. To call an internal instruction, use the prefix `$`, such as `@$echo`; eg: `@$echo("hi world")`
Internal Instruction Invocation Formatting similarly External Script Invocation Formatting. just add `$` prefix. To call an internal instruction, use the prefix `$`, such as `@$echo`; eg: `[[@$echo("hi world")]]`

```yaml
# define a internal instruction by javascript function
!fn |-
function inc(n) {
return n + 1
}
user: "3 increment 1 is: @$inc(3)"
user: "3 increment 1 is: [[@$inc(3)]]"
```

## Regular Expression (RegExp) Formatting
Expand Down
6 changes: 3 additions & 3 deletions lib/guide/lang-reuse.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,19 +191,19 @@ In messages, we support content substitution by invoking scripts or instructions
```yaml
# the `#` prefix means immediate formatting
# call the `calculator.ai.yaml` script with the parameter '5+2'
user: "#five plus two equals @calculator('5+2')"
user: "#five plus two equals [[@calculator('5+2')]]"
```
Notes:
* The prefix `#` indicates immediate formatting of the string.
* The prefix `@` indicates calling an external script with the ID `calculator`. if there are no parameters, you must omit the parentheses.
* The Invocation formatting should be placed within two square brackets. The prefix `@` indicates calling an external script with the ID `calculator`. if there are no parameters, you must omit the parentheses.
* If placed within text, ensure there is at least one space before and after. Extra spaces will be removed after substitution.

Here’s an example of how to load a file and generate a summary using this method:

```yaml
user: |-
Generate a summary for the following file:
@file(file.txt)
[[@file(file.txt)]]
```
4 changes: 2 additions & 2 deletions lib/guide/lang.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ The role messages can be formatted using Jinja2 templates and advanced replaceme
* **AI Parameter Passing:** AI parameters can be passed within double brackets (e.g., `[[Answer:temperature=0.7]]`).
* **Constrained AI Responses:** Double brackets can enforce that AI responses are limited to specific options (e.g., `[[FRUITS:|Apple|Banana]]`).
* **Script and Instruction Replacement:** call the script or instruction in the message text. The script or instruction's output is then replaced into the message text.
* **External Script Replacement:** External scripts can be invoked using the `@` symbol (e.g., `@say_hi_script(param1=value1, p2=v2)`, it will be replaced by `hi`).
* **Internal Instruction Replacement:** Internal instructions can be called and replaced similarly (e.g., `@$instruction(param1=value1)`).
* **External Script Replacement:** External scripts can be invoked using the `@` symbol (e.g., `[[@say_hi_script(param1=value1, p2=v2)]]`, it will be replaced by `hi`).
* **Internal Instruction Replacement:** Internal instructions can be called and replaced similarly (e.g., `[[@$instruction(param1=value1)]]`).
* **Regular Expression Replacement:** `/RegExp/[RegOpts]:Answer[:index_or_group_name]` allows for pattern-based replacement on the `Answer` variable.

### Chaining and Script Function Calls
Expand Down
2 changes: 1 addition & 1 deletion lib/guide/trans.ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ content: "This is a test."
then:
- $set:
lang: "$getLanguageFromIso6391(lang)"
- $echo: "@translator(content=content, terms='- PPE: Programmable Prompt Engine', lang='English', target=lang)"
- $echo: "[[@translator(content=content, terms='- PPE: Programmable Prompt Engine', lang='English', target=lang)]]"
else:
- $echo: ?=content
Loading

0 comments on commit a6bb6f2

Please sign in to comment.