@piagent/platform 1.28.3 → 1.29.0

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 (63) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -1
  3. package/README.vi.md +1 -1
  4. package/docs/command-reference-vietnamese.md +4 -2
  5. package/docs/company-dev-commands.md +6 -0
  6. package/docs/distribution-standard.md +6 -6
  7. package/docs/languages.json +2 -2
  8. package/docs/operator-manual-vietnamese.md +7 -7
  9. package/docs/publishing-for-teams.md +1 -0
  10. package/docs/release-install-policy.md +2 -2
  11. package/docs/team-onboarding.md +2 -2
  12. package/docs-site/architecture.html +1 -1
  13. package/docs-site/benchmark.html +1 -1
  14. package/docs-site/commands.html +1 -1
  15. package/docs-site/content/en/index.html +4 -4
  16. package/docs-site/content/en/whats-new.html +6 -0
  17. package/docs-site/content/index.html +4 -4
  18. package/docs-site/content/whats-new.html +6 -0
  19. package/docs-site/context-engine.html +1 -1
  20. package/docs-site/ecosystem.html +1 -1
  21. package/docs-site/en/architecture.html +1 -1
  22. package/docs-site/en/benchmark.html +1 -1
  23. package/docs-site/en/commands.html +1 -1
  24. package/docs-site/en/context-engine.html +1 -1
  25. package/docs-site/en/ecosystem.html +1 -1
  26. package/docs-site/en/index.html +5 -5
  27. package/docs-site/en/mcp-approval.html +1 -1
  28. package/docs-site/en/mcp-auth.html +1 -1
  29. package/docs-site/en/mcp-servers.html +1 -1
  30. package/docs-site/en/mcp.html +1 -1
  31. package/docs-site/en/permissions.html +1 -1
  32. package/docs-site/en/profiles.html +1 -1
  33. package/docs-site/en/quickstart.html +1 -1
  34. package/docs-site/en/runtime.html +1 -1
  35. package/docs-site/en/scope.html +1 -1
  36. package/docs-site/en/security.html +1 -1
  37. package/docs-site/en/team.html +1 -1
  38. package/docs-site/en/whats-new.html +7 -1
  39. package/docs-site/en/windows.html +1 -1
  40. package/docs-site/en/workflows.html +1 -1
  41. package/docs-site/index.html +5 -5
  42. package/docs-site/mcp-approval.html +1 -1
  43. package/docs-site/mcp-auth.html +1 -1
  44. package/docs-site/mcp-servers.html +1 -1
  45. package/docs-site/mcp.html +1 -1
  46. package/docs-site/permissions.html +1 -1
  47. package/docs-site/profiles.html +1 -1
  48. package/docs-site/quickstart.html +1 -1
  49. package/docs-site/runtime.html +1 -1
  50. package/docs-site/scope.html +1 -1
  51. package/docs-site/security.html +1 -1
  52. package/docs-site/team.html +1 -1
  53. package/docs-site/whats-new.html +7 -1
  54. package/docs-site/windows.html +1 -1
  55. package/docs-site/workflows.html +1 -1
  56. package/evals/private-holdout-v1/public-exposure.v2.json +1 -1
  57. package/package.json +1 -1
  58. package/packages/piagent-core/managed/memory.mjs +3 -0
  59. package/packages/piagent-core/managed/request-stream.mjs +4 -0
  60. package/packages/piagent-core/managed/session.mjs +2 -2
  61. package/packages/piagent-core/package.json +1 -1
  62. package/scripts/company-terminal.mjs +192 -0
  63. package/scripts/piagent-studio.mjs +11 -3
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/runtime" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/runtime" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/scope" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/scope" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/security" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/security" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/team" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/team" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/whats-new" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/whats-new" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -104,6 +104,12 @@
104
104
  <h1>1.9.0: ask in plain language, the team's Harness checks</h1>
105
105
  <p>The task contract and workflow commands are gone. Company mode asks for checks and a review on its own; Stop, network commands on approval and clearer approval cards.</p>
106
106
  </div>
107
+ <section class="section">
108
+ <p class="section-kicker">v1.29.0 · 2026-10-18</p>
109
+ <h2 id="v1-29-0">The company Terminal gets its own look; Stop no longer breaks the conversation</h2>
110
+ <p class="section-lead">The company Terminal (<span class="inline-code">piagent studio</span>) has its own header: team, Harness model and effort, permission, Fast, memory. The footer shows the real effort and no USD cost, the plan is a checklist, and while it waits for your answer it says so. <span class="inline-code">/share</span> and <span class="inline-code">/bug</span> are refused because they send company conversations outside; <span class="inline-code">/login</span>, <span class="inline-code">/model</span>, <span class="inline-code">/thinking</span>… say the team’s Harness decides. Stopping a turn while a command runs no longer breaks the next one (with Agent Studio 0.28.1, Agent Watch 0.15.7).</p>
111
+ </section>
112
+
107
113
  <section class="section">
108
114
  <p class="section-kicker">v1.28.3 · 2026-10-18</p>
