@ouro.bot/cli 0.1.0-alpha.134 → 0.1.0-alpha.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.json +7 -0
- package/dist/heart/core.js +63 -39
- package/dist/heart/tool-loop.js +5 -1
- package/dist/mind/context.js +62 -0
- package/dist/mind/prompt.js +9 -4
- package/dist/repertoire/ado-semantic.js +6 -0
- package/dist/repertoire/coding/tools.js +5 -0
- package/dist/repertoire/tools-base.js +24 -31
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-teams.js +9 -36
- package/dist/repertoire/tools.js +15 -69
- package/package.json +1 -1
- package/dist/heart/safe-workspace.js +0 -381
package/changelog.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.135",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Metacognitive tool vocabulary complete: go_inward renamed to descend. RunAgentOutcome value is now 'descended', event is 'engine.descended'.",
|
|
8
|
+
"summarizeArgs rewritten: reads summaryKeys from ToolDefinition instead of per-tool switch branches. summarizeTeamsArgs and summarizeGithubArgs eliminated."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.134",
|
|
6
13
|
"changes": [
|
package/dist/heart/core.js
CHANGED
|
@@ -176,7 +176,7 @@ Object.defineProperty(exports, "buildSystem", { enumerable: true, get: function
|
|
|
176
176
|
const SOLE_CALL_REJECTION = {
|
|
177
177
|
settle: "rejected: settle must be the only tool call. finish your work first, then call settle alone.",
|
|
178
178
|
observe: "rejected: observe must be the only tool call. call observe alone when you want to stay silent.",
|
|
179
|
-
|
|
179
|
+
descend: "rejected: descend must be the only tool call. finish your other work first, then call descend alone.",
|
|
180
180
|
};
|
|
181
181
|
const DELEGATION_REASON_PROSE_HANDOFF = {
|
|
182
182
|
explicit_reflection: "something in the conversation called for reflection",
|
|
@@ -186,7 +186,7 @@ const DELEGATION_REASON_PROSE_HANDOFF = {
|
|
|
186
186
|
non_fast_path_tool: "this needs tools beyond a simple reply",
|
|
187
187
|
unresolved_obligation: "there's an unresolved commitment from an earlier conversation",
|
|
188
188
|
};
|
|
189
|
-
function
|
|
189
|
+
function buildDescendHandoffPacket(params) {
|
|
190
190
|
const reasons = params.delegationDecision?.reasons ?? [];
|
|
191
191
|
const reasonProse = reasons.length > 0
|
|
192
192
|
? reasons.map((r) => DELEGATION_REASON_PROSE_HANDOFF[r]).join("; ")
|
|
@@ -245,14 +245,14 @@ function isExternalStateQuery(toolName, args) {
|
|
|
245
245
|
const cmd = String(args.command ?? "");
|
|
246
246
|
return /\bgh\s+(pr|run|api|issue)\b/.test(cmd) || /\bnpm\s+(view|info|show)\b/.test(cmd);
|
|
247
247
|
}
|
|
248
|
-
function getSettleRetryError(mustResolveBeforeHandoff, intent, sawSteeringFollowUp, _delegationDecision, sawSendMessageSelf,
|
|
248
|
+
function getSettleRetryError(mustResolveBeforeHandoff, intent, sawSteeringFollowUp, _delegationDecision, sawSendMessageSelf, sawDescend, _sawQuerySession, currentObligation, innerJob, sawExternalStateQuery) {
|
|
249
249
|
// Delegation adherence removed: the delegation decision is surfaced in the
|
|
250
250
|
// system prompt as a suggestion. Hard-gating settle caused infinite
|
|
251
251
|
// rejection loops where the agent couldn't respond to the user at all.
|
|
252
252
|
// The agent is free to follow or ignore the delegation hint.
|
|
253
253
|
// 2. Pending obligation not addressed
|
|
254
|
-
if (innerJob?.obligationStatus === "pending" && !sawSendMessageSelf && !
|
|
255
|
-
return "you're still holding something from an earlier conversation -- someone is waiting for your answer. finish the thought first, or
|
|
254
|
+
if (innerJob?.obligationStatus === "pending" && !sawSendMessageSelf && !sawDescend) {
|
|
255
|
+
return "you're still holding something from an earlier conversation -- someone is waiting for your answer. finish the thought first, or descend to keep working on it privately.";
|
|
256
256
|
}
|
|
257
257
|
// 3. mustResolveBeforeHandoff + missing intent
|
|
258
258
|
if (mustResolveBeforeHandoff && !intent) {
|
|
@@ -496,7 +496,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
496
496
|
let mustResolveBeforeHandoffActive = options?.mustResolveBeforeHandoff === true;
|
|
497
497
|
let currentReasoningEffort = "medium";
|
|
498
498
|
let sawSendMessageSelf = false;
|
|
499
|
-
let
|
|
499
|
+
let sawDescend = false;
|
|
500
500
|
let sawQuerySession = false;
|
|
501
501
|
let sawBridgeManage = false;
|
|
502
502
|
let sawExternalStateQuery = false;
|
|
@@ -522,11 +522,11 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
522
522
|
providerRuntime.resetTurnState(messages);
|
|
523
523
|
while (!done) {
|
|
524
524
|
// Channel-based tool filtering:
|
|
525
|
-
// - Inner dialog: exclude
|
|
525
|
+
// - Inner dialog: exclude descend (already inward), send_message (delivery via surface), observe (no one to observe)
|
|
526
526
|
// - 1:1 sessions: exclude observe (can't ignore someone talking directly to you)
|
|
527
527
|
// - Group chats: observe available
|
|
528
528
|
//
|
|
529
|
-
//
|
|
529
|
+
// descend, settle, surface, and observe are always assembled based on channel context.
|
|
530
530
|
// toolChoiceRequired only controls whether tool_choice: "required" is set in the API call.
|
|
531
531
|
const isInnerDialog = channel === "inner";
|
|
532
532
|
const filteredBaseTools = isInnerDialog
|
|
@@ -534,7 +534,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
534
534
|
: baseTools;
|
|
535
535
|
const activeTools = [
|
|
536
536
|
...filteredBaseTools,
|
|
537
|
-
...(!isInnerDialog ? [tools_1.
|
|
537
|
+
...(!isInnerDialog ? [tools_1.descendTool] : []),
|
|
538
538
|
...(isInnerDialog ? [surface_tool_1.surfaceToolDef] : []),
|
|
539
539
|
...(currentContext?.isGroupChat && !isInnerDialog ? [tools_1.observeTool] : []),
|
|
540
540
|
tools_1.settleTool,
|
|
@@ -619,9 +619,18 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
619
619
|
else {
|
|
620
620
|
// Check for settle sole call: intercept before tool execution
|
|
621
621
|
if (isSoleSettle) {
|
|
622
|
+
/* v8 ignore next -- defensive: JSON.parse catch for malformed settle args @preserve */
|
|
623
|
+
const settleArgs = (() => { try {
|
|
624
|
+
return JSON.parse(result.toolCalls[0].arguments);
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
return {};
|
|
628
|
+
} })();
|
|
629
|
+
callbacks.onToolStart("settle", settleArgs);
|
|
622
630
|
// Inner dialog attention queue gate: reject settle if items remain
|
|
623
631
|
const attentionQueue = (augmentedToolContext ?? options?.toolContext)?.delegatedOrigins;
|
|
624
632
|
if (isInnerDialog && attentionQueue && attentionQueue.length > 0) {
|
|
633
|
+
callbacks.onToolEnd("settle", (0, tools_1.summarizeArgs)("settle", settleArgs), false);
|
|
625
634
|
callbacks.onClearText?.();
|
|
626
635
|
messages.push(msg);
|
|
627
636
|
const gateMessage = "you're holding thoughts someone is waiting for — surface them before you settle.";
|
|
@@ -634,6 +643,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
634
643
|
const { answer, intent } = parseSettlePayload(result.toolCalls[0].arguments);
|
|
635
644
|
// Inner dialog settle: no CompletionMetadata, "(settled)" ack
|
|
636
645
|
if (isInnerDialog) {
|
|
646
|
+
callbacks.onToolEnd("settle", (0, tools_1.summarizeArgs)("settle", settleArgs), true);
|
|
637
647
|
messages.push(msg);
|
|
638
648
|
const settled = "(settled)";
|
|
639
649
|
messages.push({ role: "tool", tool_call_id: result.toolCalls[0].id, content: settled });
|
|
@@ -642,7 +652,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
642
652
|
done = true;
|
|
643
653
|
continue;
|
|
644
654
|
}
|
|
645
|
-
const retryError = getSettleRetryError(mustResolveBeforeHandoffActive, intent, sawSteeringFollowUp, options?.delegationDecision, sawSendMessageSelf,
|
|
655
|
+
const retryError = getSettleRetryError(mustResolveBeforeHandoffActive, intent, sawSteeringFollowUp, options?.delegationDecision, sawSendMessageSelf, sawDescend, sawQuerySession, options?.currentObligation ?? null, options?.activeWorkFrame?.inner?.job, sawExternalStateQuery);
|
|
646
656
|
const deliveredAnswer = answer;
|
|
647
657
|
const validDirectReply = mustResolveBeforeHandoffActive && intent === "direct_reply" && sawSteeringFollowUp;
|
|
648
658
|
const validTerminalIntent = intent === "complete" || intent === "blocked";
|
|
@@ -650,6 +660,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
650
660
|
&& !retryError
|
|
651
661
|
&& (!mustResolveBeforeHandoffActive || validDirectReply || validTerminalIntent);
|
|
652
662
|
if (validClosure) {
|
|
663
|
+
callbacks.onToolEnd("settle", (0, tools_1.summarizeArgs)("settle", settleArgs), true);
|
|
653
664
|
completion = {
|
|
654
665
|
answer: deliveredAnswer,
|
|
655
666
|
intent: validDirectReply ? "direct_reply" : intent === "blocked" ? "blocked" : "complete",
|
|
@@ -684,6 +695,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
684
695
|
// Answer is undefined -- the model's settle was incomplete or
|
|
685
696
|
// malformed. Clear any partial streamed text or noise, then push the
|
|
686
697
|
// assistant msg + error tool result and let the model try again.
|
|
698
|
+
callbacks.onToolEnd("settle", (0, tools_1.summarizeArgs)("settle", settleArgs), false);
|
|
687
699
|
callbacks.onClearText?.();
|
|
688
700
|
messages.push(msg);
|
|
689
701
|
const toolRetryMessage = retryError
|
|
@@ -696,19 +708,24 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
696
708
|
// Check for observe sole call: intercept before tool execution
|
|
697
709
|
const isSoleObserve = result.toolCalls.length === 1 && result.toolCalls[0].name === "observe";
|
|
698
710
|
if (isSoleObserve) {
|
|
699
|
-
|
|
700
|
-
try {
|
|
701
|
-
|
|
702
|
-
if (typeof parsed?.reason === "string")
|
|
703
|
-
reason = parsed.reason;
|
|
711
|
+
/* v8 ignore next -- defensive: JSON.parse catch for malformed observe args @preserve */
|
|
712
|
+
const observeArgs = (() => { try {
|
|
713
|
+
return JSON.parse(result.toolCalls[0].arguments);
|
|
704
714
|
}
|
|
705
|
-
catch {
|
|
715
|
+
catch {
|
|
716
|
+
return {};
|
|
717
|
+
} })();
|
|
718
|
+
let reason;
|
|
719
|
+
if (typeof observeArgs?.reason === "string")
|
|
720
|
+
reason = observeArgs.reason;
|
|
721
|
+
callbacks.onToolStart("observe", observeArgs);
|
|
706
722
|
(0, runtime_1.emitNervesEvent)({
|
|
707
723
|
component: "engine",
|
|
708
724
|
event: "engine.observe",
|
|
709
725
|
message: "agent declined to respond in group chat",
|
|
710
726
|
meta: { ...(reason ? { reason } : {}) },
|
|
711
727
|
});
|
|
728
|
+
callbacks.onToolEnd("observe", (0, tools_1.summarizeArgs)("observe", observeArgs), true);
|
|
712
729
|
messages.push(msg);
|
|
713
730
|
const silenced = "(silenced)";
|
|
714
731
|
messages.push({ role: "tool", tool_call_id: result.toolCalls[0].id, content: silenced });
|
|
@@ -717,14 +734,15 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
717
734
|
done = true;
|
|
718
735
|
continue;
|
|
719
736
|
}
|
|
720
|
-
// Check for
|
|
721
|
-
const
|
|
722
|
-
if (
|
|
737
|
+
// Check for descend sole call: intercept before tool execution
|
|
738
|
+
const isSoleDescend = result.toolCalls.length === 1 && result.toolCalls[0].name === "descend";
|
|
739
|
+
if (isSoleDescend) {
|
|
723
740
|
let parsedArgs = {};
|
|
724
741
|
try {
|
|
725
742
|
parsedArgs = JSON.parse(result.toolCalls[0].arguments);
|
|
726
743
|
}
|
|
727
744
|
catch { /* ignore */ }
|
|
745
|
+
callbacks.onToolStart("descend", parsedArgs);
|
|
728
746
|
/* v8 ignore next -- defensive: topic always string from model @preserve */
|
|
729
747
|
const topic = typeof parsedArgs.topic === "string" ? parsedArgs.topic : "";
|
|
730
748
|
const answer = typeof parsedArgs.answer === "string" ? parsedArgs.answer : undefined;
|
|
@@ -738,7 +756,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
738
756
|
callbacks.onTextChunk(answer);
|
|
739
757
|
}
|
|
740
758
|
// Build handoff packet and enqueue
|
|
741
|
-
const handoffContent =
|
|
759
|
+
const handoffContent = buildDescendHandoffPacket({
|
|
742
760
|
topic,
|
|
743
761
|
mode,
|
|
744
762
|
delegationDecision: options?.delegationDecision,
|
|
@@ -749,6 +767,24 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
749
767
|
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_2.getAgentName)());
|
|
750
768
|
const currentSession = options?.toolContext?.currentSession;
|
|
751
769
|
const isInnerChannel = currentSession?.friendId === "self" && currentSession?.channel === "inner";
|
|
770
|
+
// Create obligation FIRST so we can attach its ID to the pending message
|
|
771
|
+
let createdObligationId;
|
|
772
|
+
if (currentSession && !isInnerChannel) {
|
|
773
|
+
try {
|
|
774
|
+
const obligation = (0, obligations_1.createObligation)((0, identity_2.getAgentRoot)(), {
|
|
775
|
+
origin: {
|
|
776
|
+
friendId: currentSession.friendId,
|
|
777
|
+
channel: currentSession.channel,
|
|
778
|
+
key: currentSession.key,
|
|
779
|
+
},
|
|
780
|
+
content: topic,
|
|
781
|
+
});
|
|
782
|
+
createdObligationId = obligation.id;
|
|
783
|
+
}
|
|
784
|
+
catch {
|
|
785
|
+
/* v8 ignore next -- defensive: obligation store write failure should not break descend @preserve */
|
|
786
|
+
}
|
|
787
|
+
}
|
|
752
788
|
const envelope = {
|
|
753
789
|
from: (0, identity_2.getAgentName)(),
|
|
754
790
|
friendId: "self",
|
|
@@ -764,40 +800,28 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
764
800
|
key: currentSession.key,
|
|
765
801
|
},
|
|
766
802
|
obligationStatus: "pending",
|
|
803
|
+
/* v8 ignore next -- defensive: createdObligationId is undefined only when obligation store write fails @preserve */
|
|
804
|
+
...(createdObligationId ? { obligationId: createdObligationId } : {}),
|
|
767
805
|
} : {}),
|
|
768
806
|
};
|
|
769
807
|
(0, pending_1.queuePendingMessage)(pendingDir, envelope);
|
|
770
|
-
if (currentSession && !isInnerChannel) {
|
|
771
|
-
try {
|
|
772
|
-
(0, obligations_1.createObligation)((0, identity_2.getAgentRoot)(), {
|
|
773
|
-
origin: {
|
|
774
|
-
friendId: currentSession.friendId,
|
|
775
|
-
channel: currentSession.channel,
|
|
776
|
-
key: currentSession.key,
|
|
777
|
-
},
|
|
778
|
-
content: topic,
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
catch {
|
|
782
|
-
/* v8 ignore next -- defensive: obligation store write failure should not break go_inward @preserve */
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
808
|
try {
|
|
786
809
|
await (0, socket_client_1.requestInnerWake)((0, identity_2.getAgentName)());
|
|
787
810
|
}
|
|
788
811
|
catch { /* daemon may not be running */ }
|
|
789
|
-
|
|
812
|
+
callbacks.onToolEnd("descend", (0, tools_1.summarizeArgs)("descend", parsedArgs), true);
|
|
813
|
+
sawDescend = true;
|
|
790
814
|
messages.push(msg);
|
|
791
815
|
const ack = "(going inward)";
|
|
792
816
|
messages.push({ role: "tool", tool_call_id: result.toolCalls[0].id, content: ack });
|
|
793
817
|
providerRuntime.appendToolOutput(result.toolCalls[0].id, ack);
|
|
794
818
|
(0, runtime_1.emitNervesEvent)({
|
|
795
819
|
component: "engine",
|
|
796
|
-
event: "engine.
|
|
820
|
+
event: "engine.descended",
|
|
797
821
|
message: "taking thread inward",
|
|
798
822
|
meta: { mode, hasAnswer: answer !== undefined, contentSnippet: topic.slice(0, 80) },
|
|
799
823
|
});
|
|
800
|
-
outcome = "
|
|
824
|
+
outcome = "descended";
|
|
801
825
|
done = true;
|
|
802
826
|
continue;
|
|
803
827
|
}
|
|
@@ -957,7 +981,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
957
981
|
trace_id: traceId,
|
|
958
982
|
component: "engine",
|
|
959
983
|
message: "runAgent turn completed",
|
|
960
|
-
meta: { done,
|
|
984
|
+
meta: { done, sawDescend, sawQuerySession, sawBridgeManage },
|
|
961
985
|
});
|
|
962
986
|
return {
|
|
963
987
|
usage: lastUsage,
|
package/dist/heart/tool-loop.js
CHANGED
|
@@ -178,8 +178,12 @@ function recordToolOutcome(state, toolName, args, result, success) {
|
|
|
178
178
|
state.history.splice(0, state.history.length - exports.TOOL_LOOP_HISTORY_LIMIT);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
+
// Tools that must never be blocked by the circuit breaker.
|
|
182
|
+
// settle = end the turn, surface = deliver results outward.
|
|
183
|
+
// Blocking these traps the agent: it can think all it wants but can never speak.
|
|
184
|
+
const CIRCUIT_BREAKER_EXEMPT = new Set(["settle", "surface"]);
|
|
181
185
|
function detectToolLoop(state, toolName, args) {
|
|
182
|
-
if (state.history.length >= exports.GLOBAL_CIRCUIT_BREAKER_LIMIT) {
|
|
186
|
+
if (state.history.length >= exports.GLOBAL_CIRCUIT_BREAKER_LIMIT && !CIRCUIT_BREAKER_EXEMPT.has(toolName)) {
|
|
183
187
|
return emitDetection("global_circuit_breaker", toolName, state.history.length, `this turn has already made ${state.history.length} tool calls. stop thrashing, use the current evidence, and either change approach or answer truthfully with the best grounded status.`);
|
|
184
188
|
}
|
|
185
189
|
const callHash = digest(normalizeArgs(toolName, args));
|
package/dist/mind/context.js
CHANGED
|
@@ -36,7 +36,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.trimMessages = trimMessages;
|
|
37
37
|
exports.validateSessionMessages = validateSessionMessages;
|
|
38
38
|
exports.repairSessionMessages = repairSessionMessages;
|
|
39
|
+
exports.migrateToolNames = migrateToolNames;
|
|
39
40
|
exports.saveSession = saveSession;
|
|
41
|
+
exports.appendSyntheticAssistantMessage = appendSyntheticAssistantMessage;
|
|
40
42
|
exports.loadSession = loadSession;
|
|
41
43
|
exports.postTurn = postTurn;
|
|
42
44
|
exports.deleteSession = deleteSession;
|
|
@@ -255,6 +257,43 @@ function stripOrphanedToolResults(messages) {
|
|
|
255
257
|
}
|
|
256
258
|
return repaired;
|
|
257
259
|
}
|
|
260
|
+
// Tool renames that have shipped. Old names in session history confuse the
|
|
261
|
+
// model into calling tools that no longer exist. Applied on session load so
|
|
262
|
+
// the transcript uses the current vocabulary.
|
|
263
|
+
const TOOL_NAME_MIGRATIONS = {
|
|
264
|
+
final_answer: "settle",
|
|
265
|
+
no_response: "observe",
|
|
266
|
+
go_inward: "descend",
|
|
267
|
+
};
|
|
268
|
+
function migrateToolNames(messages) {
|
|
269
|
+
let migrated = 0;
|
|
270
|
+
const result = messages.map((msg) => {
|
|
271
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls) || msg.tool_calls.length === 0)
|
|
272
|
+
return msg;
|
|
273
|
+
let changed = false;
|
|
274
|
+
const updatedCalls = msg.tool_calls.map((tc) => {
|
|
275
|
+
if (tc.type !== "function")
|
|
276
|
+
return tc;
|
|
277
|
+
const newName = TOOL_NAME_MIGRATIONS[tc.function.name];
|
|
278
|
+
if (!newName)
|
|
279
|
+
return tc;
|
|
280
|
+
changed = true;
|
|
281
|
+
migrated++;
|
|
282
|
+
return { ...tc, function: { ...tc.function, name: newName } };
|
|
283
|
+
});
|
|
284
|
+
return changed ? { ...msg, tool_calls: updatedCalls } : msg;
|
|
285
|
+
});
|
|
286
|
+
if (migrated > 0) {
|
|
287
|
+
(0, runtime_1.emitNervesEvent)({
|
|
288
|
+
level: "info",
|
|
289
|
+
event: "mind.session_tool_name_migration",
|
|
290
|
+
component: "mind",
|
|
291
|
+
message: "migrated deprecated tool names in session history",
|
|
292
|
+
meta: { migrated },
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
258
297
|
function saveSession(filePath, messages, lastUsage, state) {
|
|
259
298
|
const violations = validateSessionMessages(messages);
|
|
260
299
|
if (violations.length > 0) {
|
|
@@ -280,6 +319,28 @@ function saveSession(filePath, messages, lastUsage, state) {
|
|
|
280
319
|
}
|
|
281
320
|
fs.writeFileSync(filePath, JSON.stringify(envelope, null, 2));
|
|
282
321
|
}
|
|
322
|
+
function appendSyntheticAssistantMessage(filePath, content) {
|
|
323
|
+
try {
|
|
324
|
+
if (!fs.existsSync(filePath))
|
|
325
|
+
return false;
|
|
326
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
327
|
+
const data = JSON.parse(raw);
|
|
328
|
+
if (data.version !== 1 || !Array.isArray(data.messages))
|
|
329
|
+
return false;
|
|
330
|
+
data.messages.push({ role: "assistant", content });
|
|
331
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
332
|
+
(0, runtime_1.emitNervesEvent)({
|
|
333
|
+
component: "mind",
|
|
334
|
+
event: "mind.session_synthetic_message_appended",
|
|
335
|
+
message: "appended synthetic assistant message to session",
|
|
336
|
+
meta: { path: filePath, contentLength: content.length },
|
|
337
|
+
});
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
283
344
|
function loadSession(filePath) {
|
|
284
345
|
try {
|
|
285
346
|
const raw = fs.readFileSync(filePath, "utf-8");
|
|
@@ -299,6 +360,7 @@ function loadSession(filePath) {
|
|
|
299
360
|
messages = repairSessionMessages(messages);
|
|
300
361
|
}
|
|
301
362
|
messages = stripOrphanedToolResults(messages);
|
|
363
|
+
messages = migrateToolNames(messages);
|
|
302
364
|
const rawState = data?.state && typeof data.state === "object" && data.state !== null
|
|
303
365
|
? data.state
|
|
304
366
|
: undefined;
|
package/dist/mind/prompt.js
CHANGED
|
@@ -56,6 +56,7 @@ const ouro_version_manager_1 = require("../heart/daemon/ouro-version-manager");
|
|
|
56
56
|
const tools_1 = require("../repertoire/tools");
|
|
57
57
|
const skills_1 = require("../repertoire/skills");
|
|
58
58
|
const identity_1 = require("../heart/identity");
|
|
59
|
+
const runtime_mode_1 = require("../heart/daemon/runtime-mode");
|
|
59
60
|
const types_1 = require("./friends/types");
|
|
60
61
|
const trust_explanation_1 = require("./friends/trust-explanation");
|
|
61
62
|
const channel_1 = require("./friends/channel");
|
|
@@ -262,6 +263,9 @@ function runtimeInfoSection(channel) {
|
|
|
262
263
|
}
|
|
263
264
|
}
|
|
264
265
|
lines.push(`changelog available at: ${(0, bundle_manifest_1.getChangelogPath)()}`);
|
|
266
|
+
const sourceRoot = (0, identity_1.getRepoRoot)();
|
|
267
|
+
lines.push(`source root: ${sourceRoot}`);
|
|
268
|
+
lines.push(`runtime mode: ${(0, runtime_mode_1.detectRuntimeMode)(sourceRoot)}`);
|
|
265
269
|
lines.push(`cwd: ${process.cwd()}`);
|
|
266
270
|
lines.push(`channel: ${channel}`);
|
|
267
271
|
lines.push(`current sense: ${channel}`);
|
|
@@ -557,7 +561,7 @@ i should orient around that live lane first, then decide what still needs to com
|
|
|
557
561
|
return `## where my attention is
|
|
558
562
|
i have unfinished work that needs attention before i move on.
|
|
559
563
|
|
|
560
|
-
i can take it inward with
|
|
564
|
+
i can take it inward with descend to think privately, or address it directly here.`;
|
|
561
565
|
}
|
|
562
566
|
if (cog === "shared-work") {
|
|
563
567
|
/* v8 ignore stop */
|
|
@@ -626,12 +630,13 @@ do NOT call no-op tools just before \`settle\`. if i am done, i call \`settle\`
|
|
|
626
630
|
}
|
|
627
631
|
function workspaceDisciplineSection() {
|
|
628
632
|
return `## repo workspace discipline
|
|
629
|
-
|
|
630
|
-
|
|
633
|
+
my source code lives at the path shown in \`source root\` above. that always matches my running version.
|
|
634
|
+
when i need to read my own code to understand my tools or debug behavior, i read from source root.
|
|
635
|
+
when i need to EDIT harness code (self-fix, feature work), i create a git worktree first so i don't dirty the working tree.
|
|
631
636
|
|
|
632
637
|
before the first repo edit, i tell the user in 1-2 short lines:
|
|
633
638
|
- the friction i'm fixing
|
|
634
|
-
- the
|
|
639
|
+
- the worktree path/branch i'm using
|
|
635
640
|
- the first concrete action i'm taking`;
|
|
636
641
|
}
|
|
637
642
|
function contextSection(context, options) {
|
|
@@ -279,6 +279,7 @@ exports.adoSemanticToolDefinitions = [
|
|
|
279
279
|
return formatForChannel(items, ctx, organization, project);
|
|
280
280
|
},
|
|
281
281
|
integration: "ado",
|
|
282
|
+
summaryKeys: ["organization", "project"],
|
|
282
283
|
},
|
|
283
284
|
// -- ado_create_epic --
|
|
284
285
|
{
|
|
@@ -318,6 +319,7 @@ exports.adoSemanticToolDefinitions = [
|
|
|
318
319
|
},
|
|
319
320
|
integration: "ado",
|
|
320
321
|
confirmationRequired: true,
|
|
322
|
+
summaryKeys: ["organization", "project", "title"],
|
|
321
323
|
},
|
|
322
324
|
// -- ado_create_issue --
|
|
323
325
|
{
|
|
@@ -359,6 +361,7 @@ exports.adoSemanticToolDefinitions = [
|
|
|
359
361
|
},
|
|
360
362
|
integration: "ado",
|
|
361
363
|
confirmationRequired: true,
|
|
364
|
+
summaryKeys: ["organization", "project", "title"],
|
|
362
365
|
},
|
|
363
366
|
// -- ado_move_items --
|
|
364
367
|
{
|
|
@@ -413,6 +416,7 @@ exports.adoSemanticToolDefinitions = [
|
|
|
413
416
|
},
|
|
414
417
|
integration: "ado",
|
|
415
418
|
confirmationRequired: true,
|
|
419
|
+
summaryKeys: ["organization", "project", "workItemIds"],
|
|
416
420
|
},
|
|
417
421
|
// -- ado_restructure_backlog --
|
|
418
422
|
{
|
|
@@ -471,6 +475,7 @@ exports.adoSemanticToolDefinitions = [
|
|
|
471
475
|
},
|
|
472
476
|
integration: "ado",
|
|
473
477
|
confirmationRequired: true,
|
|
478
|
+
summaryKeys: ["organization", "project"],
|
|
474
479
|
},
|
|
475
480
|
// -- ado_validate_structure --
|
|
476
481
|
{
|
|
@@ -672,6 +677,7 @@ exports.adoSemanticToolDefinitions = [
|
|
|
672
677
|
},
|
|
673
678
|
integration: "ado",
|
|
674
679
|
confirmationRequired: true,
|
|
680
|
+
summaryKeys: ["organization", "project"],
|
|
675
681
|
},
|
|
676
682
|
// -- ado_detect_orphans --
|
|
677
683
|
{
|
|
@@ -279,6 +279,7 @@ exports.codingToolDefinitions = [
|
|
|
279
279
|
}
|
|
280
280
|
return JSON.stringify(session);
|
|
281
281
|
},
|
|
282
|
+
summaryKeys: ["runner", "workdir", "taskRef"],
|
|
282
283
|
},
|
|
283
284
|
{
|
|
284
285
|
tool: codingStatusTool,
|
|
@@ -294,6 +295,7 @@ exports.codingToolDefinitions = [
|
|
|
294
295
|
return `session not found: ${sessionId}`;
|
|
295
296
|
return JSON.stringify(session);
|
|
296
297
|
},
|
|
298
|
+
summaryKeys: ["sessionId"],
|
|
297
299
|
},
|
|
298
300
|
{
|
|
299
301
|
tool: codingTailTool,
|
|
@@ -307,6 +309,7 @@ exports.codingToolDefinitions = [
|
|
|
307
309
|
return `session not found: ${sessionId}`;
|
|
308
310
|
return (0, index_1.formatCodingTail)(session);
|
|
309
311
|
},
|
|
312
|
+
summaryKeys: ["sessionId"],
|
|
310
313
|
},
|
|
311
314
|
{
|
|
312
315
|
tool: codingSendInputTool,
|
|
@@ -320,6 +323,7 @@ exports.codingToolDefinitions = [
|
|
|
320
323
|
return "input is required";
|
|
321
324
|
return JSON.stringify((0, index_1.getCodingSessionManager)().sendInput(sessionId, input));
|
|
322
325
|
},
|
|
326
|
+
summaryKeys: ["sessionId", "input"],
|
|
323
327
|
},
|
|
324
328
|
{
|
|
325
329
|
tool: codingKillTool,
|
|
@@ -330,5 +334,6 @@ exports.codingToolDefinitions = [
|
|
|
330
334
|
return "sessionId is required";
|
|
331
335
|
return JSON.stringify((0, index_1.getCodingSessionManager)().killSession(sessionId));
|
|
332
336
|
},
|
|
337
|
+
summaryKeys: ["sessionId"],
|
|
333
338
|
},
|
|
334
339
|
];
|