@blade-hq/agent-client 2610.0.0-beta.0 → 2610.0.0-beta.10
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.
- package/README.md +17 -3
- package/dist/blade-client.d.ts +2 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +153 -21
- package/dist/index.js.map +1 -1
- package/dist/resources/sessions.d.ts +40 -0
- package/dist/schemas/message.d.ts +2 -0
- package/dist/schemas/projection-utils.d.ts +3 -0
- package/dist/schemas/projection.d.ts +16 -0
- package/dist/session/agent-session.d.ts +2 -0
- package/dist/session/state.d.ts +1 -0
- package/dist/shared/projection/builder.d.ts +5 -0
- package/dist/shared/projection/helpers.d.ts +2 -0
- package/dist/shared/projection/index.d.ts +1 -1
- package/dist/types/socket-events.d.ts +6 -0
- package/package.json +4 -2
- package/public-api.md +106 -1
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ new BladeClient({
|
|
|
56
56
|
baseUrl: "https://blade.example.com", // 后端地址;同域部署可传 ""
|
|
57
57
|
token: "sk-blade-xxx", // 可选:PAT。不传则用 cookie 或 login()
|
|
58
58
|
tokenStorage: "local", // 可选:login() 的令牌存哪("local" 默认 / "memory")
|
|
59
|
+
streamTokens: false, // 可选:只接收完成态内容,不订阅逐 token 增量
|
|
59
60
|
})
|
|
60
61
|
```
|
|
61
62
|
|
|
@@ -133,6 +134,7 @@ Solution 和 Skill 都声明为 `{ path, content }[]` 文本文件;SDK 负责
|
|
|
133
134
|
|
|
134
135
|
```ts
|
|
135
136
|
await client.sessions.listSessions() // 会话列表
|
|
137
|
+
await client.sessions.searchOwnedContent({ q: "项目报告" }) // 搜索自己的对话和文件名
|
|
136
138
|
await client.sessions.getSession(id) // 会话详情
|
|
137
139
|
await client.sessions.updateSession(id, { intent: "新标题" })
|
|
138
140
|
await client.sessions.deleteSession(id)
|
|
@@ -224,6 +226,18 @@ await chat.countFiles() // 递归统计,不含目录
|
|
|
224
226
|
await chat.downloadFile("输出/简历.md", "简历.md") // 浏览器下载
|
|
225
227
|
```
|
|
226
228
|
|
|
229
|
+
对符合评价条件的最新整体结果,可读取或更新当前用户的反馈:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
const feedback = await client.sessions.listResultFeedback(id)
|
|
233
|
+
await client.sessions.putResultFeedback(id, assistantEntryId, {
|
|
234
|
+
helpful: false,
|
|
235
|
+
reason: "incomplete",
|
|
236
|
+
})
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`ResultFeedbackReason` 是固定枚举;Server 会校验结果资格、写权限,并自行推导 Chat / 软件工厂场景和项目 ID。
|
|
240
|
+
|
|
227
241
|
### 模型目录
|
|
228
242
|
|
|
229
243
|
```ts
|
|
@@ -502,11 +516,11 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
502
516
|
- **SDK 身份**:`SDK_NAME`、`SDK_VERSION`
|
|
503
517
|
- **声明式会话**:`SessionDefinition`、`SolutionDefinition`、`SkillDefinition`、`SessionConfig`、`TextFile`、`SessionSetupError`、`SessionSetupStage`
|
|
504
518
|
- **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
|
|
505
|
-
- **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`SessionHistory`、`SessionContextStats`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
|
|
519
|
+
- **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`GlobalSearchResult`、`GlobalSearchResultItem`、`GlobalSearchConversationResult`、`GlobalSearchFileResult`、`SessionHistory`、`SessionContextStats`、`ResultFeedback`、`ResultFeedbackReason`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
|
|
506
520
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
507
521
|
- **会话状态机**:`SessionHub`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
508
522
|
- **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
|
|
509
|
-
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
523
|
+
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
510
524
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
|
511
525
|
- **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
|
|
512
|
-
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`
|
|
526
|
+
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`
|
package/dist/blade-client.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface BladeClientOptions {
|
|
|
23
23
|
tokenStorage?: TokenStorageMode;
|
|
24
24
|
fetchImpl?: typeof fetch;
|
|
25
25
|
onRefreshSuccess?: () => void | Promise<void>;
|
|
26
|
+
/** 是否订阅逐 token 增量,默认 true。关闭后仍接收完整消息和语义事件。 */
|
|
27
|
+
streamTokens?: boolean;
|
|
26
28
|
}
|
|
27
29
|
export declare class BladeClient {
|
|
28
30
|
private refreshPromise;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { SessionHub } from "./session/hub";
|
|
|
9
9
|
export type { AgentSessionEvents, AgentSessionEventName } from "./session/events";
|
|
10
10
|
export { SessionSetupError } from "./session/definition";
|
|
11
11
|
export type { SessionConfig, SessionDefinition, SessionSetupStage, SkillDefinition, TextFile, SolutionDefinition, } from "./session/definition";
|
|
12
|
-
export { createInitialSessionState, toReplaySnapshot } from "./session/state";
|
|
12
|
+
export { createInitialSessionState, reconcileOptimisticUserTurns, toReplaySnapshot, } from "./session/state";
|
|
13
13
|
export type { AskUserAnswerData, AgentLoopInfo, ActiveCompactionState, ConnectionStatus, ReplaySnapshot, SessionState, } from "./session/state";
|
|
14
14
|
export { connectEmbedded } from "./commands/embedded";
|
|
15
15
|
export type { EmbeddedChat, EmbeddedChatOptions } from "./commands/embedded";
|
|
@@ -21,11 +21,12 @@ export type { HeadlessResource } from "./resources/headless";
|
|
|
21
21
|
export { ModelsResource } from "./resources/models";
|
|
22
22
|
export type { ModelCatalog, ModelOption } from "./resources/models";
|
|
23
23
|
export type { SessionsResource } from "./resources/sessions";
|
|
24
|
-
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
24
|
+
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
25
25
|
export type { ArchivedFileInfo, ArchivedToolCallInfo, ChatMessage, CompactionInfo, FileContentPart, ImageUrlContentPart, MemoryRefInfo, MessageContent, MessageContentPart, TextContentPart, ToolBridgeContent, ToolCallInfo, } from "./schemas/message";
|
|
26
26
|
export { buildMessageContent, contentPreview, extractTextAttachments, getFileParts, getImageParts, getTextContent, groupMessagesByLoop, isHiddenInternalMessage, normalizeMessageContent, transformSlashCommand, } from "./schemas/message-utils";
|
|
27
27
|
export type { ParsedTextAttachment, ParsedTextContext, SkillMentionAvailability, } from "./schemas/message-utils";
|
|
28
|
-
export type { ContentBlock, MemoryRef, PatchEnvelope, TurnProjection } from "./schemas/projection";
|
|
28
|
+
export type { ContentBlock, FinalArtifact, MemoryRef, PatchEnvelope, PostChatFollowup, TurnProjection, } from "./schemas/projection";
|
|
29
|
+
export { latestPostChatFollowup } from "./schemas/projection-utils";
|
|
29
30
|
export { DEFAULT_REPLAY_SPEED } from "./schemas/session";
|
|
30
31
|
export { SessionInfo, SessionStatus } from "./schemas/session";
|
|
31
32
|
export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot, ReplayPreview, ReplaySpeed, ReplayState, SessionDetail, SessionPortMapping, PublishedSolutionRef, TemplateId, } from "./schemas/session";
|
|
@@ -33,7 +34,7 @@ export { LayoutType } from "./schemas/solution";
|
|
|
33
34
|
export type { BizRole, Solution, SolutionAppField, SolutionAppState, SolutionAppUiConfig, } from "./schemas/solution";
|
|
34
35
|
export { Task, TaskStatus } from "./schemas/task";
|
|
35
36
|
export type { BackgroundTask, BackgroundTaskStopResult } from "./schemas/background";
|
|
36
|
-
export { ClientProjectionBuilder } from "./shared/projection";
|
|
37
|
+
export { acceptedPostChatFollowupCompletesLatestRun, ClientProjectionBuilder } from "./shared/projection";
|
|
37
38
|
export type { RawEvent } from "./shared/projection";
|
|
38
39
|
export { createSocket } from "./socket";
|
|
39
40
|
export type { CreateSocketOptions, TypedSocket } from "./socket";
|
package/dist/index.js
CHANGED
|
@@ -350,7 +350,11 @@ var HeadlessResource = class {
|
|
|
350
350
|
socket.on("chat:start", onChatStart);
|
|
351
351
|
socket.on("chat:end", onChatEnd);
|
|
352
352
|
socket.on("system:error", onSystemError);
|
|
353
|
-
socket.emit("session:subscribe", {
|
|
353
|
+
socket.emit("session:subscribe", {
|
|
354
|
+
session_id,
|
|
355
|
+
event_format: "raw",
|
|
356
|
+
stream_tokens: this.client.options.streamTokens !== false
|
|
357
|
+
});
|
|
354
358
|
socket.emit(
|
|
355
359
|
"chat:send",
|
|
356
360
|
{
|
|
@@ -893,7 +897,7 @@ function sourceLoopFor(loopId, loopDescriptions) {
|
|
|
893
897
|
if (!description) return null;
|
|
894
898
|
return { loop_name: loopId, description };
|
|
895
899
|
}
|
|
896
|
-
var MAX_FINAL_ARTIFACTS =
|
|
900
|
+
var MAX_FINAL_ARTIFACTS = 20;
|
|
897
901
|
function normalizeFinalArtifacts(raw) {
|
|
898
902
|
if (!Array.isArray(raw)) return [];
|
|
899
903
|
const artifacts = [];
|
|
@@ -927,12 +931,16 @@ function normalizePostChatFollowup(data, assistantEntryId) {
|
|
|
927
931
|
}
|
|
928
932
|
const recaption = String(data.recaption ?? "");
|
|
929
933
|
const finalArtifacts = normalizeFinalArtifacts(data.final_artifacts);
|
|
930
|
-
|
|
934
|
+
const feedbackEligible = data.feedback_eligible === true;
|
|
935
|
+
if (suggestions.length === 0 && !recaption && finalArtifacts.length === 0 && !feedbackEligible)
|
|
936
|
+
return null;
|
|
931
937
|
return {
|
|
932
938
|
assistant_entry_id: assistantEntryId,
|
|
933
939
|
recaption,
|
|
934
940
|
suggestions: suggestions.slice(0, 3),
|
|
935
|
-
final_artifacts: finalArtifacts
|
|
941
|
+
final_artifacts: finalArtifacts,
|
|
942
|
+
feedback_eligible: feedbackEligible,
|
|
943
|
+
feedback_scope: "latest_result"
|
|
936
944
|
};
|
|
937
945
|
}
|
|
938
946
|
function normalizeChildPause(pausePayload) {
|
|
@@ -1016,11 +1024,60 @@ function toolStatusFromResult(result) {
|
|
|
1016
1024
|
}
|
|
1017
1025
|
|
|
1018
1026
|
// src/shared/projection/builder.ts
|
|
1027
|
+
function hasChatRunEvent(events) {
|
|
1028
|
+
return events.some(
|
|
1029
|
+
(event) => event.type !== "session:post_chat_followup" && !event.type.startsWith("compaction:")
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
function acceptedPostChatFollowupCompletesLatestRun(events, updates) {
|
|
1033
|
+
const acceptedAssistantEntryIds = new Set(
|
|
1034
|
+
updates.flatMap((update) => {
|
|
1035
|
+
if (update.kind !== "upsert") return [];
|
|
1036
|
+
const followup = update.turn.post_chat_followup;
|
|
1037
|
+
return followup?.assistant_entry_id ? [followup.assistant_entry_id] : [];
|
|
1038
|
+
})
|
|
1039
|
+
);
|
|
1040
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
1041
|
+
const event = events[index];
|
|
1042
|
+
if (event?.type !== "session:post_chat_followup") continue;
|
|
1043
|
+
const assistantEntryId = String(event.payload.assistant_entry_id ?? "");
|
|
1044
|
+
return acceptedAssistantEntryIds.has(assistantEntryId) && !hasChatRunEvent(events.slice(index + 1));
|
|
1045
|
+
}
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1019
1048
|
function isConversationTurn(turn) {
|
|
1020
1049
|
return (turn.role === "user" || turn.role === "assistant") && (turn.kind ?? "message") === "message" && !turn.blocks.some(
|
|
1021
1050
|
(block) => block.type === "mode_change" || block.type === "plan_status" || block.type === "ask_user_answer"
|
|
1022
1051
|
);
|
|
1023
1052
|
}
|
|
1053
|
+
function completedResponseText(content) {
|
|
1054
|
+
if (typeof content === "string") return content;
|
|
1055
|
+
if (!Array.isArray(content)) return content == null ? "" : String(content);
|
|
1056
|
+
return content.filter(
|
|
1057
|
+
(part) => typeof part === "object" && part !== null && !Array.isArray(part)
|
|
1058
|
+
).filter((part) => part.type === "text").map((part) => String(part.text ?? "")).join("");
|
|
1059
|
+
}
|
|
1060
|
+
function replaceTextContent(state, content) {
|
|
1061
|
+
if (state.blocks.some((block) => block.type === "text")) return;
|
|
1062
|
+
const replacement = { type: "text", content };
|
|
1063
|
+
const blocks = [];
|
|
1064
|
+
let inserted = false;
|
|
1065
|
+
for (const block of state.blocks) {
|
|
1066
|
+
if (block.type === "text") {
|
|
1067
|
+
if (content && !inserted) {
|
|
1068
|
+
blocks.push(replacement);
|
|
1069
|
+
inserted = true;
|
|
1070
|
+
}
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
blocks.push(block);
|
|
1074
|
+
}
|
|
1075
|
+
if (content && !inserted) {
|
|
1076
|
+
const toolIndex = blocks.findIndex((block) => block.type === "tool_use");
|
|
1077
|
+
blocks.splice(toolIndex < 0 ? blocks.length : toolIndex, 0, replacement);
|
|
1078
|
+
}
|
|
1079
|
+
state.blocks = blocks;
|
|
1080
|
+
}
|
|
1024
1081
|
var ClientProjectionBuilder = class {
|
|
1025
1082
|
activeTurns = /* @__PURE__ */ new Map();
|
|
1026
1083
|
lastTurnIds = /* @__PURE__ */ new Map();
|
|
@@ -1103,6 +1160,9 @@ var ClientProjectionBuilder = class {
|
|
|
1103
1160
|
return this.onDelta(state, "thinking", "", String(payload.content ?? ""));
|
|
1104
1161
|
case "llm:content:delta":
|
|
1105
1162
|
return this.onDelta(state, "text", "", String(payload.content ?? ""));
|
|
1163
|
+
case "llm:content:complete":
|
|
1164
|
+
replaceTextContent(state, String(payload.content ?? ""));
|
|
1165
|
+
return this.syncPatch(state);
|
|
1106
1166
|
case "llm:tool_call:created":
|
|
1107
1167
|
return this.onToolCallCreated(state, payload);
|
|
1108
1168
|
case "llm:response:done":
|
|
@@ -1392,6 +1452,9 @@ var ClientProjectionBuilder = class {
|
|
|
1392
1452
|
if (typeof payload.usage === "object" && payload.usage !== null) {
|
|
1393
1453
|
state.usage = { ...payload.usage };
|
|
1394
1454
|
}
|
|
1455
|
+
if ("content" in payload) {
|
|
1456
|
+
replaceTextContent(state, completedResponseText(payload.content));
|
|
1457
|
+
}
|
|
1395
1458
|
const toolCalls = payload.tool_calls;
|
|
1396
1459
|
if (Array.isArray(toolCalls)) {
|
|
1397
1460
|
for (const raw of toolCalls) {
|
|
@@ -2195,6 +2258,11 @@ var SessionsResource = class {
|
|
|
2195
2258
|
listSessionsWithSkillData() {
|
|
2196
2259
|
return this.client.json("GET", "/api/sessions/with-skill-data");
|
|
2197
2260
|
}
|
|
2261
|
+
searchOwnedContent(params) {
|
|
2262
|
+
const searchParams = new URLSearchParams({ q: params.q.trim() });
|
|
2263
|
+
if (params.limit !== void 0) searchParams.set("limit", String(params.limit));
|
|
2264
|
+
return this.client.json("GET", `/api/search?${searchParams.toString()}`);
|
|
2265
|
+
}
|
|
2198
2266
|
createSession(intent, template_id, primary_skill_id) {
|
|
2199
2267
|
return this.createSessionWithRequest({ intent, template_id, primary_skill_id });
|
|
2200
2268
|
}
|
|
@@ -2261,6 +2329,16 @@ var SessionsResource = class {
|
|
|
2261
2329
|
);
|
|
2262
2330
|
return projectHistory(entries);
|
|
2263
2331
|
}
|
|
2332
|
+
listResultFeedback(sessionId) {
|
|
2333
|
+
return this.client.json("GET", `/api/sessions/${encodeURIComponent(sessionId)}/feedback`);
|
|
2334
|
+
}
|
|
2335
|
+
putResultFeedback(sessionId, assistantEntryId, feedback) {
|
|
2336
|
+
return this.client.json(
|
|
2337
|
+
"PUT",
|
|
2338
|
+
`/api/sessions/${encodeURIComponent(sessionId)}/turns/${encodeURIComponent(assistantEntryId)}/feedback`,
|
|
2339
|
+
feedback
|
|
2340
|
+
);
|
|
2341
|
+
}
|
|
2264
2342
|
getSessionContextStats(sessionId, init) {
|
|
2265
2343
|
return this.client.jsonFromInit(`/api/sessions/${sessionId}/context-stats`, init);
|
|
2266
2344
|
}
|
|
@@ -3062,6 +3140,25 @@ function orderTurns(turns) {
|
|
|
3062
3140
|
}
|
|
3063
3141
|
return turns;
|
|
3064
3142
|
}
|
|
3143
|
+
function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
|
|
3144
|
+
const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]));
|
|
3145
|
+
const optimisticUserTurn = currentTurns.find(
|
|
3146
|
+
(turn) => turn.role === "user" && turn.turn_id.startsWith("local-user-")
|
|
3147
|
+
);
|
|
3148
|
+
let optimisticUserMatched = false;
|
|
3149
|
+
return incomingTurns.map((turn) => {
|
|
3150
|
+
const current = currentById.get(turn.turn_id);
|
|
3151
|
+
if (current) {
|
|
3152
|
+
const currentRenderId = current.client_render_id;
|
|
3153
|
+
return turn.client_render_id || !currentRenderId ? turn : { ...turn, client_render_id: currentRenderId };
|
|
3154
|
+
}
|
|
3155
|
+
if (!optimisticUserMatched && optimisticUserTurn && turn.role === "user" && !turn.turn_id.startsWith("local-user-")) {
|
|
3156
|
+
optimisticUserMatched = true;
|
|
3157
|
+
return { ...turn, client_render_id: optimisticUserTurn.turn_id };
|
|
3158
|
+
}
|
|
3159
|
+
return turn;
|
|
3160
|
+
});
|
|
3161
|
+
}
|
|
3065
3162
|
function areAgentLoopsEqual(left, right) {
|
|
3066
3163
|
if (!left) return Object.keys(right).length === 0;
|
|
3067
3164
|
const leftEntries = Object.entries(left);
|
|
@@ -3073,7 +3170,7 @@ function areAgentLoopsEqual(left, right) {
|
|
|
3073
3170
|
});
|
|
3074
3171
|
}
|
|
3075
3172
|
function withTurns(state, turns) {
|
|
3076
|
-
const orderedTurns = orderTurns(turns);
|
|
3173
|
+
const orderedTurns = orderTurns(reconcileOptimisticUserTurns(state.turns, turns));
|
|
3077
3174
|
const { messages, agentLoops, activeCompaction } = materialize(orderedTurns);
|
|
3078
3175
|
const isWaitingForInput = orderedTurns.some(
|
|
3079
3176
|
(turn) => turn.tool_calls.some((toolCall) => toolCall.status === "awaiting_answer")
|
|
@@ -3083,7 +3180,13 @@ function withTurns(state, turns) {
|
|
|
3083
3180
|
const preservedErrors = lastTurnId ? state.messages.filter(
|
|
3084
3181
|
(m) => m.role === "error" && typeof m.entry_id === "string" && m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`)
|
|
3085
3182
|
) : [];
|
|
3086
|
-
const
|
|
3183
|
+
const turnById = new Map(orderedTurns.map((turn) => [turn.turn_id, turn]));
|
|
3184
|
+
const messagesWithRenderIds = messages.map((message) => {
|
|
3185
|
+
if (!message.entry_id) return message;
|
|
3186
|
+
const renderId = turnById.get(message.entry_id)?.client_render_id;
|
|
3187
|
+
return renderId ? { ...message, render_id: renderId } : message;
|
|
3188
|
+
});
|
|
3189
|
+
const mergedMessages = preservedErrors.length > 0 ? [...messagesWithRenderIds, ...preservedErrors] : messagesWithRenderIds;
|
|
3087
3190
|
const latestMode = [...orderedTurns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
|
|
3088
3191
|
return {
|
|
3089
3192
|
...state,
|
|
@@ -3118,14 +3221,17 @@ function addUserMessage(state, content) {
|
|
|
3118
3221
|
}
|
|
3119
3222
|
function upsertTurn(state, turn) {
|
|
3120
3223
|
let existing = [...state.turns];
|
|
3121
|
-
|
|
3122
|
-
|
|
3224
|
+
const [nextTurn] = reconcileOptimisticUserTurns(existing, [turn]);
|
|
3225
|
+
if (nextTurn.client_render_id && turn.role === "user") {
|
|
3226
|
+
existing = existing.filter(
|
|
3227
|
+
(item) => !(item.role === "user" && item.turn_id.startsWith("local-user-"))
|
|
3228
|
+
);
|
|
3123
3229
|
}
|
|
3124
|
-
const index = existing.findIndex((item) => item.turn_id ===
|
|
3230
|
+
const index = existing.findIndex((item) => item.turn_id === nextTurn.turn_id);
|
|
3125
3231
|
if (index >= 0) {
|
|
3126
|
-
existing[index] =
|
|
3232
|
+
existing[index] = nextTurn;
|
|
3127
3233
|
} else {
|
|
3128
|
-
existing.push(
|
|
3234
|
+
existing.push(nextTurn);
|
|
3129
3235
|
}
|
|
3130
3236
|
return withTurns(state, existing);
|
|
3131
3237
|
}
|
|
@@ -3229,7 +3335,7 @@ function extractTerminalChatEndStatus(events) {
|
|
|
3229
3335
|
}
|
|
3230
3336
|
return null;
|
|
3231
3337
|
}
|
|
3232
|
-
function
|
|
3338
|
+
function hasChatRunEvent2(events) {
|
|
3233
3339
|
return events.some(
|
|
3234
3340
|
(event) => event.type !== "session:post_chat_followup" && !event.type.startsWith("compaction:")
|
|
3235
3341
|
);
|
|
@@ -3281,6 +3387,7 @@ var AgentSession = class _AgentSession {
|
|
|
3281
3387
|
const session = new _AgentSession(
|
|
3282
3388
|
sessionId,
|
|
3283
3389
|
{
|
|
3390
|
+
streamTokens: false,
|
|
3284
3391
|
emitEvent: readonlyError,
|
|
3285
3392
|
emitWithAck: async () => readonlyError(),
|
|
3286
3393
|
ensureConnected: readonlyError,
|
|
@@ -3654,7 +3761,7 @@ var AgentSession = class _AgentSession {
|
|
|
3654
3761
|
_handleTurnEvents(events) {
|
|
3655
3762
|
if (!events.length) return;
|
|
3656
3763
|
const terminalChatEndStatus = extractTerminalChatEndStatus(events);
|
|
3657
|
-
if (!terminalChatEndStatus &&
|
|
3764
|
+
if (!terminalChatEndStatus && hasChatRunEvent2(events)) {
|
|
3658
3765
|
this.markRunningIfIdle();
|
|
3659
3766
|
}
|
|
3660
3767
|
if (this.state.turns.length) {
|
|
@@ -3668,8 +3775,8 @@ var AgentSession = class _AgentSession {
|
|
|
3668
3775
|
this.emitter.emit("workspaceChanged", {});
|
|
3669
3776
|
}
|
|
3670
3777
|
}
|
|
3671
|
-
if (terminalChatEndStatus) {
|
|
3672
|
-
this.
|
|
3778
|
+
if (terminalChatEndStatus || acceptedPostChatFollowupCompletesLatestRun(events, updates)) {
|
|
3779
|
+
this.completeChat(terminalChatEndStatus ?? "completed");
|
|
3673
3780
|
}
|
|
3674
3781
|
}
|
|
3675
3782
|
/** @internal */
|
|
@@ -3679,10 +3786,7 @@ var AgentSession = class _AgentSession {
|
|
|
3679
3786
|
/** @internal */
|
|
3680
3787
|
_handleChatEnd(status) {
|
|
3681
3788
|
this.flushPatches();
|
|
3682
|
-
this.
|
|
3683
|
-
this.recentChatEndAt = Date.now();
|
|
3684
|
-
void this.syncTurnsFromHistory();
|
|
3685
|
-
this.emitter.emit("chatEnd", { status });
|
|
3789
|
+
this.completeChat(status);
|
|
3686
3790
|
}
|
|
3687
3791
|
/** @internal */
|
|
3688
3792
|
_handleSystemError(message) {
|
|
@@ -3826,6 +3930,12 @@ var AgentSession = class _AgentSession {
|
|
|
3826
3930
|
return next;
|
|
3827
3931
|
});
|
|
3828
3932
|
}
|
|
3933
|
+
completeChat(status) {
|
|
3934
|
+
this.finishStreaming(status);
|
|
3935
|
+
this.recentChatEndAt = Date.now();
|
|
3936
|
+
void this.syncTurnsFromHistory();
|
|
3937
|
+
this.emitter.emit("chatEnd", { status });
|
|
3938
|
+
}
|
|
3829
3939
|
applyTurn(turn) {
|
|
3830
3940
|
this.flushPatches();
|
|
3831
3941
|
const previous = this.state;
|
|
@@ -4008,7 +4118,12 @@ var AgentSession = class _AgentSession {
|
|
|
4008
4118
|
if (this.joinPending) return this.joinPending;
|
|
4009
4119
|
const join = this.runtime.emitWithAck(
|
|
4010
4120
|
"session:subscribe",
|
|
4011
|
-
{
|
|
4121
|
+
{
|
|
4122
|
+
session_id: this.sessionId,
|
|
4123
|
+
event_format: "raw",
|
|
4124
|
+
resume: true,
|
|
4125
|
+
stream_tokens: this.runtime.streamTokens
|
|
4126
|
+
},
|
|
4012
4127
|
5e3
|
|
4013
4128
|
).then((response) => {
|
|
4014
4129
|
if (response && response.ok === false) {
|
|
@@ -4144,6 +4259,7 @@ var SessionHub = class {
|
|
|
4144
4259
|
}
|
|
4145
4260
|
runtimeFor() {
|
|
4146
4261
|
return {
|
|
4262
|
+
streamTokens: this.client.options?.streamTokens !== false,
|
|
4147
4263
|
emitEvent: (event, data) => {
|
|
4148
4264
|
;
|
|
4149
4265
|
this.client.socket().emit(event, data);
|
|
@@ -4383,7 +4499,7 @@ function resolveAuthToken(options) {
|
|
|
4383
4499
|
|
|
4384
4500
|
// src/version.ts
|
|
4385
4501
|
var SDK_NAME = "agent-client";
|
|
4386
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
4502
|
+
var SDK_VERSION = true ? "2610.0.0-beta.10" : "1.1.1";
|
|
4387
4503
|
|
|
4388
4504
|
// src/socket.ts
|
|
4389
4505
|
function withSdkIdentity(auth) {
|
|
@@ -4835,6 +4951,19 @@ function connectEmbedded(options) {
|
|
|
4835
4951
|
};
|
|
4836
4952
|
}
|
|
4837
4953
|
|
|
4954
|
+
// src/schemas/projection-utils.ts
|
|
4955
|
+
function latestPostChatFollowup(turns) {
|
|
4956
|
+
for (let index = turns.length - 1; index >= 0; index -= 1) {
|
|
4957
|
+
const turn = turns[index];
|
|
4958
|
+
if (turn.loop_id === "root" && (turn.role === "user" || turn.role === "assistant") && (turn.kind ?? "message") === "message" && !turn.blocks.some(
|
|
4959
|
+
(block) => ["mode_change", "plan_status", "ask_user_answer"].includes(block.type)
|
|
4960
|
+
)) {
|
|
4961
|
+
return turn.role === "assistant" ? turn.post_chat_followup ?? null : null;
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
return null;
|
|
4965
|
+
}
|
|
4966
|
+
|
|
4838
4967
|
// src/schemas/solution.ts
|
|
4839
4968
|
var LayoutType = /* @__PURE__ */ ((LayoutType2) => {
|
|
4840
4969
|
LayoutType2["Default"] = "default";
|
|
@@ -4877,6 +5006,7 @@ export {
|
|
|
4877
5006
|
SessionStatus,
|
|
4878
5007
|
Task,
|
|
4879
5008
|
TaskStatus,
|
|
5009
|
+
acceptedPostChatFollowupCompletesLatestRun,
|
|
4880
5010
|
buildMessageContent,
|
|
4881
5011
|
connectEmbedded,
|
|
4882
5012
|
contentPreview,
|
|
@@ -4890,7 +5020,9 @@ export {
|
|
|
4890
5020
|
isCommandEnvelope,
|
|
4891
5021
|
isHiddenInternalMessage,
|
|
4892
5022
|
isInboundEnvelope,
|
|
5023
|
+
latestPostChatFollowup,
|
|
4893
5024
|
normalizeMessageContent,
|
|
5025
|
+
reconcileOptimisticUserTurns,
|
|
4894
5026
|
toReplaySnapshot,
|
|
4895
5027
|
transformSlashCommand
|
|
4896
5028
|
};
|