@librechat/agents 3.1.40 → 3.1.41
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/dist/cjs/messages/format.cjs +68 -17
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/esm/messages/format.mjs +68 -17
- package/dist/esm/messages/format.mjs.map +1 -1
- package/package.json +2 -2
- package/src/messages/format.ts +75 -18
- package/src/messages/formatAgentMessages.test.ts +993 -4
|
@@ -478,7 +478,8 @@ describe('formatAgentMessages', () => {
|
|
|
478
478
|
id: 'ts_1',
|
|
479
479
|
name: 'tool_search',
|
|
480
480
|
args: '{"query":"commits"}',
|
|
481
|
-
output:
|
|
481
|
+
output:
|
|
482
|
+
'{"found": 1, "tools": [{"name": "list_commits_mcp_github"}]}',
|
|
482
483
|
},
|
|
483
484
|
},
|
|
484
485
|
],
|
|
@@ -634,8 +635,7 @@ describe('formatAgentMessages', () => {
|
|
|
634
635
|
},
|
|
635
636
|
{
|
|
636
637
|
type: ContentTypes.TEXT,
|
|
637
|
-
[ContentTypes.TEXT]:
|
|
638
|
-
'Found the tool! Now I will list the commits.',
|
|
638
|
+
[ContentTypes.TEXT]: 'Found the tool! Now I will list the commits.',
|
|
639
639
|
tool_call_ids: ['commits_1'],
|
|
640
640
|
},
|
|
641
641
|
{
|
|
@@ -767,7 +767,7 @@ describe('formatAgentMessages', () => {
|
|
|
767
767
|
expect(result.messages[1].content).toHaveLength(2);
|
|
768
768
|
});
|
|
769
769
|
|
|
770
|
-
it('should
|
|
770
|
+
it('should strip THINK content and join TEXT parts as string', () => {
|
|
771
771
|
const payload = [
|
|
772
772
|
{
|
|
773
773
|
role: 'assistant',
|
|
@@ -1510,4 +1510,993 @@ describe('formatAgentMessages', () => {
|
|
|
1510
1510
|
expect(result.messages[1].name).toBe('search');
|
|
1511
1511
|
expect(result.messages[1].content).toBe('');
|
|
1512
1512
|
});
|
|
1513
|
+
|
|
1514
|
+
describe('proportional token distribution', () => {
|
|
1515
|
+
it('should distribute tokens proportionally based on content length', () => {
|
|
1516
|
+
const payload = [
|
|
1517
|
+
{
|
|
1518
|
+
role: 'assistant',
|
|
1519
|
+
content: [
|
|
1520
|
+
{
|
|
1521
|
+
type: ContentTypes.TEXT,
|
|
1522
|
+
[ContentTypes.TEXT]: 'Short text',
|
|
1523
|
+
tool_call_ids: ['tool_1'],
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
type: ContentTypes.TOOL_CALL,
|
|
1527
|
+
tool_call: {
|
|
1528
|
+
id: 'tool_1',
|
|
1529
|
+
name: 'search',
|
|
1530
|
+
args: '{"query":"test"}',
|
|
1531
|
+
output:
|
|
1532
|
+
'A much longer tool result that contains significantly more content than the original message text',
|
|
1533
|
+
},
|
|
1534
|
+
},
|
|
1535
|
+
],
|
|
1536
|
+
},
|
|
1537
|
+
];
|
|
1538
|
+
|
|
1539
|
+
const indexTokenCountMap = { 0: 100 };
|
|
1540
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1541
|
+
|
|
1542
|
+
expect(result.messages).toHaveLength(2);
|
|
1543
|
+
const aiTokens = result.indexTokenCountMap?.[0] ?? 0;
|
|
1544
|
+
const toolTokens = result.indexTokenCountMap?.[1] ?? 0;
|
|
1545
|
+
expect(aiTokens + toolTokens).toBe(100);
|
|
1546
|
+
expect(toolTokens).toBeGreaterThan(aiTokens);
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
it('should give the vast majority of tokens to a large tool result vs tiny AI message', () => {
|
|
1550
|
+
const bigOutput = 'x'.repeat(10000);
|
|
1551
|
+
const payload = [
|
|
1552
|
+
{
|
|
1553
|
+
role: 'assistant',
|
|
1554
|
+
content: [
|
|
1555
|
+
{
|
|
1556
|
+
type: ContentTypes.TEXT,
|
|
1557
|
+
[ContentTypes.TEXT]: 'ok',
|
|
1558
|
+
tool_call_ids: ['tool_1'],
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
type: ContentTypes.TOOL_CALL,
|
|
1562
|
+
tool_call: {
|
|
1563
|
+
id: 'tool_1',
|
|
1564
|
+
name: 'snapshot',
|
|
1565
|
+
args: '{}',
|
|
1566
|
+
output: bigOutput,
|
|
1567
|
+
},
|
|
1568
|
+
},
|
|
1569
|
+
],
|
|
1570
|
+
},
|
|
1571
|
+
];
|
|
1572
|
+
|
|
1573
|
+
const indexTokenCountMap = { 0: 5000 };
|
|
1574
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1575
|
+
|
|
1576
|
+
expect(result.messages).toHaveLength(2);
|
|
1577
|
+
const aiTokens = result.indexTokenCountMap?.[0] ?? 0;
|
|
1578
|
+
const toolTokens = result.indexTokenCountMap?.[1] ?? 0;
|
|
1579
|
+
expect(aiTokens + toolTokens).toBe(5000);
|
|
1580
|
+
expect(toolTokens).toBeGreaterThan(4900);
|
|
1581
|
+
expect(aiTokens).toBeLessThan(100);
|
|
1582
|
+
});
|
|
1583
|
+
|
|
1584
|
+
it('should fall back to even distribution when all content lengths are zero', () => {
|
|
1585
|
+
const payload = [
|
|
1586
|
+
{
|
|
1587
|
+
role: 'assistant',
|
|
1588
|
+
content: [
|
|
1589
|
+
{
|
|
1590
|
+
type: ContentTypes.TEXT,
|
|
1591
|
+
[ContentTypes.TEXT]: '',
|
|
1592
|
+
tool_call_ids: ['tool_1'],
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
type: ContentTypes.TOOL_CALL,
|
|
1596
|
+
tool_call: {
|
|
1597
|
+
id: 'tool_1',
|
|
1598
|
+
name: 'noop',
|
|
1599
|
+
args: '{}',
|
|
1600
|
+
output: '',
|
|
1601
|
+
},
|
|
1602
|
+
},
|
|
1603
|
+
],
|
|
1604
|
+
},
|
|
1605
|
+
];
|
|
1606
|
+
|
|
1607
|
+
const indexTokenCountMap = { 0: 20 };
|
|
1608
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1609
|
+
|
|
1610
|
+
expect(result.messages).toHaveLength(2);
|
|
1611
|
+
const aiTokens = result.indexTokenCountMap?.[0] ?? 0;
|
|
1612
|
+
const toolTokens = result.indexTokenCountMap?.[1] ?? 0;
|
|
1613
|
+
expect(aiTokens + toolTokens).toBe(20);
|
|
1614
|
+
expect(aiTokens).toBeGreaterThanOrEqual(0);
|
|
1615
|
+
expect(toolTokens).toBeGreaterThanOrEqual(0);
|
|
1616
|
+
});
|
|
1617
|
+
|
|
1618
|
+
it('should handle odd token counts without losing remainder', () => {
|
|
1619
|
+
const payload = [
|
|
1620
|
+
{
|
|
1621
|
+
role: 'assistant',
|
|
1622
|
+
content: [
|
|
1623
|
+
{
|
|
1624
|
+
type: ContentTypes.TEXT,
|
|
1625
|
+
[ContentTypes.TEXT]: 'abc',
|
|
1626
|
+
tool_call_ids: ['tool_1', 'tool_2', 'tool_3'],
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
type: ContentTypes.TOOL_CALL,
|
|
1630
|
+
tool_call: {
|
|
1631
|
+
id: 'tool_1',
|
|
1632
|
+
name: 'a',
|
|
1633
|
+
args: '{}',
|
|
1634
|
+
output: 'abc',
|
|
1635
|
+
},
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
type: ContentTypes.TOOL_CALL,
|
|
1639
|
+
tool_call: {
|
|
1640
|
+
id: 'tool_2',
|
|
1641
|
+
name: 'b',
|
|
1642
|
+
args: '{}',
|
|
1643
|
+
output: 'abc',
|
|
1644
|
+
},
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
type: ContentTypes.TOOL_CALL,
|
|
1648
|
+
tool_call: {
|
|
1649
|
+
id: 'tool_3',
|
|
1650
|
+
name: 'c',
|
|
1651
|
+
args: '{}',
|
|
1652
|
+
output: 'abc',
|
|
1653
|
+
},
|
|
1654
|
+
},
|
|
1655
|
+
],
|
|
1656
|
+
},
|
|
1657
|
+
];
|
|
1658
|
+
|
|
1659
|
+
const indexTokenCountMap = { 0: 7 };
|
|
1660
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1661
|
+
|
|
1662
|
+
expect(result.messages).toHaveLength(4);
|
|
1663
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1664
|
+
(sum, v) => sum + v,
|
|
1665
|
+
0
|
|
1666
|
+
);
|
|
1667
|
+
expect(total).toBe(7);
|
|
1668
|
+
for (let i = 0; i < result.messages.length; i++) {
|
|
1669
|
+
expect(result.indexTokenCountMap?.[i]).toBeGreaterThanOrEqual(0);
|
|
1670
|
+
}
|
|
1671
|
+
});
|
|
1672
|
+
|
|
1673
|
+
it('should never produce negative token counts', () => {
|
|
1674
|
+
const payload = [
|
|
1675
|
+
{
|
|
1676
|
+
role: 'assistant',
|
|
1677
|
+
content: [
|
|
1678
|
+
{
|
|
1679
|
+
type: ContentTypes.TEXT,
|
|
1680
|
+
[ContentTypes.TEXT]: 'a',
|
|
1681
|
+
tool_call_ids: ['t1', 't2', 't3', 't4', 't5'],
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
type: ContentTypes.TOOL_CALL,
|
|
1685
|
+
tool_call: { id: 't1', name: 'x', args: '{}', output: 'b' },
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
type: ContentTypes.TOOL_CALL,
|
|
1689
|
+
tool_call: { id: 't2', name: 'x', args: '{}', output: 'c' },
|
|
1690
|
+
},
|
|
1691
|
+
{
|
|
1692
|
+
type: ContentTypes.TOOL_CALL,
|
|
1693
|
+
tool_call: { id: 't3', name: 'x', args: '{}', output: 'd' },
|
|
1694
|
+
},
|
|
1695
|
+
{
|
|
1696
|
+
type: ContentTypes.TOOL_CALL,
|
|
1697
|
+
tool_call: { id: 't4', name: 'x', args: '{}', output: 'e' },
|
|
1698
|
+
},
|
|
1699
|
+
{
|
|
1700
|
+
type: ContentTypes.TOOL_CALL,
|
|
1701
|
+
tool_call: { id: 't5', name: 'x', args: '{}', output: 'f' },
|
|
1702
|
+
},
|
|
1703
|
+
],
|
|
1704
|
+
},
|
|
1705
|
+
];
|
|
1706
|
+
|
|
1707
|
+
const indexTokenCountMap = { 0: 3 };
|
|
1708
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1709
|
+
|
|
1710
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1711
|
+
(sum, v) => sum + v,
|
|
1712
|
+
0
|
|
1713
|
+
);
|
|
1714
|
+
expect(total).toBe(3);
|
|
1715
|
+
for (const val of Object.values(result.indexTokenCountMap || {})) {
|
|
1716
|
+
expect(val).toBeGreaterThanOrEqual(0);
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
|
|
1720
|
+
it('should handle single token budget distributed across many messages', () => {
|
|
1721
|
+
const payload = [
|
|
1722
|
+
{
|
|
1723
|
+
role: 'assistant',
|
|
1724
|
+
content: [
|
|
1725
|
+
{
|
|
1726
|
+
type: ContentTypes.TEXT,
|
|
1727
|
+
[ContentTypes.TEXT]: 'hello',
|
|
1728
|
+
tool_call_ids: ['t1', 't2'],
|
|
1729
|
+
},
|
|
1730
|
+
{
|
|
1731
|
+
type: ContentTypes.TOOL_CALL,
|
|
1732
|
+
tool_call: {
|
|
1733
|
+
id: 't1',
|
|
1734
|
+
name: 'a',
|
|
1735
|
+
args: '{}',
|
|
1736
|
+
output: 'result one',
|
|
1737
|
+
},
|
|
1738
|
+
},
|
|
1739
|
+
{
|
|
1740
|
+
type: ContentTypes.TOOL_CALL,
|
|
1741
|
+
tool_call: {
|
|
1742
|
+
id: 't2',
|
|
1743
|
+
name: 'b',
|
|
1744
|
+
args: '{}',
|
|
1745
|
+
output: 'result two',
|
|
1746
|
+
},
|
|
1747
|
+
},
|
|
1748
|
+
],
|
|
1749
|
+
},
|
|
1750
|
+
];
|
|
1751
|
+
|
|
1752
|
+
const indexTokenCountMap = { 0: 1 };
|
|
1753
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1754
|
+
|
|
1755
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1756
|
+
(sum, v) => sum + v,
|
|
1757
|
+
0
|
|
1758
|
+
);
|
|
1759
|
+
expect(total).toBe(1);
|
|
1760
|
+
for (const val of Object.values(result.indexTokenCountMap || {})) {
|
|
1761
|
+
expect(val).toBeGreaterThanOrEqual(0);
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
it('should handle zero token budget', () => {
|
|
1766
|
+
const payload = [
|
|
1767
|
+
{
|
|
1768
|
+
role: 'assistant',
|
|
1769
|
+
content: [
|
|
1770
|
+
{
|
|
1771
|
+
type: ContentTypes.TEXT,
|
|
1772
|
+
[ContentTypes.TEXT]: 'hello',
|
|
1773
|
+
tool_call_ids: ['t1'],
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
type: ContentTypes.TOOL_CALL,
|
|
1777
|
+
tool_call: { id: 't1', name: 'a', args: '{}', output: 'world' },
|
|
1778
|
+
},
|
|
1779
|
+
],
|
|
1780
|
+
},
|
|
1781
|
+
];
|
|
1782
|
+
|
|
1783
|
+
const indexTokenCountMap = { 0: 0 };
|
|
1784
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1785
|
+
|
|
1786
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1787
|
+
(sum, v) => sum + v,
|
|
1788
|
+
0
|
|
1789
|
+
);
|
|
1790
|
+
expect(total).toBe(0);
|
|
1791
|
+
});
|
|
1792
|
+
|
|
1793
|
+
it('should distribute tokens proportionally with 5 tool calls of varying sizes', () => {
|
|
1794
|
+
const payload = [
|
|
1795
|
+
{
|
|
1796
|
+
role: 'assistant',
|
|
1797
|
+
content: [
|
|
1798
|
+
{
|
|
1799
|
+
type: ContentTypes.TEXT,
|
|
1800
|
+
[ContentTypes.TEXT]: 'I will perform multiple operations.',
|
|
1801
|
+
tool_call_ids: ['t1', 't2', 't3', 't4', 't5'],
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
type: ContentTypes.TOOL_CALL,
|
|
1805
|
+
tool_call: {
|
|
1806
|
+
id: 't1',
|
|
1807
|
+
name: 'navigate',
|
|
1808
|
+
args: '{"url":"https://example.com"}',
|
|
1809
|
+
output: 'Navigated successfully.',
|
|
1810
|
+
},
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
type: ContentTypes.TOOL_CALL,
|
|
1814
|
+
tool_call: {
|
|
1815
|
+
id: 't2',
|
|
1816
|
+
name: 'snapshot',
|
|
1817
|
+
args: '{}',
|
|
1818
|
+
output: 'x'.repeat(5000),
|
|
1819
|
+
},
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
type: ContentTypes.TOOL_CALL,
|
|
1823
|
+
tool_call: {
|
|
1824
|
+
id: 't3',
|
|
1825
|
+
name: 'click',
|
|
1826
|
+
args: '{"selector":"#btn"}',
|
|
1827
|
+
output: 'Clicked.',
|
|
1828
|
+
},
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
type: ContentTypes.TOOL_CALL,
|
|
1832
|
+
tool_call: {
|
|
1833
|
+
id: 't4',
|
|
1834
|
+
name: 'snapshot',
|
|
1835
|
+
args: '{}',
|
|
1836
|
+
output: 'y'.repeat(8000),
|
|
1837
|
+
},
|
|
1838
|
+
},
|
|
1839
|
+
{
|
|
1840
|
+
type: ContentTypes.TOOL_CALL,
|
|
1841
|
+
tool_call: {
|
|
1842
|
+
id: 't5',
|
|
1843
|
+
name: 'extract',
|
|
1844
|
+
args: '{"selector":"h1"}',
|
|
1845
|
+
output: 'Page Title',
|
|
1846
|
+
},
|
|
1847
|
+
},
|
|
1848
|
+
],
|
|
1849
|
+
},
|
|
1850
|
+
];
|
|
1851
|
+
|
|
1852
|
+
const indexTokenCountMap = { 0: 3000 };
|
|
1853
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1854
|
+
|
|
1855
|
+
expect(result.messages).toHaveLength(6);
|
|
1856
|
+
|
|
1857
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1858
|
+
(sum, v) => sum + v,
|
|
1859
|
+
0
|
|
1860
|
+
);
|
|
1861
|
+
expect(total).toBe(3000);
|
|
1862
|
+
|
|
1863
|
+
const snapshotIdx1 = 2;
|
|
1864
|
+
const snapshotIdx2 = 4;
|
|
1865
|
+
const bigSnapshotTokens =
|
|
1866
|
+
(result.indexTokenCountMap?.[snapshotIdx1] ?? 0) +
|
|
1867
|
+
(result.indexTokenCountMap?.[snapshotIdx2] ?? 0);
|
|
1868
|
+
expect(bigSnapshotTokens).toBeGreaterThan(2500);
|
|
1869
|
+
|
|
1870
|
+
for (const val of Object.values(result.indexTokenCountMap || {})) {
|
|
1871
|
+
expect(val).toBeGreaterThanOrEqual(0);
|
|
1872
|
+
}
|
|
1873
|
+
});
|
|
1874
|
+
|
|
1875
|
+
it('should handle HN-like payload: AI with 18 tool calls and large snapshot results', () => {
|
|
1876
|
+
const smallOutput = 'Successfully navigated to page.';
|
|
1877
|
+
const hugeSnapshot = 'uid=8_0 RootWebArea ' + 'x'.repeat(20000);
|
|
1878
|
+
|
|
1879
|
+
const toolCalls: Array<{
|
|
1880
|
+
type: string;
|
|
1881
|
+
tool_call: { id: string; name: string; args: string; output: string };
|
|
1882
|
+
}> = [];
|
|
1883
|
+
const toolCallIds: string[] = [];
|
|
1884
|
+
|
|
1885
|
+
for (let i = 0; i < 18; i++) {
|
|
1886
|
+
const id = `tool_${i}`;
|
|
1887
|
+
toolCallIds.push(id);
|
|
1888
|
+
const isSnapshot = i % 3 === 1;
|
|
1889
|
+
toolCalls.push({
|
|
1890
|
+
type: ContentTypes.TOOL_CALL,
|
|
1891
|
+
tool_call: {
|
|
1892
|
+
id,
|
|
1893
|
+
name: isSnapshot ? 'take_snapshot' : 'navigate_page',
|
|
1894
|
+
args: isSnapshot ? '{}' : `{"url":"https://example.com/${i}"}`,
|
|
1895
|
+
output: isSnapshot ? hugeSnapshot : smallOutput,
|
|
1896
|
+
},
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
const payload = [
|
|
1901
|
+
{
|
|
1902
|
+
role: 'user',
|
|
1903
|
+
content: 'Look up top 5 posts on HN',
|
|
1904
|
+
},
|
|
1905
|
+
{
|
|
1906
|
+
role: 'assistant',
|
|
1907
|
+
content: [
|
|
1908
|
+
{
|
|
1909
|
+
type: ContentTypes.TEXT,
|
|
1910
|
+
[ContentTypes.TEXT]: '',
|
|
1911
|
+
tool_call_ids: toolCallIds,
|
|
1912
|
+
},
|
|
1913
|
+
...toolCalls,
|
|
1914
|
+
],
|
|
1915
|
+
},
|
|
1916
|
+
];
|
|
1917
|
+
|
|
1918
|
+
const indexTokenCountMap = { 0: 20, 1: 10000 };
|
|
1919
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1920
|
+
|
|
1921
|
+
expect(result.messages.length).toBeGreaterThan(2);
|
|
1922
|
+
|
|
1923
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1924
|
+
(sum, v) => sum + v,
|
|
1925
|
+
0
|
|
1926
|
+
);
|
|
1927
|
+
expect(total).toBe(10020);
|
|
1928
|
+
|
|
1929
|
+
expect(result.indexTokenCountMap?.[0]).toBe(20);
|
|
1930
|
+
|
|
1931
|
+
let snapshotTokenTotal = 0;
|
|
1932
|
+
let navTokenTotal = 0;
|
|
1933
|
+
for (let i = 1; i < result.messages.length; i++) {
|
|
1934
|
+
const tokens = result.indexTokenCountMap?.[i] ?? 0;
|
|
1935
|
+
expect(tokens).toBeGreaterThanOrEqual(0);
|
|
1936
|
+
|
|
1937
|
+
if (result.messages[i] instanceof ToolMessage) {
|
|
1938
|
+
const content = result.messages[i].content;
|
|
1939
|
+
if (typeof content === 'string' && content.length > 1000) {
|
|
1940
|
+
snapshotTokenTotal += tokens;
|
|
1941
|
+
} else {
|
|
1942
|
+
navTokenTotal += tokens;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
expect(snapshotTokenTotal).toBeGreaterThan(navTokenTotal);
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
it('should complete proportional distribution within reasonable time for large payloads', () => {
|
|
1951
|
+
const toolCalls: Array<{
|
|
1952
|
+
type: string;
|
|
1953
|
+
tool_call: { id: string; name: string; args: string; output: string };
|
|
1954
|
+
}> = [];
|
|
1955
|
+
const toolCallIds: string[] = [];
|
|
1956
|
+
|
|
1957
|
+
for (let i = 0; i < 50; i++) {
|
|
1958
|
+
const id = `tool_${i}`;
|
|
1959
|
+
toolCallIds.push(id);
|
|
1960
|
+
toolCalls.push({
|
|
1961
|
+
type: ContentTypes.TOOL_CALL,
|
|
1962
|
+
tool_call: {
|
|
1963
|
+
id,
|
|
1964
|
+
name: `tool_${i}`,
|
|
1965
|
+
args: JSON.stringify({ data: 'x'.repeat(100) }),
|
|
1966
|
+
output: 'y'.repeat(Math.floor(Math.random() * 10000)),
|
|
1967
|
+
},
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
const payload = [
|
|
1972
|
+
{
|
|
1973
|
+
role: 'assistant',
|
|
1974
|
+
content: [
|
|
1975
|
+
{
|
|
1976
|
+
type: ContentTypes.TEXT,
|
|
1977
|
+
[ContentTypes.TEXT]: 'Processing...',
|
|
1978
|
+
tool_call_ids: toolCallIds,
|
|
1979
|
+
},
|
|
1980
|
+
...toolCalls,
|
|
1981
|
+
],
|
|
1982
|
+
},
|
|
1983
|
+
];
|
|
1984
|
+
|
|
1985
|
+
const indexTokenCountMap = { 0: 50000 };
|
|
1986
|
+
|
|
1987
|
+
const start = performance.now();
|
|
1988
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
1989
|
+
const elapsed = performance.now() - start;
|
|
1990
|
+
|
|
1991
|
+
expect(elapsed).toBeLessThan(500);
|
|
1992
|
+
|
|
1993
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
1994
|
+
(sum, v) => sum + v,
|
|
1995
|
+
0
|
|
1996
|
+
);
|
|
1997
|
+
expect(total).toBe(50000);
|
|
1998
|
+
});
|
|
1999
|
+
|
|
2000
|
+
it('should always preserve total token count across multiple original messages', () => {
|
|
2001
|
+
const payload = [
|
|
2002
|
+
{ role: 'user', content: 'Hello' },
|
|
2003
|
+
{
|
|
2004
|
+
role: 'assistant',
|
|
2005
|
+
content: [
|
|
2006
|
+
{
|
|
2007
|
+
type: ContentTypes.TEXT,
|
|
2008
|
+
[ContentTypes.TEXT]: 'Let me search.',
|
|
2009
|
+
tool_call_ids: ['t1'],
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
type: ContentTypes.TOOL_CALL,
|
|
2013
|
+
tool_call: {
|
|
2014
|
+
id: 't1',
|
|
2015
|
+
name: 'search',
|
|
2016
|
+
args: '{"q":"test"}',
|
|
2017
|
+
output:
|
|
2018
|
+
'Found 10 results with detailed descriptions: ' +
|
|
2019
|
+
'z'.repeat(500),
|
|
2020
|
+
},
|
|
2021
|
+
},
|
|
2022
|
+
],
|
|
2023
|
+
},
|
|
2024
|
+
{ role: 'user', content: 'Thanks' },
|
|
2025
|
+
{ role: 'assistant', content: 'You are welcome!' },
|
|
2026
|
+
];
|
|
2027
|
+
|
|
2028
|
+
const indexTokenCountMap = { 0: 5, 1: 200, 2: 3, 3: 8 };
|
|
2029
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2030
|
+
|
|
2031
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2032
|
+
(sum, v) => sum + v,
|
|
2033
|
+
0
|
|
2034
|
+
);
|
|
2035
|
+
expect(total).toBe(216);
|
|
2036
|
+
|
|
2037
|
+
for (const val of Object.values(result.indexTokenCountMap || {})) {
|
|
2038
|
+
expect(val).toBeGreaterThanOrEqual(0);
|
|
2039
|
+
expect(Number.isInteger(val)).toBe(true);
|
|
2040
|
+
}
|
|
2041
|
+
});
|
|
2042
|
+
|
|
2043
|
+
it('should produce integer token counts (no floating point)', () => {
|
|
2044
|
+
const payload = [
|
|
2045
|
+
{
|
|
2046
|
+
role: 'assistant',
|
|
2047
|
+
content: [
|
|
2048
|
+
{
|
|
2049
|
+
type: ContentTypes.TEXT,
|
|
2050
|
+
[ContentTypes.TEXT]: 'abc',
|
|
2051
|
+
tool_call_ids: ['t1', 't2', 't3'],
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
type: ContentTypes.TOOL_CALL,
|
|
2055
|
+
tool_call: { id: 't1', name: 'a', args: '{}', output: 'defgh' },
|
|
2056
|
+
},
|
|
2057
|
+
{
|
|
2058
|
+
type: ContentTypes.TOOL_CALL,
|
|
2059
|
+
tool_call: { id: 't2', name: 'b', args: '{}', output: 'ij' },
|
|
2060
|
+
},
|
|
2061
|
+
{
|
|
2062
|
+
type: ContentTypes.TOOL_CALL,
|
|
2063
|
+
tool_call: {
|
|
2064
|
+
id: 't3',
|
|
2065
|
+
name: 'c',
|
|
2066
|
+
args: '{}',
|
|
2067
|
+
output: 'klmnopqrst',
|
|
2068
|
+
},
|
|
2069
|
+
},
|
|
2070
|
+
],
|
|
2071
|
+
},
|
|
2072
|
+
];
|
|
2073
|
+
|
|
2074
|
+
const indexTokenCountMap = { 0: 97 };
|
|
2075
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2076
|
+
|
|
2077
|
+
for (const val of Object.values(result.indexTokenCountMap || {})) {
|
|
2078
|
+
expect(Number.isInteger(val)).toBe(true);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2082
|
+
(sum, v) => sum + v,
|
|
2083
|
+
0
|
|
2084
|
+
);
|
|
2085
|
+
expect(total).toBe(97);
|
|
2086
|
+
});
|
|
2087
|
+
|
|
2088
|
+
it('should account for tool call args in content length calculation', () => {
|
|
2089
|
+
const payload = [
|
|
2090
|
+
{
|
|
2091
|
+
role: 'assistant',
|
|
2092
|
+
content: [
|
|
2093
|
+
{
|
|
2094
|
+
type: ContentTypes.TEXT,
|
|
2095
|
+
[ContentTypes.TEXT]: 'x',
|
|
2096
|
+
tool_call_ids: ['t1', 't2'],
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
type: ContentTypes.TOOL_CALL,
|
|
2100
|
+
tool_call: {
|
|
2101
|
+
id: 't1',
|
|
2102
|
+
name: 'tiny_tool',
|
|
2103
|
+
args: '{}',
|
|
2104
|
+
output: 'small',
|
|
2105
|
+
},
|
|
2106
|
+
},
|
|
2107
|
+
{
|
|
2108
|
+
type: ContentTypes.TOOL_CALL,
|
|
2109
|
+
tool_call: {
|
|
2110
|
+
id: 't2',
|
|
2111
|
+
name: 'big_args_tool',
|
|
2112
|
+
args: JSON.stringify({ data: 'a'.repeat(5000) }),
|
|
2113
|
+
output: 'small',
|
|
2114
|
+
},
|
|
2115
|
+
},
|
|
2116
|
+
],
|
|
2117
|
+
},
|
|
2118
|
+
];
|
|
2119
|
+
|
|
2120
|
+
const indexTokenCountMap = { 0: 1000 };
|
|
2121
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2122
|
+
|
|
2123
|
+
expect(result.messages).toHaveLength(3);
|
|
2124
|
+
|
|
2125
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2126
|
+
(sum, v) => sum + v,
|
|
2127
|
+
0
|
|
2128
|
+
);
|
|
2129
|
+
expect(total).toBe(1000);
|
|
2130
|
+
|
|
2131
|
+
for (const val of Object.values(result.indexTokenCountMap || {})) {
|
|
2132
|
+
expect(val).toBeGreaterThanOrEqual(0);
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
|
|
2136
|
+
it('should not throw when indexTokenCountMap has undefined values for some indices', () => {
|
|
2137
|
+
const payload = [
|
|
2138
|
+
{ role: 'user', content: 'Hello' },
|
|
2139
|
+
{
|
|
2140
|
+
role: 'assistant',
|
|
2141
|
+
content: [
|
|
2142
|
+
{
|
|
2143
|
+
type: ContentTypes.TEXT,
|
|
2144
|
+
[ContentTypes.TEXT]: 'response',
|
|
2145
|
+
tool_call_ids: ['t1'],
|
|
2146
|
+
},
|
|
2147
|
+
{
|
|
2148
|
+
type: ContentTypes.TOOL_CALL,
|
|
2149
|
+
tool_call: {
|
|
2150
|
+
id: 't1',
|
|
2151
|
+
name: 'search',
|
|
2152
|
+
args: '{}',
|
|
2153
|
+
output: 'result',
|
|
2154
|
+
},
|
|
2155
|
+
},
|
|
2156
|
+
],
|
|
2157
|
+
},
|
|
2158
|
+
];
|
|
2159
|
+
|
|
2160
|
+
const indexTokenCountMap: Record<number, number | undefined> = {
|
|
2161
|
+
0: undefined,
|
|
2162
|
+
1: 50,
|
|
2163
|
+
};
|
|
2164
|
+
|
|
2165
|
+
expect(() => {
|
|
2166
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2167
|
+
expect(result.indexTokenCountMap).toBeDefined();
|
|
2168
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2169
|
+
(sum, v) => sum + v,
|
|
2170
|
+
0
|
|
2171
|
+
);
|
|
2172
|
+
expect(total).toBe(50);
|
|
2173
|
+
}).not.toThrow();
|
|
2174
|
+
});
|
|
2175
|
+
|
|
2176
|
+
it('should not throw when indexTokenCountMap is sparse (missing indices)', () => {
|
|
2177
|
+
const payload = [
|
|
2178
|
+
{ role: 'user', content: 'Hello' },
|
|
2179
|
+
{ role: 'assistant', content: 'World' },
|
|
2180
|
+
{ role: 'user', content: 'Bye' },
|
|
2181
|
+
];
|
|
2182
|
+
|
|
2183
|
+
const indexTokenCountMap = { 0: 5, 2: 3 };
|
|
2184
|
+
|
|
2185
|
+
expect(() => {
|
|
2186
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2187
|
+
expect(result.indexTokenCountMap).toBeDefined();
|
|
2188
|
+
expect(result.indexTokenCountMap?.[0]).toBe(5);
|
|
2189
|
+
expect(result.indexTokenCountMap?.[2]).toBe(3);
|
|
2190
|
+
}).not.toThrow();
|
|
2191
|
+
});
|
|
2192
|
+
|
|
2193
|
+
it('should not throw when indexTokenCountMap has extra indices beyond payload', () => {
|
|
2194
|
+
const payload = [{ role: 'user', content: 'Hello' }];
|
|
2195
|
+
|
|
2196
|
+
const indexTokenCountMap = { 0: 5, 1: 10, 2: 15, 99: 999 };
|
|
2197
|
+
|
|
2198
|
+
expect(() => {
|
|
2199
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2200
|
+
expect(result.indexTokenCountMap?.[0]).toBe(5);
|
|
2201
|
+
}).not.toThrow();
|
|
2202
|
+
});
|
|
2203
|
+
|
|
2204
|
+
it('should not throw with empty payload and non-empty indexTokenCountMap', () => {
|
|
2205
|
+
const payload: Array<{ role: string; content: string }> = [];
|
|
2206
|
+
const indexTokenCountMap = { 0: 100 };
|
|
2207
|
+
|
|
2208
|
+
expect(() => {
|
|
2209
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2210
|
+
expect(result.messages).toHaveLength(0);
|
|
2211
|
+
}).not.toThrow();
|
|
2212
|
+
});
|
|
2213
|
+
|
|
2214
|
+
it('should not throw when assistant message content is empty array', () => {
|
|
2215
|
+
const payload = [
|
|
2216
|
+
{
|
|
2217
|
+
role: 'assistant',
|
|
2218
|
+
content: [] as Array<{ type: string; text?: string }>,
|
|
2219
|
+
},
|
|
2220
|
+
];
|
|
2221
|
+
|
|
2222
|
+
const indexTokenCountMap = { 0: 50 };
|
|
2223
|
+
|
|
2224
|
+
expect(() => {
|
|
2225
|
+
formatAgentMessages(payload, indexTokenCountMap);
|
|
2226
|
+
}).not.toThrow();
|
|
2227
|
+
});
|
|
2228
|
+
|
|
2229
|
+
it('should not throw when tool call output is null or undefined', () => {
|
|
2230
|
+
const payload = [
|
|
2231
|
+
{
|
|
2232
|
+
role: 'assistant',
|
|
2233
|
+
content: [
|
|
2234
|
+
{
|
|
2235
|
+
type: ContentTypes.TEXT,
|
|
2236
|
+
[ContentTypes.TEXT]: 'calling tools',
|
|
2237
|
+
tool_call_ids: ['t1', 't2'],
|
|
2238
|
+
},
|
|
2239
|
+
{
|
|
2240
|
+
type: ContentTypes.TOOL_CALL,
|
|
2241
|
+
tool_call: {
|
|
2242
|
+
id: 't1',
|
|
2243
|
+
name: 'search',
|
|
2244
|
+
args: '{}',
|
|
2245
|
+
output: null as unknown as string,
|
|
2246
|
+
},
|
|
2247
|
+
},
|
|
2248
|
+
{
|
|
2249
|
+
type: ContentTypes.TOOL_CALL,
|
|
2250
|
+
tool_call: {
|
|
2251
|
+
id: 't2',
|
|
2252
|
+
name: 'fetch',
|
|
2253
|
+
args: '{}',
|
|
2254
|
+
output: undefined as unknown as string,
|
|
2255
|
+
},
|
|
2256
|
+
},
|
|
2257
|
+
],
|
|
2258
|
+
},
|
|
2259
|
+
];
|
|
2260
|
+
|
|
2261
|
+
const indexTokenCountMap = { 0: 30 };
|
|
2262
|
+
|
|
2263
|
+
expect(() => {
|
|
2264
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2265
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2266
|
+
(sum, v) => sum + v,
|
|
2267
|
+
0
|
|
2268
|
+
);
|
|
2269
|
+
expect(total).toBe(30);
|
|
2270
|
+
}).not.toThrow();
|
|
2271
|
+
});
|
|
2272
|
+
|
|
2273
|
+
it('should not throw when tool call args are deeply nested objects', () => {
|
|
2274
|
+
const deepArgs = { a: { b: { c: { d: { e: { f: 'deep' } } } } } };
|
|
2275
|
+
const payload = [
|
|
2276
|
+
{
|
|
2277
|
+
role: 'assistant',
|
|
2278
|
+
content: [
|
|
2279
|
+
{
|
|
2280
|
+
type: ContentTypes.TEXT,
|
|
2281
|
+
[ContentTypes.TEXT]: 'deep call',
|
|
2282
|
+
tool_call_ids: ['t1'],
|
|
2283
|
+
},
|
|
2284
|
+
{
|
|
2285
|
+
type: ContentTypes.TOOL_CALL,
|
|
2286
|
+
tool_call: {
|
|
2287
|
+
id: 't1',
|
|
2288
|
+
name: 'deep_tool',
|
|
2289
|
+
args: JSON.stringify(deepArgs),
|
|
2290
|
+
output: 'done',
|
|
2291
|
+
},
|
|
2292
|
+
},
|
|
2293
|
+
],
|
|
2294
|
+
},
|
|
2295
|
+
];
|
|
2296
|
+
|
|
2297
|
+
const indexTokenCountMap = { 0: 100 };
|
|
2298
|
+
|
|
2299
|
+
expect(() => {
|
|
2300
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2301
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2302
|
+
(sum, v) => sum + v,
|
|
2303
|
+
0
|
|
2304
|
+
);
|
|
2305
|
+
expect(total).toBe(100);
|
|
2306
|
+
}).not.toThrow();
|
|
2307
|
+
});
|
|
2308
|
+
|
|
2309
|
+
it('should not throw when tool call args are not valid JSON strings', () => {
|
|
2310
|
+
const payload = [
|
|
2311
|
+
{
|
|
2312
|
+
role: 'assistant',
|
|
2313
|
+
content: [
|
|
2314
|
+
{
|
|
2315
|
+
type: ContentTypes.TEXT,
|
|
2316
|
+
[ContentTypes.TEXT]: 'bad args',
|
|
2317
|
+
tool_call_ids: ['t1'],
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
type: ContentTypes.TOOL_CALL,
|
|
2321
|
+
tool_call: {
|
|
2322
|
+
id: 't1',
|
|
2323
|
+
name: 'tool',
|
|
2324
|
+
args: '{not valid json!!!',
|
|
2325
|
+
output: 'output',
|
|
2326
|
+
},
|
|
2327
|
+
},
|
|
2328
|
+
],
|
|
2329
|
+
},
|
|
2330
|
+
];
|
|
2331
|
+
|
|
2332
|
+
const indexTokenCountMap = { 0: 40 };
|
|
2333
|
+
|
|
2334
|
+
expect(() => {
|
|
2335
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2336
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2337
|
+
(sum, v) => sum + v,
|
|
2338
|
+
0
|
|
2339
|
+
);
|
|
2340
|
+
expect(total).toBe(40);
|
|
2341
|
+
}).not.toThrow();
|
|
2342
|
+
});
|
|
2343
|
+
|
|
2344
|
+
it('should not throw when content array has mixed types including unexpected values', () => {
|
|
2345
|
+
const payload = [
|
|
2346
|
+
{
|
|
2347
|
+
role: 'assistant',
|
|
2348
|
+
content: [
|
|
2349
|
+
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: 'hello' },
|
|
2350
|
+
null as unknown as { type: string },
|
|
2351
|
+
undefined as unknown as { type: string },
|
|
2352
|
+
{ type: 'unknown_type', something: 'weird' },
|
|
2353
|
+
],
|
|
2354
|
+
},
|
|
2355
|
+
];
|
|
2356
|
+
|
|
2357
|
+
const indexTokenCountMap = { 0: 25 };
|
|
2358
|
+
|
|
2359
|
+
expect(() => {
|
|
2360
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2361
|
+
expect(result.indexTokenCountMap?.[0]).toBe(25);
|
|
2362
|
+
}).not.toThrow();
|
|
2363
|
+
});
|
|
2364
|
+
|
|
2365
|
+
it('should not throw when tool call has empty name and empty args', () => {
|
|
2366
|
+
const payload = [
|
|
2367
|
+
{
|
|
2368
|
+
role: 'assistant',
|
|
2369
|
+
content: [
|
|
2370
|
+
{
|
|
2371
|
+
type: ContentTypes.TEXT,
|
|
2372
|
+
[ContentTypes.TEXT]: 'test',
|
|
2373
|
+
tool_call_ids: ['t1'],
|
|
2374
|
+
},
|
|
2375
|
+
{
|
|
2376
|
+
type: ContentTypes.TOOL_CALL,
|
|
2377
|
+
tool_call: {
|
|
2378
|
+
id: 't1',
|
|
2379
|
+
name: '',
|
|
2380
|
+
args: '',
|
|
2381
|
+
output: 'some output',
|
|
2382
|
+
},
|
|
2383
|
+
},
|
|
2384
|
+
],
|
|
2385
|
+
},
|
|
2386
|
+
];
|
|
2387
|
+
|
|
2388
|
+
const indexTokenCountMap = { 0: 50 };
|
|
2389
|
+
|
|
2390
|
+
expect(() => {
|
|
2391
|
+
formatAgentMessages(payload, indexTokenCountMap);
|
|
2392
|
+
}).not.toThrow();
|
|
2393
|
+
});
|
|
2394
|
+
|
|
2395
|
+
it('should not throw when all content parts are filtered out (THINK + ERROR only)', () => {
|
|
2396
|
+
const payload = [
|
|
2397
|
+
{
|
|
2398
|
+
role: 'assistant',
|
|
2399
|
+
content: [
|
|
2400
|
+
{ type: ContentTypes.THINK, [ContentTypes.THINK]: 'thinking...' },
|
|
2401
|
+
{ type: ContentTypes.ERROR, [ContentTypes.ERROR]: 'error...' },
|
|
2402
|
+
],
|
|
2403
|
+
},
|
|
2404
|
+
];
|
|
2405
|
+
|
|
2406
|
+
const indexTokenCountMap = { 0: 100 };
|
|
2407
|
+
|
|
2408
|
+
expect(() => {
|
|
2409
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2410
|
+
expect(Object.keys(result.indexTokenCountMap || {}).length).toBe(0);
|
|
2411
|
+
}).not.toThrow();
|
|
2412
|
+
});
|
|
2413
|
+
|
|
2414
|
+
it('should not throw with very large token count values', () => {
|
|
2415
|
+
const payload = [
|
|
2416
|
+
{
|
|
2417
|
+
role: 'assistant',
|
|
2418
|
+
content: [
|
|
2419
|
+
{
|
|
2420
|
+
type: ContentTypes.TEXT,
|
|
2421
|
+
[ContentTypes.TEXT]: 'big tokens',
|
|
2422
|
+
tool_call_ids: ['t1'],
|
|
2423
|
+
},
|
|
2424
|
+
{
|
|
2425
|
+
type: ContentTypes.TOOL_CALL,
|
|
2426
|
+
tool_call: { id: 't1', name: 'a', args: '{}', output: 'b' },
|
|
2427
|
+
},
|
|
2428
|
+
],
|
|
2429
|
+
},
|
|
2430
|
+
];
|
|
2431
|
+
|
|
2432
|
+
const indexTokenCountMap = { 0: Number.MAX_SAFE_INTEGER };
|
|
2433
|
+
|
|
2434
|
+
expect(() => {
|
|
2435
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2436
|
+
const total = Object.values(result.indexTokenCountMap || {}).reduce(
|
|
2437
|
+
(sum, v) => sum + v,
|
|
2438
|
+
0
|
|
2439
|
+
);
|
|
2440
|
+
expect(total).toBe(Number.MAX_SAFE_INTEGER);
|
|
2441
|
+
}).not.toThrow();
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
it('should not throw when multiple payload messages expand and some have undefined token counts', () => {
|
|
2445
|
+
const payload = [
|
|
2446
|
+
{ role: 'user', content: 'msg1' },
|
|
2447
|
+
{
|
|
2448
|
+
role: 'assistant',
|
|
2449
|
+
content: [
|
|
2450
|
+
{
|
|
2451
|
+
type: ContentTypes.TEXT,
|
|
2452
|
+
[ContentTypes.TEXT]: 'response with tool',
|
|
2453
|
+
tool_call_ids: ['t1'],
|
|
2454
|
+
},
|
|
2455
|
+
{
|
|
2456
|
+
type: ContentTypes.TOOL_CALL,
|
|
2457
|
+
tool_call: {
|
|
2458
|
+
id: 't1',
|
|
2459
|
+
name: 'search',
|
|
2460
|
+
args: '{}',
|
|
2461
|
+
output: 'found',
|
|
2462
|
+
},
|
|
2463
|
+
},
|
|
2464
|
+
],
|
|
2465
|
+
},
|
|
2466
|
+
{ role: 'user', content: 'msg2' },
|
|
2467
|
+
{
|
|
2468
|
+
role: 'assistant',
|
|
2469
|
+
content: [
|
|
2470
|
+
{
|
|
2471
|
+
type: ContentTypes.TEXT,
|
|
2472
|
+
[ContentTypes.TEXT]: 'another response',
|
|
2473
|
+
tool_call_ids: ['t2'],
|
|
2474
|
+
},
|
|
2475
|
+
{
|
|
2476
|
+
type: ContentTypes.TOOL_CALL,
|
|
2477
|
+
tool_call: {
|
|
2478
|
+
id: 't2',
|
|
2479
|
+
name: 'fetch',
|
|
2480
|
+
args: '{}',
|
|
2481
|
+
output: 'data',
|
|
2482
|
+
},
|
|
2483
|
+
},
|
|
2484
|
+
],
|
|
2485
|
+
},
|
|
2486
|
+
];
|
|
2487
|
+
|
|
2488
|
+
const indexTokenCountMap: Record<number, number | undefined> = {
|
|
2489
|
+
0: 5,
|
|
2490
|
+
1: undefined,
|
|
2491
|
+
2: 3,
|
|
2492
|
+
3: 80,
|
|
2493
|
+
};
|
|
2494
|
+
|
|
2495
|
+
expect(() => {
|
|
2496
|
+
const result = formatAgentMessages(payload, indexTokenCountMap);
|
|
2497
|
+
expect(result.indexTokenCountMap).toBeDefined();
|
|
2498
|
+
expect(result.indexTokenCountMap?.[0]).toBe(5);
|
|
2499
|
+
}).not.toThrow();
|
|
2500
|
+
});
|
|
2501
|
+
});
|
|
1513
2502
|
});
|