@ouro.bot/cli 0.1.0-alpha.868 → 0.1.0-alpha.869
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 +7 -0
- package/deploy/unraid/sanctuary-butler-upgrade.mjs +1 -1
- package/deploy/unraid/sanctuary-replay-gate.mjs +16 -10
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/senses/private-runtime.js +3 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
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.869",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Await ticks no longer inherit the last assistant text of the shared inner session as their checkpoint: a true note about one await (\"already archived as yes\") was handed to every later tick, so the replay await never checked its condition and the Butler's own awaits could be skipped the same way; an await now carries only its own last observation and check count.",
|
|
8
|
+
"Replay gate await case: the await has a name unique to the run, new awaits are told from archived ones by creation time instead of name alone, the readback reports the exact archive status and cancel reason, the case waits up to 8 minutes, and the replay window default is 45 minutes so it covers that wait."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.868",
|
|
6
13
|
"changes": [
|
|
@@ -74,7 +74,7 @@ const SHUTDOWN_FLAG = "/run/ouro-authority-shutdown"
|
|
|
74
74
|
const GATE_SCRIPT = `${ROOT}/package/deploy/unraid/sanctuary-replay-gate.mjs`
|
|
75
75
|
const GATE_PROVISION = `${BUNDLE}/state/replay-client/provision.json`
|
|
76
76
|
// The whole gate (every case, including the six-minute await wait) must finish well inside this; a hung gate is a failed gate.
|
|
77
|
-
export const GATE_TIMEOUT_MS =
|
|
77
|
+
export const GATE_TIMEOUT_MS = 60 * 60 * 1000
|
|
78
78
|
const UPGRADE_STEPS = ["stop", "switch", "resident", "migrate", "start"]
|
|
79
79
|
|
|
80
80
|
const sh = (file, args, opts = {}) => execFileSync(file, args, { encoding: "utf8", maxBuffer: 64 << 20, ...opts })
|
|
@@ -22,8 +22,10 @@ export const CONTAINER = "ouro-butler"
|
|
|
22
22
|
// The uid the A2A sense runs as inside the container; the trust probe must see the window exactly as that process does.
|
|
23
23
|
export const BUTLER_USER = "10001:10001"
|
|
24
24
|
export const CLI_ENTRY = "/opt/ouro/dist/heart/daemon/ouro-entry.js"
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// Long enough for every case at its slowest (five chat cases at up to 5.5 minutes each, plus the await case's 8 minute wait),
|
|
26
|
+
// and well inside the 2 hour cap: an await that has not resolved when the window closes is cancelled by the Butler.
|
|
27
|
+
export const DEFAULT_WINDOW_MINUTES = 45
|
|
28
|
+
export const AWAIT_TIMEOUT_MS = 8 * 60 * 1000
|
|
27
29
|
export const AWAIT_POLL_MS = 15 * 1000
|
|
28
30
|
export const MESSAGE_TIMEOUT_MS = 330 * 1000
|
|
29
31
|
const PEER_PROFILE = "sanctuary-agent-peer"
|
|
@@ -184,7 +186,9 @@ export const CASES = [
|
|
|
184
186
|
},
|
|
185
187
|
{
|
|
186
188
|
id: "await-self-resolve",
|
|
187
|
-
|
|
189
|
+
// A name unique to the run: an earlier run leaves an archived await of the same name behind, and the Butler's
|
|
190
|
+
// shared inner session remembers it.
|
|
191
|
+
words: ({ context }) => `file an await named replay_${context.slice(0, 8)} that resolves once the ouro-butler container is running, check every 1m, max 15m`,
|
|
188
192
|
sender: "principal",
|
|
189
193
|
// An await filed from a plain A2A chat has no request id, so the runtime cancels it as legacy provenance. Only a
|
|
190
194
|
// delegated principal command carries the follow-up authority an await needs.
|
|
@@ -198,7 +202,7 @@ export const CASES = [
|
|
|
198
202
|
const filed = newAwaits(before, after)
|
|
199
203
|
return [
|
|
200
204
|
check("an await was filed", filed.length > 0),
|
|
201
|
-
check("every new await was archived as resolved", filed.length > 0 && filed.every((entry) => entry.done && entry.status === "resolved"), filed.map((entry) => `${entry.name}:${entry.done ? entry.status : "pending"}`).join(",")),
|
|
205
|
+
check("every new await was archived as resolved", filed.length > 0 && filed.every((entry) => entry.done && entry.status === "resolved"), filed.map((entry) => `${entry.name}:${entry.done ? entry.status : "pending"}${entry.reason ? ` (${entry.reason})` : ""}`).join(",")),
|
|
202
206
|
check("its delivery went to the sink", sinkFor(sink, friends.principal, (line) => !isDelegatedNotice(line)).length > 0),
|
|
203
207
|
]
|
|
204
208
|
},
|
|
@@ -207,10 +211,11 @@ export const CASES = [
|
|
|
207
211
|
|
|
208
212
|
/** Awaits present after the case that were not present before it, with their archive state. */
|
|
209
213
|
export function newAwaits(before, after) {
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
+
// Name alone is not identity: an archived await from an earlier run can share a name with a new one.
|
|
215
|
+
const key = (entry) => `${entry.name}|${entry.createdAt ?? ""}`
|
|
216
|
+
const known = new Set([...before.awaiting, ...before.done].map(key))
|
|
217
|
+
const view = (entry, done) => ({ name: entry.name, done, status: entry.status, createdAt: entry.createdAt ?? "", reason: entry.reason ?? "" })
|
|
218
|
+
return [...after.awaiting.filter((entry) => !known.has(key(entry))).map((entry) => view(entry, false)), ...after.done.filter((entry) => !known.has(key(entry))).map((entry) => view(entry, true))]
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
// ---- orchestration (all I/O is behind `host`) --------------------------------------------------------------------
|
|
@@ -225,7 +230,8 @@ export async function runCase(host, testCase, { plant } = {}) {
|
|
|
225
230
|
return { id: testCase.id, status: "skipped", reason: skipReason, checks: [] }
|
|
226
231
|
}
|
|
227
232
|
const context = randomUUID()
|
|
228
|
-
const
|
|
233
|
+
const text = typeof testCase.words === "function" ? testCase.words({ context }) : testCase.words
|
|
234
|
+
const sent = await host.send({ who: testCase.sender, text, delegated: testCase.delegated, context })
|
|
229
235
|
let after = await host.observe()
|
|
230
236
|
if (testCase.poll) {
|
|
231
237
|
const deadline = host.now() + testCase.poll.timeoutMs
|
|
@@ -372,7 +378,7 @@ export function makeHost({ bundle = DEFAULT_BUNDLE, cardUrl, log = console.error
|
|
|
372
378
|
const list = (dir) => (existsSync(dir) ? readdirSync(dir) : [])
|
|
373
379
|
const awaitEntries = (dir) => list(dir).filter((name) => name.endsWith(".md")).map((name) => {
|
|
374
380
|
const text = readFileSync(path.join(dir, name), "utf8")
|
|
375
|
-
return { name, status: /^status:\s*(\S+)/m.exec(text)?.[1] ?? "pending" }
|
|
381
|
+
return { name, status: /^status:\s*(\S+)/m.exec(text)?.[1] ?? "pending", createdAt: /^created_at:\s*(\S+)/m.exec(text)?.[1] ?? "", reason: /^cancel_reason:\s*(.+)$/m.exec(text)?.[1]?.trim() ?? "" }
|
|
376
382
|
})
|
|
377
383
|
return {
|
|
378
384
|
friends: { principal: provisioned.principal.friendId, stranger: provisioned.stranger.friendId },
|
|
@@ -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.869</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
|
@@ -1191,7 +1191,9 @@ async function runPrivateRuntimeTurn(options) {
|
|
|
1191
1191
|
lastCheckedAt,
|
|
1192
1192
|
lastObservation,
|
|
1193
1193
|
checkedCount,
|
|
1194
|
-
checkpoint:
|
|
1194
|
+
// No checkpoint: every await shares one private-runtime session, so its last assistant text is whatever the previous
|
|
1195
|
+
// (possibly different) await's tick said. An await's own state is its last observation and checked count.
|
|
1196
|
+
checkpoint: undefined,
|
|
1195
1197
|
now,
|
|
1196
1198
|
});
|
|
1197
1199
|
}
|
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.869",
|
|
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.869",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|