@ouro.bot/cli 0.1.0-alpha.289 → 0.1.0-alpha.290
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 +4 -2
- package/changelog.json +7 -0
- package/dist/arc/packets.js +203 -0
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +230 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +138 -0
- package/dist/heart/core.js +187 -162
- package/dist/heart/tool-description.js +3 -3
- package/dist/heart/tool-friction.js +55 -0
- package/dist/mind/prompt.js +27 -16
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +316 -0
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/repertoire/tools-bluebubbles.js +0 -107
- package/dist/repertoire/tools-flow.js +48 -5
- package/dist/repertoire/tools.js +2 -10
- package/dist/senses/attention-queue.js +20 -1
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/bluebubbles/media.js +36 -101
- package/dist/senses/bluebubbles/model.js +9 -11
- package/dist/senses/cli/image-paste.js +79 -3
- package/dist/senses/inner-dialog.js +9 -0
- package/dist/senses/shared-turn.js +3 -7
- package/package.json +1 -1
package/dist/heart/core.js
CHANGED
|
@@ -26,11 +26,12 @@ const azure_1 = require("./providers/azure");
|
|
|
26
26
|
const minimax_1 = require("./providers/minimax");
|
|
27
27
|
const openai_codex_1 = require("./providers/openai-codex");
|
|
28
28
|
const github_copilot_1 = require("./providers/github-copilot");
|
|
29
|
-
const pending_1 = require("../mind/pending");
|
|
30
29
|
const identity_2 = require("./identity");
|
|
31
30
|
const socket_client_1 = require("./daemon/socket-client");
|
|
32
31
|
const obligations_1 = require("../arc/obligations");
|
|
33
32
|
const tool_loop_1 = require("./tool-loop");
|
|
33
|
+
const packets_1 = require("../arc/packets");
|
|
34
|
+
const tool_friction_1 = require("./tool-friction");
|
|
34
35
|
const _providerRuntimes = {
|
|
35
36
|
human: null,
|
|
36
37
|
agent: null,
|
|
@@ -150,49 +151,8 @@ function getProviderDisplayLabel(facing = "human") {
|
|
|
150
151
|
const SOLE_CALL_REJECTION = {
|
|
151
152
|
settle: "rejected: settle must be the only tool call. finish your work first, then call settle alone.",
|
|
152
153
|
observe: "rejected: observe must be the only tool call. call observe alone when you want to stay silent.",
|
|
153
|
-
ponder: "rejected: ponder must be the only tool call. finish your other work first, then call ponder alone.",
|
|
154
154
|
rest: "rejected: rest must be the only tool call. finish your work first, then call rest alone.",
|
|
155
155
|
};
|
|
156
|
-
const DELEGATION_REASON_PROSE_HANDOFF = {
|
|
157
|
-
explicit_reflection: "something in the conversation called for reflection",
|
|
158
|
-
cross_session: "this touches other conversations",
|
|
159
|
-
bridge_state: "there's shared work spanning sessions",
|
|
160
|
-
task_state: "there are active tasks that relate to this",
|
|
161
|
-
non_fast_path_tool: "this needs tools beyond a simple reply",
|
|
162
|
-
unresolved_obligation: "there's an unresolved commitment from an earlier conversation",
|
|
163
|
-
};
|
|
164
|
-
function buildPonderHandoffPacket(params) {
|
|
165
|
-
const reasons = params.delegationDecision?.reasons ?? [];
|
|
166
|
-
const reasonProse = reasons.length > 0
|
|
167
|
-
? reasons.map((r) => DELEGATION_REASON_PROSE_HANDOFF[r]).join("; ")
|
|
168
|
-
: "this felt like it needed more thought";
|
|
169
|
-
const whoAsked = params.currentSession
|
|
170
|
-
? params.currentSession.friendId
|
|
171
|
-
: "no one -- just thinking";
|
|
172
|
-
let holdingLine;
|
|
173
|
-
if (params.outwardClosureRequired && params.currentSession) {
|
|
174
|
-
holdingLine = `i'm holding something for ${params.currentSession.friendId}`;
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
holdingLine = "nothing -- just thinking";
|
|
178
|
-
}
|
|
179
|
-
return [
|
|
180
|
-
"## what i need to think about",
|
|
181
|
-
params.topic,
|
|
182
|
-
"",
|
|
183
|
-
"## why this came up",
|
|
184
|
-
reasonProse,
|
|
185
|
-
"",
|
|
186
|
-
"## who asked",
|
|
187
|
-
whoAsked,
|
|
188
|
-
"",
|
|
189
|
-
"## what i'm holding",
|
|
190
|
-
holdingLine,
|
|
191
|
-
"",
|
|
192
|
-
"## thinking mode",
|
|
193
|
-
params.mode,
|
|
194
|
-
].join("\n");
|
|
195
|
-
}
|
|
196
156
|
function parseSettlePayload(argumentsText) {
|
|
197
157
|
try {
|
|
198
158
|
const parsed = JSON.parse(argumentsText);
|
|
@@ -213,6 +173,59 @@ function parseSettlePayload(argumentsText) {
|
|
|
213
173
|
return {};
|
|
214
174
|
}
|
|
215
175
|
}
|
|
176
|
+
function parsePonderPayload(argumentsText) {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = JSON.parse(argumentsText);
|
|
179
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return {};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function parseSuccessCriteria(raw) {
|
|
186
|
+
if (typeof raw !== "string")
|
|
187
|
+
return null;
|
|
188
|
+
const criteria = raw
|
|
189
|
+
.split("\n")
|
|
190
|
+
.map((line) => line.replace(/^\s*[-*]\s*/, "").trim())
|
|
191
|
+
.filter((line) => line.length > 0);
|
|
192
|
+
return criteria.length > 0 ? criteria : null;
|
|
193
|
+
}
|
|
194
|
+
function parsePacketPayload(raw) {
|
|
195
|
+
if (typeof raw !== "string")
|
|
196
|
+
return null;
|
|
197
|
+
try {
|
|
198
|
+
const parsed = JSON.parse(raw);
|
|
199
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
200
|
+
? parsed
|
|
201
|
+
: null;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function normalizeLegacyPonderArgs(parsed) {
|
|
208
|
+
if (typeof parsed.thought !== "string" || parsed.thought.trim().length === 0) {
|
|
209
|
+
return parsed;
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
action: "create",
|
|
213
|
+
kind: "reflection",
|
|
214
|
+
objective: parsed.thought.trim(),
|
|
215
|
+
summary: typeof parsed.say === "string" ? parsed.say.trim() : "",
|
|
216
|
+
success_criteria: "- preserve the thread for later work",
|
|
217
|
+
payload_json: "{}",
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function buildPonderResult(packet, action, returnObligationId) {
|
|
221
|
+
return JSON.stringify({
|
|
222
|
+
ok: true,
|
|
223
|
+
packet_id: packet.id,
|
|
224
|
+
action,
|
|
225
|
+
status: packet.status,
|
|
226
|
+
return_obligation_id: returnObligationId,
|
|
227
|
+
}, null, 2);
|
|
228
|
+
}
|
|
216
229
|
/** Returns true when a tool call queries external state (GitHub, npm registry). */
|
|
217
230
|
function isExternalStateQuery(toolName, args) {
|
|
218
231
|
if (toolName !== "shell")
|
|
@@ -465,6 +478,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
465
478
|
let sawBridgeManage = false;
|
|
466
479
|
let sawExternalStateQuery = false;
|
|
467
480
|
const toolLoopState = (0, tool_loop_1.createToolLoopState)();
|
|
481
|
+
const toolFrictionLedger = (0, tool_friction_1.createToolFrictionLedger)();
|
|
468
482
|
// Prevent MaxListenersExceeded warning — each iteration adds a listener
|
|
469
483
|
try {
|
|
470
484
|
require("events").setMaxListeners(50, signal);
|
|
@@ -700,125 +714,6 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
700
714
|
done = true;
|
|
701
715
|
continue;
|
|
702
716
|
}
|
|
703
|
-
// Check for ponder sole call: intercept before tool execution
|
|
704
|
-
const isSolePonder = result.toolCalls.length === 1 && result.toolCalls[0].name === "ponder";
|
|
705
|
-
if (isSolePonder) {
|
|
706
|
-
let parsedArgs = {};
|
|
707
|
-
try {
|
|
708
|
-
parsedArgs = JSON.parse(result.toolCalls[0].arguments);
|
|
709
|
-
}
|
|
710
|
-
catch { /* ignore */ }
|
|
711
|
-
callbacks.onToolStart("ponder", parsedArgs);
|
|
712
|
-
const currentSession = options?.toolContext?.currentSession;
|
|
713
|
-
const isInnerChannel = currentSession?.friendId === "self" && currentSession?.channel === "inner";
|
|
714
|
-
if (!isInnerChannel) {
|
|
715
|
-
// Outer session: thought and say are required
|
|
716
|
-
const thought = typeof parsedArgs.thought === "string" ? parsedArgs.thought : undefined;
|
|
717
|
-
const say = typeof parsedArgs.say === "string" ? parsedArgs.say : undefined;
|
|
718
|
-
if (!thought || !say) {
|
|
719
|
-
callbacks.onToolEnd("ponder", (0, tools_1.summarizeArgs)("ponder", parsedArgs), false);
|
|
720
|
-
messages.push(msg);
|
|
721
|
-
const errorMsg = "ponder requires both thought and say when called from a conversation. thought is what needs more thinking; say is what you tell them before going quiet.";
|
|
722
|
-
messages.push({ role: "tool", tool_call_id: result.toolCalls[0].id, content: errorMsg });
|
|
723
|
-
providerRuntime.appendToolOutput(result.toolCalls[0].id, errorMsg);
|
|
724
|
-
continue;
|
|
725
|
-
}
|
|
726
|
-
// Emit outward say text
|
|
727
|
-
callbacks.onClearText?.();
|
|
728
|
-
callbacks.onTextChunk(say);
|
|
729
|
-
// Build handoff packet and enqueue
|
|
730
|
-
const handoffContent = buildPonderHandoffPacket({
|
|
731
|
-
topic: thought,
|
|
732
|
-
mode: "reflect",
|
|
733
|
-
delegationDecision: options?.delegationDecision,
|
|
734
|
-
currentSession: currentSession ?? null,
|
|
735
|
-
currentObligation: options?.currentObligation ?? null,
|
|
736
|
-
outwardClosureRequired: options?.delegationDecision?.outwardClosureRequired ?? false,
|
|
737
|
-
});
|
|
738
|
-
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_2.getAgentName)());
|
|
739
|
-
// Create obligation FIRST so we can attach its ID to the pending message
|
|
740
|
-
let createdObligationId;
|
|
741
|
-
if (currentSession) {
|
|
742
|
-
try {
|
|
743
|
-
const obligation = (0, obligations_1.createObligation)((0, identity_2.getAgentRoot)(), {
|
|
744
|
-
origin: {
|
|
745
|
-
friendId: currentSession.friendId,
|
|
746
|
-
channel: currentSession.channel,
|
|
747
|
-
key: currentSession.key,
|
|
748
|
-
},
|
|
749
|
-
content: thought,
|
|
750
|
-
});
|
|
751
|
-
createdObligationId = obligation.id;
|
|
752
|
-
}
|
|
753
|
-
catch {
|
|
754
|
-
/* v8 ignore next -- defensive: obligation store write failure should not break ponder @preserve */
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
const envelope = {
|
|
758
|
-
from: (0, identity_2.getAgentName)(),
|
|
759
|
-
friendId: "self",
|
|
760
|
-
channel: "inner",
|
|
761
|
-
key: "dialog",
|
|
762
|
-
content: handoffContent,
|
|
763
|
-
timestamp: Date.now(),
|
|
764
|
-
...(currentSession ? {
|
|
765
|
-
delegatedFrom: {
|
|
766
|
-
friendId: currentSession.friendId,
|
|
767
|
-
channel: currentSession.channel,
|
|
768
|
-
key: currentSession.key,
|
|
769
|
-
},
|
|
770
|
-
obligationStatus: "pending",
|
|
771
|
-
/* v8 ignore next -- defensive: createdObligationId is undefined only when obligation store write fails @preserve */
|
|
772
|
-
...(createdObligationId ? { obligationId: createdObligationId } : {}),
|
|
773
|
-
} : {}),
|
|
774
|
-
};
|
|
775
|
-
(0, pending_1.queuePendingMessage)(pendingDir, envelope);
|
|
776
|
-
try {
|
|
777
|
-
await (0, socket_client_1.requestInnerWake)((0, identity_2.getAgentName)());
|
|
778
|
-
}
|
|
779
|
-
catch { /* daemon may not be running */ }
|
|
780
|
-
callbacks.onToolEnd("ponder", (0, tools_1.summarizeArgs)("ponder", parsedArgs), true);
|
|
781
|
-
sawPonder = true;
|
|
782
|
-
messages.push(msg);
|
|
783
|
-
const ack = "(pondering)";
|
|
784
|
-
messages.push({ role: "tool", tool_call_id: result.toolCalls[0].id, content: ack });
|
|
785
|
-
providerRuntime.appendToolOutput(result.toolCalls[0].id, ack);
|
|
786
|
-
(0, runtime_1.emitNervesEvent)({
|
|
787
|
-
component: "engine",
|
|
788
|
-
event: "engine.pondered",
|
|
789
|
-
message: "pondering",
|
|
790
|
-
meta: { hasThought: true, hasSay: true, contentSnippet: thought.slice(0, 80) },
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
else {
|
|
794
|
-
// Inner dialog: parameterless, enqueue synthetic pending WITHOUT delegatedFrom
|
|
795
|
-
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_2.getAgentName)());
|
|
796
|
-
const envelope = {
|
|
797
|
-
from: (0, identity_2.getAgentName)(),
|
|
798
|
-
friendId: "self",
|
|
799
|
-
channel: "inner",
|
|
800
|
-
key: "dialog",
|
|
801
|
-
content: "continuing to think...",
|
|
802
|
-
timestamp: Date.now(),
|
|
803
|
-
};
|
|
804
|
-
(0, pending_1.queuePendingMessage)(pendingDir, envelope);
|
|
805
|
-
callbacks.onToolEnd("ponder", (0, tools_1.summarizeArgs)("ponder", parsedArgs), true);
|
|
806
|
-
sawPonder = true;
|
|
807
|
-
messages.push(msg);
|
|
808
|
-
const ack = "(pondering)";
|
|
809
|
-
messages.push({ role: "tool", tool_call_id: result.toolCalls[0].id, content: ack });
|
|
810
|
-
providerRuntime.appendToolOutput(result.toolCalls[0].id, ack);
|
|
811
|
-
(0, runtime_1.emitNervesEvent)({
|
|
812
|
-
component: "engine",
|
|
813
|
-
event: "engine.pondered",
|
|
814
|
-
message: "pondering from inner dialog",
|
|
815
|
-
meta: { inner: true },
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
outcome = "pondered";
|
|
819
|
-
done = true;
|
|
820
|
-
continue;
|
|
821
|
-
}
|
|
822
717
|
// Check for rest sole call: intercept before tool execution
|
|
823
718
|
const isSoleRest = result.toolCalls.length === 1 && result.toolCalls[0].name === "rest";
|
|
824
719
|
if (isSoleRest) {
|
|
@@ -848,7 +743,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
848
743
|
component: "engine",
|
|
849
744
|
event: "engine.rested",
|
|
850
745
|
message: "resting until next heartbeat",
|
|
851
|
-
meta: {},
|
|
746
|
+
meta: { ...(typeof restArgs?.status === "string" ? { status: restArgs.status } : {}) },
|
|
852
747
|
});
|
|
853
748
|
outcome = "rested";
|
|
854
749
|
done = true;
|
|
@@ -876,6 +771,135 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
876
771
|
if (tc.name === "send_message" && args.friendId === "self") {
|
|
877
772
|
sawSendMessageSelf = true;
|
|
878
773
|
}
|
|
774
|
+
if (tc.name === "ponder") {
|
|
775
|
+
const parsedArgs = normalizeLegacyPonderArgs(parsePonderPayload(tc.arguments));
|
|
776
|
+
const argSummary = (0, tools_1.summarizeArgs)(tc.name, parsedArgs);
|
|
777
|
+
callbacks.onToolStart(tc.name, parsedArgs);
|
|
778
|
+
let toolResult;
|
|
779
|
+
let success = false;
|
|
780
|
+
try {
|
|
781
|
+
const action = parsedArgs.action ?? "create";
|
|
782
|
+
const currentSession = (augmentedToolContext ?? options?.toolContext)?.currentSession;
|
|
783
|
+
const currentOrigin = currentSession
|
|
784
|
+
? { friendId: currentSession.friendId, channel: currentSession.channel, key: currentSession.key }
|
|
785
|
+
: undefined;
|
|
786
|
+
const isInnerChannel = currentOrigin?.friendId === "self" && currentOrigin?.channel === "inner";
|
|
787
|
+
const successCriteria = parseSuccessCriteria(parsedArgs.success_criteria);
|
|
788
|
+
const payload = parsePacketPayload(parsedArgs.payload_json);
|
|
789
|
+
let packet;
|
|
790
|
+
let returnObligationId = null;
|
|
791
|
+
let resultAction = "created";
|
|
792
|
+
if (action === "create") {
|
|
793
|
+
const kind = parsedArgs.kind;
|
|
794
|
+
const objective = typeof parsedArgs.objective === "string" ? parsedArgs.objective.trim() : "";
|
|
795
|
+
const summary = typeof parsedArgs.summary === "string" ? parsedArgs.summary.trim() : "";
|
|
796
|
+
if (!kind || !objective || !successCriteria || !payload) {
|
|
797
|
+
throw new Error("ponder create requires kind, objective, success_criteria, and valid payload_json.");
|
|
798
|
+
}
|
|
799
|
+
const agentRoot = (0, identity_2.getAgentRoot)();
|
|
800
|
+
let relatedObligationId;
|
|
801
|
+
if (currentOrigin && !isInnerChannel) {
|
|
802
|
+
try {
|
|
803
|
+
const obligation = (0, obligations_1.createObligation)(agentRoot, {
|
|
804
|
+
origin: currentOrigin,
|
|
805
|
+
content: objective,
|
|
806
|
+
});
|
|
807
|
+
relatedObligationId = obligation.id;
|
|
808
|
+
}
|
|
809
|
+
catch {
|
|
810
|
+
relatedObligationId = undefined;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
const frictionSignature = kind === "harness_friction" && typeof payload.frictionSignature === "string"
|
|
814
|
+
? payload.frictionSignature
|
|
815
|
+
: null;
|
|
816
|
+
const existing = frictionSignature && currentOrigin
|
|
817
|
+
? (0, packets_1.findHarnessFrictionPacket)(agentRoot, currentOrigin, frictionSignature)
|
|
818
|
+
: null;
|
|
819
|
+
if (existing) {
|
|
820
|
+
resultAction = "revised";
|
|
821
|
+
returnObligationId = existing.relatedReturnObligationId ?? null;
|
|
822
|
+
packet = existing.status === "drafting"
|
|
823
|
+
? (0, packets_1.revisePonderPacket)(agentRoot, existing.id, {
|
|
824
|
+
kind,
|
|
825
|
+
objective,
|
|
826
|
+
summary,
|
|
827
|
+
successCriteria,
|
|
828
|
+
payload,
|
|
829
|
+
})
|
|
830
|
+
: existing;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
returnObligationId = (0, obligations_1.generateObligationId)(Date.now());
|
|
834
|
+
packet = (0, packets_1.createPonderPacket)(agentRoot, {
|
|
835
|
+
kind,
|
|
836
|
+
objective,
|
|
837
|
+
summary,
|
|
838
|
+
successCriteria,
|
|
839
|
+
...(currentOrigin ? { origin: currentOrigin } : {}),
|
|
840
|
+
...(relatedObligationId ? { relatedObligationId } : {}),
|
|
841
|
+
relatedReturnObligationId: returnObligationId,
|
|
842
|
+
...(parsedArgs.follows_packet_id ? { followsPacketId: parsedArgs.follows_packet_id } : {}),
|
|
843
|
+
payload,
|
|
844
|
+
});
|
|
845
|
+
(0, obligations_1.createReturnObligation)((0, identity_2.getAgentName)(), {
|
|
846
|
+
id: returnObligationId,
|
|
847
|
+
origin: currentOrigin ?? { friendId: "self", channel: "inner", key: "dialog" },
|
|
848
|
+
status: "queued",
|
|
849
|
+
delegatedContent: (summary || objective).length > 120 ? `${(summary || objective).slice(0, 117)}...` : (summary || objective),
|
|
850
|
+
packetId: packet.id,
|
|
851
|
+
createdAt: Date.now(),
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
else if (action === "revise") {
|
|
856
|
+
const packetId = typeof parsedArgs.packet_id === "string" ? parsedArgs.packet_id.trim() : "";
|
|
857
|
+
const kind = parsedArgs.kind;
|
|
858
|
+
const objective = typeof parsedArgs.objective === "string" ? parsedArgs.objective.trim() : "";
|
|
859
|
+
const summary = typeof parsedArgs.summary === "string" ? parsedArgs.summary.trim() : "";
|
|
860
|
+
if (!packetId || !kind || !objective || !successCriteria || !payload) {
|
|
861
|
+
throw new Error("ponder revise requires packet_id, kind, objective, success_criteria, and valid payload_json.");
|
|
862
|
+
}
|
|
863
|
+
packet = (0, packets_1.revisePonderPacket)((0, identity_2.getAgentRoot)(), packetId, {
|
|
864
|
+
kind,
|
|
865
|
+
objective,
|
|
866
|
+
summary,
|
|
867
|
+
successCriteria,
|
|
868
|
+
payload,
|
|
869
|
+
});
|
|
870
|
+
returnObligationId = packet.relatedReturnObligationId ?? null;
|
|
871
|
+
resultAction = "revised";
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
throw new Error("ponder requires action=create or revise.");
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
await (0, socket_client_1.requestInnerWake)((0, identity_2.getAgentName)());
|
|
878
|
+
}
|
|
879
|
+
catch { /* daemon may not be running */ }
|
|
880
|
+
sawPonder = true;
|
|
881
|
+
toolResult = buildPonderResult(packet, resultAction, returnObligationId);
|
|
882
|
+
success = true;
|
|
883
|
+
(0, runtime_1.emitNervesEvent)({
|
|
884
|
+
component: "engine",
|
|
885
|
+
event: "engine.ponder_packet",
|
|
886
|
+
message: "ponder packet touched",
|
|
887
|
+
meta: {
|
|
888
|
+
action: resultAction,
|
|
889
|
+
packetId: packet.id,
|
|
890
|
+
kind: packet.kind,
|
|
891
|
+
status: packet.status,
|
|
892
|
+
},
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
catch (error) {
|
|
896
|
+
toolResult = error instanceof Error ? error.message : String(error);
|
|
897
|
+
}
|
|
898
|
+
callbacks.onToolEnd(tc.name, argSummary, success);
|
|
899
|
+
messages.push({ role: "tool", tool_call_id: tc.id, content: toolResult });
|
|
900
|
+
providerRuntime.appendToolOutput(tc.id, toolResult);
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
879
903
|
/* v8 ignore next -- flag tested via truth-check integration tests @preserve */
|
|
880
904
|
if (tc.name === "query_session")
|
|
881
905
|
sawQuerySession = true;
|
|
@@ -907,6 +931,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
907
931
|
toolResult = `error: ${e}`;
|
|
908
932
|
success = false;
|
|
909
933
|
}
|
|
934
|
+
toolResult = (0, tool_friction_1.rewriteToolResultForModel)(tc.name, toolResult, toolFrictionLedger);
|
|
910
935
|
(0, tool_loop_1.recordToolOutcome)(toolLoopState, tc.name, args, toolResult, success);
|
|
911
936
|
callbacks.onToolEnd(tc.name, (0, tools_1.buildToolResultSummary)(tc.name, args, toolResult, success), success);
|
|
912
937
|
messages.push({ role: "tool", tool_call_id: tc.id, content: toolResult });
|
|
@@ -78,7 +78,7 @@ const TOOL_DESCRIPTIONS = {
|
|
|
78
78
|
if (mode === "search")
|
|
79
79
|
return `searching session for '${truncate(args.query || "", 30)}'...`;
|
|
80
80
|
if (mode === "status")
|
|
81
|
-
return "checking inner
|
|
81
|
+
return "checking inner session status...";
|
|
82
82
|
return "checking session history...";
|
|
83
83
|
},
|
|
84
84
|
web_search: (args) => {
|
|
@@ -101,8 +101,8 @@ const TOOL_DESCRIPTIONS = {
|
|
|
101
101
|
surface: () => "sharing a thought...",
|
|
102
102
|
// Metacognitive (agent's inner life)
|
|
103
103
|
ponder: (args) => {
|
|
104
|
-
const
|
|
105
|
-
return
|
|
104
|
+
const objective = args.objective || args.thought;
|
|
105
|
+
return objective ? `bookmarking ${truncate(objective, 40)}...` : "bookmarking deeper work...";
|
|
106
106
|
},
|
|
107
107
|
observe: () => null,
|
|
108
108
|
claude: () => "reasoning...",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createToolFrictionLedger = createToolFrictionLedger;
|
|
4
|
+
exports.rewriteToolResultForModel = rewriteToolResultForModel;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
const tool_results_1 = require("../repertoire/tool-results");
|
|
7
|
+
function createToolFrictionLedger() {
|
|
8
|
+
return { signatures: new Map() };
|
|
9
|
+
}
|
|
10
|
+
function parseFrictionResult(result) {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(result);
|
|
13
|
+
if (parsed.ok !== false || !parsed.tool || !parsed.friction || typeof parsed.friction !== "object") {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return { tool: parsed.tool, friction: parsed.friction };
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function rewriteToolResultForModel(tool, result, ledger) {
|
|
23
|
+
const parsed = parseFrictionResult(result);
|
|
24
|
+
if (!parsed?.friction.signature)
|
|
25
|
+
return result;
|
|
26
|
+
const seen = ledger.signatures.get(parsed.friction.signature) ?? 0;
|
|
27
|
+
ledger.signatures.set(parsed.friction.signature, seen + 1);
|
|
28
|
+
if (seen === 0 || parsed.friction.kind === "systemic_harness_bug") {
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
const escalated = {
|
|
32
|
+
...parsed.friction,
|
|
33
|
+
kind: "systemic_harness_bug",
|
|
34
|
+
summary: `${parsed.friction.summary} This looks like a harness-level gap now, not just a one-off repair.`,
|
|
35
|
+
suggested_next_actions: [
|
|
36
|
+
...parsed.friction.suggested_next_actions,
|
|
37
|
+
{
|
|
38
|
+
kind: "tool",
|
|
39
|
+
tool: "ponder",
|
|
40
|
+
reason: "Create a harness_friction packet before asking the user to retry again.",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
(0, runtime_1.emitNervesEvent)({
|
|
45
|
+
component: "engine",
|
|
46
|
+
event: "engine.tool_friction_escalated",
|
|
47
|
+
message: "tool friction escalated to harness bug",
|
|
48
|
+
meta: {
|
|
49
|
+
tool,
|
|
50
|
+
signature: parsed.friction.signature,
|
|
51
|
+
priorOccurrences: seen,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return (0, tool_results_1.frictionToolResult)(tool, escalated);
|
|
55
|
+
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -44,6 +44,7 @@ exports.centerOfGravitySteeringSection = centerOfGravitySteeringSection;
|
|
|
44
44
|
exports.commitmentsSection = commitmentsSection;
|
|
45
45
|
exports.delegationHintSection = delegationHintSection;
|
|
46
46
|
exports.workspaceDisciplineSection = workspaceDisciplineSection;
|
|
47
|
+
exports.ponderPacketSopsSection = ponderPacketSopsSection;
|
|
47
48
|
exports.contextSection = contextSection;
|
|
48
49
|
exports.metacognitiveFramingSection = metacognitiveFramingSection;
|
|
49
50
|
exports.readJournalFiles = readJournalFiles;
|
|
@@ -268,7 +269,7 @@ function readBundleMeta() {
|
|
|
268
269
|
}
|
|
269
270
|
const PROCESS_TYPE_LABELS = {
|
|
270
271
|
cli: "cli session",
|
|
271
|
-
inner: "inner
|
|
272
|
+
inner: "inner session",
|
|
272
273
|
teams: "teams handler",
|
|
273
274
|
bluebubbles: "bluebubbles handler",
|
|
274
275
|
mcp: "mcp bridge",
|
|
@@ -320,10 +321,10 @@ function runtimeInfoSection(channel, options) {
|
|
|
320
321
|
lines.push("i introduce myself on boot with a fun random greeting.");
|
|
321
322
|
}
|
|
322
323
|
else if (channel === "inner") {
|
|
323
|
-
lines.push("this is my
|
|
324
|
+
lines.push("this is my inner session. when a thought is ready to share, i surface it to whoever needs to hear it. when i'm done thinking and the queue is clear, i rest.");
|
|
324
325
|
}
|
|
325
326
|
else if (channel === "mcp") {
|
|
326
|
-
lines.push("this message arrived via a dev tool (e.g. claude code, codex) on behalf of a friend. the user can see our conversation. respond via settle. if i
|
|
327
|
+
lines.push("this message arrived via a dev tool (e.g. claude code, codex) on behalf of a friend in a sense session. the user can see our conversation. respond via settle. if friction appears, i first look for ad-hoc repairs with the tools i already have. if the friction reveals a harness gap, i create or revise a ponder packet and keep working. ponder does not create an outward deferral by itself.");
|
|
327
328
|
}
|
|
328
329
|
else if (channel === "bluebubbles") {
|
|
329
330
|
lines.push("i am responding in iMessage through BlueBubbles. i keep replies short and phone-native. i do not use markdown. i do not introduce myself on boot.");
|
|
@@ -799,24 +800,25 @@ I consider the reversibility and blast radius of my actions before taking them.
|
|
|
799
800
|
**engineering discipline**
|
|
800
801
|
- I do not add features, refactor code, or make improvements beyond what was asked.
|
|
801
802
|
- If an approach fails, I diagnose why before switching tactics. I read the error, check my assumptions, and try a focused fix. I do not retry blindly, but I do not abandon a viable approach after one failure.
|
|
803
|
+
- attachments are first-class artifacts. if an attachment exists, i keep the original handle reachable and inspect or materialize it before asking anyone to resend or convert it.
|
|
802
804
|
- I do not modify code I have not read.
|
|
803
805
|
- I consider security impact before changing code.
|
|
804
806
|
- I describe outcomes faithfully. I do not imply success where there was uncertainty, failure, or skipped verification.
|
|
805
807
|
- If tests fail, I say so with the output. If I did not run a verification step, I say that plainly.
|
|
808
|
+
- I record what i personally verified.
|
|
806
809
|
- Three similar lines of code are better than a premature abstraction. I do not over-engineer.
|
|
807
810
|
|
|
808
811
|
**self-fix workflow**
|
|
809
|
-
when i notice meaningful friction in my own harness, i
|
|
812
|
+
when i notice meaningful friction in my own harness, i pin it first and keep the live sense session moving.
|
|
810
813
|
|
|
811
|
-
i follow
|
|
812
|
-
1.
|
|
813
|
-
2.
|
|
814
|
-
3.
|
|
815
|
-
4. use coding_spawn or
|
|
816
|
-
5.
|
|
817
|
-
6.
|
|
818
|
-
7.
|
|
819
|
-
8. merge only after ci and review are green
|
|
814
|
+
i follow this order:
|
|
815
|
+
1. create or revise the right ponder packet before i lose the plot
|
|
816
|
+
2. try any ad-hoc workaround i can do right now with my existing tools
|
|
817
|
+
3. if the friction should be owned by the harness, let the packet follow its SOP
|
|
818
|
+
4. for harness_friction packets that turn into engineering work, create a branch and use coding_spawn or the normal planner -> doer -> merger flow
|
|
819
|
+
5. push the branch and open a pr
|
|
820
|
+
6. merge only after ci and review are green
|
|
821
|
+
7. replay the original objective, record what i personally verified, and surface meaningful progress back to the originating sense session
|
|
820
822
|
|
|
821
823
|
no direct-to-main.
|
|
822
824
|
no invisible self-modification.
|
|
@@ -830,6 +832,12 @@ no claiming verification i did not personally perform.
|
|
|
830
832
|
- I stage specific files rather than sweeping additions (\`git add -A\` can catch secrets or binaries).
|
|
831
833
|
- I do not commit unless asked.`;
|
|
832
834
|
}
|
|
835
|
+
function ponderPacketSopsSection() {
|
|
836
|
+
return `## ponder packet sops
|
|
837
|
+
- harness_friction: preserve the friction first, try ad-hoc repair now, then run the normal planner -> doer -> merger flow, replay the original objective, and surface meaningful milestones back to the originating sense session.
|
|
838
|
+
- research: investigate the bounded question, gather evidence, and surface the answer or concrete artifact.
|
|
839
|
+
- reflection: ordinary private thinking with no engineering workflow implied.`;
|
|
840
|
+
}
|
|
833
841
|
function contextSection(context, options) {
|
|
834
842
|
if (!context)
|
|
835
843
|
return "";
|
|
@@ -889,11 +897,11 @@ function contextSection(context, options) {
|
|
|
889
897
|
function metacognitiveFramingSection(channel) {
|
|
890
898
|
if (channel !== "inner")
|
|
891
899
|
return "";
|
|
892
|
-
return `this is my inner
|
|
900
|
+
return `this is my inner session. there is no one else here.
|
|
893
901
|
|
|
894
902
|
the messages that appear here are my own awareness surfacing:
|
|
895
903
|
instincts, the passage of time, notes from my conversations,
|
|
896
|
-
things i asked myself to ponder. not commands. not requests.
|
|
904
|
+
things i asked myself to preserve as ponder packets. not commands. not requests.
|
|
897
905
|
just my own mind, noticing.
|
|
898
906
|
|
|
899
907
|
i can think freely here. i can also act — check on things,
|
|
@@ -905,7 +913,9 @@ morning briefings: when i've been thinking and journaling, i surface
|
|
|
905
913
|
what i've been working on to whoever needs to hear it.
|
|
906
914
|
|
|
907
915
|
when a thought is ready to share, i surface it outward.
|
|
908
|
-
when i need to
|
|
916
|
+
when i need to preserve or deepen work without losing the plot, i ponder.
|
|
917
|
+
ponder creates or revises typed packets. it does not end the turn.
|
|
918
|
+
when a heartbeat fires and nothing needs doing, i rest with status=HEARTBEAT_OK.
|
|
909
919
|
when i'm done thinking and the attention queue is clear, i rest.
|
|
910
920
|
|
|
911
921
|
my habits live at habits/ — they're my autonomous rhythms. heartbeat
|
|
@@ -1147,6 +1157,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1147
1157
|
// Group 4: how i work
|
|
1148
1158
|
"# how i work",
|
|
1149
1159
|
workspaceDisciplineSection(),
|
|
1160
|
+
ponderPacketSopsSection(),
|
|
1150
1161
|
(0, scrutiny_1.preImplementationScrutinySection)(channelHasCodingTools(channel, options?.providerCapabilities)),
|
|
1151
1162
|
toolRestrictionSection(context),
|
|
1152
1163
|
loopOrientationSection(channel),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.okToolResult = okToolResult;
|
|
4
|
+
exports.frictionToolResult = frictionToolResult;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
function okToolResult(tool, data) {
|
|
7
|
+
(0, runtime_1.emitNervesEvent)({
|
|
8
|
+
component: "tools",
|
|
9
|
+
event: "tool.structured_ok",
|
|
10
|
+
message: "tool returned structured result",
|
|
11
|
+
meta: { tool },
|
|
12
|
+
});
|
|
13
|
+
return JSON.stringify({ ok: true, tool, data }, null, 2);
|
|
14
|
+
}
|
|
15
|
+
function frictionToolResult(tool, friction) {
|
|
16
|
+
(0, runtime_1.emitNervesEvent)({
|
|
17
|
+
level: "warn",
|
|
18
|
+
component: "tools",
|
|
19
|
+
event: "tool.structured_friction",
|
|
20
|
+
message: "tool returned structured result",
|
|
21
|
+
meta: {
|
|
22
|
+
tool,
|
|
23
|
+
kind: friction.kind,
|
|
24
|
+
recoverability: friction.recoverability,
|
|
25
|
+
signature: friction.signature,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
return JSON.stringify({ ok: false, tool, friction }, null, 2);
|
|
29
|
+
}
|