@piagent/platform 1.15.0 → 1.15.2

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 (75) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +1 -1
  3. package/README.vi.md +1 -1
  4. package/docs/command-reference-vietnamese.md +2 -2
  5. package/docs/distribution-standard.md +6 -6
  6. package/docs/languages.json +2 -2
  7. package/docs/operator-manual-vietnamese.md +7 -7
  8. package/docs/publishing-for-teams.md +2 -0
  9. package/docs/release-install-policy.md +2 -2
  10. package/docs/team-onboarding.md +2 -2
  11. package/docs-site/architecture.html +1 -1
  12. package/docs-site/benchmark.html +1 -1
  13. package/docs-site/commands.html +1 -1
  14. package/docs-site/content/en/index.html +4 -4
  15. package/docs-site/content/en/whats-new.html +23 -0
  16. package/docs-site/content/index.html +4 -4
  17. package/docs-site/content/whats-new.html +23 -0
  18. package/docs-site/context-engine.html +1 -1
  19. package/docs-site/ecosystem.html +1 -1
  20. package/docs-site/en/architecture.html +1 -1
  21. package/docs-site/en/benchmark.html +1 -1
  22. package/docs-site/en/commands.html +1 -1
  23. package/docs-site/en/context-engine.html +1 -1
  24. package/docs-site/en/ecosystem.html +1 -1
  25. package/docs-site/en/index.html +5 -5
  26. package/docs-site/en/mcp-approval.html +1 -1
  27. package/docs-site/en/mcp-auth.html +1 -1
  28. package/docs-site/en/mcp-servers.html +1 -1
  29. package/docs-site/en/mcp.html +1 -1
  30. package/docs-site/en/permissions.html +1 -1
  31. package/docs-site/en/profiles.html +1 -1
  32. package/docs-site/en/quickstart.html +1 -1
  33. package/docs-site/en/runtime.html +1 -1
  34. package/docs-site/en/scope.html +1 -1
  35. package/docs-site/en/security.html +1 -1
  36. package/docs-site/en/team.html +1 -1
  37. package/docs-site/en/whats-new.html +24 -1
  38. package/docs-site/en/windows.html +1 -1
  39. package/docs-site/en/workflows.html +1 -1
  40. package/docs-site/index.html +5 -5
  41. package/docs-site/mcp-approval.html +1 -1
  42. package/docs-site/mcp-auth.html +1 -1
  43. package/docs-site/mcp-servers.html +1 -1
  44. package/docs-site/mcp.html +1 -1
  45. package/docs-site/permissions.html +1 -1
  46. package/docs-site/profiles.html +1 -1
  47. package/docs-site/quickstart.html +1 -1
  48. package/docs-site/runtime.html +1 -1
  49. package/docs-site/scope.html +1 -1
  50. package/docs-site/security.html +1 -1
  51. package/docs-site/team.html +1 -1
  52. package/docs-site/whats-new.html +24 -1
  53. package/docs-site/windows.html +1 -1
  54. package/docs-site/workflows.html +1 -1
  55. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  56. package/package.json +1 -1
  57. package/packages/piagent-core/managed/call-purpose.mjs +49 -0
  58. package/packages/piagent-core/managed/compaction.mjs +47 -1
  59. package/packages/piagent-core/managed/helper-roles.mjs +7 -3
  60. package/packages/piagent-core/managed/helper-run.mjs +6 -3
  61. package/packages/piagent-core/managed/patch-snapshot.mjs +29 -7
  62. package/packages/piagent-core/managed/request-stream.mjs +12 -1
  63. package/packages/piagent-core/managed/review-snapshot-worker.mjs +27 -3
  64. package/packages/piagent-core/managed/sandbox-diagnostic.mjs +4 -1
  65. package/packages/piagent-core/managed/session.mjs +42 -13
  66. package/packages/piagent-core/managed/web-search.mjs +1 -1
  67. package/packages/piagent-core/managed/workflow.mjs +19 -5
  68. package/packages/piagent-core/package.json +1 -1
  69. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-PIk4Femi.js → MarkdownMessage-DjA3OGyI.js} +1 -1
  70. package/packages/piagent-webui/dist/client/assets/{index-DeCt-FaN.js → index-bE2DKmc1.js} +4 -4
  71. package/packages/piagent-webui/dist/client/index.html +1 -1
  72. package/packages/piagent-webui/gateway/session-command-controller.ts +11 -0
  73. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +2 -2
  74. package/packages/piagent-webui/ownership/session-lease-store.ts +20 -1
  75. package/scripts/piagent-cli.mjs +5 -1
