# STscript 语言参考

# 什么是 STscript?

它是一种简单而强大的脚本语言,可用于扩展 SillyTavern 的功能而无需认真的编码,使您能够:

  • 创建迷你游戏或速通挑战
  • 构建 AI 驱动的聊天洞察
  • 释放您的创造力并与他人分享

STscript 是使用斜杠命令引擎构建的,利用命令批处理、数据管道、宏和变量。 这些概念将在本文档中描述。

# 安全预防措施

能力越大,责任越大。请小心并始终在执行脚本之前检查它们。

# Hello, World!

要运行您的第一个脚本,打开任何 SillyTavern 聊天并在聊天输入栏中输入以下内容:

stscript
/pass Hello, World! | /echo
Hello World

您应该在屏幕顶部的 toast 中看到该消息。现在让我们逐个分解它。

脚本是一批命令,每个命令都以斜杠开头,带有或不带有命名和未命名参数,并以命令分隔符字符终止:|

命令按顺序一个接一个地执行,并在彼此之间传输数据。

  1. /pass 命令接受 "Hello, World!" 作为未命名参数并将其写入管道。
  2. /echo 命令通过管道从前一个命令接收值并将其显示为 toast 通知。

由于常量未命名参数和管道是可互换的,我们可以将此脚本简单地重写为:

stscript
/echo Hello, World!

# 用户输入

现在让我们为脚本添加一点交互性。我们将接受来自用户的输入值并在通知中显示它。

stscript
/input Enter your name |
/echo Hello, my name is {{pipe}}
  1. /input 命令用于显示一个输入框,其中包含未命名参数中指定的提示,然后将输出写入管道。
  2. 因为 /echo 已经有一个设置输出模板的未命名参数,我们使用 {{pipe}} 宏来指定将渲染管道值的位置。
Slim Shady Input Slim Shady Output

# 其他输入/输出命令

  • /popup (text) — 显示一个阻塞式弹出窗口,支持轻量级 HTML 格式化,例如:/popup <font color=red>我是红色的!</font>
  • /setinput (text) — 用提供的文本替换用户输入栏的内容。
  • /speak voice="name" (text) — 使用选定的 TTS 引擎和语音映射中的角色名称朗读文本,例如:/speak name="唐老鸭" 嘎嘎!
  • /buttons labels=["a","b"] (text) — 显示一个带有指定文本和按钮标签的阻塞式弹出窗口。labels 必须是 JSON 序列化的字符串数组或包含此类数组的变量名。将点击的按钮标签返回到管道中,如果取消则返回空字符串。文本支持轻量级 HTML 格式化。

# /popup/input 的参数

/popup/input 支持以下额外的命名参数:

  • large=on/off - 增加弹出窗口的垂直大小。默认:off
  • wide=on/off - 增加弹出窗口的水平大小。默认:off
  • okButton=string - 添加自定义"确定"按钮文本的功能。默认:Ok
  • rows=number - (仅适用于 /input)增加输入控件的大小。默认:1。

示例:

stscript
/popup large=on wide=on okButton="接受" 请接受我们的条款和条件...

# /echo 的参数

/echo 支持以下额外的 severity 参数值,用于设置显示消息的样式。

  • warning(警告)
  • error(错误)
  • info(信息)(默认)
  • success(成功)

示例:

stscript
/echo severity=error 发生了非常糟糕的事情。

# 变量

变量用于在脚本中存储和操作数据,可以使用命令或宏。变量可以是以下类型之一:

  • 局部变量 — 保存到当前聊天的元数据中,并且对该聊天是唯一的。
  • 全局变量 — 保存到 settings.json 中,并在应用程序的任何地方存在。
  1. /getvar name{{getvar::name}} — 获取局部变量的值。
  2. /setvar key=name value{{setvar::name::value}} — 设置局部变量的值。
  3. /addvar key=name increment{{addvar::name::increment}} — 将 increment 添加到局部变量的值中。
  4. /incvar name{{incvar::name}} — 将局部变量的值增加 1。
  5. /decvar name{{decvar::name}} — 将局部变量的值减少 1。
  6. /getglobalvar name{{getglobalvar::name}} — 获取全局变量的值。
  7. /setglobalvar key=name{{setglobalvar::name::value}} — 设置全局变量的值。
  8. /addglobalvar key=name{{addglobalvar::name:increment}} — 将 increment 添加到全局变量的值中。
  9. /incglobalvar name{{incglobalvar::name}} — 将全局变量的值增加 1。
  10. /decglobalvar name{{decglobalvar::name}} — 将全局变量的值减少 1。
  11. /flushvar name — 删除局部变量的值。
  12. /flushglobalvar name — 删除全局变量的值。
  • 以前未定义的变量的默认值是空字符串,或者如果它首次在 /addvar/incvar/decvar 命令中使用则为零。
  • /addvar 命令中,如果增量和变量值都可以转换为数字,则执行值的加法或减法,否则执行字符串连接。
  • 如果命令参数接受变量名,并且存在同名局部变量和全局变量,则局部变量优先。
  • 所有用于变量操作的斜杠命令都会将结果值写入管道,供下一个命令使用。
  • 对于,只有"get"、"inc"和"dec"类型的宏返回值,"add"和"set"被替换为空字符串。

现在,让我们考虑以下示例:

stscript
/input 您想要生成什么?|
/setvar key=SDinput |
/echo 正在请求 {{getvar::SDinput}} 的图像 |
/getvar SDinput |
/imagine
  1. 用户输入的值保存在名为 SDinput 的局部变量中。
  2. getvar 宏用于在 /echo 命令中显示值。
  3. getvar 命令用于检索变量的值并通过管道传递。
  4. 该值传递给 /imagine 命令(由图像生成插件提供)作为其输入提示。

由于变量在脚本执行之间被保存且不被刷新,您可以在其他脚本和宏中引用该变量,它将解析为与示例脚本执行期间相同的值。要保证该值将被丢弃,请在脚本中添加 /flushvar 命令。

# 数组和对象

变量值可以包含 JSON 序列化的数组或键值对(对象)。

