u-foo 3.0.1 → 3.0.2

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.
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
 
3
3
  /**
4
- * plan_graph control-plane actions:
5
- * start_task / cancel_task / fail_task / complete_task / skip_node / cancel_subtree.
4
+ * Control-plane TaskRun lifecycle:
5
+ * - startTask: graph-bound TaskRun from a plan_graph task_loop node
6
+ * - startStandaloneTask: single-point TaskRun (no plan graph / Plan Mode required)
7
+ * - cancel/fail/complete by nodeId or taskRunId
6
8
  *
7
9
  * complete_task:
8
10
  * - taskRunId → owning TaskLoop submitting TaskRun result
@@ -59,6 +61,44 @@ function dependenciesSatisfied(parent = null, node = null) {
59
61
  return { ok: unmet.length === 0, dependencies: unmet };
60
62
  }
61
63
 
64
+ function rejectMaxConcurrent(executionState = null) {
65
+ const activeCount = listActiveWritingTaskRuns(executionState).length;
66
+ const leaseCount = countWriteLeases(executionState);
67
+ if (activeCount >= MAX_CONCURRENT_WRITE_LEASES || leaseCount >= MAX_CONCURRENT_WRITE_LEASES) {
68
+ return {
69
+ status: "rejected",
70
+ ok: false,
71
+ errors: [{
72
+ code: "MAX_CONCURRENT_TASKS",
73
+ message: `At most ${MAX_CONCURRENT_WRITE_LEASES} concurrent writing TaskRuns`,
74
+ max: MAX_CONCURRENT_WRITE_LEASES,
75
+ current: Math.max(activeCount, leaseCount),
76
+ }],
77
+ };
78
+ }
79
+ return null;
80
+ }
81
+
82
+ function resolveActiveRun(executionState = null, {
83
+ nodeId = "",
84
+ taskRunId = "",
85
+ } = {}) {
86
+ const runId = String(taskRunId || "").trim();
87
+ if (runId) {
88
+ const run = getTaskRun(executionState, runId);
89
+ if (!run) return { run: null, errorCode: "TASK_RUN_NOT_FOUND" };
90
+ if (run.status === "queued" || run.status === "running" || run.status === "cancelling") {
91
+ return { run, errorCode: "" };
92
+ }
93
+ return { run, errorCode: "TASK_ALREADY_TERMINAL" };
94
+ }
95
+ const id = String(nodeId || "").trim();
96
+ if (!id) return { run: null, errorCode: "TASK_NOT_RUNNING" };
97
+ const active = findActiveTaskRunForNode(executionState, id);
98
+ if (active) return { run: active, errorCode: "" };
99
+ return { run: null, errorCode: "TASK_NOT_RUNNING" };
100
+ }
101
+
62
102
  function startTask(executionState = null, {
63
103
  nodeId = "",
64
104
  commandId = "",
@@ -125,20 +165,8 @@ function startTask(executionState = null, {
125
165
  };
126
166
  }
127
167
 
128
- const activeCount = listActiveWritingTaskRuns(executionState).length;
129
- const leaseCount = countWriteLeases(executionState);
130
- if (activeCount >= MAX_CONCURRENT_WRITE_LEASES || leaseCount >= MAX_CONCURRENT_WRITE_LEASES) {
131
- return {
132
- status: "rejected",
133
- ok: false,
134
- errors: [{
135
- code: "MAX_CONCURRENT_TASKS",
136
- message: `At most ${MAX_CONCURRENT_WRITE_LEASES} concurrent writing TaskRuns`,
137
- max: MAX_CONCURRENT_WRITE_LEASES,
138
- current: Math.max(activeCount, leaseCount),
139
- }],
140
- };
141
- }
168
+ const limited = rejectMaxConcurrent(executionState);
169
+ if (limited) return limited;
142
170
 
143
171
  // Freeze spec snapshot on node.runtime
144
172
  if (!node.runtime || typeof node.runtime !== "object") node.runtime = {};
@@ -151,16 +179,20 @@ function startTask(executionState = null, {
151
179
  : { kind: "task_loop" },
152
180
  };
153
181
 
182
+ const objective = node.objective || node.title || id;
154
183
  const run = createTaskRun({
184
+ kind: "graph_node",
155
185
  parentGraphId: parent.graphId || "",
156
186
  parentNodeId: id,
157
187
  attempt: (Number(node.attempt) || 0) + 1,
188
+ objective,
189
+ title: node.title || objective,
158
190
  });
159
191
  const child = createChildGraphState({
160
192
  parentGraphId: parent.graphId || "",
161
193
  parentNodeId: id,
162
194
  taskRunId: run.id,
163
- objective: node.objective || node.title || id,
195
+ objective,
164
196
  });
165
197
  run.childGraphId = child.graphId;
166
198
  putTaskRun(executionState, run);
@@ -192,37 +224,116 @@ function startTask(executionState = null, {
192
224
  return payload;
193
225
  }
194
226
 
227
+ /**
228
+ * Start a TaskRun that is not attached to any plan_graph node.
229
+ * Orthogonal to Plan Mode: never enters or requires Plan Mode.
230
+ */
231
+ function startStandaloneTask(executionState = null, {
232
+ objective = "",
233
+ title = "",
234
+ commandId = "",
235
+ runTool = null,
236
+ knownTools = null,
237
+ processImmediately = true,
238
+ } = {}) {
239
+ const cached = getCachedControlCommand(executionState, commandId);
240
+ if (cached) return { ...cached, idempotentReplay: true };
241
+
242
+ ensureGraphs(executionState);
243
+
244
+ const goal = String(objective || title || "").trim();
245
+ if (!goal) {
246
+ return {
247
+ status: "rejected",
248
+ ok: false,
249
+ errors: [{ code: "OBJECTIVE_REQUIRED", message: "standalone task requires objective" }],
250
+ };
251
+ }
252
+
253
+ const limited = rejectMaxConcurrent(executionState);
254
+ if (limited) return limited;
255
+
256
+ const run = createTaskRun({
257
+ kind: "standalone",
258
+ parentGraphId: "",
259
+ parentNodeId: "",
260
+ attempt: 1,
261
+ objective: goal,
262
+ title: String(title || goal).trim(),
263
+ });
264
+ const child = createChildGraphState({
265
+ parentGraphId: "",
266
+ parentNodeId: "",
267
+ taskRunId: run.id,
268
+ objective: goal,
269
+ });
270
+ run.childGraphId = child.graphId;
271
+ putTaskRun(executionState, run);
272
+ setGraph(executionState, child);
273
+
274
+ const payload = {
275
+ status: "started",
276
+ ok: true,
277
+ kind: "standalone",
278
+ graphId: "",
279
+ nodeId: "",
280
+ taskRunId: run.id,
281
+ childGraphId: child.graphId,
282
+ objective: goal,
283
+ title: run.title,
284
+ parentNodeStatus: "",
285
+ };
286
+ cacheControlCommand(executionState, commandId, payload);
287
+
288
+ enqueueTaskEvent(executionState, run.id, { kind: "advance" });
289
+
290
+ if (processImmediately) {
291
+ processTaskRun(executionState, run.id, { runTool, knownTools });
292
+ }
293
+
294
+ return payload;
295
+ }
296
+
195
297
  function cancelTask(executionState = null, {
196
298
  nodeId = "",
299
+ taskRunId = "",
197
300
  reason = "",
198
301
  commandId = "",
199
302
  } = {}) {
200
303
  const cached = getCachedControlCommand(executionState, commandId);
201
304
  if (cached) return { ...cached, idempotentReplay: true };
202
305
 
203
- const id = String(nodeId || "").trim();
204
- const active = findActiveTaskRunForNode(executionState, id);
205
- if (!active) {
206
- const { node } = findParentNode(executionState, id);
207
- if (node && (node.status === "succeeded" || node.status === "failed" || node.status === "cancelled")) {
208
- return {
209
- status: "rejected",
210
- ok: false,
211
- errors: [{
212
- code: "TASK_ALREADY_TERMINAL",
213
- message: `task ${id} already ${node.status}`,
214
- currentStatus: node.status,
215
- }],
216
- };
306
+ const resolved = resolveActiveRun(executionState, { nodeId, taskRunId });
307
+ const active = resolved.run;
308
+ if (!active || resolved.errorCode === "TASK_RUN_NOT_FOUND") {
309
+ const id = String(nodeId || "").trim();
310
+ if (id) {
311
+ const { node } = findParentNode(executionState, id);
312
+ if (node && (node.status === "succeeded" || node.status === "failed" || node.status === "cancelled")) {
313
+ return {
314
+ status: "rejected",
315
+ ok: false,
316
+ errors: [{
317
+ code: "TASK_ALREADY_TERMINAL",
318
+ message: `task ${id} already ${node.status}`,
319
+ currentStatus: node.status,
320
+ }],
321
+ };
322
+ }
217
323
  }
218
324
  return {
219
325
  status: "rejected",
220
326
  ok: false,
221
- errors: [{ code: "TASK_NOT_RUNNING", message: `no active run for ${id}` }],
327
+ errors: [{
328
+ code: resolved.errorCode || "TASK_NOT_RUNNING",
329
+ message: taskRunId
330
+ ? `no active run for taskRunId ${taskRunId}`
331
+ : `no active run for ${nodeId || "(missing id)"}`,
332
+ }],
222
333
  };
223
334
  }
224
335
 
225
- if (isTerminalTaskRun(active)) {
336
+ if (isTerminalTaskRun(active) || resolved.errorCode === "TASK_ALREADY_TERMINAL") {
226
337
  return {
227
338
  status: "rejected",
228
339
  ok: false,
@@ -252,7 +363,7 @@ function cancelTask(executionState = null, {
252
363
  const payload = {
253
364
  status: "accepted",
254
365
  ok: Boolean(done.ok),
255
- nodeId: id,
366
+ nodeId: active.parentNodeId || "",
256
367
  taskRunId: active.id,
257
368
  parentNodeStatus: done.run ? done.run.status : "cancelled",
258
369
  };
@@ -262,34 +373,43 @@ function cancelTask(executionState = null, {
262
373
 
263
374
  function failTask(executionState = null, {
264
375
  nodeId = "",
376
+ taskRunId = "",
265
377
  reason = "",
266
378
  commandId = "",
267
379
  } = {}) {
268
380
  const cached = getCachedControlCommand(executionState, commandId);
269
381
  if (cached) return { ...cached, idempotentReplay: true };
270
382
 
271
- const id = String(nodeId || "").trim();
272
- const active = findActiveTaskRunForNode(executionState, id);
273
- if (!active) {
274
- const { node } = findParentNode(executionState, id);
275
- if (node && (node.status === "succeeded" || node.status === "failed" || node.status === "cancelled")) {
276
- return {
277
- status: "rejected",
278
- ok: false,
279
- errors: [{
280
- code: "TASK_ALREADY_TERMINAL",
281
- message: `task ${id} already ${node.status}`,
282
- currentStatus: node.status,
283
- }],
284
- };
383
+ const resolved = resolveActiveRun(executionState, { nodeId, taskRunId });
384
+ const active = resolved.run;
385
+ if (!active || resolved.errorCode === "TASK_RUN_NOT_FOUND") {
386
+ const id = String(nodeId || "").trim();
387
+ if (id) {
388
+ const { node } = findParentNode(executionState, id);
389
+ if (node && (node.status === "succeeded" || node.status === "failed" || node.status === "cancelled")) {
390
+ return {
391
+ status: "rejected",
392
+ ok: false,
393
+ errors: [{
394
+ code: "TASK_ALREADY_TERMINAL",
395
+ message: `task ${id} already ${node.status}`,
396
+ currentStatus: node.status,
397
+ }],
398
+ };
399
+ }
285
400
  }
286
401
  return {
287
402
  status: "rejected",
288
403
  ok: false,
289
- errors: [{ code: "TASK_NOT_RUNNING", message: `no active run for ${id}` }],
404
+ errors: [{
405
+ code: resolved.errorCode || "TASK_NOT_RUNNING",
406
+ message: taskRunId
407
+ ? `no active run for taskRunId ${taskRunId}`
408
+ : `no active run for ${nodeId || "(missing id)"}`,
409
+ }],
290
410
  };
291
411
  }
292
- if (isTerminalTaskRun(active)) {
412
+ if (isTerminalTaskRun(active) || resolved.errorCode === "TASK_ALREADY_TERMINAL") {
293
413
  return {
294
414
  status: "rejected",
295
415
  ok: false,
@@ -313,7 +433,7 @@ function failTask(executionState = null, {
313
433
  const payload = {
314
434
  status: done.ok ? "accepted" : "rejected",
315
435
  ok: Boolean(done.ok),
316
- nodeId: id,
436
+ nodeId: active.parentNodeId || "",
317
437
  taskRunId: active.id,
318
438
  parentNodeStatus: done.run ? done.run.status : "failed",
319
439
  errors: done.ok ? undefined : [{ code: done.code || "CAS_FAILED", currentStatus: done.currentStatus }],
@@ -485,14 +605,16 @@ function runControlActions(executionState = null, {
485
605
  } else if (op === "cancel_task") {
486
606
  results.push(cancelTask(executionState, {
487
607
  nodeId: action.nodeId,
608
+ taskRunId: action.taskRunId,
488
609
  reason: action.reason,
489
- commandId: commandId && list.length === 1 ? commandId : `${commandId}:${op}:${action.nodeId}`,
610
+ commandId: commandId && list.length === 1 ? commandId : `${commandId}:${op}:${action.nodeId || action.taskRunId}`,
490
611
  }));
491
612
  } else if (op === "fail_task" || op === "mark_task_failed") {
492
613
  results.push(failTask(executionState, {
493
614
  nodeId: action.nodeId,
615
+ taskRunId: action.taskRunId,
494
616
  reason: action.reason,
495
- commandId: commandId && list.length === 1 ? commandId : `${commandId}:${op}:${action.nodeId}`,
617
+ commandId: commandId && list.length === 1 ? commandId : `${commandId}:${op}:${action.nodeId || action.taskRunId}`,
496
618
  }));
497
619
  } else if (op === "complete_task") {
498
620
  const taskRunId = String(action.taskRunId || "").trim();
@@ -528,6 +650,7 @@ function runControlActions(executionState = null, {
528
650
  } else if (op === "fail_current_task") {
529
651
  results.push(failTask(executionState, {
530
652
  nodeId: action.nodeId || (getTaskRun(executionState, action.taskRunId) || {}).parentNodeId,
653
+ taskRunId: action.taskRunId,
531
654
  reason: action.reason,
532
655
  commandId: commandId && list.length === 1 ? commandId : `${commandId}:${op}`,
533
656
  }));
@@ -554,6 +677,7 @@ function runControlActions(executionState = null, {
554
677
 
555
678
  module.exports = {
556
679
  startTask,
680
+ startStandaloneTask,
557
681
  cancelTask,
558
682
  failTask,
559
683
  completeTaskFromLoop,
@@ -82,6 +82,7 @@ function buildTaskFocus({
82
82
  currentNodeId = "",
83
83
  taskRunsById = {},
84
84
  recentlyChangedFiles = [],
85
+ standaloneTask = null,
85
86
  } = {}) {
86
87
  const byId = new Map((Array.isArray(nodes) ? nodes : []).map((n) => [n.id, n]));
87
88
  const current = byId.get(currentNodeId);
@@ -96,19 +97,38 @@ function buildTaskFocus({
96
97
  });
97
98
  const writers = Object.values(runs)
98
99
  .filter((r) => r && (r.status === "running" || r.status === "cancelling"))
99
- .map((r) => r.parentNodeId)
100
+ .map((r) => r.parentNodeId || r.id)
100
101
  .filter(Boolean);
101
102
 
103
+ let currentTask;
104
+ if (standaloneTask && typeof standaloneTask === "object") {
105
+ currentTask = {
106
+ id: standaloneTask.id || currentNodeId || "standalone",
107
+ objective: standaloneTask.objective || standaloneTask.title || "",
108
+ title: standaloneTask.title || standaloneTask.objective || standaloneTask.id || "standalone",
109
+ status: standaloneTask.status || (currentRun && currentRun.status) || "running",
110
+ };
111
+ } else if (current) {
112
+ currentTask = {
113
+ id: current.id,
114
+ objective: current.objective || current.title || "",
115
+ title: current.title || current.objective || current.id,
116
+ status: (currentRun && currentRun.status) || current.status,
117
+ };
118
+ } else {
119
+ currentTask = {
120
+ id: currentNodeId || "standalone",
121
+ objective: "",
122
+ title: currentNodeId || "standalone",
123
+ status: "unknown",
124
+ };
125
+ }
126
+
102
127
  return {
103
- currentTask: current
104
- ? {
105
- id: current.id,
106
- objective: current.objective || current.title || "",
107
- title: current.title || current.objective || current.id,
108
- status: (currentRun && currentRun.status) || current.status,
109
- }
110
- : { id: currentNodeId, objective: "", title: currentNodeId, status: "unknown" },
111
- dependencies: listDependencySummaries(nodes, currentNodeId, runs),
128
+ currentTask,
129
+ dependencies: currentNodeId
130
+ ? listDependencySummaries(nodes, currentNodeId, runs)
131
+ : [],
112
132
  parallelSiblings: siblings,
113
133
  workspace: {
114
134
  concurrentWriters: writers,
@@ -242,12 +242,23 @@ function processTaskRun(executionState = null, taskRunId = "", options = {}) {
242
242
  }
243
243
  }
244
244
 
245
- const parent = getGraph(executionState, live.parentGraphId) || executionState.planGraph;
245
+ const parent = live.parentGraphId
246
+ ? (getGraph(executionState, live.parentGraphId) || executionState.planGraph)
247
+ : null;
248
+ const standalone = !live.parentNodeId;
246
249
  const focus = buildTaskFocus({
247
250
  nodes: parent && parent.nodes ? parent.nodes : [],
248
251
  currentNodeId: live.parentNodeId,
249
252
  taskRunsById: (executionState.taskRuns && executionState.taskRuns.byId) || {},
250
253
  recentlyChangedFiles: executionState.modifiedFiles || [],
254
+ standaloneTask: standalone
255
+ ? {
256
+ id: live.id,
257
+ objective: live.objective || live.title || "",
258
+ title: live.title || live.objective || live.id,
259
+ status: live.status,
260
+ }
261
+ : null,
251
262
  });
252
263
  live.lastFocusText = renderTaskFocusText(focus);
253
264
  putTaskRun(executionState, live);
@@ -93,13 +93,22 @@ function createTaskRun({
93
93
  parentNodeId = "",
94
94
  childGraphId = "",
95
95
  attempt = 1,
96
+ kind = "",
97
+ objective = "",
98
+ title = "",
96
99
  } = {}) {
97
100
  const now = new Date().toISOString();
101
+ const parentNode = String(parentNodeId || "").trim();
102
+ const resolvedKind = String(kind || "").trim()
103
+ || (parentNode ? "graph_node" : "standalone");
98
104
  return {
99
105
  id: createTaskRunId(),
106
+ kind: resolvedKind,
100
107
  parentGraphId: String(parentGraphId || "").trim(),
101
- parentNodeId: String(parentNodeId || "").trim(),
108
+ parentNodeId: parentNode,
102
109
  childGraphId: String(childGraphId || "").trim(),
110
+ objective: String(objective || "").trim(),
111
+ title: String(title || objective || "").trim(),
103
112
  status: "queued",
104
113
  phase: "initializing",
105
114
  attempt: Number.isFinite(attempt) ? Math.max(1, Math.floor(attempt)) : 1,
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Ucode thinking-intensity levels.
5
+ *
6
+ * Used as the secondary `/model <id> <level>` menu after picking a model.
7
+ * Maps to Anthropic extended-thinking budget_tokens and OpenAI-compatible
8
+ * reasoning_effort where the transport supports it.
9
+ */
10
+
11
+ const THINKING_LEVELS = Object.freeze([
12
+ {
13
+ id: "off",
14
+ desc: "disable extended thinking",
15
+ budgetTokens: 0,
16
+ reasoningEffort: "",
17
+ },
18
+ {
19
+ id: "low",
20
+ desc: "light thinking",
21
+ budgetTokens: 2048,
22
+ reasoningEffort: "low",
23
+ },
24
+ {
25
+ id: "medium",
26
+ desc: "default thinking",
27
+ budgetTokens: 10000,
28
+ reasoningEffort: "medium",
29
+ },
30
+ {
31
+ id: "high",
32
+ desc: "deeper thinking",
33
+ budgetTokens: 32000,
34
+ reasoningEffort: "high",
35
+ },
36
+ {
37
+ id: "max",
38
+ desc: "maximum thinking budget",
39
+ budgetTokens: 48000,
40
+ reasoningEffort: "high",
41
+ },
42
+ ]);
43
+
44
+ const DEFAULT_THINKING_LEVEL = "medium";
45
+ const THINKING_LEVEL_IDS = new Set(THINKING_LEVELS.map((item) => item.id));
46
+
47
+ function normalizeThinkingLevel(value = "") {
48
+ const raw = String(value || "").trim().toLowerCase();
49
+ if (!raw) return "";
50
+ if (raw === "none" || raw === "disable" || raw === "disabled" || raw === "0") return "off";
51
+ if (raw === "med" || raw === "default") return "medium";
52
+ if (raw === "maximum" || raw === "xhigh" || raw === "ultra") return "max";
53
+ if (THINKING_LEVEL_IDS.has(raw)) return raw;
54
+ return "";
55
+ }
56
+
57
+ function getThinkingLevel(id = "") {
58
+ const normalized = normalizeThinkingLevel(id) || DEFAULT_THINKING_LEVEL;
59
+ return THINKING_LEVELS.find((item) => item.id === normalized) || THINKING_LEVELS[2];
60
+ }
61
+
62
+ function suggestThinkingLevels(options = {}) {
63
+ const current = normalizeThinkingLevel(options.current || "") || DEFAULT_THINKING_LEVEL;
64
+ return THINKING_LEVELS.map((item) => ({
65
+ id: item.id,
66
+ desc: item.id === current ? `${item.desc} · current` : item.desc,
67
+ }));
68
+ }
69
+
70
+ function resolveThinkingFromEnvAndConfig({
71
+ env = process.env,
72
+ configLevel = "",
73
+ } = {}) {
74
+ // Explicit numeric budget still wins (advanced override).
75
+ const rawBudget = env && env.UFOO_UCODE_THINKING_BUDGET_TOKENS;
76
+ if (rawBudget !== undefined && rawBudget !== null && String(rawBudget).trim() !== "") {
77
+ const parsed = Number.parseInt(String(rawBudget), 10);
78
+ if (!Number.isFinite(parsed) || parsed <= 0) {
79
+ return {
80
+ level: "off",
81
+ budgetTokens: 0,
82
+ reasoningEffort: "",
83
+ source: "env-budget",
84
+ };
85
+ }
86
+ return {
87
+ level: "",
88
+ budgetTokens: Math.floor(parsed),
89
+ reasoningEffort: "",
90
+ source: "env-budget",
91
+ };
92
+ }
93
+
94
+ const fromEnv = normalizeThinkingLevel(env && env.UFOO_UCODE_THINKING);
95
+ const fromConfig = normalizeThinkingLevel(configLevel);
96
+ const level = fromEnv || fromConfig || DEFAULT_THINKING_LEVEL;
97
+ const spec = getThinkingLevel(level);
98
+ return {
99
+ level: spec.id,
100
+ budgetTokens: spec.budgetTokens,
101
+ reasoningEffort: spec.reasoningEffort,
102
+ source: fromEnv ? "env" : (fromConfig ? "config" : "default"),
103
+ };
104
+ }
105
+
106
+ function applyThinkingLevelToEnv(level = "", env = process.env) {
107
+ const normalized = normalizeThinkingLevel(level);
108
+ if (!normalized) return "";
109
+ const spec = getThinkingLevel(normalized);
110
+ try {
111
+ env.UFOO_UCODE_THINKING = spec.id;
112
+ if (spec.budgetTokens > 0) {
113
+ env.UFOO_UCODE_THINKING_BUDGET_TOKENS = String(spec.budgetTokens);
114
+ } else {
115
+ env.UFOO_UCODE_THINKING_BUDGET_TOKENS = "0";
116
+ }
117
+ } catch {
118
+ // ignore env write failures
119
+ }
120
+ return spec.id;
121
+ }
122
+
123
+ module.exports = {
124
+ THINKING_LEVELS,
125
+ THINKING_LEVEL_IDS,
126
+ DEFAULT_THINKING_LEVEL,
127
+ normalizeThinkingLevel,
128
+ getThinkingLevel,
129
+ suggestThinkingLevels,
130
+ resolveThinkingFromEnvAndConfig,
131
+ applyThinkingLevelToEnv,
132
+ };