remote-codex 0.11.25 → 0.11.27
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/apps/relay-server/dist/index.js +69 -9
- package/apps/supervisor-api/dist/index.js +339 -81
- package/apps/supervisor-web/dist/assets/index-BVYGmxwf.css +1 -0
- package/apps/supervisor-web/dist/assets/index-pMPBEcL2.js +5 -0
- package/apps/supervisor-web/dist/assets/{thread-ui-Ck4oSYRQ.js → thread-ui-CpukI6ql.js} +46 -32
- package/apps/supervisor-web/dist/index.html +3 -3
- package/config/codex-model-pricing.json +74 -9
- package/package.json +1 -1
- package/packages/claude/src/historyItems.ts +102 -7
- package/packages/claude/src/runtimeAdapter.test.ts +479 -1
- package/packages/claude/src/runtimeAdapter.ts +231 -66
- package/packages/codex/src/historyItems.ts +1 -0
- package/packages/codex/src/modelPricing.test.ts +70 -12
- package/apps/supervisor-web/dist/assets/index-Ch_S2n2I.css +0 -1
- package/apps/supervisor-web/dist/assets/index-JrzRGVx3.js +0 -5
|
@@ -45,10 +45,12 @@ import {
|
|
|
45
45
|
hiddenInitPrompt,
|
|
46
46
|
isHiddenContinuationMessage,
|
|
47
47
|
isHiddenInitMessage,
|
|
48
|
+
limitErrorFromHistoryItems,
|
|
48
49
|
partialReasoningDelta,
|
|
49
50
|
partialTextDelta,
|
|
50
51
|
resultForToolUse,
|
|
51
52
|
suppressedClaudeToolUseIds,
|
|
53
|
+
taskNotificationToolResult,
|
|
52
54
|
toolUseFromPartialStart,
|
|
53
55
|
toolUseToHistoryItem,
|
|
54
56
|
toolResultBlocks,
|
|
@@ -748,6 +750,14 @@ function queryResultError(message: SDKMessage): string | null {
|
|
|
748
750
|
return message.errors?.join('\n') || message.stop_reason || 'Claude turn failed.';
|
|
749
751
|
}
|
|
750
752
|
|
|
753
|
+
function statusForHistoricalItems(items: AgentHistoryItem[]) {
|
|
754
|
+
const limitError = limitErrorFromHistoryItems(items);
|
|
755
|
+
return {
|
|
756
|
+
status: limitError ? ('failed' as const) : ('completed' as const),
|
|
757
|
+
error: limitError,
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
|
|
751
761
|
function assistantMessagePayload(message: SDKMessage) {
|
|
752
762
|
return message.type === 'assistant' ? message.message : null;
|
|
753
763
|
}
|
|
@@ -863,6 +873,10 @@ function streamMessageId(event: unknown) {
|
|
|
863
873
|
return messageIdFromPayload(message);
|
|
864
874
|
}
|
|
865
875
|
|
|
876
|
+
function sessionMessageTimestamp(message: SessionMessage) {
|
|
877
|
+
return typeof message.uuid === 'string' ? isoFromUuidV7(message.uuid) : null;
|
|
878
|
+
}
|
|
879
|
+
|
|
866
880
|
function addOrUpdateItem(state: ActiveClaudeTurn, item: AgentHistoryItem) {
|
|
867
881
|
if (!state.items.has(item.id)) {
|
|
868
882
|
state.itemOrder.push(item.id);
|
|
@@ -876,6 +890,68 @@ function orderedItems(state: ActiveClaudeTurn) {
|
|
|
876
890
|
.filter((item): item is AgentHistoryItem => Boolean(item));
|
|
877
891
|
}
|
|
878
892
|
|
|
893
|
+
function withHistoryItemCreatedAt<T extends AgentHistoryItem>(
|
|
894
|
+
item: T,
|
|
895
|
+
createdAt: string | null | undefined,
|
|
896
|
+
): T {
|
|
897
|
+
if (item.createdAt || !createdAt) {
|
|
898
|
+
return item;
|
|
899
|
+
}
|
|
900
|
+
return { ...item, createdAt };
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function latestReasoningItem(state: ActiveClaudeTurn) {
|
|
904
|
+
const lastItemId = state.itemOrder.at(-1);
|
|
905
|
+
const lastItem = lastItemId ? state.items.get(lastItemId) : null;
|
|
906
|
+
return lastItem?.kind === 'reasoning' ? lastItem : null;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
function joinReasoningText(left: string, right: string) {
|
|
910
|
+
if (!left) {
|
|
911
|
+
return right;
|
|
912
|
+
}
|
|
913
|
+
if (!right) {
|
|
914
|
+
return left;
|
|
915
|
+
}
|
|
916
|
+
if (right.startsWith(left)) {
|
|
917
|
+
return right;
|
|
918
|
+
}
|
|
919
|
+
if (left.endsWith(right)) {
|
|
920
|
+
return left;
|
|
921
|
+
}
|
|
922
|
+
return `${left}\n\n${right}`;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function isRunningHistoryItemStatus(status: string | null | undefined) {
|
|
926
|
+
const normalized = status?.trim().toLowerCase();
|
|
927
|
+
return (
|
|
928
|
+
normalized === 'running' ||
|
|
929
|
+
normalized === 'pending' ||
|
|
930
|
+
normalized === 'in_progress' ||
|
|
931
|
+
normalized === 'in progress'
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
function finalizeTurnItems(
|
|
936
|
+
state: ActiveClaudeTurn,
|
|
937
|
+
status: AgentTurn['status'],
|
|
938
|
+
completedAt: string,
|
|
939
|
+
) {
|
|
940
|
+
return orderedItems(state).map((item) => {
|
|
941
|
+
if (item.kind === 'userMessage') {
|
|
942
|
+
return item;
|
|
943
|
+
}
|
|
944
|
+
if (status === 'completed' && isRunningHistoryItemStatus(item.status)) {
|
|
945
|
+
return {
|
|
946
|
+
...item,
|
|
947
|
+
status: 'completed',
|
|
948
|
+
createdAt: item.createdAt ?? completedAt,
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
return withHistoryItemCreatedAt(item, completedAt);
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
|
|
879
955
|
function stringFromRecord(value: Record<string, unknown>, key: string) {
|
|
880
956
|
const raw = value[key];
|
|
881
957
|
return typeof raw === 'string' && raw.trim() ? raw : null;
|
|
@@ -1235,7 +1311,15 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1235
1311
|
const sessions = await this.withClaudeConfigEnv(() => this.listSessionsFn({} as ListSessionsOptions));
|
|
1236
1312
|
return sessions.map((session) => {
|
|
1237
1313
|
this.knownSessionIds.add(session.sessionId);
|
|
1238
|
-
|
|
1314
|
+
const summary = sessionSummaryFromInfo(session);
|
|
1315
|
+
const activeTurn = this.activeTurnForSession(summary.providerSessionId);
|
|
1316
|
+
return activeTurn
|
|
1317
|
+
? {
|
|
1318
|
+
...summary,
|
|
1319
|
+
status: 'running' as const,
|
|
1320
|
+
updatedAt: summary.updatedAt ?? activeTurn.startedAt,
|
|
1321
|
+
}
|
|
1322
|
+
: summary;
|
|
1239
1323
|
});
|
|
1240
1324
|
}
|
|
1241
1325
|
|
|
@@ -1418,9 +1502,12 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1418
1502
|
tools: { type: 'preset', preset: 'claude_code' },
|
|
1419
1503
|
}),
|
|
1420
1504
|
});
|
|
1421
|
-
const userItem =
|
|
1422
|
-
|
|
1423
|
-
|
|
1505
|
+
const userItem = withHistoryItemCreatedAt(
|
|
1506
|
+
userMessageToHistoryItem(`${providerTurnId}:user`, {
|
|
1507
|
+
content: input.prompt,
|
|
1508
|
+
}),
|
|
1509
|
+
startedAt,
|
|
1510
|
+
);
|
|
1424
1511
|
const initialItems = input.hidden ? [] : [userItem];
|
|
1425
1512
|
const state: ActiveClaudeTurn = {
|
|
1426
1513
|
providerSessionId: input.providerSessionId,
|
|
@@ -1511,6 +1598,15 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1511
1598
|
}
|
|
1512
1599
|
}
|
|
1513
1600
|
|
|
1601
|
+
private activeTurnForSession(providerSessionId: string) {
|
|
1602
|
+
for (const state of this.activeTurns.values()) {
|
|
1603
|
+
if (state.providerSessionId === providerSessionId && !state.completed) {
|
|
1604
|
+
return state;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1514
1610
|
private reconcileActiveTranscriptTurn(
|
|
1515
1611
|
providerSessionId: string,
|
|
1516
1612
|
turns: AgentTurn[],
|
|
@@ -1594,31 +1690,16 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1594
1690
|
|
|
1595
1691
|
private async consumeQuery(state: ActiveClaudeTurn) {
|
|
1596
1692
|
const rawMessages: SDKMessage[] = [];
|
|
1693
|
+
let terminalStatus: AgentTurn['status'] | null = null;
|
|
1694
|
+
let terminalError: string | null = null;
|
|
1597
1695
|
try {
|
|
1598
1696
|
for await (const message of state.query) {
|
|
1599
1697
|
rawMessages.push(message);
|
|
1600
|
-
if (state.completed) {
|
|
1601
|
-
continue;
|
|
1602
|
-
}
|
|
1603
1698
|
this.consumeMessage(state, message);
|
|
1604
1699
|
const status = queryResultStatus(message);
|
|
1605
1700
|
if (status) {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
this.emitUsage(state);
|
|
1609
|
-
this.emitRuntimeEvent({
|
|
1610
|
-
type: 'turn.completed',
|
|
1611
|
-
provider: 'claude',
|
|
1612
|
-
providerSessionId: state.providerSessionId,
|
|
1613
|
-
turn: buildAgentTurn({
|
|
1614
|
-
providerTurnId: state.providerTurnId,
|
|
1615
|
-
startedAt: state.startedAt,
|
|
1616
|
-
status: state.interrupted ? 'interrupted' : status,
|
|
1617
|
-
error: queryResultError(message),
|
|
1618
|
-
items: orderedItems(state),
|
|
1619
|
-
rawTurn: rawMessages,
|
|
1620
|
-
}),
|
|
1621
|
-
});
|
|
1701
|
+
terminalStatus = status;
|
|
1702
|
+
terminalError = queryResultError(message);
|
|
1622
1703
|
}
|
|
1623
1704
|
}
|
|
1624
1705
|
|
|
@@ -1626,6 +1707,13 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1626
1707
|
state.completed = true;
|
|
1627
1708
|
this.deleteActiveTurn(state);
|
|
1628
1709
|
this.emitUsage(state);
|
|
1710
|
+
const completedAt = new Date().toISOString();
|
|
1711
|
+
const limitError = limitErrorFromHistoryItems(orderedItems(state));
|
|
1712
|
+
const status = state.interrupted
|
|
1713
|
+
? 'interrupted'
|
|
1714
|
+
: limitError
|
|
1715
|
+
? 'failed'
|
|
1716
|
+
: terminalStatus ?? 'completed';
|
|
1629
1717
|
this.emitRuntimeEvent({
|
|
1630
1718
|
type: 'turn.completed',
|
|
1631
1719
|
provider: 'claude',
|
|
@@ -1633,8 +1721,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1633
1721
|
turn: buildAgentTurn({
|
|
1634
1722
|
providerTurnId: state.providerTurnId,
|
|
1635
1723
|
startedAt: state.startedAt,
|
|
1636
|
-
status
|
|
1637
|
-
|
|
1724
|
+
status,
|
|
1725
|
+
error: limitError ?? terminalError,
|
|
1726
|
+
items: finalizeTurnItems(state, status, completedAt),
|
|
1638
1727
|
rawTurn: rawMessages,
|
|
1639
1728
|
}),
|
|
1640
1729
|
});
|
|
@@ -1656,6 +1745,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1656
1745
|
|
|
1657
1746
|
private consumeMessage(state: ActiveClaudeTurn, message: SDKMessage) {
|
|
1658
1747
|
this.captureUsage(state, message);
|
|
1748
|
+
const messageCreatedAt = new Date().toISOString();
|
|
1659
1749
|
|
|
1660
1750
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
1661
1751
|
this.updateToolboxItemsFromSystemInit(message);
|
|
@@ -1677,8 +1767,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1677
1767
|
event: message.event,
|
|
1678
1768
|
});
|
|
1679
1769
|
if (toolItem) {
|
|
1680
|
-
|
|
1681
|
-
|
|
1770
|
+
const nextItem = withHistoryItemCreatedAt(toolItem, messageCreatedAt);
|
|
1771
|
+
addOrUpdateItem(state, nextItem);
|
|
1772
|
+
this.emitItem(state, nextItem, 'item.started');
|
|
1682
1773
|
return;
|
|
1683
1774
|
}
|
|
1684
1775
|
|
|
@@ -1688,16 +1779,22 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1688
1779
|
});
|
|
1689
1780
|
if (reasoningItem) {
|
|
1690
1781
|
const existing = state.items.get(reasoningItem.id);
|
|
1691
|
-
const
|
|
1782
|
+
const previousReasoning = existing?.kind === 'reasoning'
|
|
1783
|
+
? existing
|
|
1784
|
+
: latestReasoningItem(state);
|
|
1785
|
+
const nextItem: AgentHistoryItem = previousReasoning
|
|
1692
1786
|
? {
|
|
1693
|
-
...
|
|
1694
|
-
text:
|
|
1695
|
-
|
|
1787
|
+
...previousReasoning,
|
|
1788
|
+
text:
|
|
1789
|
+
previousReasoning.id === reasoningItem.id
|
|
1790
|
+
? `${previousReasoning.text}${reasoningItem.text}`
|
|
1791
|
+
: joinReasoningText(previousReasoning.text, reasoningItem.text),
|
|
1792
|
+
status: reasoningItem.status ?? previousReasoning.status ?? null,
|
|
1696
1793
|
}
|
|
1697
|
-
: reasoningItem;
|
|
1794
|
+
: withHistoryItemCreatedAt(reasoningItem, messageCreatedAt);
|
|
1698
1795
|
addOrUpdateItem(state, nextItem);
|
|
1699
|
-
this.emitItem(state, nextItem,
|
|
1700
|
-
force: Boolean(
|
|
1796
|
+
this.emitItem(state, nextItem, previousReasoning ? 'item.completed' : 'item.started', {
|
|
1797
|
+
force: Boolean(previousReasoning),
|
|
1701
1798
|
});
|
|
1702
1799
|
return;
|
|
1703
1800
|
}
|
|
@@ -1715,6 +1812,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1715
1812
|
})
|
|
1716
1813
|
: markTransientAgentHistoryItem({
|
|
1717
1814
|
id: delta.itemId,
|
|
1815
|
+
createdAt: messageCreatedAt,
|
|
1718
1816
|
kind: 'agentMessage',
|
|
1719
1817
|
text: delta.delta,
|
|
1720
1818
|
});
|
|
@@ -1732,6 +1830,19 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1732
1830
|
}
|
|
1733
1831
|
|
|
1734
1832
|
if (message.type === 'user') {
|
|
1833
|
+
const taskNotification = taskNotificationToolResult(message.message);
|
|
1834
|
+
if (taskNotification && !state.suppressedToolUseIds.has(taskNotification.toolUseId)) {
|
|
1835
|
+
const item = resultForToolUse({
|
|
1836
|
+
toolUseId: taskNotification.toolUseId,
|
|
1837
|
+
result: message.tool_use_result ?? taskNotification.result,
|
|
1838
|
+
previous: state.items.get(taskNotification.toolUseId) ?? null,
|
|
1839
|
+
});
|
|
1840
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1841
|
+
addOrUpdateItem(state, nextItem);
|
|
1842
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1735
1846
|
const rawToolResults = toolResultBlocks(message.message);
|
|
1736
1847
|
const toolResults = rawToolResults.filter(
|
|
1737
1848
|
(toolResult) => !state.suppressedToolUseIds.has(toolResult.toolUseId),
|
|
@@ -1743,8 +1854,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1743
1854
|
result: message.tool_use_result ?? toolResult.result,
|
|
1744
1855
|
previous: state.items.get(toolResult.toolUseId) ?? null,
|
|
1745
1856
|
});
|
|
1746
|
-
|
|
1747
|
-
|
|
1857
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1858
|
+
addOrUpdateItem(state, nextItem);
|
|
1859
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1748
1860
|
}
|
|
1749
1861
|
return;
|
|
1750
1862
|
}
|
|
@@ -1776,12 +1888,13 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1776
1888
|
messageId: assistantMessageId,
|
|
1777
1889
|
message: payload,
|
|
1778
1890
|
})) {
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1891
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1892
|
+
const existing = state.items.get(nextItem.id);
|
|
1893
|
+
addOrUpdateItem(state, nextItem);
|
|
1894
|
+
if (nextItem.kind !== 'agentMessage' && !existing) {
|
|
1895
|
+
this.emitItem(state, nextItem, 'item.started');
|
|
1896
|
+
} else if (nextItem.kind !== 'agentMessage' && existing) {
|
|
1897
|
+
this.emitItem(state, nextItem, 'item.started', { force: true });
|
|
1785
1898
|
}
|
|
1786
1899
|
}
|
|
1787
1900
|
return;
|
|
@@ -1796,8 +1909,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1796
1909
|
result: message.tool_use_result ?? message.message,
|
|
1797
1910
|
previous: state.items.get(message.parent_tool_use_id) ?? null,
|
|
1798
1911
|
});
|
|
1799
|
-
|
|
1800
|
-
|
|
1912
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1913
|
+
addOrUpdateItem(state, nextItem);
|
|
1914
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1801
1915
|
return;
|
|
1802
1916
|
}
|
|
1803
1917
|
|
|
@@ -1817,8 +1931,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1817
1931
|
status: 'running',
|
|
1818
1932
|
});
|
|
1819
1933
|
if (item) {
|
|
1820
|
-
|
|
1821
|
-
|
|
1934
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1935
|
+
addOrUpdateItem(state, nextItem);
|
|
1936
|
+
this.emitItem(state, nextItem, 'item.started');
|
|
1822
1937
|
} else {
|
|
1823
1938
|
state.suppressedToolUseIds.add(toolUseId);
|
|
1824
1939
|
}
|
|
@@ -1840,13 +1955,15 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1840
1955
|
}
|
|
1841
1956
|
: {
|
|
1842
1957
|
id: toolUseId,
|
|
1958
|
+
createdAt: messageCreatedAt,
|
|
1843
1959
|
kind: 'toolCall',
|
|
1844
1960
|
text: `${message.tool_name} denied`,
|
|
1845
1961
|
detailText: typeof message.message === 'string' ? message.message : null,
|
|
1846
1962
|
status: 'denied',
|
|
1847
1963
|
};
|
|
1848
|
-
|
|
1849
|
-
|
|
1964
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1965
|
+
addOrUpdateItem(state, nextItem);
|
|
1966
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1850
1967
|
}
|
|
1851
1968
|
}
|
|
1852
1969
|
|
|
@@ -2076,6 +2193,18 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2076
2193
|
itemsById: new Map(),
|
|
2077
2194
|
};
|
|
2078
2195
|
}
|
|
2196
|
+
const previous = current.items.at(-1);
|
|
2197
|
+
if (item.kind === 'reasoning' && previous?.kind === 'reasoning') {
|
|
2198
|
+
const merged = {
|
|
2199
|
+
...previous,
|
|
2200
|
+
text: joinReasoningText(previous.text, item.text),
|
|
2201
|
+
status: item.status ?? previous.status ?? null,
|
|
2202
|
+
};
|
|
2203
|
+
current.items[current.items.length - 1] = merged;
|
|
2204
|
+
current.itemsById.set(previous.id, merged);
|
|
2205
|
+
current.itemsById.set(item.id, merged);
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2079
2208
|
const existingIndex = current.items.findIndex((entry) => entry.id === item.id);
|
|
2080
2209
|
if (existingIndex >= 0) {
|
|
2081
2210
|
current.items[existingIndex] = item;
|
|
@@ -2087,6 +2216,25 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2087
2216
|
|
|
2088
2217
|
for (const message of messages) {
|
|
2089
2218
|
if (message.type === 'user') {
|
|
2219
|
+
const taskNotification = taskNotificationToolResult(message.message);
|
|
2220
|
+
if (taskNotification) {
|
|
2221
|
+
if (suppressedToolUseIds.has(taskNotification.toolUseId)) {
|
|
2222
|
+
continue;
|
|
2223
|
+
}
|
|
2224
|
+
const previous = current?.itemsById.get(taskNotification.toolUseId) ?? null;
|
|
2225
|
+
upsertCurrentItem(
|
|
2226
|
+
withHistoryItemCreatedAt(
|
|
2227
|
+
resultForToolUse({
|
|
2228
|
+
toolUseId: taskNotification.toolUseId,
|
|
2229
|
+
result: message.tool_use_result ?? taskNotification.result,
|
|
2230
|
+
previous,
|
|
2231
|
+
}),
|
|
2232
|
+
sessionMessageTimestamp(message) ?? current?.startedAt,
|
|
2233
|
+
),
|
|
2234
|
+
);
|
|
2235
|
+
continue;
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2090
2238
|
const rawToolResults = toolResultBlocks(message.message);
|
|
2091
2239
|
const toolResults = rawToolResults.filter(
|
|
2092
2240
|
(toolResult) => !suppressedToolUseIds.has(toolResult.toolUseId),
|
|
@@ -2094,11 +2242,16 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2094
2242
|
if (toolResults.length > 0) {
|
|
2095
2243
|
for (const toolResult of toolResults) {
|
|
2096
2244
|
const previous = current?.itemsById.get(toolResult.toolUseId) ?? null;
|
|
2097
|
-
upsertCurrentItem(
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2245
|
+
upsertCurrentItem(
|
|
2246
|
+
withHistoryItemCreatedAt(
|
|
2247
|
+
resultForToolUse({
|
|
2248
|
+
toolUseId: toolResult.toolUseId,
|
|
2249
|
+
result: toolResult.result,
|
|
2250
|
+
previous,
|
|
2251
|
+
}),
|
|
2252
|
+
sessionMessageTimestamp(message) ?? current?.startedAt,
|
|
2253
|
+
),
|
|
2254
|
+
);
|
|
2102
2255
|
}
|
|
2103
2256
|
continue;
|
|
2104
2257
|
}
|
|
@@ -2118,24 +2271,28 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2118
2271
|
}
|
|
2119
2272
|
skippingHiddenInit = false;
|
|
2120
2273
|
if (current && current.items.length > 0) {
|
|
2274
|
+
const outcome = statusForHistoricalItems(current.items);
|
|
2121
2275
|
turns.push(buildAgentTurn({
|
|
2122
2276
|
providerTurnId: current.providerTurnId,
|
|
2123
2277
|
startedAt: current.startedAt,
|
|
2124
|
-
status:
|
|
2278
|
+
status: outcome.status,
|
|
2279
|
+
error: outcome.error,
|
|
2125
2280
|
items: current.items,
|
|
2126
2281
|
}));
|
|
2127
2282
|
}
|
|
2128
2283
|
const messageUuid = message.uuid ?? randomUUID();
|
|
2284
|
+
const userStartedAt = isoFromUuidV7(messageUuid);
|
|
2129
2285
|
const userItem = await this.userMessageToHistoryItem(
|
|
2130
2286
|
messageUuid,
|
|
2131
2287
|
message.message,
|
|
2132
2288
|
context,
|
|
2133
2289
|
);
|
|
2290
|
+
const stampedUserItem = withHistoryItemCreatedAt(userItem, userStartedAt);
|
|
2134
2291
|
current = {
|
|
2135
2292
|
providerTurnId: `claude-turn-${messageUuid}`,
|
|
2136
|
-
startedAt:
|
|
2137
|
-
items: [
|
|
2138
|
-
itemsById: new Map([[messageUuid,
|
|
2293
|
+
startedAt: userStartedAt,
|
|
2294
|
+
items: [stampedUserItem],
|
|
2295
|
+
itemsById: new Map([[messageUuid, stampedUserItem]]),
|
|
2139
2296
|
};
|
|
2140
2297
|
continue;
|
|
2141
2298
|
}
|
|
@@ -2145,6 +2302,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2145
2302
|
}
|
|
2146
2303
|
|
|
2147
2304
|
if (message.type === 'assistant') {
|
|
2305
|
+
const assistantCreatedAt = sessionMessageTimestamp(message) ?? current?.startedAt;
|
|
2148
2306
|
for (const toolUseId of suppressedClaudeToolUseIds(message.message)) {
|
|
2149
2307
|
suppressedToolUseIds.add(toolUseId);
|
|
2150
2308
|
current?.itemsById.delete(toolUseId);
|
|
@@ -2153,7 +2311,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2153
2311
|
messageId: message.uuid ?? randomUUID(),
|
|
2154
2312
|
message: message.message,
|
|
2155
2313
|
})) {
|
|
2156
|
-
upsertCurrentItem(item);
|
|
2314
|
+
upsertCurrentItem(withHistoryItemCreatedAt(item, assistantCreatedAt));
|
|
2157
2315
|
}
|
|
2158
2316
|
continue;
|
|
2159
2317
|
}
|
|
@@ -2163,21 +2321,28 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2163
2321
|
continue;
|
|
2164
2322
|
}
|
|
2165
2323
|
const previous = current?.itemsById.get(message.parent_tool_use_id) ?? null;
|
|
2166
|
-
upsertCurrentItem(
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2324
|
+
upsertCurrentItem(
|
|
2325
|
+
withHistoryItemCreatedAt(
|
|
2326
|
+
resultForToolUse({
|
|
2327
|
+
toolUseId: message.parent_tool_use_id,
|
|
2328
|
+
result: isRecord(message.message) && 'content' in message.message
|
|
2329
|
+
? message.message.content
|
|
2330
|
+
: message.message,
|
|
2331
|
+
previous,
|
|
2332
|
+
}),
|
|
2333
|
+
sessionMessageTimestamp(message) ?? current?.startedAt,
|
|
2334
|
+
),
|
|
2335
|
+
);
|
|
2173
2336
|
}
|
|
2174
2337
|
}
|
|
2175
2338
|
|
|
2176
2339
|
if (current && current.items.length > 0) {
|
|
2340
|
+
const outcome = statusForHistoricalItems(current.items);
|
|
2177
2341
|
turns.push(buildAgentTurn({
|
|
2178
2342
|
providerTurnId: current.providerTurnId,
|
|
2179
2343
|
startedAt: current.startedAt,
|
|
2180
|
-
status:
|
|
2344
|
+
status: outcome.status,
|
|
2345
|
+
error: outcome.error,
|
|
2181
2346
|
items: current.items,
|
|
2182
2347
|
}));
|
|
2183
2348
|
}
|
|
@@ -509,6 +509,7 @@ export function shouldPersistLiveHistoryItem(item: ThreadHistoryItemDto) {
|
|
|
509
509
|
item.kind === 'agentToolCall' ||
|
|
510
510
|
item.kind === 'skillToolCall' ||
|
|
511
511
|
item.kind === 'toolCall' ||
|
|
512
|
+
item.kind === 'reasoning' ||
|
|
512
513
|
item.kind === 'webSearch'
|
|
513
514
|
);
|
|
514
515
|
}
|
|
@@ -71,9 +71,9 @@ describe('modelPricing', () => {
|
|
|
71
71
|
expect(estimate?.totalUsd).toBeCloseTo(0.125625, 10);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
it('prices Claude Sonnet
|
|
74
|
+
it('prices current Claude Sonnet aliases from the local pricing config', () => {
|
|
75
75
|
expect(supportsFastMode('sonnet')).toBe(false);
|
|
76
|
-
expect(contextWindowForModel('sonnet')).toBe(
|
|
76
|
+
expect(contextWindowForModel('sonnet')).toBe(1000000);
|
|
77
77
|
expect(contextWindowForModel('sonnet[1m]')).toBe(1000000);
|
|
78
78
|
|
|
79
79
|
const standardEstimate = estimateTurnPrice(sampleUsage, {
|
|
@@ -83,9 +83,9 @@ describe('modelPricing', () => {
|
|
|
83
83
|
expect(standardEstimate).toMatchObject({
|
|
84
84
|
pricingModelKey: 'sonnet',
|
|
85
85
|
pricingTierKey: 'standard',
|
|
86
|
-
inputUsd: 0.
|
|
87
|
-
cachedInputUsd: 0.
|
|
88
|
-
outputUsd: 0.
|
|
86
|
+
inputUsd: 0.002,
|
|
87
|
+
cachedInputUsd: 0.0001,
|
|
88
|
+
outputUsd: 0.015,
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
const oneMillionEstimate = estimateTurnPrice(sampleUsage, {
|
|
@@ -95,22 +95,35 @@ describe('modelPricing', () => {
|
|
|
95
95
|
expect(oneMillionEstimate).toMatchObject({
|
|
96
96
|
pricingModelKey: 'sonnet[1m]',
|
|
97
97
|
pricingTierKey: 'standard',
|
|
98
|
-
inputUsd: 0.
|
|
99
|
-
cachedInputUsd: 0.
|
|
100
|
-
outputUsd: 0.
|
|
98
|
+
inputUsd: 0.002,
|
|
99
|
+
cachedInputUsd: 0.0001,
|
|
100
|
+
outputUsd: 0.015,
|
|
101
101
|
});
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
-
it('prices current Claude Opus and Haiku aliases from the local pricing config', () => {
|
|
105
|
-
expect(contextWindowForModel('
|
|
104
|
+
it('prices current Claude Fable, Opus, and Haiku aliases from the local pricing config', () => {
|
|
105
|
+
expect(contextWindowForModel('fable')).toBe(1000000);
|
|
106
|
+
expect(contextWindowForModel('opus')).toBe(1000000);
|
|
106
107
|
expect(contextWindowForModel('claude-haiku-4-5')).toBe(200000);
|
|
107
108
|
|
|
109
|
+
const fableEstimate = estimateTurnPrice(sampleUsage, {
|
|
110
|
+
pricingModelKey: 'fable',
|
|
111
|
+
pricingTierKey: 'standard',
|
|
112
|
+
});
|
|
113
|
+
expect(fableEstimate).toMatchObject({
|
|
114
|
+
pricingModelKey: 'fable',
|
|
115
|
+
pricingTierKey: 'standard',
|
|
116
|
+
inputUsd: 0.01,
|
|
117
|
+
cachedInputUsd: 0.0005,
|
|
118
|
+
outputUsd: 0.075,
|
|
119
|
+
});
|
|
120
|
+
|
|
108
121
|
const opusEstimate = estimateTurnPrice(sampleUsage, {
|
|
109
|
-
pricingModelKey: '
|
|
122
|
+
pricingModelKey: 'opus',
|
|
110
123
|
pricingTierKey: 'standard',
|
|
111
124
|
});
|
|
112
125
|
expect(opusEstimate).toMatchObject({
|
|
113
|
-
pricingModelKey: '
|
|
126
|
+
pricingModelKey: 'opus',
|
|
114
127
|
pricingTierKey: 'standard',
|
|
115
128
|
inputUsd: 0.005,
|
|
116
129
|
cachedInputUsd: 0.00025,
|
|
@@ -130,6 +143,51 @@ describe('modelPricing', () => {
|
|
|
130
143
|
});
|
|
131
144
|
});
|
|
132
145
|
|
|
146
|
+
it('prices explicit Claude API model ids, including fast Opus and legacy Opus', () => {
|
|
147
|
+
expect(contextWindowForModel('claude-sonnet-5')).toBe(1000000);
|
|
148
|
+
expect(contextWindowForModel('claude-sonnet-4-6')).toBe(1000000);
|
|
149
|
+
expect(contextWindowForModel('claude-opus-4-8')).toBe(1000000);
|
|
150
|
+
expect(supportsFastMode('claude-opus-4-8')).toBe(true);
|
|
151
|
+
expect(supportsFastMode('claude-opus-4-7')).toBe(true);
|
|
152
|
+
expect(contextWindowForModel('claude-opus-4-1')).toBe(200000);
|
|
153
|
+
|
|
154
|
+
const sonnet5Estimate = estimateTurnPrice(sampleUsage, {
|
|
155
|
+
pricingModelKey: 'claude-sonnet-5',
|
|
156
|
+
pricingTierKey: 'standard',
|
|
157
|
+
});
|
|
158
|
+
expect(sonnet5Estimate).toMatchObject({
|
|
159
|
+
pricingModelKey: 'claude-sonnet-5',
|
|
160
|
+
pricingTierKey: 'standard',
|
|
161
|
+
inputUsd: 0.002,
|
|
162
|
+
cachedInputUsd: 0.0001,
|
|
163
|
+
outputUsd: 0.015,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const opusFastEstimate = estimateTurnPrice(sampleUsage, {
|
|
167
|
+
pricingModelKey: 'claude-opus-4-8',
|
|
168
|
+
pricingTierKey: 'fast',
|
|
169
|
+
});
|
|
170
|
+
expect(opusFastEstimate).toMatchObject({
|
|
171
|
+
pricingModelKey: 'claude-opus-4-8',
|
|
172
|
+
pricingTierKey: 'fast',
|
|
173
|
+
inputUsd: 0.01,
|
|
174
|
+
cachedInputUsd: 0.0005,
|
|
175
|
+
outputUsd: 0.075,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const legacyOpusEstimate = estimateTurnPrice(sampleUsage, {
|
|
179
|
+
pricingModelKey: 'claude-opus-4-1',
|
|
180
|
+
pricingTierKey: 'standard',
|
|
181
|
+
});
|
|
182
|
+
expect(legacyOpusEstimate).toMatchObject({
|
|
183
|
+
pricingModelKey: 'claude-opus-4-1',
|
|
184
|
+
pricingTierKey: 'standard',
|
|
185
|
+
inputUsd: 0.015,
|
|
186
|
+
cachedInputUsd: 0.00075,
|
|
187
|
+
outputUsd: 0.1125,
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
133
191
|
it('normalizes Claude date-stamped runtime model names to local pricing keys', () => {
|
|
134
192
|
expect(contextWindowForModel('claude-sonnet-4-5-20250929')).toBe(200000);
|
|
135
193
|
expect(supportsFastMode('claude-sonnet-4-5-20250929')).toBe(false);
|