@blade-hq/agent-client 1.1.1

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 (39) hide show
  1. package/README.md +351 -0
  2. package/dist/auth-login.d.ts +29 -0
  3. package/dist/auth.d.ts +8 -0
  4. package/dist/blade-client.d.ts +113 -0
  5. package/dist/commands/embedded.d.ts +32 -0
  6. package/dist/commands/protocol.d.ts +38 -0
  7. package/dist/commands/registry.d.ts +21 -0
  8. package/dist/index.d.ts +37 -0
  9. package/dist/index.js +4182 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/resources/auth.d.ts +34 -0
  12. package/dist/resources/headless.d.ts +33 -0
  13. package/dist/resources/sessions.d.ts +263 -0
  14. package/dist/rest.d.ts +21 -0
  15. package/dist/schemas/background.d.ts +16 -0
  16. package/dist/schemas/event.d.ts +51 -0
  17. package/dist/schemas/message-utils.d.ts +48 -0
  18. package/dist/schemas/message.d.ts +83 -0
  19. package/dist/schemas/projection.d.ts +87 -0
  20. package/dist/schemas/session.d.ts +126 -0
  21. package/dist/schemas/solution.d.ts +101 -0
  22. package/dist/schemas/task.d.ts +12 -0
  23. package/dist/session/agent-session.d.ts +179 -0
  24. package/dist/session/events.d.ts +143 -0
  25. package/dist/session/hub.d.ts +44 -0
  26. package/dist/session/state.d.ts +57 -0
  27. package/dist/shared/projection/builder.d.ts +59 -0
  28. package/dist/shared/projection/helpers.d.ts +34 -0
  29. package/dist/shared/projection/history.d.ts +12 -0
  30. package/dist/shared/projection/index.d.ts +3 -0
  31. package/dist/shared/projection/state.d.ts +22 -0
  32. package/dist/socket.d.ts +9 -0
  33. package/dist/types/index.d.ts +8 -0
  34. package/dist/types/rest.d.ts +17315 -0
  35. package/dist/types/sdk-profile.d.ts +47 -0
  36. package/dist/types/socket-events.d.ts +401 -0
  37. package/dist/version.d.ts +45 -0
  38. package/package.json +29 -0
  39. package/public-api.md +1103 -0
