weft-ai-language

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Weft AI Language

Weft AI 语言

Skill by ara.so — Daily 2026 Skills collection.
Weft is a programming language (implemented in Rust) for AI systems where LLMs, humans, APIs, databases, and agents are base language primitives. You wire nodes together, the compiler type-checks every connection, and the program runs with durable execution backed by Restate (survives crashes, supports multi-day human-in-the-loop pauses). A visual graph view is generated automatically from code.

ara.so提供的技能 — 2026每日技能合集。
Weft是一款基于Rust实现的AI系统编程语言,其中LLM、人类、API、数据库和Agent都是语言的基础原语。你可以将节点连接在一起,编译器会检查每一个连接的类型,程序依托Restate实现持久化执行(可在崩溃后恢复,支持多日的人机交互暂停)。代码会自动生成可视化图形视图。

Installation & Setup

安装与配置

Prerequisites

前置要求

  • Docker (for PostgreSQL)
  • Node.js
  • macOS:
    brew install bash
    (Bash 4+ required)
  • Rust, Restate, and pnpm are auto-installed by
    dev.sh
  • Docker(用于PostgreSQL)
  • Node.js
  • macOS:
    brew install bash
    (需Bash 4及以上版本)
  • Rust、Restate和pnpm会由
    dev.sh
    自动安装

Clone and Configure

克隆与配置

bash
git clone https://github.com/WeaveMindAI/weft.git
cd weft
cp .env.example .env
bash
git clone https://github.com/WeaveMindAI/weft.git
cd weft
cp .env.example .env

Edit .env — add your API keys

编辑.env — 添加你的API密钥

undefined
undefined

Environment Variables (
.env
)

