帮助开发者掌握 EdenAPI/SLAPI 新端点的流式与非流式创建方法。
该技能材料表现为开源仓库中的纯文档/提示指南,未声明需要密钥、远程端点、本地执行或数据读写能力。基于现有材料,整体风险较低,主要需留意仓库来源信息有限且维护状态未知。
材料明确标注无需密钥或环境变量;文档内容仅说明如何定义 API 端点类型与处理流程,未见凭证收集、存储、转发或滥用路径。
系统检查项与材料均显示其为 prompt-only,且未声明任何远程 host。虽然文档讨论 EdenAPI/SLAPI 与服务器交互的开发模式,但该技能本身未显示会主动连接外部端点或外发用户数据。
未见安装、脚本执行、启动本地进程或调用系统能力的说明;当前材料属于开发指南文本,不具备可见的代码执行面。
未声明读取、写入或枚举本地文件、数据库、剪贴板或其他资源的权限需求;文档仅引用代码路径作为示例位置,不构成实际数据访问能力。
正面因素是开源且来源为 GitHub,可一定程度审计;但仓库许可证未声明、社区采用度显示 0 star、维护状态未知,来源可信度信号有限,建议在实际采用前人工复核仓库内容与维护情况。
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "CREATING_ENDPOINTS" 技能: 1. 下载 https://raw.githubusercontent.com/facebook/sapling/main/eden/.llms/skills/CREATING_ENDPOINTS/SKILL.md 2. 保存为 ~/.claude/skills/CREATING_ENDPOINTS/SKILL.md 3. 装好后重载技能,告诉我可以用了
请根据 EdenAPI/SLAPI 规范,给我一个创建非流式端点的最小示例,包含请求处理、参数校验和返回 JSON 响应。
一份可参考的非流式端点代码示例,并说明关键结构与实现步骤。
请演示如何在 EdenAPI/SLAPI 中实现一个流式端点,逐步返回内容,并说明与普通端点在控制流上的差异。
一个流式端点实现示例,包含分块输出方式及与非流式模式的对比说明。
请为新建 EdenAPI/SLAPI 端点整理一份开发清单,覆盖路由定义、输入输出格式、错误处理、日志和测试要点。
一份结构清晰的端点开发清单,可用于自查实现完整性与质量。
This guide explains how to create new EdenAPI/SLAPI endpoints, covering both streaming and non-streaming patterns.
EdenAPI is a REST-like API that connects Sapling clients to the Mononoke server. Creating a new endpoint involves three main steps:
edenapi_typesslapi_service| Component | Location |
|---|---|
| Types | fbcode/eden/scm/lib/edenapi/types/src/ |
| Server Handler Trait | fbcode/eden/mononoke/servers/slapi/slapi_service/src/handlers/handler.rs |
| Server Handlers | fbcode/eden/mononoke/servers/slapi/slapi_service/src/handlers/*.rs |
| Router Registration | fbcode/eden/mononoke/servers/slapi/slapi_service/src/handlers.rs |
| Client API Trait | fbcode/eden/scm/lib/edenapi/trait/src/api.rs |
| Client Implementation | fbcode/eden/scm/lib/edenapi/src/client.rs |
Location: fbcode/eden/scm/lib/edenapi/types/src/
Types need the #[auto_wire] macro to generate wire format serialization and the ToWire trait implementation. All parameters should be sent in the request body, not in the URL path.
#[auto_wire]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "for-tests"), derive(Arbitrary))]
pub struct MyRequest {
#[id(1)]
pub field_one: String,
#[id(2)]
pub field_two: Option<u64>,
}
Key points:
#[auto_wire] generates wire format code#[id(N)] assigns a stable field ID for serialization (use sequential numbers)Serialize, Deserialize for serde supportArbitrary derive enables property-based testingSee EphemeralPrepareRequest/EphemeralPrepareResponse in types/src/commit.rs:555-570:
#[auto_wire]
#[derive(Clone, Default, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct EphemeralPrepareRequest {
#[id(1)]
pub custom_duration_secs: Option<u64>,
#[id(2)]
pub labels: Option<Vec<String>>,
}
// Response doesn't need #[auto_wire] if not batched
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct EphemeralPrepareResponse {
pub bubble_id: NonZeroU64,
pub expiration_timestamp: Option<i64>,
}
See CommitMutationsRequest/CommitMutationsResponse in types/src/commit.rs:609-623:
#[auto_wire]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct CommitMutationsRequest {
#[id(1)]
pub commits: Vec<HgId>,
}
#[auto_wire]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct CommitMutationsResponse {
#[id(1)]
pub mutation: HgMutationEntryContent,
}
Location: fbcode/eden/mononoke/servers/slapi/slapi_service/src/handlers/
In handlers.rs, add your method to the enum:
pub enum SaplingRemoteApiMethod {
// ... existing methods
MyNewMethod,
}
And update the Display impl:
impl fmt::Display for SaplingRemoteApiMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
// ... existing matches
Self::MyNewMethod => "my_new_method",
};
write!(f, "{}", name)
}
}
Create a handler struct and implement SaplingRemoteApiHandler:
pub struct MyNewHandler;
#[async_trait]
impl SaplingRemoteApiHandler for MyNewHandler {
type Request = MyRequest;
type Response = MyResponse;
const HTTP_METHOD: hyper::Method = hyper::Method::POST;
…