Skip to content

Commit f1bfc2e

Browse files
committed
feat(sdk): 新增子 Agent 线程与事件查询
补齐线程分页、事件快照、取消信号和公开类型,增加合同测试、Cloud 验证探针与文档。 同步提高 Zod 安全版本下界,并验证外部包消费者可以使用新增公开接口。
1 parent 7a98e0f commit f1bfc2e

25 files changed

Lines changed: 851 additions & 43 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@openagentpack/sdk": minor
3+
---
4+
5+
新增百炼 Session 子 Agent 线程列表和事件历史查询,保留分页、取消及完整快照语义,并公开浏览器可用的线程类型。

‎.changeset/zod-security-bound.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@openagentpack/sdk": patch
3+
"@openagentpack/playground": patch
4+
---
5+
6+
将 Zod 依赖下界更新为 4.6.6,修复 GHSA-mrhx-c7xc-m3w5,避免新安装解析到受影响版本。

‎bun.lock‎

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎docs/reference/sdk.md‎

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ sanitizeSessionEvents(events, { ...completeContent, includeRaw: true });
6969
`code`、`id`、`status` 等字段仍按所选策略脱敏和截断,包括 `metadata.tool_input` 与可选 raw。
7070
- 仅关闭内容策略不会开启增量或补齐旧 `legacy` 投影;需要结构化内容时同时选择
7171
下文的 `snapshot` 模式。
72-
- `streamSessionEvents()` 和 `listSessionEvents()` 返回 `ProviderSessionEvent`;
72+
- `streamSessionEvents()`、`listSessionEvents()` 和 `listSessionThreadEvents()` 返回 `ProviderSessionEvent`;
7373
内容策略在转换为契约 `SessionEvent` 时传入,不是 Provider 请求参数。
7474

