Expand model tag support: add GLM-5.1, simplify Anthropic IDs, scan tags anywhere in message

- Flink update_bars debouncing
- update_bars subscription idempotency bugfix
- Price decimal correction bugfix of previous commit
- Add GLM-5.1 model tag alongside renamed GLM-5
- Use short Anthropic model IDs (sonnet/haiku/opus) instead of full version strings
- Allow @tags anywhere in message content, not just at start
- Return hasOtherContent flag instead of trimmed rest string
- Only trigger greeting stream when tag has no other content
- Update workspace knowledge base references to platform/workspace and platform/shapes
- Hierarchical knowledge base catalog
- 151 Trading Strategies knowledge base articles
- Shapes knowledge base article
- MutateShapes tool instead of workspace patch
This commit is contained in:
2026-04-28 15:05:15 -04:00
parent d41fcd0499
commit 47471b7700
184 changed files with 9044 additions and 170 deletions

View File

@@ -191,8 +191,8 @@ const handleMessage = (data: WebSocketMessage) => {
const newMessages: any[] = [systemMsg]
// Re-add the user's first message (content after the @Tag)
const userContent: string = pendingModelSwitchContent || data.rest || ''
// Re-add the user's first message if there was content beyond the @Tag
const userContent: string = (data.hasOtherContent && pendingModelSwitchContent) ? pendingModelSwitchContent : ''
if (userContent) {
const userMsgId = generateMessageId()
lastSentMessageId = userMsgId
@@ -494,9 +494,9 @@ const sendMessage = async (event: any) => {
}
if (modelSwitchUser) {
// Model switch: store content-after-tag for model_switched handler to re-insert.
// Model switch: store full message content for model_switched handler to re-insert as user bubble.
// Don't add a user message bubble now — model_switched will set up the full initial state.
pendingModelSwitchContent = content.replace(`@${modelSwitchUser.username}`, '').trim()
pendingModelSwitchContent = content
wsManager.send(wsMessage)
isAgentProcessing.value = true
return

View File

@@ -83,15 +83,29 @@ export class WebSocketDatafeed implements IBasicDataFeed {
}
private handleMessage(message: any): void {
// On reconnect the server sends a fresh 'connected' message.
// Any pending requests were sent on the old socket and will never be answered,
// so reject them immediately so TradingView can retry on the new connection.
if (message.type === 'connected' && this.pendingRequests.size > 0) {
console.warn('[TradingView Datafeed] WebSocket reconnected — rejecting', this.pendingRequests.size, 'stale pending request(s)')
for (const [requestId, pending] of this.pendingRequests) {
clearTimeout(pending.timeout)
pending.reject(new Error('WebSocket reconnected'))
this.pendingRequests.delete(requestId)
// On reconnect (or initial connect) the server sends a 'connected' message.
// Reject any stale pending requests from the old socket, then re-subscribe all
// active bar subscriptions so the server has the correct state.
if (message.type === 'connected') {
if (this.pendingRequests.size > 0) {
console.warn('[TradingView Datafeed] WebSocket reconnected — rejecting', this.pendingRequests.size, 'stale pending request(s)')
for (const [requestId, pending] of this.pendingRequests) {
clearTimeout(pending.timeout)
pending.reject(new Error('WebSocket reconnected'))
this.pendingRequests.delete(requestId)
}
}
if (this.subscriptions.size > 0) {
console.log('[TradingView Datafeed] Reconnected — re-subscribing', this.subscriptions.size, 'active bar subscription(s)')
for (const [guid, sub] of this.subscriptions) {
this.sendRequest<any>({
type: 'subscribe_bars',
symbol: sub.symbolInfo.ticker || sub.symbolInfo.name,
period_seconds: intervalToSeconds(sub.resolution),
subscription_id: guid,
bar_type: 'open',
}).catch(() => {})
}
}
return
}