• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lucasliet / llm-telegram-bot / 17309262078

28 Aug 2025 10:19PM UTC coverage: 33.696% (+2.2%) from 31.514%
17309262078

push

github

lucasliet
refactor: services and improve code consistency

- Updated import statements for consistency across services.
- Refactored image generation URL construction in PollinationsService.
- Cleaned up formatting and spacing in TelegramService for better readability.
- Streamlined function definitions and error handling in ToolService.
- Enhanced GeminiService and GithubCopilotService for improved readability and consistency.
- Removed unnecessary comments and improved documentation in ChatConfigUtil.
- Added detailed instructions for applying patches and prompts in resources.

47 of 82 branches covered (57.32%)

Branch coverage included in aggregate %.

24 of 302 new or added lines in 17 files covered. (7.95%)

9 existing lines in 6 files now uncovered.

1160 of 3500 relevant lines covered (33.14%)

1.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.02
/src/service/openai/GithubCopilotService.ts
1
import OpenAi from 'npm:openai';
2✔
2
import OpenAiService from './OpenAIService.ts';
2✔
3
import { StreamReplyResponse } from '@/util/ChatConfigUtil.ts';
4

5
const COPILOT_TOKEN: string = Deno.env.get('COPILOT_TOKEN') as string;
2✔
6

7
interface CopilotTokenCache {
8
        token: string;
9
        expiresAt: number;
10
}
11

12
class TokenManager {
2✔
13
        private static instance: TokenManager;
2✔
14
        private cache: CopilotTokenCache | null = null;
×
15

16
        private constructor() {}
×
17

18
        static getInstance(): TokenManager {
×
19
                if (!TokenManager.instance) {
×
20
                        TokenManager.instance = new TokenManager();
×
21
                }
×
22
                return TokenManager.instance;
×
23
        }
×
24

25
        async getToken(githubToken: string): Promise<string> {
×
26
                if (this.isTokenValid()) {
×
27
                        console.log('Using cached Copilot token');
×
28
                        return this.cache!.token;
×
29
                }
×
30

31
                return await this.fetchNewToken(githubToken);
×
32
        }
×
33

34
        private isTokenValid(): boolean {
×
35
                if (this.cache === null) {
×
36
                        return false;
×
37
                }
×
38
                return Date.now() < this.cache.expiresAt;
×
39
        }
×
40

41
        private async fetchNewToken(githubToken: string): Promise<string> {
×
42
                console.log('Fetching new Copilot token');
×
43
                const response = await fetch('https://api.github.com/copilot_internal/v2/token', {
×
44
                        method: 'GET',
×
45
                        headers: this.buildAuthHeaders(githubToken),
×
46
                });
×
47

48
                if (!response.ok) {
×
49
                        this.cache = null;
×
50
                        throw new Error(`Failed to get Copilot token: ${response.status} ${response.statusText}`);
×
51
                }
×
52

53
                const data = await response.json();
×
54

55
                if (data.expires_at) {
×
56
                        const expiresAt = data.expires_at * 1000;
×
57
                        const now = Date.now();
×
58
                        const expiresInSeconds = Math.floor((expiresAt - now) / 1000);
×
59
                        console.log(`Token expires in ${expiresInSeconds} seconds`);
×
60
                        this.cache = {
×
61
                                token: data.token,
×
62
                                expiresAt: expiresAt,
×
63
                        };
×
64
                } else {
×
65
                        console.log('No expiration info, token will not be cached');
×
66
                        this.cache = null;
×
67
                }
×
68

69
                return data.token;
×
70
        }
×
71

72
        private buildAuthHeaders(githubToken: string): Record<string, string> {
×
73
                return {
×
74
                        'Authorization': `token ${githubToken}`,
×
75
                        'Editor-Version': 'vscode/1.95.0',
×
76
                        'User-Agent': 'GitHubCopilotChat/0.22.4',
×
77
                        'Accept': 'application/json',
×
78
                };
×
79
        }
×
80
}
2✔
81

82
export default class GithubCopilotService extends OpenAiService {
2✔
83
        public constructor(model: string = 'o4-mini') {
×
84
                super(
×
85
                        new OpenAi({
×
86
                                apiKey: COPILOT_TOKEN,
×
87
                                baseURL: 'https://api.githubcopilot.com',
×
88
                                defaultHeaders: {
×
89
                                        'Copilot-Vision-Request': 'true',
×
90
                                        'Editor-Version': 'vscode/1.95.0',
×
91
                                },
×
92
                        }),
×
93
                        model,
×
94
                );
95
        }
×
96

97
        private async ensureAuthenticated(): Promise<void> {
×
98
                try {
×
99
                        const tokenManager = TokenManager.getInstance();
×
100
                        const copilotToken = await tokenManager.getToken(COPILOT_TOKEN);
×
101
                        this.openai = new OpenAi({
×
102
                                apiKey: copilotToken,
×
103
                                baseURL: 'https://api.individual.githubcopilot.com',
×
104
                                defaultHeaders: {
×
105
                                        'Copilot-Vision-Request': 'true',
×
106
                                        'Editor-Version': 'vscode/1.95.0',
×
107
                                },
×
108
                        });
×
109
                } catch (error) {
×
110
                        console.warn('Failed to authenticate with GitHub Copilot, using fallback token:', error);
×
111
                        // Continue with the original token if authentication fails
×
112
                }
×
113
        }
×
114

115
        override async generateText(
×
116
                userKey: string,
×
117
                quote: string = '',
×
118
                prompt: string,
×
119
        ): Promise<StreamReplyResponse> {
×
120
                await this.ensureAuthenticated();
×
121
                return super.generateText(userKey, quote, prompt);
×
122
        }
×
123

124
        override async generateTextFromImage(
×
125
                userKey: string,
×
126
                quote: string | undefined,
×
127
                photosUrl: Promise<string>[],
×
NEW
128
                prompt: string,
×
129
        ): Promise<StreamReplyResponse> {
×
130
                await this.ensureAuthenticated();
×
131
                return super.generateTextFromImage(
×
132
                        userKey,
×
133
                        quote,
×
134
                        photosUrl,
×
135
                        prompt,
×
136
                        true,
×
137
                );
138
        }
×
139
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc