Puter Worker 路由(router)开发指南:定义 HTTP 接口、读取双上下文并操作共享存储
Puter Worker 采用基于 router 的路由体系处理 HTTP 请求——router 对象在 Worker 代码中自动可用,用于把不同的 URL 路径与方法分发给对应的处理函数。本文以此官方文档 router.md 为主体,结合仓库内 Worker 运行时源码(s2w-router.js)、类型声明(router.d.ts)与客户端 SDK(Workers.js)展开讲解。读完本文,你将掌握:如何用 router 注册 GET/POST/PUT/DELETE/OPTIONS 端点、如何捕获路径参数与通配路径、CORS 的自动处理规则,以及如何在一个 Worker 中同时操作"调用者数据"(user.puter)与"Worker 属主数据"(me.puter)实现 User-Pays 计费与共享服务逻辑。
Router 是什么:Worker 的 HTTP 请求分发中心
Puter Worker 是部署在 Puter 上的无服务器计算单元,接收外部 HTTP 请求并执行服务端逻辑。与直接监听 fetch 事件不同,Puter Worker 默认把请求交给全局 router 对象统一调度。当你基于 JS 文件部署 Worker 后(部署方式见 create.md),运行时会自动注入一个带路由能力的运行时,见 index.js:
import initS2w from './s2w-router.js';
initS2w();
initS2w()(server-to-worker 路由)完成两件事:构造 router 并挂到 globalThis.router 上,然后注册一个 fetch 事件监听器,把所有请求交给 router.route(event) 处理(见 s2w-router.js):
globalThis.router = router;
self.addEventListener('fetch', (event) => {
if (!router.routing) {
return false;
}
event.respondWith(router.route(event));
return true;
});
因此你的 Worker 源码不需要任何 import 语句,直接使用 router 即可。一个最简端点长这样:
router.post("/my-endpoint", async ({ request, user, params }) => {
return { message: "Hello, World!" };
});
处理器返回的普通对象会被运行时自动序列化为 JSON 响应,无需手动构造 Response。
支持的标准 HTTP 方法
router 为常用 HTTP 动词提供了同名注册方法,签名统一为 router.<method>(path, handler):
router.get(path, handler)—— 处理 GET 请求router.post(path, handler)—— 处理 POST 请求router.put(path, handler)—— 处理 PUT 请求router.delete(path, handler)—— 处理 DELETE 请求router.options(path, handler)—— 处理 OPTIONS 请求(会接管预检处理,见下文 CORS 章节)
从源码看(s2w-router.js),这些方法内部都委托给同一个 custom(eventName, route, eventListener):按 HTTP 方法名把"路由匹配器 + 处理函数"追加进 router.map(一个 Map,键为请求方法,值为匹配器数组)。因此还额外暴露了 router.custom(method, path, handler),可注册任意 HTTP 方法。类型声明见 router.d.ts:
/**
* Register a handler for an arbitrary HTTP method (e.g. `PATCH`, `HEAD`).
* The other verb methods all delegate to this internally.
*/
custom<S extends string>(method: string, path: S, handler: ...): void;
例如注册 PATCH 端点:router.custom('PATCH', '/posts/:id', ({ params }) => ({ patched: params.id }))(该写法在 example.worker.ts 的类型冒烟测试中出现过)。
此外,router 上还有两个运行时可调开关(见 router.d.ts):
routing: boolean—— 默认true。置为false后 Worker 停止处理 fetch 事件(index.js中router.routing为假时直接跳过请求)。handleCors: boolean—— 默认true。为true时由路由自动应答预检OPTIONS,并为缺少Access-Control-Allow-Origin的响应自动补上*;false则全部交由你自己的处理器决定。
处理器参数(Handler Parameters)
每个路由处理函数接收一个参数对象,通常解构出以下三个属性:
request—— 进来的 HTTP 请求,是 Web 标准的Request对象,可用request.url、request.json()、request.formData()、request.headers.get(...)等方法读取请求信息。user—— 发起该请求的用户对象。user.puter允许访问该用户自己的 Puter 资源(KV、FS、AI 等)。仅当 Worker 通过puter.workers.exec()被调用、并携带用户 token 时才会出现。params—— 从路径中捕获的路由参数对象(见下文"路径参数")。
运行时传给处理函数的事件对象本质上是 WorkerEvent,其类型定义(event.d.ts)完整反映了这一点:
export interface WorkerEvent<TParams extends Params = Params> extends Extendable {
request: Request;
params: TParams;
user?: PuterContext; // 仅当带 puter-auth 头调用时存在
waitUntil(f: Promise<any>): void;
}
注意:user 在类型上是可选的(user?),代码里必须先判空再访问 user.puter,否则在匿名 HTTP 调用下会抛错。事件对象上还有与 ExtendableEvent.waitUntil() 语义一致的 waitUntil(),可用来让 Worker 持续运行到某个后台任务结束。
全局对象(Global Objects)
编写 Worker 时可直接访问以下全局对象:
router—— 用于定义 API 端点的路由器对象。me—— 代表你自己,即 Worker 的属主。me.puter允许访问你自己的 Puter 资源(KV、FS、AI 等)。my、myself——me的兼容别名(已标记 deprecated,未来会移除)。puter_auth、puter_endpoint—— 旧版环境绑定,分别对应部署者的 Puter auth token 与 API 端点(默认https://api.puter.com),同样已标记 deprecated。
全局声明见 globals.d.ts。从运行时源码看,me 与 user 都是在 router.route(event) 入口处被注入的(s2w-router.js):
async route(event) {
// 1) 首次调用时初始化属主上下文 me,使用 Worker 自己的凭据
if (!globalThis.me) {
globalThis.me = {
puter: init_puter_portable(
globalThis.puter_auth,
globalThis.puter_endpoint || 'https://api.puter.com',
'userPuter',
),
};
globalThis.my = me;
globalThis.myself = me;
}
// 2) 若请求头携带 puter-auth,则注入调用者上下文 user
if (event.request.headers.has('puter-auth')) {
event.requestor = {
puter: init_puter_portable(
event.request.headers.get('puter-auth'),
globalThis.puter_endpoint || 'https://api.puter.com',
'userPuter',
),
};
event.user = event.requestor;
}
...
}
这段代码印证了文档的描述:me 永远是 Worker 属主,user 是否存在取决于请求是否带了 puter-auth 头。
路由匹配的底层原理
为了帮你准确理解路径参数与通配符的边界行为,这里展开运行时 buildRouteMatcher 的实现(s2w-router.js)。它把用户写的路由字符串编译成正则表达式:
- 普通字符会被
escapeRegex转义后原样保留; - 遇到
:开头的一个参数名(由[A-Za-z0-9_]字符连续组成),编译为([^/]+),即匹配单个路径段、不含斜杠; - 遇到
*开头的一个参数名,编译为(.*),即贪婪匹配剩余任意字符(可含斜杠); - 如果
:或*后面没有任何合法名称字符,则当作普通字面量转义保留——这正是文档强调"裸*不生效、必须命名"的原因; - 正则整体以
^开头、$结尾,即整条 pathname 必须完全匹配。
每个已注册的方法都保存这样一个"匹配器 + 处理器"对。请求到达后按方法取出映射,逐个对 url.pathname 执行 regex.exec,命中即把捕获组写入 event.params 并调用处理器(s2w-router.js);全部未命中则返回 404 "Path not found";处理器抛错则被捕获并返回 500。
处理器返回值自动包装
运行时对处理器的返回值有一套自动包装逻辑(s2w-router.js):
- 返回
Response对象:原样使用; - 返回
Blob、ArrayBuffer、Uint8Array、ReadableStream、URLSearchParams或字符串:自动new Response(value)包装; - 返回普通对象/数组/其他可 JSON 序列化值:
JSON.stringify后包装为Content-Type: application/json的响应; - 以上都包装失败:抛错,最终由外层兜底为 500 响应。
对应类型定义在 event.d.ts 的 HandlerReturn 中:Response | string | Blob | ArrayBuffer | Uint8Array | ReadableStream | URLSearchParams | Record<string, unknown> | unknown[] | number | boolean | null。理解这套规则后,下面各种返回值的写法就一目了然了。
路径参数(Route Parameters)
路径中并非每一段都是固定值(如文章 ID、用户名)。把这些段用冒号 : 前缀命名,即可捕获到 params 对象上,键名为你给的名字:
router.get("/api/posts/:category/:id", async ({ params }) => {
const { category, id } = params;
return { category, id };
});
请求 /api/posts/tech/42 命中该路由后:
params.category→"tech"params.id→"42"
参数数量不限。捕获到的值永远是字符串——如果期望的是数字,记得自行转换(如 Number(params.id))。
从源码层面看,:category、:id 被编译为两个独立的 ([^/]+) 捕获组,值按名称顺序填入 params。类型层面,运行时类型声明能直接从路径字面量推导出 params 的类型:ExtractParams<'/posts/:id'> 被解析为 { id: string }(见 params.d.ts),因此写 TypeScript 时无需手动标注 params.id 的类型(该特性在 example.worker.ts 的类型冒烟测试中有体现)。
通配符路由(Wildcard Routes)
路径参数 :name 只匹配单个路径段,而通配符 *name 匹配剩余整段路径——任意数量的段。与路径参数一样,匹配值会以 * 后面的名字作为键出现在 params 上:
router.get("/files/*path", async ({ params }) => {
// 请求 /files/images/avatars/me.png 时:
// params.path === "images/avatars/me.png"
return { path: params.path };
});
两条必须记住的规则:
- 通配符必须命名——写
*path(名字随意),不能写裸*。裸*因为没有后续名称字符,在buildRouteMatcher里被当作字面量转义,路由只会精确匹配路径/files/*而不会匹配任何子路径(这正是文档明确警告的行为)。 - 通配符路由是"兜底"手段——捕获型匹配器按注册顺序逐一尝试,通配符贪婪匹配所有剩余路径,因此应把 catch-all 路由定义在最后,确保只在其他路由都未命中时才执行。一个典型的 404 Handler 就长这样(放最后):
- 通用 GET 兜底:
router.get("/*page", ...); - 若需要同时兜底所有方法,可对每种方法分别注册兜底,或用
router.custom配合方法判断。
- 通用 GET 兜底:
CORS:默认自动处理
CORS 由运行时自动处理,你通常无需写任何 CORS 代码:
- 每个响应都会自动带上
Access-Control-Allow-Origin: *(若响应尚未含有该头,运行时会在返回前补上,见 s2w-router.js); - 预检
OPTIONS请求被自动应答。当收到带Origin、Access-Control-Request-Method、Access-Control-Request-Headers的 OPTIONS 请求且该 Worker 没有自定义 OPTIONS 路由时,默认的handleOptions会返回包含Access-Control-Allow-Origin: *、Access-Control-Allow-Methods: GET,HEAD,POST,PUT,DELETE,OPTIONS、Access-Control-Max-Age: 86400的 204 应答,并回显请求方申请的Access-Control-Allow-Headers(见 s2w-router.js)。
这意味着跨域调用开箱即用——包括 puter.workers.exec():它会把调用者的 Puter token 放进自定义请求头 puter-auth 发给 Worker(user.puter 正是由这个头注入的),全程不需要你处理任何 CORS。
唯一的例外:如果你自己定义了 OPTIONS 处理器,就等于接管了预检应答,这时浏览器期望的响应头需要你自己负责。例如:
router.options("/*path", async () => {
return new Response(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization, puter-auth",
},
});
});
警告:如果你覆盖了预检处理,并且 Worker 仍要通过
puter.workers.exec()调用,那么必须把puter-auth列入Access-Control-Allow-Headers——否则预检失败,请求根本到不了你的 Worker。
双上下文编程:me.puter 与 user.puter
与普通 App/网站一样,Worker 里也能使用 Puter.js 访问 AI、云存储、KV、数据库。区别在于用的是谁的资源:Worker 暴露给你两个 .puter 对象,每次操作记在调用它的那个账户头上:
me.puter(Worker 上下文 / 属主上下文):Worker 属主自己的资源。适合存放共享的应用数据、服务端逻辑与集中式资源。操作跑在属主账户上,费用记在属主名下。user.puter(用户上下文):调用该 Worker 的用户的资源(仅当通过puter.workers.exec()以用户 token 执行时可用)。它保持了默认的 User-Pays(用户付费)模型:每个用户的数据留在自己的存储、费用记在自己账上,而你的服务端逻辑照常执行。
因此你可以在同一份代码里混用两者——某些端点读写自己的数据(me.puter),另一些端点操作调用者数据(user.puter),费用互不混淆。
从客户端实现看,puter.workers.exec() 的本质(Workers.js)是"fetch + 自动附加会话头":
async exec (...args) {
await this.#authenticateIfNeeded();
const req = new Request(...args);
if ( ! req.headers.get('puter-auth') && !req.headers.get('x-puter-no-auth')) {
req.headers.set('puter-auth', this.puter.authToken);
}
req.headers.delete('x-puter-no-auth');
return fetch(req);
}
它接受与 Fetch API 相同的 (input, init?) 参数并返回 Response。如果需要"不带会话"地调用(即不让 Worker 获得用户上下文),显式传入 x-puter-no-auth 头即可跳过 puter-auth 注入。
常用端点写法速查
以下是官方文档给出的各类常见写法,覆盖请求读取与响应构造的所有常规形态。
基础 GET 端点
router.get("/api/hello", async ({ request }) => {
// Simple GET endpoint
return { message: "Hello, World!" };
});
读取 JSON 请求体
router.post("/api/user", async ({ request }) => {
// Get JSON body
const body = await request.json();
return { processed: true };
});
读取表单数据(multipart/form-data)
router.post("/api/user", async ({ request }) => {
// Get form data
const formData = await request.formData();
return { processed: true };
});
读取查询参数
router.get("/api/search", async ({ request }) => {
// Read query string parameters from the URL
const url = new URL(request.url);
const query = url.searchParams.get("q");
return { query };
});
读取请求头
router.post("/api/user", async ({ request }) => {
// Get headers
const contentType = request.headers.get("content-type");
return { processed: true };
});
带路径参数
router.get("/api/posts/:category/:id", async ({ request, params }) => {
const { category, id } = params;
return { category, id };
});
各类响应形态
根据前文"返回值自动包装"规则,以下几种写法都合法:
// JSON 响应(对象自动转 JSON)
router.get("/api/simple", async ({ request }) => {
return { status: "ok" }; // Automatically converted to JSON
});
// 纯文本响应
router.get("/api/text", async ({ request }) => {
return "Hello World"; // Returns plain text
});
// Blob 响应
router.get("/api/blob", async ({ request }) => {
return new Blob(["Hello World"], { type: "text/plain" });
});
// Uint8Array 响应(字节内容:"Hello World")
router.get("/api/uint8array", async ({ request }) => {
return new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
});
// 二进制流响应
router.get("/api/binary-stream", async ({ request }) => {
return new ReadableStream({
start(controller) {
controller.enqueue(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
);
controller.close();
},
});
});
// 完全自定义的 Response 对象(状态码 + 自定义头)
router.get("/api/custom", async ({ request }) => {
return new Response(JSON.stringify({ data: "custom" }), {
status: 200,
headers: {
"Content-Type": "application/json",
"Custom-Header": "value",
},
});
});
返回自定义错误响应
用 Response 设置状态码与响应头即可精确控制错误语义:
router.post("/api/risky-operation", async ({ request }) => {
try {
const body = await request.json();
const result = await someRiskyOperation(body);
return { success: true, result };
} catch (error) {
return new Response(
JSON.stringify({
error: "Operation failed",
message: error.message,
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
}
);
}
});
实战整合:与 Puter 资源的双向打通
下面几组示例演示 Worker 最有价值的用法——把"请求处理"和"属主/调用者的 Puter 资源"串起来。
Worker 上下文 vs 用户上下文
同一类操作可以分别跑在两个账户上。下面两个端点分别从调用者 KV 与属主 KV 读值:
// 从调用者的 KV 存储读取(user context)
router.get("/api/kv/user/get", async ({ request, user }) => {
const url = new URL(request.url);
const key = url.searchParams.get("key");
const value = await user.puter.kv.get(key);
return { value };
});
// 从 Worker 属主的 KV 存储读取(worker context)
router.get("/api/kv/worker/get", async ({ request }) => {
const url = new URL(request.url);
const key = url.searchParams.get("key");
const value = await me.puter.kv.get(key);
return { value };
});
文件系统(FS)集成:接收上传
router.post("/api/upload", async ({ request }) => {
const formData = await request.formData();
const file = formData.get("file");
if (!file) {
return new Response(JSON.stringify({ error: "No file provided" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
const fileName = `upload-${Date.now()}-${file.name}`;
await me.puter.fs.write(fileName, file);
return {
uploaded: true,
fileName,
originalName: file.name,
size: file.size,
};
});
KV 集成(含命名空间前缀与 404 语义)
一个值得借鉴的实践:Worker 属主与调用者共享同一账户的 KV 时,用固定前缀隔离不同数据域,避免误读调用者的其他业务数据:
router.post("/api/kv/set", async ({ request }) => {
const { key, value } = await request.json();
if (!key || value === undefined) {
return new Response(JSON.stringify({ error: "Key and value required" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
await me.puter.kv.set("myscope_" + key, value); // 加前缀,避免盲读到用户的其他 KV 数据
return { saved: true, key };
});
router.get("/api/kv/get/:key", async ({ request, params }) => {
const key = params.key;
const value = await me.puter.kv.get("myscope_" + key); // 读取时用同一前缀
if (!value) {
return new Response(JSON.stringify({ error: "Key not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}
return { key, value: value };
});
AI 集成:鉴权 + 双上下文配合
这个例子同时示范了三件事:用 user 判空做鉴权拦截(防止匿名滥用)、用调用者的 AI 资源完成对话(费用记在用户头上)、再用属主 KV 记录审计/分析数据:
router.post("/api/chat", async ({ request, user }) => {
const { message } = await request.json();
if (!message) {
return new Response(JSON.stringify({ error: "Message required" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
// 要求用户鉴权,防止滥用
if (!user || !user.puter) {
return new Response(
JSON.stringify({
error: "Authentication required",
message:
"This endpoint requires user authentication. Call this worker via puter.workers.exec() with your user token to use your own AI resources.",
}),
{
status: 401,
headers: { "Content-Type": "application/json" },
}
);
}
try {
// 使用调用者的 AI 资源
const aiResponse = await user.puter.ai.chat(message);
// 把聊天历史记到开发者自己的 KV,用于分析
const chatHistory = {
userId: user.id || "unknown",
message,
response: aiResponse,
timestamp: new Date().toISOString(),
usedUserAI: true,
};
await me.puter.kv.set(`chat_${Date.now()}`, chatHistory);
return {
originalMessage: message,
aiResponse,
usedUserAI: true,
};
} catch (error) {
return new Response(
JSON.stringify({
error: "AI service error",
message: error.message,
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
}
);
}
});
404 Handler:始终为未匹配路径兜底
推荐始终为未匹配路径提供一个兜底路由,返回结构化的 404 而非裸错误。兜底通配路由要注册在所有具体路由之后:
router.get("/*page", async ({ request, params }) => {
const requestedPath = params.page;
return new Response(
JSON.stringify({
error: "Not found",
path: requestedPath,
message: "The requested endpoint does not exist",
availableEndpoints: ["/api/hello", "/api/data", "/api/upload"],
}),
{
status: 404,
headers: { "Content-Type": "application/json" },
}
);
});
补充说明:即便不写兜底路由,运行时也会为未命中路径返回 404 "Path not found"、为"方法存在但该请求方法没有路由"返回 404 "No routes for given request type ..."(见 s2w-router.js);自定义兜底的价值在于提供更友好的业务化提示。若想区分不同方法,可对 post、put 等分别注册 /*page 兜底。
完整示例:一个多端点 Worker
以下是一个聚合了健康检查、用户管理、文件上传与兜底 404 的完整 Worker,几乎覆盖了 router 的全部常用模式。注意示例中刻意做了两点防护:写入 KV 的 key 一律使用 user_ 前缀并在读取时校验,防止任意读/写内部键:
// 健康检查
router.get("/health", async () => {
return {
status: "ok",
timestamp: new Date().toISOString(),
};
});
// 用户管理 API
router.post("/api/users", async ({ request, user }) => {
const userInfo = await user.puter.getUser();
// 存储用户数据(写入属主 KV)
const userId = `user_${Date.now()}`;
await me.puter.kv.set(userId, {
email: userInfo.email,
name: userInfo.username,
});
return {
userId,
user: {
email: userInfo.email,
username: userInfo.username,
uuid: userInfo.uuid,
},
};
});
router.get("/api/users/:id", async ({ params }) => {
const userId = params.id;
if (!userId.startsWith("user_"))
// security check:防止读取任意 KV 键
return new Response("Invalid userID!");
const userData = await me.puter.kv.get(userId);
if (!userData) {
return new Response(
JSON.stringify({
error: "User not found",
}),
{
status: 404,
headers: { "Content-Type": "application/json" },
}
);
}
return { userId, user: userData };
});
// 文件操作
router.post("/api/files/upload", async ({ request }) => {
const formData = await request.formData();
const file = formData.get("file");
if (!file) {
return new Response(
JSON.stringify({
error: "No file provided",
}),
{
status: 400,
headers: { "Content-Type": "application/json" },
}
);
}
const fileName = `upload-${Date.now()}-${file.name}`;
await me.puter.fs.write(fileName, file);
return {
uploaded: true,
fileName,
originalName: file.name,
size: file.size,
};
});
// 404 兜底:始终放在最后
router.get("/*tag", async ({ params }) => {
return new Response(
JSON.stringify({
error: "Not found",
path: params.tag,
availableEndpoints: ["/health", "/api/users", "/api/files/upload"],
}),
{
status: 404,
headers: { "Content-Type": "application/json" },
}
);
});
安全提醒(从示例中可以提炼出的通用规范):
- 用
me.puter持有集中式共享状态时,所有 KV 键设计为带业务前缀的受控命名空间,并由服务端自己拼接,不直接信任外部传来的完整键名; - 对外暴露按 ID 读取资源的端点时,先校验 ID 格式(如
startsWith("user_"))再落库查询; - 需要调用者身份/数据时,先判
user是否存在,缺失即返回 401 引导走puter.workers.exec()。
部署后如何测试你的 Router
部署 Worker 后,可以在任意网站/App(含 Node.js 环境,均可调用 puter.workers 模块)里用 puter.workers.exec() 验证端点。它会自动带上调用者的会话(puter-auth 头),从而同时测出 user context 是否正常注入:
// 测试你的 Worker 端点
const workerUrl = "https://your-worker.puter.work";
// 测试 GET 端点
const response = await puter.workers.exec(`${workerUrl}/api/hello`);
const data = await response.json();
console.log(data);
// 测试 POST 端点
const postResponse = await puter.workers.exec(`${workerUrl}/api/data`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ key: "test", value: "hello" }),
});
const postData = await postResponse.json();
console.log(postData);
若想测试"无会话调用",按 Workers.js 的实现可显式添加 x-puter-no-auth 头,此时 user 上下文不会被注入,可用于验证 Worker 对匿名请求的兜底行为。Worker 的创建、查询、删除与日志流分别见 create.md、get.md、list.md、delete.md,完整的运行时参数类型见 types.md 与 worker-types 目录下的声明文件。
小结
Puter Worker 的 router 是一个功能完整但极简的 HTTP 路由层:五种标准方法 + custom 兜底所有动词、: 捕获单段参数、*name 贪婪匹配剩余路径、自动 CORS 与自动响应包装,再加上 me.puter / user.puter 双上下文。理解匹配器的正则语义(单段 vs 多段、裸 * 是字面量)与运行时注入规则(puter-auth 头决定 user 是否存在),就能写出既安全又能精确控制计费归属的 Worker API。建议动手改一改 example.worker.ts 里的冒烟用例,在真实仓库中验证你理解的各种边界行为。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00