@piagent/platform 1.46.1 → 1.46.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 (58) hide show
  1. package/CHANGELOG.md +16 -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 +27 -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 +31 -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 +27 -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 +4 -1
  56. package/packages/piagent-core/package.json +1 -1
  57. package/packages/piagent-core/runtime/hooks/session-hooks.ts +6 -0
  58. package/packages/piagent-webui/gateway/gateway-session-stream.ts +24 -0
@@ -25,6 +25,9 @@ type SessionHookDependencies = {
25
25
  ) => TaskContract | undefined;
26
26
  onTurnEnd?: (ctx: ExtensionContext) => void;
27
27
  onAgentSettled?: (ctx: ExtensionContext) => void | Promise<void>;
28
+ // Display-only work after settlement. Pi takes the next message only when
29
+ // agent_settled handlers return, so this runs without holding the host.
30
+ afterAgentSettled?: (ctx: ExtensionContext) => void | Promise<void>;
28
31
  beforeShutdown?: (ctx: ExtensionContext) => void | Promise<void>;
29
32
  };
30
33
 
@@ -103,6 +106,9 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
103
106
  taskOutcome: task?.trace.outcome
104
107
  });
105
108
  await dependencies.onAgentSettled?.(ctx);
109
+ if (dependencies.afterAgentSettled) {
110
+ void Promise.resolve().then(() => dependencies.afterAgentSettled?.(ctx)).catch(() => undefined);
111
+ }
106
112
  });
107
113
 
108
114
  pi.on("session_compact", async (event, ctx) => {
@@ -13,6 +13,16 @@ const MAX_EVENTS = 128;
13
13
  const MAX_DELTA = 16_384;
14
14
  const PRIVATE_BEGIN = /-----BEGIN [A-Z ]*PRIVATE KEY-----/;
15
15
  const PRIVATE_END = /-----END [A-Z ]*PRIVATE KEY-----/;
16
+ // Within a line, text goes out as it arrives except its last words: a secret
17
+ // written over several words ("Authorization: Basic …", "password: …",
18
+ // "--token …") is then whole on one side of every cut.
19
+ const HELD_WORDS = 6;
20
+ // A key whose quoted value has not closed yet (`password = "two words…`).
21
+ const OPEN_QUOTED_VALUE = /(?:(?::=|:|=)\s*|--[A-Za-z][A-Za-z0-9_.-]*\s+)(["'])(?:(?!\1)[^\r\n])*$/;
22
+ // Pieces of a line share MAX_EVENTS with whole lines: they grow as the
23
+ // operation's events are spent, and stop leaving whole lines a reserve.
24
+ const PIECE_EVENTS = 96;
25
+ const PIECE_MIN_CHARS = 24;
16
26
  const RUNTIME_DRIFT = /Installed Piagent runtime changed (?:during this session|while the capability lock was being re-pinned)/i;
17
27
  const COMPLETION_GATE = /^\[Piagent completion gate: (CONTINUING|NOT APPROVED)\]/i;
18
28
 
@@ -327,6 +337,7 @@ export class GatewaySessionStream {
327
337
  const space = this.#buffer.search(/\s\S*$/);
328
338
  take = space >= 0 ? space + 1 : this.#buffer.length >= 16_384 ? this.#buffer.length : 0;
329
339
  }
340
+ if (take <= 0 && !final) take = this.#pieceEnd();
330
341
  if (take <= 0) return;
331
342
  const candidate = this.#buffer.slice(0, take), privateStart = candidate.search(PRIVATE_BEGIN);
332
343
  if (privateStart >= 0 && !PRIVATE_END.test(candidate.slice(privateStart))) {
@@ -341,6 +352,19 @@ export class GatewaySessionStream {
341
352
  this.#emit(redactSensitiveText(clean(source)).text);
342
353
  }
343
354
 
355
+ #pieceEnd(): number {
356
+ if (this.#eventCount >= PIECE_EVENTS) return 0;
357
+ const line = this.#buffer, words = [...line.matchAll(/\s+(?=\S)/g)];
358
+ if (words.length < HELD_WORDS) return 0;
359
+ const word = words[words.length - HELD_WORDS]!, end = word.index + word[0].length;
360
+ if (end < PIECE_MIN_CHARS * 2 ** Math.floor(this.#eventCount / 32)) return 0;
361
+ // Wait for the quote to close: its words would otherwise leave the key.
362
+ if (OPEN_QUOTED_VALUE.test(line)) return 0;
363
+ const head = line.slice(0, end), tail = line.slice(end);
364
+ // The cut must not change what redaction finds in the text known so far.
365
+ return redactSensitiveText(head).text + redactSensitiveText(tail).text === redactSensitiveText(line).text ? end : 0;
366
+ }
367
+
344
368
  #emit(value: string): void {
345
369
  for (let offset = 0; offset < value.length; offset += MAX_DELTA) {
346
370
  if (this.#eventCount >= MAX_EVENTS) { this.#truncated = true; break; }