Skip to content

Commit 1bdd1ef

Browse files
authored
feat(completion): update userinfo and improve performance (#622)
* feat(webview): add copy functionality for user ID and improve metrics logging * feat(logging): conditionally adjust log levels based on environment * feat(completion): improve performance * fix(webview-ui): handle encoding issues in display name for user info * fix(webview-ui): add error handling to text decoding in useZgsmUserInfo
1 parent a042184 commit 1bdd1ef

File tree

8 files changed

+68
-19
lines changed

8 files changed

+68
-19
lines changed

packages/telemetry/src/prometheus/MetricsSerializer.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,26 @@ export class MetricsSerializer {
4545
}
4646
} else if (metric instanceof Histogram) {
4747
const sumMetrics = metricData.values.filter((v) => v.metricName?.endsWith("_sum"))
48-
48+
let HistogramLogs: { [key: string]: number[] } | null = null
4949
sumMetrics.forEach((sumValue) => {
5050
if (sumValue && sumValue.value > 0) {
5151
metric.observe(sumValue.labels, sumValue.value)
52-
this.logger.debug(
53-
`[MetricsSerializer] Histogram sum for ${metricData.name} loaded with value: ${sumValue.value}`,
54-
)
52+
if (HistogramLogs === null) {
53+
HistogramLogs = {}
54+
}
55+
if (HistogramLogs[metricData.name]) {
56+
HistogramLogs[metricData.name].push(sumValue.value)
57+
} else {
58+
HistogramLogs[metricData.name] = [sumValue.value]
59+
}
5560
}
5661
})
62+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
63+
HistogramLogs && Object.keys(HistogramLogs).forEach(name => {
64+
this.logger.debug(
65+
`[MetricsSerializer] Histogram sum for ${name} loaded with value: ${HistogramLogs![name].join()}`,
66+
)
67+
})
5768
} else if (metric instanceof Gauge) {
5869
for (const item of metricData.values) {
5970
metric.set(item.labels, item.value)

src/api/providers/zgsm.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ export class ZgsmAiHandler extends BaseProvider implements SingleCompletionHandl
195195
if (this.options.zgsmModelId === autoModeModelId) {
196196
selectedLlm = response.headers.get("x-select-llm") || ""
197197
selectReason = response.headers.get("x-select-reason") || ""
198+
const isDev = process.env.NODE_ENV === "development"
198199

199-
const userInputHeader = response.headers.get("x-user-input")
200+
const userInputHeader = isDev ? response.headers.get("x-user-input") : null
200201
if (userInputHeader) {
201202
const decodedUserInput = Buffer.from(userInputHeader, "base64").toString("utf-8")
202203
this.logger.info(`[x-user-input]: ${decodedUserInput}`)
@@ -431,6 +432,7 @@ export class ZgsmAiHandler extends BaseProvider implements SingleCompletionHandl
431432
const contentBuffer: string[] = []
432433
let time = Date.now()
433434
let isPrinted = false
435+
const isDev = process.env.NODE_ENV === "development"
434436

435437
// Yield selected LLM info if available (for Auto model mode)
436438
if (selectedLlm && this.options.zgsmModelId === autoModeModelId) {
@@ -447,7 +449,7 @@ export class ZgsmAiHandler extends BaseProvider implements SingleCompletionHandl
447449
// Cache content for batch processing
448450
if (delta.content) {
449451
contentBuffer.push(delta.content)
450-
if (!isPrinted && chunk.model && this.options.zgsmModelId === autoModeModelId) {
452+
if (isDev && !isPrinted && chunk.model && this.options.zgsmModelId === autoModeModelId) {
451453
this.logger.info(`[Current Model]: ${chunk.model}`)
452454
isPrinted = true
453455
}

src/core/costrict/codebase-index/workspace-event-monitor.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export class WorkspaceEventMonitor {
147147
* Handle VSCode close event
148148
*/
149149
public handleVSCodeClose() {
150-
this.log.info("[WorkspaceEventMonitor] VSCode close event detected")
150+
this.log.debug("[WorkspaceEventMonitor] VSCode close event detected")
151151

152152
// Send workspace close events
153153
ZgsmCodebaseIndexManager.getInstance().client?.publishSyncWorkspaceEvents({
@@ -170,7 +170,7 @@ export class WorkspaceEventMonitor {
170170
* Destroy event monitor
171171
*/
172172
public async dispose() {
173-
this.log.info("[WorkspaceEventMonitor] Starting to destroy event monitor")
173+
this.log.debug("[WorkspaceEventMonitor] Starting to destroy event monitor")
174174
// Cancel timers
175175
if (this.flushTimer) {
176176
clearTimeout(this.flushTimer)
@@ -183,15 +183,15 @@ export class WorkspaceEventMonitor {
183183

184184
// Clean up document content cache
185185
this.documentContentCache.clear()
186-
this.log.info("[WorkspaceEventMonitor] Document content cache cleared")
186+
this.log.debug("[WorkspaceEventMonitor] Document content cache cleared")
187187

188188
// Send remaining events
189189
if (this.eventBuffer.size > 0) {
190190
await this.flushEventsSync()
191191
}
192192

193193
this.isInitialized = false
194-
this.log.info("[WorkspaceEventMonitor] Event monitor disposed")
194+
this.log.debug("[WorkspaceEventMonitor] Event monitor disposed")
195195
}
196196

197197
/**
@@ -420,7 +420,7 @@ export class WorkspaceEventMonitor {
420420
} else if (oldHash !== nowHash) {
421421
this.documentContentCache.set(filePath, { contentHash: nowHash })
422422
} else {
423-
this.log.info(`[WorkspaceEventMonitor] Document content unchanged, skipping event trigger`)
423+
this.log.debug(`[WorkspaceEventMonitor] Document content unchanged, skipping event trigger`)
424424
return
425425
}
426426

src/core/costrict/completion/CompletionClient.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export class CompletionClient {
7373

7474
throw new Error(OPENAI_CLIENT_NOT_INITIALIZED)
7575
}
76+
// console.time("Completion response timeout");
7677

7778
try {
7879
const response = await client.doCallApi(cp, scores, latestCompletion)
@@ -106,6 +107,7 @@ export class CompletionClient {
106107
if (client) {
107108
client.reqs.delete(cp.id)
108109
}
110+
// console.timeEnd("Completion response timeout");
109111
}
110112
}
111113

@@ -155,7 +157,8 @@ export class CompletionClient {
155157
...COSTRICT_DEFAULT_HEADERS,
156158
"X-Request-ID": uuidv7(),
157159
},
158-
timeout: 4500
160+
timeout: 5000,
161+
maxRetries: 0,
159162
})
160163

161164
if (!this.openai) {

src/utils/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class ChannelLogger implements ILogger {
8282
) {
8383
// Reuse externally injected OutputChannel; create one if not provided
8484
this.channel = opts.channel ?? vscode.window.createOutputChannel(name)
85-
this.level = opts.level ?? LogLevel.Debug
85+
this.level = opts.level ?? (process.env.NODE_ENV === "development" ? LogLevel.Debug : LogLevel.Info)
8686
this.enabled = opts.enabled ?? true
8787
this.timeFn = opts.timeFn ?? (() => new Date().toLocaleString())
8888
}

webview-ui/src/components/cloud/ZgsmAccountView.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import { telemetryClient } from "@src/utils/TelemetryClient"
1111
import { useEvent } from "react-use"
1212
import { ExtensionMessage } from "@roo/ExtensionMessage"
1313
import { useZgsmUserInfo } from "@src/hooks/useZgsmUserInfo"
14+
import { useCopyToClipboard } from "@src/utils/clipboard"
15+
import { ClipboardCopy } from "lucide-react"
16+
import { StandardTooltip } from "../ui"
1417

1518
type AccountViewProps = {
1619
apiConfiguration?: ProviderSettings
@@ -239,12 +242,12 @@ const QuotaInfoDisplay = memo(
239242

240243
const ZgsmAccountViewComponent = ({ apiConfiguration, onDone }: AccountViewProps) => {
241244
const { t } = useAppTranslation()
245+
const { copyWithFeedback } = useCopyToClipboard()
242246
const [quotaInfo, setQuotaInfo] = useState<QuotaInfo>()
243247
const [inviteCodeInfo, setInviteCodeInfo] = useState<InviteCodeInfo>()
244248
const [showQuotaInfo, setShowQuotaInfo] = useState(false)
245249
const [isLoadingQuota, setIsLoadingQuota] = useState(false)
246250
const { userInfo, logoPic, hash } = useZgsmUserInfo(apiConfiguration?.zgsmAccessToken)
247-
console.log("New Credit hash: ", hash)
248251

249252
// Cache static resource URI
250253
const coLogoUri = useMemo(() => (window as any).COSTRICT_BASE_URI + "/logo.svg", [])
@@ -392,7 +395,17 @@ const ZgsmAccountViewComponent = ({ apiConfiguration, onDone }: AccountViewProps
392395
<p className="text-xs text-vscode-descriptionForeground mb-1">{userInfo?.email}</p>
393396
)}
394397
{userInfo.id && (
395-
<h2 className="text-xs text-vscode-descriptionForeground mb-1">ID: {userInfo.id}</h2>
398+
<h2 className="text-xs text-vscode-descriptionForeground mb-1 flex items-center gap-1 whitespace-nowrap">
399+
ID: {userInfo.id}
400+
<StandardTooltip content={t("common:mermaid.buttons.copy")}>
401+
<ClipboardCopy
402+
onClick={(e) => {
403+
e.stopPropagation()
404+
copyWithFeedback(userInfo.id || "")
405+
}}
406+
aria-label="Copy message icon" className="cursor-pointer w-[14px] -translate-y-0.5" />
407+
</StandardTooltip>
408+
</h2>
396409
)}
397410
{/* Star status card */}
398411
{quotaInfo?.is_star != null && (

webview-ui/src/hooks/__tests__/useZgsmUserInfo.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe("useZgsmUserInfo", () => {
8686

8787
await waitFor(() => {
8888
expect(result.current.userInfo).toEqual({
89-
id: "user123",
89+
id: undefined,
9090
name: "testuser",
9191
picture: "https://example.com/avatar.png",
9292

webview-ui/src/hooks/useZgsmUserInfo.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,17 @@ export function useZgsmUserInfo(tokenOrConfig?: string | ProviderSettings): Zgsm
106106
try {
107107
const parsedJwt = parseJwt(token)
108108

109+
const id = parsedJwt.universal_id
109110
const userInfo: ZgsmUserInfo = {
110-
id: parsedJwt.universal_id || parsedJwt.id,
111-
name: parsedJwt?.properties?.oauth_GitHub_username || parsedJwt.id || parsedJwt.phone,
111+
id,
112+
name:
113+
parsedJwt?.properties?.oauth_GitHub_username ||
114+
fixEncoding(parsedJwt.displayName) ||
115+
parsedJwt.phone ||
116+
(id ? `user_${id}`.slice(0, 10) : id),
112117
picture: parsedJwt.avatar || parsedJwt?.properties?.oauth_GitHub_avatarUrl,
113118
email: parsedJwt.email || parsedJwt?.properties?.oauth_GitHub_email,
114-
phone: parsedJwt.phone,
119+
phone: parsedJwt.phone || parsedJwt.phone_number,
115120
organizationName: parsedJwt.organizationName,
116121
organizationImageUrl: parsedJwt.organizationImageUrl,
117122
}
@@ -152,3 +157,18 @@ export function useZgsmUserInfo(tokenOrConfig?: string | ProviderSettings): Zgsm
152157

153158
return data
154159
}
160+
161+
function fixEncoding(name?: string) {
162+
try {
163+
const misencodedPattern = /[\x80-\xFF]+/
164+
if (!name || !misencodedPattern.test(name)) {
165+
return name
166+
}
167+
168+
const bytes = Array.from(name, (c) => c.charCodeAt(0))
169+
return new TextDecoder("utf-8").decode(new Uint8Array(bytes))
170+
} catch (error) {
171+
console.error(error)
172+
return name
173+
}
174+
}

0 commit comments

Comments
 (0)