@@ -7,7 +7,7 @@
7
7
  <meta name="csp-nonce" content="__PIAGENT_CSP_NONCE__" />
8
8
  <meta name="piagent-webui-mode" content="__PIAGENT_WEBUI_MODE__" />
9
9
  <title>Piagent WebUI</title>
10
- <script type="module" crossorigin src="/assets/index-DeCt-FaN.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-bE2DKmc1.js"></script>
11
11
  <link rel="stylesheet" crossorigin href="/assets/index-Z91z6SlN.css">
12
12
  </head>
13
13
  <body>
@@ -1,4 +1,5 @@
1
1
  import { randomBytes } from "node:crypto";
2
+ import { parseFailure } from "../../piagent-core/runtime/managed-failure.mjs";
2
3
 
3
4
  import type { Catalog, SessionRow } from "../contracts/generated/session-catalog-v1.ts";
4
5
  import type { Receipt } from "../contracts/generated/session-command-v1.ts";
@@ -279,6 +280,16 @@ export class SessionCommandController {
279
280
  try { if (noDispatchEffect) attachmentReservation.release(); else attachmentReservation.commit(); }
280
281
  catch { /* an attempted dispatch with an unprovable reservation remains uncertain */ }
281
282
  }
283
+ // The company runtime of a new or reopened conversation did not open
284
+ // (key, harness, Agent Watch helper): nothing was sent. Say why, by
285
+ // its kind, rather than "resyncing" or a bare "could not restart".
286
+ const company = ["session.create", "session.acquire"].includes(command.action) && /^managed-[a-z]/.test(message) ? parseFailure(message) : null;
287
+ if (company && company.code !== "managed-request-failed") {
288
+ const receipt = this.#rejected(command, after, afterRow, "unavailable", `company-${company.kind}`);
289
+ try { this.#store.settle(command, receipt, this.#now()); } catch { /* intent remains uncertain */ }
290
+ if (command.action === "session.create" && afterRow) this.#events.publish("session.changed", { catalogRevision: after.catalogRevision, session: afterRow });
291
+ return receipt;
292
+ }
282
293
  const code = /recovery/.test(message) ? "recovery-required"
283
294
  : /(owner-conflict|operation-conflict|runtime-busy)/.test(message) ? "owner-conflict"
284
295
  : noDispatchEffect || command.action === "session.send" && !sendAttempted ? "unavailable" : "effect-unknown";
@@ -133,7 +133,7 @@ export class SessionRuntimeSupervisor {
133
133
  const runtimeInstanceRef = `runtime_${randomBytes(24).toString("base64url")}`;
134
134
  const prior = this.#leases.inspect(sessionRef);
135
135
  if (prior.state === "gateway-owned" || prior.state === "terminal-owned" || prior.state === "recovery-required") {
136
- try { this.#leases.releaseDeadOwnerForExplicitRecovery(sessionRef); } catch { /* live or unprovable owners stay authoritative */ }
136
+ try { this.#leases.releaseDeadOwnerForExplicitRecovery(sessionRef, new Date(), this.#gatewayInstanceRef); } catch { /* live or unprovable owners stay authoritative */ }
137
137
  }
138
138
  const lease = this.#leases.acquire(sessionRef, this.#gatewayInstanceRef, runtimeInstanceRef);
139
139
  try {
@@ -161,7 +161,7 @@ export class SessionRuntimeSupervisor {
161
161
  const active = this.#active.get(sessionRef);
162
162
  if (!active) {
163
163
  const current = this.#leases.inspect(sessionRef);
164
- if (current.state === "released") return current;
164
+ if (current.state === "released" || current.state === "recovery-required" && current.gatewayInstanceRef === this.#gatewayInstanceRef) return this.#leases.releaseOwnRecovery(sessionRef, this.#gatewayInstanceRef);
165
165
  throw new Error(current.state === "recovery-required" ? "session-recovery-required" : "session-owner-conflict");
166
166
  }
167
167
  if (active.operationRef) throw new Error("session-runtime-busy");
@@ -253,8 +253,10 @@ export class SessionLeaseStore {
253
253
  return this.#acquireOwner(sessionRef, gatewayInstanceRef, runtimeInstanceRef, now);
254
254
  }
255
255
 
256
- releaseDeadOwnerForExplicitRecovery(sessionRef: string, now = new Date()): SessionLeaseSnapshot {
256
+ // `ownGateway`: the calling Gateway, whose own recovery it may release.
257
+ releaseDeadOwnerForExplicitRecovery(sessionRef: string, now = new Date(), ownGateway?: string): SessionLeaseSnapshot {
257
258
  if (!Number.isFinite(now.getTime())) throw new Error("session-lease-input-invalid");
259
+ if (ownGateway && this.inspect(sessionRef).state === "recovery-required" && this.inspect(sessionRef).gatewayInstanceRef === ownGateway) return this.releaseOwnRecovery(sessionRef, ownGateway, now);
258
260
  return this.#withMutationLock(sessionRef, () => {
259
261
  const current = this.inspect(sessionRef);
260
262
  const terminalOwner = current.state === "terminal-owned"
@@ -329,6 +331,23 @@ export class SessionLeaseStore {
329
331
  });
330
332
  }
331
333
 
334
+ // A Gateway whose own runtime failed to open or to close left the lease in
335
+ // recovery under its own name. Nothing of it runs (the Gateway knows its
336
+ // live runtimes), so that Gateway may release it: archiving or reopening
337
+ // must not wait for the Gateway itself to exit. Another owner's recovery
338
+ // still needs proof that the owner is gone.
339
+ releaseOwnRecovery(sessionRef: string, gatewayInstanceRef: string, now = new Date()): SessionLeaseSnapshot {
340
+ if (!validRef(gatewayInstanceRef) || gatewayInstanceRef.startsWith(TERMINAL_OWNER_PREFIX) || !Number.isFinite(now.getTime())) throw new Error("session-lease-input-invalid");
341
+ return this.#withMutationLock(sessionRef, () => {
342
+ const current = this.inspect(sessionRef);
343
+ if (current.state === "released") return current;
344
+ if (current.state !== "recovery-required" || current.gatewayInstanceRef !== gatewayInstanceRef) throw new Error("session-recovery-required");
345
+ this.#append(sessionRef, { recordedAt: now.toISOString(), sessionRef, event: "released", ownerEpoch: current.ownerEpoch!,
346
+ gatewayInstanceRef, runtimeInstanceRef: current.runtimeInstanceRef!, reasonCode: null });
347
+ return this.inspect(sessionRef);
348
+ });
349
+ }
350
+
332
351
  requireRecovery(sessionRef: string, ownerEpoch: string, gatewayInstanceRef: string, runtimeInstanceRef: string,
333
352
  reasonCode: string, now = new Date()): SessionLeaseSnapshot {
334
353
  if (!validRef(reasonCode)) throw new Error("session-lease-reason-invalid");
@@ -51,6 +51,10 @@ if (invokedAs === "piagent") {
51
51
  } else if (subcommand === "select-verification") {
52
52
  script = "scripts/select-independent-verification.mjs";
53
53
  forwardedArgs = forwardedArgs.slice(1);
54
+ } else if (subcommand && Object.hasOwn(scriptByCommand, `piagent-${subcommand}`)) {
55
+ // `piagent doctor` is `piagent-doctor`: members type it both ways.
56
+ script = scriptByCommand[`piagent-${subcommand}`];
57
+ forwardedArgs = forwardedArgs.slice(1);
54
58
  } else if ([undefined, "help", "--help", "-h"].includes(subcommand)) {
55
59
  // Subcommands are listed, their flags are not. Restating them here meant a
56
60
  // second copy that drifts: this line still advertised the dashboard without
@@ -70,7 +74,7 @@ if (invokedAs === "piagent") {
70
74
  }
71
75
 
72
76
  if (!script) {
73
- console.error(`Unknown Pi Agent command: ${invokedAs || "(unknown)"}`);
77
+ console.error(`Unknown Pi Agent command: ${[invokedAs || "(unknown)", invokedAs === "piagent" ? forwardedArgs[0] : ""].filter(Boolean).join(" ")}`);
74
78
  console.error(`Expected one of: ${Object.keys(scriptByCommand).sort().join(", ")}`);
75
79
  process.exit(2);
76
80
  }