@vextlabs/theron-cli 0.3.0 → 0.4.0
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/api.d.ts +8 -0
- package/dist/api.js +3 -0
- package/dist/api.js.map +1 -1
- package/dist/auth.js +51 -1
- package/dist/auth.js.map +1 -1
- package/dist/banner.js +3 -2
- package/dist/banner.js.map +1 -1
- package/dist/checkpoints.d.ts +32 -0
- package/dist/checkpoints.js +61 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/index.js +59 -4
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts +61 -0
- package/dist/input.js +574 -0
- package/dist/input.js.map +1 -0
- package/dist/profiles/index.js +5 -0
- package/dist/profiles/index.js.map +1 -1
- package/dist/profiles/methodologies/operate_domains.d.ts +8 -0
- package/dist/profiles/methodologies/operate_domains.js +1239 -0
- package/dist/profiles/methodologies/operate_domains.js.map +1 -0
- package/dist/profiles/seeds.js +57 -36
- package/dist/profiles/seeds.js.map +1 -1
- package/dist/receipt.d.ts +17 -0
- package/dist/receipt.js +46 -0
- package/dist/receipt.js.map +1 -0
- package/dist/render.d.ts +4 -1
- package/dist/render.js +95 -28
- package/dist/render.js.map +1 -1
- package/dist/repl.d.ts +8 -1
- package/dist/repl.js +420 -62
- package/dist/repl.js.map +1 -1
- package/dist/sessions.d.ts +14 -0
- package/dist/sessions.js +100 -0
- package/dist/sessions.js.map +1 -1
- package/dist/ship.d.ts +2 -0
- package/dist/ship.js +62 -0
- package/dist/ship.js.map +1 -0
- package/dist/skills/catalog.d.ts +13 -0
- package/dist/skills/catalog.js +86 -0
- package/dist/skills/catalog.js.map +1 -0
- package/dist/tools/bash.js +81 -14
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.js +21 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/glob.js +4 -1
- package/dist/tools/glob.js.map +1 -1
- package/dist/tools/grep.d.ts +5 -0
- package/dist/tools/grep.js +101 -2
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.js +177 -41
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/ls.d.ts +3 -0
- package/dist/tools/ls.js +23 -12
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/multiedit.d.ts +12 -0
- package/dist/tools/multiedit.js +79 -0
- package/dist/tools/multiedit.js.map +1 -0
- package/dist/tools/stoa.d.ts +1 -1
- package/dist/tools/stoa.js +7 -3
- package/dist/tools/stoa.js.map +1 -1
- package/dist/tools/task.d.ts +9 -0
- package/dist/tools/task.js +166 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/tools/todowrite.d.ts +12 -0
- package/dist/tools/todowrite.js +38 -0
- package/dist/tools/todowrite.js.map +1 -0
- package/dist/tools/webfetch.d.ts +6 -0
- package/dist/tools/webfetch.js +98 -0
- package/dist/tools/webfetch.js.map +1 -0
- package/dist/tools/websearch.d.ts +7 -0
- package/dist/tools/websearch.js +83 -0
- package/dist/tools/websearch.js.map +1 -0
- package/dist/tools/write.js +17 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/verifiers/confidence_marked.d.ts +2 -0
- package/dist/verifiers/confidence_marked.js +49 -0
- package/dist/verifiers/confidence_marked.js.map +1 -0
- package/dist/verifiers/disclaimer_gate.d.ts +2 -0
- package/dist/verifiers/disclaimer_gate.js +57 -0
- package/dist/verifiers/disclaimer_gate.js.map +1 -0
- package/dist/verifiers/index.d.ts +5 -0
- package/dist/verifiers/index.js +20 -7
- package/dist/verifiers/index.js.map +1 -1
- package/dist/verifiers/lint.js +4 -3
- package/dist/verifiers/lint.js.map +1 -1
- package/dist/verifiers/promoted_kernels.d.ts +8 -0
- package/dist/verifiers/promoted_kernels.js +190 -0
- package/dist/verifiers/promoted_kernels.js.map +1 -0
- package/dist/verifiers/source_gate.js +2 -3
- package/dist/verifiers/source_gate.js.map +1 -1
- package/dist/verifiers/test_smoke.js +30 -0
- package/dist/verifiers/test_smoke.js.map +1 -1
- package/dist/verifiers/types.d.ts +3 -0
- package/package.json +4 -2
- package/skills/README.md +123 -0
- package/skills/ab-test.md +89 -0
- package/skills/api-design.md +175 -0
- package/skills/architecture-design.md +185 -0
- package/skills/business-case.md +77 -0
- package/skills/causal-inference.md +77 -0
- package/skills/clinical-guideline.md +98 -0
- package/skills/code-review.md +98 -0
- package/skills/cold-outreach.md +268 -0
- package/skills/competitive-teardown.md +223 -0
- package/skills/component-spec.md +121 -0
- package/skills/content-calendar.md +280 -0
- package/skills/contract-review.md +155 -0
- package/skills/data-analysis.md +187 -0
- package/skills/debug.md +91 -0
- package/skills/design-audit.md +121 -0
- package/skills/differential-diagnosis.md +79 -0
- package/skills/discovery-call.md +206 -0
- package/skills/edit-pass.md +80 -0
- package/skills/engineering-calc.md +101 -0
- package/skills/estimate.md +70 -0
- package/skills/experiment-design.md +105 -0
- package/skills/fact-check.md +82 -0
- package/skills/financial-model.md +104 -0
- package/skills/grant-proposal.md +93 -0
- package/skills/harmony-analysis.md +93 -0
- package/skills/hypothesis-generation.md +99 -0
- package/skills/incident-response.md +134 -0
- package/skills/interview-loop.md +62 -0
- package/skills/job-scorecard.md +92 -0
- package/skills/kb-article.md +174 -0
- package/skills/launch-plan.md +85 -0
- package/skills/lease-review.md +93 -0
- package/skills/lesson-plan.md +198 -0
- package/skills/literature-review.md +69 -0
- package/skills/market-entry.md +137 -0
- package/skills/market-sizing.md +159 -0
- package/skills/meta-analysis.md +140 -0
- package/skills/migrate.md +117 -0
- package/skills/optimize.md +88 -0
- package/skills/options-strategy.md +166 -0
- package/skills/peer-review.md +96 -0
- package/skills/pentest-plan.md +193 -0
- package/skills/pitch-review.md +132 -0
- package/skills/plan.md +88 -0
- package/skills/policy-brief.md +124 -0
- package/skills/positioning.md +192 -0
- package/skills/postmortem.md +168 -0
- package/skills/prd.md +105 -0
- package/skills/prioritize.md +162 -0
- package/skills/proof.md +91 -0
- package/skills/property-underwrite.md +159 -0
- package/skills/recipe-develop.md +109 -0
- package/skills/red-team.md +142 -0
- package/skills/refactor.md +58 -0
- package/skills/reflection-session.md +115 -0
- package/skills/regulatory-compliance.md +136 -0
- package/skills/reproduce.md +87 -0
- package/skills/runbook.md +344 -0
- package/skills/security-audit.md +154 -0
- package/skills/seo-brief.md +201 -0
- package/skills/sql-query.md +161 -0
- package/skills/story-craft.md +163 -0
- package/skills/tdd.md +59 -0
- package/skills/term-sheet.md +298 -0
- package/skills/theory-of-change.md +88 -0
- package/skills/threat-model.md +104 -0
- package/skills/ticket-triage.md +200 -0
- package/skills/tolerance-analysis.md +149 -0
- package/skills/training-program.md +151 -0
- package/skills/translate.md +64 -0
- package/skills/unit-economics.md +238 -0
- package/skills/valuation.md +112 -0
- package/skills/write-tests.md +77 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Task tool — bounded read-only subagent over fetch to /api/cli/chat.
|
|
2
|
+
// Allows only Read/Grep/Glob/LS. Aggregate AbortController timeout (default 300s).
|
|
3
|
+
// No agent_type param (CLI version).
|
|
4
|
+
import { execRead } from "./read.js";
|
|
5
|
+
import { execGrep } from "./grep.js";
|
|
6
|
+
import { execGlob } from "./glob.js";
|
|
7
|
+
import { execLs } from "./ls.js";
|
|
8
|
+
import { buildLocalToolSchemas } from "@vextlabs/theron-agent-sdk";
|
|
9
|
+
const MAX_TURNS = 10;
|
|
10
|
+
const DEFAULT_TIMEOUT_SECONDS = 300;
|
|
11
|
+
// Read-only tool schemas for the sub-agent.
|
|
12
|
+
const READ_ONLY_SCHEMAS = buildLocalToolSchemas({
|
|
13
|
+
Read: "Read a file from the workspace.",
|
|
14
|
+
Grep: "Search file contents with a regex.",
|
|
15
|
+
Glob: "Find files by glob pattern.",
|
|
16
|
+
LS: "List files and directories in a path.",
|
|
17
|
+
});
|
|
18
|
+
const READ_ONLY_NAMES = new Set(["Read", "Grep", "Glob", "LS"]);
|
|
19
|
+
const READ_ONLY_TOOL_SCHEMAS = READ_ONLY_SCHEMAS.filter((s) => READ_ONLY_NAMES.has(s.function.name));
|
|
20
|
+
export async function execTask(args, ctx) {
|
|
21
|
+
if (!args.prompt || !args.prompt.trim()) {
|
|
22
|
+
return "[error] prompt must be a non-empty string.";
|
|
23
|
+
}
|
|
24
|
+
if (!ctx.apiUrl) {
|
|
25
|
+
return "[error] apiUrl not configured — cannot spawn subagent.";
|
|
26
|
+
}
|
|
27
|
+
const timeoutMs = Math.max(10_000, (args.timeout_seconds ?? DEFAULT_TIMEOUT_SECONDS) * 1000);
|
|
28
|
+
const abort = new AbortController();
|
|
29
|
+
const timer = setTimeout(() => abort.abort(new Error(`Task timed out after ${timeoutMs / 1000}s`)), timeoutMs);
|
|
30
|
+
try {
|
|
31
|
+
return await runTask(args, ctx, abort.signal);
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function runTask(args, ctx, signal) {
|
|
38
|
+
const messages = [
|
|
39
|
+
{ role: "user", content: args.prompt.trim() },
|
|
40
|
+
];
|
|
41
|
+
const accumulatedText = [];
|
|
42
|
+
const label = args.description ? `[Task: ${args.description}]` : "[Task]";
|
|
43
|
+
for (let turn = 0; turn < MAX_TURNS; turn++) {
|
|
44
|
+
if (signal.aborted) {
|
|
45
|
+
return `${label}\n[error] Task timed out.\n${accumulatedText.join("")}`;
|
|
46
|
+
}
|
|
47
|
+
let response;
|
|
48
|
+
try {
|
|
49
|
+
const turnSignal = AbortSignal.any
|
|
50
|
+
? AbortSignal.any([signal, AbortSignal.timeout(60_000)])
|
|
51
|
+
: signal;
|
|
52
|
+
response = await fetch(`${ctx.apiUrl.replace(/\/$/, "")}/api/cli/chat`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: {
|
|
55
|
+
"content-type": "application/json",
|
|
56
|
+
...(ctx.apiKey ? { authorization: `Bearer ${ctx.apiKey}` } : {}),
|
|
57
|
+
accept: "application/x-ndjson",
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
messages,
|
|
61
|
+
tools: READ_ONLY_TOOL_SCHEMAS,
|
|
62
|
+
surface: "cli",
|
|
63
|
+
}),
|
|
64
|
+
signal: turnSignal,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return `${label}\n[error] Network error on turn ${turn + 1}: ${err instanceof Error ? err.message : String(err)}\n${accumulatedText.join("")}`;
|
|
69
|
+
}
|
|
70
|
+
if (!response.ok || !response.body) {
|
|
71
|
+
let detail = "";
|
|
72
|
+
try {
|
|
73
|
+
detail = (await response.text()).slice(0, 300);
|
|
74
|
+
}
|
|
75
|
+
catch { /* ignore */ }
|
|
76
|
+
return `${label}\n[error] HTTP ${response.status} on turn ${turn + 1}: ${detail}\n${accumulatedText.join("")}`;
|
|
77
|
+
}
|
|
78
|
+
const reader = response.body.getReader();
|
|
79
|
+
const decoder = new TextDecoder();
|
|
80
|
+
let buf = "";
|
|
81
|
+
let turnText = "";
|
|
82
|
+
const toolCalls = [];
|
|
83
|
+
let stopReason = "end_turn";
|
|
84
|
+
try {
|
|
85
|
+
outer: while (true) {
|
|
86
|
+
const { done, value } = await reader.read();
|
|
87
|
+
if (done)
|
|
88
|
+
break;
|
|
89
|
+
buf += decoder.decode(value, { stream: true });
|
|
90
|
+
let idx;
|
|
91
|
+
while ((idx = buf.indexOf("\n")) >= 0) {
|
|
92
|
+
const line = buf.slice(0, idx).trim();
|
|
93
|
+
buf = buf.slice(idx + 1);
|
|
94
|
+
if (!line)
|
|
95
|
+
continue;
|
|
96
|
+
let frame;
|
|
97
|
+
try {
|
|
98
|
+
frame = JSON.parse(line);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (frame.type === "text_delta" && frame.delta) {
|
|
104
|
+
turnText += frame.delta;
|
|
105
|
+
}
|
|
106
|
+
else if (frame.type === "tool_call" && frame.id && frame.name && frame.args) {
|
|
107
|
+
toolCalls.push({ id: frame.id, name: frame.name, args: frame.args });
|
|
108
|
+
}
|
|
109
|
+
else if (frame.type === "turn_end" && frame.stop_reason) {
|
|
110
|
+
stopReason = frame.stop_reason;
|
|
111
|
+
break outer;
|
|
112
|
+
}
|
|
113
|
+
else if (frame.type === "error" && frame.message) {
|
|
114
|
+
return `${label}\n[error] Subagent error: ${frame.message}\n${accumulatedText.join("")}`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
return `${label}\n[error] Stream error on turn ${turn + 1}: ${err instanceof Error ? err.message : String(err)}\n${accumulatedText.join("")}`;
|
|
121
|
+
}
|
|
122
|
+
if (turnText)
|
|
123
|
+
accumulatedText.push(turnText);
|
|
124
|
+
messages.push({ role: "assistant", content: turnText, tool_calls: toolCalls });
|
|
125
|
+
if (stopReason !== "tool_use" || toolCalls.length === 0)
|
|
126
|
+
break;
|
|
127
|
+
for (const call of toolCalls) {
|
|
128
|
+
if (!READ_ONLY_NAMES.has(call.name)) {
|
|
129
|
+
messages.push({
|
|
130
|
+
role: "tool",
|
|
131
|
+
tool_call_id: call.id,
|
|
132
|
+
content: `[error] Tool "${call.name}" is not available in a read-only subagent.`,
|
|
133
|
+
});
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
let result;
|
|
137
|
+
try {
|
|
138
|
+
switch (call.name) {
|
|
139
|
+
case "Read":
|
|
140
|
+
result = await execRead(call.args, ctx);
|
|
141
|
+
break;
|
|
142
|
+
case "Grep":
|
|
143
|
+
result = await execGrep(call.args, ctx);
|
|
144
|
+
break;
|
|
145
|
+
case "Glob":
|
|
146
|
+
result = await execGlob(call.args, ctx);
|
|
147
|
+
break;
|
|
148
|
+
case "LS":
|
|
149
|
+
result = await execLs(call.args, ctx);
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
result = `[error] Unknown read-only tool: ${call.name}`;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
result = `[error] ${call.name} threw: ${err instanceof Error ? err.message : String(err)}`;
|
|
157
|
+
}
|
|
158
|
+
messages.push({ role: "tool", tool_call_id: call.id, content: result });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const finalText = accumulatedText.join("").trim();
|
|
162
|
+
if (!finalText)
|
|
163
|
+
return `${label}\n[subagent returned no text]`;
|
|
164
|
+
return `${label}\n${finalText}`;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolContext } from "./index.js";
|
|
2
|
+
export interface TodoItem {
|
|
3
|
+
content: string;
|
|
4
|
+
status: "pending" | "in_progress" | "completed";
|
|
5
|
+
activeForm?: string;
|
|
6
|
+
}
|
|
7
|
+
interface TodoWriteArgs {
|
|
8
|
+
todos: TodoItem[];
|
|
9
|
+
}
|
|
10
|
+
export declare function execTodoWrite(args: TodoWriteArgs, _ctx: ToolContext): Promise<string>;
|
|
11
|
+
export declare function describeCurrentList(): string;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// TodoWrite tool — structured task list for the current session.
|
|
2
|
+
// Module-level state persists across tool calls within one CLI session.
|
|
3
|
+
// Module-level state — persists for the CLI session.
|
|
4
|
+
let todoList = [];
|
|
5
|
+
export async function execTodoWrite(args, _ctx) {
|
|
6
|
+
if (!Array.isArray(args.todos)) {
|
|
7
|
+
return "[error] todos must be an array.";
|
|
8
|
+
}
|
|
9
|
+
for (const item of args.todos) {
|
|
10
|
+
if (typeof item.content !== "string" || !item.content.trim()) {
|
|
11
|
+
return "[error] Each todo must have a non-empty string content field.";
|
|
12
|
+
}
|
|
13
|
+
if (!["pending", "in_progress", "completed"].includes(item.status)) {
|
|
14
|
+
return `[error] Invalid status "${item.status}" — must be pending, in_progress, or completed.`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
todoList = args.todos.map((t) => ({
|
|
18
|
+
content: t.content,
|
|
19
|
+
status: t.status,
|
|
20
|
+
activeForm: t.activeForm ?? "",
|
|
21
|
+
}));
|
|
22
|
+
return renderList(todoList);
|
|
23
|
+
}
|
|
24
|
+
function renderList(list) {
|
|
25
|
+
if (list.length === 0)
|
|
26
|
+
return "Todo list is empty.";
|
|
27
|
+
const lines = list.map((item) => {
|
|
28
|
+
const mark = item.status === "completed" ? "[x]" :
|
|
29
|
+
item.status === "in_progress" ? "[~]" :
|
|
30
|
+
"[ ]";
|
|
31
|
+
return `${mark} ${item.content}`;
|
|
32
|
+
});
|
|
33
|
+
return lines.join("\n");
|
|
34
|
+
}
|
|
35
|
+
export function describeCurrentList() {
|
|
36
|
+
return renderList(todoList);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=todowrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todowrite.js","sourceRoot":"","sources":["../../src/tools/todowrite.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,wEAAwE;AAUxE,qDAAqD;AACrD,IAAI,QAAQ,GAAe,EAAE,CAAC;AAM9B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAmB,EAAE,IAAiB;IACxE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,iCAAiC,CAAC;IAC3C,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAC7D,OAAO,+DAA+D,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,2BAA2B,IAAI,CAAC,MAAM,iDAAiD,CAAC;QACjG,CAAC;IACH,CAAC;IACD,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE;KAC/B,CAAC,CAAC,CAAC;IACJ,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,UAAU,CAAC,IAAgB;IAClC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,qBAAqB,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9B,MAAM,IAAI,GACR,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBACvC,KAAK,CAAC;QACR,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// WebFetch tool — fetches a URL, strips HTML to readable text, 15s timeout,
|
|
2
|
+
// truncates to ctx.maxBytes. SSRF guard rejects file://, loopback, and
|
|
3
|
+
// private IP ranges.
|
|
4
|
+
// Patterns to strip from HTML before returning to the model.
|
|
5
|
+
const SCRIPT_STYLE_RE = /<(script|style)[^>]*>[\s\S]*?<\/\1>/gi;
|
|
6
|
+
const HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
|
|
7
|
+
const HTML_TAG_RE = /<[^>]+>/g;
|
|
8
|
+
const MULTI_BLANK_RE = /\n{3,}/g;
|
|
9
|
+
/** Returns an error string if the URL should be rejected, else null. */
|
|
10
|
+
function ssrfCheck(parsed) {
|
|
11
|
+
if (parsed.protocol === "file:")
|
|
12
|
+
return "file: protocol is not allowed.";
|
|
13
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
14
|
+
return `protocol "${parsed.protocol}" is not allowed; only http: and https: are permitted.`;
|
|
15
|
+
}
|
|
16
|
+
const host = parsed.hostname.toLowerCase();
|
|
17
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") {
|
|
18
|
+
return `host "${host}" is a loopback address and is not allowed.`;
|
|
19
|
+
}
|
|
20
|
+
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
21
|
+
if (v4) {
|
|
22
|
+
const [, a, b] = v4.map(Number);
|
|
23
|
+
if (a === 10)
|
|
24
|
+
return `host "${host}" is in a private IP range and is not allowed.`;
|
|
25
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
26
|
+
return `host "${host}" is in a private IP range and is not allowed.`;
|
|
27
|
+
if (a === 192 && b === 168)
|
|
28
|
+
return `host "${host}" is in a private IP range and is not allowed.`;
|
|
29
|
+
if (a === 169 && b === 254)
|
|
30
|
+
return `host "${host}" is a link-local address and is not allowed.`;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
export async function execWebFetch(args, ctx) {
|
|
35
|
+
let parsed;
|
|
36
|
+
try {
|
|
37
|
+
parsed = new URL(args.url);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return `[error] Invalid URL: ${args.url}`;
|
|
41
|
+
}
|
|
42
|
+
const ssrfErr = ssrfCheck(parsed);
|
|
43
|
+
if (ssrfErr)
|
|
44
|
+
return `[error] SSRF guard: ${ssrfErr}`;
|
|
45
|
+
const url = parsed.toString();
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
response = await fetch(url, {
|
|
49
|
+
headers: {
|
|
50
|
+
"user-agent": "Mozilla/5.0 (compatible; TheronCLI/1.0; +https://itstheron.com)",
|
|
51
|
+
"accept": "text/html,application/xhtml+xml,text/plain;q=0.9,*/*;q=0.8",
|
|
52
|
+
},
|
|
53
|
+
signal: AbortSignal.timeout(15_000),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
return `[error] Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`;
|
|
58
|
+
}
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
return `[error] HTTP ${response.status} ${response.statusText} for ${url}`;
|
|
61
|
+
}
|
|
62
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
63
|
+
let body;
|
|
64
|
+
try {
|
|
65
|
+
body = await response.text();
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return `[error] Could not read response body: ${err instanceof Error ? err.message : String(err)}`;
|
|
69
|
+
}
|
|
70
|
+
let text;
|
|
71
|
+
if (contentType.includes("html")) {
|
|
72
|
+
text = body
|
|
73
|
+
.replace(SCRIPT_STYLE_RE, " ")
|
|
74
|
+
.replace(HTML_COMMENT_RE, " ")
|
|
75
|
+
.replace(HTML_TAG_RE, " ")
|
|
76
|
+
.replace(/ /g, " ")
|
|
77
|
+
.replace(/&/g, "&")
|
|
78
|
+
.replace(/</g, "<")
|
|
79
|
+
.replace(/>/g, ">")
|
|
80
|
+
.replace(/"/g, '"')
|
|
81
|
+
.replace(/'/g, "'")
|
|
82
|
+
.replace(/[ \t]+/g, " ")
|
|
83
|
+
.replace(/^ +/gm, "")
|
|
84
|
+
.replace(MULTI_BLANK_RE, "\n\n")
|
|
85
|
+
.trim();
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
text = body;
|
|
89
|
+
}
|
|
90
|
+
const cap = ctx.maxBytes;
|
|
91
|
+
const note = Buffer.byteLength(text, "utf-8") > cap ? "\n[content truncated to maxBytes]" : "";
|
|
92
|
+
if (Buffer.byteLength(text, "utf-8") > cap) {
|
|
93
|
+
const buf = Buffer.from(text, "utf-8");
|
|
94
|
+
text = buf.slice(0, cap).toString("utf-8");
|
|
95
|
+
}
|
|
96
|
+
return `${url}\n${text}${note}`;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=webfetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webfetch.js","sourceRoot":"","sources":["../../src/tools/webfetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// WebSearch tool — DuckDuckGo HTML scrape returning title + URL + snippet.
|
|
2
|
+
// No API key required.
|
|
3
|
+
const MAX_RESULTS_CAP = 20;
|
|
4
|
+
const DEFAULT_MAX = 10;
|
|
5
|
+
const RESULT_LINK_RE = /<a[^>]+class="[^"]*result__a[^"]*"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
6
|
+
const HTML_ENTITY_RE = /&[a-z]+;|&#\d+;/gi;
|
|
7
|
+
const HTML_TAG_INLINE_RE = /<[^>]+>/g;
|
|
8
|
+
function decodeEntities(s) {
|
|
9
|
+
return s
|
|
10
|
+
.replace(/&/g, "&")
|
|
11
|
+
.replace(/</g, "<")
|
|
12
|
+
.replace(/>/g, ">")
|
|
13
|
+
.replace(/"/g, '"')
|
|
14
|
+
.replace(/'/g, "'")
|
|
15
|
+
.replace(/ /g, " ")
|
|
16
|
+
.replace(HTML_ENTITY_RE, " ");
|
|
17
|
+
}
|
|
18
|
+
function stripTags(s) {
|
|
19
|
+
return s.replace(HTML_TAG_INLINE_RE, "").trim();
|
|
20
|
+
}
|
|
21
|
+
export async function execWebSearch(args, _ctx) {
|
|
22
|
+
if (!args.query || !args.query.trim()) {
|
|
23
|
+
return "[error] query must be a non-empty string.";
|
|
24
|
+
}
|
|
25
|
+
const maxResults = Math.min(args.max_results && args.max_results > 0 ? args.max_results : DEFAULT_MAX, MAX_RESULTS_CAP);
|
|
26
|
+
const encoded = encodeURIComponent(args.query.trim());
|
|
27
|
+
const searchUrl = `https://html.duckduckgo.com/html/?q=${encoded}`;
|
|
28
|
+
let response;
|
|
29
|
+
try {
|
|
30
|
+
response = await fetch(searchUrl, {
|
|
31
|
+
headers: {
|
|
32
|
+
"user-agent": "Mozilla/5.0 (compatible; TheronCLI/1.0; +https://itstheron.com)",
|
|
33
|
+
"accept": "text/html,*/*;q=0.8",
|
|
34
|
+
"accept-language": "en-US,en;q=0.9",
|
|
35
|
+
},
|
|
36
|
+
signal: AbortSignal.timeout(15_000),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
return `[error] Search request failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
41
|
+
}
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
return `[error] DuckDuckGo returned HTTP ${response.status} for "${args.query}"`;
|
|
44
|
+
}
|
|
45
|
+
let html;
|
|
46
|
+
try {
|
|
47
|
+
html = await response.text();
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
return `[error] Could not read search response: ${err instanceof Error ? err.message : String(err)}`;
|
|
51
|
+
}
|
|
52
|
+
const results = [];
|
|
53
|
+
let match;
|
|
54
|
+
RESULT_LINK_RE.lastIndex = 0;
|
|
55
|
+
while ((match = RESULT_LINK_RE.exec(html)) !== null && results.length < maxResults) {
|
|
56
|
+
const rawHref = match[1];
|
|
57
|
+
const rawTitle = match[2];
|
|
58
|
+
const title = decodeEntities(stripTags(rawTitle)).replace(/\s+/g, " ").trim();
|
|
59
|
+
if (!title)
|
|
60
|
+
continue;
|
|
61
|
+
let url = rawHref;
|
|
62
|
+
try {
|
|
63
|
+
const hrefUrl = new URL(rawHref, "https://html.duckduckgo.com");
|
|
64
|
+
const uddg = hrefUrl.searchParams.get("uddg");
|
|
65
|
+
if (uddg) {
|
|
66
|
+
url = decodeURIComponent(uddg);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
url = hrefUrl.toString();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch { /* keep rawHref */ }
|
|
73
|
+
if (!url || url.startsWith("https://duckduckgo.com"))
|
|
74
|
+
continue;
|
|
75
|
+
results.push({ title, url });
|
|
76
|
+
}
|
|
77
|
+
if (results.length === 0) {
|
|
78
|
+
return `[no results found for "${args.query}"]`;
|
|
79
|
+
}
|
|
80
|
+
const lines = results.map((r, i) => `${i + 1}. ${r.title}\n ${r.url}`);
|
|
81
|
+
return `Web search: "${args.query}" (${results.length} result${results.length === 1 ? "" : "s"})\n\n${lines.join("\n\n")}`;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=websearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websearch.js","sourceRoot":"","sources":["../../src/tools/websearch.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/write.js
CHANGED
|
@@ -3,13 +3,29 @@
|
|
|
3
3
|
// already passed.
|
|
4
4
|
import { promises as fs } from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { sha256Hex, receiptLocalAction } from "../receipt.js";
|
|
7
|
+
import { snapshot } from "../checkpoints.js";
|
|
6
8
|
export async function execWrite(args, ctx) {
|
|
7
9
|
const target = path.isAbsolute(args.file_path)
|
|
8
10
|
? args.file_path
|
|
9
11
|
: path.resolve(ctx.cwd, args.file_path);
|
|
12
|
+
// Snapshot the file's current content BEFORE overwriting so /rewind can
|
|
13
|
+
// restore it. Fail-safe: a read error (file missing, permission denied)
|
|
14
|
+
// is swallowed — the write still proceeds normally.
|
|
15
|
+
await snapshot(target).catch(() => undefined);
|
|
10
16
|
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
11
17
|
await fs.writeFile(target, args.content, "utf-8");
|
|
18
|
+
const byteLen = Buffer.byteLength(args.content, "utf-8");
|
|
12
19
|
const lineCount = args.content.split(/\r?\n/).length;
|
|
13
|
-
|
|
20
|
+
const baseResult = `Wrote ${target} (${lineCount} lines, ${byteLen} bytes)`;
|
|
21
|
+
// Mint a STOA receipt for this write. Fail-open: if the receipt POST
|
|
22
|
+
// fails, the base result is returned unmodified.
|
|
23
|
+
const postSha256 = sha256Hex(args.content);
|
|
24
|
+
const verifyUrl = await receiptLocalAction(ctx.apiUrl, ctx.apiKey, "local_write", {
|
|
25
|
+
path: target,
|
|
26
|
+
bytes: byteLen,
|
|
27
|
+
post_sha256: postSha256,
|
|
28
|
+
}).catch(() => null);
|
|
29
|
+
return verifyUrl ? baseResult + "\nsigned -- verify: " + verifyUrl : baseResult;
|
|
14
30
|
}
|
|
15
31
|
//# sourceMappingURL=write.js.map
|
package/dist/tools/write.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,qEAAqE;AACrE,kBAAkB;AAElB,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,qEAAqE;AACrE,kBAAkB;AAElB,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAO7C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAe,EAAE,GAAgB;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;QAC5C,CAAC,CAAC,IAAI,CAAC,SAAS;QAChB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1C,wEAAwE;IACxE,yEAAyE;IACzE,oDAAoD;IACpD,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAE9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACrD,MAAM,UAAU,GAAG,SAAS,MAAM,KAAK,SAAS,WAAW,OAAO,SAAS,CAAC;IAE5E,qEAAqE;IACrE,iDAAiD;IACjD,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,MAAM,kBAAkB,CACxC,GAAG,CAAC,MAAM,EACV,GAAG,CAAC,MAAM,EACV,aAAa,EACb;QACE,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,UAAU;KACxB,CACF,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAEpB,OAAO,SAAS,CAAC,CAAC,CAAC,UAAU,GAAG,sBAAsB,GAAG,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Confidence-marked gate — promotes the previously-inert `confidence_marked`
|
|
2
|
+
// alias (which just ran style_lint) into a real kernel.
|
|
3
|
+
//
|
|
4
|
+
// Research / science / scholarly / policy answers should CALIBRATE: a strong
|
|
5
|
+
// factual claim with zero uncertainty language reads as overconfident, the #1
|
|
6
|
+
// epistemic failure mode for these domains. This kernel fires (warn) only when
|
|
7
|
+
// a SUBSTANTIVE answer in a calibration-expected profile contains NO hedging or
|
|
8
|
+
// confidence language anywhere — a deliberately conservative trigger to avoid
|
|
9
|
+
// punishing answers that are already appropriately calibrated. It never blocks
|
|
10
|
+
// (calibration is a quality nudge, not a hard gate).
|
|
11
|
+
// Profiles where explicit uncertainty calibration is expected.
|
|
12
|
+
const CALIBRATION_PROFILES = new Set([
|
|
13
|
+
"research", "science", "academic", "policy", "strategy", "medical", "business", "investor",
|
|
14
|
+
]);
|
|
15
|
+
// Any one of these counts as calibration: hedges, evidence-strength language,
|
|
16
|
+
// explicit confidence markers, ranges, or qualifiers.
|
|
17
|
+
const CONFIDENCE_MARKERS = [
|
|
18
|
+
/\b(likely|unlikely|probabl(y|e)|possibl(y|e)|uncertain(ty)?|tentativ(e|ely)|preliminary)\b/i,
|
|
19
|
+
/\b(approximately|roughly|around|estimate[ds]?|on the order of|circa)\b/i,
|
|
20
|
+
/\b(appears?|seems?|suggests?|indicates?|implies?)\b/i,
|
|
21
|
+
/\b(may|might|could|can|would)\b/i,
|
|
22
|
+
/\b(evidence (suggests|indicates|is (mixed|weak|strong|limited)))\b/i,
|
|
23
|
+
/\b(high|medium|moderate|low)[- ]confidence\b/i,
|
|
24
|
+
/\bconfidence(:| level| is)\b/i,
|
|
25
|
+
/\b(established|contested|speculative|well[- ]supported|inconclusive|debated)\b/i,
|
|
26
|
+
/[~±]\s*\d/, // ~50, ±3
|
|
27
|
+
/\b\d+(\.\d+)?\s*(to|–|-)\s*\d/, // a numeric range (50 to 60, 50–60)
|
|
28
|
+
/\b(assum(e|ption|ing)|caveat|limitation|depends on)\b/i,
|
|
29
|
+
];
|
|
30
|
+
const SUBSTANTIVE_CHARS = 400;
|
|
31
|
+
export const confidenceMarkedKernel = {
|
|
32
|
+
slug: "confidence_marked",
|
|
33
|
+
describe: "Nudge for calibrated uncertainty in research/science answers (no hedging at all → warn)",
|
|
34
|
+
async run(ctx) {
|
|
35
|
+
if (!CALIBRATION_PROFILES.has(ctx.profile))
|
|
36
|
+
return [];
|
|
37
|
+
const text = ctx.assistantText ?? "";
|
|
38
|
+
if (text.trim().length < SUBSTANTIVE_CHARS)
|
|
39
|
+
return [];
|
|
40
|
+
if (CONFIDENCE_MARKERS.some((re) => re.test(text)))
|
|
41
|
+
return [];
|
|
42
|
+
return [{
|
|
43
|
+
severity: "warn",
|
|
44
|
+
kernel: "confidence_marked",
|
|
45
|
+
message: "No uncertainty/confidence calibration found. Mark how strongly the evidence supports each key claim (e.g. \"evidence suggests…\", \"likely\", a confidence level, or a range) and separate established from contested from speculative.",
|
|
46
|
+
}];
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=confidence_marked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence_marked.js","sourceRoot":"","sources":["../../src/verifiers/confidence_marked.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wDAAwD;AACxD,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,qDAAqD;AAIrD,+DAA+D;AAC/D,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU;CAC3F,CAAC,CAAC;AAEH,8EAA8E;AAC9E,sDAAsD;AACtD,MAAM,kBAAkB,GAAG;IACzB,6FAA6F;IAC7F,yEAAyE;IACzE,sDAAsD;IACtD,kCAAkC;IAClC,qEAAqE;IACrE,+CAA+C;IAC/C,+BAA+B;IAC/B,iFAAiF;IACjF,WAAW,EAAwB,UAAU;IAC7C,+BAA+B,EAAG,oCAAoC;IACtE,wDAAwD;CACzD,CAAC;AAEF,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,MAAM,CAAC,MAAM,sBAAsB,GAAa;IAC9C,IAAI,EAAE,mBAAmB;IACzB,QAAQ,EAAE,yFAAyF;IACnG,KAAK,CAAC,GAAG,CAAC,GAAoB;QAC5B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,iBAAiB;YAAE,OAAO,EAAE,CAAC;QACtD,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9D,OAAO,CAAC;gBACN,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,mBAAmB;gBAC3B,OAAO,EACL,yOAAyO;aAC5O,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Disclaimer gate — makes the safety-critical methodologies enforceable.
|
|
2
|
+
//
|
|
3
|
+
// The therapy / trader / trainer / medical methodologies (src/profiles/
|
|
4
|
+
// methodologies/*) each PROMISE a closing safety disclaimer ("this isn't
|
|
5
|
+
// therapy — reach out to 988", "educational, not investment advice", "see a
|
|
6
|
+
// sports-medicine physician", "not a substitute for a physician"). A promise
|
|
7
|
+
// the model can silently drop is not a guarantee. This kernel asserts the
|
|
8
|
+
// disclaimer is actually present on substantive turns and BLOCKS (feeds back
|
|
9
|
+
// into the next turn) when it's missing — the same discipline the pentest
|
|
10
|
+
// evidence_gate applies to findings, applied to user-safety language.
|
|
11
|
+
// Profile → required closing disclaimer. Only these safety-sensitive,
|
|
12
|
+
// educational-not-professional profiles are gated.
|
|
13
|
+
const DISCLAIMERS = {
|
|
14
|
+
therapy: {
|
|
15
|
+
label: "not-therapy / crisis resource",
|
|
16
|
+
any: [/\b988\b/, /crisis (lifeline|line)/i, /licensed (therapist|clinician|counselor)/i, /\bisn'?t therapy\b/i, /not (a substitute for |real )?therapy/i],
|
|
17
|
+
fix: 'End with the not-therapy disclaimer, e.g. "This isn\'t therapy — if things feel heavy, reach out to a licensed therapist or 988."',
|
|
18
|
+
},
|
|
19
|
+
trader: {
|
|
20
|
+
label: "not-investment-advice",
|
|
21
|
+
any: [/not (investment |financial )?advice/i, /licensed (financial )?advisor/i, /past performance/i, /\beducational\b/i],
|
|
22
|
+
fix: 'End with the not-advice disclaimer, e.g. "This is educational. Past performance does not predict future results. Talk to a licensed advisor."',
|
|
23
|
+
},
|
|
24
|
+
trainer: {
|
|
25
|
+
label: "see-a-physician",
|
|
26
|
+
any: [/physician/i, /sports[- ]medicine/i, /medical (advice|professional)/i, /\bdoctor\b/i, /healthcare (provider|professional)/i],
|
|
27
|
+
fix: 'End with the safety disclaimer, e.g. "If anything hurts beyond normal soreness, see a sports-medicine physician."',
|
|
28
|
+
},
|
|
29
|
+
medical: {
|
|
30
|
+
label: "not-a-substitute-for-a-physician",
|
|
31
|
+
any: [/physician/i, /healthcare (provider|professional)/i, /\bdoctor\b/i, /not a substitute/i, /consult (a|your) (doctor|physician|clinician)/i, /medical advice/i],
|
|
32
|
+
fix: 'Add the educational-use disclaimer — this is not a substitute for a licensed physician; the user should consult one.',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
// Below this length a turn is a clarifying aside, not substantive advice;
|
|
36
|
+
// don't force a disclaimer onto "Which symptom do you mean?".
|
|
37
|
+
const SUBSTANTIVE_CHARS = 240;
|
|
38
|
+
export const disclaimerGateKernel = {
|
|
39
|
+
slug: "disclaimer_gate",
|
|
40
|
+
describe: "Assert the required safety disclaimer is present (therapy/trader/trainer/medical)",
|
|
41
|
+
async run(ctx) {
|
|
42
|
+
const spec = DISCLAIMERS[ctx.profile];
|
|
43
|
+
if (!spec)
|
|
44
|
+
return [];
|
|
45
|
+
const text = ctx.assistantText ?? "";
|
|
46
|
+
if (text.trim().length < SUBSTANTIVE_CHARS)
|
|
47
|
+
return [];
|
|
48
|
+
if (spec.any.some((re) => re.test(text)))
|
|
49
|
+
return [];
|
|
50
|
+
return [{
|
|
51
|
+
severity: "block",
|
|
52
|
+
kernel: "disclaimer_gate",
|
|
53
|
+
message: `Missing the required ${spec.label} disclaimer for ${ctx.profile} mode. ${spec.fix}`,
|
|
54
|
+
}];
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=disclaimer_gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclaimer_gate.js","sourceRoot":"","sources":["../../src/verifiers/disclaimer_gate.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,wEAAwE;AACxE,yEAAyE;AACzE,4EAA4E;AAC5E,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,0EAA0E;AAC1E,sEAAsE;AAatE,sEAAsE;AACtE,mDAAmD;AACnD,MAAM,WAAW,GAAmC;IAClD,OAAO,EAAE;QACP,KAAK,EAAE,+BAA+B;QACtC,GAAG,EAAE,CAAC,SAAS,EAAE,yBAAyB,EAAE,2CAA2C,EAAE,qBAAqB,EAAE,wCAAwC,CAAC;QACzJ,GAAG,EAAE,mIAAmI;KACzI;IACD,MAAM,EAAE;QACN,KAAK,EAAE,uBAAuB;QAC9B,GAAG,EAAE,CAAC,sCAAsC,EAAE,gCAAgC,EAAE,mBAAmB,EAAE,kBAAkB,CAAC;QACxH,GAAG,EAAE,+IAA+I;KACrJ;IACD,OAAO,EAAE;QACP,KAAK,EAAE,iBAAiB;QACxB,GAAG,EAAE,CAAC,YAAY,EAAE,qBAAqB,EAAE,gCAAgC,EAAE,aAAa,EAAE,qCAAqC,CAAC;QAClI,GAAG,EAAE,mHAAmH;KACzH;IACD,OAAO,EAAE;QACP,KAAK,EAAE,kCAAkC;QACzC,GAAG,EAAE,CAAC,YAAY,EAAE,qCAAqC,EAAE,aAAa,EAAE,mBAAmB,EAAE,gDAAgD,EAAE,iBAAiB,CAAC;QACnK,GAAG,EAAE,sHAAsH;KAC5H;CACF,CAAC;AAEF,0EAA0E;AAC1E,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,MAAM,CAAC,MAAM,oBAAoB,GAAa;IAC5C,IAAI,EAAE,iBAAiB;IACvB,QAAQ,EAAE,mFAAmF;IAC7F,KAAK,CAAC,GAAG,CAAC,GAAoB;QAC5B,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,iBAAiB;YAAE,OAAO,EAAE,CAAC;QACtD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QACpD,OAAO,CAAC;gBACN,QAAQ,EAAE,OAAO;gBACjB,MAAM,EAAE,iBAAiB;gBACzB,OAAO,EAAE,wBAAwB,IAAI,CAAC,KAAK,mBAAmB,GAAG,CAAC,OAAO,UAAU,IAAI,CAAC,GAAG,EAAE;aAC9F,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { VerifierContext, VerifierIssue } from "./types.js";
|
|
2
2
|
export type { Verifier, VerifierContext, VerifierIssue } from "./types.js";
|
|
3
|
+
/** All registered verifier slugs (real kernels + aliases). Used by the
|
|
4
|
+
* integrity test to catch a profile referencing a slug that doesn't resolve
|
|
5
|
+
* to a kernel (runVerifiers silently drops unknown slugs, so without this a
|
|
6
|
+
* typo'd verifier slug would be an invisible no-op). */
|
|
7
|
+
export declare function listVerifierSlugs(): string[];
|
|
3
8
|
/** Run the kernels for the active profile in parallel. Each kernel
|
|
4
9
|
* has its own 5s timeout — slow kernels return [] rather than block
|
|
5
10
|
* the loop. Total wall time bounded by max(per-kernel time, 5s). */
|