@ouro.bot/cli 0.1.0-alpha.729 → 0.1.0-alpha.730
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/approval-store.js +791 -0
- package/dist/heart/core.js +177 -0
- package/dist/heart/session-events.js +167 -0
- package/dist/heart/tool-approval.js +339 -0
- package/dist/mind/context.js +80 -67
- package/dist/mind/session-transaction.js +379 -0
- package/dist/repertoire/stripe-client.js +2 -2
- package/dist/repertoire/tool-arguments.js +104 -0
- package/dist/repertoire/tools-shell.js +13 -0
- package/dist/repertoire/tools.js +4 -0
- package/dist/senses/bluebubbles/index.js +504 -493
- package/dist/senses/cli.js +234 -214
- package/dist/senses/pipeline.js +23 -0
- package/dist/senses/private-runtime.js +330 -325
- package/dist/senses/shared-turn.js +176 -169
- package/dist/senses/teams.js +175 -163
- package/package.json +2 -1
|
@@ -64,6 +64,7 @@ const packets_1 = require("../arc/packets");
|
|
|
64
64
|
const friends_1 = require("@ouro.bot/friends");
|
|
65
65
|
const trust_gate_1 = require("./trust-gate");
|
|
66
66
|
const pipeline_1 = require("./pipeline");
|
|
67
|
+
const session_transaction_1 = require("../mind/session-transaction");
|
|
67
68
|
const nerves_1 = require("../nerves");
|
|
68
69
|
const runtime_1 = require("../nerves/runtime");
|
|
69
70
|
const provider_credentials_1 = require("../heart/provider-credentials");
|
|
@@ -857,351 +858,355 @@ async function runPrivateRuntimeTurn(options) {
|
|
|
857
858
|
reason,
|
|
858
859
|
startedAt: now().toISOString(),
|
|
859
860
|
});
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
// Resumed session: task-triggered or instinct message with checkpoint context
|
|
892
|
-
const assistantTurns = existingMessages.filter((message) => message.role === "assistant").length;
|
|
893
|
-
state.cycleCount = assistantTurns + 1;
|
|
894
|
-
state.checkpoint = deriveResumeCheckpoint(existingMessages);
|
|
895
|
-
if (options?.taskId) {
|
|
896
|
-
const taskContent = readTaskFile((0, identity_1.getAgentRoot)(), options.taskId);
|
|
897
|
-
userContent = buildTaskTriggeredMessage(options.taskId, taskContent, state.checkpoint);
|
|
861
|
+
const runWithLease = options?._withSessionTurnLease ?? session_transaction_1.withSessionTurnLease;
|
|
862
|
+
return await runWithLease(sessionFilePath, async (sessionTurnLease) => {
|
|
863
|
+
try {
|
|
864
|
+
const loaded = (0, context_1.loadSession)(sessionFilePath);
|
|
865
|
+
const existingMessages = loaded?.messages ? [...loaded.messages] : [];
|
|
866
|
+
const instincts = options?.instincts ?? loadPrivateRuntimeInstincts();
|
|
867
|
+
const state = {
|
|
868
|
+
cycleCount: 1,
|
|
869
|
+
resting: false,
|
|
870
|
+
lastHeartbeatAt: now().toISOString(),
|
|
871
|
+
};
|
|
872
|
+
const pendingDir = options?.habitSession?.pendingDir ?? (0, pending_1.getPrivateRuntimePendingDir)(agentName);
|
|
873
|
+
const shouldUseHeldReturnWake = !options?.taskId && reason !== "habit" && reason !== "await"
|
|
874
|
+
? (0, obligations_1.listActiveReturnObligations)(agentName).length > 0
|
|
875
|
+
: false;
|
|
876
|
+
// ── Adapter concern: build user message ──────────────────────────
|
|
877
|
+
let userContent;
|
|
878
|
+
let habitTools;
|
|
879
|
+
let habitParsedSuccessfully = false;
|
|
880
|
+
const isPayloadSpecificWake = !!options?.taskId
|
|
881
|
+
|| (reason === "habit" && !!options?.habitName)
|
|
882
|
+
|| (reason === "await" && !!options?.awaitName);
|
|
883
|
+
if (existingMessages.length === 0 && !isPayloadSpecificWake) {
|
|
884
|
+
// Fresh session: bootstrap message with non-canonical cleanup nudge
|
|
885
|
+
const aspirations = readAspirations((0, identity_1.getAgentRoot)());
|
|
886
|
+
const nonCanonical = (0, bundle_manifest_1.findNonCanonicalBundlePaths)((0, identity_1.getAgentRoot)());
|
|
887
|
+
const cleanupNudge = buildNonCanonicalCleanupNudge(nonCanonical);
|
|
888
|
+
userContent = [
|
|
889
|
+
buildPrivateRuntimeBootstrapMessage(aspirations, "No prior private-runtime session found."),
|
|
890
|
+
cleanupNudge,
|
|
891
|
+
].filter(Boolean).join("\n\n");
|
|
898
892
|
}
|
|
899
|
-
else
|
|
900
|
-
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
893
|
+
else {
|
|
894
|
+
// Resumed session: task-triggered or instinct message with checkpoint context
|
|
895
|
+
const assistantTurns = existingMessages.filter((message) => message.role === "assistant").length;
|
|
896
|
+
state.cycleCount = assistantTurns + 1;
|
|
897
|
+
state.checkpoint = deriveResumeCheckpoint(existingMessages);
|
|
898
|
+
if (options?.taskId) {
|
|
899
|
+
const taskContent = readTaskFile((0, identity_1.getAgentRoot)(), options.taskId);
|
|
900
|
+
userContent = buildTaskTriggeredMessage(options.taskId, taskContent, state.checkpoint);
|
|
901
|
+
}
|
|
902
|
+
else if (reason === "habit" && options?.habitName) {
|
|
903
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
904
|
+
const habitName = options.habitName;
|
|
905
|
+
const habitFilePath = path.join(agentRoot, "habits", `${habitName}.md`);
|
|
906
|
+
const preparedHabit = options.preparedHabit?.habit.name === habitName ? options.preparedHabit.habit : null;
|
|
907
|
+
const rsvpHabit = (0, habit_policy_1.isRsvpHabitName)(habitName);
|
|
908
|
+
// Read and parse the habit file
|
|
909
|
+
let habitBody;
|
|
910
|
+
let habitTitle = habitName;
|
|
911
|
+
let habitLastRun = null;
|
|
912
|
+
let habitOrigin = null;
|
|
913
|
+
let habitSurface = { family: true, originator: true, extra: [] };
|
|
914
|
+
if (preparedHabit) {
|
|
915
|
+
if (rsvpHabit && !preparedHabit.rsvp) {
|
|
916
|
+
const detail = preparedHabit.status === "degraded"
|
|
917
|
+
? preparedHabit.degradedDetail
|
|
918
|
+
: null;
|
|
919
|
+
throw new Error(`RSVP habit metadata is required before private runtime execution: ${detail ?? habitName}`);
|
|
920
|
+
}
|
|
921
|
+
const blockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(preparedHabit, "private-runtime");
|
|
922
|
+
if (blockedReason)
|
|
923
|
+
throw new Error(blockedReason);
|
|
924
|
+
}
|
|
925
|
+
let currentHabit;
|
|
926
|
+
try {
|
|
927
|
+
const habitContent = fs.readFileSync(habitFilePath, "utf-8");
|
|
928
|
+
currentHabit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(habitContent, habitFilePath));
|
|
917
929
|
}
|
|
918
|
-
|
|
919
|
-
|
|
930
|
+
catch (error) {
|
|
931
|
+
const readReason = error instanceof Error ? error.message : String(error);
|
|
932
|
+
if (rsvpHabit) {
|
|
933
|
+
throw new Error(`RSVP habit metadata is required before private runtime execution: ${readReason}`);
|
|
934
|
+
}
|
|
935
|
+
const degraded = (0, habit_parser_1.createDegradedHabitFile)(habitFilePath, "read_error", "", readReason);
|
|
936
|
+
const blockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(degraded, "private-runtime");
|
|
920
937
|
throw new Error(blockedReason);
|
|
921
|
-
}
|
|
922
|
-
let currentHabit;
|
|
923
|
-
try {
|
|
924
|
-
const habitContent = fs.readFileSync(habitFilePath, "utf-8");
|
|
925
|
-
currentHabit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(habitContent, habitFilePath));
|
|
926
|
-
}
|
|
927
|
-
catch (error) {
|
|
928
|
-
const readReason = error instanceof Error ? error.message : String(error);
|
|
929
|
-
if (rsvpHabit) {
|
|
930
|
-
throw new Error(`RSVP habit metadata is required before private runtime execution: ${readReason}`);
|
|
931
938
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
939
|
+
if (rsvpHabit && !currentHabit.rsvp) {
|
|
940
|
+
const detail = currentHabit.status === "degraded" ? currentHabit.degradedDetail : null;
|
|
941
|
+
throw new Error(`RSVP habit metadata is required before private runtime execution: ${detail ?? habitName}`);
|
|
942
|
+
}
|
|
943
|
+
const currentBlockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(currentHabit, "private-runtime");
|
|
944
|
+
if (currentBlockedReason)
|
|
945
|
+
throw new Error(currentBlockedReason);
|
|
946
|
+
const executableHabit = preparedHabit ?? currentHabit;
|
|
947
|
+
habitBody = executableHabit.body || undefined;
|
|
948
|
+
habitTitle = executableHabit.title || habitName;
|
|
949
|
+
habitLastRun = executableHabit.lastRun;
|
|
950
|
+
habitTools = executableHabit.tools;
|
|
951
|
+
habitOrigin = executableHabit.origin;
|
|
952
|
+
habitSurface = executableHabit.surface;
|
|
953
|
+
// If the habit file couldn't be read at all (no body, no title parsed), error message
|
|
954
|
+
if (habitBody === undefined && habitTitle === habitName) {
|
|
955
|
+
userContent = `habit "${habitName}" could not be read (file not found or unreadable). check habits/${habitName}.md exists.`;
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
habitParsedSuccessfully = true;
|
|
959
|
+
// Unified path: gather context for ALL habits (heartbeat included)
|
|
960
|
+
const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
961
|
+
const nowMs = now().getTime();
|
|
962
|
+
const staleObligations = obligations.map((o) => ({
|
|
963
|
+
friendName: o.origin.friendId,
|
|
964
|
+
content: o.delegatedContent,
|
|
965
|
+
stalenessMs: nowMs - o.createdAt,
|
|
966
|
+
}));
|
|
967
|
+
const alsoDue = buildAlsoDueLine(agentRoot, habitName, now);
|
|
968
|
+
const arcResume = (0, flight_recorder_1.formatFlightRecorderResume)((0, flight_recorder_1.readFlightRecorderResume)(agentRoot));
|
|
969
|
+
const deskOrientation = (0, desk_section_1.deskRecordOrientationSection)(agentRoot, now());
|
|
970
|
+
const surfacePolicy = buildHabitSurfacePolicy(habitOrigin, habitSurface);
|
|
971
|
+
// Degraded state (best-effort: never crash)
|
|
972
|
+
let degradedComponents = [];
|
|
973
|
+
try {
|
|
974
|
+
const health = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
|
|
975
|
+
if (health && health.degraded.length > 0) {
|
|
976
|
+
degradedComponents = health.degraded.map((d) => ({ component: d.component, reason: d.reason }));
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
catch {
|
|
980
|
+
// Best-effort: missing file or parse error -> empty array, no crash
|
|
981
|
+
}
|
|
982
|
+
userContent = (0, habit_turn_message_1.buildHabitTurnMessage)({
|
|
983
|
+
habitName,
|
|
984
|
+
habitTitle,
|
|
985
|
+
habitBody,
|
|
986
|
+
lastRun: habitLastRun,
|
|
987
|
+
checkpoint: displayCheckpoint(state.checkpoint),
|
|
988
|
+
alsoDue: alsoDue || undefined,
|
|
989
|
+
staleObligations,
|
|
990
|
+
parseErrors: options?.parseErrors ?? [],
|
|
991
|
+
degradedComponents,
|
|
992
|
+
arcResume,
|
|
993
|
+
deskOrientation,
|
|
994
|
+
surfacePolicy,
|
|
995
|
+
priorSessionSummary: options.preparedHabit?.habit.name === habitName ? options.preparedHabit.priorSessionSummary : undefined,
|
|
996
|
+
now,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
953
999
|
}
|
|
954
|
-
else {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const alsoDue = buildAlsoDueLine(agentRoot, habitName, now);
|
|
965
|
-
const arcResume = (0, flight_recorder_1.formatFlightRecorderResume)((0, flight_recorder_1.readFlightRecorderResume)(agentRoot));
|
|
966
|
-
const deskOrientation = (0, desk_section_1.deskRecordOrientationSection)(agentRoot, now());
|
|
967
|
-
const surfacePolicy = buildHabitSurfacePolicy(habitOrigin, habitSurface);
|
|
968
|
-
// Degraded state (best-effort: never crash)
|
|
969
|
-
let degradedComponents = [];
|
|
1000
|
+
else if (reason === "await" && options?.awaitName) {
|
|
1001
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1002
|
+
const awaitName = options.awaitName;
|
|
1003
|
+
const awaitFilePath = path.join(agentRoot, "awaiting", `${awaitName}.md`);
|
|
1004
|
+
let awaitBody;
|
|
1005
|
+
let condition = null;
|
|
1006
|
+
let lastCheckedAt = null;
|
|
1007
|
+
let lastObservation = null;
|
|
1008
|
+
let checkedCount = 0;
|
|
1009
|
+
let awaitFound = false;
|
|
970
1010
|
try {
|
|
971
|
-
const
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1011
|
+
const awaitContent = fs.readFileSync(awaitFilePath, "utf-8");
|
|
1012
|
+
const parsed = (0, await_runtime_state_1.applyAwaitRuntimeState)(agentRoot, (0, await_parser_1.parseAwaitFile)(awaitContent, awaitFilePath));
|
|
1013
|
+
awaitFound = true;
|
|
1014
|
+
awaitBody = parsed.body || undefined;
|
|
1015
|
+
condition = parsed.condition;
|
|
1016
|
+
lastCheckedAt = parsed.last_checked ?? null;
|
|
1017
|
+
lastObservation = parsed.last_observation ?? null;
|
|
1018
|
+
checkedCount = parsed.checked_count ?? 0;
|
|
975
1019
|
}
|
|
976
1020
|
catch {
|
|
977
|
-
//
|
|
1021
|
+
// file missing — fall through to error message
|
|
1022
|
+
}
|
|
1023
|
+
if (!awaitFound || !condition) {
|
|
1024
|
+
userContent = `await "${awaitName}" could not be read (file not found or no condition). check awaiting/${awaitName}.md.`;
|
|
1025
|
+
}
|
|
1026
|
+
else {
|
|
1027
|
+
userContent = (0, await_turn_message_1.buildAwaitTurnMessage)({
|
|
1028
|
+
awaitName,
|
|
1029
|
+
condition,
|
|
1030
|
+
body: awaitBody,
|
|
1031
|
+
lastCheckedAt,
|
|
1032
|
+
lastObservation,
|
|
1033
|
+
checkedCount,
|
|
1034
|
+
checkpoint: displayCheckpoint(state.checkpoint),
|
|
1035
|
+
now,
|
|
1036
|
+
});
|
|
978
1037
|
}
|
|
979
|
-
userContent = (0, habit_turn_message_1.buildHabitTurnMessage)({
|
|
980
|
-
habitName,
|
|
981
|
-
habitTitle,
|
|
982
|
-
habitBody,
|
|
983
|
-
lastRun: habitLastRun,
|
|
984
|
-
checkpoint: displayCheckpoint(state.checkpoint),
|
|
985
|
-
alsoDue: alsoDue || undefined,
|
|
986
|
-
staleObligations,
|
|
987
|
-
parseErrors: options?.parseErrors ?? [],
|
|
988
|
-
degradedComponents,
|
|
989
|
-
arcResume,
|
|
990
|
-
deskOrientation,
|
|
991
|
-
surfacePolicy,
|
|
992
|
-
priorSessionSummary: options.preparedHabit?.habit.name === habitName ? options.preparedHabit.priorSessionSummary : undefined,
|
|
993
|
-
now,
|
|
994
|
-
});
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
else if (reason === "await" && options?.awaitName) {
|
|
998
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
999
|
-
const awaitName = options.awaitName;
|
|
1000
|
-
const awaitFilePath = path.join(agentRoot, "awaiting", `${awaitName}.md`);
|
|
1001
|
-
let awaitBody;
|
|
1002
|
-
let condition = null;
|
|
1003
|
-
let lastCheckedAt = null;
|
|
1004
|
-
let lastObservation = null;
|
|
1005
|
-
let checkedCount = 0;
|
|
1006
|
-
let awaitFound = false;
|
|
1007
|
-
try {
|
|
1008
|
-
const awaitContent = fs.readFileSync(awaitFilePath, "utf-8");
|
|
1009
|
-
const parsed = (0, await_runtime_state_1.applyAwaitRuntimeState)(agentRoot, (0, await_parser_1.parseAwaitFile)(awaitContent, awaitFilePath));
|
|
1010
|
-
awaitFound = true;
|
|
1011
|
-
awaitBody = parsed.body || undefined;
|
|
1012
|
-
condition = parsed.condition;
|
|
1013
|
-
lastCheckedAt = parsed.last_checked ?? null;
|
|
1014
|
-
lastObservation = parsed.last_observation ?? null;
|
|
1015
|
-
checkedCount = parsed.checked_count ?? 0;
|
|
1016
|
-
}
|
|
1017
|
-
catch {
|
|
1018
|
-
// file missing — fall through to error message
|
|
1019
|
-
}
|
|
1020
|
-
if (!awaitFound || !condition) {
|
|
1021
|
-
userContent = `await "${awaitName}" could not be read (file not found or no condition). check awaiting/${awaitName}.md.`;
|
|
1022
1038
|
}
|
|
1023
1039
|
else {
|
|
1024
|
-
userContent = (
|
|
1025
|
-
awaitName,
|
|
1026
|
-
condition,
|
|
1027
|
-
body: awaitBody,
|
|
1028
|
-
lastCheckedAt,
|
|
1029
|
-
lastObservation,
|
|
1030
|
-
checkedCount,
|
|
1031
|
-
checkpoint: displayCheckpoint(state.checkpoint),
|
|
1032
|
-
now,
|
|
1033
|
-
});
|
|
1040
|
+
userContent = buildInstinctUserMessage(instincts, reason, state);
|
|
1034
1041
|
}
|
|
1035
1042
|
}
|
|
1036
|
-
|
|
1037
|
-
userContent =
|
|
1043
|
+
if (shouldUseHeldReturnWake) {
|
|
1044
|
+
userContent = buildHeldReturnWakeMessage();
|
|
1038
1045
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1046
|
+
const userMessage = { role: "user", content: userContent };
|
|
1047
|
+
// ── Session loader: wraps existing session logic ──────────────────
|
|
1048
|
+
const innerCapabilities = (0, friends_1.getChannelCapabilities)("inner");
|
|
1049
|
+
const selfFriend = createSelfFriend(agentName);
|
|
1050
|
+
const selfContext = { friend: selfFriend, channel: innerCapabilities };
|
|
1051
|
+
const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)() ?? undefined;
|
|
1052
|
+
// ── Habit tool enforcement ───────────────────────────────────────
|
|
1053
|
+
let habitToolsResolved;
|
|
1054
|
+
if (habitTools !== undefined) {
|
|
1055
|
+
const fullTools = (0, tools_1.getToolsForChannel)(innerCapabilities);
|
|
1056
|
+
habitToolsResolved = fullTools.filter((t) => habitTools.includes(t.function.name));
|
|
1057
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1058
|
+
event: "habit.tools_restricted",
|
|
1059
|
+
component: "senses",
|
|
1060
|
+
message: "habit running with restricted tools",
|
|
1061
|
+
meta: {
|
|
1062
|
+
habitName: options?.habitName,
|
|
1063
|
+
declared: habitTools,
|
|
1064
|
+
resolved: habitToolsResolved.map((t) => t.function.name),
|
|
1065
|
+
},
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
else if (reason === "habit" && options?.habitName && habitParsedSuccessfully) {
|
|
1069
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1070
|
+
event: "habit.tools_unrestricted",
|
|
1071
|
+
component: "senses",
|
|
1072
|
+
message: "habit running with full tool repertoire",
|
|
1073
|
+
meta: { habitName: options.habitName },
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
if (options?.noSend === true) {
|
|
1077
|
+
habitToolsResolved = [];
|
|
1078
|
+
}
|
|
1079
|
+
const effectiveHabitSession = options?.noSend === true
|
|
1080
|
+
? reduceHabitSessionToNoSend(options.habitSession)
|
|
1081
|
+
: options?.habitSession;
|
|
1082
|
+
const sessionLoader = {
|
|
1083
|
+
loadOrCreate: async () => {
|
|
1084
|
+
if (existingMessages.length > 0) {
|
|
1085
|
+
return {
|
|
1086
|
+
messages: existingMessages,
|
|
1087
|
+
sessionPath: sessionFilePath,
|
|
1088
|
+
structuredOutputs: loaded?.structuredOutputs,
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
// Fresh session: build system prompt
|
|
1092
|
+
const systemPrompt = await (0, prompt_1.buildSystem)("inner", {
|
|
1093
|
+
toolChoiceRequired: true,
|
|
1094
|
+
flightRecorderResume: (0, flight_recorder_1.readFlightRecorderResume)((0, identity_1.getAgentRoot)()),
|
|
1095
|
+
});
|
|
1096
|
+
return {
|
|
1097
|
+
messages: [{ role: "system", content: (0, prompt_1.flattenSystemPrompt)(systemPrompt) }],
|
|
1098
|
+
sessionPath: sessionFilePath,
|
|
1099
|
+
structuredOutputs: [],
|
|
1100
|
+
};
|
|
1101
|
+
},
|
|
1102
|
+
};
|
|
1103
|
+
// ── Call shared pipeline ──────────────────────────────────────────
|
|
1104
|
+
const callbacks = createPrivateRuntimeCallbacks();
|
|
1105
|
+
const traceId = (0, nerves_1.createTraceId)();
|
|
1106
|
+
// Attention queue: built when pending messages are drained, shared with tool context
|
|
1107
|
+
let attentionQueue = [];
|
|
1108
|
+
const result = await (0, pipeline_1.handleInboundTurn)({
|
|
1109
|
+
channel: "inner",
|
|
1110
|
+
sessionKey: "dialog",
|
|
1111
|
+
capabilities: innerCapabilities,
|
|
1112
|
+
messages: [userMessage],
|
|
1113
|
+
continuityIngressTexts: [],
|
|
1114
|
+
callbacks,
|
|
1115
|
+
sessionTurnLease,
|
|
1116
|
+
friendResolver: { resolve: () => Promise.resolve(selfContext) },
|
|
1117
|
+
sessionLoader,
|
|
1118
|
+
pendingDir,
|
|
1119
|
+
friendStore: createNoOpFriendStore(),
|
|
1120
|
+
enforceTrustGate: trust_gate_1.enforceTrustGate,
|
|
1121
|
+
drainPending: pending_1.drainPending,
|
|
1122
|
+
runAgent: core_1.runAgent,
|
|
1123
|
+
postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
|
|
1124
|
+
const prepared = (0, context_1.postTurnTrim)(turnMessages, usage, hooks);
|
|
1125
|
+
return (0, context_1.deferPostTurnPersist)(sessionPathArg, prepared, usage, state);
|
|
1126
|
+
},
|
|
1127
|
+
accumulateFriendTokens: friends_1.accumulateFriendTokens,
|
|
1128
|
+
signal: options?.signal,
|
|
1129
|
+
/* v8 ignore start -- attention queue: callback invoked by pipeline during pending drain; tested via attention-queue unit tests @preserve */
|
|
1130
|
+
onPendingDrained: (drained) => {
|
|
1131
|
+
const outstandingObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
1132
|
+
const builtAttentionQueue = (0, attention_queue_1.buildAttentionQueue)({
|
|
1133
|
+
drainedPending: drained,
|
|
1134
|
+
outstandingObligations,
|
|
1135
|
+
friendNameResolver: (friendId) => {
|
|
1136
|
+
try {
|
|
1137
|
+
const raw = fs.readFileSync(path.join((0, identity_1.getAgentRoot)(agentName), "friends", friendId + ".json"), "utf-8");
|
|
1138
|
+
const parsed = JSON.parse(raw);
|
|
1139
|
+
return typeof parsed.name === "string" ? parsed.name : null;
|
|
1140
|
+
}
|
|
1141
|
+
catch {
|
|
1142
|
+
return null;
|
|
1143
|
+
}
|
|
1144
|
+
},
|
|
1145
|
+
packetResolver: (packetId) => {
|
|
1146
|
+
try {
|
|
1147
|
+
return (0, packets_1.readPonderPacket)((0, identity_1.getAgentRoot)(agentName), packetId);
|
|
1148
|
+
}
|
|
1149
|
+
catch {
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1153
|
+
});
|
|
1154
|
+
attentionQueue.splice(0, attentionQueue.length, ...builtAttentionQueue);
|
|
1155
|
+
const attentionFrame = (0, attention_queue_1.buildAttentionQueueStatusFrame)(attentionQueue);
|
|
1156
|
+
return attentionFrame ? [attentionFrame] : [];
|
|
1157
|
+
},
|
|
1158
|
+
/* v8 ignore stop */
|
|
1159
|
+
runAgentOptions: {
|
|
1160
|
+
traceId,
|
|
1161
|
+
toolChoiceRequired: true,
|
|
1162
|
+
mcpManager,
|
|
1163
|
+
...(habitToolsResolved !== undefined && { tools: habitToolsResolved }),
|
|
1164
|
+
toolContext: {
|
|
1165
|
+
signin: async () => undefined,
|
|
1166
|
+
delegatedOrigins: attentionQueue,
|
|
1167
|
+
...(options?.noSend ? { noSend: true } : {}),
|
|
1168
|
+
...(effectiveHabitSession ? { habitSession: effectiveHabitSession } : {}),
|
|
1169
|
+
},
|
|
1170
|
+
...(effectiveHabitSession ? { habitSession: effectiveHabitSession } : {}),
|
|
1171
|
+
},
|
|
1172
|
+
});
|
|
1173
|
+
// Post-turn routeDelegatedCompletion removed: delivery is now inline via surface tool.
|
|
1174
|
+
// settle in the private runtime produces no CompletionMetadata, so routeDelegatedCompletion
|
|
1175
|
+
// would be a no-op. The routing infrastructure is reused by the surface handler.
|
|
1176
|
+
const resultMessages = result.messages ?? [];
|
|
1177
|
+
const assistantPreview = extractAssistantPreview(resultMessages);
|
|
1178
|
+
const toolCalls = extractToolCallNames(resultMessages);
|
|
1054
1179
|
(0, runtime_1.emitNervesEvent)({
|
|
1055
|
-
event: "habit.tools_restricted",
|
|
1056
1180
|
component: "senses",
|
|
1057
|
-
|
|
1181
|
+
event: "senses.private_runtime_turn",
|
|
1182
|
+
message: "private-runtime turn completed",
|
|
1058
1183
|
meta: {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1184
|
+
reason,
|
|
1185
|
+
session: sessionFilePath,
|
|
1186
|
+
...(options?.taskId && { taskId: options.taskId }),
|
|
1187
|
+
...(assistantPreview && { assistantPreview }),
|
|
1188
|
+
...(toolCalls.length > 0 && { toolCalls }),
|
|
1189
|
+
...(result.usage && {
|
|
1190
|
+
promptTokens: result.usage.input_tokens,
|
|
1191
|
+
completionTokens: result.usage.output_tokens,
|
|
1192
|
+
totalTokens: result.usage.total_tokens,
|
|
1193
|
+
}),
|
|
1062
1194
|
},
|
|
1063
1195
|
});
|
|
1196
|
+
return {
|
|
1197
|
+
messages: resultMessages,
|
|
1198
|
+
usage: result.usage,
|
|
1199
|
+
sessionPath: result.sessionPath ?? sessionFilePath,
|
|
1200
|
+
completion: result.completion,
|
|
1201
|
+
turnOutcome: result.turnOutcome,
|
|
1202
|
+
restStatus: latestRestStatus(resultMessages),
|
|
1203
|
+
};
|
|
1064
1204
|
}
|
|
1065
|
-
|
|
1066
|
-
(
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
message: "habit running with full tool repertoire",
|
|
1070
|
-
meta: { habitName: options.habitName },
|
|
1205
|
+
finally {
|
|
1206
|
+
writePrivateRuntimeState(sessionFilePath, {
|
|
1207
|
+
status: "idle",
|
|
1208
|
+
lastCompletedAt: now().toISOString(),
|
|
1071
1209
|
});
|
|
1072
1210
|
}
|
|
1073
|
-
|
|
1074
|
-
habitToolsResolved = [];
|
|
1075
|
-
}
|
|
1076
|
-
const effectiveHabitSession = options?.noSend === true
|
|
1077
|
-
? reduceHabitSessionToNoSend(options.habitSession)
|
|
1078
|
-
: options?.habitSession;
|
|
1079
|
-
const sessionLoader = {
|
|
1080
|
-
loadOrCreate: async () => {
|
|
1081
|
-
if (existingMessages.length > 0) {
|
|
1082
|
-
return {
|
|
1083
|
-
messages: existingMessages,
|
|
1084
|
-
sessionPath: sessionFilePath,
|
|
1085
|
-
structuredOutputs: loaded?.structuredOutputs,
|
|
1086
|
-
};
|
|
1087
|
-
}
|
|
1088
|
-
// Fresh session: build system prompt
|
|
1089
|
-
const systemPrompt = await (0, prompt_1.buildSystem)("inner", {
|
|
1090
|
-
toolChoiceRequired: true,
|
|
1091
|
-
flightRecorderResume: (0, flight_recorder_1.readFlightRecorderResume)((0, identity_1.getAgentRoot)()),
|
|
1092
|
-
});
|
|
1093
|
-
return {
|
|
1094
|
-
messages: [{ role: "system", content: (0, prompt_1.flattenSystemPrompt)(systemPrompt) }],
|
|
1095
|
-
sessionPath: sessionFilePath,
|
|
1096
|
-
structuredOutputs: [],
|
|
1097
|
-
};
|
|
1098
|
-
},
|
|
1099
|
-
};
|
|
1100
|
-
// ── Call shared pipeline ──────────────────────────────────────────
|
|
1101
|
-
const callbacks = createPrivateRuntimeCallbacks();
|
|
1102
|
-
const traceId = (0, nerves_1.createTraceId)();
|
|
1103
|
-
// Attention queue: built when pending messages are drained, shared with tool context
|
|
1104
|
-
let attentionQueue = [];
|
|
1105
|
-
const result = await (0, pipeline_1.handleInboundTurn)({
|
|
1106
|
-
channel: "inner",
|
|
1107
|
-
sessionKey: "dialog",
|
|
1108
|
-
capabilities: innerCapabilities,
|
|
1109
|
-
messages: [userMessage],
|
|
1110
|
-
continuityIngressTexts: [],
|
|
1111
|
-
callbacks,
|
|
1112
|
-
friendResolver: { resolve: () => Promise.resolve(selfContext) },
|
|
1113
|
-
sessionLoader,
|
|
1114
|
-
pendingDir,
|
|
1115
|
-
friendStore: createNoOpFriendStore(),
|
|
1116
|
-
enforceTrustGate: trust_gate_1.enforceTrustGate,
|
|
1117
|
-
drainPending: pending_1.drainPending,
|
|
1118
|
-
runAgent: core_1.runAgent,
|
|
1119
|
-
postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
|
|
1120
|
-
const prepared = (0, context_1.postTurnTrim)(turnMessages, usage, hooks);
|
|
1121
|
-
return (0, context_1.deferPostTurnPersist)(sessionPathArg, prepared, usage, state);
|
|
1122
|
-
},
|
|
1123
|
-
accumulateFriendTokens: friends_1.accumulateFriendTokens,
|
|
1124
|
-
signal: options?.signal,
|
|
1125
|
-
/* v8 ignore start -- attention queue: callback invoked by pipeline during pending drain; tested via attention-queue unit tests @preserve */
|
|
1126
|
-
onPendingDrained: (drained) => {
|
|
1127
|
-
const outstandingObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
1128
|
-
const builtAttentionQueue = (0, attention_queue_1.buildAttentionQueue)({
|
|
1129
|
-
drainedPending: drained,
|
|
1130
|
-
outstandingObligations,
|
|
1131
|
-
friendNameResolver: (friendId) => {
|
|
1132
|
-
try {
|
|
1133
|
-
const raw = fs.readFileSync(path.join((0, identity_1.getAgentRoot)(agentName), "friends", friendId + ".json"), "utf-8");
|
|
1134
|
-
const parsed = JSON.parse(raw);
|
|
1135
|
-
return typeof parsed.name === "string" ? parsed.name : null;
|
|
1136
|
-
}
|
|
1137
|
-
catch {
|
|
1138
|
-
return null;
|
|
1139
|
-
}
|
|
1140
|
-
},
|
|
1141
|
-
packetResolver: (packetId) => {
|
|
1142
|
-
try {
|
|
1143
|
-
return (0, packets_1.readPonderPacket)((0, identity_1.getAgentRoot)(agentName), packetId);
|
|
1144
|
-
}
|
|
1145
|
-
catch {
|
|
1146
|
-
return null;
|
|
1147
|
-
}
|
|
1148
|
-
},
|
|
1149
|
-
});
|
|
1150
|
-
attentionQueue.splice(0, attentionQueue.length, ...builtAttentionQueue);
|
|
1151
|
-
const attentionFrame = (0, attention_queue_1.buildAttentionQueueStatusFrame)(attentionQueue);
|
|
1152
|
-
return attentionFrame ? [attentionFrame] : [];
|
|
1153
|
-
},
|
|
1154
|
-
/* v8 ignore stop */
|
|
1155
|
-
runAgentOptions: {
|
|
1156
|
-
traceId,
|
|
1157
|
-
toolChoiceRequired: true,
|
|
1158
|
-
mcpManager,
|
|
1159
|
-
...(habitToolsResolved !== undefined && { tools: habitToolsResolved }),
|
|
1160
|
-
toolContext: {
|
|
1161
|
-
signin: async () => undefined,
|
|
1162
|
-
delegatedOrigins: attentionQueue,
|
|
1163
|
-
...(options?.noSend ? { noSend: true } : {}),
|
|
1164
|
-
...(effectiveHabitSession ? { habitSession: effectiveHabitSession } : {}),
|
|
1165
|
-
},
|
|
1166
|
-
...(effectiveHabitSession ? { habitSession: effectiveHabitSession } : {}),
|
|
1167
|
-
},
|
|
1168
|
-
});
|
|
1169
|
-
// Post-turn routeDelegatedCompletion removed: delivery is now inline via surface tool.
|
|
1170
|
-
// settle in the private runtime produces no CompletionMetadata, so routeDelegatedCompletion
|
|
1171
|
-
// would be a no-op. The routing infrastructure is reused by the surface handler.
|
|
1172
|
-
const resultMessages = result.messages ?? [];
|
|
1173
|
-
const assistantPreview = extractAssistantPreview(resultMessages);
|
|
1174
|
-
const toolCalls = extractToolCallNames(resultMessages);
|
|
1175
|
-
(0, runtime_1.emitNervesEvent)({
|
|
1176
|
-
component: "senses",
|
|
1177
|
-
event: "senses.private_runtime_turn",
|
|
1178
|
-
message: "private-runtime turn completed",
|
|
1179
|
-
meta: {
|
|
1180
|
-
reason,
|
|
1181
|
-
session: sessionFilePath,
|
|
1182
|
-
...(options?.taskId && { taskId: options.taskId }),
|
|
1183
|
-
...(assistantPreview && { assistantPreview }),
|
|
1184
|
-
...(toolCalls.length > 0 && { toolCalls }),
|
|
1185
|
-
...(result.usage && {
|
|
1186
|
-
promptTokens: result.usage.input_tokens,
|
|
1187
|
-
completionTokens: result.usage.output_tokens,
|
|
1188
|
-
totalTokens: result.usage.total_tokens,
|
|
1189
|
-
}),
|
|
1190
|
-
},
|
|
1191
|
-
});
|
|
1192
|
-
return {
|
|
1193
|
-
messages: resultMessages,
|
|
1194
|
-
usage: result.usage,
|
|
1195
|
-
sessionPath: result.sessionPath ?? sessionFilePath,
|
|
1196
|
-
completion: result.completion,
|
|
1197
|
-
turnOutcome: result.turnOutcome,
|
|
1198
|
-
restStatus: latestRestStatus(resultMessages),
|
|
1199
|
-
};
|
|
1200
|
-
}
|
|
1201
|
-
finally {
|
|
1202
|
-
writePrivateRuntimeState(sessionFilePath, {
|
|
1203
|
-
status: "idle",
|
|
1204
|
-
lastCompletedAt: now().toISOString(),
|
|
1205
|
-
});
|
|
1206
|
-
}
|
|
1211
|
+
});
|
|
1207
1212
|
}
|