@piagent/platform 1.48.0 → 1.48.1

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/docs/command-reference-vietnamese.md +2 -2
  3. package/docs/distribution-standard.md +6 -6
  4. package/docs/operator-manual-vietnamese.md +7 -7
  5. package/docs/publishing-for-teams.md +1 -0
  6. package/docs/release-install-policy.md +2 -2
  7. package/docs/team-onboarding.md +2 -2
  8. package/docs-site/architecture.html +1 -1
  9. package/docs-site/assets/search-en.json +1 -1
  10. package/docs-site/assets/search-vi.json +1 -1
  11. package/docs-site/benchmark.html +1 -1
  12. package/docs-site/commands.html +1 -1
  13. package/docs-site/context-engine.html +1 -1
  14. package/docs-site/ecosystem.html +1 -1
  15. package/docs-site/en/architecture.html +1 -1
  16. package/docs-site/en/benchmark.html +1 -1
  17. package/docs-site/en/commands.html +1 -1
  18. package/docs-site/en/context-engine.html +1 -1
  19. package/docs-site/en/ecosystem.html +1 -1
  20. package/docs-site/en/index.html +9 -9
  21. package/docs-site/en/mcp-approval.html +1 -1
  22. package/docs-site/en/mcp-auth.html +1 -1
  23. package/docs-site/en/mcp-servers.html +1 -1
  24. package/docs-site/en/mcp.html +1 -1
  25. package/docs-site/en/permissions.html +1 -1
  26. package/docs-site/en/profiles.html +1 -1
  27. package/docs-site/en/quickstart.html +1 -1
  28. package/docs-site/en/runtime.html +1 -1
  29. package/docs-site/en/scope.html +1 -1
  30. package/docs-site/en/security.html +1 -1
  31. package/docs-site/en/team.html +1 -1
  32. package/docs-site/en/update.html +3 -3
  33. package/docs-site/en/whats-new.html +28 -16
  34. package/docs-site/en/windows.html +1 -1
  35. package/docs-site/en/workflows.html +1 -1
  36. package/docs-site/index.html +9 -9
  37. package/docs-site/mcp-approval.html +1 -1
  38. package/docs-site/mcp-auth.html +1 -1
  39. package/docs-site/mcp-servers.html +1 -1
  40. package/docs-site/mcp.html +1 -1
  41. package/docs-site/permissions.html +1 -1
  42. package/docs-site/profiles.html +1 -1
  43. package/docs-site/quickstart.html +1 -1
  44. package/docs-site/releases.json +36 -0
  45. package/docs-site/runtime.html +1 -1
  46. package/docs-site/scope.html +1 -1
  47. package/docs-site/security.html +1 -1
  48. package/docs-site/team.html +1 -1
  49. package/docs-site/update.html +3 -3
  50. package/docs-site/whats-new.html +28 -16
  51. package/docs-site/windows.html +1 -1
  52. package/docs-site/workflows.html +1 -1
  53. package/evals/private-holdout-v1/public-exposure.v2.json +1 -1
  54. package/package.json +1 -1
  55. package/packages/piagent-core/extensions/piagent-guard.ts +6 -1
  56. package/packages/piagent-core/package.json +1 -1
  57. package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +5 -1
  58. package/packages/piagent-core/runtime/solver/runtime-features.ts +52 -10
  59. package/packages/piagent-webui/gateway/session-inspection-registry.ts +9 -4
@@ -148,7 +148,7 @@ import { parentRoutingModeFromEnvironment, routingObjectiveFromEnvironment } fro
148
148
  import { ModelSelectionProvenanceTracker } from "../runtime/model/model-selection-provenance.ts";
149
149
  import type { TaskFeatures } from "../runtime/solver/solver-types.ts";
150
150
  import { planRetrievalRoute } from "../runtime/context/retrieval-route-policy.ts";
151
- import { evaluateRuntimeSolver } from "../runtime/solver/runtime-features.ts";
151
+ import { evaluateRuntimeSolver, refreshGitShape } from "../runtime/solver/runtime-features.ts";
152
152
  import { SolverShadowRuntime, solverModeFromEnvironment } from "../runtime/solver/solver-shadow.ts";
153
153
  import { TrajectoryRuntime } from "../runtime/trajectory/trajectory-runtime.ts";
154
154
  import { parseApplyPatchTargets, registerApplyPatchTool } from "../runtime/tools/apply-patch-tool.ts";
@@ -3386,6 +3386,11 @@ export default function piagentGuard(pi: ExtensionAPI) {
3386
3386
  });
3387
3387
  const runtimeSnapshotCapture = new RuntimeSnapshotCapture(), runtimeVersions = readRuntimeVersionMetadata(PLATFORM_ROOT);
3388
3388
  const solverShadow = solverMode === "off" ? undefined : new SolverShadowRuntime(solverMode);
