Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **All languages:** add `AgentContext.public_agents` (`GET /v1/ai/agents`) — list all publicly available Agents on the platform (the Explore catalog). Unlike `agents`, it is not scoped to a Workspace and returns every published, publicly-shared Agent. Takes the same optional `page` / `limit` / `name` parameters and returns the existing `AgentsResponse`
- **All languages:** add optional `parent_message_id` parameter to the AI Agent `conversation` and `conversation_streamed` methods — pass the `message_id` from a previous response to attach a follow-up message after the specified one, keeping the message stream in order. Only valid together with `chat_uid`; must not be set for a new conversation

### Fixed
Expand Down
11 changes: 11 additions & 0 deletions c/csrc/include/longbridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -10408,6 +10408,17 @@ void lb_agent_context_agents(const struct lb_agent_context_t *ctx,
lb_async_callback_t callback,
void *userdata);

/**
* List all publicly available Agents on the platform (the Explore catalog).
* Not scoped to a Workspace. Returns `CAgentsResponse`.
*
* @param[in] opts Options for the request (can be null)
*/
void lb_agent_context_public_agents(const struct lb_agent_context_t *ctx,
const struct lb_get_agents_options_t *opts,
lb_async_callback_t callback,
void *userdata);

/**
* Start a conversation with the specified Agent, blocking until the run
* succeeds, is interrupted, or fails. Returns `CConversationResponse`.
Expand Down
30 changes: 30 additions & 0 deletions c/src/agent_context/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,36 @@ pub unsafe extern "C" fn lb_agent_context_agents(
});
}

/// List all publicly available Agents on the platform (the Explore catalog).
/// Not scoped to a Workspace. Returns `CAgentsResponse`.
///
/// @param[in] opts Options for the request (can be null)
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_agent_context_public_agents(
ctx: *const CAgentContext,
opts: *const CGetAgentsOptions,
callback: CAsyncCallback,
userdata: *mut c_void,
) {
let ctx_inner = (*ctx).ctx.clone();
let mut opts2 = GetAgentsOptions::new();
if !opts.is_null() {
if !(*opts).page.is_null() {
opts2 = opts2.page(*(*opts).page);
}
if !(*opts).limit.is_null() {
opts2 = opts2.limit(*(*opts).limit);
}
if !(*opts).name.is_null() {
opts2 = opts2.name(cstr_to_rust((*opts).name));
}
}
execute_async(callback, ctx, userdata, async move {
let resp: CCow<CAgentsResponseOwned> = CCow::new(ctx_inner.public_agents(opts2).await?);
Ok(resp)
});
}

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails. Returns `CConversationResponse`.
///
Expand Down
5 changes: 5 additions & 0 deletions cpp/include/agent_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class AgentContext
const std::optional<GetAgentsOptions>& opts,
AsyncCallback<AgentContext, AgentsResponse> callback) const;

/// List all publicly available Agents on the platform (the Explore catalog).
/// Not scoped to a Workspace.
void public_agents(const std::optional<GetAgentsOptions>& opts,
AsyncCallback<AgentContext, AgentsResponse> callback) const;

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails.
///
Expand Down
34 changes: 34 additions & 0 deletions cpp/src/agent_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,40 @@ AgentContext::agents(
new AsyncCallback<AgentContext, AgentsResponse>(callback));
}

void
AgentContext::public_agents(
const std::optional<GetAgentsOptions>& opts,
AsyncCallback<AgentContext, AgentsResponse> callback) const
{
lb_get_agents_options_t opts2 = { nullptr, nullptr, nullptr };
if (opts) {
opts2.page = opts->page ? &opts->page.value() : nullptr;
opts2.limit = opts->limit ? &opts->limit.value() : nullptr;
opts2.name = opts->name ? opts->name->c_str() : nullptr;
}

lb_agent_context_public_agents(
ctx_,
&opts2,
[](auto res) {
auto callback_ptr =
callback::get_async_callback<AgentContext, AgentsResponse>(
res->userdata);
AgentContext ctx((const lb_agent_context_t*)res->ctx);
Status status(res->error);

if (status) {
AgentsResponse resp = convert((const lb_agents_response_t*)res->data);
(*callback_ptr)(AsyncResult<AgentContext, AgentsResponse>(
ctx, std::move(status), &resp));
} else {
(*callback_ptr)(AsyncResult<AgentContext, AgentsResponse>(
ctx, std::move(status), nullptr));
}
},
new AsyncCallback<AgentContext, AgentsResponse>(callback));
}

void
AgentContext::conversation(
const std::string& agent_id,
Expand Down
2 changes: 2 additions & 0 deletions java/javasrc/src/main/java/com/longbridge/SdkNative.java
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ public static native void quoteContextUpdatePinned(long context, Object req,
public static native void agentContextWorkspaces(long context, AsyncCallback callback);
public static native void agentContextAgents(long context, String workspaceId, Object opts,
AsyncCallback callback);
public static native void agentContextPublicAgents(long context, Object opts,
AsyncCallback callback);
public static native void agentContextConversation(long context, String agentId, String query,
String chatUid, String parentMessageId, AsyncCallback callback);
public static native void agentContextContinueConversation(long context, String agentId, String chatUid,
Expand Down
15 changes: 15 additions & 0 deletions java/javasrc/src/main/java/com/longbridge/agent/AgentContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ public CompletableFuture<AgentsResponse> agents(String workspaceId, GetAgentsOpt
});
}

/**
* List all publicly available Agents on the platform (the Explore catalog).
* Not scoped to a Workspace.
*
* @param opts Options for this request, may be {@code null}
* @return A Future representing the result of the operation
* @throws OpenApiException If an error occurs
*/
public CompletableFuture<AgentsResponse> publicAgents(GetAgentsOptions opts)
throws OpenApiException {
return AsyncCallback.executeTask((callback) -> {
SdkNative.agentContextPublicAgents(raw(), opts, callback);
});
}