109
115
  <h2 id="v1-28-3">Agent Watch updating itself no longer interrupts the company Terminal</h2>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/windows" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/windows" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · EN</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · EN</span>
34
34
  <nav class="language-switch" aria-label="Language">
35
35
  <a class="language-option" href="/workflows" hreflang="vi" lang="vi">VI</a>
36
36
  <a class="language-option current" href="/en/workflows" hreflang="en" lang="en" aria-current="true">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/" hreflang="en" lang="en">EN</a>
@@ -94,7 +94,7 @@
94
94
  <main>
95
95
  <div class="content-shell" data-article>
96
96
  <section class="hero">
97
- <p class="eyebrow">Piagent 1.28.3</p>
97
+ <p class="eyebrow">Piagent 1.29.0</p>
98
98
  <h1>Coding agent cho cả team, kiểm tra từng bước.</h1>
99
99
  <p>
100
100
  Một dashboard cho Terminal và trình duyệt. Dùng model bằng tài khoản của bạn, hoặc model của công ty qua Agent Watch và Agent Studio. Guard kiểm tra từng tool call; ở chế độ công ty, Harness của team tự yêu cầu chạy check, cho subagent review và báo kết quả ngay dưới câu trả lời.
@@ -108,7 +108,7 @@
108
108
  <div class="hero-actions">
109
109
  <a class="button primary" href="/quickstart">Bắt đầu</a>
110
110
  <a class="button" href="/ecosystem">Hệ sinh thái</a>
111
- <a class="button" href="/whats-new">Có gì mới trong 1.28.3</a>
111
+ <a class="button" href="/whats-new">Có gì mới trong 1.29.0</a>
112
112
  <a class="button" href="/commands">Xem command</a>
113
113
  </div>
114
114
  </section>
@@ -184,9 +184,9 @@ piagent-setup</code></pre>
184
184
  <h2 id="bat-dau-tu-dau">Bắt đầu từ đâu</h2>
185
185
  <div class="card-grid">
186
186
  <a class="doc-card" href="/whats-new">
187
- <span class="card-kicker">Bản 1.28.3</span>
187
+ <span class="card-kicker">Bản 1.29.0</span>
188
188
  <h3>Có gì mới</h3>
