@agent-link/server 0.1.117 → 0.1.119
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/package.json +1 -1
- package/web/app.js +24 -4
- package/web/modules/connection.js +6 -2
- package/web/style.css +10 -0
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -50,6 +50,7 @@ const App = {
|
|
|
50
50
|
const isCompacting = ref(false);
|
|
51
51
|
const latency = ref(null);
|
|
52
52
|
const queuedMessages = ref([]);
|
|
53
|
+
const usageStats = ref(null);
|
|
53
54
|
const inputRef = ref(null);
|
|
54
55
|
|
|
55
56
|
// Sidebar state
|
|
@@ -130,6 +131,7 @@ const App = {
|
|
|
130
131
|
toolMsgMap: _getToolMsgMap(),
|
|
131
132
|
messageIdCounter: streaming.getMessageIdCounter(),
|
|
132
133
|
queuedMessages: queuedMessages.value,
|
|
134
|
+
usageStats: usageStats.value,
|
|
133
135
|
};
|
|
134
136
|
}
|
|
135
137
|
|
|
@@ -149,6 +151,7 @@ const App = {
|
|
|
149
151
|
streaming.setMessageIdCounter(cached.messageIdCounter || 0);
|
|
150
152
|
_restoreToolMsgMap(cached.toolMsgMap || new Map());
|
|
151
153
|
queuedMessages.value = cached.queuedMessages || [];
|
|
154
|
+
usageStats.value = cached.usageStats || null;
|
|
152
155
|
} else {
|
|
153
156
|
// New blank conversation
|
|
154
157
|
messages.value = [];
|
|
@@ -163,6 +166,7 @@ const App = {
|
|
|
163
166
|
streaming.reset();
|
|
164
167
|
_clearToolMsgMap();
|
|
165
168
|
queuedMessages.value = [];
|
|
169
|
+
usageStats.value = null;
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
currentConversationId.value = newConvId;
|
|
@@ -247,8 +251,8 @@ const App = {
|
|
|
247
251
|
const { connect, wsSend, closeWs, submitPassword, setDequeueNext, setFileBrowser, getToolMsgMap, restoreToolMsgMap, clearToolMsgMap } = createConnection({
|
|
248
252
|
status, agentName, hostname, workDir, sessionId, error,
|
|
249
253
|
serverVersion, agentVersion, latency,
|
|
250
|
-
messages, isProcessing, isCompacting, visibleLimit, queuedMessages,
|
|
251
|
-
historySessions, currentClaudeSessionId, loadingSessions, loadingHistory,
|
|
254
|
+
messages, isProcessing, isCompacting, visibleLimit, queuedMessages, usageStats,
|
|
255
|
+
historySessions, currentClaudeSessionId, needsResume, loadingSessions, loadingHistory,
|
|
252
256
|
folderPickerLoading, folderPickerEntries, folderPickerPath,
|
|
253
257
|
authRequired, authPassword, authError, authAttempts, authLocked,
|
|
254
258
|
streaming, sidebar, scrollToBottom,
|
|
@@ -412,6 +416,21 @@ const App = {
|
|
|
412
416
|
document.title = name ? `${name} — AgentLink` : 'AgentLink';
|
|
413
417
|
});
|
|
414
418
|
|
|
419
|
+
// ── Usage formatting ──
|
|
420
|
+
function formatTokens(n) {
|
|
421
|
+
if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
|
|
422
|
+
return String(n);
|
|
423
|
+
}
|
|
424
|
+
function formatUsage(u) {
|
|
425
|
+
if (!u) return '';
|
|
426
|
+
const pct = u.contextWindow ? Math.round(u.inputTokens / u.contextWindow * 100) : 0;
|
|
427
|
+
const ctx = formatTokens(u.inputTokens) + ' / ' + formatTokens(u.contextWindow) + ' (' + pct + '%)';
|
|
428
|
+
const cost = '$' + u.totalCost.toFixed(2);
|
|
429
|
+
const model = u.model.replace(/^claude-/, '').replace(/-\d{8}$/, '').replace(/-1m$/, '');
|
|
430
|
+
const dur = (u.durationMs / 1000).toFixed(1) + 's';
|
|
431
|
+
return 'Context ' + ctx + ' \u00b7 Cost ' + cost + ' \u00b7 ' + model + ' \u00b7 ' + dur;
|
|
432
|
+
}
|
|
433
|
+
|
|
415
434
|
// ── Lifecycle ──
|
|
416
435
|
onMounted(() => { connect(scheduleHighlight); });
|
|
417
436
|
onUnmounted(() => { closeWs(); streaming.cleanup(); window.removeEventListener('resize', _resizeHandler); document.removeEventListener('click', _workdirMenuClickHandler); document.removeEventListener('keydown', _workdirMenuKeyHandler); });
|
|
@@ -420,11 +439,11 @@ const App = {
|
|
|
420
439
|
status, agentName, hostname, workDir, sessionId, error,
|
|
421
440
|
serverVersion, agentVersion, latency,
|
|
422
441
|
messages, visibleMessages, hasMoreMessages, loadMoreMessages,
|
|
423
|
-
inputText, isProcessing, isCompacting, canSend, hasInput, inputRef, queuedMessages,
|
|
442
|
+
inputText, isProcessing, isCompacting, canSend, hasInput, inputRef, queuedMessages, usageStats,
|
|
424
443
|
sendMessage, handleKeydown, cancelExecution, removeQueuedMessage, onMessageListScroll,
|
|
425
444
|
getRenderedContent, copyMessage, toggleTool,
|
|
426
445
|
isPrevAssistant: _isPrevAssistant,
|
|
427
|
-
toggleContextSummary, formatTimestamp,
|
|
446
|
+
toggleContextSummary, formatTimestamp, formatUsage,
|
|
428
447
|
getToolIcon, getToolSummary, isEditTool, getEditDiffHtml, getFormattedToolInput, autoResize,
|
|
429
448
|
// AskUserQuestion
|
|
430
449
|
selectQuestionOption,
|
|
@@ -907,6 +926,7 @@ const App = {
|
|
|
907
926
|
<button class="queue-item-remove" @click="removeQueuedMessage(qm.id)" title="Remove from queue">×</button>
|
|
908
927
|
</div>
|
|
909
928
|
</div>
|
|
929
|
+
<div v-if="usageStats" class="usage-bar">{{ formatUsage(usageStats) }}</div>
|
|
910
930
|
<div
|
|
911
931
|
:class="['input-card', { 'drag-over': dragOver }]"
|
|
912
932
|
@dragover="handleDragOver"
|
|
@@ -14,8 +14,8 @@ export function createConnection(deps) {
|
|
|
14
14
|
const {
|
|
15
15
|
status, agentName, hostname, workDir, sessionId, error,
|
|
16
16
|
serverVersion, agentVersion, latency,
|
|
17
|
-
messages, isProcessing, isCompacting, visibleLimit, queuedMessages,
|
|
18
|
-
historySessions, currentClaudeSessionId, loadingSessions, loadingHistory,
|
|
17
|
+
messages, isProcessing, isCompacting, visibleLimit, queuedMessages, usageStats,
|
|
18
|
+
historySessions, currentClaudeSessionId, needsResume, loadingSessions, loadingHistory,
|
|
19
19
|
folderPickerLoading, folderPickerEntries, folderPickerPath,
|
|
20
20
|
authRequired, authPassword, authError, authAttempts, authLocked,
|
|
21
21
|
streaming, sidebar,
|
|
@@ -202,9 +202,11 @@ export function createConnection(deps) {
|
|
|
202
202
|
}
|
|
203
203
|
cache.isProcessing = false;
|
|
204
204
|
cache.isCompacting = false;
|
|
205
|
+
if (msg.usage) cache.usageStats = msg.usage;
|
|
205
206
|
if (cache.toolMsgMap) cache.toolMsgMap.clear();
|
|
206
207
|
processingConversations.value[convId] = false;
|
|
207
208
|
if (msg.type === 'execution_cancelled') {
|
|
209
|
+
cache.needsResume = true;
|
|
208
210
|
cache.messages.push({
|
|
209
211
|
id: ++cache.messageIdCounter, role: 'system',
|
|
210
212
|
content: 'Generation stopped.', timestamp: new Date(),
|
|
@@ -586,10 +588,12 @@ export function createConnection(deps) {
|
|
|
586
588
|
isProcessing.value = false;
|
|
587
589
|
isCompacting.value = false;
|
|
588
590
|
toolMsgMap.clear();
|
|
591
|
+
if (msg.usage) usageStats.value = msg.usage;
|
|
589
592
|
if (currentConversationId && currentConversationId.value) {
|
|
590
593
|
processingConversations.value[currentConversationId.value] = false;
|
|
591
594
|
}
|
|
592
595
|
if (msg.type === 'execution_cancelled') {
|
|
596
|
+
needsResume.value = true;
|
|
593
597
|
messages.value.push({
|
|
594
598
|
id: streaming.nextId(), role: 'system',
|
|
595
599
|
content: 'Generation stopped.', timestamp: new Date(),
|
package/web/style.css
CHANGED
|
@@ -955,6 +955,16 @@ body {
|
|
|
955
955
|
color: var(--error);
|
|
956
956
|
}
|
|
957
957
|
|
|
958
|
+
.usage-bar {
|
|
959
|
+
max-width: 768px;
|
|
960
|
+
margin: 0 auto 6px;
|
|
961
|
+
padding: 4px 10px;
|
|
962
|
+
font-size: 0.75rem;
|
|
963
|
+
color: var(--text-secondary);
|
|
964
|
+
text-align: center;
|
|
965
|
+
opacity: 0.7;
|
|
966
|
+
}
|
|
967
|
+
|
|
958
968
|
.assistant-bubble {
|
|
959
969
|
background: transparent;
|
|
960
970
|
padding: 0.2rem 0;
|