@code-yeongyu/senpi-agent-core 2026.9.4 → 2026.9.5
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/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +58 -64
- package/dist/agent-loop.js.map +1 -1
- package/dist/harness/compaction/compaction.d.ts.map +1 -1
- package/dist/harness/compaction/compaction.js +16 -6
- package/dist/harness/compaction/compaction.js.map +1 -1
- package/dist/harness/messages.d.ts +1 -1
- package/dist/harness/messages.d.ts.map +1 -1
- package/dist/harness/messages.js +6 -1
- package/dist/harness/messages.js.map +1 -1
- package/dist/harness/tools/write.js +1 -1
- package/dist/harness/tools/write.js.map +1 -1
- package/dist/proxy.d.ts +2 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +40 -10
- package/dist/proxy.js.map +1 -1
- package/dist/types.d.ts +6 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/dist/agent-loop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIN,KAAK,OAAO,EAEZ,WAAW,EAIX,MAAM,uBAAuB,CAAC;AAU/B,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EAEf,YAAY,EACZ,SAAS,EACT,aAAa,EAEb,QAAQ,EACR,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAiBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAwBzC;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB;AAmBD,qBAAa,uBAAwB,SAAQ,KAAK;gBACrC,SAAS,EAAE,MAAM;CAM7B;
|
|
1
|
+
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIN,KAAK,OAAO,EAEZ,WAAW,EAIX,MAAM,uBAAuB,CAAC;AAU/B,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EAEf,YAAY,EACZ,SAAS,EACT,aAAa,EAEb,QAAQ,EACR,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAiBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAwBzC;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB;AAmBD,qBAAa,uBAAwB,SAAQ,KAAK;gBACrC,SAAS,EAAE,MAAM;CAM7B;AA2ND,uGAAuG;AACvG,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,cAAc,GAAG,kBAAkB,CAAC,EAClE,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,OAAO,CAAC,CAIlB;AA+mBD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACd;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,aAAa,CAYrG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,qBAAqB,CAOpG"}
|
package/dist/agent-loop.js
CHANGED
|
@@ -96,9 +96,8 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
96
96
|
let config = initialConfig;
|
|
97
97
|
let firstTurn = true;
|
|
98
98
|
let firstProviderRequest = true;
|
|
99
|
-
// Check for steering messages at start (user may have typed while waiting)
|
|
100
|
-
let pendingMessages = (await config.getSteeringMessages?.()) || [];
|
|
101
99
|
let drainedTerminatingQueue;
|
|
100
|
+
let turnStartAlreadyEmitted = false;
|
|
102
101
|
const refreshTerminatingQueueDrain = async () => {
|
|
103
102
|
if (!drainedTerminatingQueue || !config.restorePendingMessages)
|
|
104
103
|
return;
|
|
@@ -110,12 +109,17 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
110
109
|
drainedTerminatingQueue = pendingMessages.length > 0 ? "followUp" : undefined;
|
|
111
110
|
}
|
|
112
111
|
};
|
|
112
|
+
// Check for steering messages at start (user may have typed while waiting)
|
|
113
|
+
let pendingMessages = (await config.getSteeringMessages?.()) || [];
|
|
113
114
|
// Outer loop: continues when queued follow-up messages arrive after agent would stop
|
|
114
115
|
while (true) {
|
|
115
116
|
let hasMoreToolCalls = true;
|
|
116
117
|
// Inner loop: process tool calls and steering messages
|
|
117
118
|
while (hasMoreToolCalls || pendingMessages.length > 0) {
|
|
118
|
-
if (
|
|
119
|
+
if (turnStartAlreadyEmitted) {
|
|
120
|
+
turnStartAlreadyEmitted = false;
|
|
121
|
+
}
|
|
122
|
+
else if (!firstTurn) {
|
|
119
123
|
await emit({ type: "turn_start" });
|
|
120
124
|
}
|
|
121
125
|
else {
|
|
@@ -139,10 +143,7 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
139
143
|
}
|
|
140
144
|
pendingMessages = [];
|
|
141
145
|
}
|
|
142
|
-
// Stream assistant response
|
|
143
|
-
// provider request only. Once that request emits its first event, the
|
|
144
|
-
// configured idle timeout resumes so healthy reasoning gaps are not bound
|
|
145
|
-
// by the short liveness probe.
|
|
146
|
+
// Stream assistant response
|
|
146
147
|
const isInitialProviderRequest = firstProviderRequest;
|
|
147
148
|
firstProviderRequest = false;
|
|
148
149
|
const requestConfig = isInitialProviderRequest
|
|
@@ -152,16 +153,10 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
152
153
|
streamStartTimeoutMs: config.initialRequestStreamStartTimeoutMs ?? config.streamStartTimeoutMs,
|
|
153
154
|
}
|
|
154
155
|
: config;
|
|
155
|
-
const
|
|
156
|
-
const streamed = await streamAssistantResponse(currentContext, requestConfig, signal, emit, withEmptyAssistantRecovery(requestConfig.model, streamFunction), streamIdleTimeoutMs);
|
|
156
|
+
const streamed = await streamAssistantResponse(currentContext, requestConfig, signal, emit, withEmptyAssistantRecovery(requestConfig.model, streamFunction), isInitialProviderRequest ? config.timeoutMs : requestConfig.timeoutMs);
|
|
157
157
|
const message = promoteStopWithPendingToolCalls(streamed.message);
|
|
158
158
|
const providerToolResults = streamed.providerToolResults;
|
|
159
159
|
newMessages.push(message);
|
|
160
|
-
// Provider-resolved (Cursor exec-channel) tool results pair with
|
|
161
|
-
// already-resolved toolCall blocks in the assistant message. They are
|
|
162
|
-
// appended right after it — including on terminal error/abort paths,
|
|
163
|
-
// where dropping them would leave resolved calls unpaired and strip
|
|
164
|
-
// the interaction from every rebuilt transcript.
|
|
165
160
|
const toolResults = [];
|
|
166
161
|
for (const result of providerToolResults) {
|
|
167
162
|
await emit({ type: "message_start", message: result });
|
|
@@ -175,18 +170,14 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
175
170
|
await emit({ type: "agent_end", messages: newMessages });
|
|
176
171
|
return;
|
|
177
172
|
}
|
|
178
|
-
// Check for tool calls
|
|
179
|
-
// already executed by Cursor's exec channel mid-stream (their results
|
|
180
|
-
// arrived via `providerToolResults`); running them here again would
|
|
181
|
-
// duplicate side-effecting tools.
|
|
173
|
+
// Check for tool calls
|
|
182
174
|
const toolCalls = message.content.filter((c) => c.type === "toolCall" && !isCursorExecResolved(c));
|
|
183
175
|
hasMoreToolCalls = false;
|
|
184
176
|
let toolBatchTerminated = false;
|
|
185
177
|
if (toolCalls.length > 0) {
|
|
186
|
-
// A
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
// native, unwrapped length responses for this message-wide safeguard.
|
|
178
|
+
// A "length" stop means the output was cut off by the token limit, so
|
|
179
|
+
// every tool call in the message may carry truncated arguments. Fail
|
|
180
|
+
// them all instead of executing potentially borked calls.
|
|
190
181
|
const executedToolBatch = message.stopReason === "length"
|
|
191
182
|
? await failToolCallsFromTruncatedMessage(toolCalls, emit)
|
|
192
183
|
: await executeToolCalls(currentContext, message, config, signal, emit);
|
|
@@ -209,34 +200,35 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
209
200
|
context: currentContext,
|
|
210
201
|
newMessages,
|
|
211
202
|
};
|
|
203
|
+
if (await config.shouldStopAfterTurn?.(nextTurnContext)) {
|
|
204
|
+
await emit({ type: "agent_end", messages: newMessages });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
212
207
|
if (toolBatchTerminated) {
|
|
213
|
-
if (await config.shouldStopAfterTurn?.(nextTurnContext)) {
|
|
214
|
-
await emit({ type: "agent_end", messages: newMessages });
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
208
|
pendingMessages = (await config.getSteeringMessages?.()) || [];
|
|
218
|
-
if (pendingMessages.length > 0)
|
|
209
|
+
if (pendingMessages.length > 0)
|
|
219
210
|
drainedTerminatingQueue = "steering";
|
|
220
|
-
}
|
|
221
211
|
if (pendingMessages.length === 0) {
|
|
222
212
|
pendingMessages = (await config.getFollowUpMessages?.()) || [];
|
|
223
|
-
if (pendingMessages.length > 0)
|
|
213
|
+
if (pendingMessages.length > 0)
|
|
224
214
|
drainedTerminatingQueue = "followUp";
|
|
225
|
-
}
|
|
226
215
|
}
|
|
227
216
|
if (pendingMessages.length === 0) {
|
|
228
217
|
await emit({ type: "agent_end", messages: newMessages });
|
|
229
218
|
return;
|
|
230
219
|
}
|
|
220
|
+
// Give queue owners a boundary before preparation refreshes the drained
|
|
221
|
+
// snapshot, so a clear or replacement wins before admission.
|
|
222
|
+
await emit({ type: "turn_start" });
|
|
223
|
+
turnStartAlreadyEmitted = true;
|
|
231
224
|
}
|
|
232
225
|
let nextTurnSnapshot;
|
|
233
226
|
try {
|
|
234
227
|
nextTurnSnapshot = await config.prepareNextTurn?.(nextTurnContext);
|
|
235
228
|
}
|
|
236
229
|
catch (error) {
|
|
237
|
-
if (drainedTerminatingQueue)
|
|
230
|
+
if (drainedTerminatingQueue)
|
|
238
231
|
await config.restorePendingMessages?.(drainedTerminatingQueue, pendingMessages);
|
|
239
|
-
}
|
|
240
232
|
throw error;
|
|
241
233
|
}
|
|
242
234
|
if (nextTurnSnapshot) {
|
|
@@ -256,9 +248,8 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
256
248
|
};
|
|
257
249
|
}
|
|
258
250
|
if (signal?.aborted) {
|
|
259
|
-
if (drainedTerminatingQueue)
|
|
251
|
+
if (drainedTerminatingQueue)
|
|
260
252
|
await config.restorePendingMessages?.(drainedTerminatingQueue, pendingMessages);
|
|
261
|
-
}
|
|
262
253
|
await emit({ type: "agent_end", messages: newMessages });
|
|
263
254
|
return;
|
|
264
255
|
}
|
|
@@ -268,16 +259,7 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
268
259
|
await emit({ type: "agent_end", messages: newMessages });
|
|
269
260
|
return;
|
|
270
261
|
}
|
|
271
|
-
|
|
272
|
-
if (!toolBatchTerminated &&
|
|
273
|
-
(await config.shouldStopAfterTurn?.({
|
|
274
|
-
message,
|
|
275
|
-
toolResults,
|
|
276
|
-
context: currentContext,
|
|
277
|
-
newMessages,
|
|
278
|
-
}))) {
|
|
279
|
-
await emit({ type: "agent_end", messages: newMessages });
|
|
280
|
-
return;
|
|
262
|
+
drainedTerminatingQueue = undefined;
|
|
281
263
|
}
|
|
282
264
|
if (!toolBatchTerminated) {
|
|
283
265
|
pendingMessages = (await config.getSteeringMessages?.()) || [];
|
|
@@ -297,19 +279,10 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
297
279
|
}
|
|
298
280
|
/** Build the provider context using the same transform and conversion pipeline as an agent request. */
|
|
299
281
|
export async function buildProviderContext(context, config, signal) {
|
|
300
|
-
// Apply context transform if configured (AgentMessage[] → AgentMessage[])
|
|
301
282
|
let messages = context.messages;
|
|
302
|
-
if (config.transformContext)
|
|
283
|
+
if (config.transformContext)
|
|
303
284
|
messages = await config.transformContext(messages, signal);
|
|
304
|
-
}
|
|
305
|
-
// Convert to LLM-compatible messages (AgentMessage[] → Message[])
|
|
306
|
-
const llmMessages = await config.convertToLlm(messages);
|
|
307
|
-
// Build LLM context
|
|
308
|
-
return {
|
|
309
|
-
systemPrompt: context.systemPrompt,
|
|
310
|
-
messages: llmMessages,
|
|
311
|
-
tools: context.tools,
|
|
312
|
-
};
|
|
285
|
+
return { systemPrompt: context.systemPrompt, messages: await config.convertToLlm(messages), tools: context.tools };
|
|
313
286
|
}
|
|
314
287
|
/**
|
|
315
288
|
* Stream an assistant response from the LLM.
|
|
@@ -695,6 +668,7 @@ async function executeToolCallsSequential(currentContext, assistantMessage, tool
|
|
|
695
668
|
}
|
|
696
669
|
async function executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit) {
|
|
697
670
|
const finalizedCalls = [];
|
|
671
|
+
const preparedCalls = [];
|
|
698
672
|
let lastSequentialCall;
|
|
699
673
|
let currentParallelWave = [];
|
|
700
674
|
for (const toolCall of toolCalls) {
|
|
@@ -711,24 +685,44 @@ async function executeToolCallsParallel(currentContext, assistantMessage, toolCa
|
|
|
711
685
|
: lastSequentialCall
|
|
712
686
|
? [lastSequentialCall]
|
|
713
687
|
: [];
|
|
714
|
-
|
|
715
|
-
await Promise.all(dependencies);
|
|
716
|
-
const finalized = await runPreparedToolCall(currentContext, assistantMessage, preparation, config, signal, emit);
|
|
717
|
-
await emitToolExecutionEnd(finalized, emit);
|
|
718
|
-
return finalized;
|
|
719
|
-
})();
|
|
720
|
-
finalizedCalls.push(finalizedCall);
|
|
688
|
+
preparedCalls.push({ preparation, isSequential, dependencies });
|
|
721
689
|
if (isSequential) {
|
|
722
|
-
|
|
690
|
+
// Dependencies are assigned in the second phase after all preflight hooks
|
|
691
|
+
// have completed, so a later preflight abort vetoes every execution.
|
|
692
|
+
lastSequentialCall = undefined;
|
|
723
693
|
currentParallelWave = [];
|
|
724
694
|
}
|
|
725
695
|
else {
|
|
726
|
-
currentParallelWave.push(
|
|
696
|
+
currentParallelWave.push(Promise.resolve(undefined));
|
|
727
697
|
}
|
|
728
698
|
if (signal?.aborted) {
|
|
729
699
|
break;
|
|
730
700
|
}
|
|
731
701
|
}
|
|
702
|
+
let previousSequential;
|
|
703
|
+
let previousWave = [];
|
|
704
|
+
for (const { preparation, isSequential } of preparedCalls) {
|
|
705
|
+
const dependencies = isSequential
|
|
706
|
+
? [...(previousSequential ? [previousSequential] : []), ...previousWave]
|
|
707
|
+
: previousSequential
|
|
708
|
+
? [previousSequential]
|
|
709
|
+
: [];
|
|
710
|
+
const finalizedCall = (async () => {
|
|
711
|
+
await Promise.all(dependencies);
|
|
712
|
+
const finalized = signal?.aborted
|
|
713
|
+
? { toolCall: preparation.toolCall, result: createErrorToolResult("Operation aborted"), isError: true }
|
|
714
|
+
: await runPreparedToolCall(currentContext, assistantMessage, preparation, config, signal, emit);
|
|
715
|
+
await emitToolExecutionEnd(finalized, emit);
|
|
716
|
+
return finalized;
|
|
717
|
+
})();
|
|
718
|
+
finalizedCalls.push(finalizedCall);
|
|
719
|
+
if (isSequential) {
|
|
720
|
+
previousSequential = finalizedCall;
|
|
721
|
+
previousWave = [];
|
|
722
|
+
}
|
|
723
|
+
else
|
|
724
|
+
previousWave.push(finalizedCall);
|
|
725
|
+
}
|
|
732
726
|
const orderedFinalizedCalls = await Promise.all(finalizedCalls);
|
|
733
727
|
const messages = [];
|
|
734
728
|
for (const finalized of orderedFinalizedCalls) {
|