pi-harness-runtime 1.1.130 → 1.1.131
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 +157 -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,173 @@ 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 first to assign model roles");
|
|
527
|
+
} else if (!plannerKeyExists || !reviewerKeyExists || !coderKeyExists) {
|
|
429
528
|
console.error("[pi-harness] LangChain loop: API keys missing:");
|
|
430
|
-
if (!
|
|
431
|
-
if (!
|
|
432
|
-
if (!
|
|
433
|
-
|
|
529
|
+
if (!plannerKeyExists) console.error(`[pi-harness] echo "{key}" > ${keysDir}/planner-api-key.txt`);
|
|
530
|
+
if (!reviewerKeyExists) console.error(`[pi-harness] echo "{key}" > ${keysDir}/reviewer-api-key.txt`);
|
|
531
|
+
if (!coderKeyExists) console.error(`[pi-harness] echo "{key}" > ${keysDir}/coder-api-key.txt`);
|
|
532
|
+
} else {
|
|
533
|
+
console.error(`[pi-harness] LangChain loop ready (${activeConfig.planner.id} [planner] + ${activeConfig.coder.id} [coder] + ${activeConfig.reviewer.id} [reviewer])`);
|
|
434
534
|
}
|
|
435
535
|
|
|
436
|
-
// All configured — register the /langchain command
|
|
437
536
|
pi.registerCommand("langchain", {
|
|
438
|
-
description:
|
|
439
|
-
"Run LangChain ping-pong loop: planner → coder → reviewer → fix → approve",
|
|
537
|
+
description: "Run LangChain ping-pong loop: planner → coder → reviewer → fix → approve",
|
|
440
538
|
prompt: "Describe the feature or task for the LangChain loop to implement.",
|
|
441
539
|
handler: async (request: string) => {
|
|
442
540
|
if (!request.trim()) {
|
|
@@ -445,18 +543,22 @@ function initLangChain(pi: {
|
|
|
445
543
|
return;
|
|
446
544
|
}
|
|
447
545
|
|
|
546
|
+
const cfg = loadActiveConfig();
|
|
547
|
+
if (!cfg) {
|
|
548
|
+
console.error("[pi-harness] /langchain: not configured. Run /langchain-config first.");
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
448
552
|
const env: Record<string, string> = { ...(process.env as Record<string, string>) };
|
|
449
553
|
env.PLANNER_API_KEY = readFileSync(`${keysDir}/planner-api-key.txt`, "utf8").trim();
|
|
450
554
|
env.GLM_API_KEY = readFileSync(`${keysDir}/reviewer-api-key.txt`, "utf8").trim();
|
|
451
555
|
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;
|
|
556
|
+
env.PLANNER_MODEL = cfg.planner.id;
|
|
557
|
+
env.PLANNER_BASE_URL = cfg.planner.baseUrl;
|
|
558
|
+
env.GLM_MODEL = cfg.reviewer.id;
|
|
559
|
+
env.GLM_BASE_URL = cfg.reviewer.baseUrl;
|
|
560
|
+
env.MINIMAX_MODEL = cfg.coder.id;
|
|
561
|
+
env.MINIMAX_BASE_URL = cfg.coder.baseUrl;
|
|
460
562
|
|
|
461
563
|
if (existsSync(`${keysDir}/langsmith-api-key.txt`)) {
|
|
462
564
|
env.LANGSMITH_API_KEY = readFileSync(`${keysDir}/langsmith-api-key.txt`, "utf8").trim();
|
|
@@ -474,8 +576,6 @@ function initLangChain(pi: {
|
|
|
474
576
|
});
|
|
475
577
|
},
|
|
476
578
|
});
|
|
477
|
-
|
|
478
|
-
console.error(`[pi-harness] LangChain loop ready (${plannerModel} + ${reviewerModel} + ${coderModel})`);
|
|
479
579
|
}
|
|
480
580
|
|
|
481
581
|
// --- 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.131",
|
|
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",
|