/**
* Start a conversation with the specified Agent, blocking until the run
* succeeds, is interrupted, or fails.
Expand Down
19 changes: 19 additions & 0 deletions java/src/agent_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,25 @@ pub unsafe extern "system" fn Java_com_longbridge_SdkNative_agentContextAgents(
})
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_com_longbridge_SdkNative_agentContextPublicAgents(
mut env: JNIEnv,
_class: JClass,
context: i64,
opts: JObject,
callback: JObject,
) {
jni_result(&mut env, (), |env| {
let context = &*(context as *const ContextObj);
let __owned_ctx = context.ctx.clone();
let opts = read_get_agents_options(env, &opts)?;
async_util::execute(env, callback, async move {
Ok(__owned_ctx.public_agents(opts).await?)
})?;
Ok(())
})
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_com_longbridge_SdkNative_agentContextConversation(
mut env: JNIEnv,
Expand Down
5 changes: 5 additions & 0 deletions nodejs/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ export declare class AgentContext {
* ```
*/
agents(workspaceId: string, page?: number | undefined | null, limit?: number | undefined | null, name?: string | undefined | null): Promise<AgentsResponse>
/**
* List all publicly available Agents on the platform (the Explore
* catalog). Not scoped to a Workspace.
*/
publicAgents(page?: number | undefined | null, limit?: number | undefined | null, name?: string | undefined | null): Promise<AgentsResponse>
/**
* Start a conversation with the specified Agent, blocking until the run
* succeeds, is interrupted, or fails.
Expand Down
27 changes: 27 additions & 0 deletions nodejs/src/agent/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,33 @@ impl AgentContext {
.into())
}

/// List all publicly available Agents on the platform (the Explore
/// catalog). Not scoped to a Workspace.
#[napi]
pub async fn public_agents(
&self,
page: Option<i32>,
limit: Option<i32>,
name: Option<String>,
) -> Result<AgentsResponse> {
let mut opts = longbridge::agent::GetAgentsOptions::new();
if let Some(page) = page {
opts = opts.page(page);
}
if let Some(limit) = limit {
opts = opts.limit(limit);
}
if let Some(name) = name {
opts = opts.name(name);
}
Ok(self
.ctx
.public_agents(opts)
.await
.map_err(ErrorNewType)?
.into())
}

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails.
///
Expand Down
34 changes: 34 additions & 0 deletions python/pysrc/longbridge/openapi.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -14096,6 +14096,23 @@ class AgentContext:
"""
...

def public_agents(
self,
page: int | None = None,
limit: int | None = None,
name: str | None = None,
) -> AgentsResponse:
"""
List all publicly available Agents on the platform (the Explore
catalog). Not scoped to a Workspace.

Args:
page: Page number, starts at 1
limit: Page size
name: Fuzzy search by Agent name
"""
...

def conversation(
self,
agent_id: str,
Expand Down Expand Up @@ -14262,6 +14279,23 @@ class AsyncAgentContext:
"""
...

def public_agents(
self,
page: int | None = None,
limit: int | None = None,
name: str | None = None,
) -> Awaitable[AgentsResponse]:
"""
List all publicly available Agents on the platform (the Explore
catalog). Not scoped to a Workspace. Returns awaitable.

Args:
page: Page number, starts at 1
limit: Page size
name: Fuzzy search by Agent name
"""
...

def conversation(
self,
agent_id: str,
Expand Down
26 changes: 26 additions & 0 deletions python/src/agent/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,32 @@ impl AgentContext {
.into())
}

/// List all publicly available Agents on the platform.
#[pyo3(signature = (page = None, limit = None, name = None))]
fn public_agents(
&self,
py: Python<'_>,
page: Option<i32>,
limit: Option<i32>,
name: Option<String>,
) -> PyResult<AgentsResponse> {
let mut opts = GetAgentsOptions::new();
if let Some(page) = page {
opts = opts.page(page);
}
if let Some(limit) = limit {
opts = opts.limit(limit);
}
if let Some(name) = name {
opts = opts.name(name);
}

Ok(py
.detach(|| self.0.public_agents(Some(opts)))
.map_err(ErrorNewType)?
.into())
}

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails.
#[pyo3(signature = (agent_id, query, chat_uid = None, parent_message_id = None))]
Expand Down
31 changes: 31 additions & 0 deletions python/src/agent/context_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,37 @@ impl AsyncAgentContext {
.map(|b| b.unbind())
}

/// List all publicly available Agents on the platform. Returns awaitable.
#[pyo3(signature = (page = None, limit = None, name = None))]
fn public_agents(
&self,
py: Python<'_>,
page: Option<i32>,
limit: Option<i32>,
name: Option<String>,
) -> PyResult<Py<PyAny>> {
let ctx = self.ctx.clone();
let mut opts = GetAgentsOptions::new();
if let Some(page) = page {
opts = opts.page(page);
}
if let Some(limit) = limit {
opts = opts.limit(limit);
}
if let Some(name) = name {
opts = opts.name(name);
}
pyo3_async_runtimes::tokio::future_into_py(py, async move {
let resp: AgentsResponse = ctx
.public_agents(Some(opts))
.await
.map_err(ErrorNewType)?
.into();
Ok(resp)
})
.map(|b| b.unbind())
}

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails. Returns awaitable.
#[pyo3(signature = (agent_id, query, chat_uid = None, parent_message_id = None))]
Expand Down
25 changes: 25 additions & 0 deletions rust/src/agent/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,31 @@ impl AgentContext {
.0)
}

/// List all publicly available Agents on the platform — the same catalog
/// shown on the Explore page.
///
/// Unlike [`agents`](Self::agents), this endpoint is not scoped to a
/// Workspace: it returns every Agent that is published and publicly shared.
/// The returned [`Agent::uid`] is used as the path parameter of
/// [`conversation`](Self::conversation).
///
/// Path: `GET /v1/ai/agents`
pub async fn public_agents(
&self,
opts: impl Into<Option<GetAgentsOptions>>,
) -> Result<AgentsResponse> {
Ok(self
.0
.http_cli
.request(Method::GET, "/v1/ai/agents")
.query_params(opts.into().unwrap_or_default())
.response::<Json<AgentsResponse>>()
.send()
.with_subscriber(self.0.log_subscriber.clone())
.await?
.0)
}

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails.
///
Expand Down
9 changes: 9 additions & 0 deletions rust/src/blocking/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ impl AgentContextSync {
.call(move |ctx| async move { ctx.agents(workspace_id, opts).await })
}

/// List all publicly available Agents on the platform.
pub fn public_agents(
&self,
opts: impl Into<Option<GetAgentsOptions>> + Send + 'static,
) -> Result<AgentsResponse> {
self.rt
.call(move |ctx| async move { ctx.public_agents(opts).await })
}

/// Start a conversation with the specified Agent, blocking until the run
/// succeeds, is interrupted, or fails.
pub fn conversation(
Expand Down
Loading