环境变量(
.env

bash
OPENROUTER_API_KEY=     # Required for LLM nodes
TAVILY_API_KEY=         # Required for Web Search nodes
ELEVENLABS_API_KEY=     # Required for Speech-to-Text nodes
APOLLO_API_KEY=         # Required for Apollo enrichment nodes
DISCORD_BOT_TOKEN=      # Required for Discord nodes
All keys are optional at startup — missing keys surface as runtime errors only when the relevant node executes.
bash
OPENROUTER_API_KEY=     # LLM节点必填
TAVILY_API_KEY=         # 网页搜索节点必填
ELEVENLABS_API_KEY=     # 语音转文本节点必填
APOLLO_API_KEY=         # Apollo增强节点必填
DISCORD_BOT_TOKEN=      # Discord节点必填
所有密钥在启动时均为可选——仅当相关节点执行时,缺失的密钥才会触发运行时错误。

Start Development

启动开发环境

bash
undefined
bash
undefined

Terminal 1 — backend (PostgreSQL, Restate, all services)

终端1 — 后端服务(PostgreSQL、Restate及所有服务)

./dev.sh server
./dev.sh server

Terminal 2 — dashboard (SvelteKit at http://localhost:5173)

终端2 — 控制面板(SvelteKit,地址为http://localhost:5173)

./dev.sh dashboard
./dev.sh dashboard

Or both at once

或者一次性启动所有服务

./dev.sh all
undefined
./dev.sh all
undefined

VS Code

VS Code

Use the Dev Local All task to start server + dashboard in split terminals.

使用Dev Local All任务可在拆分终端中同时启动服务器和控制面板。

Development Commands

开发命令

bash
./dev.sh server               # Start backend services
./dev.sh dashboard            # Start frontend
./dev.sh all                  # Start everything
./dev.sh extension            # Build browser extension

./cleanup.sh                  # Stop everything, wipe Restate + DB
./cleanup.sh --no-db          # Stop services, keep database
./cleanup.sh --services       # Stop services only
./cleanup.sh --db-destroy     # Remove PostgreSQL container entirely

cargo build                   # Build without running PostgreSQL (uses .sqlx snapshots)
cargo test                    # Test without running PostgreSQL
bash
./dev.sh server               # 启动后端服务
./dev.sh dashboard            # 启动前端
./dev.sh all                  # 启动所有服务
./dev.sh extension            # 构建浏览器扩展

./cleanup.sh                  # 停止所有服务,清空Restate与数据库
./cleanup.sh --no-db          # 停止服务,保留数据库
./cleanup.sh --services       # 仅停止服务
./cleanup.sh --db-destroy     # 彻底移除PostgreSQL容器

cargo build                   # 构建项目,无需运行PostgreSQL(使用.sqlx快照)
cargo test                    # 测试项目,无需运行PostgreSQL

Infrastructure Nodes (Kubernetes)

基础设施节点(Kubernetes)

Only needed if using nodes like Postgres Database that provision K8s resources:
bash
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.31.0/kind-$(uname -s | tr '[:upper:]' '[:lower:]')-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind

INFRASTRUCTURE_TARGET=local ./dev.sh server

仅在使用Postgres Database等需要部署K8s资源的节点时需要:
bash
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.31.0/kind-$(uname -s | tr '[:upper:]' '[:lower:]')-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind

INFRASTRUCTURE_TARGET=local ./dev.sh server

The Weft Language

Weft语言

Core Concepts

核心概念

  • Nodes — typed computational units (LLM, HTTP, Human Query, Gate, etc.)
  • Connections — typed edges between node ports; compiler validates all types
  • Groups — collapse any set of nodes into a single reusable node
  • Durable execution — programs checkpoint via Restate; long pauses are transparent
  • 节点 — 类型化计算单元(LLM、HTTP、人工查询、网关等)
  • 连接 — 节点端口间的类型化连接;编译器会验证所有类型
  • — 将任意节点集合并为单个可复用节点
  • 持久化执行 — 程序通过Restate创建检查点;长时间暂停对程序透明

Node Syntax

节点语法

weft
node_name = NodeType -> (output_port: OutputType) {
  label: "Human-readable name"
  config_key: "value"
}
node_name.input_port = other_node.output_port
weft
node_name = NodeType -> (output_port: OutputType) {
  label: "人类可读名称"
  config_key: "value"
}
node_name.input_port = other_node.output_port

Simple Example — Poem Generator

简单示例 — 诗歌生成器

weft
undefined
weft
undefined

Project: Poem Generator

项目:诗歌生成器

Description: Writes a short poem about any topic

描述:针对任意主题创作短诗

topic = Text { label: "Topic" value: "the silence between stars" }
llm_config = LlmConfig { label: "Config" model: "anthropic/claude-sonnet-4.6" systemPrompt: "Write a short, beautiful poem (4-6 lines) about the given topic." temperature: "0.8" }
poet = LlmInference -> (response: String) { label: "Poet" } poet.prompt = topic.value poet.config = llm_config.config
output = Debug { label: "Poem" } output.data = poet.response

---
topic = Text { label: "主题" value: "星辰间的寂静" }
llm_config = LlmConfig { label: "配置" model: "anthropic/claude-sonnet-4.6" systemPrompt: "针对给定主题创作一首简短优美的诗歌(4-6行)。" temperature: "0.8" }
poet = LlmInference -> (response: String) { label: "诗人" } poet.prompt = topic.value poet.config = llm_config.config
output = Debug { label: "诗歌" } output.data = poet.response

---

Built-in Node Catalog

内置节点目录

AI Nodes

AI节点

NodePurpose
LlmConfig
Configure model, system prompt, temperature
LlmInference
Call an LLM, returns
response: String
节点用途
LlmConfig
配置模型、系统提示词、温度参数
LlmInference
调用LLM,返回
response: String

Data Nodes

数据节点

NodePurpose
Text
Static or dynamic text value
Number
Numeric value
Dict
Key-value map
List
Ordered list
Pack
/
Unpack
Bundle/unbundle multiple values
节点用途
Text
静态或动态文本值
Number
数值
Dict
键值对映射
List
有序列表
Pack
/
Unpack
打包/解包多个值

Flow Nodes

流程节点

NodePurpose
Gate
Conditional branching
HumanQuery
Pause execution, send form to human, resume on response
HumanTrigger
Start a program from a human action
节点用途
Gate
条件分支
HumanQuery
暂停执行,向人类发送表单,收到响应后恢复
HumanTrigger
通过人类操作启动程序

Communication Nodes

通信节点

Discord
,
Slack
,
Telegram
,
WhatsApp
,
Email
,
X
Discord
,
Slack
,
Telegram
,
WhatsApp
,
Email
,
X

Storage Nodes

存储节点

Postgres
,
Memory
Postgres
,
Memory

Enrichment Nodes

增强节点

Apollo
,
WebSearch
,
SpeechToText
Apollo
,
WebSearch
,
SpeechToText

Trigger Nodes

触发节点

Cron
, webhooks, polling
Cron
、Webhook、轮询

Utility Nodes

工具节点

Debug
,
Template
,
HTTP
,
Code
(Python execution)

Debug
,
Template
,
HTTP
,
Code
(Python执行)

Common Patterns

常见模式

Pattern 1 — LLM with Structured Config

模式1 — 带结构化配置的LLM

weft
undefined
weft
undefined

Project: Content Summarizer

项目:内容摘要器

Description: Summarizes a webpage given a URL

描述:针对给定URL的网页内容生成摘要

url_input = Text { label: "URL" value: "https://example.com/article" }
search = WebSearch -> (results: String) { label: "Fetch Content" } search.query = url_input.value
summarizer_config = LlmConfig { label: "Summarizer Config" model: "anthropic/claude-sonnet-4.6" systemPrompt: "Summarize the following content in 3 bullet points." temperature: "0.3" }
summarizer = LlmInference -> (response: String) { label: "Summarizer" } summarizer.prompt = search.results summarizer.config = summarizer_config.config
output = Debug { label: "Summary" } output.data = summarizer.response
undefined
url_input = Text { label: "URL" value: "https://example.com/article" }
search = WebSearch -> (results: String) { label: "获取内容" } search.query = url_input.value
summarizer_config = LlmConfig { label: "摘要器配置" model: "anthropic/claude-sonnet-4.6" systemPrompt: "将以下内容总结为3个要点。" temperature: "0.3" }
summarizer = LlmInference -> (response: String) { label: "摘要器" } summarizer.prompt = search.results summarizer.config = summarizer_config.config
output = Debug { label: "摘要" } output.data = summarizer.response
undefined

Pattern 2 — Human-in-the-Loop Approval

模式2 — 人机交互审批流程

weft
undefined
weft
undefined

Project: Content Approval Pipeline

项目:内容审批流水线

Description: AI drafts content, human approves before publishing

描述:AI生成内容草稿,经人类审批后发布

draft_config = LlmConfig { label: "Drafter Config" model: "openai/gpt-4o" systemPrompt: "Write a Twitter thread about the given topic. Be engaging." temperature: "0.7" }
topic = Text { label: "Topic" value: "distributed systems" }
drafter = LlmInference -> (response: String) { label: "Content Drafter" } drafter.prompt = topic.value drafter.config = draft_config.config
draft_config = LlmConfig { label: "草稿生成配置" model: "openai/gpt-4o" systemPrompt: "针对给定主题创作Twitter推文,风格要吸引人。" temperature: "0.7" }
topic = Text { label: "主题" value: "分布式系统" }
drafter = LlmInference -> (response: String) { label: "内容草稿生成器" } drafter.prompt = topic.value drafter.config = draft_config.config

Pauses execution indefinitely until a human responds

无限期暂停执行,直到人类响应

approval = HumanQuery -> (approved: Boolean, feedback: String) { label: "Human Approval" question: "Do you approve this draft for publishing?" } approval.content = drafter.response
gate = Gate -> (passed: String) { label: "Approval Gate" } gate.condition = approval.approved gate.value = drafter.response
publisher = Discord { label: "Publish to Discord" channel: "announcements" } publisher.message = gate.passed
undefined
approval = HumanQuery -> (approved: Boolean, feedback: String) { label: "人工审批" question: "是否批准此草稿发布?" } approval.content = drafter.response
gate = Gate -> (passed: String) { label: "审批网关" } gate.condition = approval.approved gate.value = drafter.response
publisher = Discord { label: "发布至Discord" channel: "announcements" } publisher.message = gate.passed
undefined

Pattern 3 — Conditional Branching with Gate

模式3 — 基于网关的条件分支

weft
undefined
weft
undefined

Project: Sentiment Router

项目:情感路由

Description: Routes messages based on sentiment analysis

描述:根据情感分析结果路由消息

message = Text { label: "Input Message" value: "This product is absolutely terrible!" }
sentiment_config = LlmConfig { label: "Sentiment Config" model: "anthropic/claude-haiku-3.5" systemPrompt: "Classify sentiment as 'positive' or 'negative'. Respond with one word only." temperature: "0.0" }
classifier = LlmInference -> (response: String) { label: "Sentiment Classifier" } classifier.prompt = message.value classifier.config = sentiment_config.config
is_negative = Gate -> (passed: String) { label: "Is Negative?" } is_negative.condition = classifier.response is_negative.value = message.value
alert = Slack { label: "Alert Team" channel: "customer-issues" } alert.message = is_negative.passed
undefined
message = Text { label: "输入消息" value: "这个产品简直糟透了!" }
sentiment_config = LlmConfig { label: "情感配置" model: "anthropic/claude-haiku-3.5" systemPrompt: "将情感分类为'positive'或'negative'。仅用一个单词回复。" temperature: "0.0" }
classifier = LlmInference -> (response: String) { label: "情感分类器" } classifier.prompt = message.value classifier.config = sentiment_config.config
is_negative = Gate -> (passed: String) { label: "是否负面?" } is_negative.condition = classifier.response is_negative.value = message.value
alert = Slack { label: "通知团队" channel: "customer-issues" } alert.message = is_negative.passed
undefined

Pattern 4 — Cron-Triggered Pipeline

模式4 — Cron触发的流水线

weft
undefined
weft
undefined

Project: Daily Digest

项目:每日摘要

Description: Sends a daily news digest every morning

描述:每天早上发送AI与技术新闻摘要

schedule = Cron { label: "Daily Trigger" expression: "0 8 * * *" }
news = WebSearch -> (results: String) { label: "Fetch News" } news.query = "AI and technology news today"
digest_config = LlmConfig { label: "Digest Config" model: "openai/gpt-4o-mini" systemPrompt: "Summarize these news items into a concise morning digest." temperature: "0.4" }
digest = LlmInference -> (response: String) { label: "Digest Writer" } digest.prompt = news.results digest.config = digest_config.config
send = Email { label: "Send Digest" to: "team@example.com" subject: "Your Daily AI Digest" } send.body = digest.response
undefined
schedule = Cron { label: "每日触发器" expression: "0 8 * * *" }
news = WebSearch -> (results: String) { label: "获取新闻" } news.query = "今日AI与技术新闻"
digest_config = LlmConfig { label: "摘要配置" model: "openai/gpt-4o-mini" systemPrompt: "将这些新闻条目总结为简洁的晨间摘要。" temperature: "0.4" }
digest = LlmInference -> (response: String) { label: "摘要生成器" } digest.prompt = news.results digest.config = digest_config.config
send = Email { label: "发送摘要" to: "team@example.com" subject: "你的每日AI摘要" } send.body = digest.response
undefined

Pattern 5 — Multi-Step Research Agent

模式5 — 多步骤研究Agent

weft
undefined
weft
undefined

Project: Research Agent

项目:研究Agent

Description: Researches a topic and produces a structured report

描述:研究指定主题并生成结构化报告

query = Text { label: "Research Query" value: "latest advances in protein folding" }
search = WebSearch -> (results: String) { label: "Search" } search.query = query.value
query = Text { label: "研究查询" value: "蛋白质折叠的最新进展" }
search = WebSearch -> (results: String) { label: "搜索" } search.query = query.value

Enrich with professional data

用专业数据增强内容

enrichment = Apollo -> (data: String) { label: "Enrichment" }
analyst_config = LlmConfig { label: "Analyst Config" model: "anthropic/claude-sonnet-4.6" systemPrompt: "You are a research analyst. Given search results, produce a structured report with: Executive Summary, Key Findings, Implications, and Further Reading." temperature: "0.2" }
pack_inputs = Pack -> (bundle: Dict) { label: "Combine Sources" } pack_inputs.search_results = search.results
analyst = LlmInference -> (response: String) { label: "Research Analyst" } analyst.prompt = pack_inputs.bundle analyst.config = analyst_config.config
store = Postgres { label: "Store Report" table: "research_reports" } store.data = analyst.response
notify = Slack { label: "Notify Team" channel: "research" } notify.message = analyst.response

---
enrichment = Apollo -> (data: String) { label: "数据增强" }
analyst_config = LlmConfig { label: "分析师配置" model: "anthropic/claude-sonnet-4.6" systemPrompt: "你是一名研究分析师。根据搜索结果,生成包含以下部分的结构化报告:执行摘要、关键发现、影响分析、进一步阅读。" temperature: "0.2" }
pack_inputs = Pack -> (bundle: Dict) { label: "合并数据源" } pack_inputs.search_results = search.results
analyst = LlmInference -> (response: String) { label: "研究分析师" } analyst.prompt = pack_inputs.bundle analyst.config = analyst_config.config
store = Postgres { label: "存储报告" table: "research_reports" } store.data = analyst.response
notify = Slack { label: "通知团队" channel: "research" } notify.message = analyst.response

---

Adding a Custom Node

添加自定义节点

New nodes are two files in the
catalog/
directory. No registration needed — the
inventory
crate auto-discovers nodes at startup.
新节点需在
catalog/
目录下创建两个文件,无需注册——
inventory
crate会在启动时自动发现节点。

Step 1 — Create the folder

步骤1 — 创建文件夹

catalog/
└── my_category/
    └── my_node/
        ├── backend.rs
        └── frontend.ts
catalog/
└── my_category/
    └── my_node/
        ├── backend.rs
        └── frontend.ts

Step 2 — Implement
backend.rs

步骤2 — 实现
backend.rs

rust
use weft_nodes::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct MyNodeConfig {
    pub label: String,
    pub my_setting: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MyNodeInputs {
    pub text: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MyNodeOutputs {
    pub result: String,
}

pub struct MyNode;

#[async_trait]
impl Node for MyNode {
    type Config = MyNodeConfig;
    type Inputs = MyNodeInputs;
    type Outputs = MyNodeOutputs;

    async fn run(
        config: Self::Config,
        inputs: Self::Inputs,
    ) -> Result<Self::Outputs, NodeError> {
        let result = format!("{}: {}", config.my_setting, inputs.text);
        Ok(MyNodeOutputs { result })
    }
}
rust
use weft_nodes::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct MyNodeConfig {
    pub label: String,
    pub my_setting: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MyNodeInputs {
    pub text: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MyNodeOutputs {
    pub result: String,
}

pub struct MyNode;

#[async_trait]
impl Node for MyNode {
    type Config = MyNodeConfig;
    type Inputs = MyNodeInputs;
    type Outputs = MyNodeOutputs;

    async fn run(
        config: Self::Config,
        inputs: Self::Inputs,
    ) -> Result<Self::Outputs, NodeError> {
        let result = format!("{}: {}", config.my_setting, inputs.text);
        Ok(MyNodeOutputs { result })
    }
}

Step 3 — Define
frontend.ts

步骤3 — 定义
frontend.ts

typescript
import type { NodeDefinition } from "@/types/nodes";

export const MyNode: NodeDefinition = {
  type: "MyNode",
  label: "My Node",
  icon: "sparkles",       // Lucide icon name
  category: "my_category",
  inputs: [
    { name: "text", type: "String", required: true },
  ],
  outputs: [
    { name: "result", type: "String" },
  ],
  config: [
    { name: "label", type: "string", default: "My Node" },
    { name: "my_setting", type: "string", default: "prefix" },
  ],
};
After adding both files, run
./dev.sh server
— the node is available immediately.

typescript
import type { NodeDefinition } from "@/types/nodes";

export const MyNode: NodeDefinition = {
  type: "MyNode",
  label: "My Node",
  icon: "sparkles",       // Lucide图标名称
  category: "my_category",
  inputs: [
    { name: "text", type: "String", required: true },
  ],
  outputs: [
    { name: "result", type: "String" },
  ],
  config: [
    { name: "label", type: "string", default: "My Node" },
    { name: "my_setting", type: "string", default: "prefix" },
  ],
};
添加两个文件后,运行
./dev.sh server
——节点会立即生效。

Type System

类型系统

Weft has generics, unions, type variables, and null propagation.
TypeDescription
String
Text value
Number
Numeric value
Boolean
True/false
Dict
Key-value map
List
Ordered collection
T?
Nullable type — null propagates through the graph
T | U
Union type
The compiler validates every connection before execution. Type mismatches, missing required connections, and broken architecture are caught at compile time.

Weft支持泛型、联合类型、类型变量和空值传播。
类型描述
String
文本值
Number
数值
Boolean
布尔值(真/假)
Dict
键值对映射
List
有序集合
T?
可空类型——空值会在图中传播
T | U
联合类型
编译器会在执行前验证所有连接。类型不匹配、缺失必要连接和架构问题都会在编译阶段被捕获。

Project Layout Reference

项目结构参考

weft/
├── catalog/                # Node definitions — source of truth
│   ├── ai/                 # LlmConfig, LlmInference
│   ├── code/               # Python execution
│   ├── communication/      # Discord, Slack, Telegram, WhatsApp, Email, X
│   ├── data/               # Text, Number, Dict, List, Pack, Unpack
│   ├── enrichment/         # Apollo, WebSearch, SpeechToText
│   ├── flow/               # Gate, HumanQuery, HumanTrigger
│   ├── storage/            # Postgres, Memory
│   └── triggers/           # Cron, webhooks, polling
├── crates/
│   ├── weft-core/          # Type system, compiler, executor, Restate objects
│   ├── weft-nodes/         # Node trait, registry, sandbox, node runner
│   ├── weft-api/           # REST API (triggers, files, infra, usage)
│   └── weft-orchestrator/  # Restate services + Axum project executor
├── dashboard/              # Web UI (SvelteKit + Svelte 5)
├── extension/              # Browser extension for human-in-the-loop (WXT)
└── scripts/
    └── catalog-link.sh     # Symlinks catalog into crates + dashboard

weft/
├── catalog/                # 节点定义——事实来源
│   ├── ai/                 # LlmConfig、LlmInference
│   ├── code/               # Python执行
│   ├── communication/      # Discord、Slack、Telegram、WhatsApp、Email、X
│   ├── data/               # Text、Number、Dict、List、Pack、Unpack
│   ├── enrichment/         # Apollo、WebSearch、SpeechToText
│   ├── flow/               # Gate、HumanQuery、HumanTrigger
│   ├── storage/            # Postgres、Memory
│   └── triggers/           # Cron、Webhook、轮询
├── crates/
│   ├── weft-core/          # 类型系统、编译器、执行器、Restate对象
│   ├── weft-nodes/         # 节点 trait、注册表、沙箱、节点运行器
│   ├── weft-api/           # REST API(触发器、文件、基础设施、使用统计)
│   └── weft-orchestrator/  # Restate服务 + Axum项目执行器
├── dashboard/              # Web UI(SvelteKit + Svelte 5)
├── extension/              # 人机交互浏览器扩展(WXT)
└── scripts/
    └── catalog-link.sh     # 将catalog链接到crates和dashboard

Troubleshooting

故障排除

./dev.sh server
fails immediately

./dev.sh server
立即失败

  • Ensure Docker is running (
    docker ps
    )
  • Check that ports 5432 (Postgres), 8080 (Restate), and 9070 (Restate admin) are free
  • Run
    ./cleanup.sh
    then retry
  • 确保Docker正在运行(执行
    docker ps
    检查)
  • 检查端口5432(Postgres)、8080(Restate)和9070(Restate管理端)是否空闲
  • 运行
    ./cleanup.sh
    后重试

Node shows "API key missing" at runtime

节点在运行时显示“API密钥缺失”

  • Add the required key to
    .env
  • Restart the server (
    ./cleanup.sh --services && ./dev.sh server
    )
  • 将所需密钥添加到
    .env
    文件中
  • 重启服务器(执行
    ./cleanup.sh --services && ./dev.sh server

Type mismatch compiler error

编译器报错类型不匹配

  • Check that the output port type of the source node matches the input port type of the destination node
  • Use
    Pack
    to bundle multiple values into a
    Dict
    before passing to a node that expects
    Dict
  • Nullable types (
    T?
    ) can propagate null — use a
    Gate
    node to guard against null before consuming
  • 检查源节点的输出端口类型是否与目标节点的输入端口类型匹配
  • 使用
    Pack
    将多个值打包为
    Dict
    后,再传递给需要
    Dict
    类型的节点
  • 可空类型(
    T?
    )会传播空值——在使用前用
    Gate
    节点防范空值

Restate state is stale after a crash

崩溃后Restate状态过期

bash
./cleanup.sh        # Wipes Restate journal and DB, full reset
bash
./cleanup.sh        # 清空Restate日志和数据库,完全重置

cargo build
fails without running Postgres

未运行Postgres时
cargo build
失败

The
.sqlx
directory is committed — offline mode is supported:
bash
cargo build         # Works without a running database
cargo test          # Works without a running database
.sqlx
目录已提交——支持离线模式:
bash
cargo build         # 无需运行数据库即可构建
cargo test          # 无需运行数据库即可测试

New node not appearing in dashboard

新节点未在控制面板中显示

  • Confirm both
    backend.rs
    and
    frontend.ts
    exist under
    catalog/<category>/<node>/
  • Run
    ./scripts/catalog-link.sh
    manually then restart the server
  • Check server logs for inventory discovery errors

  • 确认
    backend.rs
    frontend.ts
    都存在于
    catalog/<category>/<node>/
    目录下
  • 手动运行
    ./scripts/catalog-link.sh
    后重启服务器
  • 检查服务器日志中的节点发现错误

Key Resources

关键资源