7575
## 百炼 Session SSE 与累计快照
@@ -188,6 +188,56 @@ const mapped = toBailianSessionEvent(rawCompleteEvent, { event_format: "snapshot
188188
`./session-events` 子路径保持浏览器安全,提供纯映射、累计转换与 sanitizer;
189189
网络订阅和高层 Session 工作流使用 SDK 主入口,不应导入 `internal/*`。
190190

191+
### 子 Agent 线程与历史查询
192+
193+
百炼 Multi-Agent 的子 Agent 执行使用独立的 `sthr_*` Thread;主 Agent 的 `thrd_*`
194+
不是线程列表中的子资源。同一 Agent 可以对应多条 Thread,调用方应按 Thread ID 区分执行实例。
195+
两个 SDK 查询入口使用百炼的 Session Threads REST 路径:
196+
197+
| SDK 方法 | 百炼路径 | 结果 |
198+
| --- | --- | --- |
199+
| `listSessionThreads(ctx, sessionId, options)` | `GET /sessions/{session_id}/threads` | `SessionThreadPage`,即 `CursorPage<SessionThread>` |
200+
| `listSessionThreadEvents(ctx, sessionId, threadId, options)` | `GET /sessions/{session_id}/threads/{thread_id}/events` | `ProviderSessionEventList` |
201+
202+
这些路径由百炼 [Multi-Agent 教程](https://docs.agent.bailian.aliyun.com/zh/managed-agents/best-practices/multiagent-proposal)
203+
说明,尚未纳入正式公开 API 参考;不能据此假设其他 Provider 也支持。当前 SDK 仅百炼实现,
204+
其他 Provider 返回明确的 unsupported 错误。`ctx` 可用现有 `ProjectRuntimeContext`,
205+
也可用只包含 Provider 配置的 `ManagedApiContext`。
206+
207+
```ts
208+
import { listSessionThreads, listSessionThreadEvents } from "@openagentpack/sdk";
209+
import { sanitizeSessionEvents } from "@openagentpack/sdk/session-events";
210+
211+
const threads = await listSessionThreads(ctx, sessionId, {
212+
provider: "bailian", limit: 100, page: previousThreadPage, signal,
213+
});
214+
const history = await listSessionThreadEvents(ctx, sessionId, selectedThreadId, {
215+
provider: "bailian", event_format: "snapshot", order: "desc",
216+
limit: 50, page_token: previousEventPage, signal,
217+
});
218+
const events = sanitizeSessionEvents(history.events, { redact: false, truncate: false });
219+
```
220+
221+
`SessionThread` 保留 `id/session_id/parent_thread_id`、绑定的 `agent.id/version`、状态和时间,
222+
Provider 有名称时也保留 `agent.name` 或 `agent_name`。列表按 `limit/page` 分页;历史查询
223+
复用 `EventListOptions`,`page_token` 优先于兼容别名 `page`,请求时均映射为 `page`。
224+
两者下一页都回传不透明的 `next_page`。历史 `types` 在 SDK 内本地过滤,保留原页游标;
225+
过滤后空页不等于查询结束。两者都支持 `AbortSignal`。
226+
227+
需要补齐线程绑定 Agent 的名称时,可调用
228+
`getRemoteAgent(ctx, thread.agent.id, { version: thread.agent.version, signal })`。
229+
百炼实现会把 `signal` 传入实际 GET 请求,取消线程列表时应一并取消这些补充查询。
230+
231+
历史默认仍为 `legacy`;选择 `snapshot` 后复用完整事件转换、工具关联和 sanitizer。
232+
子线程历史页不要求包含 `session_status`。事件的 `metadata.thread_id` 是实际所属线程,
233+
`metadata.session_thread_id`、`to_session_thread_id/from_session_thread_id` 可能是被引用的子线程,
234+
不能直接用引用字段替换实际归属。
235+
236+
此处只提供列表与历史读取,不新增 Thread 创建、归档、发送或独立 SSE。实时事件继续从
237+
Session 的单一事件流获取;子线程状态不表示主会话执行结束。`SessionThread`、
238+
`SessionThreadListOptions` 和 `SessionThreadPage` 也通过 `./session-events` 导出类型,
239+
浏览器可复用合同而无需加载 SDK 主入口或 Provider 凭据。
240+
191241
### 自建后端原始事件的浏览器转换
192242

193243
自建后端透传百炼 SSE 时,调用方负责 HTTP、SSE 解帧、订阅就绪、历史分页与重试。
@@ -262,7 +312,7 @@ The public entry exposes domain workflows that return structured domain results
262312
| Sync & migrate | `resolveSyncProvider`, `syncProviderResourcesFromContext`, `syncProviderResourcesFromEnv`, `migrateConfig` |
263313
| Destroy | `planDestroyProjectContext`, `destroyPlannedProjectResources` |
264314
| Agent | `buildAgentDecl`, `getAgent`, `listAgentsWithReadiness`, `listCloudAgents`, `archiveCloudAgent`, `syncAgentResourcesWithStateBackend`, `createCloudEnvironment`, `deleteCloudEnvironment`, `listCloudEnvironments`, `createCloudVault`, `deleteCloudVault`, `listCloudVaults` |
265-
| Session | `createSessionForAgent`, `startSessionRun`, `startSessionRunPolling`, `sendSessionMessageStreaming`, `sendSessionMessagePolling`, `streamSessionEvents`, `getSession`, `listSessionSummaries`, `listSessionEvents`, `deleteSession`, `isTerminalSessionStatus`, `resolveSessionProvider` |
315+
| Session | `createSessionForAgent`, `startSessionRun`, `startSessionRunPolling`, `sendSessionMessageStreaming`, `sendSessionMessagePolling`, `streamSessionEvents`, `getSession`, `listSessionSummaries`, `listSessionEvents`, `listSessionThreads`, `listSessionThreadEvents`, `deleteSession`, `isTerminalSessionStatus`, `resolveSessionProvider` |
266316
| Files & skills | `uploadFile`, `listFiles`, `getFileInfo`, `getFileDownloadUrl`, `deleteFile`, `createSkillFromFileId`, `listSkills`, `getSkillInfo`, `deleteSkill` |
267317
| Deployment | `listDeploymentsForContext`, `getDeploymentDetailsForContext`, `getDeploymentRuntimeProviderForContext`, `runDeploymentForContext` |
268318
| Models | `listProviderModelsForContext`, `listProviderNames` |

‎packages/playground/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"chokidar": "^4.0.3",
4747
"hono": "^4.13.11",
4848
"yaml": "^2.9.0",
49-
"zod": "^4.4.3"
49+
"zod": "^4.6.6"
5050
},
5151
"devDependencies": {
5252
"@types/bun": "^1.3.14",

‎packages/sdk/docs/public-api-layers.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ New CLI and WebUI behavior should start here.
3737
- Managed-resource reads: environment, skill/version/download, vault, and file
3838
metadata/content APIs with opaque cursor preservation.
3939
- Session workflows: creation, list/get/update/archive/delete, runs, follow-up
40-
messages, raw event send/list/stream, and summaries. Managed Agents child
41-
threads remain event metadata (`session_thread_id`); there is no independent
42-
public Thread resource API.
40+
messages, raw event send/list/stream, and summaries. 百炼子 Agent 的
41+
`listSessionThreads` 与 `listSessionThreadEvents` 提供 Thread 列表和分页历史;
42+
主 Agent 不在子线程列表中,实时事件仍通过 Session 流获取。SDK 不提供 Thread
43+
创建、归档或独立流。事件与线程类型复用公开合同,浏览器只从 `./session-events` 导入。
4344
- Deployment workflows: list/get/search, run history, run, pause, and unpause.
4445
- Operation capabilities: provider-scoped support/auth/reason metadata for
4546
API-oriented command hosts.

‎packages/sdk/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
"dependencies": {
7979
"jszip": "^3.10.1",
8080
"yaml": "^2.9.0",
81-
"zod": "^4.4.3"
81+
"zod": "^4.6.6"
8282
},
8383
"devDependencies": {
8484
"@types/bun": "^1.3.14",

‎packages/sdk/src/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ export type {
359359
ProviderSessionEventList,
360360
} from "./internal/types/session-event.ts";
361361
export type { ProviderFileInfo } from "./internal/types/file.ts";
362+
export { listSessionThreadEvents, listSessionThreads } from "./internal/core/session-thread-runtime.ts";
363+
export type { SessionThread, SessionThreadListOptions, SessionThreadPage } from "./internal/types/session-thread.ts";
362364
export type { ProviderSkillInfo } from "./internal/types/skill-info.ts";
363365

364366
export { parseStateAddress } from "./internal/core/state-runtime.ts";

‎packages/sdk/src/internal/core/managed-api-runtime.ts‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ export async function listRemoteAgents(
5454
export async function getRemoteAgent(
5555
ctx: ProjectRuntimeContext,
5656
id: string,
57-
options: ManagedApiTarget & { version?: number } = {},
57+
options: ManagedApiTarget & { version?: number; signal?: AbortSignal } = {},
5858
) {
5959
const adapter = resolveAdapter(ctx, options.provider);
6060
const method = requiredMethod(adapter.getRemoteAgent, adapter.name, "agent lookup");
61-
return method.call(adapter, id, options.version);
61+
options.signal?.throwIfAborted();
62+
const result = await method.call(adapter, id, options.version, { signal: options.signal });
63+
options.signal?.throwIfAborted();
64+
return result;
6265
}
6366

6467
export async function listRemoteAgentVersions(
@@ -292,7 +295,7 @@ const UNSUPPORTED_THREAD: ManagedAgentOperationCapability = {
292295
supported: false,
293296
auth: null,
294297
reason:
295-
"Managed Agents exposes child-thread ids and lifecycle events through Session Events, but no independent Thread resource API.",
298+
"This SDK currently supports child-thread listing and event history; thread lookup and archive are not implemented.",
296299
};
297300
const UNSUPPORTED_OAUTH: ManagedAgentOperationCapability = {
298301
supported: false,
@@ -364,10 +367,10 @@ const BAILIAN_OPERATIONS: Record<string, ManagedAgentOperationCapability> = {
364367
"file.delete": API_KEY,
365368
"model.list": UNSUPPORTED_MODEL,
366369
"model.search": UNSUPPORTED_MODEL,
367-
"session_thread.list": UNSUPPORTED_THREAD,
370+
"session_thread.list": API_KEY,
368371
"session_thread.get": UNSUPPORTED_THREAD,
369372
"session_thread.archive": UNSUPPORTED_THREAD,
370-
"session_thread.events": UNSUPPORTED_THREAD,
373+
"session_thread.events": API_KEY,
371374
"mcp.oauth_login": UNSUPPORTED_OAUTH,
372375
};
373376

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { EventListOptions, ProviderSessionEventList } from "../types/session-event.ts";
2+
3+
/** Keep SDK-only routing options out of provider requests; normalize the legacy page alias. */
4+
export function sessionEventListOptions(options: EventListOptions): EventListOptions | undefined {
5+
const result: EventListOptions = {};
6+
for (const key of [
7+
"event_format",
8+
"signal",
9+
"limit",
10+
"order",
11+
"types",
12+
"created_at_gt",
13+
"created_at_gte",
14+
"created_at_lt",
15+
"created_at_lte",
16+
] as const) {
17+
if (options[key] !== undefined) Object.assign(result, { [key]: options[key] });
18+
}
19+
const pageToken = options.page_token ?? options.page;
20+
if (pageToken !== undefined) result.page_token = pageToken;
21+
return Object.keys(result).length ? result : undefined;
22+
}
23+
24+
export function filterSessionEventPage(
25+
result: ProviderSessionEventList,
26+
types: string[] | undefined,
27+
): ProviderSessionEventList {
28+
if (!types?.length) return result;
29+
const allowedTypes = new Set(types);
30+
return { ...result, events: result.events.filter((event) => allowedTypes.has(event.raw_type)) };
31+
}

0 commit comments

Comments
 (0)