@code-yeongyu/senpi-agent-core 2026.10.21-2 → 2026.10.23-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.
- package/dist/agent-loop.js +1 -1
- package/dist/agent.d.ts +4 -2
- package/dist/agent.js +4 -2
- package/dist/harness/compaction/compaction.js +3 -0
- package/dist/harness/pico3/harness.d.ts +5 -1
- package/dist/harness/pico3/harness.js +32 -14
- package/dist/harness/utils/usage.js +1 -0
- package/package.json +3 -3
package/dist/agent-loop.js
CHANGED
|
@@ -88,7 +88,7 @@ class StreamIdleTimeoutError extends Error {
|
|
|
88
88
|
// retried instead of dead-ending the session.
|
|
89
89
|
export class StreamStartTimeoutError extends Error {
|
|
90
90
|
constructor(timeoutMs) {
|
|
91
|
-
super(`Provider stream start timed out after ${timeoutMs}ms (raise streamStartTimeoutMs
|
|
91
|
+
super(`Provider stream start timed out after ${timeoutMs}ms (raise streamStartTimeoutMs: retry.provider.streamStartTimeoutMs in senpi settings; 0 disables)`);
|
|
92
92
|
this.name = "StreamStartTimeoutError";
|
|
93
93
|
}
|
|
94
94
|
}
|
package/dist/agent.d.ts
CHANGED
|
@@ -155,8 +155,10 @@ export declare class Agent {
|
|
|
155
155
|
clearAllQueues(): void;
|
|
156
156
|
/** Returns true when either queue still contains pending messages. */
|
|
157
157
|
hasQueuedMessages(): boolean;
|
|
158
|
-
/** Preview
|
|
159
|
-
peekQueuedMessages(
|
|
158
|
+
/** Preview next-turn messages, or both queues with { all: true }, without consuming them. */
|
|
159
|
+
peekQueuedMessages(options?: {
|
|
160
|
+
all?: boolean;
|
|
161
|
+
}): AgentMessage[];
|
|
160
162
|
/** Active abort signal for the current run, if any. */
|
|
161
163
|
get signal(): AbortSignal | undefined;
|
|
162
164
|
/** Abort the current run, if one is active. */
|
package/dist/agent.js
CHANGED
|
@@ -236,9 +236,11 @@ export class Agent {
|
|
|
236
236
|
hasQueuedMessages() {
|
|
237
237
|
return this.steeringQueue.hasItems() || this.followUpQueue.hasItems();
|
|
238
238
|
}
|
|
239
|
-
/** Preview
|
|
240
|
-
peekQueuedMessages() {
|
|
239
|
+
/** Preview next-turn messages, or both queues with { all: true }, without consuming them. */
|
|
240
|
+
peekQueuedMessages(options) {
|
|
241
241
|
const steering = this.steeringQueue.peek();
|
|
242
|
+
if (options?.all)
|
|
243
|
+
return [...steering, ...this.followUpQueue.peek()];
|
|
242
244
|
return steering.length > 0 ? steering : this.followUpQueue.peek();
|
|
243
245
|
}
|
|
244
246
|
/** Active abort signal for the current run, if any. */
|
|
@@ -79,6 +79,9 @@ export const DEFAULT_COMPACTION_SETTINGS = {
|
|
|
79
79
|
};
|
|
80
80
|
/** Calculate total context tokens from provider usage. */
|
|
81
81
|
export function calculateContextTokens(usage) {
|
|
82
|
+
if (usage.contextUsage !== undefined) {
|
|
83
|
+
return usage.contextUsage === null ? 0 : usage.contextUsage.input + usage.contextUsage.output;
|
|
84
|
+
}
|
|
82
85
|
return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
83
86
|
}
|
|
84
87
|
function getAssistantUsage(msg) {
|
|
@@ -96,7 +96,11 @@ export declare class Harness<Ks extends readonly AnyKind[] = []> {
|
|
|
96
96
|
private reconcileOrphans;
|
|
97
97
|
quiescent(): boolean;
|
|
98
98
|
hold(): () => void;
|
|
99
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Cancel and join in-process invocations, clear transient waits, then close without terminalizing tasks.
|
|
101
|
+
* The views and the session are closed even when joining or the waiting-state commit fails (a storage
|
|
102
|
+
* that refuses writes), so a failed suspend never leaks the session files; the first error is rethrown.
|
|
103
|
+
*/
|
|
100
104
|
suspend(ctx: Context): Promise<void>;
|
|
101
105
|
registerTaskKind<K extends AnyKind>(kind: K): () => void;
|
|
102
106
|
namespace<T extends JsonObject>(id: string, defaults: NamespaceDefaults<T>, opts?: {
|
|
@@ -266,26 +266,43 @@ export class Harness {
|
|
|
266
266
|
throw new Error("cannot hold a non-quiescent harness; suspend it instead");
|
|
267
267
|
return this.scheduler.hold();
|
|
268
268
|
}
|
|
269
|
-
/**
|
|
269
|
+
/**
|
|
270
|
+
* Cancel and join in-process invocations, clear transient waits, then close without terminalizing tasks.
|
|
271
|
+
* The views and the session are closed even when joining or the waiting-state commit fails (a storage
|
|
272
|
+
* that refuses writes), so a failed suspend never leaks the session files; the first error is rethrown.
|
|
273
|
+
*/
|
|
270
274
|
async suspend(ctx) {
|
|
271
275
|
if (this.suspended)
|
|
272
276
|
return;
|
|
273
277
|
this.suspended = true;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
278
|
+
let failure;
|
|
279
|
+
try {
|
|
280
|
+
await this.scheduler.joinAll();
|
|
281
|
+
const tools = [...this.session.liveTasks.values()].filter((task) => task.kind === "pi.tool");
|
|
282
|
+
if (tools.length > 0) {
|
|
283
|
+
const docs = [...new Set(tools.map((task) => task.conversationId))].map((conversationId) => ({ doc: "sticky", conversationId }));
|
|
284
|
+
await this.session.commit(KERNEL, (tx) => {
|
|
285
|
+
for (const task of tools) {
|
|
286
|
+
const index = task.input.index;
|
|
287
|
+
const slot = tx.sticky(task.conversationId).turn.tools[index];
|
|
288
|
+
if (slot?.waitingOn !== undefined)
|
|
289
|
+
delete slot.waitingOn;
|
|
290
|
+
}
|
|
291
|
+
}, ctx, { docs });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
failure = { error };
|
|
286
296
|
}
|
|
287
297
|
this.views.close();
|
|
288
|
-
|
|
298
|
+
try {
|
|
299
|
+
await this.session.close(ctx);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
failure ??= { error };
|
|
303
|
+
}
|
|
304
|
+
if (failure !== undefined)
|
|
305
|
+
throw failure.error;
|
|
289
306
|
}
|
|
290
307
|
// --- registries --------------------------------------------------------------
|
|
291
308
|
registerTaskKind(kind) {
|
|
@@ -317,6 +334,7 @@ export class Harness {
|
|
|
317
334
|
routes.set(key, doc);
|
|
318
335
|
}
|
|
319
336
|
}
|
|
337
|
+
// oxlint-disable-next-line eslint/prefer-const -- a closure reads it; const would throw in the TDZ if that closure ran before the assignment, so the rewrite is reviewed separately
|
|
320
338
|
let token;
|
|
321
339
|
token = {
|
|
322
340
|
id,
|
|
@@ -28,6 +28,7 @@ export function addUsage(left, right) {
|
|
|
28
28
|
cacheWrite: left.cost.cacheWrite + right.cost.cacheWrite,
|
|
29
29
|
total: left.cost.total + right.cost.total,
|
|
30
30
|
},
|
|
31
|
+
...(left.costUnknown || right.costUnknown ? { costUnknown: true } : {}),
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
//# sourceMappingURL=usage.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-agent-core",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.23-1",
|
|
4
4
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@earendil-works/chord": "0.99.1",
|
|
65
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.
|
|
66
|
-
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.
|
|
65
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.23-1",
|
|
66
|
+
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.23-1",
|
|
67
67
|
"diff": "9.0.0",
|
|
68
68
|
"ignore": "7.0.9",
|
|
69
69
|
"typebox": "1.3.34",
|