示例:

  • 数组:["苹果","香蕉","橙子"]
  • 对象:{"水果":["苹果","香蕉","橙子"]}

可以应用以下修改来处理这些变量:

  • /len 命令获取数组中的项目数量。
  • index=number/string 命名参数可以添加到 /getvar/setvar 及其全局对应项中,以通过数组的零基索引或对象的字符串键来获取或设置子值。
    • 如果在不存在变量上使用数字索引,变量将创建为空数组 []
    • 如果在不存在变量上使用字符串索引,变量将创建为空对象 {}
  • /addvar/addglobalvar 命令支持将新值推送到数组类型的变量中。

# Flow control - conditionals

您可以使用 /if 命令创建条件表达式,根据定义的规则分支执行。

stscript
/if left=valueA right=valueB rule=comparison else={: /echo (command on false) :} {: /echo (command on true) :}

请注意

stscript
/if left=valueA right=valueB rule=comparison else="(command on false)" "(command on true)"

语法也是支持的,但是 {: closures :} 将帮助您编写更清晰的脚本。

让我们查看以下示例:

stscript
/input What's your favorite drink? |
/if left={{pipe}} right="black tea" rule=eq else={: /echo You shall not pass | /abort :} {: /echo Welcome to the club, {{user}} :}

此脚本根据所需值评估用户输入,并根据输入值显示不同的消息。

# /if 的参数

  1. left 是第一个操作数。我们称之为 A。
  2. right 是第二个操作数。我们称之为 B。
  3. rule 是要应用于操作数的操作。
  4. else 是可选的子命令字符串,如果布尔比较结果为 false 则执行。
  5. 未命名参数是如果布尔比较结果为 true 则要执行的子命令。

操作数值按以下顺序评估:

  1. 数字字面量
  2. 局部变量名
  3. 全局变量名
  4. 字符串字面量

命名参数的字符串值可以用引号转义以允许多词字符串。引号随后将被丢弃。

# 布尔操作

支持的布尔比较规则如下。应用于操作数的操作结果为 true 或 false 值。

  1. eq (equals) => A = B(等于)
  2. neq (not equals) => A != B(不等于)
  3. lt (less than) => A < B(小于)
  4. gt (greater than) => A > B(大于)
  5. lte (less than or equals) => A <= B(小于等于)
  6. gte (greater than or equals) => A >= B(大于等于)
  7. not (unary negation) => !A(一元否定)
  8. in (includes substring) => A includes B, case insensitive(包含子字符串,不区分大小写)
  9. nin (not includes substring) => A not includes B, case insensitive(不包含子字符串,不区分大小写)

# 子命令

子命令是包含要执行的斜杠命令列表的字符串。

  1. 要在子命令中使用命令批处理,命令分隔符应该被转义(见下文)。
  2. 由于宏值在进入条件时执行,而不是在子命令执行时执行,宏可以额外转义以将其评估延迟到子命令执行时间。
  3. 子命令执行的结果通过管道传递到 /if 之后的命令。
  4. /abort 命令在遇到时中断脚本执行。

/if 命令可以用作三元运算符。 以下示例将向下一个命令传递 "true" 字符串,如果变量 a 等于 5,否则传递 "false" 字符串。

stscript
/if left=a right=5 rule=eq else={: /pass false:} {: /pass true :} |
/echo

# 转义序列

#

宏的转义方式与之前相同。但是,使用闭包时,您需要转义宏的频率会比以前少得多。可以转义两个开始大括号,或者同时转义开始和结束对。

stscript
/echo \{\{char}} |
/echo \{\{char\}\}

# 管道

在闭包中(当用作命令分隔符时)不需要转义管道。在任何您想要使用字面管道字符而不是命令分隔符的地方,您需要转义它。

stscript
/echo title="a\|b" c\|d |
/echo title=a\|b c\|d |

使用解析器标志 STRICT_ESCAPING 时,您不需要在引号值中转义管道。

stscript
/parser-flag STRICT_ESCAPING |
/echo title="a|b" c\|d |
/echo title=a\|b c\|d |

# 引号

要在引号值中使用字面引号字符,该字符必须被转义。

stscript
/echo title="a \"b\" c" d "e" f

# 空格

要在命名参数的值中使用空格,您必须用引号包围值,或者转义空格字符。

stscript
/echo title="a b" c d |
/echo title=a\ b c d

# 闭包分隔符

如果您想要使用用于标记闭包开始或结束的字符组合,您必须用单个反斜杠转义该序列。

stscript
/echo \{: |
/echo \:}

# 管道中断符

stscript
||

为了防止前一个命令的输出作为未命名参数自动注入到下一个命令中,在两个命令之间放置双管道。

stscript
/echo we don't want to pass this on ||
/world

# 闭包

stscript
{: ... :}

闭包(块语句、lambda、匿名函数,无论您想称呼它们为什么)是包装在 {::} 之间的一系列命令,只有在执行该部分代码时才会被评估。

# 子命令

闭包使使用子命令变得更加容易,并消除了转义管道和宏的需要。

stscript
// if without closures |
/if left=1 rule=eq right=1
    else="
        /echo not equal \|
        /return 0
    "
    /echo equal \|
    /return \{\{pipe}}
stscript
// if with closures |
/if left=1 rule=eq right=1
    else={:
        /echo not equal |
        /return 0
    :}
    {:
        /echo equal |
        /return {{pipe}}
    :}

# 作用域

闭包有自己的作用域并支持作用域变量。作用域变量用 /let 声明,它们的值用 /var 设置和检索。获取作用域变量的另一种方法是 {{var::}} 宏。

stscript
/let x |
/let y 2 |
/var x 1 |
/var y |
/echo x is {{var::x}} and y is {{pipe}}.

在闭包内,您可以访问在同一闭包或其祖先之一中声明的所有变量。您无法访问在闭包后代中声明的变量。
如果变量与在闭包祖先之一中声明的变量同名,您在此闭包及其后代中无法访问祖先变量。