189
- <p>Agent Watch tự cập nhật không còn làm gián đoạn Terminal công ty; ở 1.28.2: không còn lỗi “binding changed” ngay sau khi cập nhật; ở 1.28.1: Terminal công ty và Pi cá nhân không còn giẫm chân nhau (không nạp Piagent hai lần, dọn cấu hình công ty cũ, cuộc trò chuyện công ty chỉ mở bằng piagent studio); ở 1.28.0: team memory v2; ở 1.27.1: team memory chạy ổn cả khi agent đang gọi model; ở 1.27.0: team memory, agent công ty nhớ quyết định và quy tắc của team trong từng repo; ở 1.26.1: đổi tên cuộc trò chuyện được cả khi lượt đang chạy; ở 1.26.0: lệnh / và phím tắt của Terminal ngay trên dashboard, /undo hoàn tác lượt trước của agent, dev server chạy qua nhiều lượt; ở 1.25.0: thiếu môi trường thì agent xin quyền và chạy được sau khi bạn duyệt (run_on_host ngoài sandbox, start_docker mở Docker ngay trong cuộc trò chuyện); ở 1.24.0: chọn Fast ngay trên trang tạo cuộc trò chuyện công ty, nút Fast đổi màu vàng khi đang bật; ở 1.23.1: câu hỏi của agent luôn nằm cuối cuộc trò chuyện, ngay trên ô nhập, và dễ đọc hơn; ở 1.23.0: nút Fast cho cuộc trò chuyện công ty khi Harness cho phép, tool lỗi được báo về Studio (Logs → Tool lỗi), cuộc trò chuyện mới gửi được tin nhắn đầu sau khi Harness đổi; ở 1.22.1: dashboard không còn quay mãi khi project nằm trên ổ Windows nhìn từ WSL (/mnt/d…) hoặc phiên công ty không trả lời; ở 1.22.0: đính kèm được mọi file code và văn bản (.html, .css, .ts, .py, Dockerfile…); ở 1.21.1: bật Bypass được cả khi lượt đang chạy và được giữ sau khi tải lại; ở 1.21.0: câu hỏi và yêu cầu duyệt hiện từng cái một (main agent trước), thông báo góc phải khi cuộc trò chuyện khác xong hay đang chờ bạn, Studio ghi lại mỗi lần compact; ở 1.20.0: cài package trong sandbox công ty không phải duyệt (npm, PyPI, Go, Maven, Gradle… qua proxy chỉ cho registry); ở 1.19.0: task công ty có checklist được làm đến hết, cuối mỗi lượt báo rõ xong, dừng giữa chừng hay lỗi, Docker trong sandbox công ty, folder chứa nhiều repo; ở 1.18.0: đổi nhánh Git trên dashboard, tự thử lại khi lỗi tạm thời, Claude Haiku 5.5; ở 1.17.0: dashboard hiện nhánh Git của project; ở 1.16.3: dashboard cập nhật xong vẫn tự kiểm tra bản mới; ở 1.16.2: Terminal nói giống dashboard: hỏi cập nhật, /bypass, lỗi và ghi chú Harness bằng tiếng Việt; ở 1.16.1: bản mới được báo bằng dialog và kiểm tra mỗi giờ, tab dashboard không còn mất đăng nhập; ở 1.16.0: Bypass cho cuộc trò chuyện công ty, đổi Harness không làm gián đoạn; ở 1.15.2: cuộc trò chuyện dài tự thu gọn trở lại; ở 1.15.1: Studio thấy mỗi call của model dùng để làm gì, nhiều cuộc trò chuyện trong một folder không nhận nhầm thay đổi của nhau; ở 1.15.0: subagent bị từ chối nói đúng lý do; ở 1.14: cập nhật giữ model bạn đã chọn; ở 1.13: cuộc trò chuyện giữ chỗ đang đọc, chữ của agent có định dạng, Piagent trên Windows qua WSL2: sandbox công ty bằng bubblewrap và Agent Watch cho Windows; ở 1.12: @ chọn file và folder trên máy, skill và command dùng bằng /, nhánh cuộc trò chuyện công ty gửi được tin nhắn.</p>
189
+ <p>Terminal công ty có giao diện riêng, dừng lượt không còn làm hỏng cuộc trò chuyện; ở 1.28.3: Agent Watch tự cập nhật không còn làm gián đoạn Terminal công ty; ở 1.28.2: không còn lỗi “binding changed” ngay sau khi cập nhật; ở 1.28.1: Terminal công ty và Pi cá nhân không còn giẫm chân nhau (không nạp Piagent hai lần, dọn cấu hình công ty cũ, cuộc trò chuyện công ty chỉ mở bằng piagent studio); ở 1.28.0: team memory v2; ở 1.27.1: team memory chạy ổn cả khi agent đang gọi model; ở 1.27.0: team memory, agent công ty nhớ quyết định và quy tắc của team trong từng repo; ở 1.26.1: đổi tên cuộc trò chuyện được cả khi lượt đang chạy; ở 1.26.0: lệnh / và phím tắt của Terminal ngay trên dashboard, /undo hoàn tác lượt trước của agent, dev server chạy qua nhiều lượt; ở 1.25.0: thiếu môi trường thì agent xin quyền và chạy được sau khi bạn duyệt (run_on_host ngoài sandbox, start_docker mở Docker ngay trong cuộc trò chuyện); ở 1.24.0: chọn Fast ngay trên trang tạo cuộc trò chuyện công ty, nút Fast đổi màu vàng khi đang bật; ở 1.23.1: câu hỏi của agent luôn nằm cuối cuộc trò chuyện, ngay trên ô nhập, và dễ đọc hơn; ở 1.23.0: nút Fast cho cuộc trò chuyện công ty khi Harness cho phép, tool lỗi được báo về Studio (Logs → Tool lỗi), cuộc trò chuyện mới gửi được tin nhắn đầu sau khi Harness đổi; ở 1.22.1: dashboard không còn quay mãi khi project nằm trên ổ Windows nhìn từ WSL (/mnt/d…) hoặc phiên công ty không trả lời; ở 1.22.0: đính kèm được mọi file code và văn bản (.html, .css, .ts, .py, Dockerfile…); ở 1.21.1: bật Bypass được cả khi lượt đang chạy và được giữ sau khi tải lại; ở 1.21.0: câu hỏi và yêu cầu duyệt hiện từng cái một (main agent trước), thông báo góc phải khi cuộc trò chuyện khác xong hay đang chờ bạn, Studio ghi lại mỗi lần compact; ở 1.20.0: cài package trong sandbox công ty không phải duyệt (npm, PyPI, Go, Maven, Gradle… qua proxy chỉ cho registry); ở 1.19.0: task công ty có checklist được làm đến hết, cuối mỗi lượt báo rõ xong, dừng giữa chừng hay lỗi, Docker trong sandbox công ty, folder chứa nhiều repo; ở 1.18.0: đổi nhánh Git trên dashboard, tự thử lại khi lỗi tạm thời, Claude Haiku 5.5; ở 1.17.0: dashboard hiện nhánh Git của project; ở 1.16.3: dashboard cập nhật xong vẫn tự kiểm tra bản mới; ở 1.16.2: Terminal nói giống dashboard: hỏi cập nhật, /bypass, lỗi và ghi chú Harness bằng tiếng Việt; ở 1.16.1: bản mới được báo bằng dialog và kiểm tra mỗi giờ, tab dashboard không còn mất đăng nhập; ở 1.16.0: Bypass cho cuộc trò chuyện công ty, đổi Harness không làm gián đoạn; ở 1.15.2: cuộc trò chuyện dài tự thu gọn trở lại; ở 1.15.1: Studio thấy mỗi call của model dùng để làm gì, nhiều cuộc trò chuyện trong một folder không nhận nhầm thay đổi của nhau; ở 1.15.0: subagent bị từ chối nói đúng lý do; ở 1.14: cập nhật giữ model bạn đã chọn; ở 1.13: cuộc trò chuyện giữ chỗ đang đọc, chữ của agent có định dạng, Piagent trên Windows qua WSL2: sandbox công ty bằng bubblewrap và Agent Watch cho Windows; ở 1.12: @ chọn file và folder trên máy, skill và command dùng bằng /, nhánh cuộc trò chuyện công ty gửi được tin nhắn.</p>
190
190
  </a>
191
191
  <a class="doc-card" href="/ecosystem">
192
192
  <span class="card-kicker">Get started</span>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/mcp-approval" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/mcp-approval" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/mcp-auth" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/mcp-auth" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/mcp-servers" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/mcp-servers" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/mcp" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/mcp" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/permissions" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/permissions" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/profiles" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/profiles" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/quickstart" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/quickstart" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/runtime" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/runtime" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/scope" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/scope" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/security" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/security" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/team" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/team" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/whats-new" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/whats-new" hreflang="en" lang="en">EN</a>
@@ -104,6 +104,12 @@
104
104
  <h1>Bản 1.9.0: nói việc bằng lời, Harness của team kiểm tra</h1>
105
105
  <p>Bỏ task contract và lệnh workflow. Chế độ công ty tự yêu cầu check và review; nút Dừng, lệnh có mạng theo lần duyệt và thẻ duyệt dễ đọc hơn.</p>
106
106
  </div>
107
+ <section class="section">
108
+ <p class="section-kicker">v1.29.0 · 2026-10-18</p>
109
+ <h2 id="v1-29-0">Terminal công ty có giao diện riêng; dừng lượt không còn làm hỏng cuộc trò chuyện</h2>
110
+ <p class="section-lead">Terminal công ty (<span class="inline-code">piagent studio</span>) giờ có phần đầu riêng: team, model và mức suy luận theo Harness, quyền, Fast, memory. Thanh dưới hiện đúng mức suy luận, không hiện chi phí USD; plan hiện thành checklist; lúc chờ bạn trả lời câu hỏi thì ghi “Đang chờ bạn trả lời”. <span class="inline-code">/share</span> và <span class="inline-code">/bug</span> bị chặn vì gửi hội thoại công ty ra ngoài; <span class="inline-code">/login</span>, <span class="inline-code">/model</span>, <span class="inline-code">/thinking</span>… báo Harness của team quyết định. Dừng một lượt khi lệnh đang chạy không còn làm hỏng các lượt sau (cùng Agent Studio 0.28.1, Agent Watch 0.15.7).</p>
111
+ </section>
112
+
107
113
  <section class="section">
108
114
  <p class="section-kicker">v1.28.3 · 2026-10-18</p>
109
115
  <h2 id="v1-28-3">Agent Watch tự cập nhật không còn làm gián đoạn Terminal công ty</h2>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/windows" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/windows" hreflang="en" lang="en">EN</a>
@@ -30,7 +30,7 @@
30
30
  <span>Pi Agent Platform</span>
31
31
  </a>
32
32
  <div class="top-actions">
33
- <span class="pill"><span class="pill-dot"></span>v1.28.3 docs · VI</span>
33
+ <span class="pill"><span class="pill-dot"></span>v1.29.0 docs · VI</span>
34
34
  <nav class="language-switch" aria-label="Ngôn ngữ">
35
35
  <a class="language-option current" href="/workflows" hreflang="vi" lang="vi" aria-current="true">VI</a>
36
36
  <a class="language-option" href="/en/workflows" hreflang="en" lang="en">EN</a>
@@ -257,7 +257,7 @@
257
257
  {
258
258
  "path": "tests",
259
259
  "fileCount": 554,
260
- "sha256": "724bdb47df1d18c0257509b601da200191976313d9577e347bb563713ead3deb"
260
+ "sha256": "b1bd6124763f1e06122591028d50889d68f469b3d0ac532bce6eda426ad19e4e"
261
261
  }
262
262
  ],
263
263
  "custodianComparisonRules": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/platform",
3
- "version": "1.28.3",
3
+ "version": "1.29.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -349,6 +349,9 @@ export function attachMemory(self, manager, agentDir, verify) {
349
349
  export function trackMemoryLessons(self) {
350
350
  self.session.subscribe(event => { try { self.memoryTurn?.checks?.event(event); } catch { /* optional evidence */ } });
351
351
  }
352
+ // Whether this conversation has team memory now: Studio answered memory for
353
+ // this key recently and has not switched it off since (the Terminal's header).
354
+ export const memoryOn = self => !!self?.memory?.stateDir && self.memory.active && TeamMemory.known(self.memory.stateDir, self.origin, memoryScope(self.origin, self.manifest));
352
355
  export const memoryToolsFor = (self, agentDir) => agentDir && TeamMemory.known(agentDir, self.origin, memoryScope(self.origin, self.manifest)) ? memoryTools(self) : [];
353
356
  // A helper (scout, research, verify, review) reads the team memory with its own run token; it never writes.
354
357
  export const helperMemoryTools = (managed, grant, renew) => managed.memory?.stateDir && TeamMemory.known(managed.memory.stateDir, managed.origin, memoryScope(managed.origin, managed.manifest))
