@aragon-agent/core 0.2.0 → 0.2.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/CHANGELOG.md +36 -0
- package/dist/engine/agent.d.ts +16 -0
- package/dist/engine/agent.js +19 -0
- package/dist/engine/watchdog.d.ts +17 -1
- package/dist/engine/watchdog.js +25 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,42 @@ All notable changes to `@aragon-agent/core` are documented here. Entries at
|
|
|
5
5
|
— those releases really were published under that name, so they are left as they
|
|
6
6
|
were written.
|
|
7
7
|
|
|
8
|
+
## 0.3.0
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`Agent.pauseIdleWatchdog()` / `Agent.resumeIdleWatchdog()`** — suspend and
|
|
13
|
+
restart the idle watchdog around a tool that blocks on a human. Both are
|
|
14
|
+
idempotent, and a paused watchdog also swallows `kick()`, so an event arriving
|
|
15
|
+
mid-wait cannot silently re-arm it. Always pair them in a `try/finally`: a
|
|
16
|
+
throw inside the wait must not leave the watchdog disarmed for the rest of the
|
|
17
|
+
run. The host is the only party that can know a person is being waited on —
|
|
18
|
+
from inside the loop that call is indistinguishable from a wedged network
|
|
19
|
+
request.
|
|
20
|
+
|
|
21
|
+
- **`AgentConfig.timeouts.toolTimeoutOverrides?: Record<string, number>`** —
|
|
22
|
+
per-tool ceilings keyed by tool name, forwarded to `ToolExecutor`'s existing
|
|
23
|
+
`timeoutOverrides`. This is pure wiring of a capability the executor already
|
|
24
|
+
had and that was unreachable through `Agent`.
|
|
25
|
+
|
|
26
|
+
Read this before relying on it: `ToolExecutor` expresses a timeout by aborting
|
|
27
|
+
`context.signal` and then *continuing to await* the tool's promise — there is
|
|
28
|
+
no `Promise.race`. A tool that never observes `context.signal` is therefore
|
|
29
|
+
never timed out, and the number set here is inert for it, with no error
|
|
30
|
+
anywhere. See *Blocking on a human* in `API.md`.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- `IdleWatchdog.stop()` now clears the paused flag. Without it a run aborted
|
|
35
|
+
while paused would leave the watchdog deaf for every subsequent run, because
|
|
36
|
+
`start()` goes through `kick()` and `kick()` returns early while paused.
|
|
37
|
+
|
|
38
|
+
### Notes
|
|
39
|
+
|
|
40
|
+
- **No change to the export surface.** The two new members are instance methods
|
|
41
|
+
and the third is a config field, so `src/index.ts` and the `EXPECTED` list in
|
|
42
|
+
`public-api.test.ts` are untouched.
|
|
43
|
+
|
|
8
44
|
## 0.2.0
|
|
9
45
|
|
|
10
46
|
### Breaking
|
package/dist/engine/agent.d.ts
CHANGED
|
@@ -37,6 +37,18 @@ export interface AgentConfig {
|
|
|
37
37
|
toolTimeout?: number;
|
|
38
38
|
/** Code execution timeout (ms). Default: 30_000 (30 s). */
|
|
39
39
|
codeTimeout?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Per-tool ceilings keyed by tool name, overriding `toolTimeout`.
|
|
42
|
+
*
|
|
43
|
+
* READ THIS BEFORE RELYING ON IT: `ToolExecutor` expresses a timeout by
|
|
44
|
+
* calling `controller.abort(...)` on the context signal and then continuing
|
|
45
|
+
* to `await` the tool's promise — there is no `Promise.race`. A tool that
|
|
46
|
+
* never observes `context.signal` is therefore never timed out, and any
|
|
47
|
+
* number set here is inert for it. Tools that must honour a ceiling have to
|
|
48
|
+
* subscribe to `context.signal` explicitly (see `bash-tool.ts` in the CLI
|
|
49
|
+
* package for the house pattern).
|
|
50
|
+
*/
|
|
51
|
+
toolTimeoutOverrides?: Record<string, number>;
|
|
40
52
|
};
|
|
41
53
|
}
|
|
42
54
|
export interface AgentState {
|
|
@@ -110,6 +122,10 @@ export declare class Agent {
|
|
|
110
122
|
replaceMessages(messages: Message[]): void;
|
|
111
123
|
/** Clear both steering and follow-up message queues. */
|
|
112
124
|
clearAllQueues(): void;
|
|
125
|
+
/** Suspend the idle watchdog (e.g. while a tool waits on a human). Idempotent. */
|
|
126
|
+
pauseIdleWatchdog(): void;
|
|
127
|
+
/** Resume the idle watchdog and restart its window from now. Idempotent. */
|
|
128
|
+
resumeIdleWatchdog(): void;
|
|
113
129
|
/**
|
|
114
130
|
* Emit an event to all listeners and kick the watchdog.
|
|
115
131
|
* Listener errors are caught and logged to prevent crashing the loop.
|
package/dist/engine/agent.js
CHANGED
|
@@ -67,6 +67,9 @@ export class Agent {
|
|
|
67
67
|
// Tool executor
|
|
68
68
|
this.toolExecutor = new ToolExecutor(this.toolRegistry, {
|
|
69
69
|
defaultTimeout: this.toolTimeout,
|
|
70
|
+
...(config.timeouts?.toolTimeoutOverrides
|
|
71
|
+
? { timeoutOverrides: config.timeouts.toolTimeoutOverrides }
|
|
72
|
+
: {}),
|
|
70
73
|
});
|
|
71
74
|
// Watchdog — on timeout, abort the agent
|
|
72
75
|
this.watchdog = new IdleWatchdog(this.idleTimeout, () => {
|
|
@@ -192,6 +195,22 @@ export class Agent {
|
|
|
192
195
|
this.messageQueueManager.clearAll();
|
|
193
196
|
}
|
|
194
197
|
// =========================================================================
|
|
198
|
+
// Idle watchdog control
|
|
199
|
+
//
|
|
200
|
+
// Public because only the HOST knows that a tool is blocked on a human. The
|
|
201
|
+
// engine sees an ordinary long-running tool call and would abort the run
|
|
202
|
+
// after `idleTimeout` — which is right for a wedged network call and wrong
|
|
203
|
+
// for a person reading a plan. Always pair these in a `try/finally`.
|
|
204
|
+
// =========================================================================
|
|
205
|
+
/** Suspend the idle watchdog (e.g. while a tool waits on a human). Idempotent. */
|
|
206
|
+
pauseIdleWatchdog() {
|
|
207
|
+
this.watchdog.pause();
|
|
208
|
+
}
|
|
209
|
+
/** Resume the idle watchdog and restart its window from now. Idempotent. */
|
|
210
|
+
resumeIdleWatchdog() {
|
|
211
|
+
this.watchdog.resume();
|
|
212
|
+
}
|
|
213
|
+
// =========================================================================
|
|
195
214
|
// Internal
|
|
196
215
|
// =========================================================================
|
|
197
216
|
/**
|
|
@@ -11,12 +11,28 @@ export declare class IdleWatchdog {
|
|
|
11
11
|
private readonly onTimeout;
|
|
12
12
|
private timerId;
|
|
13
13
|
private running;
|
|
14
|
+
private paused;
|
|
14
15
|
constructor(timeoutMs: number, onTimeout: () => void);
|
|
15
16
|
/** Reset the idle timer. Must be called on every Agent event. */
|
|
16
17
|
kick(): void;
|
|
17
18
|
/** Start the watchdog. Begins (or restarts) the idle timer. */
|
|
18
19
|
start(): void;
|
|
19
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Suspend the idle timer — e.g. while a tool blocks on a human answer.
|
|
22
|
+
* Idempotent. A paused watchdog swallows `kick()`, so an event arriving
|
|
23
|
+
* mid-wait cannot silently re-arm it.
|
|
24
|
+
*/
|
|
25
|
+
pause(): void;
|
|
26
|
+
/** Resume and restart the idle window from now. Idempotent. */
|
|
27
|
+
resume(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Stop the watchdog and cancel any pending timer.
|
|
30
|
+
*
|
|
31
|
+
* Clearing `paused` here is load-bearing: a run aborted while paused would
|
|
32
|
+
* otherwise leave the watchdog deaf for the NEXT run — `start()` calls
|
|
33
|
+
* `kick()`, and `kick()` returns early while paused — and nothing anywhere
|
|
34
|
+
* would report it.
|
|
35
|
+
*/
|
|
20
36
|
stop(): void;
|
|
21
37
|
/** Update the timeout duration. Takes effect on the next `kick()`. */
|
|
22
38
|
setTimeout(ms: number): void;
|
package/dist/engine/watchdog.js
CHANGED
|
@@ -11,13 +11,14 @@ export class IdleWatchdog {
|
|
|
11
11
|
onTimeout;
|
|
12
12
|
timerId = null;
|
|
13
13
|
running = false;
|
|
14
|
+
paused = false;
|
|
14
15
|
constructor(timeoutMs, onTimeout) {
|
|
15
16
|
this.timeoutMs = timeoutMs;
|
|
16
17
|
this.onTimeout = onTimeout;
|
|
17
18
|
}
|
|
18
19
|
/** Reset the idle timer. Must be called on every Agent event. */
|
|
19
20
|
kick() {
|
|
20
|
-
if (!this.running)
|
|
21
|
+
if (!this.running || this.paused)
|
|
21
22
|
return;
|
|
22
23
|
this.clearTimer();
|
|
23
24
|
this.timerId = setTimeout(() => {
|
|
@@ -29,9 +30,31 @@ export class IdleWatchdog {
|
|
|
29
30
|
this.running = true;
|
|
30
31
|
this.kick();
|
|
31
32
|
}
|
|
32
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Suspend the idle timer — e.g. while a tool blocks on a human answer.
|
|
35
|
+
* Idempotent. A paused watchdog swallows `kick()`, so an event arriving
|
|
36
|
+
* mid-wait cannot silently re-arm it.
|
|
37
|
+
*/
|
|
38
|
+
pause() {
|
|
39
|
+
this.paused = true;
|
|
40
|
+
this.clearTimer();
|
|
41
|
+
}
|
|
42
|
+
/** Resume and restart the idle window from now. Idempotent. */
|
|
43
|
+
resume() {
|
|
44
|
+
this.paused = false;
|
|
45
|
+
this.kick();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Stop the watchdog and cancel any pending timer.
|
|
49
|
+
*
|
|
50
|
+
* Clearing `paused` here is load-bearing: a run aborted while paused would
|
|
51
|
+
* otherwise leave the watchdog deaf for the NEXT run — `start()` calls
|
|
52
|
+
* `kick()`, and `kick()` returns early while paused — and nothing anywhere
|
|
53
|
+
* would report it.
|
|
54
|
+
*/
|
|
33
55
|
stop() {
|
|
34
56
|
this.running = false;
|
|
57
|
+
this.paused = false;
|
|
35
58
|
this.clearTimer();
|
|
36
59
|
}
|
|
37
60
|
/** Update the timeout duration. Takes effect on the next `kick()`. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "AragonAgent core engine — LLM provider adapters, streaming, tool registry/execution, steering, idle watchdog, and an optional isolated-vm sandbox.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AragonAgent contributors",
|