1use std::pin::Pin;
14
15use futures::Stream;
16use objectiveai_sdk::agent::RemoteAgentBaseWithFallbacks;
17use objectiveai_sdk::cli::command::agents::get::Response as GetAgentResponse;
18use objectiveai_sdk::cli::command::functions::get::Response as GetFunctionResponse;
19use objectiveai_sdk::cli::command::functions::profiles::get::Response as GetProfileResponse;
20use objectiveai_sdk::cli::command::swarms::get::Response as GetSwarmResponse;
21use objectiveai_sdk::functions::{FullRemoteFunction, RemoteProfile};
22use objectiveai_sdk::swarm::RemoteSwarmBase;
23use objectiveai_sdk::{HttpClient, RemotePath, RemotePathCommitOptional};
24
25use crate::context::Context;
26use crate::error::Error;
27use crate::filesystem::publish::Kind;
28
29pub async fn list(
33 ctx: &Context,
34 kind: Kind,
35) -> Pin<Box<dyn Stream<Item = RemotePath> + Send>> {
36 ctx.filesystem.list(kind).await
37}
38
39pub async fn get_agent(
42 ctx: &Context,
43 path: RemotePathCommitOptional,
44) -> Result<GetAgentResponse, Error> {
45 let http = ctx.github_http_client().await?;
46 let (inner, path) = fetch_agent_base(ctx, &http, &path).await?;
47 Ok(GetAgentResponse { path, inner })
48}
49
50pub async fn get_swarm(
51 ctx: &Context,
52 path: RemotePathCommitOptional,
53) -> Result<GetSwarmResponse, Error> {
54 let http = ctx.github_http_client().await?;
55 let (inner, path) = fetch_swarm_base(ctx, &http, &path).await?;
56 Ok(GetSwarmResponse { path, inner })
57}
58
59pub async fn get_function(
60 ctx: &Context,
61 path: RemotePathCommitOptional,
62) -> Result<GetFunctionResponse, Error> {
63 let http = ctx.github_http_client().await?;
64 let (inner, path) = fetch_function(ctx, &http, &path).await?;
65 Ok(GetFunctionResponse { path, inner })
66}
67
68pub async fn get_profile(
69 ctx: &Context,
70 path: RemotePathCommitOptional,
71) -> Result<GetProfileResponse, Error> {
72 let http = ctx.github_http_client().await?;
73 let (inner, path) = fetch_profile(ctx, &http, &path).await?;
74 Ok(GetProfileResponse { path, inner })
75}
76
77async fn fetch_agent_base(
80 ctx: &Context,
81 http: &HttpClient,
82 path: &RemotePathCommitOptional,
83) -> Result<(RemoteAgentBaseWithFallbacks, RemotePath), Error> {
84 match path {
85 RemotePathCommitOptional::Github { owner, repository, commit } => {
86 let commit =
87 resolve_github_commit(http, owner, repository, commit.as_deref())
88 .await?;
89 let base = http
90 .github_get_agent(owner, repository, Some(&commit))
91 .await?
92 .ok_or_else(|| not_found("agent", owner, repository))?;
93 Ok((base, github_path(owner, repository, commit)))
94 }
95 RemotePathCommitOptional::Client { owner, repository, commit } => {
96 let (base, commit) = ctx
97 .filesystem
98 .read_json::<RemoteAgentBaseWithFallbacks>(
99 Kind::Agents,
100 owner,
101 repository,
102 commit.as_deref(),
103 )
104 .await?
105 .ok_or_else(|| not_found("agent", owner, repository))?;
106 Ok((base, client_path(owner, repository, commit)))
107 }
108 RemotePathCommitOptional::Mock { .. } => {
109 Err(Error::RemoteNotSupported("mock"))
110 }
111 }
112}
113
114async fn fetch_swarm_base(
115 ctx: &Context,
116 http: &HttpClient,
117 path: &RemotePathCommitOptional,
118) -> Result<(RemoteSwarmBase, RemotePath), Error> {
119 match path {
120 RemotePathCommitOptional::Github { owner, repository, commit } => {
121 let commit =
122 resolve_github_commit(http, owner, repository, commit.as_deref())
123 .await?;
124 let base = http
125 .github_get_swarm(owner, repository, Some(&commit))
126 .await?
127 .ok_or_else(|| not_found("swarm", owner, repository))?;
128 Ok((base, github_path(owner, repository, commit)))
129 }
130 RemotePathCommitOptional::Client { owner, repository, commit } => {
131 let (base, commit) = ctx
132 .filesystem
133 .read_json::<RemoteSwarmBase>(
134 Kind::Swarms,
135 owner,
136 repository,
137 commit.as_deref(),
138 )
139 .await?
140 .ok_or_else(|| not_found("swarm", owner, repository))?;
141 Ok((base, client_path(owner, repository, commit)))
142 }
143 RemotePathCommitOptional::Mock { .. } => {
144 Err(Error::RemoteNotSupported("mock"))
145 }
146 }
147}
148
149async fn fetch_function(
150 ctx: &Context,
151 http: &HttpClient,
152 path: &RemotePathCommitOptional,
153) -> Result<(FullRemoteFunction, RemotePath), Error> {
154 match path {
155 RemotePathCommitOptional::Github { owner, repository, commit } => {
156 let commit =
157 resolve_github_commit(http, owner, repository, commit.as_deref())
158 .await?;
159 let inner = http
160 .github_get_function(owner, repository, Some(&commit))
161 .await?
162 .ok_or_else(|| not_found("function", owner, repository))?;
163 Ok((inner, github_path(owner, repository, commit)))
164 }
165 RemotePathCommitOptional::Client { owner, repository, commit } => {
166 let (inner, commit) = ctx
167 .filesystem
168 .read_json::<FullRemoteFunction>(
169 Kind::Functions,
170 owner,
171 repository,
172 commit.as_deref(),
173 )
174 .await?
175 .ok_or_else(|| not_found("function", owner, repository))?;
176 Ok((inner, client_path(owner, repository, commit)))
177 }
178 RemotePathCommitOptional::Mock { .. } => {
179 Err(Error::RemoteNotSupported("mock"))
180 }
181 }
182}
183
184async fn fetch_profile(
185 ctx: &Context,
186 http: &HttpClient,
187 path: &RemotePathCommitOptional,
188) -> Result<(RemoteProfile, RemotePath), Error> {
189 match path {
190 RemotePathCommitOptional::Github { owner, repository, commit } => {
191 let commit =
192 resolve_github_commit(http, owner, repository, commit.as_deref())
193 .await?;
194 let inner = http
195 .github_get_profile(owner, repository, Some(&commit))
196 .await?
197 .ok_or_else(|| not_found("profile", owner, repository))?;
198 Ok((inner, github_path(owner, repository, commit)))
199 }
200 RemotePathCommitOptional::Client { owner, repository, commit } => {
201 let (inner, commit) = ctx
202 .filesystem
203 .read_json::<RemoteProfile>(
204 Kind::Profiles,
205 owner,
206 repository,
207 commit.as_deref(),
208 )
209 .await?
210 .ok_or_else(|| not_found("profile", owner, repository))?;
211 Ok((inner, client_path(owner, repository, commit)))
212 }
213 RemotePathCommitOptional::Mock { .. } => {
214 Err(Error::RemoteNotSupported("mock"))
215 }
216 }
217}
218
219async fn resolve_github_commit(
222 http: &HttpClient,
223 owner: &str,
224 repository: &str,
225 commit: Option<&str>,
226) -> Result<String, Error> {
227 match commit {
228 Some(c) => Ok(c.to_string()),
229 None => http
230 .github_resolve_commit(owner, repository)
231 .await?
232 .ok_or_else(|| Error::NotFound(format!("{owner}/{repository}"))),
233 }
234}
235
236fn github_path(owner: &str, repository: &str, commit: String) -> RemotePath {
237 RemotePath::Github {
238 owner: owner.to_string(),
239 repository: repository.to_string(),
240 commit,
241 }
242}
243
244fn client_path(owner: &str, repository: &str, commit: String) -> RemotePath {
245 RemotePath::Client {
246 owner: owner.to_string(),
247 repository: repository.to_string(),
248 commit,
249 }
250}
251
252fn not_found(kind: &str, owner: &str, repository: &str) -> Error {
253 Error::NotFound(format!("{kind} {owner}/{repository}"))
254}