@piagent/platform 1.37.0 → 1.37.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.
- package/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/README.vi.md +1 -1
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +6 -6
- package/docs/languages.json +2 -2
- package/docs/operator-manual-vietnamese.md +7 -7
- package/docs/publishing-for-teams.md +1 -0
- package/docs/release-install-policy.md +2 -2
- package/docs/team-onboarding.md +2 -2
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/content/en/index.html +4 -4
- package/docs-site/content/en/whats-new.html +6 -0
- package/docs-site/content/index.html +4 -4
- package/docs-site/content/whats-new.html +6 -0
- package/docs-site/context-engine.html +1 -1
- package/docs-site/ecosystem.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/ecosystem.html +1 -1
- package/docs-site/en/index.html +5 -5
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +1 -1
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +7 -1
- package/docs-site/en/windows.html +1 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +5 -5
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +1 -1
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +7 -1
- package/docs-site/windows.html +1 -1
- package/docs-site/workflows.html +1 -1
- package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
- package/package.json +1 -1
- package/packages/piagent-core/managed/helper-run.mjs +11 -1
- package/packages/piagent-core/managed/helper-settlement.mjs +17 -6
- package/packages/piagent-core/managed/ip-policy.mjs +50 -0
- package/packages/piagent-core/managed/memory-lessons.mjs +4 -1
- package/packages/piagent-core/managed/memory.mjs +1 -1
- package/packages/piagent-core/managed/package-proxy.mjs +12 -14
- package/packages/piagent-core/managed/session.mjs +4 -5
- package/packages/piagent-core/managed/skill-feedback.mjs +9 -1
- package/packages/piagent-core/managed/studio-link.mjs +16 -0
- package/packages/piagent-core/managed/web-fetch.mjs +3 -14
- package/packages/piagent-core/package.json +1 -1
package/docs-site/en/scope.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/en/team.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.1 · 2026-10-22</p>
|
|
109
|
+
<h2 id="v1-37-1">Closes Studio can trust</h2>
|
|
110
|
+
<p class="section-lead">When closing a run failed for a moment, the close asked again could "succeed" without reaching Studio, and Piagent recorded the run closed. With Agent Watch 0.15.11 (Windows 0.1.16) the close asked again reaches Studio; with an older Agent Watch the run stays open here and is recovered when the conversation reopens. A helper whose close fails for a moment keeps its answer, and its report to Studio is sent again. Team memory no longer merges two different commands that failed the same way into one lesson. Security: <code>web_fetch</code> and the package proxy refuse private addresses written in any IPv6 form, and with a company upstream proxy the package proxy still checks where it connects.</p>
|
|
111
|
+
</section>
|
|
112
|
+
|
|
107
113
|
<section class="section">
|
|
108
114
|
<p class="section-kicker">v1.37.0 · 2026-10-22</p>
|
|
109
115
|
<h2 id="v1-37-0">An answer cut mid-stream no longer stops a long task</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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/index.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
97
|
+
<p class="eyebrow">Piagent 1.37.1</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.37.
|
|
111
|
+
<a class="button" href="/whats-new">Có gì mới trong 1.37.1</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.37.
|
|
187
|
+
<span class="card-kicker">Bản 1.37.1</span>
|
|
188
188
|
<h3>Có gì mới</h3>
|
|
189
|
-
<p>
|
|
189
|
+
<p>Run Studio chưa xác nhận đóng không còn bị ghi là đã đóng, helper đóng lỗi vẫn giữ câu trả lời, bài học team memory ghi đúng lệnh; ở 1.37.0: câu trả lời bị cắt giữa chừng không còn làm dừng task dài, có <code>piagent studio --rpc</code>; ở 1.36.1: Agent Watch mất kết nối tới Studio trong chốc lát không còn làm dừng task; ở 1.36.0: team memory học từ chỗ làm sai: Studio chấm những gì memory đã đưa, lệnh lỗi lặp lại thành bài học; ở 1.35: task dài không dừng khi Studio cập nhật hay model báo lỗi tạm thời; ở 1.34: helper báo kết quả, Agent Watch báo khi cần bạn; ở 1.33.0: chạy trên Pi 1.3.0; ở 1.32.1: Bypass được giữ sau khi tải lại, tab đang dùng không còn bị đăng xuất sau 8 giờ; ở 1.32.0: lượt lỗi hoặc bấm Stop được dừng cả ở Studio; ở 1.31.1: <code>memory_ask</code> có ngay sau khi cập nhật; ở 1.31.0: Memory của team đi theo branch và luật của team, có <code>memory_ask</code>; ở 1.30.1: Terminal công ty không còn hiện tên model, mở <code>piagent studio</code> ở thư mục home báo rõ cần vào thư mục dự án; ở 1.30.0: context lớn đi qua mạng chậm, Terminal công ty gọn như dashboard; ở 1.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; ở 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/mcp-auth.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/mcp.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/profiles.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/runtime.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/scope.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/security.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/team.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/whats-new.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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.37.1 · 2026-10-22</p>
|
|
109
|
+
<h2 id="v1-37-1">Đóng run mà Studio tin được</h2>
|
|
110
|
+
<p class="section-lead">Khi đóng run lỗi trong chốc lát, lần hỏi đóng lại có thể "thành công" mà không tới Studio, và Piagent ghi run là đã đóng. Với Agent Watch 0.15.11 (Windows 0.1.16), lần hỏi lại tới được Studio; với Agent Watch cũ, run được để mở ở đây và được khôi phục khi mở lại cuộc trò chuyện. Helper đóng lỗi trong chốc lát vẫn giữ câu trả lời, báo cáo của nó được gửi lại cho Studio. Team memory không còn gộp hai lệnh khác nhau cùng lỗi thành một bài học. Bảo mật: <code>web_fetch</code> và package proxy chặn địa chỉ nội bộ viết dưới mọi dạng IPv6, và khi có upstream proxy của công ty, package proxy vẫn kiểm tra đích kết nối.</p>
|
|
111
|
+
</section>
|
|
112
|
+
|
|
107
113
|
<section class="section">
|
|
108
114
|
<p class="section-kicker">v1.37.0 · 2026-10-22</p>
|
|
109
115
|
<h2 id="v1-37-0">Câu trả lời bị cắt giữa chừng không còn làm dừng task dài</h2>
|
package/docs-site/windows.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
package/docs-site/workflows.html
CHANGED
|
@@ -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.37.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.37.1 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>
|
|
@@ -256,8 +256,8 @@
|
|
|
256
256
|
},
|
|
257
257
|
{
|
|
258
258
|
"path": "tests",
|
|
259
|
-
"fileCount":
|
|
260
|
-
"sha256": "
|
|
259
|
+
"fileCount": 570,
|
|
260
|
+
"sha256": "49831d3854e0342c89dc2e8dc28aaa0b9a0e6ae7870e1ab5c7ab003fee12e787"
|
|
261
261
|
}
|
|
262
262
|
],
|
|
263
263
|
"custodianComparisonRules": {
|
package/package.json
CHANGED
|
@@ -15,6 +15,7 @@ import { HELPER_CALLS, HELPER_SETUP, READ_TOOLS, countedCheck } from './helper-r
|
|
|
15
15
|
import { trackToolFailures } from './tool-failures.mjs';
|
|
16
16
|
import { helperMemoryTools, renewer } from './memory.mjs';
|
|
17
17
|
import { answeredSettlement, failedSettlement, settleHelper, OUTCOME_WORDS } from './helper-settlement.mjs';
|
|
18
|
+
import { viaLink } from './studio-link.mjs';
|
|
18
19
|
|
|
19
20
|
const textContent = result => result.content?.filter(p => p.type === 'text').map(p => p.text).join('\n') ?? '';
|
|
20
21
|
// A helper failure that another model of its role may not have: the model's
|
|
@@ -53,7 +54,16 @@ export async function runHelper(managed, role, task, signal, harness, { verifyGr
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
}
|
|
57
|
+
// A helper's role closes through the same wait as the run's close: a passing
|
|
58
|
+
// failure of Agent Watch's way to Studio is asked again. A close that still
|
|
59
|
+
// fails leaves the helper's answer standing: the role closes with the run,
|
|
60
|
+
// and the next helper of the role closes it first.
|
|
61
|
+
export async function closeRole(managed, role) {
|
|
62
|
+
try { await viaLink(managed.studioLink, () => managed.broker.request('close', { role })); managed.unclosed?.delete(role); }
|
|
63
|
+
catch { (managed.unclosed ??= new Set()).add(role); }
|
|
64
|
+
}
|
|
56
65
|
async function helperAttempt(managed, role, task, signal, harness, snapshot, parts, { verifyGrant, patiently, title }) {
|
|
66
|
+
if (managed.unclosed?.has(role)) await closeRole(managed, role);
|
|
57
67
|
// A long local tool step may outlive the main lease. Refresh authority
|
|
58
68
|
// before asking for a child; the broker serializes concurrent renewals,
|
|
59
69
|
// and main's own searches running beside it share managed renew.
|
|
@@ -143,6 +153,6 @@ async function helperAttempt(managed, role, task, signal, harness, snapshot, par
|
|
|
143
153
|
finally {
|
|
144
154
|
for (const session of sessions) session.dispose(); await boundary?.dispose();
|
|
145
155
|
await settleHelper(managed, renew.lease, report); // with the role's current token, before it closes
|
|
146
|
-
await managed
|
|
156
|
+
await closeRole(managed, role);
|
|
147
157
|
}
|
|
148
158
|
}
|
|
@@ -78,8 +78,11 @@ export function failedSettlement(role, error, signal, spec = {}) {
|
|
|
78
78
|
evidence: [], files: [], ...(Object.keys(spec ?? {}).length ? { spec } : {}) };
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
// Sends the report with the attempt's own token; never fails the helper.
|
|
82
|
-
|
|
81
|
+
// Sends the report with the attempt's own token; never fails the helper. A
|
|
82
|
+
// passing failure (no answer, 5xx, 429) is sent again after these pauses:
|
|
83
|
+
// Studio keeps one report per role, so a repeat is safe.
|
|
84
|
+
const SETTLE_PAUSES_MS = [500, 2_000];
|
|
85
|
+
export async function settleHelper(managed, grant, report, fetchImpl = (...args) => globalThis.fetch(...args), pauses = SETTLE_PAUSES_MS) {
|
|
83
86
|
if (!report || !hasCapability(managed, 'managed.settle.v1')) return false;
|
|
84
87
|
let held = null;
|
|
85
88
|
try {
|
|
@@ -87,10 +90,18 @@ export async function settleHelper(managed, grant, report, fetchImpl = (...args)
|
|
|
87
90
|
// current one (the attempt's first token may be stale by now).
|
|
88
91
|
if (typeof grant === 'function') { held = await grant(); grant = held.grant; }
|
|
89
92
|
if (!grant?.token) return false;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
94
|
+
let status = 0;
|
|
95
|
+
try {
|
|
96
|
+
const response = await fetchImpl(`${managed.origin}/v1/managed/settle`, { method: 'POST', signal: AbortSignal.timeout(3_000),
|
|
97
|
+
headers: { Authorization: `Bearer ${grant.token}`, 'Content-Type': 'application/json', 'User-Agent': CLIENT_AGENT }, body: JSON.stringify(report) });
|
|
98
|
+
void response.body?.cancel?.().catch(() => {});
|
|
99
|
+
if (response.ok) return true;
|
|
100
|
+
status = response.status;
|
|
101
|
+
} catch { /* no answer */ }
|
|
102
|
+
if ((status && status < 500 && status !== 429) || attempt >= pauses.length) return false;
|
|
103
|
+
await new Promise(resolve => setTimeout(resolve, pauses[attempt]));
|
|
104
|
+
}
|
|
94
105
|
} catch { return false; } finally { held?.release(); }
|
|
95
106
|
}
|
|
96
107
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
|
|
3
|
+
// Whether an address is this machine, a private network or not routable on
|
|
4
|
+
// the internet (IANA special-purpose registries). One classifier for every
|
|
5
|
+
// outbound check (web-fetch, package-proxy). IPv6 forms that carry an IPv4
|
|
6
|
+
// address (mapped, compatible, translated, NAT64, 6to4), dotted or hex, are
|
|
7
|
+
// judged by that IPv4 address. Teredo, IPv6 outside 2000::/3, and anything
|
|
8
|
+
// that does not parse count as private: fail closed.
|
|
9
|
+
const V4_RANGES = [['0.0.0.0', 8], ['10.0.0.0', 8], ['100.64.0.0', 10], ['127.0.0.0', 8], ['169.254.0.0', 16], ['172.16.0.0', 12],
|
|
10
|
+
['192.0.0.0', 24], ['192.0.2.0', 24], ['192.88.99.0', 24], ['192.168.0.0', 16], ['198.18.0.0', 15], ['198.51.100.0', 24],
|
|
11
|
+
['203.0.113.0', 24], ['224.0.0.0', 4], ['240.0.0.0', 4]].map(([base, bits]) => [v4Number(base), 2 ** (32 - bits)]);
|
|
12
|
+
|
|
13
|
+
function v4Number(text) {
|
|
14
|
+
const parts = String(text).split('.');
|
|
15
|
+
if (parts.length !== 4 || !parts.every(part => /^(0|[1-9]\d{0,2})$/.test(part) && Number(part) <= 255)) return null;
|
|
16
|
+
return parts.reduce((value, part) => value * 256 + Number(part), 0);
|
|
17
|
+
}
|
|
18
|
+
const v4Private = value => V4_RANGES.some(([base, size]) => value >= base && value < base + size);
|
|
19
|
+
|
|
20
|
+
// Eight 16-bit groups, or null: "::" expanded, a dotted IPv4 tail and a zone id accepted.
|
|
21
|
+
function v6Groups(text) {
|
|
22
|
+
let value = String(text).toLowerCase().replace(/%[^%]*$/, '');
|
|
23
|
+
const tail = /:(\d+\.\d+\.\d+\.\d+)$/.exec(value);
|
|
24
|
+
if (tail) {
|
|
25
|
+
const v4 = v4Number(tail[1]); if (v4 === null) return null;
|
|
26
|
+
value = value.slice(0, -tail[1].length) + `${(v4 >>> 16).toString(16)}:${(v4 & 0xffff).toString(16)}`;
|
|
27
|
+
}
|
|
28
|
+
const halves = value.split('::');
|
|
29
|
+
if (halves.length > 2) return null;
|
|
30
|
+
const head = halves[0] ? halves[0].split(':') : [], rest = halves[1] ? halves[1].split(':') : [];
|
|
31
|
+
const missing = 8 - head.length - rest.length;
|
|
32
|
+
if (halves.length === 2 ? missing < 1 : missing !== 0) return null;
|
|
33
|
+
const groups = [...head, ...Array(halves.length === 2 ? missing : 0).fill('0'), ...rest];
|
|
34
|
+
return groups.every(group => /^[0-9a-f]{1,4}$/.test(group)) ? groups.map(group => parseInt(group, 16)) : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function privateAddress(address) {
|
|
38
|
+
if (net.isIPv4(String(address))) { const v4 = v4Number(address); return v4 === null || v4Private(v4); }
|
|
39
|
+
const g = v6Groups(address);
|
|
40
|
+
if (!g) return true;
|
|
41
|
+
const zero = (from, to) => g.slice(from, to).every(group => group === 0);
|
|
42
|
+
const v4 = (high, low) => v4Private(high * 0x10000 + low);
|
|
43
|
+
if (zero(0, 5) && (g[5] === 0xffff || g[5] === 0)) return v4(g[6], g[7]); // ::ffff:0:0/96 mapped, ::/96 compatible (with :: and ::1)
|
|
44
|
+
if (zero(0, 4) && g[4] === 0xffff && g[5] === 0) return v4(g[6], g[7]); // ::ffff:0:0:0/96 translated
|
|
45
|
+
if (g[0] === 0x64 && g[1] === 0xff9b) return zero(2, 6) ? v4(g[6], g[7]) : true; // NAT64 64:ff9b::/96; 64:ff9b:1::/48 local
|
|
46
|
+
if (g[0] === 0x2002) return v4(g[1], g[2]); // 6to4
|
|
47
|
+
if ((g[0] & 0xe000) !== 0x2000) return true; // not global unicast: 100::/64, fc00::/7, fe80::/10, fec0::/10, ff00::/8, ...
|
|
48
|
+
return g[0] === 0x2001 && (g[1] === 0 || g[1] === 0xdb8 || (g[1] === 2 && g[2] === 0)) // Teredo, documentation, benchmarking
|
|
49
|
+
|| (g[0] & 0xfff0) === 0x3ff0; // 3fff::/20 documentation
|
|
50
|
+
}
|
|
@@ -43,6 +43,9 @@ function passed(output) {
|
|
|
43
43
|
// What an error says, without what varies between runs: numbers, ids,
|
|
44
44
|
// temporary paths and quoted values.
|
|
45
45
|
export const errorShape = text => clean(text,180).replace(/\/(?:tmp|var\/folders|private)\/\S*/g,'<tmp>').replace(/\b[0-9a-f]{8,}\b/gi,'<id>').replace(/\d+/g,'N').replace(/(["'`])[^"'`]{1,80}\1/g,'$1…$1');
|
|
46
|
+
// A command without what varies between runs (temporary paths, ids,
|
|
47
|
+
// numbers): \`curl service-a\` and \`curl service-b\` stay two commands.
|
|
48
|
+
const commandShape = text => clean(text,160).replace(/\/(?:tmp|var\/folders|private)\/\S*/g,'<tmp>').replace(/\b[0-9a-f]{8,}\b/gi,'<id>').replace(/\d+/g,'N');
|
|
46
49
|
const ERROR_LINE = /error|fail|exception|not found|no such|denied|refused|cannot|unknown (?:option|flag|command)|invalid|EADDRINUSE|ENOENT|EACCES/i;
|
|
47
50
|
const MAX_LESSONS = 3;
|
|
48
51
|
|
|
@@ -55,7 +58,7 @@ export class CheckLessons {
|
|
|
55
58
|
if(/managed[-_](?:tool[-_]cancelled|operation[-_]denied|helper[-_]cancelled)|Command aborted|Command timed out/i.test(output))return;
|
|
56
59
|
const line=output.split('\n').find(l=>ERROR_LINE.test(l));
|
|
57
60
|
if(!line)return;
|
|
58
|
-
const command=
|
|
61
|
+
const command=commandShape(call.command);
|
|
59
62
|
if(!command)return;
|
|
60
63
|
const shape=errorShape(line), key=hash(command+'\0'+shape), seen=this.errors.get(key);
|
|
61
64
|
if(!seen){if(this.errors.size>=40)this.errors.delete(this.errors.keys().next().value);this.errors.set(key,{id:event.toolCallId,command:clean(call.command,160),error:clean(line,180),done:false});return;}
|
|
@@ -78,7 +78,7 @@ export class TeamMemory {
|
|
|
78
78
|
const scope = this.scope(), id = scopeID(scope);
|
|
79
79
|
if (id !== this.scopeHash) {
|
|
80
80
|
this.scopeHash = id; this.outbox = new MemoryOutbox(this.stateDir, scope, this.now);
|
|
81
|
-
this.protocol = 0; this.briefed = false; this.offUntil = 0; this.retain = true;
|
|
81
|
+
this.protocol = 0; this.briefed = false; this.offUntil = 0; this.retain = true; this.serves = new RoundServes(); // served under the old scope
|
|
82
82
|
}
|
|
83
83
|
return scope;
|
|
84
84
|
}
|
|
@@ -3,6 +3,9 @@ import http from 'node:http';
|
|
|
3
3
|
import net from 'node:net';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { lookup } from 'node:dns/promises';
|
|
6
|
+
import { privateAddress } from './ip-policy.mjs';
|
|
7
|
+
|
|
8
|
+
export { privateAddress };
|
|
6
9
|
|
|
7
10
|
// The package registries a company command reaches without asking: plain
|
|
8
11
|
// bash has no network, except through this proxy, which the trusted runtime
|
|
@@ -10,6 +13,10 @@ import { lookup } from 'node:dns/promises';
|
|
|
10
13
|
// HTTP to the hosts below and the member's own additions, on ports 443 and
|
|
11
14
|
// 80 only, never to an IP literal or a name that resolves to this machine or
|
|
12
15
|
// a private network (DNS rebinding), and connects to the address it checked.
|
|
16
|
+
// With a company upstream proxy (HTTPS_PROXY) the name is still looked up and
|
|
17
|
+
// checked here, and the upstream is asked for that checked address, never the
|
|
18
|
+
// name, so it cannot resolve it elsewhere; a name this machine cannot look up
|
|
19
|
+
// is refused (run_with_network still reaches it after the member approves).
|
|
13
20
|
// Everything else is refused with 403 and remembered, so the command's
|
|
14
21
|
// failure names the host and run_with_network (the member approves it).
|
|
15
22
|
// Registries (and GitHub) take no upload without a token, and tokens stay
|
|
@@ -50,17 +57,8 @@ export function domainAllowed(host, domains) {
|
|
|
50
57
|
return domains.some(rule => rule.startsWith('*.') ? name.endsWith(rule.slice(1)) && name.length > rule.length - 1 : name === rule);
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
if (net.isIPv4(address)) {
|
|
56
|
-
const [a, b] = address.split('.').map(Number);
|
|
57
|
-
return a === 0 || a === 10 || a === 127 || (a === 100 && b >= 64 && b < 128) || (a === 169 && b === 254) || (a === 172 && b >= 16 && b < 32)
|
|
58
|
-
|| (a === 192 && b === 168) || (a === 198 && (b === 18 || b === 19)) || a >= 224;
|
|
59
|
-
}
|
|
60
|
-
const v6 = address.toLowerCase();
|
|
61
|
-
if (v6.startsWith('::ffff:')) return privateAddress(v6.slice(7));
|
|
62
|
-
return v6 === '::' || v6 === '::1' || /^f[cd]/.test(v6) || /^fe[89ab]/.test(v6) || v6.startsWith('ff');
|
|
63
|
-
}
|
|
60
|
+
// host:port of a checked address, as a CONNECT target or URL host.
|
|
61
|
+
const authority = ({ host, port }) => `${net.isIPv6(host) ? `[${host}]` : host}:${port}`;
|
|
64
62
|
|
|
65
63
|
function upstreamProxy(env) {
|
|
66
64
|
for (const name of ['HTTPS_PROXY', 'https_proxy']) {
|
|
@@ -101,7 +99,6 @@ export class PackageProxy {
|
|
|
101
99
|
// The checked public address of an allowed host, or null.
|
|
102
100
|
async #target(host, port) {
|
|
103
101
|
if (!this.ports.has(port) || !domainAllowed(host, this.domains)) { this.#deny(host); return null; }
|
|
104
|
-
if (this.upstream) return { host, port };
|
|
105
102
|
try {
|
|
106
103
|
const addresses = await this.resolve(host);
|
|
107
104
|
if (!addresses.length || addresses.some(entry => this.isPrivate(entry.address))) { this.#deny(host); return null; }
|
|
@@ -117,7 +114,7 @@ export class PackageProxy {
|
|
|
117
114
|
upstream.setTimeout(10 * 60_000, () => upstream.destroy());
|
|
118
115
|
upstream.once('connect', () => {
|
|
119
116
|
if (this.upstream) {
|
|
120
|
-
upstream.write(`CONNECT ${
|
|
117
|
+
upstream.write(`CONNECT ${authority(target)} HTTP/1.1\r\nHost: ${authority(target)}\r\n\r\n`);
|
|
121
118
|
let reply = Buffer.alloc(0);
|
|
122
119
|
const onData = chunk => {
|
|
123
120
|
reply = Buffer.concat([reply, chunk]);
|
|
@@ -144,8 +141,9 @@ export class PackageProxy {
|
|
|
144
141
|
const target = await this.#target(url.hostname, Number(url.port) || 80);
|
|
145
142
|
if (!target) { response.writeHead(403, { 'X-Piagent-Proxy': 'domain-not-allowed', 'Content-Type': 'text/plain; charset=utf-8' }).end(`piagent: ${url.hostname} is not an allowed package registry\n`); return; }
|
|
146
143
|
const headers = { ...request.headers, host: url.host }; delete headers['proxy-connection']; delete headers['proxy-authorization'];
|
|
144
|
+
const pinned = new URL(url); pinned.host = authority(target);
|
|
147
145
|
const outgoing = http.request(this.upstream
|
|
148
|
-
? { host: this.upstream.host, port: this.upstream.port, path:
|
|
146
|
+
? { host: this.upstream.host, port: this.upstream.port, path: pinned.href, method: request.method, headers }
|
|
149
147
|
: { host: target.host, port: target.port, path: url.pathname + url.search, method: request.method, headers, servername: url.hostname }, incoming => {
|
|
150
148
|
response.writeHead(incoming.statusCode ?? 502, incoming.headers); incoming.pipe(response);
|
|
151
149
|
});
|
|
@@ -13,7 +13,7 @@ import { managedThinkingLevels, nearestLevel } from './capabilities.mjs';
|
|
|
13
13
|
import { nativeManagedModel, isVendor, piProvider, studioAPI, studioPath } from './native-catalog.mjs';
|
|
14
14
|
import { fetchOriginTool } from './repository-operation.mjs';
|
|
15
15
|
import { describeFailure, failureCode, failureText } from '../runtime/managed-failure.mjs';
|
|
16
|
-
import { enableCompanyTurnRetry, wrapRoleStreams, conversationSession } from './request-stream.mjs'; import { StudioLink,
|
|
16
|
+
import { enableCompanyTurnRetry, wrapRoleStreams, conversationSession } from './request-stream.mjs'; import { StudioLink, closeRun } from './studio-link.mjs';
|
|
17
17
|
import { trackToolFailures } from './tool-failures.mjs';
|
|
18
18
|
import { fastServed, fastSetter, fastState, recordFast, restoreFast } from './fast-mode.mjs';
|
|
19
19
|
import { runHelper } from './helper-run.mjs';
|
|
@@ -296,15 +296,14 @@ 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
|
-
|
|
300
|
-
|
|
301
|
-
manager.appendCustomEntry('agent-watch-run', { run_id: self.grant.run_id, state: 'closed' });
|
|
299
|
+
// A close Studio may not have had stays "active" here (closeRun).
|
|
300
|
+
if (await closeRun(self.studioLink, self.broker, features, process, { conversation: conversationSession(self), runId: self.grant.run_id })) manager.appendCustomEntry('agent-watch-run', { run_id: self.grant.run_id, state: 'closed' });
|
|
302
301
|
}
|
|
303
302
|
// A run that could not be closed (the network or Agent Watch went away)
|
|
304
303
|
// ends the turn as failed; the run stays "active" here, so reopening
|
|
305
304
|
// the conversation recovers or abandons it.
|
|
306
305
|
} catch (error) { round.closeFailed = failureCode(failureText(error)) || 'close_failed'; }
|
|
307
|
-
finally { self.grant = null; self.run = null; self.preflight = null; }
|
|
306
|
+
finally { self.grant = null; self.run = null; self.preflight = null; self.unclosed = null; }
|
|
308
307
|
}
|
|
309
308
|
};
|
|
310
309
|
self.session.prompt = async (text, options) => {
|
|
@@ -5,9 +5,17 @@
|
|
|
5
5
|
// Piagent never edits a skill itself and makes no model call for this.
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import path from 'node:path';
|
|
8
|
+
import { createHash } from 'node:crypto';
|
|
8
9
|
|
|
9
10
|
const MIN_FAILURES = 3, MIN_SHARE = 0.5, KEEP = 10, REPROPOSE_MS = 7 * 86400_000;
|
|
10
|
-
|
|
11
|
+
// One file name per skill name: a name with other characters (or capitals,
|
|
12
|
+
// on a case-insensitive disk) gets a digest of itself, so \`a/b\` and \`a_b\`
|
|
13
|
+
// keep their own counts.
|
|
14
|
+
const safeName = name => {
|
|
15
|
+
name = String(name);
|
|
16
|
+
if (/^[a-z0-9_.-]{1,80}$/.test(name) && !/^\.+$/.test(name)) return name;
|
|
17
|
+
return `${name.replace(/[^A-Za-z0-9_.-]/g, '_').slice(0, 60)}~${createHash('sha256').update(name).digest('hex').slice(0, 12)}`;
|
|
18
|
+
};
|
|
11
19
|
|
|
12
20
|
export class SkillFeedback {
|
|
13
21
|
// A managed round's tracker, when the conversation has skills.
|