@ouro.bot/cli 0.1.0-alpha.673 → 0.1.0-alpha.675
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 +11 -5
- package/changelog.json +19 -0
- package/dist/arc/evolution.js +13 -10
- package/dist/arc/obligations.js +1 -1
- package/dist/heart/active-work.js +3 -3
- package/dist/heart/agent-entry.js +8 -8
- package/dist/heart/commitments.js +1 -1
- package/dist/heart/core.js +45 -23
- package/dist/heart/daemon/agent-config-check.js +24 -0
- package/dist/heart/daemon/agent-discovery.js +50 -0
- package/dist/heart/daemon/agent-service.js +6 -6
- package/dist/heart/daemon/await-private-wake.js +59 -0
- package/dist/heart/daemon/cli-exec.js +180 -24
- package/dist/heart/daemon/cli-help.js +20 -2
- package/dist/heart/daemon/cli-parse.js +45 -2
- package/dist/heart/daemon/cli-render.js +1 -0
- package/dist/heart/daemon/daemon-entry.js +126 -19
- package/dist/heart/daemon/daemon.js +223 -20
- package/dist/heart/daemon/habit-private-wake.js +56 -0
- package/dist/heart/daemon/health-monitor.js +6 -2
- package/dist/heart/daemon/inner-status.js +3 -3
- package/dist/heart/daemon/message-router.js +39 -3
- package/dist/heart/daemon/process-manager.js +1 -0
- package/dist/heart/daemon/pulse.js +43 -7
- package/dist/heart/daemon/socket-client.js +14 -2
- package/dist/heart/daemon/startup-tui.js +9 -1
- package/dist/heart/daemon/thoughts.js +39 -39
- package/dist/heart/habits/habit-scheduler.js +24 -4
- package/dist/heart/mailbox/mailbox-view.js +1 -1
- package/dist/heart/mailbox/readers/agent-machine.js +7 -7
- package/dist/heart/primitives.js +1 -1
- package/dist/heart/private-runtime/decision-renderer.js +156 -0
- package/dist/heart/private-runtime/index.js +18 -0
- package/dist/heart/private-runtime/ledger.js +218 -0
- package/dist/heart/private-runtime/policy.js +205 -0
- package/dist/heart/private-runtime/types.js +2 -0
- package/dist/heart/progress-story.js +1 -1
- package/dist/heart/session-transcript.js +1 -1
- package/dist/heart/tool-activity-callbacks.js +1 -1
- package/dist/heart/tool-description.js +2 -2
- package/dist/heart/tool-loop.js +2 -2
- package/dist/heart/turn-context.js +5 -5
- package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
- package/dist/mailbox-ui/index.html +1 -1
- package/dist/mailroom/attention.js +1 -1
- package/dist/mind/context.js +2 -2
- package/dist/mind/pending.js +12 -5
- package/dist/mind/prompt.js +32 -25
- package/dist/repertoire/coding/feedback.js +25 -4
- package/dist/repertoire/tools-awaiting.js +2 -2
- package/dist/repertoire/tools-flow.js +4 -4
- package/dist/repertoire/tools-record.js +1 -1
- package/dist/repertoire/tools-session.js +33 -58
- package/dist/repertoire/tools-surface.js +3 -3
- package/dist/senses/cli.js +2 -2
- package/dist/senses/inner-dialog-worker.js +13 -519
- package/dist/senses/inner-dialog.js +10 -961
- package/dist/senses/mail.js +21 -5
- package/dist/senses/pipeline.js +1 -1
- package/dist/senses/private-runtime-worker.js +578 -0
- package/dist/senses/private-runtime.js +1145 -0
- package/dist/senses/shared-turn.js +1 -1
- package/dist/senses/trust-gate.js +2 -2
- package/package.json +1 -1
- package/dist/mailbox-ui/assets/index-CaTIFDmv.js +0 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizePrivateDecision = sanitizePrivateDecision;
|
|
4
|
+
exports.buildPrivateDecisionReadPayload = buildPrivateDecisionReadPayload;
|
|
5
|
+
exports.privateDecisionReadPayloadFromDaemonData = privateDecisionReadPayloadFromDaemonData;
|
|
6
|
+
exports.privateDecisionCountSummary = privateDecisionCountSummary;
|
|
7
|
+
exports.formatPrivateDecisionReadText = formatPrivateDecisionReadText;
|
|
8
|
+
exports.formatPrivateDecisionReadJson = formatPrivateDecisionReadJson;
|
|
9
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
10
|
+
function stringField(value, fallback = "") {
|
|
11
|
+
return typeof value === "string" ? value : fallback;
|
|
12
|
+
}
|
|
13
|
+
function booleanField(value) {
|
|
14
|
+
return typeof value === "boolean" ? value : false;
|
|
15
|
+
}
|
|
16
|
+
function originRefsField(value) {
|
|
17
|
+
if (!Array.isArray(value))
|
|
18
|
+
return [];
|
|
19
|
+
return value.flatMap((entry) => {
|
|
20
|
+
if (!entry
|
|
21
|
+
|| typeof entry !== "object"
|
|
22
|
+
|| Array.isArray(entry)
|
|
23
|
+
|| typeof entry.kind !== "string"
|
|
24
|
+
|| typeof entry.id !== "string") {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const row = entry;
|
|
28
|
+
return [{ kind: row.kind, id: row.id }];
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function providerLaneField(value) {
|
|
32
|
+
const row = value && typeof value === "object" && !Array.isArray(value)
|
|
33
|
+
? value
|
|
34
|
+
: {};
|
|
35
|
+
return {
|
|
36
|
+
lane: stringField(row.lane, "inner"),
|
|
37
|
+
provider: stringField(row.provider, "unknown"),
|
|
38
|
+
model: stringField(row.model, "unknown"),
|
|
39
|
+
source: "agent.json",
|
|
40
|
+
...(typeof row.credentialRevision === "string" ? { credentialRevision: row.credentialRevision } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function ledgerLocatorField(value, ledgerPath) {
|
|
44
|
+
const row = value && typeof value === "object" && !Array.isArray(value)
|
|
45
|
+
? value
|
|
46
|
+
: {};
|
|
47
|
+
return {
|
|
48
|
+
path: stringField(row.path, ledgerPath ?? ""),
|
|
49
|
+
...(typeof row.line === "number" ? { line: row.line } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function resultField(value) {
|
|
53
|
+
return value === "allow" ? "allow" : "deny";
|
|
54
|
+
}
|
|
55
|
+
function sanitizePrivateDecision(row, ledgerPath) {
|
|
56
|
+
const record = row && typeof row === "object" && !Array.isArray(row)
|
|
57
|
+
? row
|
|
58
|
+
: {};
|
|
59
|
+
const deniedReason = stringField(record.deniedReason);
|
|
60
|
+
const duplicateOf = stringField(record.duplicateOf);
|
|
61
|
+
const error = stringField(record.error);
|
|
62
|
+
return {
|
|
63
|
+
schemaVersion: 1,
|
|
64
|
+
receiptId: stringField(record.receiptId),
|
|
65
|
+
agent: stringField(record.agent),
|
|
66
|
+
origin: stringField(record.origin),
|
|
67
|
+
reason: stringField(record.reason),
|
|
68
|
+
providerLane: providerLaneField(record.providerLane),
|
|
69
|
+
triggerSource: stringField(record.triggerSource),
|
|
70
|
+
idempotencyKey: stringField(record.idempotencyKey),
|
|
71
|
+
budgetClass: stringField(record.budgetClass),
|
|
72
|
+
originRefs: originRefsField(record.originRefs),
|
|
73
|
+
requestFingerprint: stringField(record.requestFingerprint),
|
|
74
|
+
result: resultField(record.result),
|
|
75
|
+
executable: booleanField(record.executable),
|
|
76
|
+
decidedAt: stringField(record.decidedAt),
|
|
77
|
+
ledgerLocator: ledgerLocatorField(record.ledgerLocator, ledgerPath),
|
|
78
|
+
...(deniedReason ? { deniedReason } : {}),
|
|
79
|
+
...(duplicateOf ? { duplicateOf } : {}),
|
|
80
|
+
...(error ? { error } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function decisionSortKey(decision) {
|
|
84
|
+
return decision.decidedAt || `${decision.ledgerLocator.line ?? 0}`.padStart(12, "0");
|
|
85
|
+
}
|
|
86
|
+
function sortedRecentDecisions(decisions, limit) {
|
|
87
|
+
return [...decisions]
|
|
88
|
+
.sort((a, b) => decisionSortKey(b).localeCompare(decisionSortKey(a)))
|
|
89
|
+
.slice(0, limit);
|
|
90
|
+
}
|
|
91
|
+
function buildPrivateDecisionReadPayload(input) {
|
|
92
|
+
const limit = Number.isInteger(input.limit) && input.limit && input.limit > 0 ? input.limit : input.decisions.length;
|
|
93
|
+
const decisions = sortedRecentDecisions(input.decisions.map((row) => sanitizePrivateDecision(row, input.ledgerPath)), limit);
|
|
94
|
+
(0, runtime_1.emitNervesEvent)({
|
|
95
|
+
component: "private-runtime",
|
|
96
|
+
event: "private_runtime.decision_read_payload_built",
|
|
97
|
+
message: "private-runtime decision read payload built",
|
|
98
|
+
meta: { agent: input.agent, count: decisions.length, hasLedgerPath: !!input.ledgerPath },
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
agent: input.agent,
|
|
102
|
+
...(input.ledgerPath ? { ledgerPath: input.ledgerPath } : {}),
|
|
103
|
+
decisions,
|
|
104
|
+
...(input.guidance ? { guidance: input.guidance } : {}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function privateDecisionReadPayloadFromDaemonData(data, fallbackAgent) {
|
|
108
|
+
const record = data && typeof data === "object" && !Array.isArray(data)
|
|
109
|
+
? data
|
|
110
|
+
: {};
|
|
111
|
+
const ledgerPath = stringField(record.ledgerPath);
|
|
112
|
+
const guidance = stringField(record.guidance);
|
|
113
|
+
return buildPrivateDecisionReadPayload({
|
|
114
|
+
agent: stringField(record.agent, fallbackAgent),
|
|
115
|
+
decisions: Array.isArray(record.decisions) ? record.decisions : [],
|
|
116
|
+
...(ledgerPath ? { ledgerPath } : {}),
|
|
117
|
+
...(guidance ? { guidance } : {}),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function privateDecisionCountSummary(count) {
|
|
121
|
+
return `${count} private-runtime ${count === 1 ? "decision" : "decisions"}`;
|
|
122
|
+
}
|
|
123
|
+
function decisionReason(decision) {
|
|
124
|
+
return decision.deniedReason || decision.reason || "(no reason recorded)";
|
|
125
|
+
}
|
|
126
|
+
function formatLocator(locator) {
|
|
127
|
+
const line = locator.line === undefined ? "" : `:${locator.line}`;
|
|
128
|
+
return `${locator.path}${line}`;
|
|
129
|
+
}
|
|
130
|
+
function formatPrivateDecisionReadText(payload) {
|
|
131
|
+
const lines = [`private decisions: ${payload.agent}`];
|
|
132
|
+
if (payload.ledgerPath)
|
|
133
|
+
lines.push(`ledger: ${payload.ledgerPath}`);
|
|
134
|
+
if (payload.guidance)
|
|
135
|
+
lines.push(`guidance: ${payload.guidance}`);
|
|
136
|
+
if (payload.decisions.length === 0) {
|
|
137
|
+
lines.push("no private-runtime decisions found");
|
|
138
|
+
return lines.join("\n");
|
|
139
|
+
}
|
|
140
|
+
for (const decision of payload.decisions) {
|
|
141
|
+
lines.push([
|
|
142
|
+
`- ${decision.decidedAt || "undated"}`,
|
|
143
|
+
decision.result,
|
|
144
|
+
decision.origin,
|
|
145
|
+
`key=${decision.idempotencyKey}`,
|
|
146
|
+
`lane=${decision.providerLane.lane}`,
|
|
147
|
+
`receipt=${decision.receiptId}`,
|
|
148
|
+
`reason=${decisionReason(decision)}`,
|
|
149
|
+
`locator=${formatLocator(decision.ledgerLocator)}`,
|
|
150
|
+
].join(" "));
|
|
151
|
+
}
|
|
152
|
+
return lines.join("\n");
|
|
153
|
+
}
|
|
154
|
+
function formatPrivateDecisionReadJson(payload) {
|
|
155
|
+
return JSON.stringify(payload, null, 2);
|
|
156
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizePrivateDecision = exports.privateDecisionReadPayloadFromDaemonData = exports.privateDecisionCountSummary = exports.formatPrivateDecisionReadText = exports.formatPrivateDecisionReadJson = exports.buildPrivateDecisionReadPayload = exports.recordPrivateTurnDecision = exports.readPrivateTurnLedger = exports.privateTurnLedgerPath = exports.requestPrivateTurnDecision = exports.createPrivateTurnRequestFingerprint = exports.createPrivateTurnIdempotencyKey = void 0;
|
|
4
|
+
var policy_1 = require("./policy");
|
|
5
|
+
Object.defineProperty(exports, "createPrivateTurnIdempotencyKey", { enumerable: true, get: function () { return policy_1.createPrivateTurnIdempotencyKey; } });
|
|
6
|
+
Object.defineProperty(exports, "createPrivateTurnRequestFingerprint", { enumerable: true, get: function () { return policy_1.createPrivateTurnRequestFingerprint; } });
|
|
7
|
+
Object.defineProperty(exports, "requestPrivateTurnDecision", { enumerable: true, get: function () { return policy_1.requestPrivateTurnDecision; } });
|
|
8
|
+
var ledger_1 = require("./ledger");
|
|
9
|
+
Object.defineProperty(exports, "privateTurnLedgerPath", { enumerable: true, get: function () { return ledger_1.privateTurnLedgerPath; } });
|
|
10
|
+
Object.defineProperty(exports, "readPrivateTurnLedger", { enumerable: true, get: function () { return ledger_1.readPrivateTurnLedger; } });
|
|
11
|
+
Object.defineProperty(exports, "recordPrivateTurnDecision", { enumerable: true, get: function () { return ledger_1.recordPrivateTurnDecision; } });
|
|
12
|
+
var decision_renderer_1 = require("./decision-renderer");
|
|
13
|
+
Object.defineProperty(exports, "buildPrivateDecisionReadPayload", { enumerable: true, get: function () { return decision_renderer_1.buildPrivateDecisionReadPayload; } });
|
|
14
|
+
Object.defineProperty(exports, "formatPrivateDecisionReadJson", { enumerable: true, get: function () { return decision_renderer_1.formatPrivateDecisionReadJson; } });
|
|
15
|
+
Object.defineProperty(exports, "formatPrivateDecisionReadText", { enumerable: true, get: function () { return decision_renderer_1.formatPrivateDecisionReadText; } });
|
|
16
|
+
Object.defineProperty(exports, "privateDecisionCountSummary", { enumerable: true, get: function () { return decision_renderer_1.privateDecisionCountSummary; } });
|
|
17
|
+
Object.defineProperty(exports, "privateDecisionReadPayloadFromDaemonData", { enumerable: true, get: function () { return decision_renderer_1.privateDecisionReadPayloadFromDaemonData; } });
|
|
18
|
+
Object.defineProperty(exports, "sanitizePrivateDecision", { enumerable: true, get: function () { return decision_renderer_1.sanitizePrivateDecision; } });
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.privateTurnLedgerPath = privateTurnLedgerPath;
|
|
37
|
+
exports.readPrivateTurnLedger = readPrivateTurnLedger;
|
|
38
|
+
exports.recordPrivateTurnDecision = recordPrivateTurnDecision;
|
|
39
|
+
const fs = __importStar(require("node:fs"));
|
|
40
|
+
const crypto = __importStar(require("node:crypto"));
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const identity_1 = require("../identity");
|
|
43
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
44
|
+
const DEFAULT_LEDGER_DIR = "private-runtime";
|
|
45
|
+
const DEFAULT_LEDGER_FILE = "decisions.jsonl";
|
|
46
|
+
function emitDecisionRecorded(deps, input) {
|
|
47
|
+
const payload = {
|
|
48
|
+
level: input.level,
|
|
49
|
+
component: "private-runtime",
|
|
50
|
+
event: "private_runtime.decision_recorded",
|
|
51
|
+
message: "private-runtime decision recorded",
|
|
52
|
+
meta: {
|
|
53
|
+
agent: input.decision.agent,
|
|
54
|
+
origin: input.decision.origin,
|
|
55
|
+
result: input.decision.result,
|
|
56
|
+
idempotencyKey: input.decision.idempotencyKey,
|
|
57
|
+
requestFingerprint: input.decision.requestFingerprint,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
if (deps?.emitNervesEvent) {
|
|
61
|
+
deps.emitNervesEvent(payload);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
(0, runtime_1.emitNervesEvent)({
|
|
65
|
+
level: input.level,
|
|
66
|
+
component: "private-runtime",
|
|
67
|
+
event: "private_runtime.decision_recorded",
|
|
68
|
+
message: "private-runtime decision recorded",
|
|
69
|
+
meta: payload.meta,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function emitDecisionRecordFailed(deps, input) {
|
|
73
|
+
const payload = {
|
|
74
|
+
level: "error",
|
|
75
|
+
component: "private-runtime",
|
|
76
|
+
event: "private_runtime.decision_record_failed",
|
|
77
|
+
message: "private-runtime decision ledger write failed",
|
|
78
|
+
meta: {
|
|
79
|
+
agent: input.decision.agent,
|
|
80
|
+
origin: input.decision.origin,
|
|
81
|
+
idempotencyKey: input.decision.idempotencyKey,
|
|
82
|
+
requestFingerprint: input.decision.requestFingerprint,
|
|
83
|
+
error: input.decision.error,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
if (deps?.emitNervesEvent) {
|
|
87
|
+
deps.emitNervesEvent(payload);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
(0, runtime_1.emitNervesEvent)({
|
|
91
|
+
level: "error",
|
|
92
|
+
component: "private-runtime",
|
|
93
|
+
event: "private_runtime.decision_record_failed",
|
|
94
|
+
message: "private-runtime decision ledger write failed",
|
|
95
|
+
meta: payload.meta,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function privateTurnLedgerPath(agent, deps = {}) {
|
|
99
|
+
if (deps.ledgerPath)
|
|
100
|
+
return deps.ledgerPath;
|
|
101
|
+
return path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${agent}.ouro`, "state", DEFAULT_LEDGER_DIR, DEFAULT_LEDGER_FILE);
|
|
102
|
+
}
|
|
103
|
+
function readRows(ledgerPath) {
|
|
104
|
+
if (!fs.existsSync(ledgerPath))
|
|
105
|
+
return [];
|
|
106
|
+
const raw = fs.readFileSync(ledgerPath, "utf-8").trim();
|
|
107
|
+
if (!raw)
|
|
108
|
+
return [];
|
|
109
|
+
return raw.split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
110
|
+
}
|
|
111
|
+
function writeRow(ledgerPath, row) {
|
|
112
|
+
const rowWithLocator = {
|
|
113
|
+
...row,
|
|
114
|
+
ledgerLocator: {
|
|
115
|
+
path: ledgerPath,
|
|
116
|
+
line: readRows(ledgerPath).length + 1,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
fs.appendFileSync(ledgerPath, `${JSON.stringify(rowWithLocator)}\n`, "utf-8");
|
|
120
|
+
return rowWithLocator;
|
|
121
|
+
}
|
|
122
|
+
function receiptIdFor(input) {
|
|
123
|
+
const hash = crypto
|
|
124
|
+
.createHash("sha256")
|
|
125
|
+
.update(`${input.idempotencyKey}\n${input.requestFingerprint}\n${input.result}`)
|
|
126
|
+
.digest("hex");
|
|
127
|
+
return `ptrr_${hash}`;
|
|
128
|
+
}
|
|
129
|
+
function mismatchDecision(candidate, existing) {
|
|
130
|
+
return {
|
|
131
|
+
...candidate,
|
|
132
|
+
receiptId: receiptIdFor({
|
|
133
|
+
idempotencyKey: candidate.idempotencyKey,
|
|
134
|
+
requestFingerprint: candidate.requestFingerprint,
|
|
135
|
+
result: "mismatch",
|
|
136
|
+
}),
|
|
137
|
+
result: "deny",
|
|
138
|
+
executable: false,
|
|
139
|
+
deniedReason: "idempotency-key fingerprint mismatch",
|
|
140
|
+
duplicateOf: existing.receiptId,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function duplicateDecision(existing) {
|
|
144
|
+
return {
|
|
145
|
+
...existing,
|
|
146
|
+
executable: false,
|
|
147
|
+
deniedReason: "duplicate private-turn decision already recorded",
|
|
148
|
+
duplicateOf: existing.receiptId,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function ledgerWriteFailedDecision(candidate, ledgerPath, error) {
|
|
152
|
+
return {
|
|
153
|
+
...candidate,
|
|
154
|
+
receiptId: receiptIdFor({
|
|
155
|
+
idempotencyKey: candidate.idempotencyKey,
|
|
156
|
+
requestFingerprint: candidate.requestFingerprint,
|
|
157
|
+
result: "ledger-write-failed",
|
|
158
|
+
}),
|
|
159
|
+
result: "deny",
|
|
160
|
+
executable: false,
|
|
161
|
+
deniedReason: "ledger write failed",
|
|
162
|
+
ledgerLocator: { path: ledgerPath },
|
|
163
|
+
error: String(error),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function readPrivateTurnLedger(ledgerPath) {
|
|
167
|
+
return readRows(ledgerPath);
|
|
168
|
+
}
|
|
169
|
+
function recordPrivateTurnDecision(decision, deps = {}) {
|
|
170
|
+
const ledgerPath = privateTurnLedgerPath(decision.agent, deps);
|
|
171
|
+
if (!deps.ledgerPath) {
|
|
172
|
+
fs.mkdirSync(path.dirname(ledgerPath), { recursive: true });
|
|
173
|
+
}
|
|
174
|
+
const candidate = {
|
|
175
|
+
...decision,
|
|
176
|
+
receiptId: decision.receiptId || receiptIdFor(decision),
|
|
177
|
+
ledgerLocator: { path: ledgerPath },
|
|
178
|
+
};
|
|
179
|
+
try {
|
|
180
|
+
const matchingRows = readRows(ledgerPath).filter((row) => row.idempotencyKey === candidate.idempotencyKey);
|
|
181
|
+
const anchor = matchingRows[0];
|
|
182
|
+
if (anchor) {
|
|
183
|
+
if (anchor.requestFingerprint !== candidate.requestFingerprint) {
|
|
184
|
+
const mismatch = mismatchDecision(candidate, anchor);
|
|
185
|
+
const writtenMismatch = writeRow(ledgerPath, mismatch);
|
|
186
|
+
emitDecisionRecorded(deps, { level: "warn", decision: writtenMismatch });
|
|
187
|
+
return writtenMismatch;
|
|
188
|
+
}
|
|
189
|
+
const priorExecutable = matchingRows.find((row) => row.requestFingerprint === candidate.requestFingerprint && row.executable);
|
|
190
|
+
if (priorExecutable && candidate.executable) {
|
|
191
|
+
return duplicateDecision(priorExecutable);
|
|
192
|
+
}
|
|
193
|
+
const latestSameFingerprint = [...matchingRows].reverse().find((row) => row.requestFingerprint === candidate.requestFingerprint);
|
|
194
|
+
if (latestSameFingerprint
|
|
195
|
+
&& latestSameFingerprint.result === candidate.result
|
|
196
|
+
&& latestSameFingerprint.executable === candidate.executable
|
|
197
|
+
&& latestSameFingerprint.deniedReason === candidate.deniedReason) {
|
|
198
|
+
return latestSameFingerprint;
|
|
199
|
+
}
|
|
200
|
+
if (priorExecutable && !candidate.executable) {
|
|
201
|
+
const written = writeRow(ledgerPath, candidate);
|
|
202
|
+
emitDecisionRecorded(deps, { level: "warn", decision: written });
|
|
203
|
+
return written;
|
|
204
|
+
}
|
|
205
|
+
const written = writeRow(ledgerPath, candidate);
|
|
206
|
+
emitDecisionRecorded(deps, { level: written.result === "allow" ? "info" : "warn", decision: written });
|
|
207
|
+
return written;
|
|
208
|
+
}
|
|
209
|
+
const written = writeRow(ledgerPath, candidate);
|
|
210
|
+
emitDecisionRecorded(deps, { level: written.result === "allow" ? "info" : "warn", decision: written });
|
|
211
|
+
return written;
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
const failed = ledgerWriteFailedDecision(candidate, ledgerPath, error);
|
|
215
|
+
emitDecisionRecordFailed(deps, { decision: failed });
|
|
216
|
+
return failed;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createPrivateTurnRequestFingerprint = createPrivateTurnRequestFingerprint;
|
|
37
|
+
exports.createPrivateTurnIdempotencyKey = createPrivateTurnIdempotencyKey;
|
|
38
|
+
exports.requestPrivateTurnDecision = requestPrivateTurnDecision;
|
|
39
|
+
const crypto = __importStar(require("node:crypto"));
|
|
40
|
+
const identity_1 = require("../identity");
|
|
41
|
+
const auth_flow_1 = require("../auth/auth-flow");
|
|
42
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
43
|
+
const provider_credentials_1 = require("../provider-credentials");
|
|
44
|
+
const ledger_1 = require("./ledger");
|
|
45
|
+
function isRecord(value) {
|
|
46
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
function stableJson(value) {
|
|
49
|
+
if (Array.isArray(value))
|
|
50
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
51
|
+
if (isRecord(value)) {
|
|
52
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
|
|
53
|
+
}
|
|
54
|
+
return JSON.stringify(value);
|
|
55
|
+
}
|
|
56
|
+
function normalizeOriginRefs(refs) {
|
|
57
|
+
return [...refs].sort((a, b) => stableJson(a).localeCompare(stableJson(b)));
|
|
58
|
+
}
|
|
59
|
+
function providerLaneSpendIdentity(providerLane) {
|
|
60
|
+
return {
|
|
61
|
+
lane: providerLane.lane,
|
|
62
|
+
provider: providerLane.provider,
|
|
63
|
+
model: providerLane.model,
|
|
64
|
+
source: providerLane.source,
|
|
65
|
+
...(providerLane.credentialRevision ? { credentialRevision: providerLane.credentialRevision } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function spendIdentity(request, options) {
|
|
69
|
+
return {
|
|
70
|
+
agent: request.agent,
|
|
71
|
+
origin: request.origin,
|
|
72
|
+
reason: request.reason,
|
|
73
|
+
providerLane: options.providerLane ? providerLaneSpendIdentity(options.providerLane) : request.providerLane,
|
|
74
|
+
triggerSource: request.triggerSource,
|
|
75
|
+
...(options.includeIdempotencyKey ? { idempotencyKey: request.idempotencyKey ?? "" } : {}),
|
|
76
|
+
budgetClass: request.budgetClass,
|
|
77
|
+
originRefs: normalizeOriginRefs(request.originRefs ?? []),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function sha256Prefix(prefix, value) {
|
|
81
|
+
const hash = crypto.createHash("sha256").update(stableJson(value)).digest("hex");
|
|
82
|
+
return `${prefix}_${hash}`;
|
|
83
|
+
}
|
|
84
|
+
function nowIso(deps) {
|
|
85
|
+
const raw = deps.now?.() ?? new Date();
|
|
86
|
+
return raw instanceof Date ? raw.toISOString() : raw;
|
|
87
|
+
}
|
|
88
|
+
function emitPolicyEvaluated(deps, input) {
|
|
89
|
+
const payload = {
|
|
90
|
+
level: input.result === "allow" ? "info" : "debug",
|
|
91
|
+
component: "private-runtime",
|
|
92
|
+
event: "private_runtime.policy_evaluated",
|
|
93
|
+
message: "private-runtime policy evaluated",
|
|
94
|
+
meta: {
|
|
95
|
+
agent: input.request.agent,
|
|
96
|
+
origin: input.request.origin,
|
|
97
|
+
result: input.result,
|
|
98
|
+
idempotencyKey: input.idempotencyKey,
|
|
99
|
+
requestFingerprint: input.requestFingerprint,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
if (deps.emitNervesEvent) {
|
|
103
|
+
deps.emitNervesEvent(payload);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
(0, runtime_1.emitNervesEvent)({
|
|
107
|
+
level: input.result === "allow" ? "info" : "debug",
|
|
108
|
+
component: "private-runtime",
|
|
109
|
+
event: "private_runtime.policy_evaluated",
|
|
110
|
+
message: "private-runtime policy evaluated",
|
|
111
|
+
meta: payload.meta,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async function defaultResolveProviderLane(agent, lane, deps) {
|
|
115
|
+
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
116
|
+
const { config } = (0, auth_flow_1.readAgentConfigForAgent)(agent, bundlesRoot);
|
|
117
|
+
const facing = lane === "inner" ? config.agentFacing : config.humanFacing;
|
|
118
|
+
const credential = (0, provider_credentials_1.readCachedProviderCredentialRecord)(agent, facing.provider);
|
|
119
|
+
if (!credential.ok) {
|
|
120
|
+
throw new Error(`${lane} provider ${facing.provider} (${facing.model}) credential revision unavailable: ${credential.error}`);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
lane,
|
|
124
|
+
provider: facing.provider,
|
|
125
|
+
model: facing.model,
|
|
126
|
+
source: "agent.json",
|
|
127
|
+
credentialRevision: credential.record.revision,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function resolveProviderLaneMetadata(request, deps) {
|
|
131
|
+
return deps.resolveProviderLane
|
|
132
|
+
? await deps.resolveProviderLane(request.agent, request.providerLane)
|
|
133
|
+
: defaultResolveProviderLane(request.agent, request.providerLane, deps);
|
|
134
|
+
}
|
|
135
|
+
async function evaluatePolicy(request, context, deps) {
|
|
136
|
+
if (deps.evaluatePolicy)
|
|
137
|
+
return deps.evaluatePolicy(request, context);
|
|
138
|
+
return {
|
|
139
|
+
result: "deny",
|
|
140
|
+
reason: "private runtime policy denies by default",
|
|
141
|
+
deniedReason: "default policy deny",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function emptyReceiptId() {
|
|
145
|
+
return "";
|
|
146
|
+
}
|
|
147
|
+
function createPrivateTurnRequestFingerprint(request, providerLane) {
|
|
148
|
+
return sha256Prefix("ptr", spendIdentity(request, { includeIdempotencyKey: true, providerLane }));
|
|
149
|
+
}
|
|
150
|
+
function createPrivateTurnIdempotencyKey(request) {
|
|
151
|
+
return sha256Prefix("ptk", spendIdentity(request, { includeIdempotencyKey: false }));
|
|
152
|
+
}
|
|
153
|
+
async function requestPrivateTurnDecision(request, deps = {}) {
|
|
154
|
+
const idempotencyKey = request.idempotencyKey ?? createPrivateTurnIdempotencyKey(request);
|
|
155
|
+
const normalizedRequest = { ...request, idempotencyKey };
|
|
156
|
+
let providerLane;
|
|
157
|
+
let requestFingerprint;
|
|
158
|
+
let evaluation;
|
|
159
|
+
try {
|
|
160
|
+
providerLane = await resolveProviderLaneMetadata(normalizedRequest, deps);
|
|
161
|
+
requestFingerprint = createPrivateTurnRequestFingerprint(normalizedRequest, providerLane);
|
|
162
|
+
evaluation = await evaluatePolicy(normalizedRequest, {
|
|
163
|
+
requestFingerprint,
|
|
164
|
+
idempotencyKey,
|
|
165
|
+
providerLane,
|
|
166
|
+
}, deps);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
providerLane = {
|
|
170
|
+
lane: normalizedRequest.providerLane,
|
|
171
|
+
provider: "unconfigured",
|
|
172
|
+
model: "-",
|
|
173
|
+
source: "agent.json",
|
|
174
|
+
};
|
|
175
|
+
requestFingerprint = createPrivateTurnRequestFingerprint(normalizedRequest, providerLane);
|
|
176
|
+
evaluation = {
|
|
177
|
+
result: "deny",
|
|
178
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
179
|
+
deniedReason: "provider lane resolution failed",
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const result = evaluation.result;
|
|
183
|
+
emitPolicyEvaluated(deps, { request: normalizedRequest, result, requestFingerprint, idempotencyKey });
|
|
184
|
+
const reason = evaluation.reason ?? normalizedRequest.reason;
|
|
185
|
+
const decision = {
|
|
186
|
+
schemaVersion: 1,
|
|
187
|
+
receiptId: emptyReceiptId(),
|
|
188
|
+
agent: normalizedRequest.agent,
|
|
189
|
+
origin: normalizedRequest.origin,
|
|
190
|
+
requestReason: normalizedRequest.reason,
|
|
191
|
+
reason,
|
|
192
|
+
providerLane,
|
|
193
|
+
triggerSource: normalizedRequest.triggerSource,
|
|
194
|
+
idempotencyKey,
|
|
195
|
+
budgetClass: normalizedRequest.budgetClass,
|
|
196
|
+
originRefs: normalizeOriginRefs(normalizedRequest.originRefs ?? []),
|
|
197
|
+
requestFingerprint,
|
|
198
|
+
result,
|
|
199
|
+
executable: result === "allow",
|
|
200
|
+
decidedAt: nowIso(deps),
|
|
201
|
+
ledgerLocator: { path: deps.ledgerPath ?? "" },
|
|
202
|
+
...(result === "deny" ? { deniedReason: evaluation.deniedReason ?? reason } : {}),
|
|
203
|
+
};
|
|
204
|
+
return (0, ledger_1.recordPrivateTurnDecision)(decision, deps);
|
|
205
|
+
}
|
|
@@ -4,7 +4,7 @@ exports.buildProgressStory = buildProgressStory;
|
|
|
4
4
|
exports.renderProgressStory = renderProgressStory;
|
|
5
5
|
const runtime_1 = require("../nerves/runtime");
|
|
6
6
|
function labelForScope(scope) {
|
|
7
|
-
return scope === "inner-delegation" ? "
|
|
7
|
+
return scope === "inner-delegation" ? "private-runtime work" : "shared work";
|
|
8
8
|
}
|
|
9
9
|
function compactDetail(text) {
|
|
10
10
|
if (typeof text !== "string")
|
|
@@ -62,7 +62,7 @@ function normalizeSessionMessages(events, context) {
|
|
|
62
62
|
}
|
|
63
63
|
function buildSummaryInstruction(friendId, channel, trustLevel) {
|
|
64
64
|
if (friendId === "self" && channel === "inner") {
|
|
65
|
-
return "summarize this session transcript fully and transparently. this is my own
|
|
65
|
+
return "summarize this session transcript fully and transparently. this is my own private runtime — include all details, decisions, and reasoning.";
|
|
66
66
|
}
|
|
67
67
|
return `summarize this session transcript. the person asking has trust level: ${trustLevel}. family=full transparency, friend=share work and general topics but protect other people's identities, acquaintance=very guarded minimal disclosure.`;
|
|
68
68
|
}
|
|
@@ -15,7 +15,7 @@ function createToolActivityCallbacks(options) {
|
|
|
15
15
|
// Track in-flight hidden tools so onToolEnd can SYMMETRICALLY suppress
|
|
16
16
|
// emission for the same tools that onToolStart already suppresses.
|
|
17
17
|
// Without this, a rejected hidden tool (e.g. settle blocked by the
|
|
18
|
-
// mustResolveBeforeHandoff gate or the
|
|
18
|
+
// mustResolveBeforeHandoff gate or the private-runtime attention-queue gate)
|
|
19
19
|
// would emit "✗ <previous visible tool's description> — <hidden tool's args summary>"
|
|
20
20
|
// because lastDescription persists across calls and the hidden tool's summary
|
|
21
21
|
// (built via summarizeArgs) leaks args like settle's `answer`/`intent` into
|
|
@@ -90,7 +90,7 @@ const TOOL_DESCRIPTIONS = {
|
|
|
90
90
|
if (mode === "search")
|
|
91
91
|
return `searching session for '${truncate(args.query || "", 30)}'...`;
|
|
92
92
|
if (mode === "status")
|
|
93
|
-
return "checking
|
|
93
|
+
return "checking private-runtime turn status...";
|
|
94
94
|
return "checking session history...";
|
|
95
95
|
},
|
|
96
96
|
web_search: (args) => {
|
|
@@ -115,7 +115,7 @@ const TOOL_DESCRIPTIONS = {
|
|
|
115
115
|
return to ? `sending a message to ${to}...` : "sending a message...";
|
|
116
116
|
},
|
|
117
117
|
surface: () => "sharing a thought...",
|
|
118
|
-
// Metacognitive (
|
|
118
|
+
// Metacognitive (private runtime)
|
|
119
119
|
ponder: (args) => {
|
|
120
120
|
const objective = args.objective || args.thought;
|
|
121
121
|
return objective ? `bookmarking ${truncate(objective, 40)}...` : "bookmarking deeper work...";
|
package/dist/heart/tool-loop.js
CHANGED
|
@@ -180,8 +180,8 @@ function recordToolOutcome(state, toolName, args, result, success) {
|
|
|
180
180
|
}
|
|
181
181
|
// Tools that must never be blocked by the circuit breaker.
|
|
182
182
|
// settle = end the turn, surface = deliver results outward.
|
|
183
|
-
// ponder = continue thinking (
|
|
184
|
-
// rest = end
|
|
183
|
+
// ponder = continue thinking (private runtime) or hand off to private runtime (outer).
|
|
184
|
+
// rest = end private runtime turn (added in Unit 8b).
|
|
185
185
|
// Blocking these traps the agent: it can think all it wants but can never speak or stop.
|
|
186
186
|
const CIRCUIT_BREAKER_EXEMPT = new Set(["settle", "surface", "ponder", "rest"]);
|
|
187
187
|
function detectToolLoop(state, toolName, args) {
|