remote-codex 0.11.24 → 0.11.26
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 +741 -23
- package/apps/supervisor-api/dist/index.js +233 -79
- package/apps/supervisor-web/dist/assets/index-BVYGmxwf.css +1 -0
- package/apps/supervisor-web/dist/assets/index-CIcJHgFF.js +5 -0
- package/apps/supervisor-web/dist/assets/{thread-ui-Ck4oSYRQ.js → thread-ui-CaDgVQIY.js} +52 -38
- 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 +31 -7
- package/packages/claude/src/runtimeAdapter.test.ts +220 -1
- package/packages/claude/src/runtimeAdapter.ts +180 -64
- package/packages/codex/src/historyItems.ts +1 -0
- package/packages/codex/src/modelPricing.test.ts +70 -12
- package/packages/shared/src/index.ts +54 -4
- package/apps/supervisor-web/dist/assets/index-DeQ67jTv.js +0 -5
- package/apps/supervisor-web/dist/assets/index-DgSdRu7a.css +0 -1
|
@@ -863,6 +863,10 @@ function streamMessageId(event: unknown) {
|
|
|
863
863
|
return messageIdFromPayload(message);
|
|
864
864
|
}
|
|
865
865
|
|
|
866
|
+
function sessionMessageTimestamp(message: SessionMessage) {
|
|
867
|
+
return typeof message.uuid === 'string' ? isoFromUuidV7(message.uuid) : null;
|
|
868
|
+
}
|
|
869
|
+
|
|
866
870
|
function addOrUpdateItem(state: ActiveClaudeTurn, item: AgentHistoryItem) {
|
|
867
871
|
if (!state.items.has(item.id)) {
|
|
868
872
|
state.itemOrder.push(item.id);
|
|
@@ -876,6 +880,68 @@ function orderedItems(state: ActiveClaudeTurn) {
|
|
|
876
880
|
.filter((item): item is AgentHistoryItem => Boolean(item));
|
|
877
881
|
}
|
|
878
882
|
|
|
883
|
+
function withHistoryItemCreatedAt<T extends AgentHistoryItem>(
|
|
884
|
+
item: T,
|
|
885
|
+
createdAt: string | null | undefined,
|
|
886
|
+
): T {
|
|
887
|
+
if (item.createdAt || !createdAt) {
|
|
888
|
+
return item;
|
|
889
|
+
}
|
|
890
|
+
return { ...item, createdAt };
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function latestReasoningItem(state: ActiveClaudeTurn) {
|
|
894
|
+
const lastItemId = state.itemOrder.at(-1);
|
|
895
|
+
const lastItem = lastItemId ? state.items.get(lastItemId) : null;
|
|
896
|
+
return lastItem?.kind === 'reasoning' ? lastItem : null;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function joinReasoningText(left: string, right: string) {
|
|
900
|
+
if (!left) {
|
|
901
|
+
return right;
|
|
902
|
+
}
|
|
903
|
+
if (!right) {
|
|
904
|
+
return left;
|
|
905
|
+
}
|
|
906
|
+
if (right.startsWith(left)) {
|
|
907
|
+
return right;
|
|
908
|
+
}
|
|
909
|
+
if (left.endsWith(right)) {
|
|
910
|
+
return left;
|
|
911
|
+
}
|
|
912
|
+
return `${left}\n\n${right}`;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function isRunningHistoryItemStatus(status: string | null | undefined) {
|
|
916
|
+
const normalized = status?.trim().toLowerCase();
|
|
917
|
+
return (
|
|
918
|
+
normalized === 'running' ||
|
|
919
|
+
normalized === 'pending' ||
|
|
920
|
+
normalized === 'in_progress' ||
|
|
921
|
+
normalized === 'in progress'
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function finalizeTurnItems(
|
|
926
|
+
state: ActiveClaudeTurn,
|
|
927
|
+
status: AgentTurn['status'],
|
|
928
|
+
completedAt: string,
|
|
929
|
+
) {
|
|
930
|
+
return orderedItems(state).map((item) => {
|
|
931
|
+
if (item.kind === 'userMessage') {
|
|
932
|
+
return item;
|
|
933
|
+
}
|
|
934
|
+
if (status === 'completed' && isRunningHistoryItemStatus(item.status)) {
|
|
935
|
+
return {
|
|
936
|
+
...item,
|
|
937
|
+
status: 'completed',
|
|
938
|
+
createdAt: item.createdAt ?? completedAt,
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
return withHistoryItemCreatedAt(item, completedAt);
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
|
|
879
945
|
function stringFromRecord(value: Record<string, unknown>, key: string) {
|
|
880
946
|
const raw = value[key];
|
|
881
947
|
return typeof raw === 'string' && raw.trim() ? raw : null;
|
|
@@ -1235,7 +1301,15 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1235
1301
|
const sessions = await this.withClaudeConfigEnv(() => this.listSessionsFn({} as ListSessionsOptions));
|
|
1236
1302
|
return sessions.map((session) => {
|
|
1237
1303
|
this.knownSessionIds.add(session.sessionId);
|
|
1238
|
-
|
|
1304
|
+
const summary = sessionSummaryFromInfo(session);
|
|
1305
|
+
const activeTurn = this.activeTurnForSession(summary.providerSessionId);
|
|
1306
|
+
return activeTurn
|
|
1307
|
+
? {
|
|
1308
|
+
...summary,
|
|
1309
|
+
status: 'running' as const,
|
|
1310
|
+
updatedAt: summary.updatedAt ?? activeTurn.startedAt,
|
|
1311
|
+
}
|
|
1312
|
+
: summary;
|
|
1239
1313
|
});
|
|
1240
1314
|
}
|
|
1241
1315
|
|
|
@@ -1418,9 +1492,12 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1418
1492
|
tools: { type: 'preset', preset: 'claude_code' },
|
|
1419
1493
|
}),
|
|
1420
1494
|
});
|
|
1421
|
-
const userItem =
|
|
1422
|
-
|
|
1423
|
-
|
|
1495
|
+
const userItem = withHistoryItemCreatedAt(
|
|
1496
|
+
userMessageToHistoryItem(`${providerTurnId}:user`, {
|
|
1497
|
+
content: input.prompt,
|
|
1498
|
+
}),
|
|
1499
|
+
startedAt,
|
|
1500
|
+
);
|
|
1424
1501
|
const initialItems = input.hidden ? [] : [userItem];
|
|
1425
1502
|
const state: ActiveClaudeTurn = {
|
|
1426
1503
|
providerSessionId: input.providerSessionId,
|
|
@@ -1511,6 +1588,15 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1511
1588
|
}
|
|
1512
1589
|
}
|
|
1513
1590
|
|
|
1591
|
+
private activeTurnForSession(providerSessionId: string) {
|
|
1592
|
+
for (const state of this.activeTurns.values()) {
|
|
1593
|
+
if (state.providerSessionId === providerSessionId && !state.completed) {
|
|
1594
|
+
return state;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1514
1600
|
private reconcileActiveTranscriptTurn(
|
|
1515
1601
|
providerSessionId: string,
|
|
1516
1602
|
turns: AgentTurn[],
|
|
@@ -1594,31 +1680,16 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1594
1680
|
|
|
1595
1681
|
private async consumeQuery(state: ActiveClaudeTurn) {
|
|
1596
1682
|
const rawMessages: SDKMessage[] = [];
|
|
1683
|
+
let terminalStatus: AgentTurn['status'] | null = null;
|
|
1684
|
+
let terminalError: string | null = null;
|
|
1597
1685
|
try {
|
|
1598
1686
|
for await (const message of state.query) {
|
|
1599
1687
|
rawMessages.push(message);
|
|
1600
|
-
if (state.completed) {
|
|
1601
|
-
continue;
|
|
1602
|
-
}
|
|
1603
1688
|
this.consumeMessage(state, message);
|
|
1604
1689
|
const status = queryResultStatus(message);
|
|
1605
1690
|
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
|
-
});
|
|
1691
|
+
terminalStatus = status;
|
|
1692
|
+
terminalError = queryResultError(message);
|
|
1622
1693
|
}
|
|
1623
1694
|
}
|
|
1624
1695
|
|
|
@@ -1626,6 +1697,10 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1626
1697
|
state.completed = true;
|
|
1627
1698
|
this.deleteActiveTurn(state);
|
|
1628
1699
|
this.emitUsage(state);
|
|
1700
|
+
const completedAt = new Date().toISOString();
|
|
1701
|
+
const status = state.interrupted
|
|
1702
|
+
? 'interrupted'
|
|
1703
|
+
: terminalStatus ?? 'completed';
|
|
1629
1704
|
this.emitRuntimeEvent({
|
|
1630
1705
|
type: 'turn.completed',
|
|
1631
1706
|
provider: 'claude',
|
|
@@ -1633,8 +1708,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1633
1708
|
turn: buildAgentTurn({
|
|
1634
1709
|
providerTurnId: state.providerTurnId,
|
|
1635
1710
|
startedAt: state.startedAt,
|
|
1636
|
-
status
|
|
1637
|
-
|
|
1711
|
+
status,
|
|
1712
|
+
error: terminalError,
|
|
1713
|
+
items: finalizeTurnItems(state, status, completedAt),
|
|
1638
1714
|
rawTurn: rawMessages,
|
|
1639
1715
|
}),
|
|
1640
1716
|
});
|
|
@@ -1656,6 +1732,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1656
1732
|
|
|
1657
1733
|
private consumeMessage(state: ActiveClaudeTurn, message: SDKMessage) {
|
|
1658
1734
|
this.captureUsage(state, message);
|
|
1735
|
+
const messageCreatedAt = new Date().toISOString();
|
|
1659
1736
|
|
|
1660
1737
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
1661
1738
|
this.updateToolboxItemsFromSystemInit(message);
|
|
@@ -1677,8 +1754,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1677
1754
|
event: message.event,
|
|
1678
1755
|
});
|
|
1679
1756
|
if (toolItem) {
|
|
1680
|
-
|
|
1681
|
-
|
|
1757
|
+
const nextItem = withHistoryItemCreatedAt(toolItem, messageCreatedAt);
|
|
1758
|
+
addOrUpdateItem(state, nextItem);
|
|
1759
|
+
this.emitItem(state, nextItem, 'item.started');
|
|
1682
1760
|
return;
|
|
1683
1761
|
}
|
|
1684
1762
|
|
|
@@ -1688,16 +1766,22 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1688
1766
|
});
|
|
1689
1767
|
if (reasoningItem) {
|
|
1690
1768
|
const existing = state.items.get(reasoningItem.id);
|
|
1691
|
-
const
|
|
1769
|
+
const previousReasoning = existing?.kind === 'reasoning'
|
|
1770
|
+
? existing
|
|
1771
|
+
: latestReasoningItem(state);
|
|
1772
|
+
const nextItem: AgentHistoryItem = previousReasoning
|
|
1692
1773
|
? {
|
|
1693
|
-
...
|
|
1694
|
-
text:
|
|
1695
|
-
|
|
1774
|
+
...previousReasoning,
|
|
1775
|
+
text:
|
|
1776
|
+
previousReasoning.id === reasoningItem.id
|
|
1777
|
+
? `${previousReasoning.text}${reasoningItem.text}`
|
|
1778
|
+
: joinReasoningText(previousReasoning.text, reasoningItem.text),
|
|
1779
|
+
status: reasoningItem.status ?? previousReasoning.status ?? null,
|
|
1696
1780
|
}
|
|
1697
|
-
: reasoningItem;
|
|
1781
|
+
: withHistoryItemCreatedAt(reasoningItem, messageCreatedAt);
|
|
1698
1782
|
addOrUpdateItem(state, nextItem);
|
|
1699
|
-
this.emitItem(state, nextItem,
|
|
1700
|
-
force: Boolean(
|
|
1783
|
+
this.emitItem(state, nextItem, previousReasoning ? 'item.completed' : 'item.started', {
|
|
1784
|
+
force: Boolean(previousReasoning),
|
|
1701
1785
|
});
|
|
1702
1786
|
return;
|
|
1703
1787
|
}
|
|
@@ -1715,6 +1799,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1715
1799
|
})
|
|
1716
1800
|
: markTransientAgentHistoryItem({
|
|
1717
1801
|
id: delta.itemId,
|
|
1802
|
+
createdAt: messageCreatedAt,
|
|
1718
1803
|
kind: 'agentMessage',
|
|
1719
1804
|
text: delta.delta,
|
|
1720
1805
|
});
|
|
@@ -1743,8 +1828,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1743
1828
|
result: message.tool_use_result ?? toolResult.result,
|
|
1744
1829
|
previous: state.items.get(toolResult.toolUseId) ?? null,
|
|
1745
1830
|
});
|
|
1746
|
-
|
|
1747
|
-
|
|
1831
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1832
|
+
addOrUpdateItem(state, nextItem);
|
|
1833
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1748
1834
|
}
|
|
1749
1835
|
return;
|
|
1750
1836
|
}
|
|
@@ -1776,12 +1862,13 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1776
1862
|
messageId: assistantMessageId,
|
|
1777
1863
|
message: payload,
|
|
1778
1864
|
})) {
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1865
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1866
|
+
const existing = state.items.get(nextItem.id);
|
|
1867
|
+
addOrUpdateItem(state, nextItem);
|
|
1868
|
+
if (nextItem.kind !== 'agentMessage' && !existing) {
|
|
1869
|
+
this.emitItem(state, nextItem, 'item.started');
|
|
1870
|
+
} else if (nextItem.kind !== 'agentMessage' && existing) {
|
|
1871
|
+
this.emitItem(state, nextItem, 'item.started', { force: true });
|
|
1785
1872
|
}
|
|
1786
1873
|
}
|
|
1787
1874
|
return;
|
|
@@ -1796,8 +1883,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1796
1883
|
result: message.tool_use_result ?? message.message,
|
|
1797
1884
|
previous: state.items.get(message.parent_tool_use_id) ?? null,
|
|
1798
1885
|
});
|
|
1799
|
-
|
|
1800
|
-
|
|
1886
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1887
|
+
addOrUpdateItem(state, nextItem);
|
|
1888
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1801
1889
|
return;
|
|
1802
1890
|
}
|
|
1803
1891
|
|
|
@@ -1817,8 +1905,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1817
1905
|
status: 'running',
|
|
1818
1906
|
});
|
|
1819
1907
|
if (item) {
|
|
1820
|
-
|
|
1821
|
-
|
|
1908
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1909
|
+
addOrUpdateItem(state, nextItem);
|
|
1910
|
+
this.emitItem(state, nextItem, 'item.started');
|
|
1822
1911
|
} else {
|
|
1823
1912
|
state.suppressedToolUseIds.add(toolUseId);
|
|
1824
1913
|
}
|
|
@@ -1840,13 +1929,15 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1840
1929
|
}
|
|
1841
1930
|
: {
|
|
1842
1931
|
id: toolUseId,
|
|
1932
|
+
createdAt: messageCreatedAt,
|
|
1843
1933
|
kind: 'toolCall',
|
|
1844
1934
|
text: `${message.tool_name} denied`,
|
|
1845
1935
|
detailText: typeof message.message === 'string' ? message.message : null,
|
|
1846
1936
|
status: 'denied',
|
|
1847
1937
|
};
|
|
1848
|
-
|
|
1849
|
-
|
|
1938
|
+
const nextItem = withHistoryItemCreatedAt(item, messageCreatedAt);
|
|
1939
|
+
addOrUpdateItem(state, nextItem);
|
|
1940
|
+
this.emitItem(state, nextItem, 'item.completed');
|
|
1850
1941
|
}
|
|
1851
1942
|
}
|
|
1852
1943
|
|
|
@@ -2076,6 +2167,18 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2076
2167
|
itemsById: new Map(),
|
|
2077
2168
|
};
|
|
2078
2169
|
}
|
|
2170
|
+
const previous = current.items.at(-1);
|
|
2171
|
+
if (item.kind === 'reasoning' && previous?.kind === 'reasoning') {
|
|
2172
|
+
const merged = {
|
|
2173
|
+
...previous,
|
|
2174
|
+
text: joinReasoningText(previous.text, item.text),
|
|
2175
|
+
status: item.status ?? previous.status ?? null,
|
|
2176
|
+
};
|
|
2177
|
+
current.items[current.items.length - 1] = merged;
|
|
2178
|
+
current.itemsById.set(previous.id, merged);
|
|
2179
|
+
current.itemsById.set(item.id, merged);
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2079
2182
|
const existingIndex = current.items.findIndex((entry) => entry.id === item.id);
|
|
2080
2183
|
if (existingIndex >= 0) {
|
|
2081
2184
|
current.items[existingIndex] = item;
|
|
@@ -2094,11 +2197,16 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2094
2197
|
if (toolResults.length > 0) {
|
|
2095
2198
|
for (const toolResult of toolResults) {
|
|
2096
2199
|
const previous = current?.itemsById.get(toolResult.toolUseId) ?? null;
|
|
2097
|
-
upsertCurrentItem(
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2200
|
+
upsertCurrentItem(
|
|
2201
|
+
withHistoryItemCreatedAt(
|
|
2202
|
+
resultForToolUse({
|
|
2203
|
+
toolUseId: toolResult.toolUseId,
|
|
2204
|
+
result: toolResult.result,
|
|
2205
|
+
previous,
|
|
2206
|
+
}),
|
|
2207
|
+
sessionMessageTimestamp(message) ?? current?.startedAt,
|
|
2208
|
+
),
|
|
2209
|
+
);
|
|
2102
2210
|
}
|
|
2103
2211
|
continue;
|
|
2104
2212
|
}
|
|
@@ -2126,16 +2234,18 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2126
2234
|
}));
|
|
2127
2235
|
}
|
|
2128
2236
|
const messageUuid = message.uuid ?? randomUUID();
|
|
2237
|
+
const userStartedAt = isoFromUuidV7(messageUuid);
|
|
2129
2238
|
const userItem = await this.userMessageToHistoryItem(
|
|
2130
2239
|
messageUuid,
|
|
2131
2240
|
message.message,
|
|
2132
2241
|
context,
|
|
2133
2242
|
);
|
|
2243
|
+
const stampedUserItem = withHistoryItemCreatedAt(userItem, userStartedAt);
|
|
2134
2244
|
current = {
|
|
2135
2245
|
providerTurnId: `claude-turn-${messageUuid}`,
|
|
2136
|
-
startedAt:
|
|
2137
|
-
items: [
|
|
2138
|
-
itemsById: new Map([[messageUuid,
|
|
2246
|
+
startedAt: userStartedAt,
|
|
2247
|
+
items: [stampedUserItem],
|
|
2248
|
+
itemsById: new Map([[messageUuid, stampedUserItem]]),
|
|
2139
2249
|
};
|
|
2140
2250
|
continue;
|
|
2141
2251
|
}
|
|
@@ -2145,6 +2255,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2145
2255
|
}
|
|
2146
2256
|
|
|
2147
2257
|
if (message.type === 'assistant') {
|
|
2258
|
+
const assistantCreatedAt = sessionMessageTimestamp(message) ?? current?.startedAt;
|
|
2148
2259
|
for (const toolUseId of suppressedClaudeToolUseIds(message.message)) {
|
|
2149
2260
|
suppressedToolUseIds.add(toolUseId);
|
|
2150
2261
|
current?.itemsById.delete(toolUseId);
|
|
@@ -2153,7 +2264,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2153
2264
|
messageId: message.uuid ?? randomUUID(),
|
|
2154
2265
|
message: message.message,
|
|
2155
2266
|
})) {
|
|
2156
|
-
upsertCurrentItem(item);
|
|
2267
|
+
upsertCurrentItem(withHistoryItemCreatedAt(item, assistantCreatedAt));
|
|
2157
2268
|
}
|
|
2158
2269
|
continue;
|
|
2159
2270
|
}
|
|
@@ -2163,13 +2274,18 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2163
2274
|
continue;
|
|
2164
2275
|
}
|
|
2165
2276
|
const previous = current?.itemsById.get(message.parent_tool_use_id) ?? null;
|
|
2166
|
-
upsertCurrentItem(
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2277
|
+
upsertCurrentItem(
|
|
2278
|
+
withHistoryItemCreatedAt(
|
|
2279
|
+
resultForToolUse({
|
|
2280
|
+
toolUseId: message.parent_tool_use_id,
|
|
2281
|
+
result: isRecord(message.message) && 'content' in message.message
|
|
2282
|
+
? message.message.content
|
|
2283
|
+
: message.message,
|
|
2284
|
+
previous,
|
|
2285
|
+
}),
|
|
2286
|
+
sessionMessageTimestamp(message) ?? current?.startedAt,
|
|
2287
|
+
),
|
|
2288
|
+
);
|
|
2173
2289
|
}
|
|
2174
2290
|
}
|
|
2175
2291
|
|
|
@@ -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);
|
|
@@ -112,6 +112,48 @@ export interface RelayDeviceDto {
|
|
|
112
112
|
createdAt: string;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
export interface RelayAdminUserDto extends RelayUserDto {
|
|
116
|
+
lastSeenAt: string | null;
|
|
117
|
+
deviceCount: number;
|
|
118
|
+
conversationCount: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface RelayAdminWorkspaceDto {
|
|
122
|
+
id: string;
|
|
123
|
+
label: string;
|
|
124
|
+
absPath?: string | null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface RelayAdminThreadDto {
|
|
128
|
+
id: string;
|
|
129
|
+
title: string;
|
|
130
|
+
workspaceId: string | null;
|
|
131
|
+
workspaceLabel: string | null;
|
|
132
|
+
status: string | null;
|
|
133
|
+
updatedAt: string | null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface RelayAdminDeviceDto extends RelayDeviceDto {
|
|
137
|
+
ownerUsername: string;
|
|
138
|
+
ownerEmail: string;
|
|
139
|
+
ipAddress: string | null;
|
|
140
|
+
workspaces: RelayAdminWorkspaceDto[];
|
|
141
|
+
threads: RelayAdminThreadDto[];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface RelayRegistrationSettingsDto {
|
|
145
|
+
enabled: boolean;
|
|
146
|
+
registrationPassword: string | null;
|
|
147
|
+
approvalRequired: boolean;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface RelayPendingRegistrationDto {
|
|
151
|
+
id: string;
|
|
152
|
+
email: string;
|
|
153
|
+
username: string;
|
|
154
|
+
createdAt: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
115
157
|
export type RelayThreadAccessDto = 'read' | 'control';
|
|
116
158
|
export type RelayWorkspaceAccessDto = 'none' | 'read' | 'write';
|
|
117
159
|
|
|
@@ -143,7 +185,9 @@ export interface RelaySessionShareDto {
|
|
|
143
185
|
deviceId: string;
|
|
144
186
|
deviceName: string;
|
|
145
187
|
threadId: string;
|
|
188
|
+
threadTitle: string | null;
|
|
146
189
|
workspaceId: string | null;
|
|
190
|
+
workspaceLabel: string | null;
|
|
147
191
|
label: string | null;
|
|
148
192
|
threadAccess: RelayThreadAccessDto;
|
|
149
193
|
workspaceAccess: RelayWorkspaceAccessDto;
|
|
@@ -183,8 +227,10 @@ export interface RelayLoginResultDto {
|
|
|
183
227
|
}
|
|
184
228
|
|
|
185
229
|
export interface RelayRegisterResultDto {
|
|
186
|
-
token
|
|
187
|
-
session
|
|
230
|
+
token?: string;
|
|
231
|
+
session?: RelaySessionDto;
|
|
232
|
+
pendingApproval?: boolean;
|
|
233
|
+
request?: RelayPendingRegistrationDto;
|
|
188
234
|
}
|
|
189
235
|
|
|
190
236
|
export interface RelayCreateDeviceResultDto {
|
|
@@ -200,8 +246,12 @@ export interface RelayPortalSummaryDto {
|
|
|
200
246
|
}
|
|
201
247
|
|
|
202
248
|
export interface RelayAdminSummaryDto {
|
|
203
|
-
users:
|
|
204
|
-
devices:
|
|
249
|
+
users: RelayAdminUserDto[];
|
|
250
|
+
devices: RelayAdminDeviceDto[];
|
|
251
|
+
shares: RelaySessionShareDto[];
|
|
252
|
+
pendingRegistrations: RelayPendingRegistrationDto[];
|
|
253
|
+
settings: RelayRegistrationSettingsDto;
|
|
254
|
+
conversationWindowDays: number;
|
|
205
255
|
registrationEnabled: boolean;
|
|
206
256
|
}
|
|
207
257
|
|