@ouro.bot/cli 0.1.0-alpha.869 → 0.1.0-alpha.870
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.json +6 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +7 -3
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/repertoire/tools-awaiting.js +33 -1
- package/dist/senses/await-turn-message.js +7 -1
- package/dist/senses/private-runtime.js +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.870",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Await ticks now say whether my owner was asked about this await (read from the runtime ask ledger for this await instance, never from model text) and that awaiting a decision is not true when they never were, and the ask_owner guidance counts a stall marked owner_decision_needed; media_queue marks confirmed stalls (no_peers, never_started, unfinished_for_days) with owner_decision_needed, likely_fix ask_owner and the keep_waiting, find_another_release, give_up choices shared with the diagnosis."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.869",
|
|
6
12
|
"changes": [
|
|
@@ -611,6 +611,9 @@ const rowPercent = (r) => ((r.size ?? 0) > 0 ? Math.round((((r.size ?? 0) - (r.s
|
|
|
611
611
|
// surfaces. `previous` is the persisted progress memory for this download (or undefined).
|
|
612
612
|
// Returns null while the download may still be moving; otherwise the kind, whether the stall
|
|
613
613
|
// is confirmed (only confirmed stalls are acted on) and the facts the owner is told.
|
|
614
|
+
// The owner's three choices when a download is confirmed dead; one source for every surface that asks.
|
|
615
|
+
export const STALL_OWNER_CHOICES = ["keep_waiting", "find_another_release", "give_up"]
|
|
616
|
+
|
|
614
617
|
export function classifyStall(row, nowMs, previous) {
|
|
615
618
|
const why = stallReason(row, nowMs, previous)
|
|
616
619
|
if (!why) return null
|
|
@@ -689,7 +692,7 @@ export function diagnose({ shelf, result, chain, entity, kind }) {
|
|
|
689
692
|
})
|
|
690
693
|
return { stuck_stage: "download", stuck_reason: "stalled_partial_download",
|
|
691
694
|
likely_fix: "ask_owner", human_action_required: true,
|
|
692
|
-
choices:
|
|
695
|
+
choices: STALL_OWNER_CHOICES,
|
|
693
696
|
percent_complete: result.download.percent_complete,
|
|
694
697
|
detail: items,
|
|
695
698
|
...(neverStarted.length ? { never_started: { likely_fix: "blocklist_and_research", items: neverStarted } } : {}),
|
|
@@ -762,7 +765,7 @@ async function mediaDiagnoseAndFix(a) {
|
|
|
762
765
|
}
|
|
763
766
|
if (action === "ask_owner") {
|
|
764
767
|
return { action, result: "owner_decision_needed", before, after: null, human_action_required: true,
|
|
765
|
-
choices: before.diagnosis?.choices ??
|
|
768
|
+
choices: before.diagnosis?.choices ?? STALL_OWNER_CHOICES,
|
|
766
769
|
...(before.diagnosis?.never_started ? { never_started: before.diagnosis.never_started } : {}),
|
|
767
770
|
human_action_reason: before.diagnosis?.summary ?? "The owner decides." }
|
|
768
771
|
}
|
|
@@ -939,7 +942,8 @@ export function queueRowView(r, nowMs, previous) {
|
|
|
939
942
|
percent: pct(r), timeleft: r.timeleft ?? null, size_left_bytes: r.sizeleft ?? 0, size_bytes: r.size ?? 0,
|
|
940
943
|
protocol: r.protocol ?? null, download_client: r.downloadClient ?? null, indexer: r.indexer ?? null,
|
|
941
944
|
added: r.added ?? null, stalled: Boolean(c?.confirmed),
|
|
942
|
-
...(c ? { stall: { kind: c.kind, state: c.state, percent_complete: c.percent_complete, age_hours: c.age_hours, no_eta: c.no_eta, unchanged_since: c.unchanged_since
|
|
945
|
+
...(c ? { stall: { kind: c.kind, state: c.state, percent_complete: c.percent_complete, age_hours: c.age_hours, no_eta: c.no_eta, unchanged_since: c.unchanged_since,
|
|
946
|
+
...(c.confirmed ? { owner_decision_needed: true, likely_fix: "ask_owner", choices: STALL_OWNER_CHOICES } : {}) } } : {}),
|
|
943
947
|
...(r.errorMessage ? { error_message: String(r.errorMessage).slice(0, 300) } : {}),
|
|
944
948
|
}
|
|
945
949
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0"?>
|
|
2
2
|
<Container version="2">
|
|
3
3
|
<Name>ouro-butler</Name>
|
|
4
|
-
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.
|
|
4
|
+
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.870</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
|
@@ -37,6 +37,7 @@ exports.awaitingToolDefinitions = void 0;
|
|
|
37
37
|
exports.readAwaitDefinition = readAwaitDefinition;
|
|
38
38
|
exports.setAwaitToolDeps = setAwaitToolDeps;
|
|
39
39
|
exports.resetAwaitToolDeps = resetAwaitToolDeps;
|
|
40
|
+
exports.readOwnerAskForAwait = readOwnerAskForAwait;
|
|
40
41
|
exports.cancelAwaitTool = cancelAwaitTool;
|
|
41
42
|
exports.cancelStaleAwait = cancelStaleAwait;
|
|
42
43
|
exports.isBrokenBindingReason = isBrokenBindingReason;
|
|
@@ -187,6 +188,37 @@ function recordAsk(agentRoot, entry) {
|
|
|
187
188
|
fs.mkdirSync(awaitingDir(agentRoot), { recursive: true });
|
|
188
189
|
fs.appendFileSync(askLedgerPath(agentRoot), `${JSON.stringify(entry)}\n`, "utf-8");
|
|
189
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* The most recent time the owner was asked about this await instance, read from the runtime ask ledger (never from model text).
|
|
193
|
+
* An instance is the await name filed at `createdAt`; an ask recorded before that belongs to an earlier use of the name.
|
|
194
|
+
*/
|
|
195
|
+
function readOwnerAskForAwait(agentRoot, name, createdAt) {
|
|
196
|
+
let raw;
|
|
197
|
+
try {
|
|
198
|
+
raw = fs.readFileSync(askLedgerPath(agentRoot), "utf-8");
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const createdMs = createdAt ? Date.parse(createdAt) : Number.NaN;
|
|
204
|
+
let found = null;
|
|
205
|
+
for (const line of raw.split("\n")) {
|
|
206
|
+
try {
|
|
207
|
+
const entry = JSON.parse(line);
|
|
208
|
+
if (entry.name !== name || typeof entry.at !== "string")
|
|
209
|
+
continue;
|
|
210
|
+
const atMs = Date.parse(entry.at);
|
|
211
|
+
if (!Number.isFinite(atMs) || (Number.isFinite(createdMs) && atMs < createdMs))
|
|
212
|
+
continue;
|
|
213
|
+
if (!found || atMs >= Date.parse(found.at))
|
|
214
|
+
found = { at: entry.at, question: typeof entry.question === "string" && entry.question.length > 0 ? entry.question : null };
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return found;
|
|
221
|
+
}
|
|
190
222
|
function recentAskCount(agentRoot, filer, now) {
|
|
191
223
|
let raw;
|
|
192
224
|
try {
|
|
@@ -286,7 +318,7 @@ async function askOwnerTool(name, observation, question, choices, existing, agen
|
|
|
286
318
|
/* v8 ignore next -- defensive: archiveAwait only fails on the file-disappears-mid-call race already covered by v8 ignore inside archiveAwait @preserve */
|
|
287
319
|
if (!archive.ok)
|
|
288
320
|
return JSON.stringify({ error: archive.error });
|
|
289
|
-
recordAsk(agentRoot, { filer: filerId, name, at: askedAt });
|
|
321
|
+
recordAsk(agentRoot, { filer: filerId, name, at: askedAt, question: parsed.question });
|
|
290
322
|
if (!tellsFriend || delivered(friendNotice))
|
|
291
323
|
fulfillAwaitObligation(agentRoot, archive.file);
|
|
292
324
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildAwaitTurnMessage = buildAwaitTurnMessage;
|
|
4
4
|
const runtime_1 = require("../nerves/runtime");
|
|
5
|
+
const WAITING_ON_OWNER = /\b(await(ing)?|wait(ing)?)\b[^.]{0,40}\b(ari|owner|decision|decide|choice)\b|\bdecision\b/i;
|
|
5
6
|
function formatElapsed(ms) {
|
|
6
7
|
if (ms < 60_000)
|
|
7
8
|
return "<1m ago";
|
|
@@ -48,12 +49,17 @@ function buildAwaitTurnMessage(options) {
|
|
|
48
49
|
lines.push("");
|
|
49
50
|
lines.push(`history: checked ${options.checkedCount}x so far. last checked ${age ?? "(unknown)"}. ${obs}.`);
|
|
50
51
|
}
|
|
52
|
+
const ask = options.ownerAsk ?? null;
|
|
53
|
+
lines.push(ask ? `owner asked: ${ask.at}${ask.question ? ` ("${ask.question}")` : ""}` : "owner asked: never");
|
|
54
|
+
if (!ask && options.lastObservation && WAITING_ON_OWNER.test(options.lastObservation)) {
|
|
55
|
+
lines.push("my owner has not been asked about this await, so \"awaiting a decision\" is not true. if the download is confirmed stalled, or media_queue marks it owner_decision_needed, ask now with verdict 'ask_owner'.");
|
|
56
|
+
}
|
|
51
57
|
if (options.checkpoint) {
|
|
52
58
|
lines.push("");
|
|
53
59
|
lines.push(`last checkpoint: ${options.checkpoint}`);
|
|
54
60
|
}
|
|
55
61
|
lines.push("");
|
|
56
62
|
lines.push("look around and decide. if the condition is met, call resolve_await with verdict='yes' and a one-line observation. otherwise call resolve_await with verdict='no' and a one-line observation of what i saw this tick.");
|
|
57
|
-
lines.push("verdicts: 'yes' (condition met), 'no' (not yet or unsure), 'ask_owner' (only when the condition cannot be met without my owner deciding, e.g. a confirmed dead download; give a plain question and 2-4 choices).");
|
|
63
|
+
lines.push("verdicts: 'yes' (condition met), 'no' (not yet or unsure), 'ask_owner' (only when the condition cannot be met without my owner deciding, e.g. a confirmed dead download, or a stall the tool marks owner_decision_needed; give a plain question and 2-4 choices).");
|
|
58
64
|
return lines.join("\n");
|
|
59
65
|
}
|
|
@@ -1194,6 +1194,7 @@ async function runPrivateRuntimeTurn(options) {
|
|
|
1194
1194
|
// No checkpoint: every await shares one private-runtime session, so its last assistant text is whatever the previous
|
|
1195
1195
|
// (possibly different) await's tick said. An await's own state is its last observation and checked count.
|
|
1196
1196
|
checkpoint: undefined,
|
|
1197
|
+
ownerAsk: (0, tools_awaiting_1.readOwnerAskForAwait)(agentRoot, awaitName, parsedAwait?.created_at ?? null),
|
|
1197
1198
|
now,
|
|
1198
1199
|
});
|
|
1199
1200
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.870",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@ouro.bot/cli",
|
|
9
|
-
"version": "0.1.0-alpha.
|
|
9
|
+
"version": "0.1.0-alpha.870",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|