@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.
@@ -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
- try {
861
- const loaded = (0, context_1.loadSession)(sessionFilePath);
862
- const existingMessages = loaded?.messages ? [...loaded.messages] : [];
863
- const instincts = options?.instincts ?? loadPrivateRuntimeInstincts();
864
- const state = {
865
- cycleCount: 1,
866
- resting: false,
867
- lastHeartbeatAt: now().toISOString(),
868
- };
869
- const pendingDir = options?.habitSession?.pendingDir ?? (0, pending_1.getPrivateRuntimePendingDir)(agentName);
870
- const shouldUseHeldReturnWake = !options?.taskId && reason !== "habit" && reason !== "await"
871
- ? (0, obligations_1.listActiveReturnObligations)(agentName).length > 0
872
- : false;
873
- // ── Adapter concern: build user message ──────────────────────────
874
- let userContent;
875
- let habitTools;
876
- let habitParsedSuccessfully = false;
877
- const isPayloadSpecificWake = !!options?.taskId
878
- || (reason === "habit" && !!options?.habitName)
879
- || (reason === "await" && !!options?.awaitName);
880
- if (existingMessages.length === 0 && !isPayloadSpecificWake) {
881
- // Fresh session: bootstrap message with non-canonical cleanup nudge
882
- const aspirations = readAspirations((0, identity_1.getAgentRoot)());
883
- const nonCanonical = (0, bundle_manifest_1.findNonCanonicalBundlePaths)((0, identity_1.getAgentRoot)());
884
- const cleanupNudge = buildNonCanonicalCleanupNudge(nonCanonical);
885
- userContent = [
886
- buildPrivateRuntimeBootstrapMessage(aspirations, "No prior private-runtime session found."),
887
- cleanupNudge,
888
- ].filter(Boolean).join("\n\n");
889
- }
890
- else {
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 if (reason === "habit" && options?.habitName) {
900
- const agentRoot = (0, identity_1.getAgentRoot)();
901
- const habitName = options.habitName;
902
- const habitFilePath = path.join(agentRoot, "habits", `${habitName}.md`);
903
- const preparedHabit = options.preparedHabit?.habit.name === habitName ? options.preparedHabit.habit : null;
904
- const rsvpHabit = (0, habit_policy_1.isRsvpHabitName)(habitName);
905
- // Read and parse the habit file
906
- let habitBody;
907
- let habitTitle = habitName;
908
- let habitLastRun = null;
909
- let habitOrigin = null;
910
- let habitSurface = { family: true, originator: true, extra: [] };
911
- if (preparedHabit) {
912
- if (rsvpHabit && !preparedHabit.rsvp) {
913
- const detail = preparedHabit.status === "degraded"
914
- ? preparedHabit.degradedDetail
915
- : null;
916
- throw new Error(`RSVP habit metadata is required before private runtime execution: ${detail ?? habitName}`);
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
- const blockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(preparedHabit, "private-runtime");
919
- if (blockedReason)
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
- const degraded = (0, habit_parser_1.createDegradedHabitFile)(habitFilePath, "read_error", "", readReason);
933
- const blockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(degraded, "private-runtime");
934
- throw new Error(blockedReason);
935
- }
936
- if (rsvpHabit && !currentHabit.rsvp) {
937
- const detail = currentHabit.status === "degraded" ? currentHabit.degradedDetail : null;
938
- throw new Error(`RSVP habit metadata is required before private runtime execution: ${detail ?? habitName}`);
939
- }
940
- const currentBlockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(currentHabit, "private-runtime");
941
- if (currentBlockedReason)
942
- throw new Error(currentBlockedReason);
943
- const executableHabit = preparedHabit ?? currentHabit;
944
- habitBody = executableHabit.body || undefined;
945
- habitTitle = executableHabit.title || habitName;
946
- habitLastRun = executableHabit.lastRun;
947
- habitTools = executableHabit.tools;
948
- habitOrigin = executableHabit.origin;
949
- habitSurface = executableHabit.surface;
950
- // If the habit file couldn't be read at all (no body, no title parsed), error message
951
- if (habitBody === undefined && habitTitle === habitName) {
952
- userContent = `habit "${habitName}" could not be read (file not found or unreadable). check habits/${habitName}.md exists.`;
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
- habitParsedSuccessfully = true;
956
- // Unified path: gather context for ALL habits (heartbeat included)
957
- const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
958
- const nowMs = now().getTime();
959
- const staleObligations = obligations.map((o) => ({
960
- friendName: o.origin.friendId,
961
- content: o.delegatedContent,
962
- stalenessMs: nowMs - o.createdAt,
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 health = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
972
- if (health && health.degraded.length > 0) {
973
- degradedComponents = health.degraded.map((d) => ({ component: d.component, reason: d.reason }));
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
- // Best-effort: missing file or parse error -> empty array, no crash
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 = (0, await_turn_message_1.buildAwaitTurnMessage)({
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
- else {
1037
- userContent = buildInstinctUserMessage(instincts, reason, state);
1043
+ if (shouldUseHeldReturnWake) {
1044
+ userContent = buildHeldReturnWakeMessage();
1038
1045
  }
1039
- }
1040
- if (shouldUseHeldReturnWake) {
1041
- userContent = buildHeldReturnWakeMessage();
1042
- }
1043
- const userMessage = { role: "user", content: userContent };
1044
- // ── Session loader: wraps existing session logic ──────────────────
1045
- const innerCapabilities = (0, friends_1.getChannelCapabilities)("inner");
1046
- const selfFriend = createSelfFriend(agentName);
1047
- const selfContext = { friend: selfFriend, channel: innerCapabilities };
1048
- const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)() ?? undefined;
1049
- // ── Habit tool enforcement ───────────────────────────────────────
1050
- let habitToolsResolved;
1051
- if (habitTools !== undefined) {
1052
- const fullTools = (0, tools_1.getToolsForChannel)(innerCapabilities);
1053
- habitToolsResolved = fullTools.filter((t) => habitTools.includes(t.function.name));
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
- message: "habit running with restricted tools",
1181
+ event: "senses.private_runtime_turn",
1182
+ message: "private-runtime turn completed",
1058
1183
  meta: {
1059
- habitName: options?.habitName,
1060
- declared: habitTools,
1061
- resolved: habitToolsResolved.map((t) => t.function.name),
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
- else if (reason === "habit" && options?.habitName && habitParsedSuccessfully) {
1066
- (0, runtime_1.emitNervesEvent)({
1067
- event: "habit.tools_unrestricted",
1068
- component: "senses",
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
- if (options?.noSend === true) {
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
  }