@@ -47,6 +47,10 @@ export function wrapRoleStreams(owner, runtime, role, { provider, verifyGrant })
47
47
  try {
48
48
  if (role === 'main' && owner.preflight) throw Error(owner.preflight);
49
49
  if (!owner.grant || model.provider !== provider) throw Error('managed-run-required');
50
+ // Pi asks once more after Stop cut a tool call (its loop goes on
51
+ // with the cancelled result): that ask ends here, without renewing
52
+ // the grant of a run that is about to close.
53
+ if (signal?.aborted) throw Error('managed-request-aborted');
50
54
  // Studio's answer to a failed request is a machine code: say who
51
55
  // failed and why, in words. Only an admission refusal is asked again.
52
56
  // A request the member stopped ended, it did not fail; the provider may
@@ -296,8 +296,8 @@ export class ManagedSession {
296
296
  // the newest version the broker advertises.
297
297
  const features = self.manifest.broker_features ?? [];
298
298
  const process = self.run && features.includes('process') ? self.run.report(currentPlan(manager), features.includes('process-v3') ? 3 : features.includes('process-v2') ? 2 : 1) : null;
299
- try { await self.broker.request('close', process ? { process } : {}); }
300
- catch (error) { if (!process) throw error; await self.broker.request('close'); }
299
+ try { await self.broker.request('close', process ? { process } : {}); } // only a refused report closes again without it; an unconfirmed close fails the turn
300
+ catch (error) { if (!process || String(error?.message) !== 'managed-broker:invalidResponse') throw error; await self.broker.request('close'); }
301
301
  manager.appendCustomEntry('agent-watch-run', { run_id: self.grant.run_id, state: 'closed' });
302
302
  }
303
303
  // A run that could not be closed (the network or Agent Watch went away)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/core",
3
- "version": "1.28.3",
3
+ "version": "1.29.0",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -10,6 +10,7 @@ import { pathToFileURL } from 'node:url';
10
10
  import { registerTerminalUpdateOffer } from '../packages/piagent-core/runtime/update/terminal-update-offer.mjs';
11
11
  import { parseFailure } from '../packages/piagent-core/runtime/managed-failure.mjs';
12
12
  import { checkpointsOf } from '../packages/piagent-core/managed/checkpoints.mjs';
13
+ import { memoryOn } from '../packages/piagent-core/managed/memory.mjs';
13
14
  import { companyFailureText } from '../packages/piagent-webui/shared/company-copy.ts';
14
15
  import { headlineText, outcomeText, processItems } from '../packages/piagent-webui/shared/process-copy.ts';
15
16
  import { turnEndCopy, turnEndOf } from '../packages/piagent-webui/shared/turn-end.ts';
@@ -28,6 +29,78 @@ const PERMISSION_TEXT = {
28
29
  'trusted-full-access': 'Bypass: lệnh cần internet chạy luôn; vẫn hỏi trước khi đẩy hoặc gửi dữ liệu ra ngoài, chạy migration, xoá không rõ đích hoặc dùng sudo.',
29
30
  };
30
31
 
32
+ const EFFORT = { off: 'Tắt', minimal: 'Tối thiểu', low: 'Thấp', medium: 'Trung bình', high: 'Cao', xhigh: 'Rất cao', max: 'Tối đa' };
33
+ export const effortText = (level) => EFFORT[level] ?? level ?? '';
34
+
35
+ // What the team's Harness decides for this conversation, as the header and
36
+ // footer say it. `last` is the main agent's latest run (its model and
37
+ // effort); before the first run, the Harness's first main model and its effort.
38
+ export function harnessSummary(managed, { last = null, version = null } = {}) {
39
+ const manifest = managed?.manifest, config = manifest?.harness?.configuration ?? {};
40
+ const review = config.workflow?.review !== 'off' && config.review?.model_ids?.[0] || null;
41
+ const fast = managed?.session?.managedFastState?.() ?? null;
42
+ return {
43
+ team: manifest?.user?.team_name || null,
44
+ model: last?.model_id || config.main?.model_ids?.[0] || null,
45
+ effort: last?.effort || config.main?.effort || managed?.session?.state?.thinkingLevel || null,
46
+ review, permission: managed?.permission === 'trusted-full-access' ? 'Bypass' : 'Hỏi trước',
47
+ fast: fast === null ? null : fast === 'on', memory: managed ? memoryOn(managed) : false, version,
48
+ };
49
+ }
50
+ export function headerText(summary) {
51
+ return ['Piagent công ty', summary.team && `team ${summary.team}`,
52
+ summary.model && `main ${summary.model}${summary.effort ? ` (${effortText(summary.effort)})` : ''}`,
53
+ summary.review && `review ${summary.review}`, summary.permission,
54
+ summary.fast !== null && `Fast ${summary.fast ? 'bật' : 'tắt'}`, `memory ${summary.memory ? 'bật' : 'tắt'}`, summary.version].filter(Boolean).join(' · ');
55
+ }
56
+ export const HEADER_KEYS = 'Esc dừng lượt · Ctrl+C xoá ô nhập, hai lần để thoát · / lệnh · ! shell · Ctrl+O xem thêm · /help';
57
+
58
+ // Pi's own commands that the company Terminal answers itself. /share and
59
+ // /bug would send the conversation and code outside the company; the others
60
+ // pick what the team's Harness decides. Keys that do the same (Ctrl+L,
61
+ // Ctrl+P, Shift+Tab) answer the same.
62
+ const ADMIN = 'Admin đổi trong Agent Studio → Harness.';
63
+ export function companyCommandText(name, summary = {}) {
64
+ const main = summary.model ? ` (main ${summary.model}${summary.effort ? `, ${effortText(summary.effort)}` : ''})` : '';
65
+ switch (name) {
66
+ case 'share': return '/share bị tắt trong cuộc trò chuyện công ty: lệnh này đăng toàn bộ hội thoại lên GitHub Gist, ra ngoài công ty. Cần lưu lại thì dùng /export (file trên máy này).';
67
+ case 'bug': return '/bug bị tắt trong cuộc trò chuyện công ty: báo cáo gửi hội thoại và code cho nhà phát triển Pi, ra ngoài công ty. Gặp lỗi, gửi admin của team mã lỗi trong [ ] và giờ xảy ra.';
68
+ case 'login': case 'logout': return 'Cuộc trò chuyện công ty dùng tài khoản AI của team qua Agent Watch: không cần /login hay /logout. Tài khoản và API key cá nhân chỉ dùng trong pi cá nhân.';
69
+ case 'model': case 'scoped-models': return `Model do Harness của team quyết định${main}; Terminal không chọn model. ${ADMIN}`;
70
+ case 'thinking': return `Mức suy luận do Harness của team quyết định${main}. ${ADMIN}`;
71
+ case 'settings': return `Cài đặt của cuộc trò chuyện công ty (compaction, retry…) do Harness quyết định. Phím tắt: /hotkeys. ${ADMIN}`;
72
+ default: return null;
73
+ }
74
+ }
75
+ // Pi's commands in the / suggestions say what they do here. They stay listed:
76
+ // with one hidden, Enter on "/bug" would pick the nearest other match (a
77
+ // skill) and send it to the agent.
78
+ const SUGGESTION_TEXT = { share: 'Tắt trong cuộc trò chuyện công ty', bug: 'Tắt trong cuộc trò chuyện công ty',
79
+ login: 'Không dùng: tài khoản của team qua Agent Watch', logout: 'Không dùng: tài khoản của team qua Agent Watch',
80
+ model: 'Harness của team quyết định model', 'scoped-models': 'Harness của team quyết định model',
81
+ thinking: 'Harness của team quyết định mức suy luận', settings: 'Harness của team quyết định', changelog: 'Có gì mới trong Piagent' };
82
+ export function companySuggestions(suggestions) {
83
+ if (!suggestions?.items || !String(suggestions.prefix ?? '').startsWith('/')) return suggestions;
84
+ return { ...suggestions, items: suggestions.items.map((item) => {
85
+ const text = SUGGESTION_TEXT[String(item.value ?? '').replace(/^\//, '').trim()];
86
+ return text ? { ...item, description: text } : item;
87
+ }) };
88
+ }
89
+
90
+ // /changelog: the newest Piagent releases from the installed CHANGELOG.md.
91
+ export function whatsNewMarkdown(changelog, count = 3) {
92
+ const sections = String(changelog ?? '').split(/^(?=## v\d)/m).filter((part) => part.startsWith('## v')).slice(0, count);
93
+ return sections.length ? sections.map((part) => part.trim()).join('\n\n') : 'Chưa có ghi chú phát hành.';
94
+ }
95
+
96
+ // The plan as a checklist, as the dashboard's Plan card shows it.
97
+ export function planLines(plan) {
98
+ const steps = Array.isArray(plan) ? plan : [];
99
+ const mark = { completed: '☑', in_progress: '☐', deferred: '⊘', pending: '☐' };
100
+ return [`Plan · ${steps.filter((p) => p.status === 'completed').length}/${steps.length} bước xong`,
101
+ ...steps.map((p) => ` ${mark[p.status] ?? '☐'} ${p.step}${p.status === 'in_progress' ? ' ← đang làm' : p.status === 'deferred' ? ' (để sau)' : ''}`)];
102
+ }
103
+
31
104
  // A harness note's details, in the shape the shared copy reads.
32
105
  export function processInput(details) {
33
106
  if (!details || typeof details !== 'object' || typeof details.phase !== 'string') return null;
@@ -53,6 +126,93 @@ export function failureLines(errorMessage) {
53
126
  return copy ? `${copy.title}: ${copy.text} [${failure.code}]` : null;
54
127
  }
55
128
 
129
+ const tokens = (n) => n < 1000 ? String(n) : n < 10000 ? `${(n / 1000).toFixed(1)}k` : n < 1e6 ? `${Math.round(n / 1000)}k` : `${(n / 1e6).toFixed(1)}M`;
130
+ // Pi's footer without the USD cost (company accounts are not billed per
131
+ // conversation) and with the Harness's main model and effort on the right.
132
+ export function footerLines({ session, summary, footerData, theme, width, truncateToWidth, visibleWidth }) {
133
+ const dim = (text) => theme.fg('dim', text);
134
+ if (!session) return [truncateToWidth(dim(headerText(summary)), width, dim('...'))];
135
+ const home = process.env.HOME;
136
+ let where = session.sessionManager.getCwd();
137
+ if (home && (where === home || where.startsWith(home + '/'))) where = '~' + where.slice(home.length);
138
+ const branch = footerData?.getGitBranch?.(), name = session.sessionManager.getSessionName?.();
139
+ if (branch) where += ` (${branch})`;
140
+ if (name) where += ` • ${name}`;
141
+ const sum = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
142
+ for (const entry of session.sessionManager.getEntries()) {
143
+ const usage = entry.type === 'usage' ? entry.usage : entry.type === 'message' && ['assistant', 'toolResult'].includes(entry.message?.role) ? entry.message.usage : null;
144
+ if (usage) for (const key of Object.keys(sum)) sum[key] += Number(usage[key]) || 0;
145
+ }
146
+ const context = session.getContextUsage?.(), window = context?.contextWindow ?? session.state?.model?.contextWindow ?? 0;
147
+ const percent = context?.percent ?? 0, shown = context?.percent == null ? '?' : percent.toFixed(1);
148
+ const parts = [sum.input && `↑${tokens(sum.input)}`, sum.output && `↓${tokens(sum.output)}`, sum.cacheRead && `R${tokens(sum.cacheRead)}`, sum.cacheWrite && `W${tokens(sum.cacheWrite)}`].filter(Boolean);
149
+ const ctxText = `${shown === '?' ? '?' : shown + '%'}/${tokens(window)} (auto)`;
150
+ let left = [...parts, ctxText].join(' ');
151
+ const right = summary.model ? `main ${summary.model}${summary.effort ? ` • ${effortText(summary.effort)}` : ''}` : '';
152
+ if (visibleWidth(left) > width) left = truncateToWidth(left, width, '...');
153
+ const room = width - visibleWidth(left) - 2;
154
+ const tail = room > 0 && right ? truncateToWidth(right, room, '') : '';
155
+ const pad = tail ? ' '.repeat(Math.max(2, width - visibleWidth(left) - visibleWidth(tail))) : '';
156
+ const loud = percent > 90 ? 'error' : percent > 70 ? 'warning' : null;
157
+ const stats = loud ? dim(left.slice(0, left.length - ctxText.length)) + theme.fg(loud, left.slice(left.length - ctxText.length)) : dim(left);
158
+ const lines = [truncateToWidth(dim(where), width, dim('...')), stats + dim(pad + tail)];
159
+ const statuses = footerData?.getExtensionStatuses?.();
160
+ if (statuses?.size) lines.push(truncateToWidth([...statuses.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([, text]) => String(text).replace(/\s+/g, ' ').trim()).join(' '), width, dim('...')));
161
+ return lines;
162
+ }
163
+
164
+ // The update_plan tool drawn as a checklist (set on the session's tool definition).
165
+ export async function companyToolRenderers(sdkRoot) {
166
+ const require = createRequire(path.join(sdkRoot, 'package.json'));
167
+ const { Text } = await import(pathToFileURL(require.resolve('@earendil-works/pi-tui')).href);
168
+ return { update_plan: {
169
+ renderCall: (_args, theme) => new Text(theme.fg('toolTitle', theme.bold('Plan')), 0, 0),
170
+ renderResult: (result, _options, theme) => {
171
+ const plan = result?.details?.plan;
172
+ if (!Array.isArray(plan)) return new Text(theme.fg('toolOutput', (result?.content ?? []).map((c) => c.text ?? '').join('\n')), 0, 0);
173
+ const [head, ...steps] = planLines(plan);
174
+ return new Text([theme.fg('toolOutput', head), ...steps.map((line, i) => theme.fg(plan[i].status === 'completed' ? 'success' : plan[i].status === 'in_progress' ? 'accent' : 'muted', line))].join('\n'), 0, 0);
175
+ } } };
176
+ }
177
+
178
+ // Pi's InteractiveMode for the company Terminal. Pi runs its own commands
179
+ // before an extension's (and shows its /bug hint after errors) with no hook
180
+ // for either, so the few it must not run are answered here.
181
+ export async function companyInteractiveMode(api, { sdkRoot, packageRoot, summary = () => ({}) }) {
182
+ const require = createRequire(path.join(sdkRoot, 'package.json'));
183
+ const { Markdown, Spacer } = await import(pathToFileURL(require.resolve('@earendil-works/pi-tui')).href);
184
+ const changelog = () => { try { return fs.readFileSync(path.join(packageRoot, 'CHANGELOG.md'), 'utf8'); } catch { return ''; } };
185
+ return companyMode(api.InteractiveMode, { summary, whatsNew: () => whatsNewMarkdown(changelog()), components: { Markdown, Spacer, DynamicBorder: api.DynamicBorder } });
186
+ }
187
+ export function companyMode(Base, { summary, whatsNew, components }) {
188
+ const say = (mode, name, tone = 'warning') => mode.showExtensionNotify(companyCommandText(name, summary()), tone);
189
+ return class CompanyInteractiveMode extends Base {
190
+ async handleShareCommand() { say(this, 'share'); }
191
+ async handleBugCommand() { say(this, 'bug'); }
192
+ suggestBugReport() {}
193
+ crashReportInstructions() { return 'Lần sau mở lại: piagent studio, rồi /resume. Gửi admin của team giờ xảy ra lỗi.'; }
194
+ async handleLoginCommand() { say(this, 'login', 'info'); }
195
+ async showOAuthSelector() { say(this, 'logout', 'info'); }
196
+ async handleModelCommand() { say(this, 'model', 'info'); }
197
+ showModelSelector() { say(this, 'model', 'info'); }
198
+ showModelsSelector() { say(this, 'scoped-models', 'info'); }
199
+ async cycleModel() { say(this, 'model', 'info'); }
200
+ handleThinkingCommand() { say(this, 'thinking', 'info'); }
201
+ cycleThinkingLevel() { say(this, 'thinking', 'info'); }
202
+ showSettingsSelector() { say(this, 'settings', 'info'); }
203
+ // Pi's own release notes are not Piagent's.
204
+ getChangelogForDisplay() { return undefined; }
205
+ handleChangelogCommand() {
206
+ const { Markdown, Spacer, DynamicBorder } = components;
207
+ this.chatContainer.addChild(new Spacer(1));
208
+ if (DynamicBorder) this.chatContainer.addChild(new DynamicBorder());
209
+ this.chatContainer.addChild(new Markdown(`# Có gì mới trong Piagent\n\n${whatsNew()}`, 1, 1, this.getMarkdownThemeWithSettings()));
210
+ if (DynamicBorder) this.chatContainer.addChild(new DynamicBorder());
211
+ this.ui.requestRender();
212
+ }
213
+ };
214
+ }
215
+
56
216
  export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindingChanged = () => false }) {
57
217
  const require = createRequire(path.join(sdkRoot, 'package.json'));
58
218
  let tui;
@@ -129,6 +289,38 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
129
289
  description: 'Lệnh và phím tắt của Terminal công ty (không gửi model)',
130
290
  handler: async (_args, ctx) => ctx.ui.notify(HELP_TEXT, 'info') });
131
291
 
292
+ // The company header, footer and / suggestions; Pi resets extension UI on
293
+ // every session switch, so they are set again on each session_start.
294
+ let last = null;
295
+ const summary = () => {
296
+ const grant = managed()?.grant;
297
+ if (grant?.model_id) last = { model_id: grant.model_id, effort: grant.effort };
298
+ return harnessSummary(managed(), { last, version: installed });
299
+ };
300
+ pi.on('session_start', async (_event, ctx) => {
301
+ const ui = ctx.ui;
302
+ if (!ctx.hasUI || ui?.[Symbol.for('piagent.webui.gateway-runtime-ui.v1')]) return;
303
+ const { Text, truncateToWidth, visibleWidth } = await components();
304
+ ui.setHeader?.((_tui, theme) => ({ invalidate() {},
305
+ render: (width) => new Text(`${theme.bold(theme.fg('accent', headerText(summary())))}\n${theme.fg('dim', HEADER_KEYS)}`, 1, 0).render(width) }));
306
+ ui.setFooter?.((_tui, theme, footerData) => ({ invalidate() {},
307
+ render: (width) => footerLines({ session: managed()?.session, summary: summary(), footerData, theme, width, truncateToWidth, visibleWidth }) }));
308
+ ui.addAutocompleteProvider?.((current) => ({ ...current, triggerCharacters: current.triggerCharacters,
309
+ getSuggestions: async (...args) => companySuggestions(await current.getSuggestions(...args)),
310
+ applyCompletion: (...args) => current.applyCompletion(...args),
311
+ ...(current.shouldTriggerFileCompletion && { shouldTriggerFileCompletion: (...args) => current.shouldTriggerFileCompletion(...args) }) }));
312
+ });
313
+ // While a question waits for the member, the loader says so instead of "Working".
314
+ pi.on('tool_execution_start', async (event, ctx) => {
315
+ if (event?.toolName !== 'ask_user') return;
316
+ ctx.ui?.setWorkingMessage?.('Đang chờ bạn trả lời');
317
+ ctx.ui?.setWorkingIndicator?.({ frames: ['?'] });
318
+ });
319
+ pi.on('tool_execution_end', async (event, ctx) => {
320
+ if (event?.toolName !== 'ask_user') return;
321
+ ctx.ui?.setWorkingMessage?.(); ctx.ui?.setWorkingIndicator?.();
322
+ });
323
+
132
324
  // The Harness's notes carry English for the agent; the member reads them in Vietnamese.
133
325
  pi.registerMessageRenderer('agent-watch-process', (message, _options, theme) => {
134
326
  const lines = processLines(message.details);