psyclaw 0.29.16 → 0.29.18
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/README.md +7 -4
- package/dist/apps/panel/index.html +42 -0
- package/dist/apps/panel/observability.js +87 -0
- package/dist/src/adapters/pi/extension.js +28 -1
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/chat.js +2 -0
- package/dist/src/chat.js.map +1 -1
- package/dist/src/cli.js +63 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/observability/config.d.ts +47 -0
- package/dist/src/observability/config.js +125 -0
- package/dist/src/observability/config.js.map +1 -0
- package/dist/src/observability/index.d.ts +29 -0
- package/dist/src/observability/index.js +75 -0
- package/dist/src/observability/index.js.map +1 -0
- package/dist/src/observability/node-sdks.d.ts +11 -0
- package/dist/src/observability/node-sdks.js +92 -0
- package/dist/src/observability/node-sdks.js.map +1 -0
- package/dist/src/observability/notice.d.ts +9 -0
- package/dist/src/observability/notice.js +43 -0
- package/dist/src/observability/notice.js.map +1 -0
- package/dist/src/observability/preference.d.ts +23 -0
- package/dist/src/observability/preference.js +102 -0
- package/dist/src/observability/preference.js.map +1 -0
- package/dist/src/observability/public-keys.d.ts +10 -0
- package/dist/src/observability/public-keys.js +11 -0
- package/dist/src/observability/public-keys.js.map +1 -0
- package/dist/src/orchestration/runner.js +21 -2
- package/dist/src/orchestration/runner.js.map +1 -1
- package/dist/src/panel/server.d.ts +2 -0
- package/dist/src/panel/server.js +68 -1
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/style/cli-ui.js +2 -0
- package/dist/src/style/cli-ui.js.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ PsyClaw 是面向社会科学研究的智能体工作台。它把研究项目、
|
|
|
4
4
|
|
|
5
5
|
PsyClaw 自有代码使用 MIT 许可证;随 npm 包内置的 Academic Research Skills 位于 `vendor/ars`,保持上游署名并单独遵循 CC BY-NC 4.0,仅限非商业用途。
|
|
6
6
|
|
|
7
|
-
当前版本:`0.29.
|
|
7
|
+
当前版本:`0.29.18`。正式命令、用户配置目录和后续发布统一使用 `psyclaw`。
|
|
8
8
|
|
|
9
9
|
## 发布流程
|
|
10
10
|
|
|
@@ -21,19 +21,19 @@ RELEASE_MESSAGE="release: describe the change" pnpm release:push
|
|
|
21
21
|
需要 Node.js `>=22.19.0`。官方 npm 源:
|
|
22
22
|
|
|
23
23
|
```powershell
|
|
24
|
-
npm install -g psyclaw@0.29.
|
|
24
|
+
npm install -g psyclaw@0.29.18
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
如果本机 npm 配置把 registry 误写成带有 `~/` 的地址,请显式指定官方源:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npm install -g psyclaw@0.29.
|
|
30
|
+
npm install -g psyclaw@0.29.18 --registry=https://registry.npmjs.org/
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
中国大陆网络较慢或无法访问官方源时:
|
|
34
34
|
|
|
35
35
|
```powershell
|
|
36
|
-
npm install -g psyclaw@0.29.
|
|
36
|
+
npm install -g psyclaw@0.29.18 --registry=https://registry.npmmirror.com
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
或安装脚本:
|
|
@@ -97,6 +97,7 @@ psyclaw evidence add notes\source.md --level user
|
|
|
97
97
|
| 查看 PsyClaw 和内置运行时更新 | `psyclaw check-updates` |
|
|
98
98
|
| 更新 PsyClaw 和内置运行时 | `psyclaw update` |
|
|
99
99
|
| 导出会话 | 使用 Pi 内置的 `/export` |
|
|
100
|
+
| 匿名产品遥测 | `psyclaw telemetry status`、`psyclaw telemetry off`、`psyclaw telemetry on`(默认开启;对话中 `/telemetry`) |
|
|
100
101
|
| 打开科研面板 | 在对话中输入 `/panel` |
|
|
101
102
|
| 查看或切换 Provider | 在对话中输入 `/provider` 或 `/provider <id>` |
|
|
102
103
|
| 管理启动横幅宠物 | `/pet`、`/pet on`、`/pet off`(默认关闭) |
|
|
@@ -178,6 +179,7 @@ node -e 'const fs=require("node:fs"),os=require("node:os"),path=require("node:pa
|
|
|
178
179
|
- [评测框架](docs/评测框架.md)
|
|
179
180
|
- [PsyClaw ARS 模式与保护边界](docs/PsyClaw-ARS模式.md)
|
|
180
181
|
- [文档与交付物规范](docs/文档规范.md)
|
|
182
|
+
- [遥测(匿名产品遥测,默认开启,可关闭)](docs/telemetry.md)
|
|
181
183
|
|
|
182
184
|
## 边界
|
|
183
185
|
|
|
@@ -185,5 +187,6 @@ node -e 'const fs=require("node:fs"),os=require("node:os"),path=require("node:pa
|
|
|
185
187
|
- 统计计算委托 Python/R、SPSS/Stata/Mplus 或受信任 MCP;输出必须保存脚本、输入指纹和环境信息。
|
|
186
188
|
- Skill、Plugin 和 MCP 默认只发现、不执行;启用前需要来源、版本/ref、哈希、许可证和依赖状态。
|
|
187
189
|
- 没有可定位证据的事实性 Claim 必须是 `uncertain` 或被阻断;没有审批记录的副作用不能被当作完成。
|
|
190
|
+
- 遥测默认开启(匿名产品使用与错误,不含研究正文)。首次启动会说明如何关闭:`psyclaw telemetry off`。详见 [docs/telemetry.md](docs/telemetry.md)。
|
|
188
191
|
|
|
189
192
|
许可证:MIT。
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
6
|
<title>PsyClaw Panel · 科研工作台</title>
|
|
7
|
+
<script id="psyclaw-obs-config">window.__PSYCLAW_OBS__={"surface":"panel","sentryDsn":"","posthogKey":"","posthogHost":"","release":""};</script>
|
|
8
|
+
<script src="/observability.js" defer></script>
|
|
7
9
|
<style>
|
|
8
10
|
:root {
|
|
9
11
|
color-scheme: light;
|
|
@@ -1090,6 +1092,26 @@
|
|
|
1090
1092
|
text-align: center;
|
|
1091
1093
|
}
|
|
1092
1094
|
.hidden { display: none !important; }
|
|
1095
|
+
.telemetry-notice {
|
|
1096
|
+
display: flex;
|
|
1097
|
+
align-items: flex-start;
|
|
1098
|
+
justify-content: space-between;
|
|
1099
|
+
gap: 16px;
|
|
1100
|
+
padding: 10px 20px;
|
|
1101
|
+
background: var(--brand-primary-light);
|
|
1102
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
1103
|
+
font-size: 13px;
|
|
1104
|
+
color: var(--text-main);
|
|
1105
|
+
}
|
|
1106
|
+
.telemetry-notice.hidden { display: none !important; }
|
|
1107
|
+
.telemetry-notice p {
|
|
1108
|
+
margin: 0;
|
|
1109
|
+
color: var(--text-muted);
|
|
1110
|
+
max-width: 72ch;
|
|
1111
|
+
line-height: 1.5;
|
|
1112
|
+
}
|
|
1113
|
+
.telemetry-notice strong { color: var(--text-main); }
|
|
1114
|
+
.telemetry-notice .toolbar { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
|
|
1093
1115
|
|
|
1094
1116
|
/* Pipeline Stepper */
|
|
1095
1117
|
.pipeline-stepper {
|
|
@@ -1838,6 +1860,10 @@
|
|
|
1838
1860
|
</div>
|
|
1839
1861
|
</div>
|
|
1840
1862
|
</header>
|
|
1863
|
+
<div id="telemetry-notice" class="telemetry-notice hidden" role="status">
|
|
1864
|
+
<p><strong>匿名产品遥测默认开启。</strong> 用于改进 PsyClaw 的粗粒度使用与错误信息;不含研究正文、论文或个人身份。可随时关闭。</p>
|
|
1865
|
+
<div class="toolbar"><button type="button" class="button" id="telemetry-ack">知道了</button><button type="button" class="button" id="telemetry-off">关闭遥测</button></div>
|
|
1866
|
+
</div>
|
|
1841
1867
|
|
|
1842
1868
|
<!-- 主体工作区 Layout -->
|
|
1843
1869
|
<div class="layout nav-collapsed">
|
|
@@ -3404,6 +3430,22 @@ loadProject().catch(error => {
|
|
|
3404
3430
|
});
|
|
3405
3431
|
loadProjectStatus();
|
|
3406
3432
|
|
|
3433
|
+
(function initTelemetryNotice(){
|
|
3434
|
+
const obs = window.__PSYCLAW_OBS__ || {};
|
|
3435
|
+
const banner = $("telemetry-notice");
|
|
3436
|
+
if (!banner) return;
|
|
3437
|
+
if (obs.showTelemetryNotice) banner.classList.remove("hidden");
|
|
3438
|
+
$("telemetry-ack")?.addEventListener("click", async () => {
|
|
3439
|
+
try { await json("/api/telemetry", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "ack" }) }); } catch {}
|
|
3440
|
+
banner.classList.add("hidden");
|
|
3441
|
+
});
|
|
3442
|
+
$("telemetry-off")?.addEventListener("click", async () => {
|
|
3443
|
+
try { await json("/api/telemetry", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "disable" }) }); } catch {}
|
|
3444
|
+
banner.classList.add("hidden");
|
|
3445
|
+
location.reload();
|
|
3446
|
+
});
|
|
3447
|
+
})();
|
|
3448
|
+
|
|
3407
3449
|
const initialView = decodeURIComponent((location.hash || "").replace(/^#/, "").trim());
|
|
3408
3450
|
const knownViews = new Set(["project", "ecosystem", "provider", "checklist", "chat", "help"]);
|
|
3409
3451
|
if (knownViews.has(initialView)) setView(initialView);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in browser observability for PsyClaw panel + website.
|
|
3
|
+
*
|
|
4
|
+
* Loads Sentry / PostHog from a CDN only when a DSN or project key is present
|
|
5
|
+
* on window.__PSYCLAW_OBS__, a meta tag, or (local debug) a query param.
|
|
6
|
+
* With those empty, this file is a no-op: no network calls, no SDK init.
|
|
7
|
+
*/
|
|
8
|
+
(function psyclawObservability() {
|
|
9
|
+
if (window.__PSYCLAW_OBS_BOOTED__) return;
|
|
10
|
+
window.__PSYCLAW_OBS_BOOTED__ = true;
|
|
11
|
+
|
|
12
|
+
function meta(name) {
|
|
13
|
+
const node = document.querySelector('meta[name="' + name + '"]');
|
|
14
|
+
const value = node && node.getAttribute("content");
|
|
15
|
+
return value ? String(value).trim() : "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function param(name) {
|
|
19
|
+
try {
|
|
20
|
+
return new URLSearchParams(location.search).get(name) || "";
|
|
21
|
+
} catch {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readConfig() {
|
|
27
|
+
const fromWindow = window.__PSYCLAW_OBS__ || {};
|
|
28
|
+
const sentryDsn = String(fromWindow.sentryDsn || meta("psyclaw-sentry-dsn") || param("sentryDsn") || "").trim();
|
|
29
|
+
const posthogKey = String(fromWindow.posthogKey || meta("psyclaw-posthog-key") || param("posthogKey") || "").trim();
|
|
30
|
+
const posthogHost = String(
|
|
31
|
+
fromWindow.posthogHost || meta("psyclaw-posthog-host") || param("posthogHost") || "https://us.posthog.com",
|
|
32
|
+
).trim();
|
|
33
|
+
const surface = fromWindow.surface === "panel" || fromWindow.surface === "website" ? fromWindow.surface : "web";
|
|
34
|
+
const release = String(fromWindow.release || "").trim();
|
|
35
|
+
return { sentryDsn, posthogKey, posthogHost, surface, release };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function loadEsm(url) {
|
|
39
|
+
return import(url);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function bootSentry(config) {
|
|
43
|
+
const Sentry = await loadEsm("https://cdn.jsdelivr.net/npm/@sentry/browser@10/+esm");
|
|
44
|
+
Sentry.init({
|
|
45
|
+
dsn: config.sentryDsn,
|
|
46
|
+
release: config.release || undefined,
|
|
47
|
+
environment: "local",
|
|
48
|
+
tracesSampleRate: 1.0,
|
|
49
|
+
sendDefaultPii: false,
|
|
50
|
+
integrations: typeof Sentry.browserTracingIntegration === "function" ? [Sentry.browserTracingIntegration()] : [],
|
|
51
|
+
});
|
|
52
|
+
window.Sentry = Sentry;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function bootPostHog(config) {
|
|
56
|
+
const mod = await loadEsm("https://cdn.jsdelivr.net/npm/posthog-js@1/+esm");
|
|
57
|
+
const posthog = mod.default || mod.posthog || mod;
|
|
58
|
+
const panel = config.surface === "panel";
|
|
59
|
+
posthog.init(config.posthogKey, {
|
|
60
|
+
api_host: config.posthogHost,
|
|
61
|
+
person_profiles: "identified_only",
|
|
62
|
+
autocapture: true,
|
|
63
|
+
capture_pageview: true,
|
|
64
|
+
capture_pageleave: true,
|
|
65
|
+
persistence: "memory",
|
|
66
|
+
mask_all_text: panel,
|
|
67
|
+
mask_all_element_attributes: panel,
|
|
68
|
+
session_recording: {
|
|
69
|
+
maskAllInputs: true,
|
|
70
|
+
maskTextSelector: panel
|
|
71
|
+
? ".markdown, .raw, .viewer-body, .event-detail, pre, code, textarea, [data-file]"
|
|
72
|
+
: undefined,
|
|
73
|
+
},
|
|
74
|
+
loaded: function (client) {
|
|
75
|
+
client.register({ surface: config.surface, app: "psyclaw" });
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
window.posthog = posthog;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const config = readConfig();
|
|
82
|
+
const jobs = [];
|
|
83
|
+
if (config.sentryDsn) jobs.push(bootSentry(config).catch(function () {}));
|
|
84
|
+
if (config.posthogKey) jobs.push(bootPostHog(config).catch(function () {}));
|
|
85
|
+
if (jobs.length === 0) return;
|
|
86
|
+
Promise.all(jobs).catch(function () {});
|
|
87
|
+
})();
|
|
@@ -35,6 +35,7 @@ import { continuouslyWorkWarningText, isContinuouslyWorkEnabled, } from "../../s
|
|
|
35
35
|
import { assertHumanVerifyGate, formatVerifyChecklist, isNaturalPlanConfirm, ensureDefaultVerifyChecklist, loadVerifyChecklist } from "../../verify/checklist.js";
|
|
36
36
|
import { formatSessionHelp, formatSessionHelpBrief } from "../../session/help.js";
|
|
37
37
|
import { openResearchWorkbench } from "../../panel/workbench.js";
|
|
38
|
+
import { captureAgentError, initNodeObservability, readTelemetryPreference, shutdownObservability, trackGateWaiting, writeTelemetryPreference, } from "../../observability/index.js";
|
|
38
39
|
/** Codex-style slash surface: bare command, or command + trailing free text. No subcommand trees. */
|
|
39
40
|
function parseInitArgs(args) {
|
|
40
41
|
const goal = args.trim();
|
|
@@ -43,6 +44,7 @@ function parseInitArgs(args) {
|
|
|
43
44
|
return { paradigm: "survey-observational", goal };
|
|
44
45
|
}
|
|
45
46
|
async function notifyError(ctx, error) {
|
|
47
|
+
await captureAgentError(error, { phase: "extension" });
|
|
46
48
|
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
47
49
|
}
|
|
48
50
|
const activeAgentRuns = new Set();
|
|
@@ -887,6 +889,7 @@ const WORKFLOW_RUNNERS = {
|
|
|
887
889
|
"expert-review": runExpertReview,
|
|
888
890
|
};
|
|
889
891
|
export default function psyclawExtension(pi) {
|
|
892
|
+
void initNodeObservability();
|
|
890
893
|
const developerCommands = process.env.PSYCLAW_DEVELOPER_COMMANDS === "1";
|
|
891
894
|
const legacyTestApi = typeof pi.registerTool !== "function";
|
|
892
895
|
const runtimeMcps = new RuntimeMcpRegistry();
|
|
@@ -936,7 +939,10 @@ export default function psyclawExtension(pi) {
|
|
|
936
939
|
};
|
|
937
940
|
});
|
|
938
941
|
if (!legacyTestApi && typeof pi.on === "function")
|
|
939
|
-
pi.on("session_shutdown", () =>
|
|
942
|
+
pi.on("session_shutdown", () => {
|
|
943
|
+
runtimeMcps.close();
|
|
944
|
+
void shutdownObservability();
|
|
945
|
+
});
|
|
940
946
|
if (!legacyTestApi && typeof pi.on === "function")
|
|
941
947
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
942
948
|
if (!(await readActiveProject(ctx?.cwd ?? process.cwd())))
|
|
@@ -1094,6 +1100,7 @@ export default function psyclawExtension(pi) {
|
|
|
1094
1100
|
if (requiresSeparateOperationConfirmation(event.toolName, event.input)) {
|
|
1095
1101
|
if (!ctx.hasUI)
|
|
1096
1102
|
return { block: true, terminate: true, reason: "外部发布需要用户在交互界面中明确确认" };
|
|
1103
|
+
void trackGateWaiting("tool_approval");
|
|
1097
1104
|
const choice = await ctx.ui.select(`确认外部操作\n${summary}`, ["确认执行", "取消"], { timeout: 120_000 });
|
|
1098
1105
|
const approved = choice === "确认执行";
|
|
1099
1106
|
await appendApproval(ctx.cwd, {
|
|
@@ -1607,6 +1614,26 @@ export default function psyclawExtension(pi) {
|
|
|
1607
1614
|
ctx.ui.notify(`启动横幅宠物已${action === "on" ? "开启" : "关闭"},下次启动生效`, "info");
|
|
1608
1615
|
},
|
|
1609
1616
|
});
|
|
1617
|
+
if (!legacyTestApi)
|
|
1618
|
+
pi.registerCommand("telemetry", {
|
|
1619
|
+
description: "查看或关闭匿名产品遥测",
|
|
1620
|
+
handler: async (args, ctx) => {
|
|
1621
|
+
const action = args.trim().toLowerCase() || "status";
|
|
1622
|
+
if (action === "status") {
|
|
1623
|
+
const preference = await readTelemetryPreference();
|
|
1624
|
+
ctx.ui.notify(preference.enabled
|
|
1625
|
+
? "匿名产品遥测:开启(默认)。采集粗粒度使用与错误,不含研究正文。关闭:/telemetry off"
|
|
1626
|
+
: "匿名产品遥测:已关闭。重新开启:/telemetry on", "info");
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
if (action !== "on" && action !== "off") {
|
|
1630
|
+
ctx.ui.notify("Usage: /telemetry on|off|status", "error");
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
await writeTelemetryPreference({ enabled: action === "on", noticeAcknowledged: true });
|
|
1634
|
+
ctx.ui.notify(action === "on" ? "已开启匿名产品遥测。下次启动生效。" : "已关闭匿名产品遥测。下次启动不再发送。", "info");
|
|
1635
|
+
},
|
|
1636
|
+
});
|
|
1610
1637
|
if (typeof pi.registerTool === "function") {
|
|
1611
1638
|
pi.registerTool({
|
|
1612
1639
|
name: "psyclaw_research_decision",
|