imtoagent 0.3.19 → 0.3.21
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.
|
@@ -69,7 +69,7 @@ export class ClaudeAdapter implements AgentAdapter {
|
|
|
69
69
|
private ctx: ClaudeAdapterContext;
|
|
70
70
|
private activeControllers: AbortController[] = [];
|
|
71
71
|
/** 单次调用最大超时(毫秒),0 = 不限制 */
|
|
72
|
-
static MAX_CALL_TIMEOUT_MS =
|
|
72
|
+
static MAX_CALL_TIMEOUT_MS = 15 * 60 * 1000; // 15 分钟
|
|
73
73
|
|
|
74
74
|
constructor(ctx: ClaudeAdapterContext) {
|
|
75
75
|
this.ctx = ctx;
|
|
@@ -100,6 +100,10 @@ export class ClaudeAdapter implements AgentAdapter {
|
|
|
100
100
|
const { text, session, workingDir, model, systemPrompt: overrideSystemPrompt } = input;
|
|
101
101
|
const sessionAny = session as any; // 向后兼容:访问旧字段
|
|
102
102
|
|
|
103
|
+
// 进度回调
|
|
104
|
+
const onProgress = async (t: string) => { try { await input.sendProgress?.(t); } catch {} };
|
|
105
|
+
let turnCount = 0;
|
|
106
|
+
|
|
103
107
|
// 创建 AbortController 并注册(用于超时 + shutdown 清理)
|
|
104
108
|
const abortCtrl = new AbortController();
|
|
105
109
|
this.activeControllers.push(abortCtrl);
|
|
@@ -205,6 +209,16 @@ export class ClaudeAdapter implements AgentAdapter {
|
|
|
205
209
|
const calls = extractToolCalls(msg);
|
|
206
210
|
toolCalls.push(...calls);
|
|
207
211
|
|
|
212
|
+
// 进度输出(仅 assistant 消息)
|
|
213
|
+
if (msg.type === 'assistant') {
|
|
214
|
+
turnCount++;
|
|
215
|
+
if (calls.length > 0) {
|
|
216
|
+
const names = calls.map(c => c.name).join(', ');
|
|
217
|
+
const summary = calls[0].summary.slice(0, 60);
|
|
218
|
+
onProgress(`🔧 Executing: ${names} — ${summary}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
208
222
|
// 处理最终结果
|
|
209
223
|
if (msg.type === 'result') {
|
|
210
224
|
const result = msgAny;
|
|
@@ -222,6 +236,7 @@ export class ClaudeAdapter implements AgentAdapter {
|
|
|
222
236
|
};
|
|
223
237
|
|
|
224
238
|
if (timeoutId) clearTimeout(timeoutId);
|
|
239
|
+
if (turnCount > 0) onProgress(`✅ Turn ${turnCount} completed`);
|
|
225
240
|
const responseText = fullResponse || `✅ Completed (${toolCalls.length} steps)`;
|
|
226
241
|
|
|
227
242
|
return {
|
|
@@ -106,8 +106,9 @@ async function spawnCodexResume(cwd: string, threadId: string, prompt: string):
|
|
|
106
106
|
|
|
107
107
|
async function runViaAppServer(
|
|
108
108
|
cwd: string, prompt: string, chatId: string, session: Session,
|
|
109
|
-
isFresh: boolean
|
|
109
|
+
isFresh: boolean, onProgress?: (text: string) => Promise<void>
|
|
110
110
|
): Promise<{ threadId: string; response: string; usage: { inputTokens: number; outputTokens: number } }> {
|
|
111
|
+
let turnCount = 0;
|
|
111
112
|
const manager = getAppServerManager();
|
|
112
113
|
const client = await manager.getClient(chatId);
|
|
113
114
|
|
|
@@ -138,9 +139,14 @@ async function runViaAppServer(
|
|
|
138
139
|
case 'text_delta':
|
|
139
140
|
response += event.textDelta || '';
|
|
140
141
|
break;
|
|
141
|
-
case 'tool_call':
|
|
142
|
-
|
|
142
|
+
case 'tool_call': {
|
|
143
|
+
const name = (event as any).toolCall?.name || (event as any).tool?.name || 'Tool';
|
|
144
|
+
onProgress?.(`🔧 Executing: ${name}`);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
143
147
|
case 'turn_result':
|
|
148
|
+
turnCount++;
|
|
149
|
+
onProgress?.(`✅ Turn ${turnCount} completed`);
|
|
144
150
|
totalUsage.inputTokens += event.usage?.inputTokens || 0;
|
|
145
151
|
totalUsage.outputTokens += event.usage?.outputTokens || 0;
|
|
146
152
|
break;
|
|
@@ -189,7 +195,8 @@ export class CodexAdapter implements AgentAdapter {
|
|
|
189
195
|
let execServerUsage: { inputTokens: number; outputTokens: number } | null = null;
|
|
190
196
|
|
|
191
197
|
try {
|
|
192
|
-
const r = await runViaAppServer(cwd, effectiveText, input.chatId, session, isFresh
|
|
198
|
+
const r = await runViaAppServer(cwd, effectiveText, input.chatId, session, isFresh,
|
|
199
|
+
async (t: string) => { try { await input.sendProgress?.(t); } catch {} });
|
|
193
200
|
response = r.response;
|
|
194
201
|
execServerUsage = r.usage;
|
|
195
202
|
} catch (appErr: any) {
|
|
@@ -199,7 +206,8 @@ export class CodexAdapter implements AgentAdapter {
|
|
|
199
206
|
if (errMsg.includes('thread not found') || errMsg.includes('Thread not found')) {
|
|
200
207
|
try {
|
|
201
208
|
sessionAny.codexThreadId = undefined;
|
|
202
|
-
const r2 = await runViaAppServer(cwd, effectiveText, input.chatId, session, true
|
|
209
|
+
const r2 = await runViaAppServer(cwd, effectiveText, input.chatId, session, true,
|
|
210
|
+
async (t: string) => { try { await input.sendProgress?.(t); } catch {} });
|
|
203
211
|
response = r2.response;
|
|
204
212
|
execServerUsage = r2.usage;
|
|
205
213
|
console.error(`[CodexAdapter] app-server thread rebuilt successfully`);
|
|
@@ -213,6 +221,7 @@ export class CodexAdapter implements AgentAdapter {
|
|
|
213
221
|
|
|
214
222
|
if (useExecFallback) {
|
|
215
223
|
getAppServerManager().removeClient(input.chatId);
|
|
224
|
+
input.sendProgress?.('⚙️ Processing... (CLI mode, no streaming progress)').catch(() => {});
|
|
216
225
|
if (isFresh || !sessionAny.codexThreadId) {
|
|
217
226
|
const r = await spawnCodexExec(cwd, effectiveText);
|
|
218
227
|
sessionAny.codexThreadId = r.threadId;
|
|
@@ -64,12 +64,12 @@ async function ocSendPrompt(
|
|
|
64
64
|
initialText: string,
|
|
65
65
|
system: string,
|
|
66
66
|
defaultModel: { providerID: string; modelID: string },
|
|
67
|
-
|
|
67
|
+
onProgress?: (text: string) => void,
|
|
68
68
|
cancelSignal?: AbortSignal
|
|
69
69
|
): Promise<{ response: string; toolCalls: Array<{ name: string; summary: string }> }> {
|
|
70
70
|
const MAX_TURNS = 50;
|
|
71
|
-
const TURN_TIMEOUT =
|
|
72
|
-
const MAX_DURATION =
|
|
71
|
+
const TURN_TIMEOUT = 900_000; // 15 min per turn
|
|
72
|
+
const MAX_DURATION = 3_600_000; // total timeout 60 min
|
|
73
73
|
const startTime = Date.now();
|
|
74
74
|
|
|
75
75
|
let promptText = initialText;
|
|
@@ -79,7 +79,8 @@ async function ocSendPrompt(
|
|
|
79
79
|
|
|
80
80
|
while (turn < MAX_TURNS) {
|
|
81
81
|
if (Date.now() - startTime > MAX_DURATION) {
|
|
82
|
-
console.error(
|
|
82
|
+
console.error(`[OpenCodeAdapter] Task timed out (${MAX_DURATION / 60000}min)`);
|
|
83
|
+
if (onProgress) onProgress('⚠️ Task timed out, stopped');
|
|
83
84
|
break;
|
|
84
85
|
}
|
|
85
86
|
turn++;
|
|
@@ -130,7 +131,7 @@ async function ocSendPrompt(
|
|
|
130
131
|
const summary = args.command || args.cmd || args.file_path || args.query
|
|
131
132
|
|| JSON.stringify(args).slice(0, 80);
|
|
132
133
|
allToolCalls.push({ name, summary });
|
|
133
|
-
if (
|
|
134
|
+
if (onProgress) onProgress(`🔧 Executing: ${name} — ${summary.slice(0, 60)}`);
|
|
134
135
|
console.log(`[OpenCodeAdapter] 🔧 turn ${turn}: ${name} ${summary.slice(0, 60)}`);
|
|
135
136
|
}
|
|
136
137
|
}
|
|
@@ -138,6 +139,7 @@ async function ocSendPrompt(
|
|
|
138
139
|
// 有文本回复 → 任务完成(OpenCode 内部已完成多轮 agent loop)
|
|
139
140
|
if (hasText) {
|
|
140
141
|
console.log(`[OpenCodeAdapter] ✅ completed at turn ${turn}/${MAX_TURNS}`);
|
|
142
|
+
if (onProgress) onProgress(`✅ Turn ${turn} completed`);
|
|
141
143
|
break;
|
|
142
144
|
}
|
|
143
145
|
|
|
@@ -147,7 +149,8 @@ async function ocSendPrompt(
|
|
|
147
149
|
break;
|
|
148
150
|
}
|
|
149
151
|
|
|
150
|
-
// 仅有 tool_call 无文本 →
|
|
152
|
+
// 仅有 tool_call 无文本 → 推进下一轮
|
|
153
|
+
if (onProgress) onProgress(`⏳ Turn ${turn}/${MAX_TURNS}, continuing...`);
|
|
151
154
|
promptText = 'Continue executing, complete remaining tasks';
|
|
152
155
|
}
|
|
153
156
|
|
|
@@ -215,16 +218,18 @@ export class OpenCodeAdapter implements AgentAdapter {
|
|
|
215
218
|
console.log(`[OpenCodeAdapter] 📝 system prompt built (${systemPrompt.length} chars)`);
|
|
216
219
|
|
|
217
220
|
// 发送 prompt(多轮循环:自动推进 tool_call → 纯文本响应)
|
|
221
|
+
// 注意:ocSendPrompt 不直接依赖 ctx,由 handleMessage 传入 onProgress 回调
|
|
222
|
+
const onProgress = async (text: string) => {
|
|
223
|
+
try { await input.sendProgress?.(text); } catch {}
|
|
224
|
+
};
|
|
225
|
+
|
|
218
226
|
const { response, toolCalls } = await ocSendPrompt(
|
|
219
227
|
serverUrl,
|
|
220
228
|
sessionAny.ocSessionId,
|
|
221
229
|
effectiveText,
|
|
222
230
|
systemPrompt,
|
|
223
231
|
defaultModel,
|
|
224
|
-
|
|
225
|
-
(name, args) => {
|
|
226
|
-
// 工具调用日志由 Runtime 层统一格式化
|
|
227
|
-
},
|
|
232
|
+
onProgress,
|
|
228
233
|
input.cancelSignal
|
|
229
234
|
);
|
|
230
235
|
|
package/modules/core/runtime.ts
CHANGED
package/modules/core/types.ts
CHANGED