@dougbots/avenor-core 0.5.1 → 0.6.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/README.md +3 -3
- package/dist/index.d.ts +8 -0
- package/dist/index.js +77 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Status values: `running`, `done`, `failed`, `timeout`, `killed`. If a permission
|
|
|
67
67
|
|
|
68
68
|
### `resultTool`
|
|
69
69
|
|
|
70
|
-
Waits for one run to finish and returns its
|
|
70
|
+
Waits for one run to finish and returns its complete final output without transcript or event details.
|
|
71
71
|
|
|
72
72
|
```ts
|
|
73
73
|
import { resultTool } from '@dougbots/avenor-core'
|
|
@@ -138,7 +138,7 @@ const { run_id } = await spawnTool({
|
|
|
138
138
|
label: 'security-review',
|
|
139
139
|
})
|
|
140
140
|
|
|
141
|
-
// 3. Wait for the
|
|
141
|
+
// 3. Wait for the complete final output
|
|
142
142
|
const result = await resultTool({ runId: run_id })
|
|
143
143
|
console.log(result) // { run_id, label, status: 'done', ready: true, output: '...' }
|
|
144
144
|
|
|
@@ -156,7 +156,7 @@ await shutdownTool()
|
|
|
156
156
|
| `findAvenorBinary` | function | Discover the avenor binary path |
|
|
157
157
|
| `spawnTool` | function | Start a new agent run |
|
|
158
158
|
| `statusTool` | function | Query run lifecycle status (single or all) |
|
|
159
|
-
| `resultTool` | function | Wait for and retrieve one run's
|
|
159
|
+
| `resultTool` | function | Wait for and retrieve one run's complete final output |
|
|
160
160
|
| `answerPermissionTool` | function | Answer a pending permission request |
|
|
161
161
|
| `followUpTool` | function | Resume a session with a follow-up prompt |
|
|
162
162
|
| `eventsTool` | function | Read recent events from a run's event log |
|
package/dist/index.d.ts
CHANGED
|
@@ -62,11 +62,13 @@ declare class Client {
|
|
|
62
62
|
events(options?: SubscribeOptions): AsyncIterableIterator<Event>;
|
|
63
63
|
history(options: HistoryOptions): Promise<HistoryResult>;
|
|
64
64
|
status(runtimeId?: string): Promise<Record<string, unknown>>;
|
|
65
|
+
result(runtimeId?: string): Promise<Record<string, unknown>>;
|
|
65
66
|
list(): Promise<Array<Record<string, unknown>>>;
|
|
66
67
|
spawn(params: SpawnParams): Promise<Record<string, unknown>>;
|
|
67
68
|
shutdown(mode: string): Promise<void>;
|
|
68
69
|
answerPermission(runtimeId: string, requestId: string, optionId: string): Promise<void>;
|
|
69
70
|
prompt(runtimeId: string, text: string): Promise<void>;
|
|
71
|
+
interruptAndPrompt(runtimeId: string, text: string, keepQueue?: boolean): Promise<void>;
|
|
70
72
|
cancel(runtimeId?: string): Promise<void>;
|
|
71
73
|
close(): void;
|
|
72
74
|
}
|
|
@@ -232,6 +234,9 @@ interface RunInfo {
|
|
|
232
234
|
eventLogPath: string;
|
|
233
235
|
runtimeId?: string;
|
|
234
236
|
sessionId?: string;
|
|
237
|
+
agent?: string;
|
|
238
|
+
backend?: string;
|
|
239
|
+
dir?: string;
|
|
235
240
|
brokerUrl?: string;
|
|
236
241
|
parentToken?: string;
|
|
237
242
|
}
|
|
@@ -318,6 +323,7 @@ interface StatusResult {
|
|
|
318
323
|
usage?: Record<string, unknown>;
|
|
319
324
|
latest_seq?: number;
|
|
320
325
|
final_output?: string;
|
|
326
|
+
final_output_truncated?: boolean;
|
|
321
327
|
}
|
|
322
328
|
declare function statusTool(args: {
|
|
323
329
|
runId?: string;
|
|
@@ -356,6 +362,8 @@ interface ResultResult {
|
|
|
356
362
|
stop_reason?: string;
|
|
357
363
|
pending_permission?: StatusResult['pending_permission'];
|
|
358
364
|
output?: string;
|
|
365
|
+
output_truncated?: boolean;
|
|
366
|
+
output_event_path?: string;
|
|
359
367
|
timed_out?: boolean;
|
|
360
368
|
}
|
|
361
369
|
interface ResultToolArgs {
|
package/dist/index.js
CHANGED
|
@@ -233,6 +233,10 @@ var Client = class {
|
|
|
233
233
|
const params = runtimeId ? { runtime_id: runtimeId } : void 0;
|
|
234
234
|
return this.call("status", params);
|
|
235
235
|
}
|
|
236
|
+
async result(runtimeId) {
|
|
237
|
+
const params = runtimeId ? { runtime_id: runtimeId } : void 0;
|
|
238
|
+
return this.call("result", params);
|
|
239
|
+
}
|
|
236
240
|
async list() {
|
|
237
241
|
return this.call("list");
|
|
238
242
|
}
|
|
@@ -255,6 +259,13 @@ var Client = class {
|
|
|
255
259
|
text
|
|
256
260
|
});
|
|
257
261
|
}
|
|
262
|
+
async interruptAndPrompt(runtimeId, text, keepQueue = false) {
|
|
263
|
+
await this.call("interrupt_and_prompt", {
|
|
264
|
+
runtime_id: runtimeId,
|
|
265
|
+
text,
|
|
266
|
+
keep_queue: keepQueue
|
|
267
|
+
});
|
|
268
|
+
}
|
|
258
269
|
async cancel(runtimeId) {
|
|
259
270
|
const params = runtimeId ? { runtime_id: runtimeId } : void 0;
|
|
260
271
|
await this.call("cancel", params);
|
|
@@ -1257,6 +1268,9 @@ var Supervisor = class Supervisor {
|
|
|
1257
1268
|
eventLogPath: result.on_event ?? eventLogPath,
|
|
1258
1269
|
runtimeId: result.runtime_id,
|
|
1259
1270
|
sessionId: result.session_id,
|
|
1271
|
+
agent: spawnParams.agent ?? params.agent,
|
|
1272
|
+
backend: spawnParams.backend,
|
|
1273
|
+
dir: spawnParams.dir,
|
|
1260
1274
|
brokerUrl: result.broker_url,
|
|
1261
1275
|
parentToken: result.parent_token
|
|
1262
1276
|
};
|
|
@@ -1497,7 +1511,8 @@ function buildBaseStatus(source, fallback, translatedStatus) {
|
|
|
1497
1511
|
event_path: stringField(source, "event_path", "on_event"),
|
|
1498
1512
|
usage: asRecord(source.usage) ?? void 0,
|
|
1499
1513
|
latest_seq: numberField(source, "latest_seq"),
|
|
1500
|
-
final_output: stringField(source, "final_output", "finalOutput")
|
|
1514
|
+
final_output: stringField(source, "final_output", "finalOutput"),
|
|
1515
|
+
...source.final_output_truncated === true && { final_output_truncated: true }
|
|
1501
1516
|
};
|
|
1502
1517
|
}
|
|
1503
1518
|
function shapeStatusResult(result, view = "full") {
|
|
@@ -1874,9 +1889,23 @@ function sleep(ms, signal) {
|
|
|
1874
1889
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1875
1890
|
});
|
|
1876
1891
|
}
|
|
1892
|
+
async function fullOutput(runtimeId, supervisorId) {
|
|
1893
|
+
if (supervisorId) {
|
|
1894
|
+
const { client, isSingleton } = await getSupervisorClient(supervisorId);
|
|
1895
|
+
try {
|
|
1896
|
+
const result = await client.result(runtimeId);
|
|
1897
|
+
return typeof result.final_output === "string" ? result.final_output : void 0;
|
|
1898
|
+
} finally {
|
|
1899
|
+
if (!isSingleton) client.close();
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
const result = await (await Supervisor.get()).getClient().result(runtimeId);
|
|
1903
|
+
return typeof result.final_output === "string" ? result.final_output : void 0;
|
|
1904
|
+
}
|
|
1877
1905
|
const defaultDeps = {
|
|
1878
1906
|
status: statusTool,
|
|
1879
1907
|
inspect: inspectTool,
|
|
1908
|
+
fullOutput,
|
|
1880
1909
|
sleep,
|
|
1881
1910
|
now: Date.now,
|
|
1882
1911
|
pollIntervalMs: DEFAULT_POLL_INTERVAL_MS
|
|
@@ -1893,6 +1922,8 @@ function toResult(status, timedOut = false) {
|
|
|
1893
1922
|
stop_reason: status.stop_reason,
|
|
1894
1923
|
pending_permission: status.pending_permission,
|
|
1895
1924
|
output: ready ? status.final_output : void 0,
|
|
1925
|
+
output_truncated: ready && status.final_output_truncated ? true : void 0,
|
|
1926
|
+
output_event_path: ready && status.final_output_truncated ? status.event_path : void 0,
|
|
1896
1927
|
timed_out: timedOut || void 0
|
|
1897
1928
|
};
|
|
1898
1929
|
}
|
|
@@ -1911,13 +1942,23 @@ async function executeResultTool(args, deps) {
|
|
|
1911
1942
|
const status = Array.isArray(raw) ? raw[0] : raw;
|
|
1912
1943
|
if (!status) throw new Error(`run not found: ${args.runId}`);
|
|
1913
1944
|
if (TERMINAL_STATUSES.has(status.status)) {
|
|
1914
|
-
|
|
1945
|
+
let exactOutputRetrieved = false;
|
|
1946
|
+
try {
|
|
1947
|
+
const output = await deps.fullOutput?.(status.runtime_id, args.supervisorId);
|
|
1948
|
+
if (output !== void 0) {
|
|
1949
|
+
status.final_output = output;
|
|
1950
|
+
status.final_output_truncated = false;
|
|
1951
|
+
exactOutputRetrieved = true;
|
|
1952
|
+
}
|
|
1953
|
+
} catch {}
|
|
1954
|
+
if (status.final_output === void 0) try {
|
|
1915
1955
|
const inspected = await deps.inspect({
|
|
1916
1956
|
runId: args.runId,
|
|
1917
1957
|
supervisorId: args.supervisorId
|
|
1918
1958
|
});
|
|
1919
1959
|
status.final_output = inspected.final_output ?? inspected.snapshot.final_output ?? inspected.snapshot.assistant_text;
|
|
1920
1960
|
} catch {}
|
|
1961
|
+
if (!exactOutputRetrieved && status.final_output !== void 0) status.final_output_truncated = true;
|
|
1921
1962
|
return toResult(status);
|
|
1922
1963
|
}
|
|
1923
1964
|
if (status.status === "waiting" || !wait) return toResult(status);
|
|
@@ -1970,6 +2011,10 @@ function findRunByLabel(sup, runId) {
|
|
|
1970
2011
|
if (byKey) return byKey;
|
|
1971
2012
|
for (const info of runs.values()) if (info.label === runId) return info;
|
|
1972
2013
|
}
|
|
2014
|
+
function requireResumableAgent(agent) {
|
|
2015
|
+
if (agent === void 0) throw new Error("run has no agent to resume");
|
|
2016
|
+
return agent;
|
|
2017
|
+
}
|
|
1973
2018
|
async function parseSentinel(filePath) {
|
|
1974
2019
|
try {
|
|
1975
2020
|
const content = (await fs.promises.readFile(filePath, "utf-8")).trim();
|
|
@@ -1990,28 +2035,36 @@ async function parseSentinel(filePath) {
|
|
|
1990
2035
|
}
|
|
1991
2036
|
async function followUpTool(args) {
|
|
1992
2037
|
if (args.supervisorId) {
|
|
1993
|
-
const { client, isSingleton } = await getSupervisorClient(args.supervisorId);
|
|
2038
|
+
const { client, isSingleton, sup } = await getSupervisorClient(args.supervisorId);
|
|
1994
2039
|
try {
|
|
1995
2040
|
validateRunId(args.runId);
|
|
2041
|
+
let runInfo;
|
|
2042
|
+
if (isSingleton && sup) runInfo = findRunByLabel(sup, args.runId);
|
|
2043
|
+
const fallbackSessionId = runInfo?.sessionId;
|
|
1996
2044
|
let liveStatus = null;
|
|
1997
2045
|
try {
|
|
1998
2046
|
liveStatus = await client.status(args.runId);
|
|
1999
2047
|
} catch {}
|
|
2000
|
-
const
|
|
2001
|
-
if (!
|
|
2002
|
-
const agent = liveStatus?.agent ??
|
|
2048
|
+
const sessionId = (await parseSentinel(liveStatus?.sentinel_file ?? path.join(runsRoot(), args.runId, "sentinel.done")))?.SESSION ?? liveStatus?.session_id ?? fallbackSessionId;
|
|
2049
|
+
if (!sessionId) throw new Error("run has no session to resume");
|
|
2050
|
+
const agent = requireResumableAgent(liveStatus?.agent ?? runInfo?.agent);
|
|
2051
|
+
const backend = liveStatus?.backend ?? runInfo?.backend;
|
|
2052
|
+
const dir = liveStatus?.dir ?? runInfo?.dir;
|
|
2003
2053
|
const followUpRunId = crypto.randomUUID();
|
|
2004
2054
|
const followUpLabel = args.label ?? `${args.runId}-followup`;
|
|
2005
2055
|
const { sentinelPath: followUpSentinelPath, eventLogPath } = ensureRunPaths(followUpRunId);
|
|
2056
|
+
const spawnParams = {
|
|
2057
|
+
agent,
|
|
2058
|
+
prompt: args.message,
|
|
2059
|
+
label: followUpLabel,
|
|
2060
|
+
session_id: sessionId,
|
|
2061
|
+
sentinel_file: followUpSentinelPath,
|
|
2062
|
+
on_event: eventLogPath
|
|
2063
|
+
};
|
|
2064
|
+
if (backend) spawnParams.backend = backend;
|
|
2065
|
+
if (dir) spawnParams.dir = dir;
|
|
2006
2066
|
return {
|
|
2007
|
-
run_id: (await client.spawn(
|
|
2008
|
-
agent,
|
|
2009
|
-
prompt: args.message,
|
|
2010
|
-
label: followUpLabel,
|
|
2011
|
-
session_id: sentinel.SESSION,
|
|
2012
|
-
sentinel_file: followUpSentinelPath,
|
|
2013
|
-
on_event: eventLogPath
|
|
2014
|
-
})).runtime_id ?? followUpRunId,
|
|
2067
|
+
run_id: (await client.spawn(spawnParams)).runtime_id ?? followUpRunId,
|
|
2015
2068
|
label: followUpLabel
|
|
2016
2069
|
};
|
|
2017
2070
|
} finally {
|
|
@@ -2021,18 +2074,23 @@ async function followUpTool(args) {
|
|
|
2021
2074
|
const sup = await Supervisor.get();
|
|
2022
2075
|
const runInfo = findRunByLabel(sup, args.runId);
|
|
2023
2076
|
if (!runInfo) throw new Error(`run not found: ${args.runId}`);
|
|
2024
|
-
const
|
|
2025
|
-
if (!
|
|
2077
|
+
const sessionId = (await parseSentinel(runInfo.sentinelPath))?.SESSION ?? runInfo.sessionId;
|
|
2078
|
+
if (!sessionId) throw new Error("run has no session to resume");
|
|
2026
2079
|
const client = sup.getClient();
|
|
2027
|
-
let
|
|
2080
|
+
let liveStatus = null;
|
|
2028
2081
|
if (runInfo.runtimeId) try {
|
|
2029
|
-
|
|
2082
|
+
liveStatus = await client.status(runInfo.runtimeId);
|
|
2030
2083
|
} catch {}
|
|
2084
|
+
const agent = requireResumableAgent(liveStatus?.agent ?? runInfo.agent);
|
|
2085
|
+
const backend = liveStatus?.backend ?? runInfo.backend;
|
|
2086
|
+
const dir = liveStatus?.dir ?? runInfo.dir;
|
|
2031
2087
|
const followUpLabel = args.label ?? `${runInfo.label}-followup`;
|
|
2032
2088
|
const followUpRun = await sup.spawn({
|
|
2033
2089
|
agent,
|
|
2090
|
+
backend,
|
|
2091
|
+
dir,
|
|
2034
2092
|
prompt: args.message,
|
|
2035
|
-
session_id:
|
|
2093
|
+
session_id: sessionId,
|
|
2036
2094
|
label: followUpLabel
|
|
2037
2095
|
});
|
|
2038
2096
|
return {
|