@blade-hq/agent-client 2610.0.1-alpha.1 → 2610.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +281 -11
  2. package/dist/auth.d.ts +0 -1
  3. package/dist/blade-client.d.ts +24 -1
  4. package/dist/index.d.ts +38 -7
  5. package/dist/index.js +2520 -283
  6. package/dist/index.js.map +1 -1
  7. package/dist/platform-endpoints.d.ts +14 -0
  8. package/dist/polling-backoff.d.ts +11 -0
  9. package/dist/resources/chat-groups.d.ts +31 -0
  10. package/dist/resources/computers.d.ts +115 -0
  11. package/dist/resources/models.d.ts +2 -0
  12. package/dist/resources/plugins.d.ts +43 -0
  13. package/dist/resources/sessions.d.ts +238 -2
  14. package/dist/resources/site-visits.d.ts +32 -0
  15. package/dist/rest.d.ts +8 -0
  16. package/dist/schemas/context.d.ts +49 -0
  17. package/dist/schemas/event.d.ts +9 -0
  18. package/dist/schemas/mcp-app.d.ts +30 -0
  19. package/dist/schemas/message-utils.d.ts +15 -1
  20. package/dist/schemas/message.d.ts +8 -0
  21. package/dist/schemas/projection-utils.d.ts +3 -0
  22. package/dist/schemas/projection.d.ts +53 -2
  23. package/dist/schemas/session.d.ts +10 -1
  24. package/dist/session/agent-session.d.ts +160 -16
  25. package/dist/session/definition.d.ts +6 -1
  26. package/dist/session/errors.d.ts +11 -0
  27. package/dist/session/events.d.ts +16 -2
  28. package/dist/session/history-page.d.ts +9 -0
  29. package/dist/session/hub.d.ts +9 -1
  30. package/dist/session/queue.d.ts +104 -0
  31. package/dist/session/state.d.ts +19 -2
  32. package/dist/shared/auth-busy.d.ts +9 -0
  33. package/dist/shared/projection/builder.d.ts +17 -0
  34. package/dist/shared/projection/context.d.ts +3 -0
  35. package/dist/shared/projection/helpers.d.ts +4 -2
  36. package/dist/shared/projection/history.d.ts +1 -0
  37. package/dist/shared/projection/index.d.ts +2 -1
  38. package/dist/shared/projection/state.d.ts +7 -0
  39. package/dist/shared/tool-ui-card.d.ts +60 -0
  40. package/dist/shared/type-guards.d.ts +2 -0
  41. package/dist/socket.d.ts +2 -0
  42. package/dist/types/socket-events.d.ts +201 -2
  43. package/package.json +4 -2
  44. package/public-api.md +1071 -23
@@ -0,0 +1,30 @@
1
+ /** Archived MCP App data. Credentials and executable server configuration are excluded. */
2
+ export interface McpAppData {
3
+ sourceId: string;
4
+ resourceUri: string;
5
+ mimeType: string;
6
+ resourceMeta: Record<string, unknown>;
7
+ toolInput: Record<string, unknown>;
8
+ toolResult: Record<string, unknown>;
9
+ }
10
+ export interface McpAppArchive extends McpAppData {
11
+ html: string;
12
+ plugin: string;
13
+ /** Restore the last successful view before delivering a saved failure. */
14
+ previousToolInput?: Record<string, unknown>;
15
+ previousToolResult?: Record<string, unknown>;
16
+ }
17
+ export declare function isMcpAppData(value: unknown): value is McpAppData;
18
+ /** Latest model-context state one MCP App saved for its own card. */
19
+ export interface McpAppContextState {
20
+ revision: string;
21
+ content: string;
22
+ plugin: string | null;
23
+ server_alias: string | null;
24
+ }
25
+ export interface McpAppContextUpdate {
26
+ request_id: string;
27
+ /** null on the first save; the server rejects a stale revision. */
28
+ expected_revision: string | null;
29
+ content: string;
30
+ }
@@ -1,9 +1,21 @@
1
1
  import type { ChatMessage, FileContentPart, ImageUrlContentPart, MessageContent } from "./message";
2
+ /** Ordinary chat uses business copy; developer mode may retain diagnostics. */
3
+ export declare function chatErrorForDisplay(message: string, developer?: boolean): string;
2
4
  export declare function normalizeMessageContent(content: unknown): MessageContent;
3
5
  export declare function getTextContent(content: MessageContent): string;
4
6
  export declare function isSystemReminderText(text: string): boolean;
5
7
  export declare function isLegacyForkContextText(text: string): boolean;