stscript
/let x this is root x |
/let y this is root y |
/return {:
    /echo called from level-1: x is "{{var::x}}" and y is "{{var::y}}" |
    /delay 500 |
    /let x this is level-1 x |
    /echo called from level-1: x is "{{var::x}}" and y is "{{var::y}}" |
    /delay 500 |
    /return {:
        /echo called from level-2: x is "{{var::x}}" and y is "{{var::y}}" |
        /let x this is level-2 x |
        /echo called from level-2: x is "{{var::x}}" and y is "{{var::y}}" |
        /delay 500
    :}()
:}() |
/echo called from root: x is "{{var::x}}" and y is "{{var::y}}"

# 命名闭包

stscript
/let x {: ... :} | /:x

闭包可以分配给变量(仅作用域变量),以便在稍后调用或用作子命令。

stscript
/let myClosure {:
    /echo this is my closure
:} |
/:myClosure
stscript
/let myClosure {:
    /echo this is my closure |
    /delay 500
:} |
/times 3 {{var::myClosure}}

/: 也可以用于执行快速回复,因为它只是 /run 的简写。

stscript
/:QrSetName.QrButtonLabel |
/run QrSetName.QrButtonLabel

# 闭包参数

命名闭包可以接受命名参数,就像斜杠命令一样。参数可以有默认值。

stscript
/let myClosure {: a=1 b=
    /echo a is {{var::a}} and b is {{var::b}}
:} |
/:myClosure b=10

# 闭包和管道参数

来自父闭包的管道值不会自动注入到子闭包的第一个命令中。
您仍然可以使用 {{pipe}} 显式引用父闭包的管道值,但如果您将闭包内第一个命令的未命名参数留空,该值将不会自动注入。

