@poncho-ai/cli 0.14.0 → 0.14.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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +19 -0
- package/dist/{chunk-A32BXZKP.js → chunk-AIEVSNGF.js} +523 -255
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-interactive-ink-SLWDVTDX.js → run-interactive-ink-7ULE5JJI.js} +151 -118
- package/package.json +4 -4
- package/src/index.ts +357 -197
- package/src/run-interactive-ink.ts +171 -147
- package/src/web-ui.ts +213 -101
|
@@ -339,6 +339,8 @@ var renderWebUiHtml = (options) => {
|
|
|
339
339
|
--tool-done: #6a9955;
|
|
340
340
|
--tool-error: #f48771;
|
|
341
341
|
|
|
342
|
+
--warning: #e8a735;
|
|
343
|
+
|
|
342
344
|
--approve: #78e7a6;
|
|
343
345
|
--approve-border: rgba(58,208,122,0.45);
|
|
344
346
|
--deny: #f59b9b;
|
|
@@ -416,6 +418,8 @@ var renderWebUiHtml = (options) => {
|
|
|
416
418
|
--tool-done: #16a34a;
|
|
417
419
|
--tool-error: #dc2626;
|
|
418
420
|
|
|
421
|
+
--warning: #ca8a04;
|
|
422
|
+
|
|
419
423
|
--approve: #16a34a;
|
|
420
424
|
--approve-border: rgba(22,163,74,0.35);
|
|
421
425
|
--deny: #dc2626;
|
|
@@ -561,6 +565,20 @@ var renderWebUiHtml = (options) => {
|
|
|
561
565
|
flex-direction: column;
|
|
562
566
|
gap: 2px;
|
|
563
567
|
}
|
|
568
|
+
.sidebar-section-label {
|
|
569
|
+
font-size: 11px;
|
|
570
|
+
font-weight: 600;
|
|
571
|
+
color: var(--fg-7);
|
|
572
|
+
text-transform: uppercase;
|
|
573
|
+
letter-spacing: 0.04em;
|
|
574
|
+
padding: 10px 10px 4px;
|
|
575
|
+
}
|
|
576
|
+
.sidebar-section-label:first-child { padding-top: 4px; }
|
|
577
|
+
.sidebar-section-divider {
|
|
578
|
+
height: 1px;
|
|
579
|
+
background: var(--border);
|
|
580
|
+
margin: 6px 10px;
|
|
581
|
+
}
|
|
564
582
|
.conversation-item {
|
|
565
583
|
height: 36px;
|
|
566
584
|
min-height: 36px;
|
|
@@ -578,6 +596,16 @@ var renderWebUiHtml = (options) => {
|
|
|
578
596
|
position: relative;
|
|
579
597
|
transition: color 0.15s;
|
|
580
598
|
}
|
|
599
|
+
.conversation-item .approval-dot {
|
|
600
|
+
display: inline-block;
|
|
601
|
+
width: 6px;
|
|
602
|
+
height: 6px;
|
|
603
|
+
border-radius: 50%;
|
|
604
|
+
background: var(--warning, #e8a735);
|
|
605
|
+
margin-right: 6px;
|
|
606
|
+
flex-shrink: 0;
|
|
607
|
+
vertical-align: middle;
|
|
608
|
+
}
|
|
581
609
|
.conversation-item:hover { color: var(--fg-3); }
|
|
582
610
|
.conversation-item.active {
|
|
583
611
|
color: var(--fg);
|
|
@@ -801,7 +829,7 @@ var renderWebUiHtml = (options) => {
|
|
|
801
829
|
.tool-error {
|
|
802
830
|
color: var(--tool-error);
|
|
803
831
|
}
|
|
804
|
-
.assistant-content table {
|
|
832
|
+
.assistant-content table:not(.approval-request-table) {
|
|
805
833
|
border-collapse: collapse;
|
|
806
834
|
width: 100%;
|
|
807
835
|
margin: 14px 0;
|
|
@@ -814,7 +842,7 @@ var renderWebUiHtml = (options) => {
|
|
|
814
842
|
overflow-x: auto;
|
|
815
843
|
white-space: nowrap;
|
|
816
844
|
}
|
|
817
|
-
.assistant-content th {
|
|
845
|
+
.assistant-content table:not(.approval-request-table) th {
|
|
818
846
|
background: var(--surface-4);
|
|
819
847
|
padding: 10px 12px;
|
|
820
848
|
text-align: left;
|
|
@@ -823,16 +851,16 @@ var renderWebUiHtml = (options) => {
|
|
|
823
851
|
color: var(--fg-strong);
|
|
824
852
|
min-width: 100px;
|
|
825
853
|
}
|
|
826
|
-
.assistant-content td {
|
|
854
|
+
.assistant-content table:not(.approval-request-table) td {
|
|
827
855
|
padding: 10px 12px;
|
|
828
856
|
border-bottom: 1px solid var(--border-1);
|
|
829
857
|
width: 100%;
|
|
830
858
|
min-width: 100px;
|
|
831
859
|
}
|
|
832
|
-
.assistant-content tr:last-child td {
|
|
860
|
+
.assistant-content table:not(.approval-request-table) tr:last-child td {
|
|
833
861
|
border-bottom: none;
|
|
834
862
|
}
|
|
835
|
-
.assistant-content tbody tr:hover {
|
|
863
|
+
.assistant-content table:not(.approval-request-table) tbody tr:hover {
|
|
836
864
|
background: var(--surface-1);
|
|
837
865
|
}
|
|
838
866
|
.assistant-content hr {
|
|
@@ -850,6 +878,10 @@ var renderWebUiHtml = (options) => {
|
|
|
850
878
|
line-height: 1.45;
|
|
851
879
|
color: var(--fg-tool-code);
|
|
852
880
|
width: 300px;
|
|
881
|
+
transition: width 0.2s ease;
|
|
882
|
+
}
|
|
883
|
+
.tool-activity.has-approvals {
|
|
884
|
+
width: 100%;
|
|
853
885
|
}
|
|
854
886
|
.assistant-content > .tool-activity:first-child {
|
|
855
887
|
margin-top: 0;
|
|
@@ -909,40 +941,60 @@ var renderWebUiHtml = (options) => {
|
|
|
909
941
|
border-top: 1px solid var(--border-2);
|
|
910
942
|
padding: 10px 12px 12px;
|
|
911
943
|
display: grid;
|
|
912
|
-
gap:
|
|
913
|
-
background: var(--inset-1);
|
|
944
|
+
gap: 10px;
|
|
914
945
|
}
|
|
915
946
|
.approval-requests-label {
|
|
916
|
-
font-size:
|
|
947
|
+
font-size: 12px;
|
|
917
948
|
text-transform: uppercase;
|
|
918
949
|
letter-spacing: 0.06em;
|
|
919
950
|
color: var(--fg-approval-label);
|
|
920
951
|
font-weight: 600;
|
|
921
952
|
}
|
|
953
|
+
.approval-requests-label code {
|
|
954
|
+
font-family: ui-monospace, "SF Mono", "Fira Code", monospace;
|
|
955
|
+
text-transform: none;
|
|
956
|
+
letter-spacing: 0;
|
|
957
|
+
color: var(--fg-strong);
|
|
958
|
+
}
|
|
922
959
|
.approval-request-item {
|
|
923
|
-
border: 1px solid var(--border-3);
|
|
924
|
-
background: var(--surface-2);
|
|
925
|
-
border-radius: 8px;
|
|
926
|
-
padding: 8px;
|
|
927
960
|
display: grid;
|
|
928
|
-
gap:
|
|
961
|
+
gap: 8px;
|
|
929
962
|
}
|
|
930
|
-
.approval-request-
|
|
931
|
-
|
|
932
|
-
|
|
963
|
+
.approval-request-table {
|
|
964
|
+
width: 100%;
|
|
965
|
+
border-collapse: collapse;
|
|
966
|
+
border: none;
|
|
967
|
+
font-size: 14px;
|
|
968
|
+
line-height: 1.5;
|
|
969
|
+
}
|
|
970
|
+
.approval-request-table tr,
|
|
971
|
+
.approval-request-table td {
|
|
972
|
+
border: none;
|
|
973
|
+
background: none;
|
|
974
|
+
}
|
|
975
|
+
.approval-request-table td {
|
|
976
|
+
padding: 4px 0;
|
|
977
|
+
vertical-align: top;
|
|
978
|
+
}
|
|
979
|
+
.approval-request-table .ak {
|
|
933
980
|
font-weight: 600;
|
|
934
|
-
|
|
981
|
+
color: var(--fg-approval-label);
|
|
982
|
+
white-space: nowrap;
|
|
983
|
+
width: 1%;
|
|
984
|
+
padding-right: 20px;
|
|
935
985
|
}
|
|
936
|
-
.approval-request-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
color: var(--fg-approval-input);
|
|
940
|
-
background: var(--inset-2);
|
|
941
|
-
border-radius: 6px;
|
|
942
|
-
padding: 6px;
|
|
986
|
+
.approval-request-table .av,
|
|
987
|
+
.approval-request-table .av-complex {
|
|
988
|
+
color: var(--fg);
|
|
943
989
|
overflow-wrap: anywhere;
|
|
944
|
-
|
|
990
|
+
white-space: pre-wrap;
|
|
991
|
+
max-height: 200px;
|
|
945
992
|
overflow-y: auto;
|
|
993
|
+
display: block;
|
|
994
|
+
}
|
|
995
|
+
.approval-request-table .av-complex {
|
|
996
|
+
font-family: ui-monospace, "SF Mono", "Fira Code", monospace;
|
|
997
|
+
font-size: 12px;
|
|
946
998
|
}
|
|
947
999
|
.approval-request-actions {
|
|
948
1000
|
display: flex;
|
|
@@ -983,6 +1035,7 @@ var renderWebUiHtml = (options) => {
|
|
|
983
1035
|
line-height: 1.5;
|
|
984
1036
|
overflow-wrap: break-word;
|
|
985
1037
|
word-break: break-word;
|
|
1038
|
+
white-space: pre-wrap;
|
|
986
1039
|
}
|
|
987
1040
|
.empty-state {
|
|
988
1041
|
display: flex;
|
|
@@ -1656,18 +1709,20 @@ var renderWebUiHtml = (options) => {
|
|
|
1656
1709
|
.map((req) => {
|
|
1657
1710
|
const approvalId = typeof req.approvalId === "string" ? req.approvalId : "";
|
|
1658
1711
|
const tool = typeof req.tool === "string" ? req.tool : "tool";
|
|
1659
|
-
const
|
|
1712
|
+
const input = req.input != null ? req.input : {};
|
|
1660
1713
|
const submitting = req.state === "submitting";
|
|
1661
1714
|
const approveLabel = submitting && req.pendingDecision === "approve" ? "Approving..." : "Approve";
|
|
1662
1715
|
const denyLabel = submitting && req.pendingDecision === "deny" ? "Denying..." : "Deny";
|
|
1716
|
+
const errorHtml = req._error
|
|
1717
|
+
? '<div style="color: var(--deny); font-size: 11px; margin-top: 4px;">Submit failed: ' + escapeHtml(req._error) + "</div>"
|
|
1718
|
+
: "";
|
|
1663
1719
|
return (
|
|
1664
1720
|
'<div class="approval-request-item">' +
|
|
1665
|
-
'<div class="approval-
|
|
1721
|
+
'<div class="approval-requests-label">Approval required: <code>' +
|
|
1666
1722
|
escapeHtml(tool) +
|
|
1667
|
-
"</div>" +
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
"</div>" +
|
|
1723
|
+
"</code></div>" +
|
|
1724
|
+
renderInputTable(input) +
|
|
1725
|
+
errorHtml +
|
|
1671
1726
|
'<div class="approval-request-actions">' +
|
|
1672
1727
|
'<button class="approval-action-btn approve" data-approval-id="' +
|
|
1673
1728
|
escapeHtml(approvalId) +
|
|
@@ -1690,7 +1745,6 @@ var renderWebUiHtml = (options) => {
|
|
|
1690
1745
|
.join("");
|
|
1691
1746
|
return (
|
|
1692
1747
|
'<div class="approval-requests">' +
|
|
1693
|
-
'<div class="approval-requests-label">Approval required</div>' +
|
|
1694
1748
|
rows +
|
|
1695
1749
|
"</div>"
|
|
1696
1750
|
);
|
|
@@ -1720,22 +1774,46 @@ var renderWebUiHtml = (options) => {
|
|
|
1720
1774
|
"</details>"
|
|
1721
1775
|
)
|
|
1722
1776
|
: "";
|
|
1777
|
+
const cls = "tool-activity" + (hasApprovals ? " has-approvals" : "");
|
|
1723
1778
|
return (
|
|
1724
|
-
'<div class="
|
|
1779
|
+
'<div class="' + cls + '">' +
|
|
1725
1780
|
disclosure +
|
|
1726
1781
|
renderApprovalRequests(approvalRequests) +
|
|
1727
1782
|
"</div>"
|
|
1728
1783
|
);
|
|
1729
1784
|
};
|
|
1730
1785
|
|
|
1731
|
-
const
|
|
1732
|
-
|
|
1733
|
-
return
|
|
1734
|
-
typeof nestedValue === "bigint" ? String(nestedValue) : nestedValue,
|
|
1735
|
-
);
|
|
1736
|
-
} catch {
|
|
1737
|
-
return "[unserializable input]";
|
|
1786
|
+
const renderInputTable = (input) => {
|
|
1787
|
+
if (!input || typeof input !== "object") {
|
|
1788
|
+
return '<div class="av-complex">' + escapeHtml(String(input ?? "{}")) + "</div>";
|
|
1738
1789
|
}
|
|
1790
|
+
const keys = Object.keys(input);
|
|
1791
|
+
if (keys.length === 0) {
|
|
1792
|
+
return '<div class="av-complex">{}</div>';
|
|
1793
|
+
}
|
|
1794
|
+
const formatValue = (val) => {
|
|
1795
|
+
if (val === null || val === undefined) return escapeHtml("null");
|
|
1796
|
+
if (typeof val === "boolean" || typeof val === "number") return escapeHtml(String(val));
|
|
1797
|
+
if (typeof val === "string") return escapeHtml(val);
|
|
1798
|
+
try {
|
|
1799
|
+
const replacer = (_, v) => typeof v === "bigint" ? String(v) : v;
|
|
1800
|
+
return escapeHtml(JSON.stringify(val, replacer, 2));
|
|
1801
|
+
} catch {
|
|
1802
|
+
return escapeHtml("[unserializable]");
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
const rows = keys.map((key) => {
|
|
1806
|
+
const val = input[key];
|
|
1807
|
+
const isComplex = val !== null && typeof val === "object";
|
|
1808
|
+
const cls = isComplex ? "av-complex" : "av";
|
|
1809
|
+
return (
|
|
1810
|
+
"<tr>" +
|
|
1811
|
+
'<td class="ak">' + escapeHtml(key) + "</td>" +
|
|
1812
|
+
'<td><div class="' + cls + '">' + formatValue(val) + "</div></td>" +
|
|
1813
|
+
"</tr>"
|
|
1814
|
+
);
|
|
1815
|
+
}).join("");
|
|
1816
|
+
return '<table class="approval-request-table">' + rows + "</table>";
|
|
1739
1817
|
};
|
|
1740
1818
|
|
|
1741
1819
|
const updatePendingApproval = (approvalId, updater) => {
|
|
@@ -1774,12 +1852,10 @@ var renderWebUiHtml = (options) => {
|
|
|
1774
1852
|
return null;
|
|
1775
1853
|
}
|
|
1776
1854
|
const toolName = item && typeof item.tool === "string" ? item.tool : "tool";
|
|
1777
|
-
const preview = safeJsonPreview(item?.input ?? {});
|
|
1778
|
-
const inputPreview = preview.length > 600 ? preview.slice(0, 600) + "..." : preview;
|
|
1779
1855
|
return {
|
|
1780
1856
|
approvalId,
|
|
1781
1857
|
tool: toolName,
|
|
1782
|
-
|
|
1858
|
+
input: item?.input ?? {},
|
|
1783
1859
|
state: "pending",
|
|
1784
1860
|
};
|
|
1785
1861
|
})
|
|
@@ -1857,53 +1933,87 @@ var renderWebUiHtml = (options) => {
|
|
|
1857
1933
|
elements.shell.classList.toggle("sidebar-open", open);
|
|
1858
1934
|
};
|
|
1859
1935
|
|
|
1860
|
-
const
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
const item = document.createElement("div");
|
|
1864
|
-
item.className = "conversation-item" + (c.conversationId === state.activeConversationId ? " active" : "");
|
|
1865
|
-
item.textContent = c.title;
|
|
1866
|
-
|
|
1867
|
-
const isConfirming = state.confirmDeleteId === c.conversationId;
|
|
1868
|
-
const deleteBtn = document.createElement("button");
|
|
1869
|
-
deleteBtn.className = "delete-btn" + (isConfirming ? " confirming" : "");
|
|
1870
|
-
deleteBtn.textContent = isConfirming ? "sure?" : "\\u00d7";
|
|
1871
|
-
deleteBtn.onclick = async (e) => {
|
|
1872
|
-
e.stopPropagation();
|
|
1873
|
-
if (!isConfirming) {
|
|
1874
|
-
state.confirmDeleteId = c.conversationId;
|
|
1875
|
-
renderConversationList();
|
|
1876
|
-
return;
|
|
1877
|
-
}
|
|
1878
|
-
await api("/api/conversations/" + c.conversationId, { method: "DELETE" });
|
|
1879
|
-
if (state.activeConversationId === c.conversationId) {
|
|
1880
|
-
state.activeConversationId = null;
|
|
1881
|
-
state.activeMessages = [];
|
|
1882
|
-
state.contextTokens = 0;
|
|
1883
|
-
state.contextWindow = 0;
|
|
1884
|
-
updateContextRing();
|
|
1885
|
-
pushConversationUrl(null);
|
|
1886
|
-
elements.chatTitle.textContent = "";
|
|
1887
|
-
renderMessages([]);
|
|
1888
|
-
}
|
|
1889
|
-
state.confirmDeleteId = null;
|
|
1890
|
-
await loadConversations();
|
|
1891
|
-
};
|
|
1892
|
-
item.appendChild(deleteBtn);
|
|
1936
|
+
const buildConversationItem = (c) => {
|
|
1937
|
+
const item = document.createElement("div");
|
|
1938
|
+
item.className = "conversation-item" + (c.conversationId === state.activeConversationId ? " active" : "");
|
|
1893
1939
|
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1940
|
+
if (c.hasPendingApprovals) {
|
|
1941
|
+
const dot = document.createElement("span");
|
|
1942
|
+
dot.className = "approval-dot";
|
|
1943
|
+
item.appendChild(dot);
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
const titleSpan = document.createElement("span");
|
|
1947
|
+
titleSpan.textContent = c.title;
|
|
1948
|
+
item.appendChild(titleSpan);
|
|
1949
|
+
|
|
1950
|
+
const isConfirming = state.confirmDeleteId === c.conversationId;
|
|
1951
|
+
const deleteBtn = document.createElement("button");
|
|
1952
|
+
deleteBtn.className = "delete-btn" + (isConfirming ? " confirming" : "");
|
|
1953
|
+
deleteBtn.textContent = isConfirming ? "sure?" : "\\u00d7";
|
|
1954
|
+
deleteBtn.onclick = async (e) => {
|
|
1955
|
+
e.stopPropagation();
|
|
1956
|
+
if (!isConfirming) {
|
|
1957
|
+
state.confirmDeleteId = c.conversationId;
|
|
1901
1958
|
renderConversationList();
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
};
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
await api("/api/conversations/" + c.conversationId, { method: "DELETE" });
|
|
1962
|
+
if (state.activeConversationId === c.conversationId) {
|
|
1963
|
+
state.activeConversationId = null;
|
|
1964
|
+
state.activeMessages = [];
|
|
1965
|
+
state.contextTokens = 0;
|
|
1966
|
+
state.contextWindow = 0;
|
|
1967
|
+
updateContextRing();
|
|
1968
|
+
pushConversationUrl(null);
|
|
1969
|
+
elements.chatTitle.textContent = "";
|
|
1970
|
+
renderMessages([]);
|
|
1971
|
+
}
|
|
1972
|
+
state.confirmDeleteId = null;
|
|
1973
|
+
await loadConversations();
|
|
1974
|
+
};
|
|
1975
|
+
item.appendChild(deleteBtn);
|
|
1976
|
+
|
|
1977
|
+
item.onclick = async () => {
|
|
1978
|
+
if (state.confirmDeleteId) {
|
|
1979
|
+
state.confirmDeleteId = null;
|
|
1980
|
+
}
|
|
1981
|
+
state.activeConversationId = c.conversationId;
|
|
1982
|
+
pushConversationUrl(c.conversationId);
|
|
1983
|
+
renderConversationList();
|
|
1984
|
+
await loadConversation(c.conversationId);
|
|
1985
|
+
if (isMobile()) setSidebarOpen(false);
|
|
1986
|
+
};
|
|
1905
1987
|
|
|
1906
|
-
|
|
1988
|
+
return item;
|
|
1989
|
+
};
|
|
1990
|
+
|
|
1991
|
+
const renderConversationList = () => {
|
|
1992
|
+
elements.list.innerHTML = "";
|
|
1993
|
+
const pending = state.conversations.filter(c => c.hasPendingApprovals);
|
|
1994
|
+
const rest = state.conversations.filter(c => !c.hasPendingApprovals);
|
|
1995
|
+
|
|
1996
|
+
if (pending.length > 0) {
|
|
1997
|
+
const label = document.createElement("div");
|
|
1998
|
+
label.className = "sidebar-section-label";
|
|
1999
|
+
label.textContent = "Awaiting approval";
|
|
2000
|
+
elements.list.appendChild(label);
|
|
2001
|
+
for (const c of pending) {
|
|
2002
|
+
elements.list.appendChild(buildConversationItem(c));
|
|
2003
|
+
}
|
|
2004
|
+
if (rest.length > 0) {
|
|
2005
|
+
const divider = document.createElement("div");
|
|
2006
|
+
divider.className = "sidebar-section-divider";
|
|
2007
|
+
elements.list.appendChild(divider);
|
|
2008
|
+
const recentLabel = document.createElement("div");
|
|
2009
|
+
recentLabel.className = "sidebar-section-label";
|
|
2010
|
+
recentLabel.textContent = "Recent";
|
|
2011
|
+
elements.list.appendChild(recentLabel);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
for (const c of rest) {
|
|
2016
|
+
elements.list.appendChild(buildConversationItem(c));
|
|
1907
2017
|
}
|
|
1908
2018
|
};
|
|
1909
2019
|
|
|
@@ -2332,8 +2442,6 @@ var renderWebUiHtml = (options) => {
|
|
|
2332
2442
|
const approvalId =
|
|
2333
2443
|
typeof payload.approvalId === "string" ? payload.approvalId : "";
|
|
2334
2444
|
if (approvalId) {
|
|
2335
|
-
const preview = safeJsonPreview(payload.input ?? {});
|
|
2336
|
-
const inputPreview = preview.length > 600 ? preview.slice(0, 600) + "..." : preview;
|
|
2337
2445
|
if (!Array.isArray(assistantMessage._pendingApprovals)) {
|
|
2338
2446
|
assistantMessage._pendingApprovals = [];
|
|
2339
2447
|
}
|
|
@@ -2344,7 +2452,7 @@ var renderWebUiHtml = (options) => {
|
|
|
2344
2452
|
assistantMessage._pendingApprovals.push({
|
|
2345
2453
|
approvalId,
|
|
2346
2454
|
tool: toolName,
|
|
2347
|
-
|
|
2455
|
+
input: payload.input ?? {},
|
|
2348
2456
|
state: "pending",
|
|
2349
2457
|
});
|
|
2350
2458
|
}
|
|
@@ -2992,8 +3100,6 @@ var renderWebUiHtml = (options) => {
|
|
|
2992
3100
|
const approvalId =
|
|
2993
3101
|
typeof payload.approvalId === "string" ? payload.approvalId : "";
|
|
2994
3102
|
if (approvalId) {
|
|
2995
|
-
const preview = safeJsonPreview(payload.input ?? {});
|
|
2996
|
-
const inputPreview = preview.length > 600 ? preview.slice(0, 600) + "..." : preview;
|
|
2997
3103
|
if (!Array.isArray(assistantMessage._pendingApprovals)) {
|
|
2998
3104
|
assistantMessage._pendingApprovals = [];
|
|
2999
3105
|
}
|
|
@@ -3004,7 +3110,7 @@ var renderWebUiHtml = (options) => {
|
|
|
3004
3110
|
assistantMessage._pendingApprovals.push({
|
|
3005
3111
|
approvalId,
|
|
3006
3112
|
tool: toolName,
|
|
3007
|
-
|
|
3113
|
+
input: payload.input ?? {},
|
|
3008
3114
|
state: "pending",
|
|
3009
3115
|
});
|
|
3010
3116
|
}
|
|
@@ -3353,17 +3459,23 @@ var renderWebUiHtml = (options) => {
|
|
|
3353
3459
|
});
|
|
3354
3460
|
updatePendingApproval(approvalId, () => null);
|
|
3355
3461
|
renderMessages(state.activeMessages, state.isStreaming);
|
|
3462
|
+
loadConversations();
|
|
3356
3463
|
if (!wasStreaming && state.activeConversationId) {
|
|
3357
|
-
await streamConversationEvents(state.activeConversationId);
|
|
3464
|
+
await streamConversationEvents(state.activeConversationId, { liveOnly: true });
|
|
3358
3465
|
}
|
|
3359
3466
|
} catch (error) {
|
|
3360
|
-
const
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3467
|
+
const isStale = error && error.payload && error.payload.code === "APPROVAL_NOT_FOUND";
|
|
3468
|
+
if (isStale) {
|
|
3469
|
+
updatePendingApproval(approvalId, () => null);
|
|
3470
|
+
} else {
|
|
3471
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
3472
|
+
updatePendingApproval(approvalId, (request) => ({
|
|
3473
|
+
...request,
|
|
3474
|
+
state: "pending",
|
|
3475
|
+
pendingDecision: null,
|
|
3476
|
+
_error: errMsg,
|
|
3477
|
+
}));
|
|
3478
|
+
}
|
|
3367
3479
|
renderMessages(state.activeMessages, state.isStreaming);
|
|
3368
3480
|
} finally {
|
|
3369
3481
|
if (!wasStreaming) {
|
|
@@ -5893,7 +6005,6 @@ var createRequestHandler = async (options) => {
|
|
|
5893
6005
|
const runOwners = /* @__PURE__ */ new Map();
|
|
5894
6006
|
const runConversations = /* @__PURE__ */ new Map();
|
|
5895
6007
|
const activeConversationRuns = /* @__PURE__ */ new Map();
|
|
5896
|
-
const pendingApprovals = /* @__PURE__ */ new Map();
|
|
5897
6008
|
const conversationEventStreams = /* @__PURE__ */ new Map();
|
|
5898
6009
|
const broadcastEvent = (conversationId, event) => {
|
|
5899
6010
|
let stream = conversationEventStreams.get(conversationId);
|
|
@@ -5925,51 +6036,19 @@ var createRequestHandler = async (options) => {
|
|
|
5925
6036
|
setTimeout(() => conversationEventStreams.delete(conversationId), 3e4);
|
|
5926
6037
|
}
|
|
5927
6038
|
};
|
|
5928
|
-
const persistConversationPendingApprovals = async (conversationId) => {
|
|
5929
|
-
const conversation = await conversationStore.get(conversationId);
|
|
5930
|
-
if (!conversation) {
|
|
5931
|
-
return;
|
|
5932
|
-
}
|
|
5933
|
-
conversation.pendingApprovals = Array.from(pendingApprovals.entries()).filter(
|
|
5934
|
-
([, pending]) => pending.ownerId === conversation.ownerId && pending.conversationId === conversationId
|
|
5935
|
-
).map(([approvalId, pending]) => ({
|
|
5936
|
-
approvalId,
|
|
5937
|
-
runId: pending.runId,
|
|
5938
|
-
tool: pending.tool,
|
|
5939
|
-
input: pending.input
|
|
5940
|
-
}));
|
|
5941
|
-
await conversationStore.update(conversation);
|
|
5942
|
-
};
|
|
5943
6039
|
const clearPendingApprovalsForConversation = async (conversationId) => {
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
pending.resolve(false);
|
|
6040
|
+
const conversation = await conversationStore.get(conversationId);
|
|
6041
|
+
if (!conversation) return;
|
|
6042
|
+
if (Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0) {
|
|
6043
|
+
conversation.pendingApprovals = [];
|
|
6044
|
+
await conversationStore.update(conversation);
|
|
5950
6045
|
}
|
|
5951
|
-
await persistConversationPendingApprovals(conversationId);
|
|
5952
6046
|
};
|
|
5953
6047
|
const uploadStore = await createUploadStore(config?.uploads, workingDir);
|
|
5954
6048
|
const harness = new AgentHarness({
|
|
5955
6049
|
workingDir,
|
|
5956
6050
|
environment: resolveHarnessEnvironment(),
|
|
5957
|
-
uploadStore
|
|
5958
|
-
approvalHandler: async (request) => new Promise((resolveApproval) => {
|
|
5959
|
-
const ownerIdForRun = runOwners.get(request.runId) ?? "local-owner";
|
|
5960
|
-
const conversationIdForRun = runConversations.get(request.runId) ?? null;
|
|
5961
|
-
pendingApprovals.set(request.approvalId, {
|
|
5962
|
-
ownerId: ownerIdForRun,
|
|
5963
|
-
runId: request.runId,
|
|
5964
|
-
conversationId: conversationIdForRun,
|
|
5965
|
-
tool: request.tool,
|
|
5966
|
-
input: request.input,
|
|
5967
|
-
resolve: resolveApproval
|
|
5968
|
-
});
|
|
5969
|
-
if (conversationIdForRun) {
|
|
5970
|
-
void persistConversationPendingApprovals(conversationIdForRun);
|
|
5971
|
-
}
|
|
5972
|
-
})
|
|
6051
|
+
uploadStore
|
|
5973
6052
|
});
|
|
5974
6053
|
await harness.initialize();
|
|
5975
6054
|
const telemetry = new TelemetryEmitter(config?.telemetry);
|
|
@@ -5978,6 +6057,162 @@ var createRequestHandler = async (options) => {
|
|
|
5978
6057
|
workingDir,
|
|
5979
6058
|
agentId: identity.id
|
|
5980
6059
|
});
|
|
6060
|
+
const resumeRunFromCheckpoint = async (conversationId, conversation, checkpoint, toolResults) => {
|
|
6061
|
+
const abortController = new AbortController();
|
|
6062
|
+
activeConversationRuns.set(conversationId, {
|
|
6063
|
+
ownerId: conversation.ownerId,
|
|
6064
|
+
abortController,
|
|
6065
|
+
runId: null
|
|
6066
|
+
});
|
|
6067
|
+
let latestRunId = conversation.runtimeRunId ?? "";
|
|
6068
|
+
let assistantResponse = "";
|
|
6069
|
+
const toolTimeline = [];
|
|
6070
|
+
const sections = [];
|
|
6071
|
+
let currentText = "";
|
|
6072
|
+
let currentTools = [];
|
|
6073
|
+
let checkpointedRun = false;
|
|
6074
|
+
const baseMessages = checkpoint.baseMessageCount != null ? conversation.messages.slice(0, checkpoint.baseMessageCount) : [];
|
|
6075
|
+
const fullCheckpointMessages = [...baseMessages, ...checkpoint.checkpointMessages];
|
|
6076
|
+
try {
|
|
6077
|
+
for await (const event of harness.continueFromToolResult({
|
|
6078
|
+
messages: fullCheckpointMessages,
|
|
6079
|
+
toolResults,
|
|
6080
|
+
conversationId,
|
|
6081
|
+
abortSignal: abortController.signal
|
|
6082
|
+
})) {
|
|
6083
|
+
if (event.type === "run:started") {
|
|
6084
|
+
latestRunId = event.runId;
|
|
6085
|
+
runOwners.set(event.runId, conversation.ownerId);
|
|
6086
|
+
runConversations.set(event.runId, conversationId);
|
|
6087
|
+
const active = activeConversationRuns.get(conversationId);
|
|
6088
|
+
if (active && active.abortController === abortController) {
|
|
6089
|
+
active.runId = event.runId;
|
|
6090
|
+
}
|
|
6091
|
+
}
|
|
6092
|
+
if (event.type === "model:chunk") {
|
|
6093
|
+
if (currentTools.length > 0) {
|
|
6094
|
+
sections.push({ type: "tools", content: currentTools });
|
|
6095
|
+
currentTools = [];
|
|
6096
|
+
}
|
|
6097
|
+
assistantResponse += event.content;
|
|
6098
|
+
currentText += event.content;
|
|
6099
|
+
}
|
|
6100
|
+
if (event.type === "tool:started") {
|
|
6101
|
+
if (currentText.length > 0) {
|
|
6102
|
+
sections.push({ type: "text", content: currentText });
|
|
6103
|
+
currentText = "";
|
|
6104
|
+
}
|
|
6105
|
+
const toolText = `- start \`${event.tool}\``;
|
|
6106
|
+
toolTimeline.push(toolText);
|
|
6107
|
+
currentTools.push(toolText);
|
|
6108
|
+
}
|
|
6109
|
+
if (event.type === "tool:completed") {
|
|
6110
|
+
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
6111
|
+
toolTimeline.push(toolText);
|
|
6112
|
+
currentTools.push(toolText);
|
|
6113
|
+
}
|
|
6114
|
+
if (event.type === "tool:error") {
|
|
6115
|
+
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
6116
|
+
toolTimeline.push(toolText);
|
|
6117
|
+
currentTools.push(toolText);
|
|
6118
|
+
}
|
|
6119
|
+
if (event.type === "tool:approval:required") {
|
|
6120
|
+
const toolText = `- approval required \`${event.tool}\``;
|
|
6121
|
+
toolTimeline.push(toolText);
|
|
6122
|
+
currentTools.push(toolText);
|
|
6123
|
+
}
|
|
6124
|
+
if (event.type === "tool:approval:checkpoint") {
|
|
6125
|
+
const conv = await conversationStore.get(conversationId);
|
|
6126
|
+
if (conv) {
|
|
6127
|
+
conv.pendingApprovals = [{
|
|
6128
|
+
approvalId: event.approvalId,
|
|
6129
|
+
runId: latestRunId,
|
|
6130
|
+
tool: event.tool,
|
|
6131
|
+
toolCallId: event.toolCallId,
|
|
6132
|
+
input: event.input,
|
|
6133
|
+
checkpointMessages: [...fullCheckpointMessages, ...event.checkpointMessages],
|
|
6134
|
+
baseMessageCount: 0,
|
|
6135
|
+
pendingToolCalls: event.pendingToolCalls
|
|
6136
|
+
}];
|
|
6137
|
+
conv.updatedAt = Date.now();
|
|
6138
|
+
await conversationStore.update(conv);
|
|
6139
|
+
}
|
|
6140
|
+
checkpointedRun = true;
|
|
6141
|
+
}
|
|
6142
|
+
if (event.type === "run:completed" && assistantResponse.length === 0 && event.result.response) {
|
|
6143
|
+
assistantResponse = event.result.response;
|
|
6144
|
+
}
|
|
6145
|
+
if (event.type === "run:error") {
|
|
6146
|
+
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
6147
|
+
}
|
|
6148
|
+
await telemetry.emit(event);
|
|
6149
|
+
broadcastEvent(conversationId, event);
|
|
6150
|
+
}
|
|
6151
|
+
} catch (err) {
|
|
6152
|
+
console.error("[resume-run] error:", err instanceof Error ? err.message : err);
|
|
6153
|
+
assistantResponse = assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
|
|
6154
|
+
}
|
|
6155
|
+
if (currentTools.length > 0) {
|
|
6156
|
+
sections.push({ type: "tools", content: currentTools });
|
|
6157
|
+
}
|
|
6158
|
+
if (currentText.length > 0) {
|
|
6159
|
+
sections.push({ type: "text", content: currentText });
|
|
6160
|
+
}
|
|
6161
|
+
if (!checkpointedRun) {
|
|
6162
|
+
const conv = await conversationStore.get(conversationId);
|
|
6163
|
+
if (conv) {
|
|
6164
|
+
const prevMessages = conv.messages;
|
|
6165
|
+
const hasAssistantContent = assistantResponse.length > 0 || toolTimeline.length > 0 || sections.length > 0;
|
|
6166
|
+
if (hasAssistantContent) {
|
|
6167
|
+
const lastMsg = prevMessages[prevMessages.length - 1];
|
|
6168
|
+
if (lastMsg && lastMsg.role === "assistant" && lastMsg.metadata) {
|
|
6169
|
+
const existingToolActivity = lastMsg.metadata.toolActivity;
|
|
6170
|
+
const existingSections = lastMsg.metadata.sections;
|
|
6171
|
+
const mergedTimeline = [
|
|
6172
|
+
...Array.isArray(existingToolActivity) ? existingToolActivity : [],
|
|
6173
|
+
...toolTimeline
|
|
6174
|
+
];
|
|
6175
|
+
const mergedSections = [
|
|
6176
|
+
...Array.isArray(existingSections) ? existingSections : [],
|
|
6177
|
+
...sections
|
|
6178
|
+
];
|
|
6179
|
+
const mergedText = (typeof lastMsg.content === "string" ? lastMsg.content : "") + assistantResponse;
|
|
6180
|
+
conv.messages = [
|
|
6181
|
+
...prevMessages.slice(0, -1),
|
|
6182
|
+
{
|
|
6183
|
+
role: "assistant",
|
|
6184
|
+
content: mergedText,
|
|
6185
|
+
metadata: {
|
|
6186
|
+
toolActivity: mergedTimeline,
|
|
6187
|
+
sections: mergedSections.length > 0 ? mergedSections : void 0
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
];
|
|
6191
|
+
} else {
|
|
6192
|
+
conv.messages = [
|
|
6193
|
+
...prevMessages,
|
|
6194
|
+
{
|
|
6195
|
+
role: "assistant",
|
|
6196
|
+
content: assistantResponse,
|
|
6197
|
+
metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
|
|
6198
|
+
}
|
|
6199
|
+
];
|
|
6200
|
+
}
|
|
6201
|
+
}
|
|
6202
|
+
conv.runtimeRunId = latestRunId || conv.runtimeRunId;
|
|
6203
|
+
conv.pendingApprovals = [];
|
|
6204
|
+
conv.updatedAt = Date.now();
|
|
6205
|
+
await conversationStore.update(conv);
|
|
6206
|
+
}
|
|
6207
|
+
}
|
|
6208
|
+
finishConversationStream(conversationId);
|
|
6209
|
+
activeConversationRuns.delete(conversationId);
|
|
6210
|
+
if (latestRunId) {
|
|
6211
|
+
runOwners.delete(latestRunId);
|
|
6212
|
+
runConversations.delete(latestRunId);
|
|
6213
|
+
}
|
|
6214
|
+
console.log("[resume-run] complete for", conversationId);
|
|
6215
|
+
};
|
|
5981
6216
|
const messagingRoutes = /* @__PURE__ */ new Map();
|
|
5982
6217
|
const messagingRouteRegistrar = (method, path, routeHandler) => {
|
|
5983
6218
|
let byMethod = messagingRoutes.get(path);
|
|
@@ -6026,6 +6261,7 @@ var createRequestHandler = async (options) => {
|
|
|
6026
6261
|
const sections = [];
|
|
6027
6262
|
let currentTools = [];
|
|
6028
6263
|
let currentText = "";
|
|
6264
|
+
let checkpointedRun = false;
|
|
6029
6265
|
const buildMessages = () => {
|
|
6030
6266
|
const draftSections = [
|
|
6031
6267
|
...sections.map((s) => ({
|
|
@@ -6116,19 +6352,22 @@ var createRequestHandler = async (options) => {
|
|
|
6116
6352
|
toolTimeline.push(toolText);
|
|
6117
6353
|
currentTools.push(toolText);
|
|
6118
6354
|
await persistDraftAssistantTurn();
|
|
6119
|
-
await persistConversationPendingApprovals(conversationId);
|
|
6120
6355
|
}
|
|
6121
|
-
if (event.type === "tool:approval:
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6356
|
+
if (event.type === "tool:approval:checkpoint") {
|
|
6357
|
+
await updateConversation((c) => {
|
|
6358
|
+
c.messages = buildMessages();
|
|
6359
|
+
c.pendingApprovals = [{
|
|
6360
|
+
approvalId: event.approvalId,
|
|
6361
|
+
runId: latestRunId,
|
|
6362
|
+
tool: event.tool,
|
|
6363
|
+
toolCallId: event.toolCallId,
|
|
6364
|
+
input: event.input,
|
|
6365
|
+
checkpointMessages: event.checkpointMessages,
|
|
6366
|
+
baseMessageCount: historyMessages.length,
|
|
6367
|
+
pendingToolCalls: event.pendingToolCalls
|
|
6368
|
+
}];
|
|
6369
|
+
});
|
|
6370
|
+
checkpointedRun = true;
|
|
6132
6371
|
}
|
|
6133
6372
|
if (event.type === "run:completed" && assistantResponse.length === 0 && event.result.response) {
|
|
6134
6373
|
assistantResponse = event.result.response;
|
|
@@ -6150,13 +6389,14 @@ var createRequestHandler = async (options) => {
|
|
|
6150
6389
|
sections.push({ type: "text", content: currentText });
|
|
6151
6390
|
currentText = "";
|
|
6152
6391
|
}
|
|
6153
|
-
|
|
6154
|
-
c
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6392
|
+
if (!checkpointedRun) {
|
|
6393
|
+
await updateConversation((c) => {
|
|
6394
|
+
c.messages = buildMessages();
|
|
6395
|
+
c.runtimeRunId = latestRunId || c.runtimeRunId;
|
|
6396
|
+
c.pendingApprovals = [];
|
|
6397
|
+
});
|
|
6398
|
+
}
|
|
6158
6399
|
finishConversationStream(conversationId);
|
|
6159
|
-
await persistConversationPendingApprovals(conversationId);
|
|
6160
6400
|
if (latestRunId) {
|
|
6161
6401
|
runOwners.delete(latestRunId);
|
|
6162
6402
|
runConversations.delete(latestRunId);
|
|
@@ -6418,7 +6658,8 @@ var createRequestHandler = async (options) => {
|
|
|
6418
6658
|
tenantId: conversation.tenantId,
|
|
6419
6659
|
createdAt: conversation.createdAt,
|
|
6420
6660
|
updatedAt: conversation.updatedAt,
|
|
6421
|
-
messageCount: conversation.messages.length
|
|
6661
|
+
messageCount: conversation.messages.length,
|
|
6662
|
+
hasPendingApprovals: Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0
|
|
6422
6663
|
}))
|
|
6423
6664
|
});
|
|
6424
6665
|
return;
|
|
@@ -6442,36 +6683,77 @@ var createRequestHandler = async (options) => {
|
|
|
6442
6683
|
const approvalMatch = pathname.match(/^\/api\/approvals\/([^/]+)$/);
|
|
6443
6684
|
if (approvalMatch && request.method === "POST") {
|
|
6444
6685
|
const approvalId = decodeURIComponent(approvalMatch[1] ?? "");
|
|
6445
|
-
const
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
conversation.pendingApprovals = next;
|
|
6458
|
-
await conversationStore.update(conversation);
|
|
6459
|
-
prunedStale = true;
|
|
6460
|
-
}
|
|
6686
|
+
const body = await readRequestBody(request);
|
|
6687
|
+
const approved = body.approved === true;
|
|
6688
|
+
const conversations = await conversationStore.list(ownerId);
|
|
6689
|
+
let foundConversation;
|
|
6690
|
+
let foundApproval;
|
|
6691
|
+
for (const conv of conversations) {
|
|
6692
|
+
if (!Array.isArray(conv.pendingApprovals)) continue;
|
|
6693
|
+
const match = conv.pendingApprovals.find((a) => a.approvalId === approvalId);
|
|
6694
|
+
if (match) {
|
|
6695
|
+
foundConversation = conv;
|
|
6696
|
+
foundApproval = match;
|
|
6697
|
+
break;
|
|
6461
6698
|
}
|
|
6699
|
+
}
|
|
6700
|
+
if (!foundConversation || !foundApproval) {
|
|
6462
6701
|
writeJson(response, 404, {
|
|
6463
6702
|
code: "APPROVAL_NOT_FOUND",
|
|
6464
|
-
message:
|
|
6703
|
+
message: "Approval request not found"
|
|
6465
6704
|
});
|
|
6466
6705
|
return;
|
|
6467
6706
|
}
|
|
6468
|
-
const
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6707
|
+
const conversationId = foundConversation.conversationId;
|
|
6708
|
+
if (!foundApproval.checkpointMessages || !foundApproval.toolCallId) {
|
|
6709
|
+
foundConversation.pendingApprovals = (foundConversation.pendingApprovals ?? []).filter((a) => a.approvalId !== approvalId);
|
|
6710
|
+
await conversationStore.update(foundConversation);
|
|
6711
|
+
writeJson(response, 404, {
|
|
6712
|
+
code: "APPROVAL_NOT_FOUND",
|
|
6713
|
+
message: "Approval request is no longer active (no checkpoint data)"
|
|
6714
|
+
});
|
|
6715
|
+
return;
|
|
6473
6716
|
}
|
|
6474
|
-
|
|
6717
|
+
foundConversation.pendingApprovals = (foundConversation.pendingApprovals ?? []).filter((a) => a.approvalId !== approvalId);
|
|
6718
|
+
await conversationStore.update(foundConversation);
|
|
6719
|
+
broadcastEvent(
|
|
6720
|
+
conversationId,
|
|
6721
|
+
approved ? { type: "tool:approval:granted", approvalId } : { type: "tool:approval:denied", approvalId }
|
|
6722
|
+
);
|
|
6723
|
+
void (async () => {
|
|
6724
|
+
let toolResults;
|
|
6725
|
+
if (approved) {
|
|
6726
|
+
const toolContext = {
|
|
6727
|
+
runId: foundApproval.runId,
|
|
6728
|
+
agentId: identity.id,
|
|
6729
|
+
step: 0,
|
|
6730
|
+
workingDir,
|
|
6731
|
+
parameters: {}
|
|
6732
|
+
};
|
|
6733
|
+
const execResults = await harness.executeTools(
|
|
6734
|
+
[{ id: foundApproval.toolCallId, name: foundApproval.tool, input: foundApproval.input }],
|
|
6735
|
+
toolContext
|
|
6736
|
+
);
|
|
6737
|
+
toolResults = execResults.map((r) => ({
|
|
6738
|
+
callId: r.callId,
|
|
6739
|
+
toolName: r.tool,
|
|
6740
|
+
result: r.output,
|
|
6741
|
+
error: r.error
|
|
6742
|
+
}));
|
|
6743
|
+
} else {
|
|
6744
|
+
toolResults = [{
|
|
6745
|
+
callId: foundApproval.toolCallId,
|
|
6746
|
+
toolName: foundApproval.tool,
|
|
6747
|
+
error: "Tool execution denied by user"
|
|
6748
|
+
}];
|
|
6749
|
+
}
|
|
6750
|
+
await resumeRunFromCheckpoint(
|
|
6751
|
+
conversationId,
|
|
6752
|
+
foundConversation,
|
|
6753
|
+
foundApproval,
|
|
6754
|
+
toolResults
|
|
6755
|
+
);
|
|
6756
|
+
})();
|
|
6475
6757
|
writeJson(response, 200, { ok: true, approvalId, approved });
|
|
6476
6758
|
return;
|
|
6477
6759
|
}
|
|
@@ -6533,30 +6815,18 @@ var createRequestHandler = async (options) => {
|
|
|
6533
6815
|
return;
|
|
6534
6816
|
}
|
|
6535
6817
|
if (request.method === "GET") {
|
|
6536
|
-
const storedPending = Array.isArray(conversation.pendingApprovals) ? conversation.pendingApprovals
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
tool: pending.tool,
|
|
6543
|
-
input: pending.input
|
|
6544
|
-
}));
|
|
6545
|
-
const mergedPendingById = /* @__PURE__ */ new Map();
|
|
6546
|
-
for (const approval of storedPending) {
|
|
6547
|
-
if (approval && typeof approval.approvalId === "string") {
|
|
6548
|
-
mergedPendingById.set(approval.approvalId, approval);
|
|
6549
|
-
}
|
|
6550
|
-
}
|
|
6551
|
-
for (const approval of livePending) {
|
|
6552
|
-
mergedPendingById.set(approval.approvalId, approval);
|
|
6553
|
-
}
|
|
6818
|
+
const storedPending = Array.isArray(conversation.pendingApprovals) ? conversation.pendingApprovals.map((a) => ({
|
|
6819
|
+
approvalId: a.approvalId,
|
|
6820
|
+
runId: a.runId,
|
|
6821
|
+
tool: a.tool,
|
|
6822
|
+
input: a.input
|
|
6823
|
+
})) : [];
|
|
6554
6824
|
const activeStream = conversationEventStreams.get(conversationId);
|
|
6555
6825
|
const hasActiveRun = !!activeStream && !activeStream.finished;
|
|
6556
6826
|
writeJson(response, 200, {
|
|
6557
6827
|
conversation: {
|
|
6558
6828
|
...conversation,
|
|
6559
|
-
pendingApprovals:
|
|
6829
|
+
pendingApprovals: storedPending
|
|
6560
6830
|
},
|
|
6561
6831
|
hasActiveRun
|
|
6562
6832
|
});
|
|
@@ -6740,6 +7010,7 @@ var createRequestHandler = async (options) => {
|
|
|
6740
7010
|
let currentText = "";
|
|
6741
7011
|
let currentTools = [];
|
|
6742
7012
|
let runCancelled = false;
|
|
7013
|
+
let checkpointedRun = false;
|
|
6743
7014
|
let userContent = messageText;
|
|
6744
7015
|
if (files.length > 0) {
|
|
6745
7016
|
try {
|
|
@@ -6877,17 +7148,36 @@ var createRequestHandler = async (options) => {
|
|
|
6877
7148
|
currentTools.push(toolText);
|
|
6878
7149
|
await persistDraftAssistantTurn();
|
|
6879
7150
|
}
|
|
6880
|
-
if (event.type === "tool:approval:
|
|
6881
|
-
const
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
7151
|
+
if (event.type === "tool:approval:checkpoint") {
|
|
7152
|
+
const checkpointSections = [...sections];
|
|
7153
|
+
if (currentTools.length > 0) {
|
|
7154
|
+
checkpointSections.push({ type: "tools", content: [...currentTools] });
|
|
7155
|
+
}
|
|
7156
|
+
if (currentText.length > 0) {
|
|
7157
|
+
checkpointSections.push({ type: "text", content: currentText });
|
|
7158
|
+
}
|
|
7159
|
+
conversation.messages = [
|
|
7160
|
+
...historyMessages,
|
|
7161
|
+
{ role: "user", content: userContent },
|
|
7162
|
+
...assistantResponse.length > 0 || toolTimeline.length > 0 || checkpointSections.length > 0 ? [{
|
|
7163
|
+
role: "assistant",
|
|
7164
|
+
content: assistantResponse,
|
|
7165
|
+
metadata: toolTimeline.length > 0 || checkpointSections.length > 0 ? { toolActivity: [...toolTimeline], sections: checkpointSections.length > 0 ? checkpointSections : void 0 } : void 0
|
|
7166
|
+
}] : []
|
|
7167
|
+
];
|
|
7168
|
+
conversation.pendingApprovals = [{
|
|
7169
|
+
approvalId: event.approvalId,
|
|
7170
|
+
runId: latestRunId,
|
|
7171
|
+
tool: event.tool,
|
|
7172
|
+
toolCallId: event.toolCallId,
|
|
7173
|
+
input: event.input,
|
|
7174
|
+
checkpointMessages: event.checkpointMessages,
|
|
7175
|
+
baseMessageCount: historyMessages.length,
|
|
7176
|
+
pendingToolCalls: event.pendingToolCalls
|
|
7177
|
+
}];
|
|
7178
|
+
conversation.updatedAt = Date.now();
|
|
7179
|
+
await conversationStore.update(conversation);
|
|
7180
|
+
checkpointedRun = true;
|
|
6891
7181
|
}
|
|
6892
7182
|
if (event.type === "run:completed" && assistantResponse.length === 0 && event.result.response) {
|
|
6893
7183
|
assistantResponse = event.result.response;
|
|
@@ -6905,23 +7195,25 @@ var createRequestHandler = async (options) => {
|
|
|
6905
7195
|
if (currentText.length > 0) {
|
|
6906
7196
|
sections.push({ type: "text", content: currentText });
|
|
6907
7197
|
}
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
7198
|
+
if (!checkpointedRun) {
|
|
7199
|
+
const hasAssistantContent = assistantResponse.length > 0 || toolTimeline.length > 0 || sections.length > 0;
|
|
7200
|
+
conversation.messages = hasAssistantContent ? [
|
|
7201
|
+
...historyMessages,
|
|
7202
|
+
{ role: "user", content: userContent },
|
|
7203
|
+
{
|
|
7204
|
+
role: "assistant",
|
|
7205
|
+
content: assistantResponse,
|
|
7206
|
+
metadata: toolTimeline.length > 0 || sections.length > 0 ? {
|
|
7207
|
+
toolActivity: toolTimeline,
|
|
7208
|
+
sections: sections.length > 0 ? sections : void 0
|
|
7209
|
+
} : void 0
|
|
7210
|
+
}
|
|
7211
|
+
] : [...historyMessages, { role: "user", content: userContent }];
|
|
7212
|
+
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
7213
|
+
conversation.pendingApprovals = [];
|
|
7214
|
+
conversation.updatedAt = Date.now();
|
|
7215
|
+
await conversationStore.update(conversation);
|
|
7216
|
+
}
|
|
6925
7217
|
} catch (error) {
|
|
6926
7218
|
if (abortController.signal.aborted || runCancelled) {
|
|
6927
7219
|
const fallbackSections = [...sections];
|
|
@@ -6992,7 +7284,6 @@ var createRequestHandler = async (options) => {
|
|
|
6992
7284
|
activeConversationRuns.delete(conversationId);
|
|
6993
7285
|
}
|
|
6994
7286
|
finishConversationStream(conversationId);
|
|
6995
|
-
await persistConversationPendingApprovals(conversationId);
|
|
6996
7287
|
if (latestRunId) {
|
|
6997
7288
|
runOwners.delete(latestRunId);
|
|
6998
7289
|
runConversations.delete(latestRunId);
|
|
@@ -7391,33 +7682,16 @@ Error: ${event.error.message}
|
|
|
7391
7682
|
var runInteractive = async (workingDir, params) => {
|
|
7392
7683
|
dotenv.config({ path: resolve3(workingDir, ".env") });
|
|
7393
7684
|
const config = await loadPonchoConfig(workingDir);
|
|
7394
|
-
let pendingApproval = null;
|
|
7395
|
-
let onApprovalRequest = null;
|
|
7396
|
-
const approvalHandler = async (request) => {
|
|
7397
|
-
return new Promise((resolveApproval) => {
|
|
7398
|
-
const req = {
|
|
7399
|
-
tool: request.tool,
|
|
7400
|
-
input: request.input,
|
|
7401
|
-
approvalId: request.approvalId,
|
|
7402
|
-
resolve: resolveApproval
|
|
7403
|
-
};
|
|
7404
|
-
pendingApproval = req;
|
|
7405
|
-
if (onApprovalRequest) {
|
|
7406
|
-
onApprovalRequest(req);
|
|
7407
|
-
}
|
|
7408
|
-
});
|
|
7409
|
-
};
|
|
7410
7685
|
const uploadStore = await createUploadStore(config?.uploads, workingDir);
|
|
7411
7686
|
const harness = new AgentHarness({
|
|
7412
7687
|
workingDir,
|
|
7413
7688
|
environment: resolveHarnessEnvironment(),
|
|
7414
|
-
approvalHandler,
|
|
7415
7689
|
uploadStore
|
|
7416
7690
|
});
|
|
7417
7691
|
await harness.initialize();
|
|
7418
7692
|
const identity = await ensureAgentIdentity2(workingDir);
|
|
7419
7693
|
try {
|
|
7420
|
-
const { runInteractiveInk } = await import("./run-interactive-ink-
|
|
7694
|
+
const { runInteractiveInk } = await import("./run-interactive-ink-7ULE5JJI.js");
|
|
7421
7695
|
await runInteractiveInk({
|
|
7422
7696
|
harness,
|
|
7423
7697
|
params,
|
|
@@ -7426,13 +7700,7 @@ var runInteractive = async (workingDir, params) => {
|
|
|
7426
7700
|
conversationStore: createConversationStore(resolveStateConfig(config), {
|
|
7427
7701
|
workingDir,
|
|
7428
7702
|
agentId: identity.id
|
|
7429
|
-
})
|
|
7430
|
-
onSetApprovalCallback: (cb) => {
|
|
7431
|
-
onApprovalRequest = cb;
|
|
7432
|
-
if (pendingApproval) {
|
|
7433
|
-
cb(pendingApproval);
|
|
7434
|
-
}
|
|
7435
|
-
}
|
|
7703
|
+
})
|
|
7436
7704
|
});
|
|
7437
7705
|
} finally {
|
|
7438
7706
|
await harness.shutdown();
|