open-research 1.2.0 → 1.2.1
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/dist/{chunk-32Q63SUH.js → chunk-G7IOFPGG.js} +46 -24
- package/dist/{chunk-W3MWVV2O.js → chunk-YFDZRMPM.js} +1 -1
- package/dist/cli.js +239 -66
- package/dist/{manager-queue-NK5B47A4.js → manager-queue-RWWN2TU3.js} +1 -1
- package/dist/server/serve.js +2 -2
- package/dist/{server-PLHMTHCG.js → server-7CSQEGRQ.js} +2 -2
- package/package.json +1 -1
|
@@ -693,7 +693,7 @@ ${input.workflow}
|
|
|
693
693
|
}
|
|
694
694
|
|
|
695
695
|
// src/lib/cli/version.ts
|
|
696
|
-
var PACKAGE_VERSION = "1.2.
|
|
696
|
+
var PACKAGE_VERSION = "1.2.1";
|
|
697
697
|
function getPackageVersion() {
|
|
698
698
|
return PACKAGE_VERSION;
|
|
699
699
|
}
|
|
@@ -2070,6 +2070,24 @@ async function applyProposedUpdate(workspaceDir, update) {
|
|
|
2070
2070
|
return absolutePath;
|
|
2071
2071
|
}
|
|
2072
2072
|
|
|
2073
|
+
// src/lib/agent/tools/current-task.ts
|
|
2074
|
+
var currentTask = null;
|
|
2075
|
+
function executeSetCurrentTask(args) {
|
|
2076
|
+
currentTask = args.task;
|
|
2077
|
+
return `Current focus set: ${args.task}`;
|
|
2078
|
+
}
|
|
2079
|
+
function getCurrentTaskBlock() {
|
|
2080
|
+
if (!currentTask) return null;
|
|
2081
|
+
return `## Current Focus
|
|
2082
|
+
${currentTask}`;
|
|
2083
|
+
}
|
|
2084
|
+
function getCurrentTask() {
|
|
2085
|
+
return currentTask;
|
|
2086
|
+
}
|
|
2087
|
+
function clearCurrentTask() {
|
|
2088
|
+
currentTask = null;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2073
2091
|
// src/lib/memory/store.ts
|
|
2074
2092
|
import fs6 from "fs/promises";
|
|
2075
2093
|
import path6 from "path";
|
|
@@ -5023,6 +5041,7 @@ ${input.context}` : input.goal;
|
|
|
5023
5041
|
let iterations = 0;
|
|
5024
5042
|
let handoff;
|
|
5025
5043
|
let activeSkills = [];
|
|
5044
|
+
const recentToolDescriptions = [];
|
|
5026
5045
|
function emitProgress(currentTool, status = "running") {
|
|
5027
5046
|
input.onProgress?.({
|
|
5028
5047
|
agentId: input.agentId,
|
|
@@ -5030,9 +5049,14 @@ ${input.context}` : input.goal;
|
|
|
5030
5049
|
goal: input.goal,
|
|
5031
5050
|
currentTool,
|
|
5032
5051
|
toolCount: totalToolCalls,
|
|
5052
|
+
recentTools: recentToolDescriptions.slice(-3),
|
|
5033
5053
|
status
|
|
5034
5054
|
});
|
|
5035
5055
|
}
|
|
5056
|
+
function trackCompletedTool(description) {
|
|
5057
|
+
recentToolDescriptions.push(description);
|
|
5058
|
+
if (recentToolDescriptions.length > 3) recentToolDescriptions.shift();
|
|
5059
|
+
}
|
|
5036
5060
|
emitProgress("");
|
|
5037
5061
|
for (; ; ) {
|
|
5038
5062
|
if (input.signal?.aborted) break;
|
|
@@ -5122,6 +5146,7 @@ ${input.context}` : input.goal;
|
|
|
5122
5146
|
activeSkills.push(skill);
|
|
5123
5147
|
}
|
|
5124
5148
|
}
|
|
5149
|
+
trackCompletedTool(description);
|
|
5125
5150
|
messages.push({
|
|
5126
5151
|
role: "tool",
|
|
5127
5152
|
tool_call_id: toolCall.id,
|
|
@@ -5260,21 +5285,6 @@ function describeSubAgentTool(name, args) {
|
|
|
5260
5285
|
}
|
|
5261
5286
|
}
|
|
5262
5287
|
|
|
5263
|
-
// src/lib/agent/tools/current-task.ts
|
|
5264
|
-
var currentTask = null;
|
|
5265
|
-
function executeSetCurrentTask(args) {
|
|
5266
|
-
currentTask = args.task;
|
|
5267
|
-
return `Current focus set: ${args.task}`;
|
|
5268
|
-
}
|
|
5269
|
-
function getCurrentTaskBlock() {
|
|
5270
|
-
if (!currentTask) return null;
|
|
5271
|
-
return `## Current Focus
|
|
5272
|
-
${currentTask}`;
|
|
5273
|
-
}
|
|
5274
|
-
function clearCurrentTask() {
|
|
5275
|
-
currentTask = null;
|
|
5276
|
-
}
|
|
5277
|
-
|
|
5278
5288
|
// src/lib/agent/tool-dispatcher.ts
|
|
5279
5289
|
async function executeTool(name, args, ctx, activeSkills, homeDir, signal, provider, onSubAgentProgress, toolCallId, bridges) {
|
|
5280
5290
|
switch (name) {
|
|
@@ -5746,16 +5756,27 @@ function buildSystemPrompt(ctx, activeSkills) {
|
|
|
5746
5756
|
${skill.prompt}`).join("\n\n");
|
|
5747
5757
|
return [
|
|
5748
5758
|
"You are Open Research \u2014 a research director who orchestrates specialized agents through a terminal CLI.",
|
|
5749
|
-
"Your primary mode: understand the user's research question, decompose it into steps, delegate each step to the right sub-agent, and synthesize findings into clear conclusions.",
|
|
5750
5759
|
"",
|
|
5751
|
-
"##
|
|
5752
|
-
"
|
|
5753
|
-
"
|
|
5754
|
-
"
|
|
5760
|
+
"## Before You Act: Classify the Request",
|
|
5761
|
+
"Every user message falls into one of three categories. Identify which BEFORE doing anything:",
|
|
5762
|
+
"",
|
|
5763
|
+
"**1. ANSWER DIRECTLY** \u2014 The user asks a question you can answer from knowledge or with 1-2 tool calls.",
|
|
5764
|
+
" Examples: 'What is p-hacking?', 'Summarize the notes in my workspace', 'What model am I using?'",
|
|
5765
|
+
" \u2192 Just answer. No plan file. No sub-agent. Respond immediately.",
|
|
5766
|
+
"",
|
|
5767
|
+
"**2. CLARIFY FIRST** \u2014 The request is vague, ambiguous, or could mean multiple things.",
|
|
5768
|
+
" Examples: 'Research transformers', 'Help me with my paper', 'Find some papers'",
|
|
5769
|
+
" \u2192 Use `ask_user` to clarify BEFORE doing any work. Ask: What specific question? What scope? What output format?",
|
|
5770
|
+
" \u2192 Do NOT create a plan file or launch sub-agents until the goal is crystal clear.",
|
|
5771
|
+
"",
|
|
5772
|
+
"**3. RESEARCH (multi-step)** \u2014 The request is specific and requires sustained research work.",
|
|
5773
|
+
" Examples: 'Find papers on whether attention is necessary in transformers and summarize the evidence',",
|
|
5774
|
+
" 'Run an experiment comparing dropout rates on CIFAR-10', 'Draft a literature review on scaling laws'",
|
|
5775
|
+
" \u2192 Create a plan, delegate to sub-agents, synthesize results.",
|
|
5755
5776
|
"",
|
|
5756
|
-
"## How You Work (
|
|
5777
|
+
"## How You Work (Category 3 Only)",
|
|
5757
5778
|
"1. Set your focus: `set_current_task('Planning: ...')`",
|
|
5758
|
-
"2. Create a plan: `write_new_file` with key `path:run/archive/{YYYY-MM-DDTHH-MM-SS}/plan.md`
|
|
5779
|
+
"2. Create a plan: `write_new_file` with key `path:run/archive/{YYYY-MM-DDTHH-MM-SS}/plan.md`",
|
|
5759
5780
|
"3. Delegate each step:",
|
|
5760
5781
|
" `launch_subagent(type: 'research', skill: 'source-scout', goal: '...', context: '...')`",
|
|
5761
5782
|
" Skills: source-scout, experiment-designer, data-analyst, devils-advocate, methodology-critic, evidence-adjudicator, novelty-checker, paper-explainer, draft-paper, reviewer-response",
|
|
@@ -5932,7 +5953,7 @@ ${agentsMd}` : null,
|
|
|
5932
5953
|
});
|
|
5933
5954
|
}
|
|
5934
5955
|
if (input.workspace.workspaceDir) {
|
|
5935
|
-
import("./manager-queue-
|
|
5956
|
+
import("./manager-queue-RWWN2TU3.js").then(({ enqueueOntologyManager }) => {
|
|
5936
5957
|
enqueueOntologyManager({
|
|
5937
5958
|
userMessage: input.message,
|
|
5938
5959
|
agentResponse: fullText,
|
|
@@ -6429,6 +6450,7 @@ export {
|
|
|
6429
6450
|
resetPendingQuestions,
|
|
6430
6451
|
classifyUpdateRisk,
|
|
6431
6452
|
applyProposedUpdate,
|
|
6453
|
+
getCurrentTask,
|
|
6432
6454
|
clearCurrentTask,
|
|
6433
6455
|
loadAllMemories,
|
|
6434
6456
|
deleteMemory,
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
createSkillScaffold,
|
|
11
11
|
deleteMemory,
|
|
12
12
|
getAuthStatus,
|
|
13
|
+
getCurrentTask,
|
|
13
14
|
getPackageVersion,
|
|
14
15
|
getPendingQuestion,
|
|
15
16
|
hasConfiguredProvider,
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
scanWorkspace,
|
|
26
27
|
validateSkillDirectory,
|
|
27
28
|
writeAgentsMd
|
|
28
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-G7IOFPGG.js";
|
|
29
30
|
import {
|
|
30
31
|
createSessionUsage,
|
|
31
32
|
estimateConversationTokens,
|
|
@@ -201,10 +202,10 @@ import path5 from "path";
|
|
|
201
202
|
import React6, {
|
|
202
203
|
startTransition as startTransition2,
|
|
203
204
|
useDeferredValue,
|
|
204
|
-
useEffect as
|
|
205
|
+
useEffect as useEffect5,
|
|
205
206
|
useMemo as useMemo4,
|
|
206
207
|
useRef as useRef2,
|
|
207
|
-
useState as
|
|
208
|
+
useState as useState8
|
|
208
209
|
} from "react";
|
|
209
210
|
import { Box as Box5, Static, Text as Text5, useApp, useInput as useInput5 } from "ink";
|
|
210
211
|
|
|
@@ -2300,9 +2301,10 @@ var AgentMessage = memo(function AgentMessage2({ text, width }) {
|
|
|
2300
2301
|
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: bodyWidth, children: /* @__PURE__ */ jsx4(Text4, { wrap: "wrap", children: wrappedText }) })
|
|
2301
2302
|
] });
|
|
2302
2303
|
});
|
|
2303
|
-
function ThinkingIndicator({ frame, width }) {
|
|
2304
|
+
function ThinkingIndicator({ frame, width, currentTask }) {
|
|
2304
2305
|
const theme = useTheme();
|
|
2305
2306
|
const contentWidth = resolveWidth(width);
|
|
2307
|
+
const label = currentTask || "thinking...";
|
|
2306
2308
|
return /* @__PURE__ */ jsxs3(Box4, { marginBottom: 1, width: contentWidth, children: [
|
|
2307
2309
|
/* @__PURE__ */ jsxs3(Text4, { color: theme.secondary, bold: true, children: [
|
|
2308
2310
|
GUTTER.agent,
|
|
@@ -2310,10 +2312,28 @@ function ThinkingIndicator({ frame, width }) {
|
|
|
2310
2312
|
] }),
|
|
2311
2313
|
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
2312
2314
|
frame,
|
|
2313
|
-
"
|
|
2315
|
+
" ",
|
|
2316
|
+
label
|
|
2314
2317
|
] })
|
|
2315
2318
|
] });
|
|
2316
2319
|
}
|
|
2320
|
+
function ActivityFeed({ items, frame, width }) {
|
|
2321
|
+
const theme = useTheme();
|
|
2322
|
+
const contentWidth = resolveWidth(width);
|
|
2323
|
+
const visible = items.slice(-6);
|
|
2324
|
+
if (visible.length === 0) return null;
|
|
2325
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginBottom: 1, width: contentWidth, children: visible.map((item, i) => {
|
|
2326
|
+
const icon = item.status === "done" ? "\u2713" : frame;
|
|
2327
|
+
const color = item.status === "done" ? theme.muted : theme.secondary;
|
|
2328
|
+
const duration = item.durationMs !== void 0 ? ` (${(item.durationMs / 1e3).toFixed(1)}s)` : "";
|
|
2329
|
+
return /* @__PURE__ */ jsx4(Box4, { paddingLeft: 2, children: /* @__PURE__ */ jsxs3(Text4, { color, dimColor: item.status === "done", children: [
|
|
2330
|
+
icon,
|
|
2331
|
+
" ",
|
|
2332
|
+
item.description,
|
|
2333
|
+
duration
|
|
2334
|
+
] }) }, i);
|
|
2335
|
+
}) });
|
|
2336
|
+
}
|
|
2317
2337
|
var ToolActivitySummary = memo(function ToolActivitySummary2({
|
|
2318
2338
|
summary,
|
|
2319
2339
|
tools,
|
|
@@ -2371,6 +2391,7 @@ function SubAgentIndicator({
|
|
|
2371
2391
|
goal,
|
|
2372
2392
|
currentTool,
|
|
2373
2393
|
toolCount,
|
|
2394
|
+
recentTools,
|
|
2374
2395
|
frame,
|
|
2375
2396
|
width
|
|
2376
2397
|
}) {
|
|
@@ -2406,8 +2427,14 @@ function SubAgentIndicator({
|
|
|
2406
2427
|
" ",
|
|
2407
2428
|
shortGoal
|
|
2408
2429
|
] }) }),
|
|
2430
|
+
recentTools && recentTools.length > 0 && recentTools.map((tool, i) => /* @__PURE__ */ jsx4(Box4, { width: innerWidth, children: /* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: [
|
|
2431
|
+
" \u2713 ",
|
|
2432
|
+
tool
|
|
2433
|
+
] }) }, i)),
|
|
2409
2434
|
/* @__PURE__ */ jsx4(Box4, { width: innerWidth, children: /* @__PURE__ */ jsxs3(Text4, { color: theme.text, wrap: "wrap", children: [
|
|
2410
|
-
"
|
|
2435
|
+
" ",
|
|
2436
|
+
currentTool ? "\u25D0" : "\u2514",
|
|
2437
|
+
" ",
|
|
2411
2438
|
status
|
|
2412
2439
|
] }) })
|
|
2413
2440
|
]
|
|
@@ -2986,6 +3013,7 @@ function splitMessagesForRender(messages, busy) {
|
|
|
2986
3013
|
}
|
|
2987
3014
|
function createSentenceStreamBuffer({
|
|
2988
3015
|
onFlush,
|
|
3016
|
+
isVisible = () => true,
|
|
2989
3017
|
flushIntervalMs = STREAM_FLUSH_INTERVAL_MS,
|
|
2990
3018
|
flushPattern = STREAM_FLUSH_PATTERN
|
|
2991
3019
|
}) {
|
|
@@ -2996,8 +3024,9 @@ function createSentenceStreamBuffer({
|
|
|
2996
3024
|
clearTimeout(timer);
|
|
2997
3025
|
timer = null;
|
|
2998
3026
|
};
|
|
2999
|
-
const flush = () => {
|
|
3027
|
+
const flush = (options) => {
|
|
3000
3028
|
if (!buffer) return "";
|
|
3029
|
+
if (!options?.force && !isVisible()) return "";
|
|
3001
3030
|
clearPendingTimer();
|
|
3002
3031
|
const text = buffer;
|
|
3003
3032
|
buffer = "";
|
|
@@ -3024,7 +3053,7 @@ function createSentenceStreamBuffer({
|
|
|
3024
3053
|
flush,
|
|
3025
3054
|
dispose() {
|
|
3026
3055
|
clearPendingTimer();
|
|
3027
|
-
return flush();
|
|
3056
|
+
return flush({ force: true });
|
|
3028
3057
|
}
|
|
3029
3058
|
};
|
|
3030
3059
|
}
|
|
@@ -3036,6 +3065,10 @@ import { useStdout as useStdout2 } from "ink";
|
|
|
3036
3065
|
// src/tui/ink-stdout.ts
|
|
3037
3066
|
var RAW_COLUMNS = /* @__PURE__ */ Symbol("open-research.raw-columns");
|
|
3038
3067
|
var RAW_ROWS = /* @__PURE__ */ Symbol("open-research.raw-rows");
|
|
3068
|
+
var GET_VISIBILITY = /* @__PURE__ */ Symbol("open-research.get-visibility");
|
|
3069
|
+
var SET_FOCUS_VISIBILITY = /* @__PURE__ */ Symbol("open-research.set-focus-visibility");
|
|
3070
|
+
var ADD_VISIBILITY_LISTENER = /* @__PURE__ */ Symbol("open-research.add-visibility-listener");
|
|
3071
|
+
var REMOVE_VISIBILITY_LISTENER = /* @__PURE__ */ Symbol("open-research.remove-visibility-listener");
|
|
3039
3072
|
function getStableRow(current, fallback) {
|
|
3040
3073
|
return typeof current === "number" && current > 0 ? current : fallback;
|
|
3041
3074
|
}
|
|
@@ -3057,6 +3090,20 @@ function hasRenderableTerminalDimensions(stdout) {
|
|
|
3057
3090
|
const hasRows = rows === void 0 || rows > 0;
|
|
3058
3091
|
return hasRows && typeof columns === "number" && columns >= MIN_TERMINAL_WIDTH;
|
|
3059
3092
|
}
|
|
3093
|
+
function isTerminalVisible(stdout) {
|
|
3094
|
+
const stream = stdout;
|
|
3095
|
+
return stream[GET_VISIBILITY]?.() ?? hasRenderableTerminalDimensions(stdout);
|
|
3096
|
+
}
|
|
3097
|
+
function setTerminalFocusVisible(stdout, visible) {
|
|
3098
|
+
stdout[SET_FOCUS_VISIBILITY]?.(visible);
|
|
3099
|
+
}
|
|
3100
|
+
function observeTerminalVisibility(stdout, listener) {
|
|
3101
|
+
const stream = stdout;
|
|
3102
|
+
stream[ADD_VISIBILITY_LISTENER]?.(listener);
|
|
3103
|
+
return () => {
|
|
3104
|
+
stream[REMOVE_VISIBILITY_LISTENER]?.(listener);
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3060
3107
|
function createStableInkStdout(stdout, options) {
|
|
3061
3108
|
const forceFullRedraw = options?.forceFullRedraw ?? process.env.OPEN_RESEARCH_FORCE_FULL_REDRAW === "1";
|
|
3062
3109
|
const initialRows = getRawDimension(stdout.rows);
|
|
@@ -3064,6 +3111,26 @@ function createStableInkStdout(stdout, options) {
|
|
|
3064
3111
|
let lastRows = getStableRow(initialRows, 24);
|
|
3065
3112
|
let lastColumns = typeof initialColumns === "number" && initialColumns > 0 ? Math.max(MIN_TERMINAL_WIDTH, initialColumns) : 80;
|
|
3066
3113
|
const resizeListeners = /* @__PURE__ */ new Map();
|
|
3114
|
+
const visibilityListeners = /* @__PURE__ */ new Set();
|
|
3115
|
+
let focusVisible = true;
|
|
3116
|
+
let visible = focusVisible && hasRenderableTerminalDimensions({
|
|
3117
|
+
[RAW_COLUMNS]: initialColumns,
|
|
3118
|
+
[RAW_ROWS]: initialRows
|
|
3119
|
+
});
|
|
3120
|
+
const syncVisibility = () => {
|
|
3121
|
+
const nextVisible = focusVisible && hasRenderableTerminalDimensions({
|
|
3122
|
+
[RAW_COLUMNS]: getRawDimension(stdout.columns),
|
|
3123
|
+
[RAW_ROWS]: getRawDimension(stdout.rows)
|
|
3124
|
+
});
|
|
3125
|
+
if (nextVisible === visible) {
|
|
3126
|
+
return visible;
|
|
3127
|
+
}
|
|
3128
|
+
visible = nextVisible;
|
|
3129
|
+
for (const listener of visibilityListeners) {
|
|
3130
|
+
listener(visible);
|
|
3131
|
+
}
|
|
3132
|
+
return visible;
|
|
3133
|
+
};
|
|
3067
3134
|
return new Proxy(stdout, {
|
|
3068
3135
|
get(target, prop, receiver) {
|
|
3069
3136
|
if (prop === RAW_ROWS) {
|
|
@@ -3072,6 +3139,25 @@ function createStableInkStdout(stdout, options) {
|
|
|
3072
3139
|
if (prop === RAW_COLUMNS) {
|
|
3073
3140
|
return getRawDimension(Reflect.get(target, "columns", receiver));
|
|
3074
3141
|
}
|
|
3142
|
+
if (prop === GET_VISIBILITY) {
|
|
3143
|
+
return () => visible;
|
|
3144
|
+
}
|
|
3145
|
+
if (prop === SET_FOCUS_VISIBILITY) {
|
|
3146
|
+
return (nextVisible) => {
|
|
3147
|
+
focusVisible = nextVisible;
|
|
3148
|
+
syncVisibility();
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
if (prop === ADD_VISIBILITY_LISTENER) {
|
|
3152
|
+
return (listener) => {
|
|
3153
|
+
visibilityListeners.add(listener);
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
if (prop === REMOVE_VISIBILITY_LISTENER) {
|
|
3157
|
+
return (listener) => {
|
|
3158
|
+
visibilityListeners.delete(listener);
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3075
3161
|
if (prop === "rows") {
|
|
3076
3162
|
if (forceFullRedraw) {
|
|
3077
3163
|
return 0;
|
|
@@ -3085,6 +3171,14 @@ function createStableInkStdout(stdout, options) {
|
|
|
3085
3171
|
lastColumns = getStableColumn(columns, lastColumns);
|
|
3086
3172
|
return lastColumns;
|
|
3087
3173
|
}
|
|
3174
|
+
if (prop === "write") {
|
|
3175
|
+
return (chunk, ...args) => {
|
|
3176
|
+
if (!visible) {
|
|
3177
|
+
return true;
|
|
3178
|
+
}
|
|
3179
|
+
return Reflect.get(target, prop, receiver).call(target, chunk, ...args);
|
|
3180
|
+
};
|
|
3181
|
+
}
|
|
3088
3182
|
if (prop === "on" || prop === "addListener" || prop === "once" || prop === "prependListener") {
|
|
3089
3183
|
const method = prop;
|
|
3090
3184
|
return (eventName, listener) => {
|
|
@@ -3094,6 +3188,7 @@ function createStableInkStdout(stdout, options) {
|
|
|
3094
3188
|
const rawRows = getRawDimension(Reflect.get(target, "rows", receiver));
|
|
3095
3189
|
lastColumns = getStableColumn(rawColumns, lastColumns);
|
|
3096
3190
|
lastRows = getStableRow(rawRows, lastRows);
|
|
3191
|
+
syncVisibility();
|
|
3097
3192
|
if (!hasRenderableTerminalDimensions({
|
|
3098
3193
|
[RAW_COLUMNS]: rawColumns,
|
|
3099
3194
|
[RAW_ROWS]: rawRows
|
|
@@ -3136,7 +3231,7 @@ function useAnimatedFrame(active) {
|
|
|
3136
3231
|
return;
|
|
3137
3232
|
}
|
|
3138
3233
|
const timer = setInterval(() => {
|
|
3139
|
-
if (!
|
|
3234
|
+
if (!isTerminalVisible(stdout)) {
|
|
3140
3235
|
return;
|
|
3141
3236
|
}
|
|
3142
3237
|
setIndex((v) => (v + 1) % SPINNER_FRAMES.length);
|
|
@@ -3146,16 +3241,60 @@ function useAnimatedFrame(active) {
|
|
|
3146
3241
|
return SPINNER_FRAMES[index] ?? SPINNER_FRAMES[0];
|
|
3147
3242
|
}
|
|
3148
3243
|
|
|
3244
|
+
// src/tui/hooks/use-terminal-visibility.ts
|
|
3245
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
3246
|
+
import { useStdin, useStdout as useStdout3 } from "ink";
|
|
3247
|
+
var ENABLE_FOCUS_REPORTING = "\x1B[?1004h";
|
|
3248
|
+
var DISABLE_FOCUS_REPORTING = "\x1B[?1004l";
|
|
3249
|
+
var FOCUS_IN = "\x1B[I";
|
|
3250
|
+
var FOCUS_OUT = "\x1B[O";
|
|
3251
|
+
function useTerminalVisibility() {
|
|
3252
|
+
const { stdout } = useStdout3();
|
|
3253
|
+
const { stdin } = useStdin();
|
|
3254
|
+
const [visible, setVisible] = useState6(
|
|
3255
|
+
() => isTerminalVisible(stdout)
|
|
3256
|
+
);
|
|
3257
|
+
useEffect3(() => {
|
|
3258
|
+
const output2 = stdout;
|
|
3259
|
+
const input2 = stdin;
|
|
3260
|
+
setVisible(isTerminalVisible(output2));
|
|
3261
|
+
const unsubscribe = observeTerminalVisibility(output2, setVisible);
|
|
3262
|
+
const handleData = (data) => {
|
|
3263
|
+
const text = typeof data === "string" ? data : data.toString("utf8");
|
|
3264
|
+
if (text.includes(FOCUS_OUT)) {
|
|
3265
|
+
setTerminalFocusVisible(output2, false);
|
|
3266
|
+
}
|
|
3267
|
+
if (text.includes(FOCUS_IN)) {
|
|
3268
|
+
setTerminalFocusVisible(output2, true);
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
if (output2.isTTY) {
|
|
3272
|
+
output2.write(ENABLE_FOCUS_REPORTING);
|
|
3273
|
+
}
|
|
3274
|
+
input2.on?.("data", handleData);
|
|
3275
|
+
return () => {
|
|
3276
|
+
input2.off?.("data", handleData);
|
|
3277
|
+
input2.removeListener?.("data", handleData);
|
|
3278
|
+
unsubscribe();
|
|
3279
|
+
setTerminalFocusVisible(output2, true);
|
|
3280
|
+
if (output2.isTTY) {
|
|
3281
|
+
output2.write(DISABLE_FOCUS_REPORTING);
|
|
3282
|
+
}
|
|
3283
|
+
};
|
|
3284
|
+
}, [stdin, stdout]);
|
|
3285
|
+
return visible;
|
|
3286
|
+
}
|
|
3287
|
+
|
|
3149
3288
|
// src/tui/hooks/use-terminal-width.ts
|
|
3150
|
-
import { useState as
|
|
3151
|
-
import { useStdout as
|
|
3289
|
+
import { useState as useState7, useEffect as useEffect4 } from "react";
|
|
3290
|
+
import { useStdout as useStdout4 } from "ink";
|
|
3152
3291
|
var RESIZE_DEBOUNCE_MS = 50;
|
|
3153
3292
|
function useTerminalWidth() {
|
|
3154
|
-
const { stdout } =
|
|
3155
|
-
const [terminalWidth, setTerminalWidth] =
|
|
3293
|
+
const { stdout } = useStdout4();
|
|
3294
|
+
const [terminalWidth, setTerminalWidth] = useState7(
|
|
3156
3295
|
() => getObservedTerminalWidth(stdout.columns, process.stdout.columns)
|
|
3157
3296
|
);
|
|
3158
|
-
|
|
3297
|
+
useEffect4(() => {
|
|
3159
3298
|
const stream = stdout;
|
|
3160
3299
|
let resizeTimer = null;
|
|
3161
3300
|
const commitWidth = () => {
|
|
@@ -4454,47 +4593,51 @@ function App({
|
|
|
4454
4593
|
const abortRef = useRef2(null);
|
|
4455
4594
|
const turnManagerRef = useRef2(null);
|
|
4456
4595
|
const turnIndexRef = useRef2(0);
|
|
4457
|
-
const [input2, setInput] =
|
|
4458
|
-
const [composerFocused, setComposerFocused] =
|
|
4459
|
-
const [busy, setBusy] =
|
|
4460
|
-
const [authStatus, setAuthStatus] =
|
|
4461
|
-
const [workspacePath, setWorkspacePath] =
|
|
4462
|
-
const [workspaceFiles, setWorkspaceFiles] =
|
|
4463
|
-
const [skills2, setSkills] =
|
|
4464
|
-
const [messages, setMessages] =
|
|
4465
|
-
const [history, setHistory] =
|
|
4466
|
-
const [activeSkills, setActiveSkills] =
|
|
4467
|
-
const [pendingUpdates, setPendingUpdates] =
|
|
4468
|
-
const [statusLine, setStatusLine] =
|
|
4469
|
-
const [activeToolActivities, setActiveToolActivities] =
|
|
4470
|
-
const [turnToolCount, setTurnToolCount] =
|
|
4471
|
-
const [latchedToolActivity, setLatchedToolActivity] =
|
|
4472
|
-
const [latchedToolCount, setLatchedToolCount] =
|
|
4473
|
-
const [subAgentProgress, setSubAgentProgress] =
|
|
4474
|
-
const [toolActivityExpanded, setToolActivityExpanded] =
|
|
4596
|
+
const [input2, setInput] = useState8("");
|
|
4597
|
+
const [composerFocused, setComposerFocused] = useState8(true);
|
|
4598
|
+
const [busy, setBusy] = useState8(false);
|
|
4599
|
+
const [authStatus, setAuthStatus] = useState8(initialState.authStatus);
|
|
4600
|
+
const [workspacePath, setWorkspacePath] = useState8(initialState.workspacePath);
|
|
4601
|
+
const [workspaceFiles, setWorkspaceFiles] = useState8([]);
|
|
4602
|
+
const [skills2, setSkills] = useState8([]);
|
|
4603
|
+
const [messages, setMessages] = useState8([]);
|
|
4604
|
+
const [history, setHistory] = useState8([]);
|
|
4605
|
+
const [activeSkills, setActiveSkills] = useState8([]);
|
|
4606
|
+
const [pendingUpdates, setPendingUpdates] = useState8(initialState.pendingUpdates);
|
|
4607
|
+
const [statusLine, setStatusLine] = useState8("");
|
|
4608
|
+
const [activeToolActivities, setActiveToolActivities] = useState8({});
|
|
4609
|
+
const [turnToolCount, setTurnToolCount] = useState8(0);
|
|
4610
|
+
const [latchedToolActivity, setLatchedToolActivity] = useState8("");
|
|
4611
|
+
const [latchedToolCount, setLatchedToolCount] = useState8(0);
|
|
4612
|
+
const [subAgentProgress, setSubAgentProgress] = useState8({});
|
|
4613
|
+
const [toolActivityExpanded, setToolActivityExpanded] = useState8(false);
|
|
4475
4614
|
const turnToolLogRef = useRef2([]);
|
|
4476
|
-
const [sessionTokens, setSessionTokens] =
|
|
4477
|
-
const [tokenDisplay, setTokenDisplay] =
|
|
4478
|
-
const [showSuggestions, setShowSuggestions] =
|
|
4479
|
-
const [agentMode, setAgentMode] =
|
|
4480
|
-
const [theme, setTheme] =
|
|
4481
|
-
const [config, setConfig] =
|
|
4482
|
-
const [cursorToEnd, setCursorToEnd] =
|
|
4483
|
-
const [messageRenderVersion, setMessageRenderVersion] =
|
|
4484
|
-
const [screen, setScreen] =
|
|
4485
|
-
const [resumeSessions, setResumeSessions] =
|
|
4486
|
-
const [ctrlCPending, setCtrlCPending] =
|
|
4487
|
-
const [sessionId, setSessionId] =
|
|
4615
|
+
const [sessionTokens, setSessionTokens] = useState8(() => createSessionUsage());
|
|
4616
|
+
const [tokenDisplay, setTokenDisplay] = useState8("");
|
|
4617
|
+
const [showSuggestions, setShowSuggestions] = useState8(false);
|
|
4618
|
+
const [agentMode, setAgentMode] = useState8("manual-review");
|
|
4619
|
+
const [theme, setTheme] = useState8("dark");
|
|
4620
|
+
const [config, setConfig] = useState8(null);
|
|
4621
|
+
const [cursorToEnd, setCursorToEnd] = useState8(0);
|
|
4622
|
+
const [messageRenderVersion, setMessageRenderVersion] = useState8(0);
|
|
4623
|
+
const [screen, setScreen] = useState8("main");
|
|
4624
|
+
const [resumeSessions, setResumeSessions] = useState8([]);
|
|
4625
|
+
const [ctrlCPending, setCtrlCPending] = useState8(false);
|
|
4626
|
+
const [sessionId, setSessionId] = useState8(() => crypto.randomUUID());
|
|
4488
4627
|
const deferredPendingUpdates = useDeferredValue(pendingUpdates);
|
|
4489
4628
|
const visiblePendingUpdates = deferredPendingUpdates.length > 0 ? deferredPendingUpdates : pendingUpdates;
|
|
4629
|
+
const terminalVisible = useTerminalVisibility();
|
|
4490
4630
|
const activityFrame = useAnimatedFrame(busy);
|
|
4491
4631
|
const terminalWidth = useTerminalWidth();
|
|
4492
4632
|
const contentWidth = insetWidth(terminalWidth, 2);
|
|
4493
4633
|
const panelInnerWidth = insetWidth(contentWidth, 4);
|
|
4494
4634
|
const panelBodyWidth = insetWidth(panelInnerWidth, 2);
|
|
4495
|
-
const [agentQuestion, setAgentQuestion] =
|
|
4635
|
+
const [agentQuestion, setAgentQuestion] = useState8(null);
|
|
4496
4636
|
const previewRef = useRef2(null);
|
|
4497
4637
|
const ctrlCTimerRef = useRef2(null);
|
|
4638
|
+
const terminalVisibleRef = useRef2(terminalVisible);
|
|
4639
|
+
const previousTerminalVisibleRef = useRef2(terminalVisible);
|
|
4640
|
+
const streamBufferRef = useRef2(null);
|
|
4498
4641
|
const isHome = messages.length === 0 && !busy;
|
|
4499
4642
|
const { staticMessages, dynamicMessages } = useMemo4(
|
|
4500
4643
|
() => splitMessagesForRender(messages, busy),
|
|
@@ -4514,18 +4657,12 @@ function App({
|
|
|
4514
4657
|
[activeToolActivities]
|
|
4515
4658
|
);
|
|
4516
4659
|
const currentToolActivity = useMemo4(() => {
|
|
4517
|
-
if (activeToolDescriptions.length === 0)
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
if (activeToolDescriptions.length === 1 && turnToolCount === 0) {
|
|
4521
|
-
return activeToolDescriptions[0] ?? "";
|
|
4522
|
-
}
|
|
4523
|
-
if (activeToolDescriptions.length === 1) {
|
|
4524
|
-
return "Running 1 tool";
|
|
4525
|
-
}
|
|
4660
|
+
if (activeToolDescriptions.length === 0) return "";
|
|
4661
|
+
if (activeToolDescriptions.length === 1) return activeToolDescriptions[0] ?? "";
|
|
4662
|
+
if (activeToolDescriptions.length === 2) return activeToolDescriptions.join(" \xB7 ");
|
|
4526
4663
|
return `Running ${activeToolDescriptions.length} tools in parallel`;
|
|
4527
|
-
}, [activeToolDescriptions
|
|
4528
|
-
|
|
4664
|
+
}, [activeToolDescriptions]);
|
|
4665
|
+
useEffect5(() => {
|
|
4529
4666
|
if (!busy) {
|
|
4530
4667
|
setLatchedToolActivity("");
|
|
4531
4668
|
setLatchedToolCount(0);
|
|
@@ -4543,7 +4680,7 @@ function App({
|
|
|
4543
4680
|
);
|
|
4544
4681
|
const hasWorkspace = workspacePath !== null;
|
|
4545
4682
|
const hasAuth = authStatus === "connected";
|
|
4546
|
-
|
|
4683
|
+
useEffect5(() => {
|
|
4547
4684
|
if (!busy) {
|
|
4548
4685
|
setAgentQuestion(null);
|
|
4549
4686
|
return;
|
|
@@ -4557,7 +4694,7 @@ function App({
|
|
|
4557
4694
|
}, 200);
|
|
4558
4695
|
return () => clearInterval(interval);
|
|
4559
4696
|
}, [busy, agentQuestion]);
|
|
4560
|
-
|
|
4697
|
+
useEffect5(() => {
|
|
4561
4698
|
void (async () => {
|
|
4562
4699
|
const [cfg, storedOrDiskProviderConfigured] = await Promise.all([
|
|
4563
4700
|
ensureOpenResearchConfig({ homeDir }),
|
|
@@ -4574,7 +4711,7 @@ function App({
|
|
|
4574
4711
|
});
|
|
4575
4712
|
})();
|
|
4576
4713
|
}, [homeDir]);
|
|
4577
|
-
|
|
4714
|
+
useEffect5(() => {
|
|
4578
4715
|
if (!workspacePath) return;
|
|
4579
4716
|
let cancelled = false;
|
|
4580
4717
|
void scanWorkspace(workspacePath).then((result) => {
|
|
@@ -4590,7 +4727,7 @@ function App({
|
|
|
4590
4727
|
cancelled = true;
|
|
4591
4728
|
};
|
|
4592
4729
|
}, [workspacePath, sessionId]);
|
|
4593
|
-
|
|
4730
|
+
useEffect5(() => {
|
|
4594
4731
|
let cancelled = false;
|
|
4595
4732
|
void listAvailableSkills({ homeDir }).then((available) => {
|
|
4596
4733
|
if (cancelled) return;
|
|
@@ -4602,14 +4739,24 @@ function App({
|
|
|
4602
4739
|
cancelled = true;
|
|
4603
4740
|
};
|
|
4604
4741
|
}, [homeDir]);
|
|
4605
|
-
|
|
4742
|
+
useEffect5(() => {
|
|
4606
4743
|
return () => {
|
|
4607
4744
|
if (ctrlCTimerRef.current) {
|
|
4608
4745
|
clearTimeout(ctrlCTimerRef.current);
|
|
4609
4746
|
}
|
|
4610
4747
|
};
|
|
4611
4748
|
}, []);
|
|
4612
|
-
|
|
4749
|
+
useEffect5(() => {
|
|
4750
|
+
terminalVisibleRef.current = terminalVisible;
|
|
4751
|
+
if (terminalVisible) {
|
|
4752
|
+
streamBufferRef.current?.flush();
|
|
4753
|
+
}
|
|
4754
|
+
if (terminalVisible && !previousTerminalVisibleRef.current) {
|
|
4755
|
+
setMessageRenderVersion((current) => current + 1);
|
|
4756
|
+
}
|
|
4757
|
+
previousTerminalVisibleRef.current = terminalVisible;
|
|
4758
|
+
}, [terminalVisible]);
|
|
4759
|
+
const [selectedSuggestion, setSelectedSuggestion] = useState8(-1);
|
|
4613
4760
|
const atMention = useMemo4(() => extractAtMention(input2), [input2]);
|
|
4614
4761
|
const slashTrigger = useMemo4(() => extractSlashTrigger(input2), [input2]);
|
|
4615
4762
|
const suggestions = useMemo4(() => {
|
|
@@ -4619,7 +4766,7 @@ function App({
|
|
|
4619
4766
|
if (!slashTrigger) return [];
|
|
4620
4767
|
return getUnifiedSuggestions(`/${slashTrigger.partial}`, skills2);
|
|
4621
4768
|
}, [input2, skills2, atMention, slashTrigger, workspaceFiles]);
|
|
4622
|
-
|
|
4769
|
+
useEffect5(() => {
|
|
4623
4770
|
setSelectedSuggestion(-1);
|
|
4624
4771
|
}, [suggestions.length, input2]);
|
|
4625
4772
|
const dropdownVisible = suggestions.length > 0 && input2.length > 0;
|
|
@@ -4911,8 +5058,10 @@ function App({
|
|
|
4911
5058
|
streamBuffer = createSentenceStreamBuffer({
|
|
4912
5059
|
onFlush: (text) => {
|
|
4913
5060
|
addAssistantMessage(text);
|
|
4914
|
-
}
|
|
5061
|
+
},
|
|
5062
|
+
isVisible: () => terminalVisibleRef.current
|
|
4915
5063
|
});
|
|
5064
|
+
streamBufferRef.current = streamBuffer;
|
|
4916
5065
|
const result = await runAgentTurn({
|
|
4917
5066
|
provider,
|
|
4918
5067
|
message,
|
|
@@ -4949,6 +5098,10 @@ function App({
|
|
|
4949
5098
|
durationMs: activity.durationMs
|
|
4950
5099
|
});
|
|
4951
5100
|
setTurnToolCount(turnToolLogRef.current.length);
|
|
5101
|
+
if (activity.name === "write_new_file" || activity.name === "update_existing_file") {
|
|
5102
|
+
const verb = activity.name === "write_new_file" ? "Created" : "Updated";
|
|
5103
|
+
addSystemMessage(` \u25CA ${verb}: ${activity.description ?? activity.name}`);
|
|
5104
|
+
}
|
|
4952
5105
|
}
|
|
4953
5106
|
},
|
|
4954
5107
|
onSubAgentProgress: (progress) => {
|
|
@@ -5055,6 +5208,7 @@ ${error.stack}` : String(error)}` }
|
|
|
5055
5208
|
}
|
|
5056
5209
|
} finally {
|
|
5057
5210
|
streamBuffer?.dispose();
|
|
5211
|
+
streamBufferRef.current = null;
|
|
5058
5212
|
abortRef.current = null;
|
|
5059
5213
|
setActiveToolActivities({});
|
|
5060
5214
|
setSubAgentProgress({});
|
|
@@ -5164,7 +5318,25 @@ ${error.stack}` : String(error)}` }
|
|
|
5164
5318
|
`conversation-static-${messageRenderVersion}`
|
|
5165
5319
|
),
|
|
5166
5320
|
dynamicRenderItems.length > 0 && /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 1, width: contentWidth, children: dynamicRenderItems }),
|
|
5167
|
-
showThinking && /* @__PURE__ */ jsx6(ThinkingIndicator, { frame: activityFrame, width: contentWidth }),
|
|
5321
|
+
showThinking && /* @__PURE__ */ jsx6(ThinkingIndicator, { frame: activityFrame, width: contentWidth, currentTask: getCurrentTask() ?? void 0 }),
|
|
5322
|
+
busy && turnToolLogRef.current.length > 0 && /* @__PURE__ */ jsx6(
|
|
5323
|
+
ActivityFeed,
|
|
5324
|
+
{
|
|
5325
|
+
frame: activityFrame,
|
|
5326
|
+
width: contentWidth,
|
|
5327
|
+
items: [
|
|
5328
|
+
...turnToolLogRef.current.map((t) => ({
|
|
5329
|
+
description: t.description,
|
|
5330
|
+
status: "done",
|
|
5331
|
+
durationMs: t.durationMs
|
|
5332
|
+
})),
|
|
5333
|
+
...Object.values(activeToolActivities).map((desc) => ({
|
|
5334
|
+
description: desc,
|
|
5335
|
+
status: "active"
|
|
5336
|
+
}))
|
|
5337
|
+
]
|
|
5338
|
+
}
|
|
5339
|
+
),
|
|
5168
5340
|
visibleSubAgents.map((progress) => /* @__PURE__ */ jsx6(
|
|
5169
5341
|
SubAgentIndicator,
|
|
5170
5342
|
{
|
|
@@ -5172,6 +5344,7 @@ ${error.stack}` : String(error)}` }
|
|
|
5172
5344
|
goal: progress.goal,
|
|
5173
5345
|
currentTool: progress.currentTool,
|
|
5174
5346
|
toolCount: progress.toolCount,
|
|
5347
|
+
recentTools: progress.recentTools,
|
|
5175
5348
|
frame: activityFrame,
|
|
5176
5349
|
width: contentWidth
|
|
5177
5350
|
},
|
|
@@ -5413,7 +5586,7 @@ source.command("add-url").argument("<url>").description("Fetch and add a URL sou
|
|
|
5413
5586
|
});
|
|
5414
5587
|
program.command("serve").description("Start the Open Research API server (headless mode).").option("-p, --port <port>", "Port to listen on", "3210").action(async (opts) => {
|
|
5415
5588
|
const { serve } = await import("@hono/node-server");
|
|
5416
|
-
const { createApp } = await import("./server-
|
|
5589
|
+
const { createApp } = await import("./server-7CSQEGRQ.js");
|
|
5417
5590
|
const port = parseInt(opts.port, 10);
|
|
5418
5591
|
const { app } = createApp();
|
|
5419
5592
|
console.log(`Open Research server listening on http://localhost:${port}`);
|
package/dist/server/serve.js
CHANGED
package/package.json
CHANGED