stscript
/* 这曾经尝试将模型更改为 "foo"
   因为循环外 /echo 的值 "foo"
   被注入到循环内的 /model 命令中。
   现在它将简单地回显当前模型而不
   尝试更改它。
*|
/echo foo |
/times 2 {:
	/model |
	/echo |
:} |
stscript
/* 您仍然可以通过
   显式使用 {{pipe}} 宏来重新创建旧行为。
*|
/echo foo |
/times 2 {:
	/model {{pipe}} |
	/echo |
:} |

# 立即执行闭包

stscript
{: ... :}()

闭包可以立即执行,意味着它们将被其返回值替换。这在没有明确支持闭包的地方很有帮助,并且可以缩短一些否则需要大量中间变量的命令。

stscript
// 没有闭包的两个字符串的简单长度比较 |
/len foo |
/var lenOfFoo {{pipe}} |
/len bar |
/var lenOfBar {{pipe}} |
/if left={{var::lenOfFoo}} rule=eq right={{var:lenOfBar}} /echo yay!
stscript
// 使用立即执行闭包的相同比较 |
/if left={:/len foo:}() rule=eq right={:/len bar:}() /echo yay!

除了运行保存在作用域变量中的命名闭包外,/run 命令也可用于立即执行闭包。

stscript
/run {:
	/add 1 2 3 4 |
:} |
/echo |

# 注释

stscript
// ... | /# ...

注释是脚本代码中的人类可读解释或注释。注释不会破坏管道。

stscript
// 这是一个注释 |
/echo foo |
/# 这也是一个注释

# 块注释

块注释可用于快速一次注释掉多个命令。它们不会在管道处终止。

stscript
/echo foo |
/*
/echo bar |
/echo foobar |
*|
/echo foo again |

# 流程控制

# 循环:/while/times

如果您需要在循环中运行某些命令直到满足特定条件,请使用 /while 命令。

stscript
/while left=valueA right=valueB rule=operation guard=on "commands"

在循环的每一步,它比较变量 A 的值与变量 B 的值,如果条件为 true,则执行引号内包含的任何有效斜杠命令,否则退出循环。此命令不会向输出管道写入任何内容。

# /while 的参数

可用的布尔比较集、变量处理、字面值和子命令的处理与 /if 命令相同。

可选的 guard 命名参数(默认为 on)用于防止无限循环,将迭代次数限制为 100。 要禁用并允许无限循环,请设置 guard=off

此示例将 1 添加到 i 的值,直到达到 10,然后输出结果值(本例中为 10)。

stscript
/setvar key=i 0 |
/while left=i right=10 rule=lt "/addvar key=i 1" |
/echo {{getvar::i}} |
/flushvar i

# /times 的参数

运行子命令指定的次数。

/times (repeats) "(command)" – 引号内包含的任何有效斜杠命令重复多次,例如 /setvar key=i 1 | /times 5 "/addvar key=i 1" 将 1 添加到 "i" 的值 5 次。

  • {{timesIndex}} 被替换为迭代次数(从零开始),例如 /times 4 {:/echo {{timesIndex}}:} 回显数字 0 到 4。
  • 循环默认限制为 100 次迭代,传递 guard=off 以禁用。

# 跳出循环和闭包

stscript
/break |

/break 命令可用于提前跳出循环(/while/times)或闭包。/break 的未命名参数可用于传递与当前管道不同的值。
/break 目前在以下命令中实现:

  • /while - 提前退出循环
  • /times - 提前退出循环
  • /run(带有闭包或通过变量的闭包)- 提前退出闭包
  • /:(带有闭包)- 提前退出闭包
stscript
/times 10 {:
	/echo {{timesIndex}}
	/delay 500 |
	/if left={{timesIndex}} rule=gt right=3 {:
		/break
	:} |
:} |
stscript
/let x {: iterations=2
	/if left={{var::iterations}} rule=gt right=10 {:
		/break too many iterations! |
	:} |
	/times {{var::iterations}} {:
		/delay 500 |
		/echo {{timesIndex}} |
	:} |
:} |
/:x iterations=30 |
/echo the final result is: {{pipe}}
stscript
/run {:
	/break 1 |
	/pass 2 |
:} |
/echo pipe will be one: {{pipe}} |
stscript
/let x {:
	/break 1 |
	/pass 2 |
:} |
/:x |
/echo pipe will be one: {{pipe}} |

# 数学运算

  • 以下所有运算都接受一系列数字或变量名,并将结果输出到管道。
  • 无效运算(如除以零)以及导致 NaN 值或无穷大的运算返回零。
  • 乘法、加法、最小值和最大值接受无限数量的用空格分隔的参数。
  • 减法、除法、幂运算和模运算接受两个用空格分隔的参数。
  • 正弦、余弦、自然对数、平方根、绝对值和舍入接受一个参数。

运算列表:

  1. /add (a b c d) – 执行一组值的加法,例如 /add 10 i 30 j
  2. /mul (a b c d) – 执行一组值的乘法,例如 /mul 10 i 30 j
  3. /max (a b c d) – 返回一组值中的最大值,例如 /max 1 0 4 k
  4. /min (a b c d) – 返回一组值中的最小值,例如 /min 5 4 i 2
  5. /sub (a b) – 执行两个值的减法,例如 /sub i 5
  6. /div (a b) – 执行两个值的除法,例如 /div 10 i
  7. /mod (a b) – 执行两个值的模运算,例如 /mod i 2
  8. /pow (a b) – 执行两个值的幂运算,例如 /pow i 2
  9. /sin (a) – 执行值的正弦运算,例如 /sin i
  10. /cos (a) – 执行值的余弦运算,例如 /cos i
  11. /log (a) – 执行值的自然对数运算,例如 /log i
  12. /abs (a) – 执行值的绝对值运算,例如 /abs -10
  13. /sqrt (a)– 执行值的平方根运算,例如 /sqrt 9
  14. /round (a) – 执行值到最近整数的舍入运算,例如 /round 3.14
  15. /rand (round=round|ceil|floor from=number=0 to=number=1) – 返回 from 和 to 之间的随机数,例如 /rand/rand 10/rand from=5 to=10。范围是包含的。返回值将包含小数部分。使用 round 命名参数获取整数值,例如 /rand round=ceil 向上舍入,round=floor 向下舍入,round=round 舍入到最接近的整数。

# 示例 1:获取半径为 50 的圆的面积。

stscript
/setglobalvar key=PI 3.1415 |
/setvar key=r 50 |
/mul r r PI |
/round |
/echo Circle area: {{pipe}}

# 示例 2:计算 5 的阶乘。

stscript
/setvar key=input 5 |
/setvar key=i 1 |
/setvar key=product 1 |
/while left=i right=input rule=lte "/mul product i \| /setvar key=product \| /addvar key=i 1" |
/getvar product |
/echo Factorial of {{getvar::input}}: {{pipe}} |
/flushvar input |
/flushvar i |
/flushvar product

# 使用 LLM

脚本可以使用以下命令向当前连接的 LLM API 发出请求:

  • /gen (prompt) — 使用提供的提示为所选角色生成文本,并包含聊天消息。
  • /genraw (prompt) — 仅使用提供的提示生成文本,忽略当前角色和聊天。
  • /trigger — 触发正常生成(相当于单击"发送"按钮)。如果在群组聊天中,您可以选择提供基于 1 的群组成员索引或角色名称让他们回复,否则根据群组设置触发群组轮次。

# /gen/genraw 的参数

stscript
/genraw lock=on/off stop=[] instruct=on/off (prompt)
  • lock — 可以是 onoff。指定在生成过程中是否应阻止用户输入。默认值:off
  • stop — JSON 序列化的字符串数组。仅为此生成添加自定义停止字符串(如果 API 支持)。默认值:无。
  • instruct(仅 /genraw)— 可以是 onoff。允许在输入提示上使用指令格式(如果启用了指令模式且 API 支持)。设置为 off 以强制使用纯提示。默认值:on
  • as(用于文本补全 API)— 可以是 system(默认)或 char。定义最后提示行的格式化方式。char 将使用角色名称,system 将使用无或中性名称。

生成的文本然后通过管道传递到下一个命令,并可以使用 I/O 功能保存到变量或显示:

stscript
/genraw Write a funny message from Cthulhu about taking over the world. Use emojis. |
/popup <h3>Cthulhu says:</h3><div>{{pipe}}</div>
Cthulhu Says

或将生成的消息作为角色的响应插入:

stscript
/genraw You have been memory wiped, your name is now Lisa and you're tearing me apart. You're tearing me apart Lisa! |
/sendas name={{char}} {{pipe}}

# 临时角色

如果您不在群组聊天中,脚本可以临时以不同角色向当前连接的 LLM 发出请求。

  • /ask (prompt) — 使用提供的提示为指定角色生成文本,并包含聊天消息。请注意,来自此角色的响应滑块将恢复回当前角色。
stscript
/ask name=... (prompt)

# Arguments for /ask

  • nameRequired. The name of the character to ask (or a unique character identifier, such as an avatar key). This must be provided as a named argument.
  • return — Specifies how the return value should be provided. Defaults to pipe (output via the command pipe). Other options can be specified if supported by the API.
stscript
/ask name=Alice What is your favorite color?

# 提示注入

脚本可以添加自定义 LLM 提示注入,使其本质上相当于无限的作者注释。

  • /inject (text) — 将任何文本插入到当前聊天的正常 LLM 提示中,并需要唯一标识符。保存到聊天元数据。
  • /listinjects — 在系统消息中显示脚本为当前聊天添加的所有提示注入的列表。
  • /flushinjects — 删除脚本为当前聊天添加的所有提示注入。
  • /note (text) — 设置当前聊天的作者注释值。保存到聊天元数据。
  • /interval — 设置当前聊天的作者注释插入间隔。
  • /depth — 设置聊天内位置的作者注释插入深度。
  • /position — 设置当前聊天的作者注释位置。

# /inject 的参数

stscript
/inject id=IdGoesHere position=chat depth=4 My prompt injection
  • id — 标识符字符串或对变量的引用。使用相同 ID 的 /inject 的后续调用将覆盖之前的文本注入。必需参数。
  • position — 设置注入的位置。默认值:after。可能的值:
    • after:在主提示之后。
    • before:在主提示之前。
    • chat:在聊天中。
  • depth — 设置聊天内位置的注入深度。0 表示在最后一条消息之后插入,1 - 在最后一条消息之前,等等。默认值:4。
  • 未命名参数是要注入的文本。空字符串将取消设置提供标识符的先前值。

# 访问聊天消息

# 读取消息

您可以使用 /messages 命令访问当前选定聊天中的消息。

stscript
/messages names=on/off start-finish
  • names 参数用于指定是否要包含角色名称,默认值:on
  • 在未命名参数中,它接受 start-finish 格式的消息索引或范围。范围是包含的!
  • 如果范围不可满足,即请求了无效索引或比存在的消息更多的消息,则返回空字符串。
  • 从提示中隐藏的消息(由幽灵图标表示)从输出中排除。
  • 如果您想知道最新消息的索引,请使用 {{lastMessageId}} 宏,{{lastMessage}} 将为您获取消息本身。

要计算范围的起始索引,例如,当您需要获取最后 N 条消息时,请使用变量减法。 此示例将为您获取聊天中的最后 3 条消息:

stscript
/setvar key=start {{lastMessageId}} |
/addvar key=start -2 |
/messages names=off {{getvar::start}}-{{lastMessageId}} |
/setinput

# 发送消息

脚本可以以用户、角色、人格、中性叙述者身份发送消息,或添加评论。

  1. /send (text) — 以当前选定的人格添加消息。
  2. /sendas name=charname (text) — 以任何角色添加消息,通过名称匹配。name 参数是必需的。使用 {{char}} 宏以当前角色发送。
  3. /sys (text) — 添加不属于用户或角色的中性叙述者消息。显示的名称纯粹是装饰性的,可以使用 /sysname 命令自定义。
  4. /comment (text) — 添加在聊天中显示但对提示不可见的隐藏评论。
  5. /addswipe (text) — 向最后一条角色消息添加滑块。无法向用户或隐藏消息添加滑块。
  6. /hide (message id or range) — 根据提供的消息索引或 start-finish 格式的包含范围,从提示中隐藏一条或多条消息。
  7. /unhide (message id or range) — 根据提供的消息索引或 start-finish 格式的包含范围,将一条或多条消息返回到提示中。

/send/sendassys/comment 命令可选地接受命名参数 at,其具有从零开始的数值(或包含此类值的变量名),该参数指定消息插入的确切位置。默认情况下,新消息插入到聊天日志的末尾。

这将在对话历史的开头插入用户消息:

stscript
/send at=0 Hi, I use Linux.

# 删除消息

这些命令可能具有破坏性,并且没有"撤销"功能。如果您意外删除了重要内容,请检查 /backups/ 文件夹。

  1. /cut (message id or range) — 根据提供的消息索引或 start-finish 格式的包含范围,从聊天中剪切一条或多条消息。
  2. /del (number) — 从聊天中删除最后 N 条消息。
  3. /delswipe (1-based swipe id) — 根据提供的基于 1 的滑块 ID,从最后一条角色消息中删除滑块。
  4. /delname (character name) — 删除当前聊天中属于指定名称角色的所有消息。
  5. /delchat — 删除当前聊天。

# 世界信息命令

世界信息(也称为 Lorebook)是一个高度实用的工具,用于动态向提示中插入数据。有关更详细的解释,请参阅专用页面:世界信息

  1. /getchatbook – 获取聊天绑定的世界信息文件的名称,如果未绑定则创建一个新文件,并将其传递到管道中。
  2. /findentry file=bookName field=fieldName [text] – 使用字段值与提供文本的模糊匹配(默认字段:key)从指定文件(或指向文件名的变量)中查找记录的 UID,并将 UID 传递到管道中,例如 /findentry file=chatLore field=key Shadowfang
  3. /getentryfield file=bookName field=field [UID] – 从指定世界信息文件(或指向文件名的变量)中获取具有 UID 的记录的字段值(默认字段:content),并将值传递到管道中,例如 /getentryfield file=chatLore field=content 123
  4. /setentryfield file=bookName uid=UID field=field [text] – 设置从指定世界信息文件(或指向文件名的变量)中具有 UID(或指向 UID 的变量)的记录的字段值(默认字段:content)。要为关键字段设置多个值,请使用逗号分隔的列表作为文本值,例如 /setentryfield file=chatLore uid=123 field=key Shadowfang,sword,weapon
  5. /createentry file=bookName key=keyValue [content text] – 在指定文件(或指向文件名的变量)中创建一个新记录,包含键和内容(这两个参数都是可选的),并将 UID 传递到管道中,例如 /createentry file=chatLore key=Shadowfang The sword of the king

# 有效条目字段

Field UI element Value type
content Content String
comment Title / Memo String
key Primary Keywords List of strings
keysecondary Optional Filter List of strings
constant Constant Status Boolean (1/0)
disable Disabled Status Boolean (1/0)
order Order Number
selectiveLogic Logic (see below)
excludeRecursion Non-recursable Boolean (1/0)
probability Trigger% Number (0-100)
depth Depth Number (0-999)
position Position (see below)
role Depth Role (see below)
scanDepth Scan Depth Number (0-100)
caseSensitive Case-Sensitive Boolean (1/0)
matchWholeWords Match Whole Words Boolean (1/0)
vectorized Vectorized Status Boolean (1/0)
automationId Automation ID String
group Inclusion Group String
groupOverride Inclusion Group Prioritize Boolean (1/0)
groupWeight Inclusion Group Weight Number (0-100)
useGroupScoring Group Scoring Boolean (1/0)
characterFilterExclude Character Filter Exclude Mode List of strings
characterFilterNames Character Filter Names List of strings
characterFilterTags Character Filter Tags List of strings
matchCharacterDepthPrompt Match Character Depth Prompt Boolean (1/0)
matchCharacterDescription Match Character Description Boolean (1/0)
matchCharacterPersonality Match Character Personality Boolean (1/0)
matchCreatorNotes Match Creator Notes Boolean (1/0)
matchPersonaDescription Match Persona Description Boolean (1/0)
matchScenario Match Scenario Boolean (1/0)

逻辑值

  • 0 = AND ANY(与任意)
  • 1 = NOT ALL(非全部)
  • 2 = NOT ANY(非任意)
  • 3 = AND ALL(与全部)

位置值

  • 0 = 在主提示词之前
  • 1 = 在主提示词之后
  • 2 = 在作者注释顶部
  • 3 = 在作者注释底部
  • 4 = 在聊天深度中
  • 5 = 在示例消息顶部
  • 6 = 在示例消息底部

角色值(仅限位置 = 4)

  • 0 = 系统
  • 1 = 用户
  • 2 = 助手

# 示例 1:通过键从聊天lorebook中读取内容

stscript
/getchatbook | /setvar key=chatLore |
/findentry file={{getvar::chatLore}} field=key Shadowfang |
/getentryfield file={{getvar::chatLore}} field=key |
/echo

# 示例 2:使用键和内容创建聊天lorebook条目

stscript
/getchatbook | /setvar key=chatLore |
/createentry file={{getvar::chatLore}} key="Milla" Milla Basset is a friend of Lilac and Carol. She is a hush basset puppy who possesses the power of alchemy. |
/echo

# 示例 3:使用聊天中的新信息扩展现有的lorebook条目

stscript
/getchatbook | /setvar key=chatLore |
/findentry file={{getvar::chatLore}} field=key Milla |
/setvar key=millaUid |
/getentryfield file={{getvar::chatLore}} field=content |
/setvar key=millaContent |
/gen lock=on Tell me more about Milla Basset based on the provided conversation history. Incorporate existing information into your reply: {{getvar::millaContent}} |
/setvar key=millaContent |
/echo New content: {{pipe}} |
/setentryfield file={{getvar::chatLore}} uid=millaUid field=content {{getvar::millaContent}}

# 文本操作

有各种有用的文本操作实用命令,可用于各种脚本场景。

  1. /trimtokens — 将输入修剪为从开头或结尾开始的指定数量的文本令牌,并将结果输出到管道。
  2. /trimstart — 将输入修剪到第一个完整句子的开头,并将结果输出到管道。
  3. /trimend — 将输入修剪到最后一个完整句子的结尾,并将结果输出到管道。
  4. /fuzzy — 对输入文本与字符串列表执行模糊匹配,将最佳字符串匹配输出到管道。
  5. /regex name=scriptName [text] — 对指定文本执行正则表达式扩展中的正则表达式脚本。该脚本必须已启用。

# /trimtokens 的参数

stscript
/trimtokens limit=number direction=start/end (input)
  1. direction 设置修剪方向,可以是 startend。默认值:end
  2. limit 设置输出中要保留的令牌数量。也可以指定包含该数字的变量名。必需参数。
  3. 未命名参数是要修剪的输入文本。

# /fuzzy 的参数

stscript
/fuzzy list=["candidate1","candidate2"] (input)
  1. list 是包含候选者的 JSON 序列化字符串数组。也可以指定包含该列表的变量名。必需参数。
  2. 未命名参数是要匹配的输入文本。输出是与输入最匹配的候选者之一。

# 自动补全

  • 自动补全在聊天输入和大型快速回复编辑器上都已启用。
  • 自动补全在您输入的任何位置都有效。即使有多个管道命令和嵌套闭包。
  • 自动补全支持三种查找匹配命令的方式(用户设置 -> STscript 匹配)。
  1. 开头匹配 "旧"方式。只有以输入值精确开头的命令才会显示。
  2. 包含匹配 所有包含输入值的命令都会显示。示例:输入 /delete 时,命令 /qr-delete/qr-set-delete 将显示在自动补全列表中(/qr-delete,/qr-set-delete)。
  3. 模糊匹配 所有可以与输入值进行模糊匹配的命令都会显示。示例:输入 /seas 时,命令 /sendas 将显示在自动补全列表中(/sendas)。
  • 自动补全也支持命令参数。对于必需参数,列表会自动显示。对于可选参数,按 Ctrl+Space 打开可用选项列表。
  • 输入 /: 执行闭包或 QR 时,自动补全将显示作用域变量和 QR 列表。
  • 自动补全对宏(在斜杠命令中)有有限的支持。输入 {{ 获取可用宏列表。
  • 使用箭头键从自动补全选项列表中选择一个选项。
  • EnterTab点击选项将选项放置到光标位置。
  • Escape 关闭自动补全列表。
  • Ctrl+Space 打开自动补全列表或切换所选选项的详细信息。

# 解析器标志

stscript
/parser-flag

解析器接受标志来修改其行为。这些标志可以在脚本中的任何点开启和关闭,所有后续输入将相应地进行评估。
您可以在用户设置中设置默认标志。

# 严格转义

stscript
/parser-flag STRICT_ESCAPING on |

启用 STRICT_ESCAPING 后的变化如下。

# 管道

在引号值中不需要转义管道。

stscript
/echo title="a|b" c\|d

# 反斜杠

符号前面的反斜杠可以被转义,以提供字面反斜杠后跟功能符号。

stscript
// 这将输出 "foo \",然后输出 "bar" |
/echo foo \\|
/echo bar
stscript
/echo \\|
/echo \\\|

# 替换变量宏

stscript
/parser-flag REPLACE_GETVAR on |

此标志有助于避免变量值包含可能被解释为宏的文本时的双重替换。{{var::}} 宏最后被替换,对结果文本/变量值不会进行进一步的替换。

将所有 {{getvar::}}{{getglobalvar::}} 宏替换为 {{var::}}。 在幕后,解析器将在带有替换宏的命令之前插入一系列命令执行器:

  • 调用 /let 将当前的 {{pipe}} 保存到作用域变量
  • 调用 /getvar/getglobalvar 获取宏中使用的变量
  • 调用 /let 将检索到的变量保存到作用域变量
  • 调用 /return 并使用保存的 {{pipe}} 值为下一个命令恢复正确的管道值
stscript
// 以下将输出最后一条消息的 ID / 编号 |
/setvar key=x \{\{lastMessageId}} |
/echo {{getvar::x}}
stscript
// 这将输出字面文本 {{lastMessageId}} |
/parser-flag REPLACE_GETVAR |
/setvar key=x \{\{lastMessageId}} |
/echo {{getvar::x}}

# 快速回复:脚本库和自动执行

快速回复是 SillyTavern 的内置扩展,提供了一种存储和执行脚本的简便方法。

# 配置快速回复

要开始,请启用扩展面板(堆叠块图标),然后展开快速回复菜单。

快速回复
快速回复

快速回复默认禁用,您需要先启用它们。 然后您将看到在聊天输入栏上方出现一个栏。

您可以设置显示的按钮文本标签(我们建议使用表情符号以保持简洁)和点击按钮时将执行的脚本。

按钮数量由插槽数量设置控制(最多 = 100),根据您的需求调整,完成后点击"应用"。

自动注入用户输入建议在使用 STscript 时禁用,否则可能会干扰您的输入,改为使用 {{input}} 宏在脚本中获取输入栏的当前值。

快速回复预设允许拥有多组预定义的快速回复,并可以手动切换或使用 /qrset (set name) 命令切换。 在切换到不同的预设之前,不要忘记点击"更新"以将您的更改写入当前使用的预设!

# 手动执行

现在您可以将您的第一个脚本添加到库中。选择任何空闲插槽(或创建一个),在左侧框中键入"Click me"以设置标签,然后将此粘贴到右侧框中:

stscript
/addvar key=clicks 1 |
/if left=clicks right=5 rule=eq else="/echo Keep going..." "/echo You did it!  \| /flushvar clicks"

然后在聊天栏上方出现的按钮上点击 5 次。 每次点击都会将变量 clicks 增加 1,并在值等于 5 时显示不同的消息并重置变量。

# 自动执行

通过单击创建命令的 按钮打开模态菜单。

自动执行

在此菜单中,您可以执行以下操作:

  • 在便捷的全屏编辑器中编辑脚本
  • 从聊天栏中隐藏按钮,使其仅可用于自动执行
  • 在以下一个或多个条件下启用自动执行:
    • 应用启动
    • 向聊天发送用户消息
    • 在聊天中接收 AI 消息
    • 打开角色或群组聊天
    • 触发群组成员的回复
    • 使用相同的自动化 ID 激活世界信息条目
  • 为快速回复提供自定义工具提示(悬停在 UI 中的快速回复上时显示的文本)
  • 为测试目的执行脚本

只有在启用快速回复扩展时,命令才会自动执行。

例如,您可以通过添加以下脚本并将其设置为在用户消息上自动执行,在发送五条用户消息后显示一条消息。

stscript
/addvar key=usercounter 1 |
/echo You've sent {{pipe}} messages. |
/if left=usercounter right=5 rule=gte "/echo Game over! \| /flushvar usercounter"

# 调试器

在展开的快速回复编辑器中存在一个基本的调试器。使用 /breakpoint | 在脚本中的任何位置设置断点。从 QR 编辑器执行脚本时,执行将在该点中断,允许您检查当前可用的变量、管道、命令参数等,并逐步执行剩余的代码。

stscript
/let x {: n=1
	/echo n is {{var::n}} |
	/mul n n |
:} |
/breakpoint |
/:x n=3 |
/echo result is {{pipe}} |
QR 编辑器调试器

# 调用过程

/run 命令可以通过标签调用在快速回复中定义的脚本,基本上提供了定义过程并从中返回结果的能力。这允许拥有可重用的脚本块,其他脚本可以引用这些块。过程管道中的最后一个结果将传递给其后的下一个命令。

stscript
/run ScriptLabel

让我们创建两个快速回复:


标签:

GetRandom

命令:

stscript
/pass {{roll:d100}}

标签:

GetMessage

命令:

stscript
/run GetRandom | /echo Your lucky number is: {{pipe}}

单击 GetMessage 按钮将调用 GetRandom 过程,该过程将解析 {{roll}} 宏并将数字传递给调用者,将其显示给用户。

  • 过程不接受命名或未命名参数,但可以引用与调用者相同的变量。
  • 调用过程时避免递归,因为如果处理不当可能会产生"调用堆栈超出"错误。

# 从不同的快速回复预设调用过程

您可以使用 a.b 语法从不同的快速回复预设调用过程,其中 a = QR 预设名称,b = QR 标签名称

stscript
/run QRpreset1.QRlabel1

默认情况下,系统将首先查找快速回复标签 a.b,因此如果您的某个标签字面意思是 "QRpreset1.QRlabel1",它将尝试运行该标签。如果找不到这样的标签,它将搜索名为 "QRpreset1" 的 QR 预设,其中包含标记为 "QRlabel1" 的 QR。

# 快速回复管理命令

# 创建快速回复

  • /qr-create (arguments, [message]) – 创建新的快速回复,示例:/qr-create set=MyPreset label=MyButton /echo 123

参数:

  • label - 字符串 - 按钮上的文本,例如 label=MyButton
  • set - 字符串 - QR 集的名称,例如 set=PresetName1
  • hidden - 布尔值 - 按钮是否应隐藏,例如 hidden=true
  • startup - 布尔值 - 在应用启动时自动执行,例如 startup=true
  • user - 布尔值 - 在用户消息时自动执行,例如 user=true
  • bot - 布尔值 - 在 AI 消息时自动执行,例如 bot=true
  • load - 布尔值 - 在聊天加载时自动执行,例如 load=true
  • title - 布尔值 - 要在按钮上显示的标题/工具提示,例如 title="My Fancy Button"

# 删除快速回复

  • /qr-delete (set=string [label]) – 删除快速回复

# 更新快速回复

  • /qr-update (arguments, [message]) – 更新快速回复,示例:/qr-update set=MyPreset label=MyButton newlabel=MyRenamedButton /echo 123

参数:

  • newlabel - 字符串 - 按钮的新文本,例如 newlabel=MyRenamedButton
  • label - 字符串 - 按钮上的文本,例如 label=MyButton
  • set - 字符串 - QR 集的名称,例如 set=PresetName1
  • hidden - 布尔值 - 按钮是否应隐藏,例如 hidden=true
  • startup - 布尔值 - 在应用启动时自动执行,例如 startup=true
  • user - 布尔值 - 在用户消息时自动执行,例如 user=true
  • bot - 布尔值 - 在 AI 消息时自动执行,例如 bot=true
  • load - 布尔值 - 在聊天加载时自动执行,例如 load=true
  • title - 布尔值 - 要在按钮上显示的标题/工具提示,例如 title="My Fancy Button"

#

  • qr-get - 检索快速回复的所有属性,示例:/qr-get set=myQrSet id=42

# 创建或更新 QR 预设

  • /qr-presetupdate (arguments [label])/qr-presetadd (arguments [label])

参数:

  • enabled - 布尔值 - 启用或禁用预设
  • nosend - 布尔值 - 禁用在用户输入中发送/插入(对斜杠命令无效)
  • before - 布尔值 - 将 QR 放置在用户输入之前
  • slots - 整数 - 插槽数量
  • inject - 布尔值 - 自动注入用户输入(如果禁用则使用 {{input}}

创建新预设(覆盖现有预设),示例:/qr-presetadd slots=3 MyNewPreset

# 添加 QR 上下文菜单

  • /qr-contextadd (set=string label=string chain=bool [preset name]) – 向 QR 添加上下文菜单预设,示例:/qr-contextadd set=MyPreset label=MyButton chain=true MyOtherPreset

# 删除所有上下文菜单

  • /qr-contextclear (set=string [label]) – 从 QR 中删除所有上下文菜单预设,示例:/qr-contextclear set=MyPreset MyButton

# 删除一个上下文菜单

  • /qr-contextdel (set=string label=string [preset name]) – 从 QR 中删除上下文菜单预设,示例:/qr-contextdel set=MyPreset label=MyButton MyOtherPreset

# 快速回复值转义

在 QR 消息/命令中,|{} 可以用反斜杠转义。

例如,使用 /qr-create label=MyButton /getvar myvar \| /echo \{\{pipe\}\} 创建一个调用 /getvar myvar | /echo {{pipe}} 的 QR。

# 扩展命令

SillyTavern 扩展(内置、可下载和第三方)可以添加自己的斜杠命令。以下只是官方扩展中功能的示例。列表可能不完整,请确保检查 /help slash 以获取可用命令的最完整列表。

  1. /websearch (query) — 在线搜索指定查询的网页片段,并将结果返回到管道。由网络搜索扩展提供。
  2. /imagine (prompt) — 使用提供的提示生成图像。由图像生成扩展提供。
  3. /emote (sprite) — 通过模糊匹配名称为活动角色设置精灵。由角色表情扩展提供。
  4. /costume (subfolder) — 为活动角色设置精灵集覆盖。由角色表情扩展提供。
  5. /music (name) — 按名称强制更改播放的背景音乐文件。由动态音频扩展提供。
  6. /ambient (name) — 按名称强制更改播放的环境声音文件。由动态音频扩展提供。
  7. /roll (dice formula) — 向聊天添加包含骰子结果结果的隐藏消息。由 D&D 骰子扩展提供。

# UI 交互

脚本还可以与 SillyTavern 的 UI 交互:浏览聊天或更改样式参数。

# 角色导航

  1. /random — 打开与随机角色的聊天。
  2. /go (name) — 打开与指定名称角色的聊天。首先搜索精确名称匹配,然后搜索前缀,最后搜索子字符串。

# UI 样式

  1. /bubble — 将消息样式设置为"气泡聊天"样式。
  2. /flat — 将消息样式设置为"平面聊天"样式。
  3. /single — 将消息样式设置为"单文档"样式。
  4. /movingui (name) — 按名称激活 MovingUI 预设。
  5. /resetui — 将 MovingUI 面板状态重置为其原始位置。
  6. /panels — 切换 UI 面板可见性:顶部栏、左右抽屉。
  7. /bg (name) — 使用模糊名称匹配查找并设置背景。尊重聊天背景锁定状态。
  8. /lockbg — 锁定当前聊天的背景图像。
  9. /unlockbg — 解锁当前聊天的背景图像。

# 更多示例

# 生成聊天摘要(由 @IkariDevGIT 提供)

stscript
/setglobalvar key=summaryPrompt Summarize the most important facts and events that have happened in the chat given to you in the Input header. Limit the summary to 100 words or less. Your response should include nothing but the summary. |
/setvar key=tmp |
/messages 0-{{lastMessageId}} |
/trimtokens limit=3000 direction=end |
/setvar key=s1 |
/echo Generating, please wait... |
/genraw lock=on instruct=off {{instructInput}}{{newline}}{{getglobalvar::summaryPrompt}}{{newline}}{{newline}}{{instructInput}}{{newline}}{{getvar::s1}}{{newline}}{{newline}}{{instructOutput}}{{newline}}The chat summary:{{newline}} |
/setvar key=tmp |
/echo Done! |
/setinput {{getvar::tmp}} |
/flushvar tmp |
/flushvar s1

# 按钮弹出窗口使用

stscript
/setglobalvar key=genders ["boy", "girl", "other"] |
/buttons labels=genders Who are you? |
/echo You picked: {{pipe}}

# 获取第 N 个斐波那契数(使用比奈公式)

stscript
/setvar key=fib_no 5 |
/pow 5 0.5 | /setglobalvar key=SQRT5 |
/setglobalvar key=PHI 1.618033 |
/pow PHI fib_no | /div {{pipe}} SQRT5 |
/round |
/echo {{getvar::fib_no}}th Fibonacci's number is: {{pipe}}

# 递归阶乘(使用闭包)

stscript
/let fact {: n=
    /if left={{var::n}} rule=gt right=1
        else={:
            /return 1
        :}
        {:
            /sub {{var::n}} 1 |
            /:fact n={{pipe}} |
            /mul {{var::n}} {{pipe}}
        :}
:} |

/input Calculate factorial of: |
/let n {{pipe}} |
/:fact n={{var::n}} |
/echo factorial of {{var::n}} is {{pipe}}