@keyou007/agent-bot 0.1.0
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/.env.example +8 -0
- package/CHANGELOG.md +11 -0
- package/LICENSE +675 -0
- package/README.md +187 -0
- package/README.zh.md +187 -0
- package/SECURITY.md +13 -0
- package/config.example.yaml +56 -0
- package/dist/acp/AcpJsonRpcConnection.js +155 -0
- package/dist/acp/AcpJsonRpcConnection.js.map +1 -0
- package/dist/acp/AcpProcessManager.js +65 -0
- package/dist/acp/AcpProcessManager.js.map +1 -0
- package/dist/acp/AcpSessionManager.js +164 -0
- package/dist/acp/AcpSessionManager.js.map +1 -0
- package/dist/acp/acpTypes.js +10 -0
- package/dist/acp/acpTypes.js.map +1 -0
- package/dist/cli/FeishuAppConfiguration.js +349 -0
- package/dist/cli/FeishuAppConfiguration.js.map +1 -0
- package/dist/cli/FeishuAppRegistration.js +160 -0
- package/dist/cli/FeishuAppRegistration.js.map +1 -0
- package/dist/cli/Initializer.js +112 -0
- package/dist/cli/Initializer.js.map +1 -0
- package/dist/cli/LocalControlClient.js +47 -0
- package/dist/cli/LocalControlClient.js.map +1 -0
- package/dist/cli/LocalControlServer.js +66 -0
- package/dist/cli/LocalControlServer.js.map +1 -0
- package/dist/cli/SkillRegistry.js +126 -0
- package/dist/cli/SkillRegistry.js.map +1 -0
- package/dist/cli/controlProtocol.js +10 -0
- package/dist/cli/controlProtocol.js.map +1 -0
- package/dist/cli/taskChatRoute.js +23 -0
- package/dist/cli/taskChatRoute.js.map +1 -0
- package/dist/cli.js +616 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex/AppServerConnection.js +131 -0
- package/dist/codex/AppServerConnection.js.map +1 -0
- package/dist/codex/CodexEventMapper.js +296 -0
- package/dist/codex/CodexEventMapper.js.map +1 -0
- package/dist/codex/CodexLocalActivityDetector.js +124 -0
- package/dist/codex/CodexLocalActivityDetector.js.map +1 -0
- package/dist/codex/CodexProcessManager.js +64 -0
- package/dist/codex/CodexProcessManager.js.map +1 -0
- package/dist/codex/CodexRuntime.js +825 -0
- package/dist/codex/CodexRuntime.js.map +1 -0
- package/dist/codex/ProjectlessWorkspace.js +74 -0
- package/dist/codex/ProjectlessWorkspace.js.map +1 -0
- package/dist/codex/protocol.js +10 -0
- package/dist/codex/protocol.js.map +1 -0
- package/dist/commands/CommandRouter.js +176 -0
- package/dist/commands/CommandRouter.js.map +1 -0
- package/dist/commands/commandTypes.js +2 -0
- package/dist/commands/commandTypes.js.map +1 -0
- package/dist/config/loadConfig.js +107 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/config/paths.js +32 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/schema.js +38 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/console/ConsoleConnector.js +39 -0
- package/dist/console/ConsoleConnector.js.map +1 -0
- package/dist/console/ConsoleTurnPresenter.js +60 -0
- package/dist/console/ConsoleTurnPresenter.js.map +1 -0
- package/dist/feishu/CardRenderer.js +972 -0
- package/dist/feishu/CardRenderer.js.map +1 -0
- package/dist/feishu/CardUpdateScheduler.js +148 -0
- package/dist/feishu/CardUpdateScheduler.js.map +1 -0
- package/dist/feishu/ConsoleFeishuClient.js +18 -0
- package/dist/feishu/ConsoleFeishuClient.js.map +1 -0
- package/dist/feishu/FeishuConnector.js +257 -0
- package/dist/feishu/FeishuConnector.js.map +1 -0
- package/dist/feishu/FeishuMarkdown.js +37 -0
- package/dist/feishu/FeishuMarkdown.js.map +1 -0
- package/dist/feishu/FeishuMessageClient.js +459 -0
- package/dist/feishu/FeishuMessageClient.js.map +1 -0
- package/dist/feishu/FeishuTurnPresenter.js +425 -0
- package/dist/feishu/FeishuTurnPresenter.js.map +1 -0
- package/dist/feishu/GroupAvatarGenerator.js +86 -0
- package/dist/feishu/GroupAvatarGenerator.js.map +1 -0
- package/dist/feishu/LocalCardImage.js +13 -0
- package/dist/feishu/LocalCardImage.js.map +1 -0
- package/dist/feishu/LocalImageMarkdown.js +89 -0
- package/dist/feishu/LocalImageMarkdown.js.map +1 -0
- package/dist/feishu/contextKey.js +12 -0
- package/dist/feishu/contextKey.js.map +1 -0
- package/dist/feishu/transport.js +14 -0
- package/dist/feishu/transport.js.map +1 -0
- package/dist/feishu/types.js +2 -0
- package/dist/feishu/types.js.map +1 -0
- package/dist/index.js +213 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/logger.js +22 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/presentation/OutboundRouter.js +127 -0
- package/dist/presentation/OutboundRouter.js.map +1 -0
- package/dist/presentation/TurnStateReducer.js +307 -0
- package/dist/presentation/TurnStateReducer.js.map +1 -0
- package/dist/presentation/splitMarkdown.js +341 -0
- package/dist/presentation/splitMarkdown.js.map +1 -0
- package/dist/presentation/turnViewTypes.js +2 -0
- package/dist/presentation/turnViewTypes.js.map +1 -0
- package/dist/proxy/ProxySessionController.js +2819 -0
- package/dist/proxy/ProxySessionController.js.map +1 -0
- package/dist/runtime/AcpRuntimeAdapter.js +271 -0
- package/dist/runtime/AcpRuntimeAdapter.js.map +1 -0
- package/dist/runtime/AgentRuntimeRegistry.js +18 -0
- package/dist/runtime/AgentRuntimeRegistry.js.map +1 -0
- package/dist/runtime/agentEnvironment.js +11 -0
- package/dist/runtime/agentEnvironment.js.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/startup/SessionMetadataHydrator.js +46 -0
- package/dist/startup/SessionMetadataHydrator.js.map +1 -0
- package/dist/startup/StartupNotifier.js +78 -0
- package/dist/startup/StartupNotifier.js.map +1 -0
- package/dist/startup/startFeishu.js +6 -0
- package/dist/startup/startFeishu.js.map +1 -0
- package/dist/state/StateStore.js +893 -0
- package/dist/state/StateStore.js.map +1 -0
- package/dist/state/migrations.js +129 -0
- package/dist/state/migrations.js.map +1 -0
- package/dist/supervision/SafeRestartNotifier.js +116 -0
- package/dist/supervision/SafeRestartNotifier.js.map +1 -0
- package/dist/supervision/SafeRestartScheduler.js +123 -0
- package/dist/supervision/SafeRestartScheduler.js.map +1 -0
- package/dist/supervision/replacementSupervisor.js +8 -0
- package/dist/supervision/replacementSupervisor.js.map +1 -0
- package/dist/supervision/restartPolicy.js +16 -0
- package/dist/supervision/restartPolicy.js.map +1 -0
- package/dist/supervisor.js +94 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/utils/executeShellCommand.js +76 -0
- package/dist/utils/executeShellCommand.js.map +1 -0
- package/dist/utils/id.js +5 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/markdown.js +29 -0
- package/dist/utils/markdown.js.map +1 -0
- package/dist/utils/spawnCommand.js +21 -0
- package/dist/utils/spawnCommand.js.map +1 -0
- package/dist/utils/taskTitle.js +10 -0
- package/dist/utils/taskTitle.js.map +1 -0
- package/docs/technical-reference.md +294 -0
- package/docs/technical-reference.zh.md +294 -0
- package/npm-shrinkwrap.json +4525 -0
- package/package.json +87 -0
- package/skills/agent-bot/SKILL.md +141 -0
- package/skills/agent-bot/agents/openai.yaml +4 -0
- package/src/acp/AcpJsonRpcConnection.ts +212 -0
- package/src/acp/AcpProcessManager.ts +87 -0
- package/src/acp/AcpSessionManager.ts +227 -0
- package/src/acp/acpTypes.ts +99 -0
- package/src/cli/FeishuAppConfiguration.ts +473 -0
- package/src/cli/FeishuAppRegistration.ts +207 -0
- package/src/cli/Initializer.ts +159 -0
- package/src/cli/LocalControlClient.ts +48 -0
- package/src/cli/LocalControlServer.ts +67 -0
- package/src/cli/SkillRegistry.ts +151 -0
- package/src/cli/controlProtocol.ts +34 -0
- package/src/cli/taskChatRoute.ts +31 -0
- package/src/cli.ts +630 -0
- package/src/codex/AppServerConnection.ts +159 -0
- package/src/codex/CodexEventMapper.ts +351 -0
- package/src/codex/CodexLocalActivityDetector.ts +148 -0
- package/src/codex/CodexProcessManager.ts +63 -0
- package/src/codex/CodexRuntime.ts +1025 -0
- package/src/codex/ProjectlessWorkspace.ts +90 -0
- package/src/codex/protocol.ts +37 -0
- package/src/commands/CommandRouter.ts +179 -0
- package/src/commands/commandTypes.ts +28 -0
- package/src/config/loadConfig.ts +115 -0
- package/src/config/paths.ts +37 -0
- package/src/config/schema.ts +46 -0
- package/src/console/ConsoleConnector.ts +40 -0
- package/src/console/ConsoleTurnPresenter.ts +64 -0
- package/src/feishu/CardRenderer.ts +1157 -0
- package/src/feishu/CardUpdateScheduler.ts +165 -0
- package/src/feishu/ConsoleFeishuClient.ts +22 -0
- package/src/feishu/FeishuConnector.ts +277 -0
- package/src/feishu/FeishuMarkdown.ts +47 -0
- package/src/feishu/FeishuMessageClient.ts +649 -0
- package/src/feishu/FeishuTurnPresenter.ts +539 -0
- package/src/feishu/GroupAvatarGenerator.ts +102 -0
- package/src/feishu/LocalCardImage.ts +13 -0
- package/src/feishu/LocalImageMarkdown.ts +92 -0
- package/src/feishu/contextKey.ts +14 -0
- package/src/feishu/transport.ts +24 -0
- package/src/feishu/types.ts +83 -0
- package/src/index.ts +228 -0
- package/src/logging/logger.ts +28 -0
- package/src/presentation/OutboundRouter.ts +205 -0
- package/src/presentation/TurnStateReducer.ts +341 -0
- package/src/presentation/splitMarkdown.ts +358 -0
- package/src/presentation/turnViewTypes.ts +54 -0
- package/src/proxy/ProxySessionController.ts +3311 -0
- package/src/runtime/AcpRuntimeAdapter.ts +324 -0
- package/src/runtime/AgentRuntimeRegistry.ts +20 -0
- package/src/runtime/agentEnvironment.ts +14 -0
- package/src/runtime/types.ts +215 -0
- package/src/startup/SessionMetadataHydrator.ts +46 -0
- package/src/startup/StartupNotifier.ts +92 -0
- package/src/startup/startFeishu.ts +19 -0
- package/src/state/StateStore.ts +1249 -0
- package/src/state/migrations.ts +128 -0
- package/src/supervision/SafeRestartNotifier.ts +122 -0
- package/src/supervision/SafeRestartScheduler.ts +149 -0
- package/src/supervision/replacementSupervisor.ts +10 -0
- package/src/supervision/restartPolicy.ts +19 -0
- package/src/supervisor.ts +106 -0
- package/src/utils/executeShellCommand.ts +97 -0
- package/src/utils/id.ts +5 -0
- package/src/utils/markdown.ts +25 -0
- package/src/utils/spawnCommand.ts +35 -0
- package/src/utils/taskTitle.ts +9 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
const MAX_TEXT = 6_000;
|
|
2
|
+
const MAX_COMPLETED_TOOLS = 20;
|
|
3
|
+
const MAX_FAILED_TOOLS = 5;
|
|
4
|
+
const MAX_FILES = 30;
|
|
5
|
+
export function createTurnViewState(sessionId, turnId, startedAt, taskTitle, replyTarget, projectCwd, prompt) {
|
|
6
|
+
return {
|
|
7
|
+
sessionId,
|
|
8
|
+
turnId,
|
|
9
|
+
taskTitle,
|
|
10
|
+
prompt,
|
|
11
|
+
projectCwd,
|
|
12
|
+
replyTarget,
|
|
13
|
+
status: "starting",
|
|
14
|
+
startedAt,
|
|
15
|
+
assistantText: "",
|
|
16
|
+
plan: [],
|
|
17
|
+
activities: [],
|
|
18
|
+
totalToolCount: 0,
|
|
19
|
+
completedToolCount: 0,
|
|
20
|
+
failedToolCount: 0,
|
|
21
|
+
toolStatuses: {},
|
|
22
|
+
completedTools: [],
|
|
23
|
+
failedTools: [],
|
|
24
|
+
fileSummary: [],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function reduceTurnEvent(state, event) {
|
|
28
|
+
if (event.sessionId !== state.sessionId || event.turnId !== state.turnId)
|
|
29
|
+
return state;
|
|
30
|
+
switch (event.type) {
|
|
31
|
+
case "turn_started":
|
|
32
|
+
return { ...state, status: "running", startedAt: event.startedAt };
|
|
33
|
+
case "agent_text_delta":
|
|
34
|
+
return { ...state, assistantText: bound(`${state.assistantText}${event.text}`) };
|
|
35
|
+
case "token_usage_updated": {
|
|
36
|
+
const lastTokens = normalizeTokenCount(event.lastTokens);
|
|
37
|
+
const cumulativeTokens = normalizeTokenCount(event.cumulativeTokens);
|
|
38
|
+
const previousCumulative = state.tokenUsageCumulative;
|
|
39
|
+
const delta = previousCumulative === undefined
|
|
40
|
+
? lastTokens
|
|
41
|
+
: Math.max(0, cumulativeTokens - previousCumulative);
|
|
42
|
+
return {
|
|
43
|
+
...state,
|
|
44
|
+
totalTokens: (state.totalTokens ?? 0) + delta,
|
|
45
|
+
tokenUsageCumulative: Math.max(previousCumulative ?? 0, cumulativeTokens),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
case "progress": {
|
|
49
|
+
const activityUpdate = upsertReasoningActivity(state.activities ?? [], event.activityId ?? "progress", event.text, event.append === true, event.activityId?.startsWith("commentary:") ? "assistant" : "reasoning");
|
|
50
|
+
return {
|
|
51
|
+
...state,
|
|
52
|
+
progressText: bound(event.text),
|
|
53
|
+
activities: activityUpdate.activities,
|
|
54
|
+
activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
case "plan_updated":
|
|
58
|
+
return { ...state, plan: event.steps.slice(0, 30).map((step) => ({ ...step, text: bound(step.text) })) };
|
|
59
|
+
case "tool_started": {
|
|
60
|
+
const tool = withToolTiming(state, event.tool);
|
|
61
|
+
const bounded = boundTool(tool);
|
|
62
|
+
const activityUpdate = upsertToolActivity(state.activities ?? [], bounded);
|
|
63
|
+
const tracking = trackToolStatus(state, tool);
|
|
64
|
+
return {
|
|
65
|
+
...state,
|
|
66
|
+
...tracking,
|
|
67
|
+
status: "tool_running",
|
|
68
|
+
activeTool: bounded,
|
|
69
|
+
activities: activityUpdate.activities,
|
|
70
|
+
activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
|
|
71
|
+
fileSummary: mergeFiles(state.fileSummary, tool.files),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
case "tool_updated":
|
|
75
|
+
return reduceToolUpdate(state, event.tool);
|
|
76
|
+
case "tool_output_delta":
|
|
77
|
+
return reduceToolOutputDelta(state, event.toolId, event.delta);
|
|
78
|
+
case "approval_requested":
|
|
79
|
+
return { ...state, status: "waiting_for_approval", approval: event.request };
|
|
80
|
+
case "approval_resolved":
|
|
81
|
+
return { ...state, status: state.activeTool ? "tool_running" : "running", approval: undefined };
|
|
82
|
+
case "turn_completed":
|
|
83
|
+
return {
|
|
84
|
+
...state,
|
|
85
|
+
status: "completed",
|
|
86
|
+
activeTool: undefined,
|
|
87
|
+
approval: undefined,
|
|
88
|
+
completedAt: state.startedAt + (event.durationMs ?? Date.now() - state.startedAt),
|
|
89
|
+
durationMs: event.durationMs ?? Date.now() - state.startedAt,
|
|
90
|
+
finalResponse: event.finalResponse,
|
|
91
|
+
};
|
|
92
|
+
case "turn_cancelled":
|
|
93
|
+
return { ...state, status: "cancelled", activeTool: undefined, approval: undefined, completedAt: Date.now() };
|
|
94
|
+
case "turn_failed":
|
|
95
|
+
return {
|
|
96
|
+
...state,
|
|
97
|
+
status: "failed",
|
|
98
|
+
activeTool: undefined,
|
|
99
|
+
approval: undefined,
|
|
100
|
+
completedAt: Date.now(),
|
|
101
|
+
error: bound(event.message),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export function appendSteerMessage(state, id, text) {
|
|
106
|
+
const normalized = text.trim();
|
|
107
|
+
if (!normalized)
|
|
108
|
+
return state;
|
|
109
|
+
const activities = state.activities ?? [];
|
|
110
|
+
const index = activities.findIndex((activity) => activity.id === id);
|
|
111
|
+
const activityUpdate = upsertActivity(activities, index, {
|
|
112
|
+
kind: "user",
|
|
113
|
+
id,
|
|
114
|
+
text: bound(normalized),
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
...state,
|
|
118
|
+
activities: activityUpdate.activities,
|
|
119
|
+
activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function reduceToolOutputDelta(state, toolId, delta) {
|
|
123
|
+
if (!delta)
|
|
124
|
+
return state;
|
|
125
|
+
const tool = findTool(state, toolId);
|
|
126
|
+
if (!tool || tool.status !== "running" || tool.kind !== "command")
|
|
127
|
+
return state;
|
|
128
|
+
return reduceToolUpdate(state, {
|
|
129
|
+
...tool,
|
|
130
|
+
output: appendBoundedOutput(tool.output, delta),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function findTool(state, toolId) {
|
|
134
|
+
if (state.activeTool?.id === toolId)
|
|
135
|
+
return state.activeTool;
|
|
136
|
+
const activity = [...(state.activities ?? [])].reverse().find((candidate) => candidate.kind === "tool" && candidate.tool.id === toolId);
|
|
137
|
+
if (activity?.kind === "tool")
|
|
138
|
+
return activity.tool;
|
|
139
|
+
return state.failedTools.find((tool) => tool.id === toolId)
|
|
140
|
+
?? state.completedTools.find((tool) => tool.id === toolId);
|
|
141
|
+
}
|
|
142
|
+
function withToolTiming(state, tool) {
|
|
143
|
+
const previous = findTool(state, tool.id);
|
|
144
|
+
const now = Date.now();
|
|
145
|
+
const startedAt = tool.startedAt ?? previous?.startedAt ?? tool.completedAt ?? now;
|
|
146
|
+
return {
|
|
147
|
+
...tool,
|
|
148
|
+
startedAt,
|
|
149
|
+
completedAt: tool.status === "running" ? tool.completedAt : tool.completedAt ?? now,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function appendBoundedOutput(previous, delta) {
|
|
153
|
+
const combined = `${previous ?? ""}${delta}`;
|
|
154
|
+
if (combined.length <= MAX_TEXT)
|
|
155
|
+
return combined;
|
|
156
|
+
return `…${combined.slice(-(MAX_TEXT - 1))}`;
|
|
157
|
+
}
|
|
158
|
+
function reduceToolUpdate(state, tool) {
|
|
159
|
+
tool = withToolTiming(state, tool);
|
|
160
|
+
const tracking = trackToolStatus(state, tool);
|
|
161
|
+
const bounded = boundTool(tool);
|
|
162
|
+
const activityUpdate = upsertToolActivity(state.activities ?? [], bounded);
|
|
163
|
+
const withoutCompleted = state.completedTools.filter((item) => item.id !== tool.id);
|
|
164
|
+
const withoutFailed = state.failedTools.filter((item) => item.id !== tool.id);
|
|
165
|
+
const activeTool = state.activeTool?.id === tool.id ? undefined : state.activeTool;
|
|
166
|
+
if (tool.status === "running") {
|
|
167
|
+
return {
|
|
168
|
+
...state,
|
|
169
|
+
...tracking,
|
|
170
|
+
status: "tool_running",
|
|
171
|
+
activeTool: bounded,
|
|
172
|
+
activities: activityUpdate.activities,
|
|
173
|
+
activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
|
|
174
|
+
completedTools: withoutCompleted,
|
|
175
|
+
failedTools: withoutFailed,
|
|
176
|
+
fileSummary: mergeFiles(state.fileSummary, tool.files),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (tool.status === "failed") {
|
|
180
|
+
return {
|
|
181
|
+
...state,
|
|
182
|
+
...tracking,
|
|
183
|
+
status: activeTool ? "tool_running" : "running",
|
|
184
|
+
activeTool,
|
|
185
|
+
activities: activityUpdate.activities,
|
|
186
|
+
activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
|
|
187
|
+
completedTools: withoutCompleted,
|
|
188
|
+
failedTools: [...withoutFailed, bounded].slice(-MAX_FAILED_TOOLS),
|
|
189
|
+
fileSummary: mergeFiles(state.fileSummary, tool.files),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
...state,
|
|
194
|
+
...tracking,
|
|
195
|
+
status: activeTool ? "tool_running" : "running",
|
|
196
|
+
activeTool,
|
|
197
|
+
activities: activityUpdate.activities,
|
|
198
|
+
activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
|
|
199
|
+
failedTools: withoutFailed,
|
|
200
|
+
completedTools: [...withoutCompleted, bounded].slice(-MAX_COMPLETED_TOOLS),
|
|
201
|
+
fileSummary: mergeFiles(state.fileSummary, tool.files),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function trackToolStatus(state, tool) {
|
|
205
|
+
const toolStatuses = state.toolStatuses
|
|
206
|
+
? { ...state.toolStatuses }
|
|
207
|
+
: legacyToolStatuses(state);
|
|
208
|
+
const previous = toolStatuses[tool.id];
|
|
209
|
+
let totalToolCount = state.totalToolCount ?? Object.keys(toolStatuses).length;
|
|
210
|
+
let completedToolCount = state.completedToolCount
|
|
211
|
+
?? Object.values(toolStatuses).filter((status) => status === "completed").length;
|
|
212
|
+
let failedToolCount = state.failedToolCount
|
|
213
|
+
?? Object.values(toolStatuses).filter((status) => status === "failed").length;
|
|
214
|
+
if (previous === undefined)
|
|
215
|
+
totalToolCount += 1;
|
|
216
|
+
if (previous !== tool.status) {
|
|
217
|
+
if (previous === "completed")
|
|
218
|
+
completedToolCount = Math.max(0, completedToolCount - 1);
|
|
219
|
+
if (previous === "failed")
|
|
220
|
+
failedToolCount = Math.max(0, failedToolCount - 1);
|
|
221
|
+
if (tool.status === "completed")
|
|
222
|
+
completedToolCount += 1;
|
|
223
|
+
if (tool.status === "failed")
|
|
224
|
+
failedToolCount += 1;
|
|
225
|
+
}
|
|
226
|
+
toolStatuses[tool.id] = tool.status;
|
|
227
|
+
return { totalToolCount, completedToolCount, failedToolCount, toolStatuses };
|
|
228
|
+
}
|
|
229
|
+
function legacyToolStatuses(state) {
|
|
230
|
+
const statuses = {};
|
|
231
|
+
for (const tool of state.completedTools ?? [])
|
|
232
|
+
statuses[tool.id] = tool.status;
|
|
233
|
+
for (const tool of state.failedTools ?? [])
|
|
234
|
+
statuses[tool.id] = tool.status;
|
|
235
|
+
for (const activity of state.activities ?? []) {
|
|
236
|
+
if (activity.kind === "tool")
|
|
237
|
+
statuses[activity.tool.id] = activity.tool.status;
|
|
238
|
+
}
|
|
239
|
+
if (state.activeTool)
|
|
240
|
+
statuses[state.activeTool.id] = state.activeTool.status;
|
|
241
|
+
return statuses;
|
|
242
|
+
}
|
|
243
|
+
function upsertReasoningActivity(activities, id, text, append, kind) {
|
|
244
|
+
const index = activities.findIndex((activity) => activity.id === id);
|
|
245
|
+
const existing = index >= 0 ? activities[index] : undefined;
|
|
246
|
+
const previousText = existing?.kind === "reasoning" || existing?.kind === "assistant" ? existing.text : "";
|
|
247
|
+
const combined = append ? `${previousText}${text}` : text;
|
|
248
|
+
const next = {
|
|
249
|
+
kind,
|
|
250
|
+
id,
|
|
251
|
+
text: kind === "assistant" ? combined : bound(combined),
|
|
252
|
+
};
|
|
253
|
+
return upsertActivity(activities, index, next);
|
|
254
|
+
}
|
|
255
|
+
function upsertToolActivity(activities, tool) {
|
|
256
|
+
const index = activities.findIndex((activity) => activity.id === tool.id);
|
|
257
|
+
return upsertActivity(activities, index, { kind: "tool", id: tool.id, tool });
|
|
258
|
+
}
|
|
259
|
+
function upsertActivity(activities, index, activity) {
|
|
260
|
+
const updated = [...activities];
|
|
261
|
+
if (index >= 0)
|
|
262
|
+
updated[index] = activity;
|
|
263
|
+
else
|
|
264
|
+
updated.push(activity);
|
|
265
|
+
return {
|
|
266
|
+
activities: updated,
|
|
267
|
+
truncated: false,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function boundTool(tool) {
|
|
271
|
+
return {
|
|
272
|
+
...tool,
|
|
273
|
+
title: bound(tool.title),
|
|
274
|
+
command: tool.command === undefined ? undefined : bound(tool.command),
|
|
275
|
+
output: tool.output === undefined ? undefined : bound(tool.output),
|
|
276
|
+
error: tool.error === undefined ? undefined : bound(tool.error),
|
|
277
|
+
files: tool.files?.slice(0, MAX_FILES),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function mergeFiles(existing, incoming) {
|
|
281
|
+
if (!incoming?.length)
|
|
282
|
+
return existing;
|
|
283
|
+
const merged = new Map(existing.map((file) => [file.path, { ...file }]));
|
|
284
|
+
for (const file of incoming) {
|
|
285
|
+
const previous = merged.get(file.path);
|
|
286
|
+
merged.set(file.path, {
|
|
287
|
+
path: file.path,
|
|
288
|
+
additions: addOptional(previous?.additions, file.additions),
|
|
289
|
+
deletions: addOptional(previous?.deletions, file.deletions),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
return [...merged.values()].slice(-MAX_FILES);
|
|
293
|
+
}
|
|
294
|
+
function addOptional(left, right) {
|
|
295
|
+
if (left === undefined && right === undefined)
|
|
296
|
+
return undefined;
|
|
297
|
+
return (left ?? 0) + (right ?? 0);
|
|
298
|
+
}
|
|
299
|
+
function bound(value) {
|
|
300
|
+
if (value.length <= MAX_TEXT)
|
|
301
|
+
return value;
|
|
302
|
+
return `${value.slice(0, MAX_TEXT - 1)}…`;
|
|
303
|
+
}
|
|
304
|
+
function normalizeTokenCount(value) {
|
|
305
|
+
return Math.max(0, Math.round(value));
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=TurnStateReducer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TurnStateReducer.js","sourceRoot":"","sources":["../../src/presentation/TurnStateReducer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
export function splitMarkdown(text, maxLength = 4_000) {
|
|
2
|
+
if (maxLength < 32)
|
|
3
|
+
throw new Error("maxLength must be at least 32");
|
|
4
|
+
if (text.length <= maxLength)
|
|
5
|
+
return [text];
|
|
6
|
+
const chunks = [];
|
|
7
|
+
let current = "";
|
|
8
|
+
let fence;
|
|
9
|
+
const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
10
|
+
const closingSuffix = () => {
|
|
11
|
+
if (!fence)
|
|
12
|
+
return "";
|
|
13
|
+
return `${current.endsWith("\n") ? "" : "\n"}${fence.delimiter}`;
|
|
14
|
+
};
|
|
15
|
+
const flush = () => {
|
|
16
|
+
if (!current)
|
|
17
|
+
return;
|
|
18
|
+
const continuation = fence;
|
|
19
|
+
chunks.push(`${current}${closingSuffix()}`);
|
|
20
|
+
current = continuation ? `${continuation.opener}\n` : "";
|
|
21
|
+
};
|
|
22
|
+
const appendPlainLine = (line) => {
|
|
23
|
+
const atomicRanges = fence ? [] : markdownAtomicRanges(line);
|
|
24
|
+
let offset = 0;
|
|
25
|
+
while (offset < line.length) {
|
|
26
|
+
// Reserve the worst-case newline plus delimiter because the appended
|
|
27
|
+
// slice may change a newline-terminated buffer into a partial line.
|
|
28
|
+
const reserve = fence ? fence.delimiter.length + 1 : 0;
|
|
29
|
+
const available = maxLength - current.length - reserve;
|
|
30
|
+
if (available <= 0) {
|
|
31
|
+
flush();
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const continuationPrefix = fence ? `${fence.opener}\n` : "";
|
|
35
|
+
const hasPayload = current.length > continuationPrefix.length;
|
|
36
|
+
const remainingLength = line.length - offset;
|
|
37
|
+
if (remainingLength > available && hasPayload) {
|
|
38
|
+
// Prefer a line boundary over filling the previous chunk. Apart from
|
|
39
|
+
// producing more readable pages, this gives inline Markdown such as
|
|
40
|
+
// links and code spans the full capacity of the next chunk.
|
|
41
|
+
flush();
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
let partLength = Math.min(remainingLength, available);
|
|
45
|
+
if (!fence && remainingLength > available) {
|
|
46
|
+
partLength = findSafeMarkdownSplit(line, offset, available, atomicRanges);
|
|
47
|
+
// A Markdown construct may itself be larger than the message limit.
|
|
48
|
+
// It cannot be kept intact, so retain the lossless hard-split fallback.
|
|
49
|
+
if (partLength <= 0)
|
|
50
|
+
partLength = available;
|
|
51
|
+
}
|
|
52
|
+
const part = line.slice(offset, offset + partLength);
|
|
53
|
+
current += part;
|
|
54
|
+
offset += part.length;
|
|
55
|
+
if (offset < line.length)
|
|
56
|
+
flush();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const appendTable = (tableLines) => {
|
|
60
|
+
const header = tableLines[0];
|
|
61
|
+
const delimiter = tableLines[1];
|
|
62
|
+
if (!header || !delimiter)
|
|
63
|
+
return;
|
|
64
|
+
const continuationPrefix = `${header}${delimiter}`;
|
|
65
|
+
const firstRow = tableLines[2];
|
|
66
|
+
const headerLength = header.length + delimiter.length;
|
|
67
|
+
const initialTableLength = firstRow && headerLength + firstRow.length <= maxLength
|
|
68
|
+
? headerLength + firstRow.length
|
|
69
|
+
: headerLength;
|
|
70
|
+
if (current && initialTableLength <= maxLength && current.length + initialTableLength > maxLength)
|
|
71
|
+
flush();
|
|
72
|
+
if (headerLength <= maxLength) {
|
|
73
|
+
current += header;
|
|
74
|
+
current += delimiter;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
appendPlainLine(header);
|
|
78
|
+
appendPlainLine(delimiter);
|
|
79
|
+
}
|
|
80
|
+
for (const row of tableLines.slice(2)) {
|
|
81
|
+
if (current.length + row.length <= maxLength) {
|
|
82
|
+
current += row;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
flush();
|
|
86
|
+
if (continuationPrefix.length + row.length <= maxLength) {
|
|
87
|
+
current = continuationPrefix;
|
|
88
|
+
current += row;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
// A single data row can itself exceed the card limit. There is no way
|
|
92
|
+
// to preserve it as one Markdown table row in that case, so retain the
|
|
93
|
+
// existing lossless hard-split fallback.
|
|
94
|
+
current = continuationPrefix;
|
|
95
|
+
appendPlainLine(row);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
99
|
+
const line = lines[index];
|
|
100
|
+
if (!fence && isTableHeader(line, lines[index + 1])) {
|
|
101
|
+
const tableLines = [line, lines[index + 1]];
|
|
102
|
+
index += 2;
|
|
103
|
+
while (index < lines.length && isTableRow(lines[index])) {
|
|
104
|
+
tableLines.push(lines[index]);
|
|
105
|
+
index += 1;
|
|
106
|
+
}
|
|
107
|
+
index -= 1;
|
|
108
|
+
appendTable(tableLines);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const fenceLine = parseFence(line);
|
|
112
|
+
if (fenceLine) {
|
|
113
|
+
const isClosing = fence !== undefined && fenceLine.delimiter.startsWith(fence.delimiter.slice(0, 3));
|
|
114
|
+
const nextFence = isClosing ? undefined : fence ?? fenceLine;
|
|
115
|
+
const reserve = nextFence ? suffixLength(current + line, nextFence.delimiter) : 0;
|
|
116
|
+
if (current && current.length + line.length + reserve > maxLength)
|
|
117
|
+
flush();
|
|
118
|
+
current += line;
|
|
119
|
+
fence = nextFence;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
appendPlainLine(line);
|
|
123
|
+
}
|
|
124
|
+
flush();
|
|
125
|
+
return chunks;
|
|
126
|
+
}
|
|
127
|
+
function isTableHeader(line, nextLine) {
|
|
128
|
+
return isTableRow(line) && nextLine !== undefined && isTableDelimiter(nextLine);
|
|
129
|
+
}
|
|
130
|
+
function isTableRow(line) {
|
|
131
|
+
const value = line.trim();
|
|
132
|
+
return value.length > 0 && unescapedPipeCount(value) > 0;
|
|
133
|
+
}
|
|
134
|
+
function isTableDelimiter(line) {
|
|
135
|
+
const cells = tableCells(line);
|
|
136
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()));
|
|
137
|
+
}
|
|
138
|
+
function tableCells(line) {
|
|
139
|
+
const value = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
140
|
+
const cells = [];
|
|
141
|
+
let current = "";
|
|
142
|
+
let escaped = false;
|
|
143
|
+
for (const character of value) {
|
|
144
|
+
if (character === "|" && !escaped) {
|
|
145
|
+
cells.push(current);
|
|
146
|
+
current = "";
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
current += character;
|
|
150
|
+
}
|
|
151
|
+
if (character === "\\" && !escaped)
|
|
152
|
+
escaped = true;
|
|
153
|
+
else
|
|
154
|
+
escaped = false;
|
|
155
|
+
}
|
|
156
|
+
cells.push(current);
|
|
157
|
+
return cells;
|
|
158
|
+
}
|
|
159
|
+
function unescapedPipeCount(value) {
|
|
160
|
+
let count = 0;
|
|
161
|
+
let escaped = false;
|
|
162
|
+
for (const character of value) {
|
|
163
|
+
if (character === "|" && !escaped)
|
|
164
|
+
count += 1;
|
|
165
|
+
if (character === "\\" && !escaped)
|
|
166
|
+
escaped = true;
|
|
167
|
+
else
|
|
168
|
+
escaped = false;
|
|
169
|
+
}
|
|
170
|
+
return count;
|
|
171
|
+
}
|
|
172
|
+
function findSafeMarkdownSplit(value, start, limit, ranges) {
|
|
173
|
+
if (value.length - start <= limit)
|
|
174
|
+
return value.length - start;
|
|
175
|
+
let boundary = start + limit;
|
|
176
|
+
const activeRanges = ranges.filter((range) => range.start >= start);
|
|
177
|
+
for (const range of activeRanges) {
|
|
178
|
+
if (range.start < boundary && boundary < range.end) {
|
|
179
|
+
boundary = range.start;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (boundary <= start)
|
|
184
|
+
return 0;
|
|
185
|
+
// Prefer a natural reading boundary, provided it is not inside another
|
|
186
|
+
// protected Markdown construct. Whitespace remains in the preceding chunk,
|
|
187
|
+
// so concatenating plain-text chunks is lossless.
|
|
188
|
+
for (let index = boundary; index > start; index -= 1) {
|
|
189
|
+
if (/\s/.test(value[index - 1]) && isSafeBoundary(index, activeRanges))
|
|
190
|
+
return index - start;
|
|
191
|
+
}
|
|
192
|
+
for (let index = boundary; index > start; index -= 1) {
|
|
193
|
+
if (/[,。;:、,.!?;:]/.test(value[index - 1]) && isSafeBoundary(index, activeRanges))
|
|
194
|
+
return index - start;
|
|
195
|
+
}
|
|
196
|
+
return isSafeBoundary(boundary, activeRanges) ? boundary - start : 0;
|
|
197
|
+
}
|
|
198
|
+
function markdownAtomicRanges(value) {
|
|
199
|
+
const ranges = [];
|
|
200
|
+
collectCodeSpans(value, ranges);
|
|
201
|
+
collectLinksAndImages(value, ranges);
|
|
202
|
+
collectAngleSpans(value, ranges);
|
|
203
|
+
collectEmphasisSpans(value, ranges);
|
|
204
|
+
return mergeRanges(ranges);
|
|
205
|
+
}
|
|
206
|
+
function collectCodeSpans(value, ranges) {
|
|
207
|
+
for (let index = 0; index < value.length;) {
|
|
208
|
+
if (value[index] !== "`" || isEscaped(value, index)) {
|
|
209
|
+
index += 1;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const delimiterLength = repeatedCharacterLength(value, index, "`");
|
|
213
|
+
const end = findClosingRun(value, index + delimiterLength, "`", delimiterLength);
|
|
214
|
+
if (end === -1) {
|
|
215
|
+
index += delimiterLength;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
ranges.push({ start: index, end: end + delimiterLength });
|
|
219
|
+
index = end + delimiterLength;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function collectLinksAndImages(value, ranges) {
|
|
223
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
224
|
+
if (value[index] !== "[" || isEscaped(value, index))
|
|
225
|
+
continue;
|
|
226
|
+
const labelEnd = findMatchingDelimiter(value, index, "[", "]");
|
|
227
|
+
if (labelEnd === -1)
|
|
228
|
+
continue;
|
|
229
|
+
const start = index > 0 && value[index - 1] === "!" && !isEscaped(value, index - 1)
|
|
230
|
+
? index - 1
|
|
231
|
+
: index;
|
|
232
|
+
let end = labelEnd + 1;
|
|
233
|
+
if (value[end] === "(") {
|
|
234
|
+
const destinationEnd = findMatchingDelimiter(value, end, "(", ")");
|
|
235
|
+
if (destinationEnd !== -1)
|
|
236
|
+
end = destinationEnd + 1;
|
|
237
|
+
}
|
|
238
|
+
else if (value[end] === "[") {
|
|
239
|
+
const referenceEnd = findMatchingDelimiter(value, end, "[", "]");
|
|
240
|
+
if (referenceEnd !== -1)
|
|
241
|
+
end = referenceEnd + 1;
|
|
242
|
+
}
|
|
243
|
+
ranges.push({ start, end });
|
|
244
|
+
index = end - 1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function collectAngleSpans(value, ranges) {
|
|
248
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
249
|
+
if (value[index] !== "<" || isEscaped(value, index))
|
|
250
|
+
continue;
|
|
251
|
+
const end = findUnescaped(value, ">", index + 1);
|
|
252
|
+
if (end !== -1) {
|
|
253
|
+
ranges.push({ start: index, end: end + 1 });
|
|
254
|
+
index = end;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function collectEmphasisSpans(value, ranges) {
|
|
259
|
+
const delimiters = ["***", "___", "**", "__", "~~", "*", "_"];
|
|
260
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
261
|
+
if (isEscaped(value, index))
|
|
262
|
+
continue;
|
|
263
|
+
const delimiter = delimiters.find((candidate) => value.startsWith(candidate, index));
|
|
264
|
+
if (!delimiter || /\s/.test(value[index + delimiter.length] ?? ""))
|
|
265
|
+
continue;
|
|
266
|
+
const end = findUnescaped(value, delimiter, index + delimiter.length, (candidate) => (candidate > index + delimiter.length
|
|
267
|
+
&& !/\s/.test(value[candidate - 1] ?? "")));
|
|
268
|
+
if (end === -1)
|
|
269
|
+
continue;
|
|
270
|
+
ranges.push({ start: index, end: end + delimiter.length });
|
|
271
|
+
index = end + delimiter.length - 1;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function findMatchingDelimiter(value, start, opener, closer) {
|
|
275
|
+
let depth = 0;
|
|
276
|
+
for (let index = start; index < value.length; index += 1) {
|
|
277
|
+
if (isEscaped(value, index))
|
|
278
|
+
continue;
|
|
279
|
+
if (value[index] === opener)
|
|
280
|
+
depth += 1;
|
|
281
|
+
else if (value[index] === closer) {
|
|
282
|
+
depth -= 1;
|
|
283
|
+
if (depth === 0)
|
|
284
|
+
return index;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return -1;
|
|
288
|
+
}
|
|
289
|
+
function findClosingRun(value, start, character, length) {
|
|
290
|
+
const delimiter = character.repeat(length);
|
|
291
|
+
return findUnescaped(value, delimiter, start, (index) => (value[index - 1] !== character && value[index + length] !== character));
|
|
292
|
+
}
|
|
293
|
+
function findUnescaped(value, needle, start, accept = () => true) {
|
|
294
|
+
let index = value.indexOf(needle, start);
|
|
295
|
+
while (index !== -1) {
|
|
296
|
+
if (!isEscaped(value, index) && accept(index))
|
|
297
|
+
return index;
|
|
298
|
+
index = value.indexOf(needle, index + 1);
|
|
299
|
+
}
|
|
300
|
+
return -1;
|
|
301
|
+
}
|
|
302
|
+
function repeatedCharacterLength(value, start, character) {
|
|
303
|
+
let end = start;
|
|
304
|
+
while (value[end] === character)
|
|
305
|
+
end += 1;
|
|
306
|
+
return end - start;
|
|
307
|
+
}
|
|
308
|
+
function isEscaped(value, index) {
|
|
309
|
+
let slashes = 0;
|
|
310
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1)
|
|
311
|
+
slashes += 1;
|
|
312
|
+
return slashes % 2 === 1;
|
|
313
|
+
}
|
|
314
|
+
function mergeRanges(ranges) {
|
|
315
|
+
const sorted = [...ranges].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
316
|
+
const merged = [];
|
|
317
|
+
for (const range of sorted) {
|
|
318
|
+
const previous = merged.at(-1);
|
|
319
|
+
if (!previous || range.start >= previous.end) {
|
|
320
|
+
merged.push({ ...range });
|
|
321
|
+
}
|
|
322
|
+
else if (range.end > previous.end) {
|
|
323
|
+
previous.end = range.end;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return merged;
|
|
327
|
+
}
|
|
328
|
+
function isSafeBoundary(index, ranges) {
|
|
329
|
+
return ranges.every((range) => index <= range.start || index >= range.end);
|
|
330
|
+
}
|
|
331
|
+
function parseFence(line) {
|
|
332
|
+
const trimmed = line.trimEnd();
|
|
333
|
+
const match = trimmed.match(/^\s*((?:`{3,})|(?:~{3,}))(.*)$/);
|
|
334
|
+
if (!match?.[1])
|
|
335
|
+
return undefined;
|
|
336
|
+
return { opener: trimmed.trimStart(), delimiter: match[1] };
|
|
337
|
+
}
|
|
338
|
+
function suffixLength(value, delimiter) {
|
|
339
|
+
return (value.endsWith("\n") ? 0 : 1) + delimiter.length;
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=splitMarkdown.js.map
|