@ouro.bot/cli 0.1.0-alpha.205 → 0.1.0-alpha.207
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 +12 -0
- package/dist/heart/config-registry.js +305 -0
- package/dist/heart/core.js +4 -2
- package/dist/heart/start-of-turn-packet.js +103 -5
- package/dist/nerves/coverage/file-completeness.js +38 -5
- package/dist/repertoire/tools-base.js +28 -1792
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-config.js +266 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flow.js +62 -0
- package/dist/repertoire/tools-memory.js +347 -0
- package/dist/repertoire/tools-session.js +682 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-surface.js +228 -0
- package/dist/repertoire/tools.js +14 -225
- package/dist/senses/pipeline.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shellToolDefinitions = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const shell_sessions_1 = require("./shell-sessions");
|
|
6
|
+
const identity_1 = require("../heart/identity");
|
|
7
|
+
const runtime_1 = require("../nerves/runtime");
|
|
8
|
+
exports.shellToolDefinitions = [
|
|
9
|
+
{
|
|
10
|
+
tool: {
|
|
11
|
+
type: "function",
|
|
12
|
+
function: {
|
|
13
|
+
name: "shell",
|
|
14
|
+
description: "Run a shell command and return stdout/stderr. Working directory persists between calls. Use dedicated tools instead of shell when available: read_file instead of cat, edit_file instead of sed, glob instead of find, grep instead of grep/rg. Reserve shell for operations that genuinely need the shell: installing packages, running builds/tests, git operations, process management. Be careful with destructive commands -- consider reversibility before running. If a command fails, read the error output before retrying with a different approach.",
|
|
15
|
+
parameters: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
command: { type: "string" },
|
|
19
|
+
timeout_ms: {
|
|
20
|
+
type: "number",
|
|
21
|
+
description: "Timeout in milliseconds. Default: 30000. Max: 600000.",
|
|
22
|
+
},
|
|
23
|
+
background: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
description: "Run in background. Returns immediately with a process ID. Use shell_status/shell_tail to monitor.",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
required: ["command"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
handler: (a) => {
|
|
33
|
+
// Destructive pattern detection (friction, not a block)
|
|
34
|
+
const destructivePatterns = (0, shell_sessions_1.detectDestructivePatterns)(a.command);
|
|
35
|
+
if (destructivePatterns.length > 0) {
|
|
36
|
+
(0, runtime_1.emitNervesEvent)({
|
|
37
|
+
level: "warn",
|
|
38
|
+
event: "tool.shell.destructive_detected",
|
|
39
|
+
component: "tools",
|
|
40
|
+
message: `destructive pattern detected: ${destructivePatterns.join(", ")}`,
|
|
41
|
+
meta: { command: a.command, patterns: destructivePatterns },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// Background mode: spawn and return immediately
|
|
45
|
+
if (a.background === "true") {
|
|
46
|
+
const session = (0, shell_sessions_1.spawnBackgroundShell)(a.command);
|
|
47
|
+
return JSON.stringify({ id: session.id, command: session.command, status: session.status });
|
|
48
|
+
}
|
|
49
|
+
const MAX_TIMEOUT = 600000;
|
|
50
|
+
const requestedTimeout = Number(a.timeout_ms) || 0;
|
|
51
|
+
let configDefault = 30000;
|
|
52
|
+
try {
|
|
53
|
+
configDefault = (0, identity_1.loadAgentConfig)().shell?.defaultTimeout ?? 30000;
|
|
54
|
+
}
|
|
55
|
+
catch { /* test env: no --agent flag */ }
|
|
56
|
+
const baseTimeout = requestedTimeout > 0 ? requestedTimeout : configDefault;
|
|
57
|
+
const timeout = Math.min(baseTimeout, MAX_TIMEOUT);
|
|
58
|
+
const output = (0, child_process_1.execSync)(a.command, {
|
|
59
|
+
encoding: "utf-8",
|
|
60
|
+
timeout,
|
|
61
|
+
});
|
|
62
|
+
if (destructivePatterns.length > 0) {
|
|
63
|
+
return `${output}\n\n--- destructive pattern detected: ${destructivePatterns.join(", ")} ---`;
|
|
64
|
+
}
|
|
65
|
+
return output;
|
|
66
|
+
},
|
|
67
|
+
summaryKeys: ["command"],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
tool: {
|
|
71
|
+
type: "function",
|
|
72
|
+
function: {
|
|
73
|
+
name: "shell_status",
|
|
74
|
+
description: "Check status of background shell processes. Omit id to list all.",
|
|
75
|
+
parameters: {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: {
|
|
78
|
+
id: { type: "string", description: "Background shell process ID" },
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
handler: (a) => {
|
|
84
|
+
if (!a.id) {
|
|
85
|
+
return JSON.stringify((0, shell_sessions_1.listShellSessions)());
|
|
86
|
+
}
|
|
87
|
+
const session = (0, shell_sessions_1.getShellSession)(a.id);
|
|
88
|
+
if (!session)
|
|
89
|
+
return `process not found: ${a.id}`;
|
|
90
|
+
return JSON.stringify(session);
|
|
91
|
+
},
|
|
92
|
+
summaryKeys: ["id"],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
tool: {
|
|
96
|
+
type: "function",
|
|
97
|
+
function: {
|
|
98
|
+
name: "shell_tail",
|
|
99
|
+
description: "Show recent output from a background shell process.",
|
|
100
|
+
parameters: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: {
|
|
103
|
+
id: { type: "string", description: "Background shell process ID" },
|
|
104
|
+
},
|
|
105
|
+
required: ["id"],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
handler: (a) => {
|
|
110
|
+
/* v8 ignore next -- schema requires id, defensive guard @preserve */
|
|
111
|
+
if (!a.id)
|
|
112
|
+
return "id is required";
|
|
113
|
+
const output = (0, shell_sessions_1.tailShellSession)(a.id);
|
|
114
|
+
if (output === undefined)
|
|
115
|
+
return `process not found: ${a.id}`;
|
|
116
|
+
return output || "(no output yet)";
|
|
117
|
+
},
|
|
118
|
+
summaryKeys: ["id"],
|
|
119
|
+
},
|
|
120
|
+
];
|
|
@@ -0,0 +1,228 @@
|
|
|
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.surfaceToolDefinition = exports.surfaceToolDef = void 0;
|
|
37
|
+
const identity_1 = require("../heart/identity");
|
|
38
|
+
const surface_tool_1 = require("../senses/surface-tool");
|
|
39
|
+
const obligations_1 = require("../heart/obligations");
|
|
40
|
+
const session_activity_1 = require("../heart/session-activity");
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
// Surface tool schema — canonical home. Handler lives in senses/surface-tool.ts.
|
|
43
|
+
exports.surfaceToolDef = {
|
|
44
|
+
type: "function",
|
|
45
|
+
function: {
|
|
46
|
+
name: "surface",
|
|
47
|
+
description: "share a thought outward — deliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
|
|
48
|
+
parameters: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
content: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "the message to deliver",
|
|
54
|
+
},
|
|
55
|
+
delegationId: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "ID from your attention queue — addresses a specific held thought",
|
|
58
|
+
},
|
|
59
|
+
friendId: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "friend to reach out to spontaneously (when not addressing a held thought)",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
required: ["content"],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
// Surface tool handler: routes content to friend's freshest session
|
|
69
|
+
/* v8 ignore start -- surface handler wiring: core logic tested via surface-tool.test.ts; this wires identity/routing deps @preserve */
|
|
70
|
+
exports.surfaceToolDefinition = {
|
|
71
|
+
tool: exports.surfaceToolDef,
|
|
72
|
+
handler: async (args, ctx) => {
|
|
73
|
+
const queue = ctx?.delegatedOrigins ?? [];
|
|
74
|
+
const agentName = (() => { try {
|
|
75
|
+
return (0, identity_1.getAgentName)();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return "unknown";
|
|
79
|
+
} })();
|
|
80
|
+
const routeToFriend = async (friendId, content, queueItem) => {
|
|
81
|
+
/* v8 ignore start -- routing: integration path tested via inner-dialog routing tests @preserve */
|
|
82
|
+
try {
|
|
83
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
84
|
+
const sessionsDir = path.join(agentRoot, "state", "sessions");
|
|
85
|
+
const friendsDir = path.join(agentRoot, "friends");
|
|
86
|
+
// Priority 1: Bridge-preferred session (if queue item has a bridgeId)
|
|
87
|
+
if (queueItem?.bridgeId) {
|
|
88
|
+
const { createBridgeManager } = await Promise.resolve().then(() => __importStar(require("../heart/bridges/manager")));
|
|
89
|
+
const bridge = createBridgeManager().getBridge(queueItem.bridgeId);
|
|
90
|
+
if (bridge && bridge.lifecycle !== "completed" && bridge.lifecycle !== "cancelled") {
|
|
91
|
+
const allSessions = (0, session_activity_1.listSessionActivity)({ sessionsDir, friendsDir, agentName });
|
|
92
|
+
const bridgeTarget = allSessions.find((activity) => activity.friendId === friendId
|
|
93
|
+
&& activity.channel !== "inner"
|
|
94
|
+
&& bridge.attachedSessions.some((s) => s.friendId === activity.friendId && s.channel === activity.channel && s.key === activity.key));
|
|
95
|
+
if (bridgeTarget) {
|
|
96
|
+
// Attempt proactive BB delivery for bridge target
|
|
97
|
+
if (bridgeTarget.channel === "bluebubbles") {
|
|
98
|
+
const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
|
|
99
|
+
const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
|
|
100
|
+
friendId: bridgeTarget.friendId,
|
|
101
|
+
sessionKey: bridgeTarget.key,
|
|
102
|
+
text: content,
|
|
103
|
+
});
|
|
104
|
+
if (proactiveResult.delivered) {
|
|
105
|
+
// Inject surfaced content into the target session so it knows what was delivered
|
|
106
|
+
const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
|
|
107
|
+
const sessionFilePath = path.join(sessionsDir, bridgeTarget.friendId, bridgeTarget.channel, `${bridgeTarget.key}.json`);
|
|
108
|
+
appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
|
|
109
|
+
return { status: "delivered", detail: "via iMessage" };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Fall back to pending queue for bridge target
|
|
113
|
+
const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
114
|
+
const pendingDir = getPendingDir(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key);
|
|
115
|
+
queuePendingMessage(pendingDir, {
|
|
116
|
+
from: agentName,
|
|
117
|
+
friendId: bridgeTarget.friendId,
|
|
118
|
+
channel: bridgeTarget.channel,
|
|
119
|
+
key: bridgeTarget.key,
|
|
120
|
+
content,
|
|
121
|
+
timestamp: Date.now(),
|
|
122
|
+
});
|
|
123
|
+
return { status: "queued", detail: `for next interaction via ${bridgeTarget.channel}` };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Priority 2: Freshest active friend session
|
|
128
|
+
const freshest = (0, session_activity_1.findFreshestFriendSession)({
|
|
129
|
+
sessionsDir,
|
|
130
|
+
friendsDir,
|
|
131
|
+
agentName,
|
|
132
|
+
friendId,
|
|
133
|
+
activeOnly: true,
|
|
134
|
+
});
|
|
135
|
+
if (freshest && freshest.channel !== "inner") {
|
|
136
|
+
// Attempt proactive BB delivery
|
|
137
|
+
if (freshest.channel === "bluebubbles") {
|
|
138
|
+
const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
|
|
139
|
+
const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
|
|
140
|
+
friendId: freshest.friendId,
|
|
141
|
+
sessionKey: freshest.key,
|
|
142
|
+
text: content,
|
|
143
|
+
});
|
|
144
|
+
if (proactiveResult.delivered) {
|
|
145
|
+
// Inject surfaced content into the target session so it knows what was delivered
|
|
146
|
+
const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
|
|
147
|
+
const sessionFilePath = path.join(sessionsDir, freshest.friendId, freshest.channel, `${freshest.key}.json`);
|
|
148
|
+
appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
|
|
149
|
+
return { status: "delivered", detail: "via iMessage" };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Queue as pending for next interaction
|
|
153
|
+
const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
154
|
+
const pendingDir = getPendingDir(agentName, freshest.friendId, freshest.channel, freshest.key);
|
|
155
|
+
queuePendingMessage(pendingDir, {
|
|
156
|
+
from: agentName,
|
|
157
|
+
friendId: freshest.friendId,
|
|
158
|
+
channel: freshest.channel,
|
|
159
|
+
key: freshest.key,
|
|
160
|
+
content,
|
|
161
|
+
timestamp: Date.now(),
|
|
162
|
+
});
|
|
163
|
+
return { status: "queued", detail: `for next interaction via ${freshest.channel}` };
|
|
164
|
+
}
|
|
165
|
+
// Priority 3: Deferred — no active session found
|
|
166
|
+
const { getDeferredReturnDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
167
|
+
const { queuePendingMessage: queueDeferred } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
168
|
+
const deferredDir = getDeferredReturnDir(agentName, friendId);
|
|
169
|
+
queueDeferred(deferredDir, {
|
|
170
|
+
from: agentName,
|
|
171
|
+
friendId,
|
|
172
|
+
channel: "deferred",
|
|
173
|
+
key: "return",
|
|
174
|
+
content,
|
|
175
|
+
timestamp: Date.now(),
|
|
176
|
+
});
|
|
177
|
+
return { status: "deferred", detail: "they'll see it next time" };
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return { status: "failed" };
|
|
181
|
+
}
|
|
182
|
+
/* v8 ignore stop */
|
|
183
|
+
};
|
|
184
|
+
return (0, surface_tool_1.handleSurface)({
|
|
185
|
+
content: args.content ?? "",
|
|
186
|
+
delegationId: args.delegationId,
|
|
187
|
+
friendId: args.friendId,
|
|
188
|
+
queue,
|
|
189
|
+
routeToFriend,
|
|
190
|
+
advanceObligation: (obligationId, update) => {
|
|
191
|
+
/* v8 ignore start -- obligation advance: tested via attention-queue tests @preserve */
|
|
192
|
+
try {
|
|
193
|
+
const name = (() => { try {
|
|
194
|
+
return (0, identity_1.getAgentName)();
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return "unknown";
|
|
198
|
+
} })();
|
|
199
|
+
(0, obligations_1.advanceReturnObligation)(name, obligationId, {
|
|
200
|
+
status: update.status,
|
|
201
|
+
...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
|
|
202
|
+
...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// swallowed — obligation advance must never break surface delivery
|
|
207
|
+
}
|
|
208
|
+
/* v8 ignore stop */
|
|
209
|
+
},
|
|
210
|
+
fulfillHeartObligation: (origin) => {
|
|
211
|
+
/* v8 ignore start -- heart obligation fulfillment: tested via surface-tool.test.ts @preserve */
|
|
212
|
+
try {
|
|
213
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
214
|
+
const heartObligation = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, origin);
|
|
215
|
+
if (heartObligation) {
|
|
216
|
+
(0, obligations_1.fulfillObligation)(agentRoot, heartObligation.id);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// swallowed — heart obligation fulfillment must never break surface delivery
|
|
221
|
+
}
|
|
222
|
+
/* v8 ignore stop */
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
},
|
|
226
|
+
summaryKeys: ["content", "delegationId"],
|
|
227
|
+
};
|
|
228
|
+
/* v8 ignore stop */
|
package/dist/repertoire/tools.js
CHANGED
|
@@ -1,41 +1,9 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.surfaceToolDef = exports.restTool = exports.ponderTool = exports.observeTool = exports.settleTool = exports.tools = void 0;
|
|
37
4
|
exports.getToolsForChannel = getToolsForChannel;
|
|
38
5
|
exports.isConfirmationRequired = isConfirmationRequired;
|
|
6
|
+
exports.isConfirmationAlwaysRequired = isConfirmationAlwaysRequired;
|
|
39
7
|
exports.execTool = execTool;
|
|
40
8
|
exports.summarizeArgs = summarizeArgs;
|
|
41
9
|
exports.buildToolResultSummary = buildToolResultSummary;
|
|
@@ -47,10 +15,7 @@ const tools_github_1 = require("./tools-github");
|
|
|
47
15
|
const runtime_1 = require("../nerves/runtime");
|
|
48
16
|
const guardrails_1 = require("./guardrails");
|
|
49
17
|
const identity_1 = require("../heart/identity");
|
|
50
|
-
const
|
|
51
|
-
const obligations_1 = require("../heart/obligations");
|
|
52
|
-
const session_activity_1 = require("../heart/session-activity");
|
|
53
|
-
const path = __importStar(require("path"));
|
|
18
|
+
const tools_surface_1 = require("./tools-surface");
|
|
54
19
|
function safeGetAgentRoot() {
|
|
55
20
|
try {
|
|
56
21
|
return (0, identity_1.getAgentRoot)();
|
|
@@ -66,195 +31,11 @@ Object.defineProperty(exports, "settleTool", { enumerable: true, get: function (
|
|
|
66
31
|
Object.defineProperty(exports, "observeTool", { enumerable: true, get: function () { return tools_base_2.observeTool; } });
|
|
67
32
|
Object.defineProperty(exports, "ponderTool", { enumerable: true, get: function () { return tools_base_2.ponderTool; } });
|
|
68
33
|
Object.defineProperty(exports, "restTool", { enumerable: true, get: function () { return tools_base_2.restTool; } });
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
function: {
|
|
73
|
-
name: "surface",
|
|
74
|
-
description: "share a thought outward — deliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
|
|
75
|
-
parameters: {
|
|
76
|
-
type: "object",
|
|
77
|
-
properties: {
|
|
78
|
-
content: {
|
|
79
|
-
type: "string",
|
|
80
|
-
description: "the message to deliver",
|
|
81
|
-
},
|
|
82
|
-
delegationId: {
|
|
83
|
-
type: "string",
|
|
84
|
-
description: "ID from your attention queue — addresses a specific held thought",
|
|
85
|
-
},
|
|
86
|
-
friendId: {
|
|
87
|
-
type: "string",
|
|
88
|
-
description: "friend to reach out to spontaneously (when not addressing a held thought)",
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
required: ["content"],
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
// Surface tool handler: routes content to friend's freshest session
|
|
96
|
-
/* v8 ignore start -- surface handler wiring: core logic tested via surface-tool.test.ts; this wires identity/routing deps @preserve */
|
|
97
|
-
const surfaceToolDefinition = {
|
|
98
|
-
tool: exports.surfaceToolDef,
|
|
99
|
-
handler: async (args, ctx) => {
|
|
100
|
-
const queue = ctx?.delegatedOrigins ?? [];
|
|
101
|
-
const agentName = (() => { try {
|
|
102
|
-
return (0, identity_1.getAgentName)();
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
return "unknown";
|
|
106
|
-
} })();
|
|
107
|
-
const routeToFriend = async (friendId, content, queueItem) => {
|
|
108
|
-
/* v8 ignore start -- routing: integration path tested via inner-dialog routing tests @preserve */
|
|
109
|
-
try {
|
|
110
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
111
|
-
const sessionsDir = path.join(agentRoot, "state", "sessions");
|
|
112
|
-
const friendsDir = path.join(agentRoot, "friends");
|
|
113
|
-
// Priority 1: Bridge-preferred session (if queue item has a bridgeId)
|
|
114
|
-
if (queueItem?.bridgeId) {
|
|
115
|
-
const { createBridgeManager } = await Promise.resolve().then(() => __importStar(require("../heart/bridges/manager")));
|
|
116
|
-
const bridge = createBridgeManager().getBridge(queueItem.bridgeId);
|
|
117
|
-
if (bridge && bridge.lifecycle !== "completed" && bridge.lifecycle !== "cancelled") {
|
|
118
|
-
const allSessions = (0, session_activity_1.listSessionActivity)({ sessionsDir, friendsDir, agentName });
|
|
119
|
-
const bridgeTarget = allSessions.find((activity) => activity.friendId === friendId
|
|
120
|
-
&& activity.channel !== "inner"
|
|
121
|
-
&& bridge.attachedSessions.some((s) => s.friendId === activity.friendId && s.channel === activity.channel && s.key === activity.key));
|
|
122
|
-
if (bridgeTarget) {
|
|
123
|
-
// Attempt proactive BB delivery for bridge target
|
|
124
|
-
if (bridgeTarget.channel === "bluebubbles") {
|
|
125
|
-
const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
|
|
126
|
-
const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
|
|
127
|
-
friendId: bridgeTarget.friendId,
|
|
128
|
-
sessionKey: bridgeTarget.key,
|
|
129
|
-
text: content,
|
|
130
|
-
});
|
|
131
|
-
if (proactiveResult.delivered) {
|
|
132
|
-
// Inject surfaced content into the target session so it knows what was delivered
|
|
133
|
-
const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
|
|
134
|
-
const sessionFilePath = path.join(sessionsDir, bridgeTarget.friendId, bridgeTarget.channel, `${bridgeTarget.key}.json`);
|
|
135
|
-
appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
|
|
136
|
-
return { status: "delivered", detail: "via iMessage" };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Fall back to pending queue for bridge target
|
|
140
|
-
const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
141
|
-
const pendingDir = getPendingDir(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key);
|
|
142
|
-
queuePendingMessage(pendingDir, {
|
|
143
|
-
from: agentName,
|
|
144
|
-
friendId: bridgeTarget.friendId,
|
|
145
|
-
channel: bridgeTarget.channel,
|
|
146
|
-
key: bridgeTarget.key,
|
|
147
|
-
content,
|
|
148
|
-
timestamp: Date.now(),
|
|
149
|
-
});
|
|
150
|
-
return { status: "queued", detail: `for next interaction via ${bridgeTarget.channel}` };
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// Priority 2: Freshest active friend session
|
|
155
|
-
const freshest = (0, session_activity_1.findFreshestFriendSession)({
|
|
156
|
-
sessionsDir,
|
|
157
|
-
friendsDir,
|
|
158
|
-
agentName,
|
|
159
|
-
friendId,
|
|
160
|
-
activeOnly: true,
|
|
161
|
-
});
|
|
162
|
-
if (freshest && freshest.channel !== "inner") {
|
|
163
|
-
// Attempt proactive BB delivery
|
|
164
|
-
if (freshest.channel === "bluebubbles") {
|
|
165
|
-
const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
|
|
166
|
-
const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
|
|
167
|
-
friendId: freshest.friendId,
|
|
168
|
-
sessionKey: freshest.key,
|
|
169
|
-
text: content,
|
|
170
|
-
});
|
|
171
|
-
if (proactiveResult.delivered) {
|
|
172
|
-
// Inject surfaced content into the target session so it knows what was delivered
|
|
173
|
-
const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
|
|
174
|
-
const sessionFilePath = path.join(sessionsDir, freshest.friendId, freshest.channel, `${freshest.key}.json`);
|
|
175
|
-
appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
|
|
176
|
-
return { status: "delivered", detail: "via iMessage" };
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// Queue as pending for next interaction
|
|
180
|
-
const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
181
|
-
const pendingDir = getPendingDir(agentName, freshest.friendId, freshest.channel, freshest.key);
|
|
182
|
-
queuePendingMessage(pendingDir, {
|
|
183
|
-
from: agentName,
|
|
184
|
-
friendId: freshest.friendId,
|
|
185
|
-
channel: freshest.channel,
|
|
186
|
-
key: freshest.key,
|
|
187
|
-
content,
|
|
188
|
-
timestamp: Date.now(),
|
|
189
|
-
});
|
|
190
|
-
return { status: "queued", detail: `for next interaction via ${freshest.channel}` };
|
|
191
|
-
}
|
|
192
|
-
// Priority 3: Deferred — no active session found
|
|
193
|
-
const { getDeferredReturnDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
194
|
-
const { queuePendingMessage: queueDeferred } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
|
|
195
|
-
const deferredDir = getDeferredReturnDir(agentName, friendId);
|
|
196
|
-
queueDeferred(deferredDir, {
|
|
197
|
-
from: agentName,
|
|
198
|
-
friendId,
|
|
199
|
-
channel: "deferred",
|
|
200
|
-
key: "return",
|
|
201
|
-
content,
|
|
202
|
-
timestamp: Date.now(),
|
|
203
|
-
});
|
|
204
|
-
return { status: "deferred", detail: "they'll see it next time" };
|
|
205
|
-
}
|
|
206
|
-
catch {
|
|
207
|
-
return { status: "failed" };
|
|
208
|
-
}
|
|
209
|
-
/* v8 ignore stop */
|
|
210
|
-
};
|
|
211
|
-
return (0, surface_tool_1.handleSurface)({
|
|
212
|
-
content: args.content ?? "",
|
|
213
|
-
delegationId: args.delegationId,
|
|
214
|
-
friendId: args.friendId,
|
|
215
|
-
queue,
|
|
216
|
-
routeToFriend,
|
|
217
|
-
advanceObligation: (obligationId, update) => {
|
|
218
|
-
/* v8 ignore start -- obligation advance: tested via attention-queue tests @preserve */
|
|
219
|
-
try {
|
|
220
|
-
const name = (() => { try {
|
|
221
|
-
return (0, identity_1.getAgentName)();
|
|
222
|
-
}
|
|
223
|
-
catch {
|
|
224
|
-
return "unknown";
|
|
225
|
-
} })();
|
|
226
|
-
(0, obligations_1.advanceReturnObligation)(name, obligationId, {
|
|
227
|
-
status: update.status,
|
|
228
|
-
...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
|
|
229
|
-
...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
catch {
|
|
233
|
-
// swallowed — obligation advance must never break surface delivery
|
|
234
|
-
}
|
|
235
|
-
/* v8 ignore stop */
|
|
236
|
-
},
|
|
237
|
-
fulfillHeartObligation: (origin) => {
|
|
238
|
-
/* v8 ignore start -- heart obligation fulfillment: tested via surface-tool.test.ts @preserve */
|
|
239
|
-
try {
|
|
240
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
241
|
-
const heartObligation = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, origin);
|
|
242
|
-
if (heartObligation) {
|
|
243
|
-
(0, obligations_1.fulfillObligation)(agentRoot, heartObligation.id);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
// swallowed — heart obligation fulfillment must never break surface delivery
|
|
248
|
-
}
|
|
249
|
-
/* v8 ignore stop */
|
|
250
|
-
},
|
|
251
|
-
});
|
|
252
|
-
},
|
|
253
|
-
summaryKeys: ["content", "delegationId"],
|
|
254
|
-
};
|
|
255
|
-
/* v8 ignore stop */
|
|
34
|
+
// Re-export surface tool schema for consumers (e.g. heart/core.ts)
|
|
35
|
+
var tools_surface_2 = require("./tools-surface");
|
|
36
|
+
Object.defineProperty(exports, "surfaceToolDef", { enumerable: true, get: function () { return tools_surface_2.surfaceToolDef; } });
|
|
256
37
|
// All tool definitions in a single registry
|
|
257
|
-
const allDefinitions = [...tools_base_1.baseToolDefinitions, ...tools_bluebubbles_1.bluebubblesToolDefinitions, ...tools_teams_1.teamsToolDefinitions, ...ado_semantic_1.adoSemanticToolDefinitions, ...tools_github_1.githubToolDefinitions, surfaceToolDefinition];
|
|
38
|
+
const allDefinitions = [...tools_base_1.baseToolDefinitions, ...tools_bluebubbles_1.bluebubblesToolDefinitions, ...tools_teams_1.teamsToolDefinitions, ...ado_semantic_1.adoSemanticToolDefinitions, ...tools_github_1.githubToolDefinitions, tools_surface_1.surfaceToolDefinition];
|
|
258
39
|
function baseToolsForCapabilities() {
|
|
259
40
|
// Use baseToolDefinitions at call time so dynamically-added tools are included
|
|
260
41
|
return tools_base_1.baseToolDefinitions.map((d) => d.tool);
|
|
@@ -325,6 +106,12 @@ function isConfirmationRequired(toolName) {
|
|
|
325
106
|
const def = allDefinitions.find((d) => d.tool.function.name === toolName);
|
|
326
107
|
return def?.confirmationRequired === true;
|
|
327
108
|
}
|
|
109
|
+
// Check whether a tool's confirmation is non-bypassable (cannot be skipped by skipConfirmation).
|
|
110
|
+
// Used for T2 config proposals that must always require operator approval.
|
|
111
|
+
function isConfirmationAlwaysRequired(toolName) {
|
|
112
|
+
const def = allDefinitions.find((d) => d.tool.function.name === toolName);
|
|
113
|
+
return def?.confirmationAlwaysRequired === true;
|
|
114
|
+
}
|
|
328
115
|
function normalizeGuardArgs(_name, args) {
|
|
329
116
|
return args;
|
|
330
117
|
}
|
|
@@ -419,6 +206,7 @@ function summarizeArgs(name, args) {
|
|
|
419
206
|
* Falls back to arg-based summary for unrecognized tools.
|
|
420
207
|
*/
|
|
421
208
|
function buildToolResultSummary(name, args, _result, success) {
|
|
209
|
+
/* v8 ignore start -- branches: ?? fallbacks and ternaries in tool summary formatting @preserve */
|
|
422
210
|
switch (name) {
|
|
423
211
|
case "edit_file": {
|
|
424
212
|
if (!success)
|
|
@@ -448,4 +236,5 @@ function buildToolResultSummary(name, args, _result, success) {
|
|
|
448
236
|
default:
|
|
449
237
|
return summarizeArgs(name, args);
|
|
450
238
|
}
|
|
239
|
+
/* v8 ignore stop */
|
|
451
240
|
}
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -390,6 +390,10 @@ async function handleInboundTurn(input) {
|
|
|
390
390
|
if (syncFailure) {
|
|
391
391
|
startOfTurnPacket.syncFailure = syncFailure;
|
|
392
392
|
}
|
|
393
|
+
const capabilities = (0, start_of_turn_packet_1.buildCapabilitiesSection)(agentRoot);
|
|
394
|
+
if (capabilities) {
|
|
395
|
+
startOfTurnPacket.capabilities = capabilities;
|
|
396
|
+
}
|
|
393
397
|
renderedStartOfTurnPacket = (0, start_of_turn_packet_1.renderStartOfTurnPacket)(startOfTurnPacket);
|
|
394
398
|
if (!renderedStartOfTurnPacket)
|
|
395
399
|
renderedStartOfTurnPacket = undefined;
|