* feat(website): serve paseo.sh in Simplified Chinese
Every page of the website now has a Simplified Chinese version under
/zh-CN: the interface, docs, blog posts, comparison pages, legal pages,
all changelog releases and the homepage mockup. English URLs are unchanged.
The URL alone decides the language. There is no browser-language redirect
and no stored preference, because either would have to redirect the
unprefixed English URLs that people share and search engines index.
Internal links carry the page's language instead, and hreflang alternates
point Chinese search results at /zh-CN.
Translated headings pin the English anchor with {#id}, so section links
work in both languages. content-translations.test.ts fails when a page
has no translation or a translation's headings drift from the English.
Changelog releases and plugin listings without a translation render
whole in English under a notice, so a release never waits on one.
Plugin manifests and the registry gain optional translations and
OVERVIEW.zh-CN.md fields; older clients and registries ignore them.
* feat(website): replace the native language select with an EN/ZH menu
The header showed an OS-native select whose popup did not match the site.
The trigger now shows the language abbreviated (EN, ZH) and opens a menu in
the app's dropdown style that names each language in itself, with its name
in the page language underneath. Rows are real links to the same page in
that language; arrows, Escape, outside presses and taps behave as a menu
button, and the menu keeps itself on screen when a narrow header pushes the
trigger toward an edge.
Also drops the stray space after the full-width comma in the Chinese
homepage subtitle.
* docs(website): translate main's new docs and 0.12.0 release notes
Main added Keep run workspaces to the schedules docs, rewrote plugin icons
around inline SVG, and promoted 0.12.0 with new entries. Bring the Chinese
pages and changelog in line so no section falls back to English.
* fix(server): leave plugin listing translations to the registry
The daemon rejected manifests whose translations the registry would refuse,
so a plugin main installs could fail to load here. Paseo never reads
translations; the registry validates them at publish. Docs now say which
checks are automated at publish and which are human review.
* docs(plugins): describe the registry's final overview translation discovery
* style(server): format manifest test
* test(app): measure sidebar rows one at a time
After a reload the developer error toast appears while expectVerticalOrder
measures every row at once. Each concurrent boundingBox runs the toast
locator handler, and only one of them resumes, so the poll timed out on
every attempt since #7424. Measuring sequentially keeps one action in flight.
* test(app): return sidebar row measuring to main
#7480 hides the developer toast instead of running a locator handler, so
measuring the rows concurrently no longer races it. Reverts 41ac23016.
* test(app): wait for the compact shell before opening compact Changes
The shell survives the breakpoint, so right after the resize the wide
Explorer could still be visible: the test skipped the Explorer toggle and
the tab then disappeared, or toggled at the wrong time. Wait for the
compact-shell marker, as the composer helpers do since #7424.
* docs(website): translate main's plugin file panel docs
* test(app): edit the code font size after the font family remount
A committed appearance change remounts the settings screen through
AppearanceStyleBoundary, and the new form starts from the stored size.
Filling the size before that remount lost the edit in CI.
* docs(website): translate main's client/ui import docs
Follows #7474: one /client/ui entry, StreamedText instead of useRevealedText,
SettingsGroup dropped from the settings table, and the new
'UI imports in v0.13' migration section.
* test(app): wait for the previous layout's file panel picker to leave
After a resize the old layout's picker animates out while the new one is
already mounted, so the Use button matched two elements and the strict
locator failed. Wait for the shell's layout and a single picker first.
6.7 KiB
title, description, nav
| title | description | nav |
|---|---|---|
| Hub workflow | 用提示词、路由、输出和 Provider 权限构建有序的 Hub workflow。 | Workflow |
Hub workflow
一个 workflow 文件包含一个触发器,以及它启动的有序 step。文件从 .paseo/workflows/*.yml 中发现。
你的第一个 workflow
假设 .paseo/hub.yml 定义了一个名为 dev 的环境和一个名为 codex 的 Agent。添加 .paseo/workflows/slack-help.yml:
name: slack-help
on: slack.mention
max_runtime: 1h
filters:
workspace: T01234567
channels: [C01234567]
from_users: [U01234567]
steps:
- id: answer
environment: dev
max_runtime: 30m
idle_timeout: 5m
agent: codex
prompt:
- text: |
Answer the request. Call hub.reply once, then call hub.finish_execution.
<user-prompt>
${{ paseo.prompt }}
</user-prompt>
allow_outputs:
- { type: slack.reply, max: 1, required: true }
Hub 会先去掉提及和已声明的输入头部,再把剩余文本作为 ${{ paseo.prompt }} 提供。回复能力在 Slack 触发器旁边显式声明。Discord 使用 discord.reply;GitHub 使用 step 级的 github 块,而不是 hub.reply。
选择 step 在哪里运行
字面值选择一个命名环境:
environment: dev
有限取值的输入可以在多个完整的命名环境中选择:
name: route-repository
on: manual.run
max_runtime: 1h
filters:
from_users: [automation]
inputs:
repo:
type: string
required: true
choices: [paseo, hub]
steps:
- id: work
environment: ${{ paseo.inputs.repo }}
max_runtime: 30m
idle_timeout: 5m
agent: codex
prompt:
- text: ${{ paseo.prompt }}
激活时会检查每一个 choices 结果。环境对象永远不会被 workflow 合并或覆盖。
选择 Agent
step 可以选择一个命名 Agent:
agent: codex-safe
也可以提供一份完整的静态内联配置:
agent:
provider: claude
mode: full-access
对于动态路由,用一个有限取值的表达式在多个完整的命名 Agent 中选择:
name: route-agent
on: manual.run
max_runtime: 1h
filters:
from_users: [automation]
inputs:
agent:
type: string
required: true
choices: [codex-safe, claude]
steps:
- id: work
environment: paseo
max_runtime: 30m
idle_timeout: 5m
agent: ${{ paseo.inputs.agent }}
prompt:
- text: ${{ paseo.prompt }}
如果 codex-safe 在 hub.yml 中包含结构化的沙箱选项,选择它时会原样带上这些选项。像 provider: ${{ paseo.inputs.agent }} 这样的动态内联对象会被拒绝。
由分类器路由
前面的 step 可以返回有限取值的结构化输出。之后的权限必须由该输出 schema 中的 enum 或 const 加以限定。
name: classify-request
on: discord.mention
max_runtime: 2h
filters:
guild: "123456789012345678"
from_users: ["345678901234567890"]
values:
selected_environment: ${{ steps.classify.outputs.environment }}
selected_agent: ${{ steps.classify.outputs.agent }}
steps:
- id: classify
environment: hub
max_runtime: 5m
idle_timeout: 1m
agent: claude
prompt:
- include: partials/classify.md
- text: ${{ paseo.prompt }}
output:
schema:
type: object
required: [environment, agent]
properties:
environment: { enum: [paseo, hub] }
agent: { enum: [codex-safe, claude] }
additionalProperties: false
- id: work
environment: ${{ values.selected_environment }}
max_runtime: 1h
idle_timeout: 10m
agent: ${{ values.selected_agent }}
prompt:
- text: |
Complete the request. Call hub.reply once, then call hub.finish_execution.
- text: ${{ paseo.prompt }}
allow_outputs:
- { type: discord.reply, max: 1, required: true }
.paseo/workflows/partials/classify.md:
Choose one configured repository environment and one complete named agent configuration.
这个 workflow 保留了一个分类器分支和一个执行者分支,不需要为每个环境/Provider 组合重复编写执行者 step。
提示词与上下文
提示词块保持有序。include 的内容是文件的字面内容;Hub 不会递归扫描片段文本。
prompt:
- include: partials/instructions.md
- text: |
Provider evidence:
${{ paseo.context }}
<user-prompt>
${{ paseo.prompt }}
</user-prompt>
${{ paseo.prompt }}是规范化后的请求文本。它始终在编写的提示词中显式出现。${{ paseo.context }}让该 step 选择加入 Provider 上下文的物化,并插入 JSON。没有这个表达式时,Hub 不会获取或注入环境上下文。
把不受信任的请求文本放在界限清晰的块中。片段是指令文本,而不是隐藏的权限。
条件与有序输出
step 按文件顺序运行。if 可以读取输入、值和之前 step 的输出:
name: conditional-review
on: manual.run
max_runtime: 1h
filters:
from_users: [automation]
steps:
- id: inspect
environment: paseo
max_runtime: 10m
idle_timeout: 2m
agent: codex-safe
prompt:
- text: ${{ paseo.prompt }}
output:
schema:
type: object
required: [needs_review]
properties:
needs_review: { type: boolean }
additionalProperties: false
- id: review
if: ${{ steps.inspect.outputs.needs_review == true }}
environment: paseo
max_runtime: 30m
idle_timeout: 5m
agent: claude
prompt:
- text: Review the prior result and call hub.finish_execution.
step 不能读取之后的 step。step ID 在 workflow 内唯一。
告诉 Agent 调用哪个工具
allow_outputs 授予一项能力;它不会改写提示词。请写明需要执行的操作:
prompt:
- text: |
Send the final answer with hub.reply.
Then call hub.finish_execution.
allow_outputs:
- type: slack.reply
max: 1
required: true
max 默认为 1。required: true 会阻止成功完成,直到该能力被使用过。请把 Slack 和 Discord 的回复类型分别放在各自 Provider 的 workflow 文件中。
时限
workflow 的 max_runtime 限制整次运行。每个 step 都有自己的 max_runtime 和 idle_timeout;workflow 的剩余时间同时为两者封顶。超时会让运行失败,并停止之后的 step。