@librechat/agents 3.1.32 → 3.1.34
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/agents/AgentContext.cjs +14 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +35 -8
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -4
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +43 -11
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +10 -7
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +32 -0
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +34 -13
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +14 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +35 -8
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +3 -4
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +43 -11
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/types.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +10 -7
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +32 -0
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +34 -13
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +2 -0
- package/dist/types/llm/anthropic/index.d.ts +7 -1
- package/dist/types/llm/anthropic/types.d.ts +5 -2
- package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
- package/dist/types/tools/ToolNode.d.ts +8 -3
- package/dist/types/types/tools.d.ts +2 -0
- package/package.json +4 -1
- package/src/agents/AgentContext.ts +18 -5
- package/src/graphs/Graph.ts +45 -9
- package/src/graphs/MultiAgentGraph.ts +3 -4
- package/src/llm/anthropic/index.ts +68 -15
- package/src/llm/anthropic/llm.spec.ts +402 -0
- package/src/llm/anthropic/types.ts +8 -2
- package/src/llm/anthropic/utils/message_inputs.ts +16 -33
- package/src/llm/anthropic/utils/message_outputs.ts +40 -1
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +165 -0
- package/src/specs/agent-handoffs.test.ts +16 -18
- package/src/specs/thinking-handoff.test.ts +2 -2
- package/src/tools/ToolNode.ts +52 -18
- package/src/types/tools.ts +2 -0
- package/src/utils/llmConfig.ts +2 -1
|
@@ -28,6 +28,7 @@ import { tool } from '@langchain/core/tools';
|
|
|
28
28
|
import { z } from 'zod';
|
|
29
29
|
import { CustomAnthropic as ChatAnthropic } from './index';
|
|
30
30
|
import { AnthropicMessageResponse, ChatAnthropicContentBlock } from './types';
|
|
31
|
+
import { _convertMessagesToAnthropicPayload } from './utils/message_inputs';
|
|
31
32
|
jest.setTimeout(120000);
|
|
32
33
|
|
|
33
34
|
async function invoke(
|
|
@@ -1440,3 +1441,404 @@ test('Can handle google function calling blocks in content', async () => {
|
|
|
1440
1441
|
const res = await chat.invoke(messages);
|
|
1441
1442
|
expect(res.content.length).toBeGreaterThan(1);
|
|
1442
1443
|
});
|
|
1444
|
+
|
|
1445
|
+
const opus46Model = 'claude-opus-4-6';
|
|
1446
|
+
|
|
1447
|
+
describe('Opus 4.6', () => {
|
|
1448
|
+
describe('Adaptive thinking', () => {
|
|
1449
|
+
test('invocationParams accepts adaptive thinking type', () => {
|
|
1450
|
+
const model = new ChatAnthropic({
|
|
1451
|
+
model: opus46Model,
|
|
1452
|
+
apiKey: 'testing',
|
|
1453
|
+
maxTokens: 4096,
|
|
1454
|
+
thinking: { type: 'adaptive' },
|
|
1455
|
+
});
|
|
1456
|
+
|
|
1457
|
+
const params = model.invocationParams({});
|
|
1458
|
+
|
|
1459
|
+
expect(params.thinking).toEqual({ type: 'adaptive' });
|
|
1460
|
+
});
|
|
1461
|
+
|
|
1462
|
+
test('adaptive thinking disables temperature/topK/topP', () => {
|
|
1463
|
+
const model = new ChatAnthropic({
|
|
1464
|
+
model: opus46Model,
|
|
1465
|
+
apiKey: 'testing',
|
|
1466
|
+
maxTokens: 4096,
|
|
1467
|
+
thinking: { type: 'adaptive' },
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
const params = model.invocationParams({});
|
|
1471
|
+
|
|
1472
|
+
expect(params.temperature).toBeUndefined();
|
|
1473
|
+
expect(params.top_k).toBeUndefined();
|
|
1474
|
+
expect(params.top_p).toBeUndefined();
|
|
1475
|
+
});
|
|
1476
|
+
|
|
1477
|
+
test('adaptive thinking throws on non-default temperature', () => {
|
|
1478
|
+
const model = new ChatAnthropic({
|
|
1479
|
+
model: opus46Model,
|
|
1480
|
+
temperature: 0.5,
|
|
1481
|
+
apiKey: 'testing',
|
|
1482
|
+
maxTokens: 4096,
|
|
1483
|
+
thinking: { type: 'adaptive' },
|
|
1484
|
+
});
|
|
1485
|
+
|
|
1486
|
+
expect(() => model.invocationParams({})).toThrow(
|
|
1487
|
+
'temperature is not supported when thinking is enabled'
|
|
1488
|
+
);
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1491
|
+
test('adaptive thinking invoke', async () => {
|
|
1492
|
+
const model = new ChatAnthropic({
|
|
1493
|
+
model: opus46Model,
|
|
1494
|
+
maxTokens: 4096,
|
|
1495
|
+
thinking: { type: 'adaptive' },
|
|
1496
|
+
});
|
|
1497
|
+
|
|
1498
|
+
const result = await model.invoke('What is 15 * 23?');
|
|
1499
|
+
expect(result.content).toBeDefined();
|
|
1500
|
+
|
|
1501
|
+
if (Array.isArray(result.content)) {
|
|
1502
|
+
const textBlocks = (result.content as any[]).filter(
|
|
1503
|
+
(b) => b.type === 'text'
|
|
1504
|
+
);
|
|
1505
|
+
expect(textBlocks.length).toBeGreaterThan(0);
|
|
1506
|
+
} else {
|
|
1507
|
+
expect(typeof result.content).toBe('string');
|
|
1508
|
+
expect((result.content as string).length).toBeGreaterThan(0);
|
|
1509
|
+
}
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
test('adaptive thinking multiturn round-trip', async () => {
|
|
1513
|
+
const model = new ChatAnthropic({
|
|
1514
|
+
model: opus46Model,
|
|
1515
|
+
maxTokens: 4096,
|
|
1516
|
+
thinking: { type: 'adaptive' },
|
|
1517
|
+
});
|
|
1518
|
+
|
|
1519
|
+
const messages: BaseMessage[] = [new HumanMessage('Hello')];
|
|
1520
|
+
const response1 = await model.invoke(messages);
|
|
1521
|
+
messages.push(response1);
|
|
1522
|
+
messages.push(new HumanMessage('What is 42 + 7?'));
|
|
1523
|
+
|
|
1524
|
+
const response2 = await model.invoke(messages);
|
|
1525
|
+
expect(response2.content).toBeDefined();
|
|
1526
|
+
});
|
|
1527
|
+
});
|
|
1528
|
+
|
|
1529
|
+
describe('Effort parameter (outputConfig)', () => {
|
|
1530
|
+
test('invocationParams passes outputConfig from constructor', () => {
|
|
1531
|
+
const model = new ChatAnthropic({
|
|
1532
|
+
model: opus46Model,
|
|
1533
|
+
apiKey: 'testing',
|
|
1534
|
+
maxTokens: 4096,
|
|
1535
|
+
outputConfig: { effort: 'medium' },
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
const params = model.invocationParams({});
|
|
1539
|
+
|
|
1540
|
+
expect(params.output_config).toEqual({ effort: 'medium' });
|
|
1541
|
+
});
|
|
1542
|
+
|
|
1543
|
+
test('invocationParams passes outputConfig from call options', () => {
|
|
1544
|
+
const model = new ChatAnthropic({
|
|
1545
|
+
model: opus46Model,
|
|
1546
|
+
apiKey: 'testing',
|
|
1547
|
+
maxTokens: 4096,
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
const params = model.invocationParams({
|
|
1551
|
+
outputConfig: { effort: 'low' },
|
|
1552
|
+
} as any);
|
|
1553
|
+
|
|
1554
|
+
expect(params.output_config).toEqual({ effort: 'low' });
|
|
1555
|
+
});
|
|
1556
|
+
|
|
1557
|
+
test('call-option outputConfig overrides constructor outputConfig', () => {
|
|
1558
|
+
const model = new ChatAnthropic({
|
|
1559
|
+
model: opus46Model,
|
|
1560
|
+
apiKey: 'testing',
|
|
1561
|
+
maxTokens: 4096,
|
|
1562
|
+
outputConfig: { effort: 'high' },
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
const params = model.invocationParams({
|
|
1566
|
+
outputConfig: { effort: 'low' },
|
|
1567
|
+
} as any);
|
|
1568
|
+
|
|
1569
|
+
expect(params.output_config).toEqual({ effort: 'low' });
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
test('effort max is accepted', () => {
|
|
1573
|
+
const model = new ChatAnthropic({
|
|
1574
|
+
model: opus46Model,
|
|
1575
|
+
apiKey: 'testing',
|
|
1576
|
+
maxTokens: 4096,
|
|
1577
|
+
outputConfig: { effort: 'max' },
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
const params = model.invocationParams({});
|
|
1581
|
+
|
|
1582
|
+
expect(params.output_config).toEqual({ effort: 'max' });
|
|
1583
|
+
});
|
|
1584
|
+
|
|
1585
|
+
test('output_config is undefined when not set', () => {
|
|
1586
|
+
const model = new ChatAnthropic({
|
|
1587
|
+
model: opus46Model,
|
|
1588
|
+
apiKey: 'testing',
|
|
1589
|
+
maxTokens: 4096,
|
|
1590
|
+
});
|
|
1591
|
+
|
|
1592
|
+
const params = model.invocationParams({});
|
|
1593
|
+
|
|
1594
|
+
expect(params.output_config).toBeUndefined();
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
test.each(['low', 'medium', 'high'] as const)(
|
|
1598
|
+
'invoke with %s effort',
|
|
1599
|
+
async (effort) => {
|
|
1600
|
+
const model = new ChatAnthropic({
|
|
1601
|
+
model: opus46Model,
|
|
1602
|
+
maxTokens: 4096,
|
|
1603
|
+
thinking: { type: 'adaptive' },
|
|
1604
|
+
outputConfig: { effort },
|
|
1605
|
+
});
|
|
1606
|
+
|
|
1607
|
+
const result = await model.invoke('Say hello.');
|
|
1608
|
+
expect(result.content).toBeDefined();
|
|
1609
|
+
}
|
|
1610
|
+
);
|
|
1611
|
+
|
|
1612
|
+
test.each(['low', 'medium', 'high'] as const)(
|
|
1613
|
+
'stream with %s effort',
|
|
1614
|
+
async (effort) => {
|
|
1615
|
+
const model = new ChatAnthropic({
|
|
1616
|
+
model: opus46Model,
|
|
1617
|
+
maxTokens: 4096,
|
|
1618
|
+
thinking: { type: 'adaptive' },
|
|
1619
|
+
outputConfig: { effort },
|
|
1620
|
+
});
|
|
1621
|
+
|
|
1622
|
+
let full: AIMessageChunk | undefined;
|
|
1623
|
+
for await (const chunk of await model.stream('Say hello.')) {
|
|
1624
|
+
full = full ? concat(full, chunk) : chunk;
|
|
1625
|
+
}
|
|
1626
|
+
expect(full).toBeInstanceOf(AIMessageChunk);
|
|
1627
|
+
expect(full!.content).toBeDefined();
|
|
1628
|
+
}
|
|
1629
|
+
);
|
|
1630
|
+
|
|
1631
|
+
test('via call options', async () => {
|
|
1632
|
+
const model = new ChatAnthropic({
|
|
1633
|
+
model: opus46Model,
|
|
1634
|
+
maxTokens: 4096,
|
|
1635
|
+
thinking: { type: 'adaptive' },
|
|
1636
|
+
});
|
|
1637
|
+
|
|
1638
|
+
const result = await model.invoke('Say hello.', {
|
|
1639
|
+
outputConfig: { effort: 'low' },
|
|
1640
|
+
} as any);
|
|
1641
|
+
expect(result.content).toBeDefined();
|
|
1642
|
+
});
|
|
1643
|
+
});
|
|
1644
|
+
|
|
1645
|
+
describe('outputFormat to outputConfig.format migration', () => {
|
|
1646
|
+
test('deprecated outputFormat on call options maps to output_config.format', () => {
|
|
1647
|
+
const model = new ChatAnthropic({
|
|
1648
|
+
model: opus46Model,
|
|
1649
|
+
apiKey: 'testing',
|
|
1650
|
+
maxTokens: 4096,
|
|
1651
|
+
});
|
|
1652
|
+
|
|
1653
|
+
const params = model.invocationParams({
|
|
1654
|
+
outputFormat: {
|
|
1655
|
+
type: 'json_schema',
|
|
1656
|
+
schema: { type: 'object' },
|
|
1657
|
+
},
|
|
1658
|
+
} as any);
|
|
1659
|
+
|
|
1660
|
+
expect(params.output_config).toEqual({
|
|
1661
|
+
format: {
|
|
1662
|
+
type: 'json_schema',
|
|
1663
|
+
schema: { type: 'object' },
|
|
1664
|
+
},
|
|
1665
|
+
});
|
|
1666
|
+
});
|
|
1667
|
+
|
|
1668
|
+
test('outputConfig.format takes precedence over deprecated outputFormat', () => {
|
|
1669
|
+
const model = new ChatAnthropic({
|
|
1670
|
+
model: opus46Model,
|
|
1671
|
+
apiKey: 'testing',
|
|
1672
|
+
maxTokens: 4096,
|
|
1673
|
+
});
|
|
1674
|
+
|
|
1675
|
+
const params = model.invocationParams({
|
|
1676
|
+
outputConfig: {
|
|
1677
|
+
format: {
|
|
1678
|
+
type: 'json_schema',
|
|
1679
|
+
schema: { type: 'object', properties: { a: { type: 'string' } } },
|
|
1680
|
+
},
|
|
1681
|
+
},
|
|
1682
|
+
outputFormat: {
|
|
1683
|
+
type: 'json_schema',
|
|
1684
|
+
schema: { type: 'object', properties: { b: { type: 'number' } } },
|
|
1685
|
+
},
|
|
1686
|
+
} as any);
|
|
1687
|
+
|
|
1688
|
+
expect(params.output_config?.format).toEqual({
|
|
1689
|
+
type: 'json_schema',
|
|
1690
|
+
schema: { type: 'object', properties: { a: { type: 'string' } } },
|
|
1691
|
+
});
|
|
1692
|
+
});
|
|
1693
|
+
|
|
1694
|
+
test('effort and format can be combined in outputConfig', () => {
|
|
1695
|
+
const model = new ChatAnthropic({
|
|
1696
|
+
model: opus46Model,
|
|
1697
|
+
apiKey: 'testing',
|
|
1698
|
+
maxTokens: 4096,
|
|
1699
|
+
outputConfig: { effort: 'medium' },
|
|
1700
|
+
});
|
|
1701
|
+
|
|
1702
|
+
const params = model.invocationParams({
|
|
1703
|
+
outputFormat: {
|
|
1704
|
+
type: 'json_schema',
|
|
1705
|
+
schema: { type: 'object' },
|
|
1706
|
+
},
|
|
1707
|
+
} as any);
|
|
1708
|
+
|
|
1709
|
+
expect(params.output_config).toEqual({
|
|
1710
|
+
effort: 'medium',
|
|
1711
|
+
format: {
|
|
1712
|
+
type: 'json_schema',
|
|
1713
|
+
schema: { type: 'object' },
|
|
1714
|
+
},
|
|
1715
|
+
});
|
|
1716
|
+
});
|
|
1717
|
+
});
|
|
1718
|
+
|
|
1719
|
+
describe('Data residency (inferenceGeo)', () => {
|
|
1720
|
+
test('invocationParams passes inferenceGeo from constructor', () => {
|
|
1721
|
+
const model = new ChatAnthropic({
|
|
1722
|
+
model: opus46Model,
|
|
1723
|
+
apiKey: 'testing',
|
|
1724
|
+
maxTokens: 4096,
|
|
1725
|
+
inferenceGeo: 'us',
|
|
1726
|
+
});
|
|
1727
|
+
|
|
1728
|
+
const params = model.invocationParams({});
|
|
1729
|
+
|
|
1730
|
+
expect(params.inference_geo).toBe('us');
|
|
1731
|
+
});
|
|
1732
|
+
|
|
1733
|
+
test('invocationParams passes inferenceGeo from call options', () => {
|
|
1734
|
+
const model = new ChatAnthropic({
|
|
1735
|
+
model: opus46Model,
|
|
1736
|
+
apiKey: 'testing',
|
|
1737
|
+
maxTokens: 4096,
|
|
1738
|
+
});
|
|
1739
|
+
|
|
1740
|
+
const params = model.invocationParams({
|
|
1741
|
+
inferenceGeo: 'us',
|
|
1742
|
+
} as any);
|
|
1743
|
+
|
|
1744
|
+
expect(params.inference_geo).toBe('us');
|
|
1745
|
+
});
|
|
1746
|
+
|
|
1747
|
+
test('call-option inferenceGeo overrides constructor inferenceGeo', () => {
|
|
1748
|
+
const model = new ChatAnthropic({
|
|
1749
|
+
model: opus46Model,
|
|
1750
|
+
apiKey: 'testing',
|
|
1751
|
+
maxTokens: 4096,
|
|
1752
|
+
inferenceGeo: 'eu',
|
|
1753
|
+
});
|
|
1754
|
+
|
|
1755
|
+
const params = model.invocationParams({
|
|
1756
|
+
inferenceGeo: 'us',
|
|
1757
|
+
} as any);
|
|
1758
|
+
|
|
1759
|
+
expect(params.inference_geo).toBe('us');
|
|
1760
|
+
});
|
|
1761
|
+
|
|
1762
|
+
test('inferenceGeo is undefined when not set', () => {
|
|
1763
|
+
const model = new ChatAnthropic({
|
|
1764
|
+
model: opus46Model,
|
|
1765
|
+
apiKey: 'testing',
|
|
1766
|
+
maxTokens: 4096,
|
|
1767
|
+
});
|
|
1768
|
+
|
|
1769
|
+
const params = model.invocationParams({});
|
|
1770
|
+
|
|
1771
|
+
expect(params.inference_geo).toBeUndefined();
|
|
1772
|
+
});
|
|
1773
|
+
|
|
1774
|
+
test('inferenceGeo accepted by API', async () => {
|
|
1775
|
+
const model = new ChatAnthropic({
|
|
1776
|
+
model: opus46Model,
|
|
1777
|
+
maxTokens: 256,
|
|
1778
|
+
inferenceGeo: 'us',
|
|
1779
|
+
});
|
|
1780
|
+
|
|
1781
|
+
const result = await model.invoke('Say hello.');
|
|
1782
|
+
expect(result.content).toBeDefined();
|
|
1783
|
+
});
|
|
1784
|
+
});
|
|
1785
|
+
|
|
1786
|
+
describe('Compaction API', () => {
|
|
1787
|
+
test('context_management passed through invocationParams', () => {
|
|
1788
|
+
const model = new ChatAnthropic({
|
|
1789
|
+
model: opus46Model,
|
|
1790
|
+
apiKey: 'testing',
|
|
1791
|
+
maxTokens: 4096,
|
|
1792
|
+
contextManagement: {
|
|
1793
|
+
edits: [
|
|
1794
|
+
{
|
|
1795
|
+
type: 'compact_20260112',
|
|
1796
|
+
trigger: { type: 'input_tokens', value: 50000 },
|
|
1797
|
+
},
|
|
1798
|
+
],
|
|
1799
|
+
},
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
const params = model.invocationParams({});
|
|
1803
|
+
|
|
1804
|
+
expect(params.context_management).toBeDefined();
|
|
1805
|
+
expect(params.context_management.edits[0].type).toBe('compact_20260112');
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
test('Can properly format messages with compaction blocks', () => {
|
|
1809
|
+
const messageHistory = [
|
|
1810
|
+
new AIMessage({
|
|
1811
|
+
content: [
|
|
1812
|
+
{
|
|
1813
|
+
type: 'compaction',
|
|
1814
|
+
content:
|
|
1815
|
+
'Summary: The user asked about building a web scraper...',
|
|
1816
|
+
},
|
|
1817
|
+
{
|
|
1818
|
+
type: 'text',
|
|
1819
|
+
text: 'Based on our conversation so far, let me continue...',
|
|
1820
|
+
},
|
|
1821
|
+
],
|
|
1822
|
+
}),
|
|
1823
|
+
];
|
|
1824
|
+
|
|
1825
|
+
const formattedMessages =
|
|
1826
|
+
_convertMessagesToAnthropicPayload(messageHistory);
|
|
1827
|
+
|
|
1828
|
+
expect(formattedMessages.messages).toHaveLength(1);
|
|
1829
|
+
expect(formattedMessages.messages[0].role).toBe('assistant');
|
|
1830
|
+
expect(formattedMessages.messages[0].content).toHaveLength(2);
|
|
1831
|
+
|
|
1832
|
+
const [compactionBlock, textBlock] = formattedMessages.messages[0]
|
|
1833
|
+
.content as any[];
|
|
1834
|
+
expect(compactionBlock).toEqual({
|
|
1835
|
+
type: 'compaction',
|
|
1836
|
+
content: 'Summary: The user asked about building a web scraper...',
|
|
1837
|
+
});
|
|
1838
|
+
expect(textBlock).toEqual({
|
|
1839
|
+
type: 'text',
|
|
1840
|
+
text: 'Based on our conversation so far, let me continue...',
|
|
1841
|
+
});
|
|
1842
|
+
});
|
|
1843
|
+
});
|
|
1844
|
+
});
|
|
@@ -51,6 +51,10 @@ export type AnthropicWebSearchResultBlockParam =
|
|
|
51
51
|
Anthropic.Messages.WebSearchResultBlockParam;
|
|
52
52
|
export type AnthropicSearchResultBlockParam =
|
|
53
53
|
Anthropic.Beta.BetaSearchResultBlockParam;
|
|
54
|
+
export type AnthropicCompactionBlockParam =
|
|
55
|
+
Anthropic.Beta.BetaCompactionBlockParam;
|
|
56
|
+
export type AnthropicOutputConfig = Anthropic.Messages.OutputConfig;
|
|
57
|
+
export type ChatAnthropicOutputFormat = Anthropic.Messages.JSONOutputFormat;
|
|
54
58
|
|
|
55
59
|
// Union of all possible content block types including server tool use
|
|
56
60
|
export type AnthropicContentBlock =
|
|
@@ -63,7 +67,8 @@ export type AnthropicContentBlock =
|
|
|
63
67
|
| AnthropicRedactedThinkingBlockParam
|
|
64
68
|
| AnthropicServerToolUseBlockParam
|
|
65
69
|
| AnthropicWebSearchToolResultBlockParam
|
|
66
|
-
| AnthropicWebSearchResultBlockParam
|
|
70
|
+
| AnthropicWebSearchResultBlockParam
|
|
71
|
+
| AnthropicCompactionBlockParam;
|
|
67
72
|
|
|
68
73
|
// Union of all possible content block types including server tool use
|
|
69
74
|
export type ChatAnthropicContentBlock =
|
|
@@ -77,7 +82,8 @@ export type ChatAnthropicContentBlock =
|
|
|
77
82
|
| AnthropicServerToolUseBlockParam
|
|
78
83
|
| AnthropicWebSearchToolResultBlockParam
|
|
79
84
|
| AnthropicWebSearchResultBlockParam
|
|
80
|
-
| AnthropicSearchResultBlockParam
|
|
85
|
+
| AnthropicSearchResultBlockParam
|
|
86
|
+
| AnthropicCompactionBlockParam;
|
|
81
87
|
|
|
82
88
|
export function isAnthropicImageBlockParam(
|
|
83
89
|
block: unknown
|
|
@@ -24,8 +24,6 @@ import {
|
|
|
24
24
|
AnthropicImageBlockParam,
|
|
25
25
|
AnthropicMessageCreateParams,
|
|
26
26
|
AnthropicTextBlockParam,
|
|
27
|
-
AnthropicToolResultBlockParam,
|
|
28
|
-
AnthropicToolUseBlockParam,
|
|
29
27
|
AnthropicDocumentBlockParam,
|
|
30
28
|
AnthropicThinkingBlockParam,
|
|
31
29
|
AnthropicRedactedThinkingBlockParam,
|
|
@@ -33,6 +31,7 @@ import {
|
|
|
33
31
|
AnthropicWebSearchToolResultBlockParam,
|
|
34
32
|
isAnthropicImageBlockParam,
|
|
35
33
|
AnthropicSearchResultBlockParam,
|
|
34
|
+
AnthropicCompactionBlockParam,
|
|
36
35
|
AnthropicToolResponse,
|
|
37
36
|
} from '../types';
|
|
38
37
|
|
|
@@ -494,7 +493,7 @@ function _formatContent(message: BaseMessage) {
|
|
|
494
493
|
return block;
|
|
495
494
|
} else if (contentPart.type === 'search_result') {
|
|
496
495
|
const block: AnthropicSearchResultBlockParam = {
|
|
497
|
-
type: 'search_result' as const,
|
|
496
|
+
type: 'search_result' as const,
|
|
498
497
|
title: contentPart.title,
|
|
499
498
|
source: contentPart.source,
|
|
500
499
|
...('cache_control' in contentPart && contentPart.cache_control
|
|
@@ -506,6 +505,13 @@ function _formatContent(message: BaseMessage) {
|
|
|
506
505
|
content: contentPart.content,
|
|
507
506
|
};
|
|
508
507
|
return block;
|
|
508
|
+
} else if (contentPart.type === 'compaction') {
|
|
509
|
+
const block: AnthropicCompactionBlockParam = {
|
|
510
|
+
type: 'compaction' as const,
|
|
511
|
+
content: contentPart.content,
|
|
512
|
+
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
513
|
+
};
|
|
514
|
+
return block;
|
|
509
515
|
} else if (
|
|
510
516
|
textTypes.find((t) => t === contentPart.type) &&
|
|
511
517
|
'text' in contentPart
|
|
@@ -682,38 +688,15 @@ function mergeMessages(messages: AnthropicMessageCreateParams['messages']) {
|
|
|
682
688
|
const result: AnthropicMessageCreateParams['messages'] = [];
|
|
683
689
|
let currentMessage = messages[0];
|
|
684
690
|
|
|
691
|
+
type ContentBlocks = Exclude<
|
|
692
|
+
AnthropicMessageCreateParams['messages'][number]['content'],
|
|
693
|
+
string
|
|
694
|
+
>;
|
|
685
695
|
const normalizeContent = (
|
|
686
|
-
content:
|
|
687
|
-
|
|
688
|
-
| Array<
|
|
689
|
-
| AnthropicTextBlockParam
|
|
690
|
-
| AnthropicImageBlockParam
|
|
691
|
-
| AnthropicToolUseBlockParam
|
|
692
|
-
| AnthropicToolResultBlockParam
|
|
693
|
-
| AnthropicDocumentBlockParam
|
|
694
|
-
| AnthropicThinkingBlockParam
|
|
695
|
-
| AnthropicRedactedThinkingBlockParam
|
|
696
|
-
| AnthropicServerToolUseBlockParam
|
|
697
|
-
| AnthropicWebSearchToolResultBlockParam
|
|
698
|
-
>
|
|
699
|
-
): Array<
|
|
700
|
-
| AnthropicTextBlockParam
|
|
701
|
-
| AnthropicImageBlockParam
|
|
702
|
-
| AnthropicToolUseBlockParam
|
|
703
|
-
| AnthropicToolResultBlockParam
|
|
704
|
-
| AnthropicDocumentBlockParam
|
|
705
|
-
| AnthropicThinkingBlockParam
|
|
706
|
-
| AnthropicRedactedThinkingBlockParam
|
|
707
|
-
| AnthropicServerToolUseBlockParam
|
|
708
|
-
| AnthropicWebSearchToolResultBlockParam
|
|
709
|
-
> => {
|
|
696
|
+
content: AnthropicMessageCreateParams['messages'][number]['content']
|
|
697
|
+
): ContentBlocks => {
|
|
710
698
|
if (typeof content === 'string') {
|
|
711
|
-
return [
|
|
712
|
-
{
|
|
713
|
-
type: 'text',
|
|
714
|
-
text: content,
|
|
715
|
-
},
|
|
716
|
-
];
|
|
699
|
+
return [{ type: 'text', text: content }];
|
|
717
700
|
}
|
|
718
701
|
return content;
|
|
719
702
|
};
|
|
@@ -12,8 +12,19 @@ import { ChatGeneration } from '@langchain/core/outputs';
|
|
|
12
12
|
import { extractToolCalls } from './output_parsers';
|
|
13
13
|
import { AnthropicMessageResponse } from '../types';
|
|
14
14
|
|
|
15
|
+
function _isAnthropicCompactionBlock(
|
|
16
|
+
block: unknown
|
|
17
|
+
): block is Anthropic.Beta.BetaCompactionBlockParam {
|
|
18
|
+
return (
|
|
19
|
+
typeof block === 'object' &&
|
|
20
|
+
block !== null &&
|
|
21
|
+
'type' in block &&
|
|
22
|
+
block.type === 'compaction'
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
export function _makeMessageChunkFromAnthropicEvent(
|
|
16
|
-
data: Anthropic.Messages.
|
|
27
|
+
data: Anthropic.Beta.Messages.BetaRawMessageStreamEvent,
|
|
17
28
|
fields: {
|
|
18
29
|
streamUsage: boolean;
|
|
19
30
|
coerceContentToString: boolean;
|
|
@@ -233,6 +244,34 @@ export function _makeMessageChunkFromAnthropicEvent(
|
|
|
233
244
|
: [{ index: data.index, ...data.content_block }],
|
|
234
245
|
}),
|
|
235
246
|
};
|
|
247
|
+
} else if (
|
|
248
|
+
data.type === 'content_block_start' &&
|
|
249
|
+
_isAnthropicCompactionBlock(data.content_block)
|
|
250
|
+
) {
|
|
251
|
+
return {
|
|
252
|
+
chunk: new AIMessageChunk({
|
|
253
|
+
content: fields.coerceContentToString
|
|
254
|
+
? ''
|
|
255
|
+
: [{ index: data.index, ...data.content_block }],
|
|
256
|
+
}),
|
|
257
|
+
};
|
|
258
|
+
} else if (
|
|
259
|
+
data.type === 'content_block_delta' &&
|
|
260
|
+
data.delta.type === 'compaction_delta'
|
|
261
|
+
) {
|
|
262
|
+
return {
|
|
263
|
+
chunk: new AIMessageChunk({
|
|
264
|
+
content: fields.coerceContentToString
|
|
265
|
+
? ''
|
|
266
|
+
: [
|
|
267
|
+
{
|
|
268
|
+
index: data.index,
|
|
269
|
+
...data.delta,
|
|
270
|
+
type: 'compaction',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
}),
|
|
274
|
+
};
|
|
236
275
|
}
|
|
237
276
|
return null;
|
|
238
277
|
}
|