@ouro.bot/cli 0.1.0-alpha.50 → 0.1.0-alpha.52

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.
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listTargetSessionCandidates = listTargetSessionCandidates;
4
+ exports.formatTargetSessionCandidates = formatTargetSessionCandidates;
5
+ const session_recall_1 = require("./session-recall");
6
+ const session_activity_1 = require("./session-activity");
7
+ const trust_explanation_1 = require("../mind/friends/trust-explanation");
8
+ const runtime_1 = require("../nerves/runtime");
9
+ function synthesizeFriendRecord(candidate) {
10
+ return {
11
+ id: candidate.friendId,
12
+ name: candidate.friendName,
13
+ role: "stranger",
14
+ trustLevel: "stranger",
15
+ connections: [],
16
+ externalIds: [],
17
+ tenantMemberships: [],
18
+ toolPreferences: {},
19
+ notes: {},
20
+ totalTokens: 0,
21
+ createdAt: new Date(0).toISOString(),
22
+ updatedAt: new Date(0).toISOString(),
23
+ schemaVersion: 1,
24
+ };
25
+ }
26
+ function deliveryPriority(mode) {
27
+ if (mode === "deliver_now")
28
+ return 0;
29
+ if (mode === "queue_only")
30
+ return 1;
31
+ return 2;
32
+ }
33
+ function activityPriority(source) {
34
+ return source === "friend-facing" ? 0 : 1;
35
+ }
36
+ function describeDelivery(candidate) {
37
+ if (candidate.channel !== "bluebubbles" && candidate.channel !== "teams") {
38
+ return { mode: "blocked", reason: "this channel does not support proactive outward delivery yet" };
39
+ }
40
+ if (candidate.trust.level === "family" || candidate.trust.level === "friend") {
41
+ return { mode: "deliver_now", reason: "directly trusted target on a proactive-delivery channel" };
42
+ }
43
+ return { mode: "queue_only", reason: "visible as a live chat, but immediate delivery still needs explicit cross-chat authorization" };
44
+ }
45
+ async function listTargetSessionCandidates(input) {
46
+ (0, runtime_1.emitNervesEvent)({
47
+ component: "engine",
48
+ event: "engine.target_resolution_start",
49
+ message: "listing live target session candidates",
50
+ meta: {
51
+ sessionsDir: input.sessionsDir,
52
+ currentSession: input.currentSession
53
+ ? `${input.currentSession.friendId}/${input.currentSession.channel}/${input.currentSession.key}`
54
+ : null,
55
+ },
56
+ });
57
+ const activity = (0, session_activity_1.listSessionActivity)({
58
+ sessionsDir: input.sessionsDir,
59
+ friendsDir: input.friendsDir,
60
+ agentName: input.agentName,
61
+ currentSession: input.currentSession ?? null,
62
+ }).filter((entry) => entry.channel !== "inner");
63
+ const candidates = [];
64
+ for (const entry of activity) {
65
+ const friend = await input.friendStore.get(entry.friendId) ?? synthesizeFriendRecord(entry);
66
+ const trust = (0, trust_explanation_1.describeTrustContext)({
67
+ friend,
68
+ channel: entry.channel,
69
+ });
70
+ const recall = await (0, session_recall_1.recallSession)({
71
+ sessionPath: entry.sessionPath,
72
+ friendId: entry.friendId,
73
+ channel: entry.channel,
74
+ key: entry.key,
75
+ messageCount: 6,
76
+ summarize: input.summarize,
77
+ trustLevel: trust.level,
78
+ });
79
+ const snapshot = recall.kind === "ok"
80
+ ? recall.snapshot
81
+ : recall.kind === "empty"
82
+ ? "recent focus: no recent visible messages"
83
+ : "recent focus: session transcript unavailable";
84
+ const delivery = describeDelivery({
85
+ channel: entry.channel,
86
+ trust,
87
+ });
88
+ candidates.push({
89
+ friendId: entry.friendId,
90
+ friendName: entry.friendName,
91
+ channel: entry.channel,
92
+ key: entry.key,
93
+ sessionPath: entry.sessionPath,
94
+ snapshot,
95
+ trust,
96
+ delivery,
97
+ lastActivityAt: entry.lastActivityAt,
98
+ lastActivityMs: entry.lastActivityMs,
99
+ activitySource: entry.activitySource,
100
+ });
101
+ }
102
+ return candidates.sort((a, b) => {
103
+ const deliveryDiff = deliveryPriority(a.delivery.mode) - deliveryPriority(b.delivery.mode);
104
+ if (deliveryDiff !== 0)
105
+ return deliveryDiff;
106
+ const sourceDiff = activityPriority(a.activitySource) - activityPriority(b.activitySource);
107
+ if (sourceDiff !== 0)
108
+ return sourceDiff;
109
+ return b.lastActivityMs - a.lastActivityMs;
110
+ });
111
+ }
112
+ function formatTargetSessionCandidates(candidates) {
113
+ if (candidates.length === 0)
114
+ return "";
115
+ const lines = ["## candidate target chats"];
116
+ for (const candidate of candidates) {
117
+ lines.push(`- ${candidate.friendName} [${candidate.friendId}] via ${candidate.channel}/${candidate.key}`);
118
+ lines.push(` trust: ${candidate.trust.level} (${candidate.trust.basis}) — ${candidate.trust.summary}`);
119
+ lines.push(` delivery: ${candidate.delivery.mode} — ${candidate.delivery.reason}`);
120
+ lines.push(` snapshot: ${candidate.snapshot}`);
121
+ }
122
+ return lines.join("\n");
123
+ }
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.upsertGroupContextParticipants = upsertGroupContextParticipants;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const runtime_1 = require("../../nerves/runtime");
6
+ const CURRENT_SCHEMA_VERSION = 1;
7
+ function normalizeDisplayName(externalId, displayName) {
8
+ const trimmed = displayName?.trim();
9
+ return trimmed && trimmed.length > 0 ? trimmed : externalId;
10
+ }
11
+ function buildNameNotes(name, now) {
12
+ return name !== "Unknown"
13
+ ? { name: { value: name, savedAt: now } }
14
+ : {};
15
+ }
16
+ function dedupeParticipants(participants) {
17
+ const deduped = new Map();
18
+ for (const participant of participants) {
19
+ const externalId = participant.externalId.trim();
20
+ if (!externalId)
21
+ continue;
22
+ const key = `${participant.provider}:${externalId}`;
23
+ if (!deduped.has(key)) {
24
+ deduped.set(key, {
25
+ ...participant,
26
+ externalId,
27
+ displayName: participant.displayName?.trim() || undefined,
28
+ });
29
+ }
30
+ }
31
+ return Array.from(deduped.values());
32
+ }
33
+ function createGroupExternalId(provider, groupExternalId, linkedAt) {
34
+ return {
35
+ provider,
36
+ externalId: groupExternalId,
37
+ linkedAt,
38
+ };
39
+ }
40
+ function shouldPromoteToAcquaintance(friend) {
41
+ return (friend.trustLevel ?? "stranger") === "stranger";
42
+ }
43
+ function createAcquaintanceRecord(participant, groupExternalId, linkedAt) {
44
+ const name = normalizeDisplayName(participant.externalId, participant.displayName);
45
+ return {
46
+ id: (0, node_crypto_1.randomUUID)(),
47
+ name,
48
+ role: "acquaintance",
49
+ trustLevel: "acquaintance",
50
+ connections: [],
51
+ externalIds: [
52
+ {
53
+ provider: participant.provider,
54
+ externalId: participant.externalId,
55
+ linkedAt,
56
+ },
57
+ createGroupExternalId(participant.provider, groupExternalId, linkedAt),
58
+ ],
59
+ tenantMemberships: [],
60
+ toolPreferences: {},
61
+ notes: buildNameNotes(name, linkedAt),
62
+ totalTokens: 0,
63
+ createdAt: linkedAt,
64
+ updatedAt: linkedAt,
65
+ schemaVersion: CURRENT_SCHEMA_VERSION,
66
+ };
67
+ }
68
+ async function upsertGroupContextParticipants(input) {
69
+ (0, runtime_1.emitNervesEvent)({
70
+ component: "friends",
71
+ event: "friends.group_context_upsert_start",
72
+ message: "upserting shared-group participant context",
73
+ meta: {
74
+ participantCount: input.participants.length,
75
+ hasGroupExternalId: input.groupExternalId.trim().length > 0,
76
+ },
77
+ });
78
+ const groupExternalId = input.groupExternalId.trim();
79
+ if (!groupExternalId) {
80
+ return [];
81
+ }
82
+ const now = input.now ?? (() => new Date().toISOString());
83
+ const participants = dedupeParticipants(input.participants);
84
+ const results = [];
85
+ for (const participant of participants) {
86
+ const linkedAt = now();
87
+ const existing = await input.store.findByExternalId(participant.provider, participant.externalId);
88
+ if (!existing) {
89
+ const created = createAcquaintanceRecord(participant, groupExternalId, linkedAt);
90
+ await input.store.put(created.id, created);
91
+ results.push({
92
+ friendId: created.id,
93
+ name: created.name,
94
+ trustLevel: "acquaintance",
95
+ created: true,
96
+ updated: false,
97
+ addedGroupExternalId: true,
98
+ });
99
+ continue;
100
+ }
101
+ const hasGroupExternalId = existing.externalIds.some((externalId) => externalId.externalId === groupExternalId);
102
+ const promoteToAcquaintance = shouldPromoteToAcquaintance(existing);
103
+ const trustLevel = promoteToAcquaintance
104
+ ? "acquaintance"
105
+ : existing.trustLevel;
106
+ const role = promoteToAcquaintance
107
+ ? "acquaintance"
108
+ : existing.role;
109
+ const updatedExternalIds = hasGroupExternalId
110
+ ? existing.externalIds
111
+ : [...existing.externalIds, createGroupExternalId(participant.provider, groupExternalId, linkedAt)];
112
+ const updated = promoteToAcquaintance || !hasGroupExternalId;
113
+ const record = updated
114
+ ? {
115
+ ...existing,
116
+ role,
117
+ trustLevel,
118
+ externalIds: updatedExternalIds,
119
+ updatedAt: linkedAt,
120
+ }
121
+ : existing;
122
+ if (updated) {
123
+ await input.store.put(record.id, record);
124
+ }
125
+ results.push({
126
+ friendId: record.id,
127
+ name: record.name,
128
+ trustLevel,
129
+ created: false,
130
+ updated,
131
+ addedGroupExternalId: !hasGroupExternalId,
132
+ });
133
+ }
134
+ (0, runtime_1.emitNervesEvent)({
135
+ component: "friends",
136
+ event: "friends.group_context_upsert_end",
137
+ message: "upserted shared-group participant context",
138
+ meta: {
139
+ participantCount: participants.length,
140
+ updatedCount: results.filter((result) => result.created || result.updated).length,
141
+ },
142
+ });
143
+ return results;
144
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeTrustContext = describeTrustContext;
4
+ const runtime_1 = require("../../nerves/runtime");
5
+ function findRelatedGroupId(friend) {
6
+ return friend.externalIds.find((externalId) => externalId.externalId.startsWith("group:"))?.externalId;
7
+ }
8
+ function resolveLevel(friend) {
9
+ return friend.trustLevel ?? "stranger";
10
+ }
11
+ function describeTrustContext(input) {
12
+ const level = resolveLevel(input.friend);
13
+ const relatedGroupId = findRelatedGroupId(input.friend);
14
+ const explanation = level === "family" || level === "friend"
15
+ ? {
16
+ level,
17
+ basis: "direct",
18
+ summary: level === "family"
19
+ ? "direct family trust"
20
+ : "direct trusted relationship",
21
+ why: "this relationship is directly trusted rather than inferred through a shared group or cold first contact.",
22
+ permits: [
23
+ "local operations when appropriate",
24
+ "proactive follow-through",
25
+ "full collaborative problem solving",
26
+ ],
27
+ constraints: [],
28
+ }
29
+ : level === "acquaintance"
30
+ ? {
31
+ level,
32
+ basis: "shared_group",
33
+ summary: relatedGroupId
34
+ ? "known through the shared project group"
35
+ : "known through a shared group context",
36
+ why: relatedGroupId
37
+ ? `this trust comes from the shared group context ${relatedGroupId}, not from direct endorsement.`
38
+ : "this trust comes from shared group context rather than direct endorsement.",
39
+ permits: [
40
+ "group-safe coordination",
41
+ "normal conversation inside the shared context",
42
+ ],
43
+ constraints: [
44
+ "guarded local actions",
45
+ "do not assume broad private authority",
46
+ ],
47
+ relatedGroupId,
48
+ }
49
+ : {
50
+ level,
51
+ basis: "unknown",
52
+ summary: "truly unknown first-contact context",
53
+ why: "this person is not known through direct trust or a shared group context.",
54
+ permits: [
55
+ "safe first-contact orientation only",
56
+ ],
57
+ constraints: [
58
+ "first contact does not reach the full model on open channels",
59
+ "no local or privileged actions",
60
+ ],
61
+ };
62
+ (0, runtime_1.emitNervesEvent)({
63
+ component: "friends",
64
+ event: "friends.trust_explained",
65
+ message: "built explicit trust explanation",
66
+ meta: {
67
+ channel: input.channel,
68
+ level: explanation.level,
69
+ basis: explanation.basis,
70
+ hasRelatedGroup: Boolean(explanation.relatedGroupId),
71
+ },
72
+ });
73
+ return explanation;
74
+ }
@@ -51,6 +51,7 @@ const tools_1 = require("../repertoire/tools");
51
51
  const skills_1 = require("../repertoire/skills");
52
52
  const identity_1 = require("../heart/identity");
53
53
  const types_1 = require("./friends/types");
54
+ const trust_explanation_1 = require("./friends/trust-explanation");
54
55
  const channel_1 = require("./friends/channel");
55
56
  const runtime_1 = require("../nerves/runtime");
56
57
  const bundle_manifest_1 = require("./bundle-manifest");
@@ -311,7 +312,7 @@ function dateSection() {
311
312
  return `current date: ${today}`;
312
313
  }
313
314
  function toolsSection(channel, options, context) {
314
- const channelTools = (0, tools_1.getToolsForChannel)((0, channel_1.getChannelCapabilities)(channel), undefined, context);
315
+ const channelTools = (0, tools_1.getToolsForChannel)((0, channel_1.getChannelCapabilities)(channel), undefined, context, options?.providerCapabilities);
315
316
  const activeTools = (options?.toolChoiceRequired ?? true) ? [...channelTools, tools_1.finalAnswerTool] : channelTools;
316
317
  const list = activeTools
317
318
  .map((t) => `- ${t.function.name}: ${t.function.description}`)
@@ -329,6 +330,31 @@ some of my tools are unavailable right now: ${toolList}
329
330
 
330
331
  i don't know this person well enough yet to run local operations on their behalf. i can suggest remote-safe alternatives or ask them to run it from CLI.`;
331
332
  }
333
+ function trustContextSection(context) {
334
+ if (!context?.friend)
335
+ return "";
336
+ const channelName = context.channel.channel;
337
+ if (channelName === "cli" || channelName === "inner")
338
+ return "";
339
+ const explanation = (0, trust_explanation_1.describeTrustContext)({
340
+ friend: context.friend,
341
+ channel: channelName,
342
+ isGroupChat: context.isGroupChat,
343
+ });
344
+ const lines = [
345
+ "## trust context",
346
+ `level: ${explanation.level}`,
347
+ `basis: ${explanation.basis}`,
348
+ `summary: ${explanation.summary}`,
349
+ `why: ${explanation.why}`,
350
+ `permits: ${explanation.permits.join(", ")}`,
351
+ `constraints: ${explanation.constraints.join(", ") || "none"}`,
352
+ ];
353
+ if (explanation.relatedGroupId) {
354
+ lines.push(`related group: ${explanation.relatedGroupId}`);
355
+ }
356
+ return lines.join("\n");
357
+ }
332
358
  function skillsSection() {
333
359
  const names = (0, skills_1.listSkills)() || [];
334
360
  if (!names.length)
@@ -383,6 +409,14 @@ function delegationHintSection(options) {
383
409
  ];
384
410
  return lines.join("\n");
385
411
  }
412
+ function reasoningEffortSection(options) {
413
+ if (!options?.providerCapabilities?.has("reasoning-effort"))
414
+ return "";
415
+ const levels = options.supportedReasoningEfforts ?? [];
416
+ const levelList = levels.length > 0 ? levels.join(", ") : "varies by model";
417
+ return `## reasoning effort
418
+ i can adjust my own reasoning depth using the set_reasoning_effort tool. i use higher effort for complex analysis and lower effort for simple tasks. available levels: ${levelList}.`;
419
+ }
386
420
  function toolBehaviorSection(options) {
387
421
  if (!(options?.toolChoiceRequired ?? true))
388
422
  return "";
@@ -510,7 +544,9 @@ async function buildSystem(channel = "cli", options, context) {
510
544
  providerSection(),
511
545
  dateSection(),
512
546
  toolsSection(channel, options, context),
547
+ reasoningEffortSection(options),
513
548
  toolRestrictionSection(context),
549
+ trustContextSection(context),
514
550
  mixedTrustGroupSection(context),
515
551
  skillsSection(),
516
552
  taskBoardSection(),
@@ -50,6 +50,7 @@ const tools_1 = require("./coding/tools");
50
50
  const memory_1 = require("../mind/memory");
51
51
  const pending_1 = require("../mind/pending");
52
52
  const progress_story_1 = require("../heart/progress-story");
53
+ const cross_chat_delivery_1 = require("../heart/cross-chat-delivery");
53
54
  // Tracks which file paths have been read via read_file in this session.
54
55
  // edit_file requires a file to be read first (must-read-first guard).
55
56
  exports.editFileReadTracker = new Set();
@@ -115,6 +116,34 @@ function normalizeProgressOutcome(text) {
115
116
  }
116
117
  return trimmed;
117
118
  }
119
+ function writePendingEnvelope(queueDir, message) {
120
+ fs.mkdirSync(queueDir, { recursive: true });
121
+ const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
122
+ const filePath = path.join(queueDir, fileName);
123
+ fs.writeFileSync(filePath, JSON.stringify(message, null, 2));
124
+ }
125
+ function renderCrossChatDeliveryStatus(target, result) {
126
+ const phase = result.status === "delivered_now"
127
+ ? "completed"
128
+ : result.status === "queued_for_later"
129
+ ? "queued"
130
+ : result.status === "blocked"
131
+ ? "blocked"
132
+ : "errored";
133
+ const lead = result.status === "delivered_now"
134
+ ? "delivered now"
135
+ : result.status === "queued_for_later"
136
+ ? "queued for later"
137
+ : result.status === "blocked"
138
+ ? "blocked"
139
+ : "failed";
140
+ return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
141
+ scope: "shared-work",
142
+ phase,
143
+ objective: `message to ${target}`,
144
+ outcomeText: `${lead}\n${result.detail}`,
145
+ }));
146
+ }
118
147
  function renderInnerProgressStatus(status) {
119
148
  if (status.processing === "pending") {
120
149
  return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
@@ -817,7 +846,7 @@ exports.baseToolDefinitions = [
817
846
  type: "function",
818
847
  function: {
819
848
  name: "send_message",
820
- description: "send a message to a friend's session. the message is queued as a pending file and delivered when the target session drains its queue.",
849
+ description: "send a message to a friend's session. when the request is explicitly authorized from a trusted live chat, the harness will try to deliver immediately; otherwise it reports truthful queued/block/failure state.",
821
850
  parameters: {
822
851
  type: "object",
823
852
  properties: {
@@ -843,9 +872,6 @@ exports.baseToolDefinitions = [
843
872
  const pendingDir = isSelf
844
873
  ? (0, pending_1.getInnerDialogPendingDir)(agentName)
845
874
  : (0, pending_1.getPendingDir)(agentName, friendId, channel, key);
846
- fs.mkdirSync(pendingDir, { recursive: true });
847
- const fileName = `${now}-${Math.random().toString(36).slice(2, 10)}.json`;
848
- const filePath = path.join(pendingDir, fileName);
849
875
  const delegatingBridgeId = findDelegatingBridgeId(ctx);
850
876
  const delegatedFrom = isSelf
851
877
  && ctx?.currentSession
@@ -866,8 +892,8 @@ exports.baseToolDefinitions = [
866
892
  timestamp: now,
867
893
  ...(delegatedFrom ? { delegatedFrom } : {}),
868
894
  };
869
- fs.writeFileSync(filePath, JSON.stringify(envelope, null, 2));
870
895
  if (isSelf) {
896
+ writePendingEnvelope(pendingDir, envelope);
871
897
  let wakeResponse = null;
872
898
  try {
873
899
  wakeResponse = await (0, socket_client_1.requestInnerWake)(agentName);
@@ -906,10 +932,138 @@ exports.baseToolDefinitions = [
906
932
  surfaced: "nothing yet",
907
933
  });
908
934
  }
909
- const preview = content.length > 80 ? content.slice(0, 80) + "…" : content;
910
- const target = `${channel}/${key}`;
911
- return `message queued for delivery to ${friendId} on ${target}. preview: "${preview}". it will be delivered when their session is next active.`;
935
+ const deliveryResult = await (0, cross_chat_delivery_1.deliverCrossChatMessage)({
936
+ friendId,
937
+ channel,
938
+ key,
939
+ content,
940
+ intent: ctx?.currentSession && ctx.currentSession.friendId !== "self"
941
+ ? "explicit_cross_chat"
942
+ : "generic_outreach",
943
+ ...(ctx?.currentSession && ctx.currentSession.friendId !== "self"
944
+ ? {
945
+ authorizingSession: {
946
+ friendId: ctx.currentSession.friendId,
947
+ channel: ctx.currentSession.channel,
948
+ key: ctx.currentSession.key,
949
+ trustLevel: ctx?.context?.friend?.trustLevel,
950
+ },
951
+ }
952
+ : {}),
953
+ }, {
954
+ agentName,
955
+ queuePending: (message) => writePendingEnvelope(pendingDir, message),
956
+ deliverers: {
957
+ bluebubbles: async (request) => {
958
+ const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
959
+ const result = await sendProactiveBlueBubblesMessageToSession({
960
+ friendId: request.friendId,
961
+ sessionKey: request.key,
962
+ text: request.content,
963
+ intent: request.intent,
964
+ authorizingSession: request.authorizingSession,
965
+ });
966
+ if (result.delivered) {
967
+ return {
968
+ status: "delivered_now",
969
+ detail: "sent to the active bluebubbles chat now",
970
+ };
971
+ }
972
+ if (result.reason === "missing_target") {
973
+ return {
974
+ status: "blocked",
975
+ detail: "bluebubbles could not resolve a routable target for that session",
976
+ };
977
+ }
978
+ if (result.reason === "send_error") {
979
+ return {
980
+ status: "failed",
981
+ detail: "bluebubbles send failed",
982
+ };
983
+ }
984
+ return {
985
+ status: "unavailable",
986
+ detail: "live delivery unavailable right now; queued for the next active turn",
987
+ };
988
+ },
989
+ teams: async (request) => {
990
+ if (!ctx?.botApi) {
991
+ return {
992
+ status: "unavailable",
993
+ detail: "live delivery unavailable right now; queued for the next active turn",
994
+ };
995
+ }
996
+ const { sendProactiveTeamsMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/teams")));
997
+ const result = await sendProactiveTeamsMessageToSession({
998
+ friendId: request.friendId,
999
+ sessionKey: request.key,
1000
+ text: request.content,
1001
+ intent: request.intent,
1002
+ authorizingSession: request.authorizingSession,
1003
+ }, {
1004
+ botApi: ctx.botApi,
1005
+ });
1006
+ if (result.delivered) {
1007
+ return {
1008
+ status: "delivered_now",
1009
+ detail: "sent to the active teams chat now",
1010
+ };
1011
+ }
1012
+ if (result.reason === "missing_target") {
1013
+ return {
1014
+ status: "blocked",
1015
+ detail: "teams could not resolve a routable target for that session",
1016
+ };
1017
+ }
1018
+ if (result.reason === "send_error") {
1019
+ return {
1020
+ status: "failed",
1021
+ detail: "teams send failed",
1022
+ };
1023
+ }
1024
+ return {
1025
+ status: "unavailable",
1026
+ detail: "live delivery unavailable right now; queued for the next active turn",
1027
+ };
1028
+ },
1029
+ },
1030
+ });
1031
+ return renderCrossChatDeliveryStatus(`${friendId} on ${channel}/${key}`, deliveryResult);
1032
+ },
1033
+ },
1034
+ {
1035
+ tool: {
1036
+ type: "function",
1037
+ function: {
1038
+ name: "set_reasoning_effort",
1039
+ description: "adjust your own reasoning depth for subsequent turns. use higher effort for complex analysis, lower for simple tasks.",
1040
+ parameters: {
1041
+ type: "object",
1042
+ properties: {
1043
+ level: { type: "string", description: "the reasoning effort level to set" },
1044
+ },
1045
+ required: ["level"],
1046
+ },
1047
+ },
1048
+ },
1049
+ handler: (args, ctx) => {
1050
+ if (!ctx?.supportedReasoningEfforts || !ctx.setReasoningEffort) {
1051
+ return "reasoning effort adjustment is not available in this context.";
1052
+ }
1053
+ const level = (args.level || "").trim();
1054
+ if (!ctx.supportedReasoningEfforts.includes(level)) {
1055
+ return `invalid reasoning effort level "${level}". accepted levels: ${ctx.supportedReasoningEfforts.join(", ")}`;
1056
+ }
1057
+ ctx.setReasoningEffort(level);
1058
+ (0, runtime_1.emitNervesEvent)({
1059
+ component: "repertoire",
1060
+ event: "repertoire.reasoning_effort_changed",
1061
+ message: `reasoning effort set to ${level}`,
1062
+ meta: { level },
1063
+ });
1064
+ return `reasoning effort set to "${level}".`;
912
1065
  },
1066
+ requiredCapability: "reasoning-effort",
913
1067
  },
914
1068
  ...tools_1.codingToolDefinitions,
915
1069
  ];