pi-harness-runtime 1.1.130 → 1.1.132
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/index.ts +158 -57
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
package/index.ts
CHANGED
|
@@ -355,8 +355,9 @@ async function initHoncho(pi: { events: { emit(name: string, data: unknown): voi
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
// --- langchain-loop: Ping-pong write-review loop via harness/langchain/ -----------
|
|
358
|
-
//
|
|
359
|
-
//
|
|
358
|
+
// User picks model-role mapping once via /langchain-config.
|
|
359
|
+
// Stores selection in ~/.pi-harness-runtime/keys/langchain-role.json.
|
|
360
|
+
// /langchain reads from that file and spawns the loop.
|
|
360
361
|
function initLangChain(pi: {
|
|
361
362
|
registerCommand(
|
|
362
363
|
name: string,
|
|
@@ -367,76 +368,174 @@ function initLangChain(pi: {
|
|
|
367
368
|
},
|
|
368
369
|
): void;
|
|
369
370
|
}): void {
|
|
370
|
-
const { readFileSync, existsSync } = require("node:fs");
|
|
371
|
+
const { readFileSync, writeFileSync, existsSync } = require("node:fs");
|
|
371
372
|
const { spawn } = require("node:child_process");
|
|
372
373
|
const { fileURLToPath } = require("url");
|
|
373
374
|
const { dirname } = require("node:path");
|
|
375
|
+
const readline = require("node:readline");
|
|
374
376
|
|
|
375
377
|
const home = process.env.HOME || process.env.USERPROFILE || "/home/frappe";
|
|
376
378
|
const keysDir = `${home}/.pi-harness-runtime/keys`;
|
|
377
379
|
const modelsStorePath = `${home}/.pi/agent/models-store.json`;
|
|
380
|
+
const roleConfigPath = `${keysDir}/langchain-role.json`;
|
|
378
381
|
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
let reviewerUrl = "";
|
|
385
|
-
let coderModel = "";
|
|
386
|
-
let coderUrl = "";
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
// Load models from models-store.json
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
interface ModelEntry { id: string; baseUrl: string }
|
|
386
|
+
interface RoleConfig { planner?: string; coder?: string; reviewer?: string }
|
|
387
387
|
|
|
388
|
+
let store: Record<string, { models: Array<{ id: string; baseUrl?: string }> }> = {};
|
|
388
389
|
try {
|
|
389
390
|
if (existsSync(modelsStorePath)) {
|
|
390
|
-
|
|
391
|
+
store = JSON.parse(readFileSync(modelsStorePath, "utf8"));
|
|
392
|
+
}
|
|
393
|
+
} catch { /* ignore */ }
|
|
394
|
+
|
|
395
|
+
// Flat list of all models: "provider/model-id"
|
|
396
|
+
function listAllModels(): Array<{ index: number; provider: string; id: string; baseUrl: string }> {
|
|
397
|
+
const entries: Array<{ index: number; provider: string; id: string; baseUrl: string }> = [];
|
|
398
|
+
let idx = 1;
|
|
399
|
+
for (const [provider, info] of Object.entries(store)) {
|
|
400
|
+
for (const model of info.models ?? []) {
|
|
401
|
+
entries.push({ index: idx++, provider, id: model.id, baseUrl: model.baseUrl ?? "" });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return entries;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function resolveModel(spec: string): ModelEntry | null {
|
|
408
|
+
// spec format: "provider/model-id"
|
|
409
|
+
const parts = spec.split("/");
|
|
410
|
+
if (parts.length !== 2) return null;
|
|
411
|
+
const [provider, id] = parts;
|
|
412
|
+
const found = store[provider]?.models?.find((m) => m.id === id);
|
|
413
|
+
if (found) return { id: found.id, baseUrl: found.baseUrl ?? "" };
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
391
416
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
// Load saved role config
|
|
419
|
+
// ---------------------------------------------------------------------------
|
|
420
|
+
function loadRoleConfig(): RoleConfig {
|
|
421
|
+
try {
|
|
422
|
+
if (existsSync(roleConfigPath)) {
|
|
423
|
+
return JSON.parse(readFileSync(roleConfigPath, "utf8"));
|
|
397
424
|
}
|
|
425
|
+
} catch { /* ignore */ }
|
|
426
|
+
return {};
|
|
427
|
+
}
|
|
398
428
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
// /langchain-config: interactive model -> role picker
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
pi.registerCommand("langchain-config", {
|
|
433
|
+
description: "Pick which model is planner / coder / reviewer for the LangChain loop",
|
|
434
|
+
prompt: "Interactive: assign models to planner, coder, reviewer roles",
|
|
435
|
+
handler: async () => {
|
|
436
|
+
const allModels = listAllModels();
|
|
437
|
+
if (allModels.length === 0) {
|
|
438
|
+
console.error("[pi-harness] /langchain-config: no models found in ~/.pi/agent/models-store.json");
|
|
439
|
+
console.error("[pi-harness] Configure models first via /model in pi");
|
|
440
|
+
return;
|
|
404
441
|
}
|
|
405
442
|
|
|
406
|
-
//
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
coderUrl = minimaxModels[0].baseUrl ?? "https://api.minimaxi.com/v1";
|
|
443
|
+
// Print available models
|
|
444
|
+
console.error("[pi-harness] Available models:");
|
|
445
|
+
for (const m of allModels) {
|
|
446
|
+
console.error(` [${m.index}] ${m.provider}/${m.id}`);
|
|
411
447
|
}
|
|
412
|
-
}
|
|
413
|
-
} catch {
|
|
414
|
-
// models-store.json not readable — skip silently
|
|
415
|
-
}
|
|
416
448
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const coderKey = existsSync(`${keysDir}/coder-api-key.txt`);
|
|
449
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
450
|
+
const question = (q: string): Promise<string> =>
|
|
451
|
+
new Promise((res) => rl.question(`? ${q}: `, (a: string) => res(a.trim())));
|
|
421
452
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
453
|
+
let plannerSpec = "";
|
|
454
|
+
let coderSpec = "";
|
|
455
|
+
let reviewerSpec = "";
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
const plannerIdx = parseInt(await question("Planner model index"), 10);
|
|
459
|
+
const plannerEntry = allModels.find((m) => m.index === plannerIdx);
|
|
460
|
+
if (plannerEntry) plannerSpec = `${plannerEntry.provider}/${plannerEntry.id}`;
|
|
461
|
+
|
|
462
|
+
const coderIdx = parseInt(await question("Coder model index"), 10);
|
|
463
|
+
const coderEntry = allModels.find((m) => m.index === coderIdx);
|
|
464
|
+
if (coderEntry) coderSpec = `${coderEntry.provider}/${coderEntry.id}`;
|
|
465
|
+
|
|
466
|
+
const reviewerIdx = parseInt(await question("Reviewer model index"), 10);
|
|
467
|
+
const reviewerEntry = allModels.find((m) => m.index === reviewerIdx);
|
|
468
|
+
if (reviewerEntry) reviewerSpec = `${reviewerEntry.provider}/${reviewerEntry.id}`;
|
|
469
|
+
} finally {
|
|
470
|
+
rl.close();
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (!plannerSpec || !coderSpec || !reviewerSpec) {
|
|
474
|
+
console.error("[pi-harness] /langchain-config: all three roles must be selected");
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Save to langchain-role.json
|
|
479
|
+
const config: RoleConfig = {
|
|
480
|
+
planner: plannerSpec,
|
|
481
|
+
coder: coderSpec,
|
|
482
|
+
reviewer: reviewerSpec,
|
|
483
|
+
};
|
|
484
|
+
writeFileSync(roleConfigPath, JSON.stringify(config, null, 2), "utf8");
|
|
485
|
+
|
|
486
|
+
console.error("[pi-harness] LangChain role config saved:");
|
|
487
|
+
console.error(`[pi-harness] planner: ${plannerSpec}`);
|
|
488
|
+
console.error(`[pi-harness] coder: ${coderSpec}`);
|
|
489
|
+
console.error(`[pi-harness] reviewer: ${reviewerSpec}`);
|
|
490
|
+
|
|
491
|
+
// Also prompt for API keys if missing
|
|
492
|
+
if (!existsSync(`${keysDir}/planner-api-key.txt`)) {
|
|
493
|
+
console.error(`[pi-harness] planner-api-key.txt missing. echo "{key}" > ${keysDir}/planner-api-key.txt`);
|
|
494
|
+
}
|
|
495
|
+
if (!existsSync(`${keysDir}/reviewer-api-key.txt`)) {
|
|
496
|
+
console.error(`[pi-harness] reviewer-api-key.txt missing. echo "{key}" > ${keysDir}/reviewer-api-key.txt`);
|
|
497
|
+
}
|
|
498
|
+
if (!existsSync(`${keysDir}/coder-api-key.txt`)) {
|
|
499
|
+
console.error(`[pi-harness] coder-api-key.txt missing. echo "{key}" > ${keysDir}/coder-api-key.txt`);
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// ---------------------------------------------------------------------------
|
|
505
|
+
// /langchain: spawn the ping-pong loop
|
|
506
|
+
// ---------------------------------------------------------------------------
|
|
507
|
+
|
|
508
|
+
function loadActiveConfig(): { planner: ModelEntry; coder: ModelEntry; reviewer: ModelEntry } | null {
|
|
509
|
+
const cfg = loadRoleConfig();
|
|
510
|
+
if (!cfg.planner || !cfg.coder || !cfg.reviewer) return null;
|
|
511
|
+
const planner = resolveModel(cfg.planner);
|
|
512
|
+
const coder = resolveModel(cfg.coder);
|
|
513
|
+
const reviewer = resolveModel(cfg.reviewer);
|
|
514
|
+
if (!planner || !coder || !reviewer) return null;
|
|
515
|
+
return { planner, coder, reviewer };
|
|
426
516
|
}
|
|
427
517
|
|
|
428
|
-
|
|
518
|
+
const activeConfig = loadActiveConfig();
|
|
519
|
+
|
|
520
|
+
// Check API keys exist
|
|
521
|
+
const plannerKeyExists = existsSync(`${keysDir}/planner-api-key.txt`);
|
|
522
|
+
const reviewerKeyExists = existsSync(`${keysDir}/reviewer-api-key.txt`);
|
|
523
|
+
const coderKeyExists = existsSync(`${keysDir}/coder-api-key.txt`);
|
|
524
|
+
|
|
525
|
+
if (!activeConfig) {
|
|
526
|
+
console.error("[pi-harness] LangChain loop: run /langchain-config to assign model roles");
|
|
527
|
+
console.error("[pi-harness] (after npm package updates, use /reload to pick up new version)");
|
|
528
|
+
} else if (!plannerKeyExists || !reviewerKeyExists || !coderKeyExists) {
|
|
429
529
|
console.error("[pi-harness] LangChain loop: API keys missing:");
|
|
430
|
-
if (!
|
|
431
|
-
if (!
|
|
432
|
-
if (!
|
|
433
|
-
|
|
530
|
+
if (!plannerKeyExists) console.error(`[pi-harness] echo "{key}" > ${keysDir}/planner-api-key.txt`);
|
|
531
|
+
if (!reviewerKeyExists) console.error(`[pi-harness] echo "{key}" > ${keysDir}/reviewer-api-key.txt`);
|
|
532
|
+
if (!coderKeyExists) console.error(`[pi-harness] echo "{key}" > ${keysDir}/coder-api-key.txt`);
|
|
533
|
+
} else {
|
|
534
|
+
console.error(`[pi-harness] LangChain loop ready (${activeConfig.planner.id} [planner] + ${activeConfig.coder.id} [coder] + ${activeConfig.reviewer.id} [reviewer])`);
|
|
434
535
|
}
|
|
435
536
|
|
|
436
|
-
// All configured — register the /langchain command
|
|
437
537
|
pi.registerCommand("langchain", {
|
|
438
|
-
description:
|
|
439
|
-
"Run LangChain ping-pong loop: planner → coder → reviewer → fix → approve",
|
|
538
|
+
description: "Run LangChain ping-pong loop: planner → coder → reviewer → fix → approve",
|
|
440
539
|
prompt: "Describe the feature or task for the LangChain loop to implement.",
|
|
441
540
|
handler: async (request: string) => {
|
|
442
541
|
if (!request.trim()) {
|
|
@@ -445,18 +544,22 @@ function initLangChain(pi: {
|
|
|
445
544
|
return;
|
|
446
545
|
}
|
|
447
546
|
|
|
547
|
+
const cfg = loadActiveConfig();
|
|
548
|
+
if (!cfg) {
|
|
549
|
+
console.error("[pi-harness] /langchain: not configured. Run /langchain-config first.");
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
448
553
|
const env: Record<string, string> = { ...(process.env as Record<string, string>) };
|
|
449
554
|
env.PLANNER_API_KEY = readFileSync(`${keysDir}/planner-api-key.txt`, "utf8").trim();
|
|
450
555
|
env.GLM_API_KEY = readFileSync(`${keysDir}/reviewer-api-key.txt`, "utf8").trim();
|
|
451
556
|
env.MINIMAX_API_KEY = readFileSync(`${keysDir}/coder-api-key.txt`, "utf8").trim();
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
env.
|
|
455
|
-
env.
|
|
456
|
-
env.
|
|
457
|
-
env.
|
|
458
|
-
env.MINIMAX_MODEL = coderModel;
|
|
459
|
-
env.MINIMAX_BASE_URL = coderUrl;
|
|
557
|
+
env.PLANNER_MODEL = cfg.planner.id;
|
|
558
|
+
env.PLANNER_BASE_URL = cfg.planner.baseUrl;
|
|
559
|
+
env.GLM_MODEL = cfg.reviewer.id;
|
|
560
|
+
env.GLM_BASE_URL = cfg.reviewer.baseUrl;
|
|
561
|
+
env.MINIMAX_MODEL = cfg.coder.id;
|
|
562
|
+
env.MINIMAX_BASE_URL = cfg.coder.baseUrl;
|
|
460
563
|
|
|
461
564
|
if (existsSync(`${keysDir}/langsmith-api-key.txt`)) {
|
|
462
565
|
env.LANGSMITH_API_KEY = readFileSync(`${keysDir}/langsmith-api-key.txt`, "utf8").trim();
|
|
@@ -474,8 +577,6 @@ function initLangChain(pi: {
|
|
|
474
577
|
});
|
|
475
578
|
},
|
|
476
579
|
});
|
|
477
|
-
|
|
478
|
-
console.error(`[pi-harness] LangChain loop ready (${plannerModel} + ${reviewerModel} + ${coderModel})`);
|
|
479
580
|
}
|
|
480
581
|
|
|
481
582
|
// --- moocoding-sync-hint: Suggest syncing skills if skills dir is empty --------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.132",
|
|
4
4
|
"description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|