@@ -0,0 +1,126 @@
1
+ import type { Solution } from "./solution";
2
+ export declare const SessionStatus: import("arktype/internal/variants/string.ts").StringType<"completed" | "created" | "failed" | "interrupted" | "running" | "waiting_for_input", {}>;
3
+ export type SessionStatus = typeof SessionStatus.infer;
4
+ export type TemplateId = "default" | "skill_editor" | "ship_attack";
5
+ export type SkillEditorTemplateId = "skill_editor";
6
+ export type ModeId = "planning" | "executing";
7
+ export interface ReplayState {
8
+ source_session_id?: string;
9
+ status?: "replay" | "autonomous";
10
+ speed?: 1 | 2 | 5;
11
+ next_source_entry_id?: string | null;
12
+ ended_at?: string | null;
13
+ autonomous_reason?: string | null;
14
+ }
15
+ export interface SessionPortMapping {
16
+ container_port: number;
17
+ host_port: number;
18
+ }
19
+ /**
20
+ * 列表搜索时单条会话的命中信息。
21
+ * - field='title':关键词出现在 intent 里,snippet 为 null(标题本身就在 UI 上)
22
+ * - field='content':关键词出现在历史消息里,snippet 含截窗预览与角色
23
+ */
24
+ export interface SessionSearchMatch {
25
+ field: "title" | "content";
26
+ snippet: {
27
+ role: string;
28
+ text: string;
29
+ } | null;
30
+ }
31
+ export declare const SessionInfo: import("arktype/internal/variants/object.ts").ObjectType<{
32
+ id: string;
33
+ intent: string;
34
+ status: "completed" | "created" | "failed" | "interrupted" | "running" | "waiting_for_input";
35
+ created_at: string;
36
+ updated_at: string;
37
+ shared?: boolean | undefined;
38
+ memory_enabled?: boolean | undefined;
39
+ is_persistent?: boolean | undefined;
40
+ is_headless?: boolean | undefined;
41
+ viewer_role?: "owner" | "viewer" | undefined;
42
+ template_id?: string | null | undefined;
43
+ model?: string | null | undefined;
44
+ enable_thinking?: boolean | null | undefined;
45
+ solution_id?: string | null | undefined;
46
+ biz_role_id?: string | null | undefined;
47
+ solution?: unknown;
48
+ plan_summary?: string | null | undefined;
49
+ primary_skill_id?: string | null | undefined;
50
+ bound_skill_id?: string | null | undefined;
51
+ replay_state?: unknown;
52
+ is_pinned?: boolean | undefined;
53
+ pinned_at?: string | null | undefined;
54
+ is_example?: boolean | undefined;
55
+ ports?: unknown;
56
+ disable_tools?: string[] | undefined;
57
+ runtime_type?: string | null | undefined;
58
+ daemon_id?: string | null | undefined;
59
+ match?: unknown;
60
+ }, {}>;
61
+ export type SessionInfo = Omit<typeof SessionInfo.infer, "template_id" | "solution" | "ports" | "match"> & {
62
+ shared?: boolean;
63
+ memory_enabled?: boolean;
64
+ is_persistent?: boolean;
65
+ is_headless?: boolean;
66
+ viewer_role?: "owner" | "viewer";
67
+ template_id?: TemplateId | null;
68
+ model?: string | null;
69
+ enable_thinking?: boolean | null;
70
+ solution_id?: string | null;
71
+ biz_role_id?: string | null;
72
+ solution?: Solution | null;
73
+ primary_skill_id?: string | null;
74
+ bound_skill_id?: string | null;
75
+ replay_state?: ReplayState | null;
76
+ is_pinned?: boolean;
77
+ pinned_at?: string | null;
78
+ is_example?: boolean;
79
+ ports?: SessionPortMapping[];
80
+ disable_tools?: string[];
81
+ runtime_type?: "sandbox" | "daemon" | string | null;
82
+ daemon_id?: string | null;
83
+ /** 仅在带 q 搜索的列表响应中出现;普通列表里此字段缺省。 */
84
+ match?: SessionSearchMatch | null;
85
+ };
86
+ /**
87
+ * 主 skill 配置快照(v2)。创建 session 时从 SKILL.md frontmatter 抽出并
88
+ * 固化到 session_root/.blade/primary-skill.json;ship-attack 页面骨架的唯
89
+ * 一数据源。
90
+ */
91
+ export interface PrimarySkillStepSpec {
92
+ n: number;
93
+ label: string;
94
+ }
95
+ export interface PrimarySkillStageSpec {
96
+ id: string;
97
+ name: string;
98
+ steps: PrimarySkillStepSpec[];
99
+ }
100
+ export interface PrimarySkillParallelMode {
101
+ id: string;
102
+ name: string;
103
+ prompt_hint: string;
104
+ }
105
+ export interface PrimarySkillSnapshot {
106
+ version: number;
107
+ skill_id: string;
108
+ title: string;
109
+ description: string;
110
+ stages: PrimarySkillStageSpec[];
111
+ parallel_modes: PrimarySkillParallelMode[];
112
+ captured_at: string;
113
+ }
114
+ /**
115
+ * 单 session detail(GET /api/sessions/:id)。列表接口返回 SessionInfo,
116
+ * detail 在此基础上附加 primary_skill_snapshot。
117
+ */
118
+ export interface SessionDetail extends SessionInfo {
119
+ primary_skill_snapshot?: PrimarySkillSnapshot | null;
120
+ preview_url?: string | null;
121
+ /**
122
+ * 会话级环境变量(owner-only)。后端仅在 GET detail 和 PUT /env 响应中返回,
123
+ * 列表/搜索响应不带此字段。调用 setSessionEnv 后可类型安全地读回。
124
+ */
125
+ env?: Record<string, string>;
126
+ }
@@ -0,0 +1,101 @@
1
+ export declare enum LayoutType {
2
+ Default = "default",
3
+ SkillEditor = "skill-editor",
4
+ BladeCoa = "blade-coa",
5
+ SolutionEditor = "solution-editor",
6
+ SolutionEditor2 = "solution-editor2",
7
+ ChatPreview = "chat-preview",
8
+ ChatOnly = "chat-only",
9
+ SolutionApp = "solution-app",
10
+ Custom = "custom"
11
+ }
12
+ export interface Solution {
13
+ id: string;
14
+ name: string;
15
+ version: string;
16
+ description?: string | null;
17
+ source?: "builtin" | "personal" | string | null;
18
+ layout_type: LayoutType | string;
19
+ initial_mode?: "planning" | "executing" | string | null;
20
+ initial_message?: string | null;
21
+ preview?: {
22
+ url: string;
23
+ title?: string | null;
24
+ } | null;
25
+ layout?: {
26
+ available?: boolean;
27
+ source_dir?: string;
28
+ entry?: string;
29
+ export?: string;
30
+ } | null;
31
+ roles?: BizRole[] | null;
32
+ data?: Record<string, unknown> | null;
33
+ ui_config?: SolutionAppUiConfig | null;
34
+ }
35
+ export interface SolutionAppUiConfig {
36
+ branding: {
37
+ name: string;
38
+ subtitle?: string;
39
+ icon_text: string;
40
+ icon_gradient?: string;
41
+ };
42
+ list: {
43
+ title: string;
44
+ create_button: string;
45
+ card?: {
46
+ subtitle?: string;
47
+ stats?: Array<{
48
+ label: string;
49
+ value: string;
50
+ color?: string;
51
+ }>;
52
+ };
53
+ };
54
+ create: {
55
+ title: string;
56
+ description?: string;
57
+ submit_button: string;
58
+ sections: Array<{
59
+ id: string;
60
+ title: string;
61
+ description?: string;
62
+ fields: Array<SolutionAppField>;
63
+ }>;
64
+ };
65
+ }
66
+ export type SolutionAppField = {
67
+ id: string;
68
+ kind: "textarea";
69
+ label: string;
70
+ placeholder?: string;
71
+ } | {
72
+ id: string;
73
+ kind: "file-upload";
74
+ accept?: string[];
75
+ categories?: Array<{
76
+ label: string;
77
+ description: string;
78
+ color: string;
79
+ }>;
80
+ };
81
+ export interface SolutionAppState {
82
+ pipeline: Array<{
83
+ id: string;
84
+ label: string;
85
+ status: "done" | "active" | "pending" | "error";
86
+ }>;
87
+ meta: Record<string, {
88
+ label: string;
89
+ value: string;
90
+ color?: string;
91
+ }>;
92
+ }
93
+ export interface BizRole {
94
+ id: string;
95
+ name: string;
96
+ description?: string | null;
97
+ preview?: {
98
+ url: string;
99
+ title?: string | null;
100
+ } | null;
101
+ }
@@ -0,0 +1,12 @@
1
+ export declare const TaskStatus: import("arktype/internal/variants/string.ts").StringType<"done" | "failed" | "in_progress" | "pending" | "skipped", {}>;
2
+ export type TaskStatus = typeof TaskStatus.infer;
3
+ export declare const Task: import("arktype/internal/variants/object.ts").ObjectType<{
4
+ id: string;
5
+ goal: string;
6
+ skills: string[];
7
+ depends_on: string[];
8
+ status: "done" | "failed" | "in_progress" | "pending" | "skipped";
9
+ result_summary: string;
10
+ number: string;
11
+ }, {}>;
12
+ export type Task = typeof Task.infer;
@@ -0,0 +1,179 @@
1
+ import { type RawEvent } from "../shared/projection";
2
+ import type { MessageContent } from "../schemas/message";
3
+ import type { PatchEnvelope, TurnProjection } from "../schemas/projection";
4
+ import type { SessionStatus } from "../schemas/session";
5
+ import { type CommandHandler } from "../commands/registry";
6
+ import { type AgentSessionEvents } from "./events";
7
+ import { type ConnectionStatus, type SessionState } from "./state";
8
+ /** SessionHub 注入给 AgentSession 的运行时依赖(socket 收发 + REST 补数)。 */
9
+ export interface SessionRuntime {
10
+ emitEvent(event: string, data: unknown): void;
11
+ emitWithAck(event: string, data: unknown, timeoutMs: number): Promise<Record<string, unknown> | undefined>;
12
+ ensureConnected(): void;
13
+ fetchTurns(sessionId: string): Promise<TurnProjection[]>;
14
+ onDispose(session: AgentSession): void;
15
+ }
16
+ export interface SendOptions {
17
+ /** planning / executing 模式。 */
18
+ mode?: string;
19
+ /** AskUserQuestion 的作答(tool_call_id + 选项)。 */
20
+ askUserAnswer?: Record<string, unknown>;
21
+ /** 本次运行的模型覆盖。 */
22
+ model?: string;
23
+ /** 本次运行是否强制开/关思考。 */
24
+ thinkingOverride?: boolean;
25
+ whatif?: {
26
+ from_step: number;
27
+ quotes: Array<Record<string, unknown>>;
28
+ deprecate_entry_ids: string[];
29
+ };
30
+ replayDecision?: "keep_replay" | "continue_replay";
31
+ }
32
+ export declare function sessionStatusFromChatEnd(status: string | undefined): SessionStatus;
33
+ /**
34
+ * 一个会话的实时状态机:封装 Socket.IO 订阅、历史 + 流式合流、断线补数,
35
+ * 对外只有三样东西——状态快照(getState/subscribe)、动作(send/stop/…)、
36
+ * 语义事件(on/onCommand)。
37
+ *
38
+ * 状态完全归属实例:同一页面创建多个 AgentSession 互不干扰。
39
+ */
40
+ export declare class AgentSession {
41
+ readonly sessionId: string;
42
+ private state;
43
+ private readonly listeners;
44
+ private readonly emitter;
45
+ private readonly commands;
46
+ private readonly runtime;
47
+ private readonly projectionBuilder;
48
+ private readonly pendingTurnPatches;
49
+ private patchFlushHandle;
50
+ private patchFlushCancel;
51
+ private joined;
52
+ private joinPending;
53
+ private pendingReplayMessage;
54
+ private pendingReplayMode;
55
+ private recentChatEndAt;
56
+ private disposed;
57
+ private readonly deliveredCommandKeys;
58
+ private readonly deliveredToolPreviews;
59
+ private readonly oomNotifiedKeys;
60
+ private readonly seenToolCallIds;
61
+ private readonly finishedToolCallIds;
62
+ private readonly emittedMessageTurnIds;
63
+ constructor(sessionId: string, runtime: SessionRuntime, connection: ConnectionStatus);
64
+ /** 从一份静态 turn 快照构造只展示历史的会话(例如公开分享页)。 */
65
+ static fromTurns(sessionId: string, turns: TurnProjection[]): AgentSession;
66
+ /** 返回当前会话快照。引用稳定:状态未变化时返回同一对象。 */
67
+ getState(): SessionState;
68
+ /** 订阅状态变化。返回取消订阅函数。 */
69
+ subscribe(listener: () => void): () => void;
70
+ private setState;
71
+ private update;
72
+ /** 监听语义事件(底层逃生舱,见 events.ts)。返回取消函数。 */
73
+ on<K extends keyof AgentSessionEvents>(name: K, handler: (event: AgentSessionEvents[K]) => void): () => void;
74
+ off<K extends keyof AgentSessionEvents>(name: K, handler: (event: AgentSessionEvents[K]) => void): void;
75
+ /**
76
+ * 监听智能体下发给宿主页面的指令。
77
+ *
78
+ * action 是技能作者在工具返回值 `_meta.bridge` 里写的契约字符串(如
79
+ * "map.highlight"),由你和技能作者约定;注册前到达的指令会被缓冲补投。
80
+ */
81
+ onCommand(action: string, handler: CommandHandler): () => void;
82
+ /** 发送一条消息。字符串或多模态内容均可。 */
83
+ send(content: MessageContent, options?: SendOptions): Promise<void>;
84
+ /** 智能体运行期间追加补充说明(不打断当前回复)。 */
85
+ append(text: string): void;
86
+ /** 停止当前回复。 */
87
+ stop(): Promise<Record<string, unknown>>;
88
+ /** 手动触发上下文压缩。 */
89
+ compact(): Promise<Record<string, unknown>>;
90
+ /**
91
+ * 把一段业务数据作为附件放进聊天输入框(比如地图上选中的点位)。
92
+ * 附件随下一条消息一起发给智能体。需要 ChatView / useChat 渲染层配合展示;
93
+ * 无 UI 场景可直接用 send()。
94
+ */
95
+ attach(label: string, data: unknown): void;
96
+ /** 往聊天输入框追加一段文字(不发送)。 */
97
+ insertText(text: string): void;
98
+ /** 释放订阅与监听器。之后该实例不再接收任何事件。 */
99
+ dispose(): void;
100
+ get isDisposed(): boolean;
101
+ /** @internal 连接状态变化(同 client 下所有会话共享一条连接)。 */
102
+ _setConnection(connection: ConnectionStatus): void;
103
+ /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */
104
+ _rejoinAfterReconnect(): Promise<void>;
105
+ /** @internal 首次连接:加载历史 + 加入房间。 */
106
+ _bootstrap(): Promise<void>;
107
+ /** @internal */
108
+ _handleTurnStart(turn: TurnProjection): void;
109
+ /** @internal */
110
+ _handleTurnPatch(patch: PatchEnvelope): void;
111
+ /** @internal */
112
+ _handleTurnEnd(turn: TurnProjection): void;
113
+ /** @internal 历史回放通道(event_format: raw)。 */
114
+ _handleTurnEvents(events: RawEvent[]): void;
115
+ /** @internal */
116
+ _handleChatStart(): void;
117
+ /** @internal */
118
+ _handleChatEnd(status: string): void;
119
+ /** @internal */
120
+ _handleSystemError(message: string): void;
121
+ /** @internal */
122
+ _handleTaskUpdated(tasks: unknown[]): void;
123
+ /** @internal */
124
+ _handleWorkspaceFilesChanged(filePath?: string): void;
125
+ /** @internal */
126
+ _handleSessionUpdated(data: {
127
+ intent?: string;
128
+ status?: SessionStatus;
129
+ model?: string | null;
130
+ bound_skill_id?: string | null;
131
+ replay_state?: Record<string, unknown> | null;
132
+ }): void;
133
+ /** @internal */
134
+ _handleRewind(checkpointId: string): void;
135
+ /** @internal */
136
+ _handleReplayMismatch(data: {
137
+ actual_message?: string;
138
+ expected_message?: string;
139
+ }): void;
140
+ /** @internal */
141
+ _handleSystemNotification(loopId: string, notification: Record<string, unknown>): void;
142
+ /** @internal */
143
+ _handleBackgroundTask(task: {
144
+ id: string;
145
+ command: string;
146
+ description?: string;
147
+ status: "running" | "done" | "failed";
148
+ exitCode?: number | null;
149
+ elapsedSeconds: number;
150
+ output?: string;
151
+ }): void;
152
+ /** @internal */
153
+ _handleArtifact(event: AgentSessionEvents["artifact"]): void;
154
+ /** @internal 加入房间的应答里带 is_running,据此校准流式状态。 */
155
+ _applyRunningState(isRunning: boolean): void;
156
+ private markRunningIfIdle;
157
+ private finishStreaming;
158
+ private applyTurn;
159
+ private schedulePatchFlush;
160
+ private cancelPatchFlush;
161
+ private flushPatches;
162
+ /** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */
163
+ private emitTurnDerivedEvents;
164
+ private dispatchCommand;
165
+ private notifySandboxOom;
166
+ private syncTurnsFromHistory;
167
+ /**
168
+ * 把历史里的指令补投给宿主页面。
169
+ *
170
+ * 重开会话、断线补数时,地图高亮这类"页面当前状态"必须能恢复——
171
+ * 否则刷新一次页面,之前智能体让页面做的事就全丢了。
172
+ * 只回放指令:toolCall / message 这些事件如果按历史全量重放,
173
+ * 监听器会在挂载瞬间收到几百条陈年事件。
174
+ * dispatch 内部按 deliveredCommandKeys 去重,重复调用安全。
175
+ */
176
+ private replayCommandsFromTurns;
177
+ private ensureJoined;
178
+ private ensureIdleBeforeSend;
179
+ }
@@ -0,0 +1,143 @@
1
+ import type { ChatMessage, ToolCallInfo } from "../schemas/message";
2
+ import type { TurnProjection } from "../schemas/projection";
3
+ import type { SessionStatus } from "../schemas/session";
4
+ /**
5
+ * AgentSession 的语义事件表。
6
+ *
7
+ * 这是"底层逃生舱"(L1):React 使用者优先用 useChat() 的响应式状态(L2)
8
+ * 或 <ChatView onToolCall/commands> 的声明式入口(L3),一般不需要直接监听。
9
+ * Vue / 无框架集成者用 session.on(...) 精确订阅。
10
+ */
11
+ export interface AgentSessionEvents {
12
+ /** 一条消息物化完成(turn 离开 streaming 状态)。 */
13
+ message: {
14
+ message: ChatMessage;
15
+ turn: TurnProjection;
16
+ };
17
+ /** 智能体发起了一次工具调用(首次出现)。 */
18
+ toolCall: {
19
+ toolCall: ToolCallInfo;
20
+ turn: TurnProjection;
21
+ };
22
+ /** 一次工具调用出结果(done / error / cancelled)。 */
23
+ toolResult: {
24
+ toolCall: ToolCallInfo;
25
+ turn: TurnProjection;
26
+ };
27
+ /** 一轮回复结束。status: completed / paused / interrupted / failed。 */
28
+ chatEnd: {
29
+ status: string;
30
+ };
31
+ /** 运行错误(system:error、发送失败等)。 */
32
+ error: {
33
+ message: string;
34
+ };
35
+ /** planning / executing 模式切换。 */
36
+ modeChange: {
37
+ mode: "planning" | "executing";
38
+ };
39
+ /**
40
+ * 智能体给宿主页面下发指令。
41
+ *
42
+ * action 的来源:技能作者在工具实现的返回值 JSON 里写 `_meta.bridge:
43
+ * { action, payload }`,后端剥离后经事件流送达前端。action 是技能作者与
44
+ * 宿主页面开发者约定的业务契约字符串(如 "map.highlight"),LLM 不参与、
45
+ * SDK 不做枚举。一般用 session.onCommand(action, fn) 消费,而不是监听本事件。
46
+ */
47
+ command: {
48
+ action: string;
49
+ payload: unknown;
50
+ toolCallId?: string;
51
+ };
52
+ /** 系统通知(技能阶段提示、后台任务启动等)。 */
53
+ notification: {
54
+ type: string;
55
+ title: string;
56
+ detail?: string;
57
+ status: "info" | "running" | "done" | "error";
58
+ loopId?: string;
59
+ metadata?: Record<string, unknown>;
60
+ };
61
+ /** 工作区文件发生变化(写文件、重命名等)。 */
62
+ workspaceChanged: {
63
+ filePath?: string;
64
+ };
65
+ /** 智能体产出了文件成果(artifact:created / artifact:updated)。 */
66
+ artifact: {
67
+ filePath: string;
68
+ contentType: string;
69
+ title: string;
70
+ content: string;
71
+ oldString?: string;
72
+ newString?: string;
73
+ kind: "created" | "updated";
74
+ };
75
+ /** 工具返回值带 _meta.ui 的可视化预览(resource HTML / URI)。 */
76
+ toolPreview: {
77
+ toolCallId: string;
78
+ type: "resource-html" | "resource-uri";
79
+ content: string;
80
+ title: string;
81
+ };
82
+ /** 任务清单(TaskCreate 等)更新。 */
83
+ taskListUpdated: {
84
+ tasks: unknown[];
85
+ };
86
+ /** 沙盒后台命令状态更新。 */
87
+ backgroundTask: {
88
+ id: string;
89
+ command: string;
90
+ description?: string;
91
+ status: "running" | "done" | "failed";
92
+ exitCode?: number | null;
93
+ elapsedSeconds: number;
94
+ output?: string;
95
+ };
96
+ /** 会话被回溯到某个检查点。 */
97
+ rewind: {
98
+ checkpointId: string;
99
+ };
100
+ /** 会话属性(名称、状态、绑定技能等)被服务端更新。 */
101
+ sessionUpdated: {
102
+ intent?: string;
103
+ status?: SessionStatus;
104
+ model?: string | null;
105
+ boundSkillId?: string | null;
106
+ replayState?: Record<string, unknown> | null;
107
+ };
108
+ /** 回放输入不匹配,需要决定保持回放还是转自主模式。 */
109
+ replayMismatch: {
110
+ actualMessage?: string;
111
+ expectedMessage?: string;
112
+ respond: (decision: "keep_replay" | "continue_replay") => void;
113
+ };
114
+ /** 沙盒内存超限自动重启。 */
115
+ sandboxOom: {
116
+ toolCallId: string;
117
+ };
118
+ /** session.attach() 被调用,渲染层(ChatView/useChat)应把它显示为输入框附件。 */
119
+ attachRequested: {
120
+ label: string;
121
+ content: string;
122
+ };
123
+ /** session.insertText() 被调用,渲染层应把文字追加到输入框。 */
124
+ insertTextRequested: {
125
+ text: string;
126
+ };
127
+ }
128
+ export type AgentSessionEventName = keyof AgentSessionEvents;
129
+ type Handler<E> = (event: E) => void;
130
+ export declare class Emitter<Events> {
131
+ private handlers;
132
+ on<K extends keyof Events>(name: K, handler: Handler<Events[K]>): () => void;
133
+ off<K extends keyof Events>(name: K, handler: Handler<Events[K]>): void;
134
+ emit<K extends keyof Events>(name: K, event: Events[K]): void;
135
+ /**
136
+ * 只把事件交给最先注册的处理器。用于必须由单一交互入口作答的事件,
137
+ * 避免多个 UI 同时弹窗并提交相互冲突的决定。
138
+ */
139
+ emitFirst<K extends keyof Events>(name: K, event: Events[K]): boolean;
140
+ listenerCount(name: keyof Events): number;
141
+ clear(): void;
142
+ }
143
+ export {};
@@ -0,0 +1,44 @@
1
+ import type { BladeClient } from "../blade-client";
2
+ import { AgentSession } from "./agent-session";
3
+ import type { ConnectionStatus } from "./state";
4
+ /**
5
+ * 每个 BladeClient 一个:管理一条 Socket.IO 连接,按 session_id 把事件
6
+ * 路由给各 AgentSession 实例。多会话共享连接、状态互不干扰。
7
+ */
8
+ export declare class SessionHub {
9
+ private readonly client;
10
+ private readonly sessions;
11
+ private readonly bootstrapPending;
12
+ private connection;
13
+ private readonly connectionListeners;
14
+ private bound;
15
+ private hasConnected;
16
+ constructor(client: BladeClient);
17
+ /** 当前 Socket.IO 连接状态。 */
18
+ getConnection(): ConnectionStatus;
19
+ /** 订阅连接状态变化。 */
20
+ onConnectionChange(listener: (status: ConnectionStatus) => void): () => void;
21
+ /** 取得(或复用)一个会话的 AgentSession,并完成历史加载 + 房间订阅。 */
22
+ connect(sessionId: string): Promise<AgentSession>;
23
+ /** 已有实例则返回,不触发网络请求。 */
24
+ peek(sessionId: string): AgentSession | undefined;
25
+ /** 手动重连(例如登录态变化后)。 */
26
+ reconnect(): void;
27
+ /** 断开连接(不清理 session 实例)。 */
28
+ disconnect(): void;
29
+ /** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */
30
+ disposeAll(): void;
31
+ /**
32
+ * @internal 底层 socket 被换掉时由 BladeClient 调用(如 setBaseUrl)。
33
+ * 事件监听器绑在旧 socket 实例上,换新实例后必须重绑,否则所有
34
+ * turn:* / chat:* 事件都会静默丢弃。
35
+ */
36
+ _handleSocketReplaced(): void;
37
+ private runtimeFor;
38
+ private ensureConnected;
39
+ private setConnection;
40
+ /** 事件带 session_id 时精确路由;缺省时按当前唯一活跃会话兜底。 */
41
+ private route;
42
+ private ensureBound;
43
+ private routeArtifact;
44
+ }
@@ -0,0 +1,57 @@
1
+ import type { ChatMessage, CompactionInfo, MessageContent } from "../schemas/message";
2
+ import type { ContentBlock, PatchEnvelope, TurnProjection } from "../schemas/projection";
3
+ import type { SessionStatus } from "../schemas/session";
4
+ /** 一次 AskUserQuestion 的用户作答(选项选择 + 自定义输入)。 */
5
+ export interface AskUserAnswerData {
6
+ selections: Record<number, number[]>;
7
+ custom: Record<number, string>;
8
+ }
9
+ export interface AgentLoopInfo {
10
+ toolCallId: string;
11
+ description: string;
12
+ status: "running" | "done" | "error" | "cancelled" | "awaiting_answer";
13
+ }
14
+ export interface ActiveCompactionState extends CompactionInfo {
15
+ turn_id: string;
16
+ status: "streaming" | "completed" | "paused" | "failed" | "interrupted";
17
+ }
18
+ export type ConnectionStatus = "connecting" | "connected" | "reconnecting" | "disconnected";
19
+ /**
20
+ * 一个会话的完整快照。引用不可变:任何变更都会产生新对象,
21
+ * 满足 React `useSyncExternalStore` / Vue `shallowRef` 的订阅契约。
22
+ */
23
+ export interface SessionState {
24
+ sessionId: string;
25
+ /** 服务端投影的原始 turn 列表(按 sequence 有序)。 */
26
+ turns: TurnProjection[];
27
+ /** 由 turns 物化出的聊天消息列表,UI 直接渲染。 */
28
+ messages: ChatMessage[];
29
+ /** 智能体是否正在流式回复。 */
30
+ isStreaming: boolean;
31
+ /** 会话状态(running / completed / failed / waiting_for_input / interrupted …)。 */
32
+ status: SessionStatus | null;
33
+ /** 当前模式(planning / executing),来自 mode_change 事件。 */
34
+ mode: "planning" | "executing" | null;
35
+ /** Socket.IO 连接状态(同一 client 下所有会话共享)。 */
36
+ connection: ConnectionStatus;
37
+ /** 最近一次运行错误消息(system:error 等)。 */
38
+ errorMessage: string | null;
39
+ askAnswers: Record<string, AskUserAnswerData>;
40
+ agentLoops: Record<string, AgentLoopInfo>;
41
+ activeCompaction: ActiveCompactionState | null;
42
+ }
43
+ export declare function createInitialSessionState(sessionId: string): SessionState;
44
+ export declare function extractModeFromBlocks(blocks: ContentBlock[]): "planning" | "executing" | null;
45
+ /**
46
+ * 用一份新的 turn 列表重建会话状态。
47
+ * addErrorMessage 注入的 role==="error" 消息不在 turns 里,默认会被物化过程抹掉;
48
+ * 这里沿用锚点策略:只保留锚定在"当前最后一个 turn"上的错误气泡,
49
+ * turn 推进(新消息 / rewind / 重连)时旧错误自动消失。
50
+ */
51
+ export declare function withTurns(state: SessionState, turns: TurnProjection[]): SessionState;
52
+ export declare function addUserMessage(state: SessionState, content: MessageContent): SessionState;
53
+ export declare function upsertTurn(state: SessionState, turn: TurnProjection): SessionState;
54
+ export declare function applyTurnPatch(state: SessionState, patch: PatchEnvelope): SessionState;
55
+ export declare function addErrorMessage(state: SessionState, content: string): SessionState;
56
+ export declare function markInterrupted(state: SessionState): SessionState;
57
+ export declare function markFailed(state: SessionState): SessionState;