pi-mono扩展开发指南:构建自定义生态与外部服务集成
第一章:扩展开发基础架构
技术要点提示
- 扩展系统核心概念:Extensions作为功能扩展的统一接口
- 模块化文件结构:遵循特定目录组织实现自动发现
- 工具注册机制:静态声明与动态加载的双重支持
- 上下文访问模型:通过ToolContext实现功能交互
- 事件驱动架构:基于事件总线的扩展间通信
1.1 扩展系统架构解析
pi-mono的扩展系统采用插件化架构设计,允许开发者通过统一接口扩展核心功能。该系统基于TypeScript构建,提供类型安全的开发体验,同时支持动态加载与热更新。扩展可以添加新工具、修改UI行为、集成外部服务,或改变agent的决策逻辑。
图1:pi-mono交互式模式界面,展示了扩展加载后的功能界面
扩展系统主要由以下组件构成:
- 扩展加载器:负责发现、验证和加载扩展
- 上下文对象:提供扩展与核心系统的交互接口
- 事件总线:实现扩展间的松耦合通信
- 工具注册表:管理所有可用工具的元数据
1.2 从零构建扩展:从文件组织到功能实现
pi-mono扩展采用标准化的文件结构,确保系统能够自动发现并正确加载:
extensions/
my-extension/ # 扩展根目录
index.ts # 扩展入口文件
package.json # 扩展元数据
src/ # 源代码目录
tools/ # 工具定义
components/ # UI组件
utils/ # 辅助函数
test/ # 测试代码
README.md # 扩展文档
以下是一个基础扩展的实现示例,创建一个简单的天气查询工具:
// index.ts - 扩展入口文件
import { Extension, ExtensionContext } from "@mariozechner/pi-coding-agent";
import { createWeatherTool } from "./src/tools/weather-tool";
export default function activate(ctx: ExtensionContext) {
// 注册工具
ctx.tools.register(createWeatherTool());
// 注册事件监听器
ctx.events.on("session:started", () => {
console.log("Weather extension activated");
});
return {
// 扩展提供的API
getWeatherHistory: () => {
// 实现历史查询功能
}
};
}
// 可选的停用函数
export function deactivate(ctx: ExtensionContext) {
// 清理资源
ctx.tools.unregister("weather");
}
工具实现代码:
// src/tools/weather-tool.ts
import { Tool, ToolContext } from "@mariozechner/pi-coding-agent";
export function createWeatherTool(): Tool {
return {
name: "weather",
description: "获取指定城市的天气信息",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称,如'北京'或'New York'"
},
units: {
type: "string",
enum: ["celsius", "fahrenheit"],
default: "celsius",
description: "温度单位"
}
},
required: ["city"]
},
async execute(ctx: ToolContext, params) {
// 工具实现逻辑
ctx.ui.showStatus(`正在查询${params.city}的天气...`);
// 实际实现将在这里调用外部API
return `[模拟] ${params.city} 当前温度: 22°C, 晴朗`;
}
};
}
1.3 扩展注册与发现机制
pi-mono提供多种扩展注册方式,适应不同的开发和部署场景:
-
自动发现:放置在以下目录的扩展会被自动加载
- 用户目录:
~/.pi/agent/extensions/ - 项目目录:
./extensions/ - 全局目录:
/usr/local/share/pi/extensions/
- 用户目录:
-
手动注册:通过命令行参数指定扩展
pi --extension ./path/to/my-extension -
编程方式:在代码中动态注册
import { loadExtension } from "@mariozechner/pi-coding-agent"; async function setup() { const extension = await loadExtension("./my-extension"); await extension.activate(ctx); }
1.4 常见问题
Q1: 扩展加载失败如何排查?
A1: 检查以下几点:确保package.json中的"main"字段指向正确的入口文件;验证扩展是否导出activate函数;查看日志文件~/.pi/agent/logs/extension-loader.log。
Q2: 如何确保扩展之间的兼容性?
A2: 在package.json中声明扩展依赖和兼容版本:
{
"pi": {
"compatibility": {
"pi-mono": ">=0.9.3 <1.0.0",
"extensions": {
"core-utils": "~1.2.0"
}
}
}
}
Q3: 能否在扩展中覆盖内置功能?
A3: 可以通过"override"机制替换内置工具,但建议谨慎使用。使用ctx.tools.register(tool, { override: true })可以覆盖同名工具。
第二章:外部服务集成策略
技术要点提示
- 认证机制选择:API密钥、OAuth2.0与令牌管理
- 服务通信模式:REST、WebSocket与事件流处理
- 错误处理策略:重试机制与降级方案
- 数据转换层:请求/响应的标准化处理
- 缓存策略:减少API调用与提升响应速度
2.1 API认证机制详解
pi-mono提供多种安全的API认证方式,适应不同服务的需求:
| 认证方式 | 适用场景 | 安全级别 | 实现复杂度 |
|---|---|---|---|
| API密钥 | 服务器端服务、内部工具 | 中 | 低 |
| OAuth2.0 | 第三方服务、用户授权 | 高 | 中 |
| 令牌存储 | 频繁访问的服务 | 中高 | 低 |
| 环境变量 | 开发环境、CI/CD | 低 | 低 |
以下是实现OAuth2.0认证的示例代码:
// src/auth/weather-oauth.ts
import { OAuthProvider, OAuthSession } from "@mariozechner/pi-ai";
export class WeatherOAuthProvider extends OAuthProvider {
constructor() {
super({
providerId: "weather-api",
authorizationEndpoint: "https://api.weather.com/oauth/authorize",
tokenEndpoint: "https://api.weather.com/oauth/token",
clientId: "YOUR_CLIENT_ID",
scopes: ["read:weather", "read:forecast"]
});
}
async getAccessToken(): Promise<string> {
// 尝试从缓存获取
const cachedSession = await this.loadSession();
if (cachedSession && !this.isExpired(cachedSession)) {
return cachedSession.accessToken;
}
// 如需刷新令牌
if (cachedSession?.refreshToken) {
try {
const newSession = await this.refreshToken(cachedSession.refreshToken);
await this.saveSession(newSession);
return newSession.accessToken;
} catch (error) {
console.warn("令牌刷新失败,需要重新授权");
}
}
// 启动授权流程
const session = await this.startAuthorizationFlow();
await this.saveSession(session);
return session.accessToken;
}
}
在工具中使用认证服务:
// 在工具execute方法中
async execute(ctx: ToolContext, params) {
// 获取OAuth提供器
const oauthProvider = new WeatherOAuthProvider();
const accessToken = await oauthProvider.getAccessToken();
// 调用API
const response = await fetch(
`https://api.weather.com/v1/current.json?q=${params.city}`,
{
headers: {
"Authorization": `Bearer ${accessToken}`
}
}
);
// 处理响应...
}
2.2 服务集成模式与实现
根据外部服务的特性,pi-mono支持多种集成模式:
2.2.1 REST API集成
最常见的集成方式,适用于大多数第三方服务:
// src/services/weather-rest-client.ts
import { HttpClient, ApiError } from "@mariozechner/pi-coding-agent";
export class WeatherRestClient {
private client: HttpClient;
constructor(private apiKey: string) {
this.client = new HttpClient({
baseUrl: "https://api.weather.com/v1",
timeout: 10000,
headers: {
"Accept": "application/json",
"User-Agent": "pi-mono-extension/1.0"
}
});
}
async getCurrentWeather(city: string, units: "celsius" | "fahrenheit" = "celsius"): Promise<WeatherData> {
try {
return await this.client.get("/current.json", {
params: {
q: city,
units: units === "celsius" ? "m" : "f",
key: this.apiKey
}
});
} catch (error) {
if (error instanceof ApiError) {
if (error.status === 404) {
throw new Error(`未找到城市: ${city}`);
} else if (error.status === 401) {
throw new Error("API密钥无效或已过期");
}
}
throw new Error(`获取天气失败: ${error.message}`);
}
}
}
// 类型定义
interface WeatherData {
location: {
name: string;
region: string;
country: string;
};
current: {
temp_c: number;
temp_f: number;
condition: {
text: string;
icon: string;
};
humidity: number;
wind_kph: number;
};
}
2.2.2 实时数据流集成
对于需要实时数据的场景,如股票行情、实时日志等:
// src/services/realtime-data-client.ts
import { EventEmitter } from "events";
export class RealtimeDataClient extends EventEmitter {
private socket: WebSocket;
private reconnectTimeout: NodeJS.Timeout;
constructor(private url: string) {
super();
this.connect();
}
connect() {
this.socket = new WebSocket(this.url);
this.socket.onopen = () => {
this.emit("connected");
this.clearReconnectTimeout();
};
this.socket.onmessage = (event) => {
const data = JSON.parse(event.data);
this.emit("data", data);
};
this.socket.onerror = (error) => {
this.emit("error", error);
this.scheduleReconnect();
};
this.socket.onclose = () => {
this.emit("disconnected");
this.scheduleReconnect();
};
}
private scheduleReconnect() {
this.clearReconnectTimeout();
this.reconnectTimeout = setTimeout(() => this.connect(), 5000);
}
private clearReconnectTimeout() {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
}
subscribe(topic: string) {
this.socket.send(JSON.stringify({
action: "subscribe",
topic
}));
}
unsubscribe(topic: string) {
this.socket.send(JSON.stringify({
action: "unsubscribe",
topic
}));
}
close() {
this.clearReconnectTimeout();
this.socket.close();
}
}
2.3 数据转换与标准化
外部服务返回的数据格式往往各不相同,实现统一的数据转换层可以提高扩展的可维护性:
// src/transformers/weather-transformer.ts
import { WeatherData, WeatherCondition, NormalizedWeather } from "../types";
export class WeatherTransformer {
static toNormalizedFormat(rawData: WeatherData): NormalizedWeather {
// 映射不同API的天气状况到统一的枚举
const conditionMap: Record<string, WeatherCondition> = {
"sunny": "clear",
"partly cloudy": "partly-cloudy",
"cloudy": "cloudy",
"rain": "rain",
"snow": "snow",
"thunder": "thunderstorm"
};
const rawCondition = rawData.current.condition.text.toLowerCase();
const normalizedCondition = conditionMap[rawCondition] || "unknown";
return {
location: {
name: rawData.location.name,
region: rawData.location.region,
country: rawData.location.country,
coordinates: {
// 如果API提供经纬度
latitude: rawData.location.lat || 0,
longitude: rawData.location.lon || 0
}
},
current: {
temperature: {
celsius: rawData.current.temp_c,
fahrenheit: rawData.current.temp_f
},
condition: normalizedCondition,
humidity: rawData.current.humidity,
windSpeed: {
kph: rawData.current.wind_kph,
mph: rawData.current.wind_kph * 0.621371
},
timestamp: new Date().toISOString()
},
source: "weather-api"
};
}
}
2.4 常见问题
Q1: 如何处理API调用频率限制?
A1: 实现请求限流机制:
import { RateLimiter } from "limiter";
// 创建限流器:每分钟最多60个请求
const limiter = new RateLimiter({ tokensPerInterval: 60, interval: "minute" });
async function throttledApiCall() {
// 等待令牌可用
await limiter.removeTokens(1);
// 执行API调用
return fetchApiData();
}
Q2: 如何确保API密钥安全?
A2: 使用pi-mono的安全存储API:
// 存储密钥
await ctx.secrets.set("weather-api-key", "your-secret-key");
// 检索密钥
const apiKey = await ctx.secrets.get("weather-api-key");
Q3: 外部服务不可用时如何处理?
A3: 实现降级策略和缓存机制:
async function getWeatherWithFallback(city: string) {
try {
// 尝试获取实时数据
const data = await weatherClient.getCurrentWeather(city);
// 更新缓存
await ctx.cache.set(`weather:${city}`, data, { ttl: 3600 });
return data;
} catch (error) {
// 尝试从缓存获取
const cached = await ctx.cache.get(`weather:${city}`);
if (cached) {
ctx.ui.showWarning("使用缓存数据,可能不是最新的");
return cached;
}
// 完全失败时返回默认数据或错误
throw new Error("无法获取天气数据,服务暂时不可用");
}
}
第三章:扩展生态构建与最佳实践
技术要点提示
- 扩展打包与分发:npm包结构与版本管理
- 性能优化策略:内存管理与资源释放
- 安全最佳实践:输入验证与权限控制
- 测试策略:单元测试与集成测试
- 文档规范:API文档与使用示例
3.1 扩展打包与分发
将扩展打包为npm包是分享和分发的最佳方式。以下是一个扩展的package.json示例:
{
"name": "pi-weather-extension",
"version": "1.0.0",
"description": "Weather extension for pi-mono",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"watch": "tsc --watch",
"test": "vitest run",
"lint": "biome check src",
"prepare": "npm run build"
},
"keywords": ["pi-mono", "extension", "weather"],
"author": "",
"license": "MIT",
"pi": {
"type": "extension",
"displayName": "Weather Tools",
"description": "Adds weather查询 capabilities to pi-mono",
"icon": "icon.png",
"categories": ["tools", "external-services"],
"compatibility": {
"pi-mono": ">=0.9.3"
}
},
"dependencies": {
"@mariozechner/pi-coding-agent": "^0.9.3"
},
"devDependencies": {
"typescript": "^5.2.2",
"vitest": "^1.2.2",
"@biomejs/biome": "^1.4.1"
}
}
打包与发布流程:
# 构建扩展
npm run build
# 本地测试安装
npm pack
pi --extension pi-weather-extension-1.0.0.tgz
# 发布到npm
npm publish
3.2 性能优化策略
扩展性能直接影响pi-mono的整体体验,以下是关键优化点:
3.2.1 内存管理
-
避免内存泄漏:及时清理事件监听器
// 不好的做法 - 可能导致内存泄漏 ctx.events.on("data", (data) => { processData(data); }); // 好的做法 - 提供清理机制 function activate(ctx: ExtensionContext) { const handler = (data) => processData(data); ctx.events.on("data", handler); return { deactivate() { ctx.events.off("data", handler); } }; } -
大型数据处理:使用流处理代替一次性加载
// 处理大型JSON文件 import { createReadStream } from "fs"; import { createInterface } from "readline"; async function processLargeDataFile(path: string) { const stream = createReadStream(path, { encoding: "utf-8" }); const rl = createInterface({ input: stream }); for await (const line of rl) { // 逐行处理 const data = JSON.parse(line); processRecord(data); } }
3.2.2 执行效率
-
缓存频繁计算结果:
import { Cache } from "@mariozechner/pi-coding-agent"; const cache = new Cache({ ttl: 300 }); // 5分钟缓存 async function expensiveCalculation(input: string) { const cacheKey = `calc:${input}`; const cached = await cache.get(cacheKey); if (cached) return cached; // 执行耗时计算 const result = await performExpensiveCalculation(input); // 存入缓存 await cache.set(cacheKey, result); return result; } -
并行处理:
// 使用Promise.all处理并行任务 async function fetchMultipleResources(urls: string[]) { // 限制并发数为5 const concurrency = 5; const results = []; for (let i = 0; i < urls.length; i += concurrency) { const batch = urls.slice(i, i + concurrency); const batchResults = await Promise.all( batch.map(url => fetchResource(url)) ); results.push(...batchResults); } return results; }
3.3 安全最佳实践
扩展开发必须重视安全问题,特别是处理用户数据和系统资源时:
3.3.1 输入验证
所有用户输入和外部数据必须经过严格验证:
import { z } from "zod";
// 定义验证模式
const WeatherParamsSchema = z.object({
city: z.string().min(1).max(100),
units: z.enum(["celsius", "fahrenheit"]).optional()
});
// 在工具中使用验证
async execute(ctx: ToolContext, params) {
// 验证输入
const result = WeatherParamsSchema.safeParse(params);
if (!result.success) {
throw new Error(`参数验证失败: ${result.error.message}`);
}
const validatedParams = result.data;
// 继续处理...
}
3.3.2 权限控制
实现细粒度的权限检查:
// 检查是否有权限执行文件操作
async function writeToFile(ctx: ToolContext, path: string, content: string) {
// 检查路径是否在允许的范围内
if (!ctx.security.isPathAllowed(path)) {
throw new Error(`没有权限写入文件: ${path}`);
}
// 检查是否有写入权限
if (!await ctx.security.hasPermission("file:write")) {
throw new Error("没有文件写入权限,请联系管理员");
}
// 执行写入操作
return ctx.fs.writeFile(path, content);
}
3.4 测试策略
完善的测试确保扩展质量和兼容性:
3.4.1 单元测试
使用vitest测试工具功能:
// test/unit/weather-tool.test.ts
import { describe, it, expect, vi } from "vitest";
import { createWeatherTool } from "../../src/tools/weather-tool";
describe("Weather Tool", () => {
it("should validate parameters correctly", async () => {
const tool = createWeatherTool();
const ctx = {
ui: { showStatus: vi.fn() }
} as any;
// 测试缺少必填参数
await expect(tool.execute(ctx, {})).rejects.toThrow("参数验证失败");
// 测试有效参数
const result = await tool.execute(ctx, { city: "北京" });
expect(result).toContain("北京");
});
});
3.4.2 集成测试
测试扩展与pi-mono核心系统的交互:
// test/integration/extension.test.ts
import { describe, it, expect, vi, beforeAll, afterAll } from "vitest";
import { ExtensionContext, createTestContext } from "@mariozechner/pi-coding-agent/testing";
import activate from "../../src/index";
describe("Weather Extension Integration", () => {
let ctx: ExtensionContext;
beforeAll(async () => {
// 创建测试上下文
ctx = await createTestContext();
// 激活扩展
await activate(ctx);
});
afterAll(async () => {
// 清理
await ctx.dispose();
});
it("should register weather tool", () => {
const tools = ctx.tools.getAll();
const weatherTool = tools.find(t => t.name === "weather");
expect(weatherTool).toBeDefined();
});
it("should execute weather tool correctly", async () => {
const tools = ctx.tools.getAll();
const weatherTool = tools.find(t => t.name === "weather");
const result = await weatherTool.execute(ctx, { city: "上海" });
expect(result).toContain("上海");
});
});
3.5 常见问题
Q1: 如何处理不同pi-mono版本的兼容性?
A1: 实现版本适配层:
// src/compatibility.ts
import { version } from "@mariozechner/pi-coding-agent";
import semver from "semver";
export function getApiClient() {
if (semver.gte(version, "1.0.0")) {
return new NewApiClient();
} else {
return new LegacyApiClient();
}
}
Q2: 扩展如何存储用户配置?
A2: 使用设置API:
// 存储配置
await ctx.settings.set("weather.defaultCity", "Beijing");
await ctx.settings.set("weather.units", "celsius");
// 读取配置
const defaultCity = await ctx.settings.get("weather.defaultCity", "Shanghai");
const units = await ctx.settings.get("weather.units", "celsius");
Q3: 如何为扩展提供用户界面?
A3: 使用TUI组件系统:
// src/components/weather-display.ts
import { Box, Text, Widget } from "@mariozechner/pi-tui";
export function createWeatherWidget(data: NormalizedWeather): Widget {
return Box({
title: `天气 - ${data.location.name}`,
border: "line",
children: [
Text(`温度: ${data.current.temperature.celsius}°C`),
Text(`状况: ${data.current.condition}`),
Text(`湿度: ${data.current.humidity}%`),
Text(`风速: ${data.current.windSpeed.kph} km/h`)
]
});
}
// 在扩展中注册
ctx.ui.registerWidget("weather", createWeatherWidget);
第四章:扩展开发检查清单与资源导航
4.1 扩展开发检查清单
开发扩展时,使用以下清单确保质量和兼容性:
功能完整性
- [ ] 所有工具实现完整的参数验证
- [ ] 错误处理覆盖所有可能的异常情况
- [ ] 提供清晰的错误消息和用户指导
- [ ] 实现必要的默认值和回退机制
性能与安全
- [ ] 验证所有用户输入和外部数据
- [ ] 实现适当的缓存策略减少API调用
- [ ] 清理所有事件监听器避免内存泄漏
- [ ] 不存储敏感信息在代码或日志中
- [ ] 限制并发请求数量防止过载
可维护性
- [ ] 代码遵循项目的代码风格指南
- [ ] 关键功能有单元测试覆盖
- [ ] 提供完整的JSDoc注释
- [ ] 文档包含安装、配置和使用说明
- [ ] 声明明确的版本依赖和兼容性
发布准备
- [ ] 构建过程生成优化的生产代码
- [ ] 包含必要的元数据在package.json中
- [ ] 测试与目标pi-mono版本的兼容性
- [ ] 准备变更日志记录功能和修复
4.2 资源导航
官方文档
- 扩展开发指南:packages/coding-agent/docs/extensions.md
- API参考:packages/coding-agent/docs/api.md
- 工具开发规范:packages/coding-agent/docs/tools.md
示例扩展
- 基础工具示例:packages/coding-agent/examples/extensions/hello.ts
- API集成示例:packages/coding-agent/examples/extensions/weather.ts
- UI组件示例:packages/coding-agent/examples/extensions/rainbow-editor.ts
开发工具
- 扩展生成器:
npx create-pi-extension my-extension - 测试框架:packages/coding-agent/test/
- 代码检查:biome.json
社区资源
- 扩展注册表:packages/coding-agent/docs/extensions-registry.md
- 常见问题解答:packages/coding-agent/docs/faq.md
- 贡献指南:CONTRIBUTING.md
4.3 高级扩展示例
以下是一个完整的高级扩展示例,展示了前面讨论的多种技术:
// 完整的天气扩展实现
import { Extension, ExtensionContext, Tool, ToolContext } from "@mariozechner/pi-coding-agent";
import { WeatherRestClient } from "./src/services/weather-rest-client";
import { WeatherTransformer } from "./src/transformers/weather-transformer";
import { WeatherOAuthProvider } from "./src/auth/weather-oauth";
import { createWeatherWidget } from "./src/components/weather-display";
import { z } from "zod";
// 参数验证模式
const WeatherParamsSchema = z.object({
city: z.string().min(1).max(100),
units: z.enum(["celsius", "fahrenheit"]).default("celsius")
});
// 工具实现
function createWeatherTool(): Tool {
return {
name: "weather",
description: "获取指定城市的天气信息",
parameters: WeatherParamsSchema.shape,
async execute(ctx: ToolContext, params) {
// 验证参数
const result = WeatherParamsSchema.safeParse(params);
if (!result.success) {
throw new Error(`参数错误: ${result.error.message}`);
}
const validatedParams = result.data;
// 显示状态
ctx.ui.showStatus(`正在查询${validatedParams.city}的天气...`);
try {
// 获取认证令牌
const oauthProvider = new WeatherOAuthProvider();
const accessToken = await oauthProvider.getAccessToken();
// 创建API客户端
const client = new WeatherRestClient(accessToken);
// 调用API
const rawData = await client.getCurrentWeather(
validatedParams.city,
validatedParams.units
);
// 转换数据格式
const normalizedData = WeatherTransformer.toNormalizedFormat(rawData);
// 缓存结果
await ctx.cache.set(
`weather:${validatedParams.city}:${validatedParams.units}`,
normalizedData,
{ ttl: 3600 } // 缓存1小时
);
// 返回格式化结果
return `当前${normalizedData.location.name}天气:
温度: ${normalizedData.current.temperature.celsius}°C
状况: ${normalizedData.current.condition}
湿度: ${normalizedData.current.humidity}%
风速: ${normalizedData.current.windSpeed.kph} km/h`;
} catch (error) {
// 尝试从缓存获取
const cached = await ctx.cache.get(
`weather:${validatedParams.city}:${validatedParams.units}`
);
if (cached) {
ctx.ui.showWarning("使用缓存数据,可能不是最新的");
return `[缓存] 当前${cached.location.name}天气:
温度: ${cached.current.temperature.celsius}°C
状况: ${cached.current.condition}`;
}
throw error;
}
}
};
}
// 扩展激活函数
export default function activate(ctx: ExtensionContext) {
// 注册工具
ctx.tools.register(createWeatherTool());
// 注册UI组件
ctx.ui.registerWidget("weather", createWeatherWidget);
// 注册命令
ctx.commands.register({
id: "weather:current",
description: "显示当前天气",
async execute() {
const defaultCity = await ctx.settings.get("weather.defaultCity", "北京");
return ctx.tools.execute("weather", { city: defaultCity });
}
});
// 监听设置变化
ctx.settings.onDidChange("weather.defaultCity", (newValue) => {
ctx.ui.showMessage(`默认城市已更新为: ${newValue}`);
});
// 提供扩展API
return {
async getCurrentWeather(city: string) {
return ctx.tools.execute("weather", { city });
}
};
}
// 扩展停用函数
export function deactivate(ctx: ExtensionContext) {
// 清理资源
ctx.tools.unregister("weather");
ctx.ui.unregisterWidget("weather");
ctx.commands.unregister("weather:current");
}
4.4 总结
pi-mono的扩展系统为开发者提供了强大而灵活的方式来扩展平台功能。通过遵循本文介绍的最佳实践和模式,你可以构建高质量、安全且性能优良的扩展,为pi-mono生态系统贡献价值。
无论是创建简单的工具还是复杂的外部服务集成,扩展开发都遵循相同的核心原则:模块化设计、类型安全、事件驱动和用户体验优先。随着pi-mono生态系统的不断发展,扩展将成为定制和增强AI agent能力的关键方式。
开始构建你的第一个扩展,释放pi-mono的全部潜力!
GLM-5智谱 AI 正式发布 GLM-5,旨在应对复杂系统工程和长时域智能体任务。Jinja00
GLM-5-w4a8GLM-5-w4a8基于混合专家架构,专为复杂系统工程与长周期智能体任务设计。支持单/多节点部署,适配Atlas 800T A3,采用w4a8量化技术,结合vLLM推理优化,高效平衡性能与精度,助力智能应用开发Jinja00
jiuwenclawJiuwenClaw 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。Python0188- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
AtomGit城市坐标计划AtomGit 城市坐标计划开启!让开源有坐标,让城市有星火。致力于与城市合伙人共同构建并长期运营一个健康、活跃的本地开发者生态。01
awesome-zig一个关于 Zig 优秀库及资源的协作列表。Makefile00
