thoth-agents 0.9.12 → 0.10.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/{chunk-2ER6FKVC.js → chunk-6NZTNWI4.js} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/pi-install.d.ts +1 -1
- package/dist/cli/tui/index.js +1 -1
- package/dist/pi-gate-verdict.d.ts +11 -1
- package/dist/pi.d.ts +6 -1
- package/dist/pi.js +169 -21
- package/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
|
@@ -8994,7 +8994,7 @@ function resolvePiPaths(options = {}) {
|
|
|
8994
8994
|
}
|
|
8995
8995
|
|
|
8996
8996
|
// src/cli/pi-install.ts
|
|
8997
|
-
var PI_MINIMUM_VERSION = "
|
|
8997
|
+
var PI_MINIMUM_VERSION = "1.5.0";
|
|
8998
8998
|
var PI_NODE_MINIMUM = "22.19.0";
|
|
8999
8999
|
var PI_COMMAND_TIMEOUT_MS = 12e4;
|
|
9000
9000
|
var PI_PACKAGE_SPECS = [
|
package/dist/cli/index.js
CHANGED
package/dist/cli/pi-install.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type PiExternalPackageEvidence, type PiExternalPackageSpec } from './pi-external-package';
|
|
2
2
|
import { type PiPackageReceipt, type PiPackageReceiptOptions } from './pi-package-receipt';
|
|
3
3
|
import { type PiPathOptions, type PiPaths } from './pi-paths';
|
|
4
|
-
export declare const PI_MINIMUM_VERSION = "
|
|
4
|
+
export declare const PI_MINIMUM_VERSION = "1.5.0";
|
|
5
5
|
export declare const PI_NODE_MINIMUM = "22.19.0";
|
|
6
6
|
export declare const PI_COMMAND_TIMEOUT_MS = 120000;
|
|
7
7
|
export interface PiSetupPackageSpec extends PiExternalPackageSpec {
|
package/dist/cli/tui/index.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare class PiContextGateVerdicts {
|
|
2
|
+
private readonly appendEntry?;
|
|
3
|
+
private readonly verdicts;
|
|
4
|
+
private sessionCache?;
|
|
5
|
+
constructor(appendEntry?: ((customType: string, data: unknown) => void) | undefined);
|
|
6
|
+
useSession(owner?: object): void;
|
|
7
|
+
restore(entries: Iterable<unknown>, sourceSessionFile?: string): void;
|
|
8
|
+
private readEntries;
|
|
9
|
+
getOrCreate(key: string, create: () => string | undefined): string | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare function withPiContextGateVerdicts(event: Record<string, unknown>, cwd: string, frozenVerdicts: PiContextGateVerdicts, entries?: Iterable<unknown>): {
|
|
2
12
|
messages: unknown[];
|
|
3
13
|
} | undefined;
|
|
4
14
|
export declare function withPiToolGateVerdicts(event: Record<string, unknown>, cwd: string): Record<string, unknown> | undefined;
|
package/dist/pi.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
type PiHandler = (event: Record<string, unknown>, context?: {
|
|
2
2
|
cwd?: string;
|
|
3
|
+
sessionManager?: {
|
|
4
|
+
getEntries?(): Iterable<unknown>;
|
|
5
|
+
getBranch?(): Iterable<unknown>;
|
|
6
|
+
};
|
|
3
7
|
isIdle?(): boolean;
|
|
4
8
|
ui?: {
|
|
5
9
|
notify(message: string, type?: 'info' | 'warning' | 'error'): void;
|
|
6
10
|
};
|
|
7
11
|
}) => unknown;
|
|
8
12
|
export interface PiExtensionApi {
|
|
9
|
-
on(event: 'input' | 'before_agent_start' | 'session_start' | 'tool_result' | 'context', handler: PiHandler): void;
|
|
13
|
+
on(event: 'input' | 'before_agent_start' | 'session_start' | 'session_tree' | 'tool_result' | 'context', handler: PiHandler): void;
|
|
10
14
|
registerCommand?(name: string, command: {
|
|
11
15
|
description: string;
|
|
12
16
|
handler(args: string | undefined, context: unknown): unknown;
|
|
@@ -15,6 +19,7 @@ export interface PiExtensionApi {
|
|
|
15
19
|
name: string;
|
|
16
20
|
source?: string;
|
|
17
21
|
}>;
|
|
22
|
+
appendEntry?(customType: string, data: unknown): void;
|
|
18
23
|
}
|
|
19
24
|
export interface PiExtensionOptions {
|
|
20
25
|
packageRoot?: string;
|
package/dist/pi.js
CHANGED
|
@@ -19,7 +19,100 @@ import { dirname, join } from "path";
|
|
|
19
19
|
import { fileURLToPath } from "url";
|
|
20
20
|
|
|
21
21
|
// src/pi-gate-verdict.ts
|
|
22
|
+
import { createHash } from "crypto";
|
|
23
|
+
import { readFileSync } from "fs";
|
|
22
24
|
var VERDICT_PREFIX = "thoth-gate-verdict ";
|
|
25
|
+
var FROZEN_VERDICT_ENTRY = "thoth-pi-gate-verdict";
|
|
26
|
+
var SESSION_CACHE_KEY = /* @__PURE__ */ Symbol.for(
|
|
27
|
+
"thoth-agents.pi-gate-verdict.sessions.v1"
|
|
28
|
+
);
|
|
29
|
+
var shared = globalThis;
|
|
30
|
+
function sessionVerdicts(owner) {
|
|
31
|
+
if (!owner) return void 0;
|
|
32
|
+
shared[SESSION_CACHE_KEY] ??= /* @__PURE__ */ new WeakMap();
|
|
33
|
+
const sessions = shared[SESSION_CACHE_KEY];
|
|
34
|
+
let verdicts = sessions.get(owner);
|
|
35
|
+
if (!verdicts) {
|
|
36
|
+
verdicts = /* @__PURE__ */ new Map();
|
|
37
|
+
sessions.set(owner, verdicts);
|
|
38
|
+
}
|
|
39
|
+
return verdicts;
|
|
40
|
+
}
|
|
41
|
+
var PiContextGateVerdicts = class {
|
|
42
|
+
constructor(appendEntry) {
|
|
43
|
+
this.appendEntry = appendEntry;
|
|
44
|
+
}
|
|
45
|
+
appendEntry;
|
|
46
|
+
verdicts = /* @__PURE__ */ new Map();
|
|
47
|
+
sessionCache;
|
|
48
|
+
useSession(owner) {
|
|
49
|
+
this.sessionCache = sessionVerdicts(owner);
|
|
50
|
+
}
|
|
51
|
+
restore(entries, sourceSessionFile) {
|
|
52
|
+
const retainedEntries = [...entries];
|
|
53
|
+
const sourceVerdicts = new Map(this.sessionCache);
|
|
54
|
+
for (const [key, verdict] of this.verdicts)
|
|
55
|
+
sourceVerdicts.set(key, verdict);
|
|
56
|
+
this.verdicts.clear();
|
|
57
|
+
this.readEntries(retainedEntries, this.verdicts);
|
|
58
|
+
const retainedKeys = [];
|
|
59
|
+
for (const value of retainedEntries) {
|
|
60
|
+
const completion = persistedOracleCompletion(value);
|
|
61
|
+
if (!completion) continue;
|
|
62
|
+
const key = completionVerdictKey(
|
|
63
|
+
completion.fingerprint,
|
|
64
|
+
completion.entryId
|
|
65
|
+
);
|
|
66
|
+
retainedKeys.push(key);
|
|
67
|
+
}
|
|
68
|
+
const missingKeys = retainedKeys.filter((key) => !this.verdicts.has(key));
|
|
69
|
+
if (sourceSessionFile && missingKeys.some((key) => !sourceVerdicts.has(key))) {
|
|
70
|
+
try {
|
|
71
|
+
const sourceEntries = readFileSync(sourceSessionFile, "utf8").split("\n").flatMap((line) => {
|
|
72
|
+
try {
|
|
73
|
+
return [JSON.parse(line)];
|
|
74
|
+
} catch {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
this.readEntries(sourceEntries, sourceVerdicts);
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const key of missingKeys) {
|
|
83
|
+
this.getOrCreate(key, () => sourceVerdicts.get(key));
|
|
84
|
+
}
|
|
85
|
+
this.sessionCache?.clear();
|
|
86
|
+
for (const key of retainedKeys) {
|
|
87
|
+
const verdict = this.verdicts.get(key);
|
|
88
|
+
if (verdict !== void 0) this.sessionCache?.set(key, verdict);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
readEntries(entries, verdicts) {
|
|
92
|
+
for (const value of entries) {
|
|
93
|
+
const entry = asRecord(value);
|
|
94
|
+
if (entry?.type !== "custom" || entry.customType !== FROZEN_VERDICT_ENTRY)
|
|
95
|
+
continue;
|
|
96
|
+
const data = asRecord(entry.data);
|
|
97
|
+
if (data?.version !== 1 || typeof data.key !== "string" || !/^[a-f0-9]{64}$/.test(data.key) || typeof data.verdict !== "string" || !data.verdict.startsWith(VERDICT_PREFIX) || data.verdict.includes("\n") || verdicts.has(data.key))
|
|
98
|
+
continue;
|
|
99
|
+
verdicts.set(data.key, data.verdict);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
getOrCreate(key, create) {
|
|
103
|
+
const frozen = this.verdicts.get(key);
|
|
104
|
+
if (frozen !== void 0) {
|
|
105
|
+
this.sessionCache?.set(key, frozen);
|
|
106
|
+
return frozen;
|
|
107
|
+
}
|
|
108
|
+
const verdict = this.sessionCache?.get(key) ?? create();
|
|
109
|
+
if (verdict === void 0) return void 0;
|
|
110
|
+
this.appendEntry?.(FROZEN_VERDICT_ENTRY, { version: 1, key, verdict });
|
|
111
|
+
this.verdicts.set(key, verdict);
|
|
112
|
+
this.sessionCache?.set(key, verdict);
|
|
113
|
+
return verdict;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
23
116
|
function asRecord(value) {
|
|
24
117
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
25
118
|
}
|
|
@@ -48,29 +141,64 @@ function oracleGateVerdict(taskValue, result, cwd) {
|
|
|
48
141
|
};
|
|
49
142
|
return formatGateVerdict(summary);
|
|
50
143
|
}
|
|
51
|
-
function
|
|
144
|
+
function oracleCompletion(message) {
|
|
145
|
+
const details = asRecord(message.details);
|
|
146
|
+
const task = asRecord(details?.task);
|
|
147
|
+
const result = details?.full_result ?? task?.result;
|
|
148
|
+
if (task?.agent !== "thoth-oracle" || typeof result !== "string" || !result.includes("```thoth-result"))
|
|
149
|
+
return void 0;
|
|
150
|
+
return {
|
|
151
|
+
task,
|
|
152
|
+
result,
|
|
153
|
+
fingerprint: JSON.stringify([task.id ?? null, result])
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function persistedOracleCompletion(value) {
|
|
157
|
+
const entry = asRecord(value);
|
|
158
|
+
if (entry?.type !== "custom_message" || entry.customType !== "subagent-completion" || typeof entry.id !== "string")
|
|
159
|
+
return void 0;
|
|
160
|
+
const completion = oracleCompletion(entry);
|
|
161
|
+
return completion ? { ...completion, entryId: entry.id } : void 0;
|
|
162
|
+
}
|
|
163
|
+
function completionVerdictKey(fingerprint, identity) {
|
|
164
|
+
return createHash("sha256").update(JSON.stringify([fingerprint, identity])).digest("hex");
|
|
165
|
+
}
|
|
166
|
+
function withPiContextGateVerdicts(event, cwd, frozenVerdicts, entries = []) {
|
|
52
167
|
if (!Array.isArray(event.messages)) return void 0;
|
|
168
|
+
const completionIds = /* @__PURE__ */ new Map();
|
|
169
|
+
for (const value of entries) {
|
|
170
|
+
const completion = persistedOracleCompletion(value);
|
|
171
|
+
if (!completion) continue;
|
|
172
|
+
const ids = completionIds.get(completion.fingerprint) ?? [];
|
|
173
|
+
ids.push(completion.entryId);
|
|
174
|
+
completionIds.set(completion.fingerprint, ids);
|
|
175
|
+
}
|
|
53
176
|
let changed = false;
|
|
54
|
-
const messages = event.messages
|
|
55
|
-
|
|
177
|
+
const messages = [...event.messages];
|
|
178
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
179
|
+
const message = asRecord(messages[index]);
|
|
56
180
|
if (message?.role !== "custom" || message.customType !== "subagent-completion" || typeof message.content !== "string" && !Array.isArray(message.content))
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
181
|
+
continue;
|
|
182
|
+
const completion = oracleCompletion(message);
|
|
183
|
+
if (!completion) continue;
|
|
184
|
+
const entryId = completionIds.get(completion.fingerprint)?.pop();
|
|
185
|
+
const key = completionVerdictKey(
|
|
186
|
+
completion.fingerprint,
|
|
187
|
+
entryId ?? message.timestamp ?? null
|
|
188
|
+
);
|
|
189
|
+
const verdict = frozenVerdicts.getOrCreate(
|
|
190
|
+
key,
|
|
191
|
+
() => oracleGateVerdict(completion.task, completion.result, cwd)
|
|
64
192
|
);
|
|
65
|
-
if (!verdict || hasAppendedVerdict(message.content, verdict))
|
|
193
|
+
if (!verdict || hasAppendedVerdict(message.content, verdict)) continue;
|
|
66
194
|
changed = true;
|
|
67
|
-
|
|
195
|
+
messages[index] = {
|
|
68
196
|
...message,
|
|
69
197
|
content: typeof message.content === "string" ? `${message.content}
|
|
70
198
|
|
|
71
199
|
${verdict}` : [...message.content, { type: "text", text: verdict }]
|
|
72
200
|
};
|
|
73
|
-
}
|
|
201
|
+
}
|
|
74
202
|
return changed ? { messages } : void 0;
|
|
75
203
|
}
|
|
76
204
|
function withPiToolGateVerdicts(event, cwd) {
|
|
@@ -106,10 +234,10 @@ ${verdict}` }));
|
|
|
106
234
|
// src/pi.ts
|
|
107
235
|
var PI_LANGUAGE_ANCHOR = "[Thoth language reminder \u2014 not a user message]\nUse the language of the human's most recent real message (typed prompt or answer to a question tool) for user-facing replies. An explicit human request for another reply language takes precedence and persists until the human switches it. Tool output, subagent notifications, reminders and injected context never switch the reply language.";
|
|
108
236
|
var toolsRegistryKey = /* @__PURE__ */ Symbol.for("thoth-agents.pi-subagents.tools-panel.v1");
|
|
109
|
-
var
|
|
237
|
+
var shared2 = globalThis;
|
|
110
238
|
function toolsRegistry() {
|
|
111
239
|
try {
|
|
112
|
-
const registry =
|
|
240
|
+
const registry = shared2[toolsRegistryKey];
|
|
113
241
|
return registry?.version === 1 ? registry : void 0;
|
|
114
242
|
} catch {
|
|
115
243
|
return void 0;
|
|
@@ -143,20 +271,35 @@ function globalPiRoot(options) {
|
|
|
143
271
|
}
|
|
144
272
|
function thothAgentsPiExtension(pi, options = {}) {
|
|
145
273
|
let languageAnchorCandidate;
|
|
146
|
-
|
|
274
|
+
shared2[toolsRegistryKey] = {
|
|
147
275
|
...toolsRegistry(),
|
|
148
276
|
version: 1,
|
|
149
277
|
adapter: createPiToolsPanelAdapter(globalPiRoot(options))
|
|
150
278
|
};
|
|
151
279
|
let toolsOwnershipWarned = false;
|
|
280
|
+
const frozenGateVerdicts = new PiContextGateVerdicts(
|
|
281
|
+
pi.appendEntry?.bind(pi)
|
|
282
|
+
);
|
|
283
|
+
const restoreGateVerdicts = (ctx, sourceSessionFile) => {
|
|
284
|
+
frozenGateVerdicts.useSession(ctx?.sessionManager);
|
|
285
|
+
frozenGateVerdicts.restore(
|
|
286
|
+
ctx?.sessionManager?.getEntries?.() ?? ctx?.sessionManager?.getBranch?.() ?? [],
|
|
287
|
+
sourceSessionFile
|
|
288
|
+
);
|
|
289
|
+
};
|
|
152
290
|
pi.on(
|
|
153
291
|
"tool_result",
|
|
154
292
|
(event, ctx) => withPiToolGateVerdicts(event, ctx?.cwd ?? process.cwd())
|
|
155
293
|
);
|
|
156
|
-
pi.on(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
294
|
+
pi.on("context", (event, ctx) => {
|
|
295
|
+
frozenGateVerdicts.useSession(ctx?.sessionManager);
|
|
296
|
+
return withPiContextGateVerdicts(
|
|
297
|
+
event,
|
|
298
|
+
ctx?.cwd ?? process.cwd(),
|
|
299
|
+
frozenGateVerdicts,
|
|
300
|
+
ctx?.sessionManager?.getBranch?.() ?? ctx?.sessionManager?.getEntries?.() ?? []
|
|
301
|
+
);
|
|
302
|
+
});
|
|
160
303
|
pi.on("input", (event, ctx) => {
|
|
161
304
|
languageAnchorCandidate = (event.source === "interactive" || event.source === "rpc") && typeof event.text === "string" && event.text.trim() && ctx?.isIdle?.() ? event.text : void 0;
|
|
162
305
|
});
|
|
@@ -186,7 +329,11 @@ function thothAgentsPiExtension(pi, options = {}) {
|
|
|
186
329
|
)
|
|
187
330
|
};
|
|
188
331
|
});
|
|
189
|
-
pi.on("session_start", (
|
|
332
|
+
pi.on("session_start", (event, ctx) => {
|
|
333
|
+
restoreGateVerdicts(
|
|
334
|
+
ctx,
|
|
335
|
+
typeof event.previousSessionFile === "string" ? event.previousSessionFile : void 0
|
|
336
|
+
);
|
|
190
337
|
if (!toolsOwnershipWarned && !hasToolsOwnership(pi) && ctx?.ui?.notify) {
|
|
191
338
|
toolsOwnershipWarned = true;
|
|
192
339
|
ctx.ui.notify(
|
|
@@ -204,6 +351,7 @@ function thothAgentsPiExtension(pi, options = {}) {
|
|
|
204
351
|
} catch {
|
|
205
352
|
}
|
|
206
353
|
});
|
|
354
|
+
pi.on("session_tree", (_event, ctx) => restoreGateVerdicts(ctx));
|
|
207
355
|
}
|
|
208
356
|
export {
|
|
209
357
|
thothAgentsPiExtension as default,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thoth-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Adaptive multi-harness orchestration with six roles, runtime-autonomous AI-first execution routes, and external provider boundaries.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -95,14 +95,14 @@
|
|
|
95
95
|
"zod": "^4.1.8"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
|
-
"@earendil-works/pi-ai": ">=
|
|
99
|
-
"@earendil-works/pi-tui": ">=
|
|
98
|
+
"@earendil-works/pi-ai": ">=1.5.0",
|
|
99
|
+
"@earendil-works/pi-tui": ">=1.5.0"
|
|
100
100
|
},
|
|
101
101
|
"devDependencies": {
|
|
102
102
|
"@biomejs/biome": "2.4.2",
|
|
103
|
-
"@earendil-works/pi-ai": "1.0
|
|
104
|
-
"@earendil-works/pi-coding-agent": "1.0
|
|
105
|
-
"@earendil-works/pi-tui": "1.0
|
|
103
|
+
"@earendil-works/pi-ai": "1.5.0",
|
|
104
|
+
"@earendil-works/pi-coding-agent": "1.5.0",
|
|
105
|
+
"@earendil-works/pi-tui": "1.5.0",
|
|
106
106
|
"@types/hosted-git-info": "3.0.5",
|
|
107
107
|
"@types/node": "^22.19.19",
|
|
108
108
|
"@types/react": "^19.2.15",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thoth-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Bundled AI-first work skills and MCP configuration; the six-role global Codex layer requires thoth-agents CLI setup.",
|
|
5
5
|
"skills": "./skills/",
|
|
6
6
|
"mcpServers": "./codex.mcp.json",
|