3389
+ if (solverShadow) {
3390
+ // The solver's Git shape is read ahead of the prompt (runtime-features.ts).
3391
+ pi.on("session_start", (_event, ctx) => { void refreshGitShape(ctx.cwd); });
3392
+ pi.on("agent_settled", (_event, ctx) => { void refreshGitShape(ctx.cwd); });
3393
+ }
3389
3394
  const modelRouteRuntime = new ModelRouteRuntime(parentRoutingMode, routingObjective);
3390
3395
  const modelSelectionProvenance = new ModelSelectionProvenanceTracker();
3391
3396
  const serviceTierRuntime = new ServiceTierRuntime({ environmentValue: process.env.PIAGENT_FAST_MODE });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/core",
3
- "version": "1.48.0",
3
+ "version": "1.48.1",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -252,7 +252,11 @@ export class RuntimeEventStore {
252
252
  const flags = fs.constants.O_WRONLY | fs.constants.O_APPEND | (fs.constants.O_NOFOLLOW ?? 0)
253
253
  | (creating ? fs.constants.O_CREAT | fs.constants.O_EXCL : 0);
254
254
  const descriptor = fs.openSync(target, flags, 0o600);
255
- try { fs.writeFileSync(descriptor, `${JSON.stringify(event)}\n`); fs.fsyncSync(descriptor); fs.fchmodSync(descriptor, 0o600); } finally { fs.closeSync(descriptor); }
255
+ // No fsync: it ran for every event, Terminal sessions included, and three of
256
+ // them sat between Enter and the message showing. A store belongs to one
257
+ // runtime instance, and one left damaged by a power cut only sends the
258
+ // dashboard back to a snapshot (resyncRequired).
259
+ try { fs.writeFileSync(descriptor, `${JSON.stringify(event)}\n`); fs.fchmodSync(descriptor, 0o600); } finally { fs.closeSync(descriptor); }
256
260
  segment.count += 1; this.events.push(event); this.eventById.set(event.eventId, event);
257
261
  if (candidate) this.emissionGuard.recordAccepted(candidate);
258
262
  try { this.enforceRetention(); } catch { this.corruptions.push("event-retention-failed"); }
@@ -1,3 +1,5 @@
1
+ import { execFile } from "node:child_process";
2
+
1
3
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
4
 
3
5
  import { gitEvidenceRootDetails, workingTreeHasChanges } from "../../extensions/workspace-evidence-roots.js";
@@ -8,17 +10,57 @@ import type { TaskFeatureInput } from "./task-features.ts";
8
10
  import type { SolverShadowEvaluation } from "./solver-shadow.ts";
9
11
  import { SolverShadowRuntime } from "./solver-shadow.ts";
10
12
 
11
- // Finding the repositories under a parent folder runs Git once per child and
12
- // blocks the terminal; they rarely change between two prompts.
13
- const ROOTS_TTL_MS = 30_000;
14
- const rootDetails = new Map<string, { at: number; details: ReturnType<typeof gitEvidenceRootDetails> }>();
15
- function gitShape(cwd: string): { gitReady: boolean; dirtyTree: boolean } {
16
- let cached = rootDetails.get(cwd);
17
- if (!cached || Date.now() - cached.at > ROOTS_TTL_MS) {
18
- try { cached = { at: Date.now(), details: gitEvidenceRootDetails(cwd) }; } catch { return { gitReady: false, dirtyTree: true }; }
19
- rootDetails.set(cwd, cached);
13
+ type GitShape = { gitReady: boolean; dirtyTree: boolean };
14
+
15
+ function readGitShape(cwd: string): GitShape {
16
+ try {
17
+ const details = gitEvidenceRootDetails(cwd);
18
+ return { gitReady: details.roots.length > 0, dirtyTree: workingTreeHasChanges(cwd, details) };
19
+ } catch { return { gitReady: false, dirtyTree: true }; }
20
+ }
21
+
22
+ // The Git shape runs `git rev-parse` (once per child repository in a parent
23
+ // folder) and `git status`. Read synchronously on every prompt it held the
24
+ // Terminal between Enter and the message showing, longer the larger the
25
+ // repository. It is now read in a child process when the session starts and
26
+ // after each run, and a prompt takes the last answer. Only a prompt with no
27
+ // answer yet reads it inline, as before.
28
+ const SHAPE_FRESH_MS = 5_000;
29
+ const SHAPE_PROBE = `import(${JSON.stringify(new URL("../../extensions/workspace-evidence-roots.js", import.meta.url).href)}).then((git) => {
30
+ let shape; try { const details = git.gitEvidenceRootDetails(process.argv[1]);
31
+ shape = { gitReady: details.roots.length > 0, dirtyTree: git.workingTreeHasChanges(process.argv[1], details) };
32
+ } catch { shape = { gitReady: false, dirtyTree: true }; }
33
+ process.stdout.write(JSON.stringify(shape));
34
+ });`;
35
+ const shapes = new Map<string, { at: number; shape: GitShape }>();
36
+ const probing = new Map<string, Promise<void>>();
37
+
38
+ export function refreshGitShape(cwd: string): Promise<void> {
39
+ const running = probing.get(cwd);
40
+ if (running) return running;
41
+ const startedAt = Date.now();
42
+ const probe = new Promise<void>((resolve) => {
43
+ execFile(process.execPath, ["--input-type=module", "-e", SHAPE_PROBE, cwd], { timeout: 60_000, maxBuffer: 4096, windowsHide: true }, (error, stdout) => {
44
+ try {
45
+ const shape = JSON.parse(String(stdout)) as GitShape;
46
+ if (!error && typeof shape.gitReady === "boolean" && typeof shape.dirtyTree === "boolean") shapes.set(cwd, { at: startedAt, shape });
47
+ } catch { /* the next prompt reads it inline */ }
48
+ resolve();
49
+ });
50
+ }).finally(() => probing.delete(cwd));
51
+ probing.set(cwd, probe);
52
+ return probe;
53
+ }
54
+
55
+ function gitShape(cwd: string): GitShape {
56
+ const cached = shapes.get(cwd);
57
+ if (!cached) {
58
+ const shape = readGitShape(cwd);
59
+ shapes.set(cwd, { at: Date.now(), shape });
60
+ return shape;
20
61
  }
21
- return { gitReady: cached.details.roots.length > 0, dirtyTree: workingTreeHasChanges(cwd, cached.details) };
62
+ if (Date.now() - cached.at > SHAPE_FRESH_MS) void refreshGitShape(cwd);
63
+ return cached.shape;
22
64
  }
23
65
 
24
66
  export function runtimeTaskFeatureInput(options: {
@@ -249,13 +249,18 @@ export class SessionInspectionRegistry {
249
249
  ...(provider === "agent_watch_managed" && value.managedFast === true ? { managedFast: true } : {}),
250
250
  ...(provider === "agent_watch_managed" && value.managedBypass === true ? { managedBypass: true } : {}) }];
251
251
  });
252
- // Only offer a default present in the authenticated host catalog. Retain
253
- // the previous Sol baseline for accounts that have not received GPT-6 yet.
252
+ // A new conversation starts where the Terminal does: the model and thinking
253
+ // level Pi keeps in settings.json (the last ones chosen with /model). Only
254
+ // a default present in the authenticated host catalog is offered; an account
255
+ // that set none gets the Sol baseline (GPT-5.6 before GPT-6 reached it).
254
256
  const managed = models.length === 1 && models[0].provider === 'agent_watch_managed';
255
- const defaultModel = managed ? models[0] : ["gpt-6-sol", "gpt-5.6-sol"].map((id) => models.find((value) => value.provider === "openai-codex" && value.modelId === id)).find(Boolean);
257
+ const settings = this.#agentDir ? safeRead(() => JSON.parse(fs.readFileSync(path.join(this.#agentDir!, "settings.json"), "utf8")) as Record<string, unknown>, {}) : {};
258
+ const chosen = models.find((value) => value.provider === settings.defaultProvider && value.modelId === settings.defaultModel);
259
+ const defaultModel = managed ? models[0] : chosen ?? ["gpt-6-sol", "gpt-5.6-sol"].map((id) => models.find((value) => value.provider === "openai-codex" && value.modelId === id)).find(Boolean);
260
+ const chosenThinking = !managed && typeof settings.defaultThinkingLevel === "string" && defaultModel?.thinkingLevels.includes(settings.defaultThinkingLevel) ? settings.defaultThinkingLevel : null;
256
261
  return { schemaVersion: 1, version: "piagent-session-creation-options-v1", generatedAt: new Date().toISOString(),
257
262
  projects: [...projects.values()].slice(0, 200), models,
258
- defaultModelRef: defaultModel?.modelRef ?? null, defaultThinkingLevel: defaultModel ? (defaultModel.thinkingLevels.includes("high") ? "high" : defaultModel.thinkingLevels[0] ?? null) : null,
263
+ defaultModelRef: defaultModel?.modelRef ?? null, defaultThinkingLevel: defaultModel ? chosenThinking ?? (defaultModel.thinkingLevels.includes("high") ? "high" : defaultModel.thinkingLevels[0] ?? null) : null,
259
264
  profiles: managed ? [] : profiles, workflows: [],
260
265
  runtimeActions: managed ? [] : WEBUI_RUNTIME_ACTIONS,
261
266
  webSearch: inspectWebSearchCapability({ agentDir: this.#agentDir, models: availableModels }),