Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {resolveTestPython} from "../../../../scripts/test-python.mjs";
import {readAnalysisSnapshot, ResearchAnalysisPanel} from "../src/features/personal-workspace/goal-research-analysis.tsx";
import {ResearchCaseStudy} from "../src/features/personal-workspace/research-case-study.tsx";
import {fetchExploreResults} from "../src/data/chat.ts";
import {ResearchGoalNavigation} from "../src/features/personal-workspace/goal-research-workbench.tsx";
import {GoalResearchWorkbench} from "../src/features/personal-workspace/goal-research-workbench.tsx";

// The persisted directory can organize explicitly linked physical sources.
// Navigation must not turn organization into shared evidence or execution.
Expand All @@ -30,8 +30,9 @@ const goals = [
{goalId:'child',parentGoalId:'parent',title:'Local case'},
{goalId:'foreign',parentGoalId:'parent',title:'Foreign case',sourceAccess:{namespace:'other',label:'Other',readOnly:true}},
];
const navigate = goalId => renderToStaticMarkup(createElement(ResearchGoalNavigation, {
goalId, goals, zh:false, onSelect: () => {throw Error('read navigated');},
const navigate = goalId => renderToStaticMarkup(createElement(GoalResearchWorkbench, {
goalId, goals, zh: false, active: true, refreshRevision: 0,
statusNotice: createElement("p", null, "Loading status"), onSelectGoal: () => {throw Error('read navigated');},
}));
assert.ok(navigate('parent').includes('Local case'));
assert.ok(navigate('parent').includes('Foreign case'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,8 @@ export function ResearchAnalysisPanel({analysis: a, onHistory}: {analysis: Contr
: benefit?.unknown ? (zh ? "原目标收益的检验情况仍未知" : "Original-objective utility testing remains unknown")
: benefit?.yes ? (zh ? "模型记录了收益检验;这不等于收益为正" : "The model identified a utility test; this does not imply positive utility")
: (zh ? "此方法未覆盖原目标收益检验" : "This method does not cover original-objective utility testing");
const scope = p ? <>{p.episode_count} {zh ? "个研究片段" : "research episodes"} · {p.selection.exhaustive ? (zh ? "固定范围" : "Fixed scope") : (zh ? "定向抽样" : "Purposive sample")}</> : null;
const episodeLabel = result ? (zh ? "个研究片段" : "research episodes") : (zh ? "个输入片段" : "input episodes");
const scope = p ? <>{p.episode_count} {episodeLabel} · {p.selection.exhaustive ? (zh ? "固定范围" : "Fixed scope") : (zh ? "定向抽样" : "Purposive sample")}</> : null;
const scopeHelp = p ? <ContextHelp label={zh ? "分析范围" : "Analysis scope"} icon={result?.synthesis ? Sparkles : undefined}>
{result?.synthesis ? <p><strong>{zh ? "Agent 分析 · 未校准" : "Agent analysis · uncalibrated"}</strong></p> : null}
<p>{p.selection.exhaustive ? (zh ? "覆盖此固定分析范围;不等于覆盖全部研究。" : "Covers this fixed analysis scope, not necessarily the whole research history.") : (zh ? "定向抽样,仅分析选定研究片段;范围外或未捕获的工作未纳入,不代表全程。" : "Purposive sample of selected episodes; work outside this scope or not captured is excluded. It does not represent the whole run.")}</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,19 +281,27 @@ export function ResearchProgress({pack: p, packs, selectedId, zh, onSelect, onCi
const incomplete = usage?.incomplete_turn;
const coverage = usage?.request_coverage;
const number = (n: number) => new Intl.NumberFormat(zh ? "zh-CN" : "en", {maximumFractionDigits: 1}).format(n);
const scope = p ? `${number(p.episode_count)} ${zh ? "个片段" : "episodes"} · ${p.selection.exhaustive ? (zh ? "固定范围" : "Fixed scope") : (zh ? "定向抽样" : "Purposive sample")}` : "";
const duration = (s: number) => `${number(s / 60)} ${zh ? "分钟" : "min"}`;
const stamp = (s: string) => new Intl.DateTimeFormat(zh ? "zh-CN" : "en", {timeZone: "UTC", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false}).format(new Date(s));
return <section className="research-progress" aria-label={zh ? "长程效果与用量" : "Long-horizon results and usage"}>
<header><div className="research-progress-heading"><div className="research-progress-title"><h3>{p?.native_outcomes ? (zh ? "研究结果" : "Research results") : (zh ? "研究效果判读" : "Research effectiveness")}</h3><ContextHelp label={resultHelp} icon={historical ? TriangleAlert : p && !result ? CircleHelp : undefined}>
{historical ? <p>{zh ? "来源或方法已变化;历史捕获与判读不能当作当前结果。" : "The source or method changed; historical captures and judgments cannot establish current results."}</p> : null}
{p && !result ? <p>{zh ? "可先浏览已采集的测量与记录;深度分析需单独点击,不会随浏览自动运行。" : "Captured measurements and records remain readable. Deep analysis requires a separate action and never runs while browsing."}</p> : null}
{p && !result ? <>
<p>{zh ? "分析输入" : "Analysis input"} · {scope}</p>
<p>{zh ? "可先浏览已采集的测量与记录;深度分析需单独点击,不会随浏览自动运行。" : "Captured measurements and records remain readable. Deep analysis requires a separate action and never runs while browsing."}</p>
</> : null}
{p ? <p>{p.title}</p> : null}
<p>{zh ? "分析器判读未校准,仅限所选片段;范围外或未捕获的工作未纳入。数字为“是 / 适用片段”,未知仍在分母中;点选指标可看依据。" : "Uncalibrated judgments of selected episodes only; work outside this scope or not captured is excluded. Counts are yes / eligible episodes, including unknowns. Select a metric for evidence."}</p>
<p>{zh ? "不适用来自原始片段的明确取样规则,不算“否”或“未知”;展开指标可看被排除的片段。" : "Ineligible episodes follow the source's explicit selection, not a no or unknown judgment. Expand a metric to identify them."}</p>
<p>{zh ? "收益检验的“是”不保证收益为正;无益重复的“是”表示发现问题。六项分别判断,不合成总分、成功率或原生收益。" : "Yes for benefit testing does not imply positive utility; yes for repetition identifies a problem. The six judgments are not a total score, success rate or native utility."}</p>
<p>{p?.selection.exhaustive ? (zh ? "仅覆盖声明的固定分析范围,不等于覆盖全部研究。" : "Covers the declared fixed analysis scope, not necessarily the whole study.") : p?.selection.population_episodes == null ? (zh ? "定向抽样,全程覆盖未知。" : "Purposive sample; whole-run coverage is unknown.") : (zh ? "定向抽样,不代表全程。" : "Purposive sample, not the whole run.")}</p>
<p>{zh ? "原生测量缺失时保持未采集;分析器判读不能补成实际收益。完整取样规则与版本在“来源与用量”中。" : "Missing native measurements remain uncaptured; judgments cannot supply realized utility. Full selection rules and revisions are under Sources and usage."}</p>
</ContextHelp></div>{p ? <p className="research-progress-scope" data-pack-id={p.pack_id}>{number(p.episode_count)} {zh ? "个片段" : "episodes"} · {p.selection.exhaustive ? (zh ? "固定范围" : "Fixed scope") : (zh ? "定向抽样" : "Purposive sample")}{result ? (zh ? " · 未校准" : " · Uncalibrated") : ""}</p> : null}</div>{packs.length > 1 ? <label>{zh ? "评估范围" : "Evaluation scope"}<select value={selectedId} onChange={e => onSelect(e.target.value)}>{packs.map(pack => <option key={pack.pack_id} value={pack.pack_id}>{pack.title}</option>)}</select></label> : null}</header>
{result ? <>
<p>{zh ? "分析器判读未校准,仅限所选片段;范围外或未捕获的工作未纳入。数字为“是 / 适用片段”,未知仍在分母中;点选指标可看依据。" : "Uncalibrated judgments of selected episodes only; work outside this scope or not captured is excluded. Counts are yes / eligible episodes, including unknowns. Select a metric for evidence."}</p>
<p>{zh ? "不适用来自原始片段的明确取样规则,不算“否”或“未知”;展开指标可看被排除的片段。" : "Ineligible episodes follow the source's explicit selection, not a no or unknown judgment. Expand a metric to identify them."}</p>
<p>{zh ? "收益检验的“是”不保证收益为正;无益重复的“是”表示发现问题。六项分别判断,不合成总分、成功率或原生收益。" : "Yes for benefit testing does not imply positive utility; yes for repetition identifies a problem. The six judgments are not a total score, success rate or native utility."}</p>
</> : null}
{p ? <>
<p>{p.selection.exhaustive ? (zh ? "仅覆盖声明的固定分析范围,不等于覆盖全部研究。" : "Covers the declared fixed analysis scope, not necessarily the whole study.") : p.selection.population_episodes == null ? (zh ? "定向抽样,全程覆盖未知。" : "Purposive sample; whole-run coverage is unknown.") : (zh ? "定向抽样,不代表全程。" : "Purposive sample, not the whole run.")}</p>
<p>{zh ? "原生测量缺失时保持未采集;分析器判读不能补成实际收益。完整取样规则与版本在“来源与用量”中。" : "Missing native measurements remain uncaptured; judgments cannot supply realized utility. Full selection rules and revisions are under Sources and usage."}</p>
</> : <p>{zh ? "当前没有可读的分析范围。" : "No analysis scope is available."}</p>}
</ContextHelp></div>{p ? <p className="research-progress-scope" data-pack-id={p.pack_id}>{result ? `${scope}${zh ? " · 未校准" : " · Uncalibrated"}` : (zh ? "尚无分析器判读" : "No analyzer judgments yet")}</p> : null}</div>{packs.length > 1 ? <label>{zh ? "评估范围" : "Evaluation scope"}<select value={selectedId} onChange={e => onSelect(e.target.value)}>{packs.map(pack => <option key={pack.pack_id} value={pack.pack_id}>{pack.title}</option>)}</select></label> : null}</header>
{p ? <>
{p.native_outcomes ? <NativeResults native={p.native_outcomes} zh={zh} onCitation={onCitation}/> : null}
{p.native_outcomes ? <RetainedImprovement native={p.native_outcomes} zh={zh} onCitation={onCitation}/> : null}
Expand Down
11 changes: 10 additions & 1 deletion examples/personal-workspace-browser/research-history.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,12 @@ export const researchHistoryScenario = {
assert.doesNotMatch(await native.locator('.research-native-scope').innerText(), /T00:00:00Z/);
assert.equal(await native.locator('.research-native-basis').evaluate(e => e.open), false);
assert.equal(await nativePage.locator('.research-progress-basis').evaluate(e => e.open), false);
assert.equal(await nativePage.getByRole('button',{name:'所选范围尚未分析',exact:true}).isVisible(), true, 'Measured progress remains readable before model analysis; the unknown analysis is contextual help');
const pendingScope = nativePage.locator('.research-progress-scope');
assert.equal(await pendingScope.innerText(), '尚无分析器判读', 'Prepared input counts cannot be mistaken for completed judgments');
const pendingHelp = nativePage.getByRole('button', {name: '所选范围尚未分析', exact: true});
await pendingHelp.focus();
assert.match(await nativePage.getByRole('tooltip').innerText(), /分析输入 · \d+ 个片段/);
await nativePage.keyboard.press('Escape');
assert.equal(await nativePage.locator('.research-progress > header .context-help-trigger').count(), 1, 'Result state and interpretation share one heading help entry');
await nativePage.screenshot({path: resolve(outputDir, 'research-native-default-desktop.png'), animations: 'disabled'});
await native.getByRole('button', {name: /首次提交.*查看原始证据/}).click();
Expand Down Expand Up @@ -1675,6 +1680,7 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
await progress.getByRole("combobox").focus();
await progress.getByRole("combobox").selectOption("c".repeat(64));
await progress.locator(`.research-progress-scope[data-pack-id="${"c".repeat(64)}"]`).waitFor();
assert.match(await progress.locator('.research-progress-scope').innerText(), /1 个片段 · .*未校准/, 'Stored judgments retain their visible coverage and calibration boundary');
assert.equal(await progress.locator('.research-progress-basis > summary').getByRole('button',{name:/完整成本未知/}).isVisible(),true,'The cost boundary remains discoverable with the details closed');
await progress.locator('.research-progress-basis > summary').click();
assert.match(await progress.locator('.research-usage-heading').first().innerText(), /未采集|Not captured/);
Expand Down Expand Up @@ -1713,6 +1719,7 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
assert(await unfinishedHelp.evaluate(element => element === document.activeElement));
await progress.locator('.research-progress-basis > summary').click();
assert.equal(await progress.getByRole('button',{name:'所选范围尚未分析',exact:true}).isVisible(),true);
assert.equal(await progress.locator('.research-progress-scope').innerText(), '尚无分析器判读');
assert.equal(await nativeResults.isVisible(), true, 'An unanalysed pack still exposes its recorded outcomes with cost details closed');
assert.equal(await progress.locator('.research-effect-metrics').count(), 0, 'An unanalysed cost pack never borrows another pack’s judgments');
assert.equal(await analysis.count(), 0, 'Choosing an unanalysed source never requests analysis');
Expand All @@ -1730,7 +1737,9 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
await analysis.getByRole('button', {name: '重试读取', exact: true}).click();
await analysis.getByRole('alert').waitFor({state: 'hidden'});
assert(await analysis.getByRole('button', {name: '分析所选范围', exact: true}).isEnabled(), 'A successful owner read restores the existing explicit analysis action');
assert.match(await analysis.locator('.analysis-scope').innerText(), /\d+ 个输入片段/);
await analysis.press('Escape');
await analysis.waitFor({state: 'hidden'});
await basis.locator(':scope > summary').click();
assert.equal(await nativeResults.locator('[data-native-point="retained"] strong').textContent(), '3', 'Native facts do not require an analyzer result');
assert.match(await nativeResults.innerText(), /部分窗口 · 起点未知/);
Expand Down
Loading