mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 06:30:10 +08:00
* feat: add tracing modules * Initial commit * fix: problem * fix: update trace web * fix: trace view * fix: trace view * fix: fix some problem * fix: knowledge and mcp trace * feat: save trace to user home dir * feat: open trace with electron browser window * fix: root trace outputs * feat: trace internationalization and add trace icon * feat: add trace title * feat: update * package.json添加windows运行script * feat: update window title * fix: mcp trace param * fix: error show * fix: listTool result * fix: merge error * feat: add stream usage and response * feat: change trace stream * fix: change stream adapter * fix: span detail show problem * fix: process show by time * fix: stream outputs * fix: merge problem * fix: stream outputs * fix: output text * fix: EDAS support text * fix: change trace footer style * fix: topicId is loaded multiple times * fix: span reload problem & attribute with cache * fix: refresh optimization * Change Powered by text. * resolve upstream conflicts * fix: build-time type exception * fix: exceptions not used when building * fix: recend no trace * fix: resend trace list * fix: delete temporary files * feat: trace for resend * fix: trace for resend message with edit * fix: directory structure and construction method of mcp-trace * fix: change CRLF to LF * fix: add function call outputs * Revert "fix: change CRLF to LF" * fix: reorganize multi-model display * fix: append model trace binding topic * fix: some problems * fix: code optimization * fix: delete async * fix: UI optimization * fix: sort import --------- Co-authored-by: 崔顺发 <csf01409784@alibaba-inc.com> Co-authored-by: 管鑫荣 <gxr01409783@alibaba-inc.com>
100 lines
3.5 KiB
TypeScript
100 lines
3.5 KiB
TypeScript
import { Context, context } from '@opentelemetry/api'
|
||
|
||
const originalPromise = globalThis.Promise
|
||
|
||
class TraceContextPromise<T> extends Promise<T> {
|
||
_context: Context
|
||
|
||
constructor(
|
||
executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void,
|
||
ctx?: Context
|
||
) {
|
||
const capturedContext = ctx || context.active()
|
||
super((resolve, reject) => {
|
||
context.with(capturedContext, () => {
|
||
executor(
|
||
(value) => context.with(capturedContext, () => resolve(value)),
|
||
(reason) => context.with(capturedContext, () => reject(reason))
|
||
)
|
||
})
|
||
})
|
||
this._context = capturedContext
|
||
}
|
||
|
||
// 兼容 Promise.resolve/reject
|
||
static resolve(): Promise<void>
|
||
static resolve<T>(value: T | PromiseLike<T>): Promise<T>
|
||
static resolve<T>(value: T | PromiseLike<T>, ctx?: Context): Promise<T>
|
||
static resolve<T>(value?: T | PromiseLike<T>, ctx?: Context): Promise<T | void> {
|
||
return new TraceContextPromise<T | void>((resolve) => resolve(value as T), ctx)
|
||
}
|
||
|
||
static reject<T = never>(reason?: any): Promise<T>
|
||
static reject<T = never>(reason?: any, ctx?: Context): Promise<T> {
|
||
return new TraceContextPromise<T>((_, reject) => reject(reason), ctx)
|
||
}
|
||
|
||
static all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]> {
|
||
// 尝试从缓存获取 context
|
||
let capturedContext = context.active()
|
||
const newValues = values.map((v) => {
|
||
if (v instanceof Promise && !(v instanceof TraceContextPromise)) {
|
||
return new TraceContextPromise((resolve, reject) => v.then(resolve, reject), capturedContext)
|
||
} else if (typeof v === 'function') {
|
||
// 如果 v 是一个 Function,使用 context 传递 trace 上下文
|
||
return (...args: any[]) => context.with(capturedContext, () => v(...args))
|
||
} else {
|
||
return v
|
||
}
|
||
})
|
||
if (Array.isArray(values) && values.length > 0 && values[0] instanceof TraceContextPromise) {
|
||
capturedContext = (values[0] as TraceContextPromise<any>)._context
|
||
}
|
||
return originalPromise.all(newValues) as Promise<T[]>
|
||
}
|
||
|
||
static race<T>(values: (T | PromiseLike<T>)[]): Promise<T> {
|
||
const capturedContext = context.active()
|
||
return new TraceContextPromise<T>((resolve, reject) => {
|
||
originalPromise.race(values).then(
|
||
(result) => context.with(capturedContext, () => resolve(result)),
|
||
(err) => context.with(capturedContext, () => reject(err))
|
||
)
|
||
}, capturedContext)
|
||
}
|
||
|
||
static allSettled<T>(values: (T | PromiseLike<T>)[]): Promise<PromiseSettledResult<T>[]> {
|
||
const capturedContext = context.active()
|
||
return new TraceContextPromise<PromiseSettledResult<T>[]>((resolve, reject) => {
|
||
originalPromise.allSettled(values).then(
|
||
(result) => context.with(capturedContext, () => resolve(result)),
|
||
(err) => context.with(capturedContext, () => reject(err))
|
||
)
|
||
}, capturedContext)
|
||
}
|
||
|
||
static any<T>(values: (T | PromiseLike<T>)[]): Promise<T> {
|
||
const capturedContext = context.active()
|
||
return new TraceContextPromise<T>((resolve, reject) => {
|
||
originalPromise.any(values).then(
|
||
(result) => context.with(capturedContext, () => resolve(result)),
|
||
(err) => context.with(capturedContext, () => reject(err))
|
||
)
|
||
}, capturedContext)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 用 TraceContextPromise 替换全局 Promise
|
||
*/
|
||
export function instrumentPromises() {
|
||
globalThis.Promise = TraceContextPromise as unknown as PromiseConstructor
|
||
}
|
||
|
||
/**
|
||
* 恢复原生 Promise
|
||
*/
|
||
export function uninstrumentPromises() {
|
||
globalThis.Promise = originalPromise
|
||
}
|