6
- export declare function isHiddenInternalMessage(message: Pick<ChatMessage, "role" | "content">): boolean;
8
+ /**
9
+ * 平台自己写进去、不该露给用户的内部提示。
10
+ *
11
+ * 服务端的消息导航目录有一份同名同语义的 Python 实现
12
+ * (`server/.../routes/sessions.py` 的 `_is_hidden_internal_message`):客户端靠它决定
13
+ * 渲染不渲染,服务端靠它决定进不进目录。改这里必须同时改那边,否则目录会列出没有对应
14
+ * 行的死条目,或者把内部提示原文当标题露出去。
15
+ */
16
+ export declare function isHiddenInternalMessage(message: Pick<ChatMessage, "role" | "content">, options?: {
17
+ includeLegacyForkContext?: boolean;
18
+ }): boolean;
7
19
  export declare function buildMessageContent(text: string, attachments: Array<{
8
20
  kind: "file";
9
21
  name: string;
@@ -55,4 +67,6 @@ interface MessageGroup {
55
67
  }[];
56
68
  }
57
69
  export declare function groupMessagesByLoop(messages: ChatMessage[]): MessageGroup[];
70
+ /** A typed wake input stays internal for navigation, but has a visible notice. */
71
+ export declare function isBackgroundWakeMessage(message: Pick<ChatMessage, "blocks">): boolean;
58
72
  export {};
@@ -1,4 +1,5 @@
1
1
  import type { ContentBlock, PendingQuestionRef, ToolBridgeContent } from "./projection";
2
+ import type { ContextProjectionData } from "./context";
2
3
  export interface TextContentPart {
3
4
  type: "text";
4
5
  text: string;
@@ -7,6 +8,9 @@ export interface ImageUrlContentPart {
7
8
  type: "image_url";
8
9
  image_url: {
9
10
  url: string;
11
+ source_path?: string;
12
+ width?: number;
13
+ height?: number;
10
14
  };
11
15
  }
12
16
  export interface FileContentPart {
@@ -70,6 +74,8 @@ export interface ChatMessage {
70
74
  duration_ms?: number;
71
75
  timestamp?: string;
72
76
  entry_id?: string;
77
+ /** Stable React key retained when an optimistic user message is confirmed. */
78
+ render_id?: string;
73
79
  parent_id?: string | null;
74
80
  loop_name?: string;
75
81
  /** Entry kind from backend -- present for non-message entries like mode changes. */
@@ -80,4 +86,6 @@ export interface ChatMessage {
80
86
  blocks?: ContentBlock[];
81
87
  /** Compaction metadata for compaction turns. */
82
88
  compaction?: CompactionInfo;
89
+ /** Sourced Context metadata for rendering or headless consumers. */
90
+ context?: ContextProjectionData;
83
91
  }
@@ -0,0 +1,3 @@
1
+ import type { PostChatFollowup, TurnProjection } from "./projection";
2
+ /** 返回最新根会话轮次的小结;新用户消息到达后旧小结立即失效。 */
3
+ export declare function latestPostChatFollowup(turns: TurnProjection[]): PostChatFollowup | null;
@@ -5,6 +5,8 @@ export interface ToolBridgeContent {
5
5
  export interface ContentBlock {
6
6
  type: "text" | "thinking" | "tool_use" | "tool_result" | "tool_ui" | "tool_bridge" | "system_notification" | "mode_change" | "plan_status" | "ask_user_answer";
7
7
  content: unknown;
8
+ /** Stable history-entry identity for a tool_bridge delivery. */
9
+ delivery_id?: string | null;
8
10
  tool_call_id?: string | null;
9
11
  tool_name?: string | null;
10
12
  display_name?: string | null;
@@ -14,6 +16,15 @@ export interface PendingQuestionRef {
14
16
  child_tool_call_id: string;
15
17
  description?: string | null;
16
18
  }
19
+ /** 一次运行(用户轮或子智能体)的实际墙钟区间。 */
20
+ export interface RunTiming {
21
+ run_id: string;
22
+ scope: "chat" | "subagent";
23
+ loop_id: string;
24
+ started_at?: string | null;
25
+ duration_ms?: number | null;
26
+ status: "completed" | "failed" | "cancelled" | "paused" | "incomplete";
27
+ }
17
28
  export interface ToolCallProjection {
18
29
  id: string;
19
30
  tool_name: string;
@@ -22,6 +33,11 @@ export interface ToolCallProjection {
22
33
  status: "pending" | "done" | "error" | "cancelled" | "awaiting_answer" | string;
23
34
  result?: unknown;
24
35
  duration_ms?: number | null;
36
+ /** 工具真正进入执行的墙钟起点;排队/待审批的调用没有该值。 */
37
+ started_at?: string | null;
38
+ ran_in_parallel?: boolean;
39
+ /** 该工具派生的子智能体运行区间,仅作外层展示。 */
40
+ subagent_runs?: RunTiming[];
25
41
  pending_question_ref?: PendingQuestionRef | null;
26
42
  }
27
43
  export interface MemoryRef {
@@ -29,23 +45,57 @@ export interface MemoryRef {
29
45
  content_preview: string;
30
46
  skill_name?: string | null;
31
47
  }
48
+ export interface FinalArtifact {
49
+ kind: "file" | "link";
50
+ target: string;
51
+ label: string;
52
+ }
53
+ export interface PostChatFollowup {
54
+ assistant_entry_id: string;
55
+ recaption?: string;
56
+ suggestions: string[];
57
+ final_artifacts?: FinalArtifact[];
58
+ feedback_eligible: boolean;
59
+ feedback_scope: "latest_result";
60
+ }
32
61
  export interface TurnProjection {
33
62
  id: string;
34
63
  sequence: number;
35
64
  turn_id: string;
36
65
  loop_id: string;
37
- kind?: "message" | "compaction";
66
+ kind?: "message" | "context" | "compaction";
38
67
  role: "user" | "assistant" | "system";
39
68
  status: "streaming" | "completed" | "paused" | "failed" | "interrupted";
40
69
  blocks: ContentBlock[];
41
70
  tool_calls: ToolCallProjection[];
42
71
  model?: string | null;
43
72
  usage?: Record<string, unknown> | null;
44
- duration_ms?: number;
73
+ /** 模型请求区间(不含后续工具);未知时为 null,不用 0 冒充。 */
74
+ duration_ms?: number | null;
75
+ first_token_ms?: number | null;
76
+ stream_duration_ms?: number | null;
77
+ first_token_delivery_ms?: number | null;
45
78
  started_at?: string | null;
79
+ /** started_at 是否来自生产者上报(而非旧会话的落盘回落)。瀑布只承认前者。 */
80
+ has_reported_timing?: boolean;
46
81
  context_window?: number;
47
82
  memory_refs?: MemoryRef[] | null;
48
83
  parent_fork_tool_call_id?: string | null;
84
+ context_kind?: string | null;
85
+ context_key?: string | null;
86
+ context_name?: string | null;
87
+ context_order?: number | null;
88
+ context_action?: import("./context").ContextAction | null;
89
+ context_revision?: string | null;
90
+ /** 原始 Context 内容仅供开发者模式诊断;常规消息投影不消费。 */
91
+ context_content?: unknown;
92
+ display_title?: string | null;
93
+ display_summary?: string | null;
94
+ sources?: import("./context").ContextSourceInfo[] | null;
95
+ /** Client-only stable identity for reconciling an optimistic user turn. */
96
+ client_render_id?: string | null;
97
+ /** Send identity echoed by the server for exact optimistic reconciliation. */
98
+ client_request_id?: string | null;
49
99
  compaction_id?: string | null;
50
100
  summary_preview?: string | null;
51
101
  summary_full?: string | null;
@@ -58,6 +108,7 @@ export interface TurnProjection {
58
108
  trigger?: "auto" | "manual" | "forced_retry" | null;
59
109
  failure_reason?: string | null;
60
110
  fallback_applied?: boolean | null;
111
+ post_chat_followup?: PostChatFollowup | null;
61
112
  }
62
113
  export interface ArchivedFileInfo {
63
114
  tool_name?: string | null;
@@ -62,6 +62,7 @@ export declare const SessionInfo: import("arktype/internal/variants/object.ts").
62
62
  shared?: boolean | undefined;
63
63
  memory_enabled?: boolean | undefined;
64
64
  is_persistent?: boolean | undefined;
65
+ initiator?: "sdk" | "ui" | "unknown" | null | undefined;
65
66
  is_headless?: boolean | undefined;
66
67
  viewer_role?: "owner" | "viewer" | undefined;
67
68
  template_id?: string | null | undefined;
@@ -82,7 +83,11 @@ export declare const SessionInfo: import("arktype/internal/variants/object.ts").
82
83
  disable_tools?: string[] | undefined;
83
84
  runtime_type?: string | null | undefined;
84
85
  daemon_id?: string | null | undefined;
86
+ agent_runtime_id?: string | null | undefined;
85
87
  workspace_path?: string | null | undefined;
88
+ ba_version?: string | null | undefined;
89
+ sandbox_version?: string | null | undefined;
90
+ chat_group_id?: string | null | undefined;
86
91
  match?: unknown;
87
92
  }, {}>;
88
93
  export type SessionInfo = Omit<typeof SessionInfo.infer, "template_id" | "solution" | "ports" | "match"> & {
@@ -106,9 +111,13 @@ export type SessionInfo = Omit<typeof SessionInfo.infer, "template_id" | "soluti
106
111
  is_example?: boolean;
107
112
  ports?: SessionPortMapping[];
108
113
  disable_tools?: string[];
109
- runtime_type?: "sandbox" | "daemon" | string | null;
114
+ runtime_type?: "sandbox" | "daemon" | "native" | string | null;
110
115
  daemon_id?: string | null;
116
+ agent_runtime_id?: string | null;
111
117
  workspace_path?: string | null;
118
+ ba_version?: string | null;
119
+ sandbox_version?: string | null;
120
+ chat_group_id?: string | null;
112
121
  /** 仅在带 q 搜索的列表响应中出现;普通列表里此字段缺省。 */
113
122
  match?: SessionSearchMatch | null;
114
123
  };
@@ -4,14 +4,17 @@ import type { PatchEnvelope, TurnProjection } from "../schemas/projection";
4
4
  import type { ReplaySpeed, ReplayState, SessionStatus } from "../schemas/session";
5
5
  import { type CommandHandler } from "../commands/registry";
6
6
  import { type AgentSessionEvents } from "./events";
7
- import type { AppCliAttachment, AppCliDefinition, FileEntry } from "../resources/sessions";
7
+ import type { AppCliAttachment, AppCliDefinition, FileEntry, HistoricalCommand, SessionTurnIndex, SessionTurnIndexItem, SessionTurnsPage, SessionTurnsQuery } from "../resources/sessions";
8
+ import { type QueueOperationResult } from "./queue";
8
9
  import { type ConnectionStatus, type SessionState } from "./state";
9
10
  /** SessionHub 注入给 AgentSession 的运行时依赖(socket 收发 + REST 补数)。 */
10
11
  export interface SessionRuntime {
11
12
  emitEvent(event: string, data: unknown): void;
12
13
  emitWithAck(event: string, data: unknown, timeoutMs: number): Promise<Record<string, unknown> | undefined>;
13
14
  ensureConnected(): void;
14
- fetchTurns(sessionId: string): Promise<TurnProjection[]>;
15
+ fetchTurnsPage(sessionId: string, query?: SessionTurnsQuery, init?: RequestInit): Promise<SessionTurnsPage>;
16
+ fetchTurnIndex(sessionId: string): Promise<SessionTurnIndex>;
17
+ fetchCommands(sessionId: string): Promise<HistoricalCommand[]>;
15
18
  /** 会话详情,目前只用来取回放状态。 */
16
19
  fetchSessionInfo(sessionId: string): Promise<{
17
20
  replay_state?: ReplayState | null;
@@ -52,6 +55,13 @@ export interface SendOptions {
52
55
  deprecate_entry_ids: string[];
53
56
  };
54
57
  replayDecision?: "keep_replay" | "continue_replay";
58
+ /** 用户显式选择的知识库 id;后端将元信息作为 once Context 提供给模型。 */
59
+ kbIds?: number[];
60
+ /**
61
+ * 声明"会话在跑就把这条消息放进等待队列"。默认不排队、运行中直接报错:
62
+ * 是否真的入队由服务端按运行状态判定(等待回答时发送即作答,不会被误排队)。
63
+ */
64
+ queueWhenRunning?: boolean;
55
65
  }
56
66
  export declare function sessionStatusFromChatEnd(status: string | undefined): SessionStatus;
57
67
  /**
@@ -74,10 +84,45 @@ export declare class AgentSession {
74
84
  private patchFlushCancel;
75
85
  private joined;
76
86
  private joinPending;
87
+ private subscriptionQueue;
88
+ private replaceQueue;
89
+ private timelineEpoch;
90
+ /** 定位请求的流水号:被后一次选择取代的那次定位不再提交窗口(见 locateEntry)。 */
91
+ private locateToken;
92
+ /** 在途那次定位的请求句柄。**只**服务定位:权威刷新不共用它(见 cancelPendingLocate)。 */
93
+ private locateAbort;
94
+ private pagingGeneration;
95
+ private liveRevision;
96
+ private modeRevision;
97
+ private readonly liveRevisions;
98
+ private readonly pendingOptimisticTurnIds;
99
+ private olderPending;
100
+ private replaceInFlight;
77
101
  private replayQueue;
102
+ private commandRestoreQueue;
103
+ private commandRecoveryGeneration;
104
+ private commandRestoreRetryAttempt;
105
+ private commandRestoreRetryHandle;
106
+ private bufferedCommandDeliveries;
78
107
  private pendingReplayMessage;
79
108
  private pendingReplayMode;
109
+ private pendingReplayKbIds;
80
110
  private recentChatEndAt;
111
+ /**
112
+ * 最近一次已经通过 `error` 事件投递过的服务端失败(`message` + `code`)。
113
+ *
114
+ * `chat:send` 被代理时服务端会先发 `system:error`、再用同一条失败回 ack,两条
115
+ * 通道都会到达这里:前者走 `_handleSystemError`,后者走发送失败的回滚。不去重
116
+ * 的话调用方会收到两次同一个 `error`(重复提示、重试逻辑跑两遍)。
117
+ *
118
+ * 带代际边界,只认「本次 `emitWithAck` 等待期间」投递的那一条:否则队列/停止
119
+ * 失败留下的标记会一直挂着,之后一次无关的订阅失败只是文案码相同就被当成
120
+ * 重复而静音。用单调递增的代际号而不是时间戳,同一毫秒内的两条也不会混淆。
121
+ */
122
+ private lastDeliveredSystemError;
123
+ /** 每次投递 `system:error` 递增,用于判定某条失败是否属于本次等待。 */
124
+ private systemErrorGeneration;
125
+ private subscriptionReplaySource;
81
126
  private disposed;
82
127
  private getAppContext;
83
128
  private sendPending;
@@ -88,11 +133,55 @@ export declare class AgentSession {
88
133
  private readonly seenToolCallIds;
89
134
  private readonly finishedToolCallIds;
90
135
  private readonly emittedMessageTurnIds;
91
- constructor(sessionId: string, runtime: SessionRuntime, connection: ConnectionStatus);
136
+ constructor(sessionId: string, runtime: SessionRuntime, connection: ConnectionStatus, options?: {
137
+ staticHistory?: boolean;
138
+ });
139
+ /**
140
+ * 静态历史(分享页 / `fromTurns`):没有目录接口,也**没有**"目录还没到位"这个中间态。
141
+ *
142
+ * 宿主据此决定要不要拿已加载窗口当兜底条目——真实会话在 timeline 被重写后,窗口里还是
143
+ * 旧分支的发言,拿它兜底会把已经失效的 entry id 重新摆到轨道上,点了必然找不到。
144
+ */
145
+ readonly isStatic: boolean;
92
146
  /** 从一份静态 turn 快照构造只展示历史的会话(例如公开分享页)。 */
93
147
  static fromTurns(sessionId: string, turns: TurnProjection[]): AgentSession;
94
148
  /** 返回当前会话快照。引用稳定:状态未变化时返回同一对象。 */
95
149
  getState(): SessionState;
150
+ get hasOlderHistory(): boolean;
151
+ /** Load the page immediately preceding the current display window. */
152
+ loadOlderHistory(options?: {
153
+ beforeCommit?: () => void;
154
+ }): Promise<void>;
155
+ /**
156
+ * 定位到一条窗口外的历史发言:请服务端返回"从这条发言到最新"的窗口并整窗替换。
157
+ *
158
+ * 返回 false 表示这次定位没有落地(请求失败,或期间 timeline 被重写、会话已释放),
159
+ * 当前窗口保持不变,调用方可以原样重试。已加载的发言不要走这里——宿主直接滚动,
160
+ * 一次网络请求都不该发。
161
+ */
162
+ locateEntry(entryId: string): Promise<boolean>;
163
+ /**
164
+ * 取消在途定位:用户改选了另一条发言(哪怕那条已经加载、不需要请求),
165
+ * 先前那次定位既不该再落地,也不该继续占着替换队列——排队中的下一次定位
166
+ * 不然要等它跑完(用户看到的是"点了新目标一直转圈")。
167
+ *
168
+ * **只**中止定位自己的请求:权威刷新(运行结束 / 重连补数)不共用这个 controller,
169
+ * 否则"运行刚结束时点一下侧栏"就会把终态对账一起中止,流式与历史对不上。
170
+ */
171
+ cancelPendingLocate(): void;
172
+ /**
173
+ * timeline 被整体改写(rewind / checkout / 释放):推进纪元,并把在途定位请求一并中止
174
+ * ——它已经属于旧 timeline,却还占着替换队列,会让改写后的权威窗口排在后面等它跑完。
175
+ * 作废号仍然保留:中止只是让它更早结束。
176
+ */
177
+ private invalidateTimeline;
178
+ /**
179
+ * 拉取当前分支的用户发言目录(消息导航侧栏用)。
180
+ *
181
+ * 不在这里缓存:什么时候该刷新只有调用方知道(会话切换、历史被替换、新发言),
182
+ * 缓存只会让旧条目在 rewind 之后继续可点。
183
+ */
184
+ loadTurnIndex(): Promise<SessionTurnIndexItem[]>;
96
185
  /** 订阅状态变化。返回取消订阅函数。 */
97
186
  subscribe(listener: () => void): () => void;
98
187
  private setState;
@@ -115,10 +204,44 @@ export declare class AgentSession {
115
204
  attachApp(options: AttachAppOptions): Promise<AppCliAttachment | null>;
116
205
  /** 发送一条消息。字符串或多模态内容均可。 */
117
206
  send(content: MessageContent, options?: SendOptions): Promise<boolean>;
207
+ /**
208
+ * 入队一条等待消息(运行中排队 / 暂停期间照常入队)。
209
+ *
210
+ * ack 超时或传输失败时结果未知:用**同一个** `client_request_id` 重试一次,
211
+ * 服务端按 `(session_id, client_request_id)` 幂等,不会制造第二条。
212
+ */
213
+ queueMessage(content: string): Promise<QueueOperationResult>;
214
+ /** 修改一条等待消息的正文;`expectedVersion` 是客户端看到的条目版本。 */
215
+ updateQueuedMessage(itemId: string, expectedVersion: number, content: string): Promise<QueueOperationResult>;
216
+ /**
217
+ * 重排等待消息。`orderedIds` 必须是当前 pending 条目 id 的**完整集合**(顺序任意),
218
+ * 服务端按 `expectedRevision` 校验后整体替换顺序。
219
+ *
220
+ * 拖动排序就该像本地操作一样落地:版本冲突(运行中的任务刚领走一条 / 另一个端也在
221
+ * 动队列)不甩给用户「刷新后重试」,而是拿冲突响应里那份**最新快照**重算一次再提交
222
+ * ——掉队的条目(已经被领取执行的)从顺序里剔除,剩下的保持用户拖出来的相对次序。
223
+ * 最多补两次;仍旧冲突才把结果交回调用方。
224
+ */
225
+ reorderQueuedMessages(expectedRevision: number, orderedIds: string[]): Promise<QueueOperationResult>;
226
+ /** 删除一条等待消息;不传版本时由服务端自行判定。 */
227
+ cancelQueuedMessage(itemId: string, expectedVersion?: number): Promise<QueueOperationResult>;
228
+ /** 立即补充:把等待消息交给当前运行,在下一个接收点消费,不停止也不另起一轮。 */
229
+ deliverQueuedMessage(itemId: string, expectedVersion: number): Promise<QueueOperationResult>;
230
+ /** 继续执行:清除暂停,并按当前顺序恢复逐条接续。 */
231
+ resumeQueue(): Promise<QueueOperationResult>;
232
+ /** 拉取一份权威队列快照。首次连接与每次重连后由实例自动调用,也可以手动刷新。 */
233
+ refreshQueue(): Promise<QueueOperationResult>;
234
+ /**
235
+ * 发出一条队列命令并安装 ack 里的快照。
236
+ * 传输层失败(超时 / 断线)会 reject,由调用方决定是否重试。
237
+ */
238
+ private requestQueueAck;
239
+ /** 队列命令的对外入口:传输失败只体现为失败结果,不向调用方抛异常。 */
240
+ private runQueueCommand;
118
241
  private sendUnlocked;
119
242
  private rollbackOptimisticSend;
120
- /** 智能体运行期间追加补充说明(不打断当前回复)。 */
121
- append(text: string): void;
243
+ /** 撤回一次乐观提交:移除乐观消息、恢复提问作答、清掉回放草稿。 */
244
+ private discardOptimisticSend;
122
245
  /** 停止当前回复。 */
123
246
  stop(): Promise<Record<string, unknown>>;
124
247
  /** 手动触发上下文压缩。 */
@@ -145,10 +268,17 @@ export declare class AgentSession {
145
268
  get isDisposed(): boolean;
146
269
  /** @internal 连接状态变化(同 client 下所有会话共享一条连接)。 */
147
270
  _setConnection(connection: ConnectionStatus): void;
271
+ /**
272
+ * @internal 服务端广播的权威队列快照。
273
+ * 结构不合法或 revision 不新的一律丢弃,绝不用旧快照覆盖新状态。
274
+ */
275
+ _handleQueueUpdated(payload: unknown): void;
148
276
  /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */
149
277
  _rejoinAfterReconnect(): Promise<void>;
150
278
  /** @internal 首次连接:加载历史 + 加入房间。 */
151
279
  _bootstrap(): Promise<void>;
280
+ /** 订阅生命周期串行执行;一次失败只由自己的调用方观察,不截断后续重连。 */
281
+ private enqueueSubscription;
152
282
  /** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */
153
283
  private get canControlReplay();
154
284
  /** 拉一次会话详情,填回放状态和只读身份;失败按非回放会话处理,不挡启动。 */
@@ -166,19 +296,21 @@ export declare class AgentSession {
166
296
  /** @internal */
167
297
  _handleTurnEnd(turn: TurnProjection): void;
168
298
  /** @internal 历史回放通道(event_format: raw)。 */
169
- _handleTurnEvents(events: RawEvent[]): void;
299
+ _handleTurnEvents(events: RawEvent[], replayed?: boolean): void;
170
300
  /** @internal */
171
301
  _handleChatStart(): void;
172
302
  /** @internal */
173
303
  _handleChatEnd(status: string): void;
174
304
  /** @internal */
175
- _handleSystemError(message: string): void;
305
+ _handleSystemError(message: string, code?: string): void;
176
306
  /** @internal */
177
307
  _handleTaskUpdated(tasks: unknown[]): void;
178
308
  /** @internal */
179
309
  _handleWorkspaceFilesChanged(filePath?: string): void;
180
310
  /** @internal */
181
311
  _handleSessionUpdated(data: {
312
+ workspace_path?: string;
313
+ chat_group_id?: string | null;
182
314
  intent?: string;
183
315
  status?: SessionStatus;
184
316
  model?: string | null;
@@ -199,9 +331,13 @@ export declare class AgentSession {
199
331
  /** @internal */
200
332
  _handleArtifact(event: AgentSessionEvents["artifact"]): void;
201
333
  /** @internal 加入房间的应答里带 is_running,据此校准流式状态。 */
202
- _applyRunningState(isRunning: boolean): void;
334
+ _applyRunningState(isRunning: boolean, liveRevisionAtJoin?: number): void;
203
335
  private markRunningIfIdle;
204
336
  private finishStreaming;
337
+ private completeChat;
338
+ private markTurnFresh;
339
+ private markOptimisticTurnPending;
340
+ private pruneOptimisticLiveRevisions;
205
341
  private applyTurn;
206
342
  private schedulePatchFlush;
207
343
  private cancelPatchFlush;
@@ -209,18 +345,26 @@ export declare class AgentSession {
209
345
  /** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */
210
346
  private emitTurnDerivedEvents;
211
347
  private dispatchCommand;
348
+ private dispatchRawCommands;
349
+ private deliverCommand;
350
+ private deliverCommandNow;
212
351
  private notifySandboxOom;
213
- private syncTurnsFromHistory;
214
352
  /**
215
- * 把历史里的指令补投给宿主页面。
353
+ * 权威刷新(运行结束 / 重连补数):**按当前窗口第一条发言取窗口**,不再另记"用户想看哪段"。
216
354
  *
217
- * 重开会话、断线补数时,地图高亮这类"页面当前状态"必须能恢复——
218
- * 否则刷新一次页面,之前智能体让页面做的事就全丢了。
219
- * 只回放指令:toolCall / message 这些事件如果按历史全量重放,
220
- * 监听器会在挂载瞬间收到几百条陈年事件。
221
- * dispatch 内部按 deliveredCommandKeys 去重,重复调用安全。
355
+ * 窗口本身就是"用户在看哪段":首屏就是最新一页,向上翻页 / 定位之后首条就是用户滚到的位置。
356
+ * 直接拿 `from_entry_id = 当前窗口第一条 turn_id` 去取,运行结束、重连补数、翻页之后的对账
357
+ * 是同一条规则,不需要意图、锚点、已落地锚点这些状态;窗口首条已经不在分支上(404 / 409)时
358
+ * 回落到最新一页。
222
359
  */
223
- private replayCommandsFromTurns;
360
+ private refreshAuthoritativeHistory;
361
+ private replaceFromHistory;
362
+ private invalidateOlderPaging;
363
+ private beginCommandRecovery;
364
+ private scheduleHistoricalCommandRestore;
365
+ private flushBufferedCommands;
366
+ /** 首次订阅前的 REST 历史建立语义事件基线,随后同一工具的订阅回放不再投递。 */
367
+ private seedToolCallDeliveryBaseline;
224
368
  private ensureJoined;
225
369
  private ensureIdleBeforeSend;
226
370
  }
@@ -11,11 +11,16 @@ export type SolutionDefinition = {
11
11
  files: TextFile[];
12
12
  role?: string;
13
13
  };
14
+ export type SkillFile = TextFile & {
15
+ /** 二进制内容使用 base64;省略时为 UTF-8 文本。 */
16
+ encoding?: "utf-8" | "base64";
17
+ executable?: boolean;
18
+ };
14
19
  export interface SkillDefinition {
15
20
  /** 会话内安装名,格式为 `组织/名称`。 */
16
21
  name: string;
17
22
  /** 必须包含根目录的 SKILL.md。 */
18
- files: TextFile[];
23
+ files: SkillFile[];
19
24
  }
20
25
  export interface SessionConfig {
21
26
  /** Server 模型目录中的 model ID。 */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 一次会话操作的失败。
3
+ *
4
+ * `code` 是服务端给的机器可读原因(如 `owner_timeout` / `route_broken`),
5
+ * 调用方据此决定要不要重试;`message` 是可以直接展示的业务文案,不要当协议解析。
6
+ */
7
+ export declare class AgentSessionError extends Error {
8
+ readonly name = "AgentSessionError";
9
+ readonly code?: string;
10
+ constructor(message: string, code?: string);
11
+ }
@@ -1,4 +1,5 @@
1
1
  import type { ChatMessage, ToolCallInfo } from "../schemas/message";
2
+ import type { McpAppData } from "../schemas/mcp-app";
2
3
  import type { TurnProjection } from "../schemas/projection";
3
4
  import type { SessionStatus } from "../schemas/session";
4
5
  /**
@@ -23,14 +24,22 @@ export interface AgentSessionEvents {
23
24
  toolResult: {
24
25
  toolCall: ToolCallInfo;
25
26
  turn: TurnProjection;
27
+ /** 实时到达,或首次连接/断线重连时由服务端回放。 */
28
+ source: "live" | "bootstrap_replay" | "reconnect_replay";
26
29
  };
27
30
  /** 一轮回复结束。status: completed / paused / interrupted / failed。 */
28
31
  chatEnd: {
29
32
  status: string;
30
33
  };
31
- /** 运行错误(system:error、发送失败等)。 */
34
+ /**
35
+ * 运行错误(system:error、发送失败等)。
36
+ *
37
+ * `code` 是服务端给的机器可读原因(如 `owner_timeout` / `route_broken`),
38
+ * 供调用方决定要不要重试;`message` 是可以直接展示的业务文案。
39
+ */
32
40
  error: {
33
41
  message: string;
42
+ code?: string;
34
43
  };
35
44
  /** planning / executing 模式切换。 */
36
45
  modeChange: {
@@ -74,10 +83,13 @@ export interface AgentSessionEvents {
74
83
  };
75
84
  /** 工具返回值带 _meta.ui 的可视化预览(resource HTML / URI)。 */
76
85
  toolPreview: {
86
+ /** Source file identity when the preview comes from a local HTML file. */
87
+ sourcePath?: string;
77
88
  toolCallId: string;
78
- type: "resource-html" | "resource-uri";
89
+ type: "resource-html" | "resource-uri" | "resource-file";
79
90
  content: string;
80
91
  title: string;
92
+ mcpApp?: McpAppData;
81
93
  };
82
94
  /** 任务清单(TaskCreate 等)更新。 */
83
95
  taskListUpdated: {
@@ -106,6 +118,8 @@ export interface AgentSessionEvents {
106
118
  };
107
119
  /** 会话属性(名称、状态、绑定技能等)被服务端更新。 */
108
120
  sessionUpdated: {
121
+ workspacePath?: string;
122
+ chatGroupId?: string | null;
109
123
  intent?: string;
110
124
  status?: SessionStatus;
111
125
  model?: string | null;
@@ -0,0 +1,9 @@
1
+ import type { TurnProjection } from "../schemas/projection";
2
+ export interface LiveRevisionState {
3
+ current: number;
4
+ byTurnId: ReadonlyMap<string, number>;
5
+ }
6
+ /** Add an older authoritative slice without allowing it to roll back live content. */
7
+ export declare function prependOlder(current: TurnProjection[], page: TurnProjection[]): TurnProjection[];
8
+ /** Install a new authoritative window, retaining only live writes newer than the request. */
9
+ export declare function replaceWindow(current: TurnProjection[], page: TurnProjection[], liveRevisionAtStart: number, liveRevisions: LiveRevisionState): TurnProjection[];
@@ -1,6 +1,13 @@
1
1
  import type { BladeClient } from "../blade-client";
2
2
  import { AgentSession } from "./agent-session";
3
3
  import type { ConnectionStatus } from "./state";
4
+ export interface SessionConnectOptions {
5
+ /**
6
+ * 在会话进入事件路由后、历史加载与房间订阅开始前同步执行。
7
+ * 适合安装不能漏掉 bootstrap 回放事件的监听器。
8
+ */
9
+ setup?: (session: AgentSession) => void;
10
+ }
4
11
  /**
5
12
  * 每个 BladeClient 一个:管理一条 Socket.IO 连接,按 session_id 把事件
6
13
  * 路由给各 AgentSession 实例。多会话共享连接、状态互不干扰。
@@ -15,6 +22,7 @@ export declare class SessionHub {
15
22
  private readonly connectionListeners;
16
23
  private bound;
17
24
  private hasConnected;
25
+ private readonly authBusyReconnect;
18
26
  constructor(client: BladeClient);
19
27
  /** 当前 Socket.IO 连接状态。 */
20
28
  getConnection(): ConnectionStatus;
@@ -27,7 +35,7 @@ export declare class SessionHub {
27
35
  * 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类"连两次
28
36
  * 只释放一次"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。
29
37
  */
30
- connect(sessionId: string): Promise<AgentSession>;
38
+ connect(sessionId: string, options?: SessionConnectOptions): Promise<AgentSession>;
31
39
  /** 已有实例则返回,不触发网络请求。 */
32
40
  peek(sessionId: string): AgentSession | undefined;
33
41
  /** 手动重连(例如登录态变化后)。 */