copilot-api-node20 0.14.0 → 0.15.0

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.
Files changed (3) hide show
  1. package/README.md +114 -192
  2. package/dist/main.js +10 -8
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -1,282 +1,204 @@
1
- # 🚀 Copilot API Proxy (Node 20+ Compatible)
2
-
3
- > **Transform GitHub Copilot into OpenAI/Anthropic API** • **Claude Code Ready** • **One Command Setup**
1
+ # copilot-api
4
2
 
5
3
  [![npm version](https://img.shields.io/npm/v/copilot-api-node20)](https://www.npmjs.com/package/copilot-api-node20)
6
4
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
5
  [![GitHub stars](https://img.shields.io/github/stars/johnib/copilot-api)](https://github.com/johnib/copilot-api)
8
6
 
9
- Turn your existing **GitHub Copilot subscription** into a powerful OpenAI/Anthropic-compatible API server. Perfect for powering [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview), custom tools, and any application expecting OpenAI or Anthropic APIs.
10
-
11
- ## ✨ Why This Proxy?
12
-
13
- - **🎯 One Command Launch**: Get Claude Code running with Copilot in seconds
14
- - **💰 Use What You Pay For**: Leverage your existing Copilot subscription
15
- - **🔄 Dual API Support**: Both OpenAI (`/v1/chat/completions`) and Anthropic (`/v1/messages`) endpoints
16
- - **📊 Usage Dashboard**: Beautiful web interface to monitor your API usage
17
- - **⚡ Node 20+ Ready**: Optimized fork with modern Node.js compatibility
18
- - **🛡️ Rate Limiting**: Built-in controls to respect GitHub's limits
19
-
20
- ---
21
-
22
- ## 🎮 Quick Start with Claude Code
7
+ **Turn a GitHub Copilot subscription into OpenAI and Anthropic compatible API endpoints.**
23
8
 
24
- The fastest way to get Claude Code working with your Copilot subscription:
9
+ One command. No separate API key. Run Claude Code through the Copilot plan you already pay for.
25
10
 
26
11
  ```bash
27
- # 1. Launch the proxy with Claude Code integration
28
12
  npx copilot-api-node20@latest start --claude-code
29
-
30
- # 2. Follow the interactive setup (select your models)
31
- # 3. Copy the generated command and run it in a new terminal
32
- # 4. Start coding with Claude Code powered by your Copilot subscription! 🎉
33
13
  ```
34
14
 
35
- That's it! Claude Code will now use your GitHub Copilot subscription instead of requiring separate API keys.
36
-
37
15
  ---
38
16
 
39
- ## 📋 Prerequisites
17
+ ## The story
40
18
 
41
- - **Node.js 20+** (this fork is optimized for modern Node versions)
42
- - **GitHub account** with active Copilot subscription (Individual, Business, or Enterprise)
43
- - **No additional API keys needed!** Uses your existing Copilot access
19
+ This project started as a clever piece of engineering by [Erick Christian](https://github.com/ericc-ch/copilot-api): reverse-engineer the GitHub Copilot API and re-expose it through standard OpenAI and Anthropic interfaces. It worked. You could point Claude Code at it and skip the Anthropic billing page entirely.
44
20
 
45
- ---
21
+ Then I started using it for real work. Eight hours a day, every day, running Claude Code through it for serious development sessions. **That is when things started breaking.**
46
22
 
47
- ## 🚀 Installation & Usage
23
+ Not all at once. The failures were subtle. A streaming response would die mid-paragraph with no error. A request would come back as a `400 Bad Request` for no apparent reason. The proxy would lose authentication after a laptop sleep cycle and silently serve stale tokens. GitHub would start rate-limiting aggressively, returning `429` after just a handful of requests.
48
24
 
49
- ### Option 1: NPX (Recommended)
25
+ Each of these bugs cost me hours of debugging. Each one had a specific root cause. And each one is now fixed in this fork.
50
26
 
51
- ```bash
52
- # Quick start - launches server and opens usage dashboard
53
- npx copilot-api-node20@latest start
27
+ > **This is a hardened fork of [ericc-ch/copilot-api](https://github.com/ericc-ch/copilot-api), battle-tested under sustained, high-scale daily usage with Claude Code.** Every fix below came from a real production incident. Nothing is theoretical.
54
28
 
55
- # With Claude Code integration
56
- npx copilot-api-node20@latest start --claude-code
29
+ ---
57
30
 
58
- # Custom port and verbose logging
59
- npx copilot-api-node20@latest start --port 8080 --verbose
60
- ```
31
+ ## What we fixed
61
32
 
62
- ### Option 2: Global Install
33
+ **Streaming responses dying mid-completion.**
34
+ The `undici` HTTP client ships with a body timeout that is far too aggressive for long AI completions. When a model takes its time generating a complex response, the connection would silently drop. We now set the body timeout to a multiple of the configured request timeout, giving the model room to think.
63
35
 
64
- ```bash
65
- npm install -g copilot-api-node20
66
- copilot-api start --claude-code
67
- ```
36
+ **Random 400 Bad Request from GitHub.**
37
+ Payloads forwarded to the Copilot API sometimes contained ANSI escape sequences, invisible Unicode characters, and other malformed content that GitHub's backend rejects. The proxy now sanitizes every JSON payload before forwarding, stripping anything that does not belong.
68
38
 
69
- ### Option 3: Docker
39
+ **Token expiry after laptop sleep or network change.**
40
+ The original proxy had no awareness of network state. After a laptop lid close, a VPN reconnect, or a Wi-Fi switch, the next request would fail with a stale Copilot token. A background connectivity monitor now detects network restoration and triggers an immediate token refresh so the very next request succeeds.
70
41
 
71
- ```bash
72
- # Build and run
73
- docker build -t copilot-api .
74
- docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/copilot-api copilot-api
42
+ **Aggressive 429 rate limiting from GitHub.**
43
+ GitHub's rate limiter treats different clients differently. Requests that do not look like they come from a real VS Code session get throttled much faster. The proxy now matches VS Code Insiders headers -- machine ID, session ID, editor version, plugin version -- so GitHub treats it as a legitimate client.
75
44
 
76
- # With environment variables
77
- docker run -p 4141:4141 -e GH_TOKEN=your_token copilot-api
78
- ```
45
+ **Billing metadata leaking into system prompts.**
46
+ Claude Code injects an `x-anthropic-billing-header` into its requests. When this metadata leaked into the system prompt content forwarded to Copilot, the model would hallucinate on it or the request would be rejected entirely. It is now filtered before forwarding.
79
47
 
80
- ---
48
+ **Stale API headers causing silent rejections.**
49
+ GitHub's backend expects specific API version strings and header shapes that change over time. When the proxy's headers drifted out of sync, requests would fail silently. Headers are now kept current with what GitHub's Copilot Chat protocol expects.
81
50
 
82
- ## 🎯 Core Features
51
+ **Auth scopes too narrow.**
52
+ The original OAuth client ID and scopes were insufficient for some operations. Updated to the correct GitHub client ID and broader OAuth scopes.
83
53
 
84
- ### 🤖 Claude Code Integration
54
+ **Slow requests timing out prematurely.**
55
+ Large-context completions -- especially with Claude's 1M context window variants -- can take minutes. The default timeout is now 10 minutes and is configurable via `--timeout`.
85
56
 
86
- - **One-command setup** with `--claude-code` flag
87
- - **Interactive model selection** or specify models directly
88
- - **Automatic configuration** - no manual JSON editing needed
89
- - **Works out of the box** with all Claude Code features
57
+ ---
90
58
 
91
- ### 🔄 Dual API Compatibility
59
+ ## Features
92
60
 
93
- | OpenAI Format | Anthropic Format | Description |
94
- |---------------|------------------|-------------|
95
- | `POST /v1/chat/completions` | `POST /v1/messages` | Chat completions |
96
- | `GET /v1/models` | - | Available models |
97
- | `POST /v1/embeddings` | - | Text embeddings |
98
- | - | `POST /v1/messages/count_tokens` | Token counting |
61
+ > **Web search via Tavily** -- Claude Code's `web_search` tool calls are intercepted and routed through the [Tavily API](https://tavily.com). Copilot does not support this tool type natively, so without this integration, web search calls fail silently. Set `TAVILY_API_KEY` as an environment variable to enable. The proxy degrades gracefully when the key is absent.
99
62
 
100
- ### 📊 Usage Monitoring
63
+ **Smart model name normalization.**
64
+ Claude Code sends model names in various formats: `claude-3-5-sonnet-20241022`, `claude-sonnet-4.5`, `claude-opus-4-6[1m]`. The proxy normalizes all variations to the correct Copilot model ID via regex pattern matching. Bracket suffixes for context window variants are handled automatically.
101
65
 
102
- - **Web Dashboard**: Beautiful interface at `/usage` endpoint
103
- - **Real-time Stats**: Monitor quotas, requests, and usage patterns
104
- - **Terminal Usage**: Quick check with `copilot-api check-usage`
66
+ **Claude 4.6 and 1M context support.**
67
+ Latest model mappings are included, covering `claude-opus-4.6`, `claude-sonnet-4.6`, `claude-sonnet-4.5`, `claude-sonnet-4`, `claude-haiku-4.5`, and their `-1m` / `-fast` suffix variants.
105
68
 
106
- ### 🛡️ Smart Rate Limiting
69
+ **Model validation.**
70
+ Invalid model names are rejected early with a clear error message. No more forwarding garbage to GitHub and getting a cryptic 400 back.
107
71
 
108
- ```bash
109
- # Manual approval for each request
110
- copilot-api start --manual
72
+ **Token usage logging.**
73
+ Every completion logs input and output token counts in a compact format -- `^ 12.4k v 1.2k` -- alongside the context window utilization percentage. You always know how much of the model's capacity each request consumes.
111
74
 
112
- # 30-second minimum between requests
113
- copilot-api start --rate-limit 30
75
+ **Startup model listing.**
76
+ Available models and their context windows are printed on boot so you can verify what your Copilot plan provides before sending a single request.
114
77
 
115
- # Wait instead of erroring on rate limits
116
- copilot-api start --rate-limit 30 --wait
117
- ```
78
+ **Clean API responses.**
79
+ Internal caching metadata from Copilot responses is stripped before returning to the client. Your tooling sees only clean, standard API responses.
118
80
 
119
81
  ---
120
82
 
121
- ## 💡 Advanced Usage Examples
83
+ ## Quick start
122
84
 
123
- ### Claude Code with Specific Models
85
+ **Prerequisites:** Node.js 20+, a GitHub account with an active Copilot subscription.
124
86
 
125
87
  ```bash
126
- # Skip interactive setup - specify models directly
127
- npx copilot-api-node20@latest start \
128
- --claude-code \
129
- --model "claude-sonnet-4" \
130
- --small-model "claude-sonnet-4"
88
+ npx copilot-api-node20@latest start --claude-code
131
89
  ```
132
90
 
133
- ### Enterprise/Business Accounts
91
+ On first run, the proxy walks you through GitHub device-code OAuth. After authentication, it prints a shell command (copied to your clipboard) that configures Claude Code to route through the proxy.
134
92
 
135
- ```bash
136
- # For GitHub Business/Enterprise Copilot
137
- npx copilot-api-node20@latest start --account-type business
138
- npx copilot-api-node20@latest start --account-type enterprise
139
- ```
140
-
141
- ### Production Deployment
93
+ To skip the interactive model picker:
142
94
 
143
95
  ```bash
144
- # With comprehensive settings
145
96
  npx copilot-api-node20@latest start \
146
- --port 8080 \
147
- --rate-limit 10 \
148
- --wait \
149
- --timeout 180000 \
150
- --account-type business
97
+ --claude-code \
98
+ --model claude-sonnet-4 \
99
+ --small-model claude-haiku-4.5
151
100
  ```
152
101
 
153
- ### CI/CD Integration
102
+ ---
154
103
 
155
- ```bash
156
- # Authenticate separately for token reuse
157
- npx copilot-api-node20@latest auth --show-token
104
+ ## API endpoints
158
105
 
159
- # Use token in production
160
- npx copilot-api-node20@latest start --github-token $GITHUB_TOKEN
161
- ```
106
+ | Method | Path | Compatibility |
107
+ |---|---|---|
108
+ | `POST` | `/v1/chat/completions` | OpenAI (streaming + non-streaming) |
109
+ | `POST` | `/v1/messages` | Anthropic (streaming + non-streaming) |
110
+ | `GET` | `/v1/models` | OpenAI |
111
+ | `POST` | `/v1/embeddings` | OpenAI |
112
+ | `POST` | `/v1/messages/count_tokens` | Anthropic (stub) |
113
+ | `GET` | `/usage` | Web dashboard |
114
+
115
+ OpenAI-compatible routes (`/chat/completions`, `/models`, `/embeddings`) are also available without the `/v1/` prefix.
162
116
 
163
117
  ---
164
118
 
165
- ## 🔧 Command Reference
119
+ ## Commands
166
120
 
167
- ### Main Commands
121
+ ```
122
+ copilot-api start Start the proxy server
123
+ copilot-api auth Authenticate with GitHub (device code flow)
124
+ copilot-api check-usage Display current Copilot usage quota
125
+ copilot-api debug Print diagnostic information
126
+ ```
168
127
 
169
- | Command | Description |
170
- |---------|-------------|
171
- | `start` | Launch the API proxy server |
172
- | `auth` | Run GitHub authentication only |
173
- | `check-usage` | Show usage stats in terminal |
174
- | `debug` | Display diagnostic information |
128
+ ### start options
175
129
 
176
- ### Key Options
130
+ | Flag | Alias | Default | Description |
131
+ |---|---|---|---|
132
+ | `--port` | `-p` | `4141` | Port to listen on |
133
+ | `--claude-code` | `-c` | `false` | Generate and copy Claude Code launch command |
134
+ | `--model` | `-m` | -- | Model for Claude Code (requires `--claude-code`) |
135
+ | `--small-model` | `-s` | -- | Small/fast model for Claude Code (requires `--claude-code`) |
136
+ | `--rate-limit` | `-r` | -- | Minimum seconds between requests |
137
+ | `--wait` | `-w` | `false` | Queue requests instead of rejecting when rate-limited |
138
+ | `--manual` | | `false` | Require manual approval for each request |
139
+ | `--timeout` | `-t` | `600000` | API timeout in milliseconds (default: 10 minutes) |
140
+ | `--account-type` | `-a` | `individual` | `individual`, `business`, or `enterprise` |
141
+ | `--github-token` | `-g` | -- | Provide a GitHub token directly (from the `auth` command) |
142
+ | `--verbose` | `-v` | `false` | Enable debug-level logging |
177
143
 
178
- | Flag | Description | Example |
179
- |------|-------------|---------|
180
- | `--claude-code` | Generate Claude Code launch command | `start --claude-code` |
181
- | `--model` | Primary model for Claude Code | `--model "claude-sonnet-4"` |
182
- | `--small-model` | Fast model for background tasks | `--small-model "claude-sonnet-4"` |
183
- | `--rate-limit` | Seconds between requests | `--rate-limit 30` |
184
- | `--manual` | Manual request approval | `--manual` |
185
- | `--account-type` | GitHub plan type | `--account-type business` |
144
+ When both `--model` and `--small-model` are provided, model selection is non-interactive.
186
145
 
187
146
  ---
188
147
 
189
- ## 🌐 API Endpoints
190
-
191
- Once running (default: `http://localhost:4141`):
192
-
193
- ### OpenAI Compatible
148
+ ## Docker
194
149
 
195
150
  ```bash
196
- curl -X POST http://localhost:4141/v1/chat/completions \
197
- -H "Content-Type: application/json" \
198
- -d '{
199
- "model": "claude-sonnet-4",
200
- "messages": [{"role": "user", "content": "Hello!"}]
201
- }'
151
+ docker build -t copilot-api .
152
+
153
+ docker run -p 4141:4141 \
154
+ -v $(pwd)/copilot-data:/root/.local/share/copilot-api \
155
+ copilot-api
202
156
  ```
203
157
 
204
- ### Anthropic Compatible
158
+ To inject a pre-authenticated token at build time:
205
159
 
206
160
  ```bash
207
- curl -X POST http://localhost:4141/v1/messages \
208
- -H "Content-Type: application/json" \
209
- -d '{
210
- "model": "claude-3-5-sonnet-20241022",
211
- "max_tokens": 1024,
212
- "messages": [{"role": "user", "content": "Hello!"}]
213
- }'
161
+ docker build --build-arg GH_TOKEN=your_token -t copilot-api .
162
+ docker run -p 4141:4141 copilot-api
214
163
  ```
215
164
 
216
- ### Usage Dashboard
217
-
218
- Open `http://localhost:4141/usage` in your browser for a beautiful usage monitoring interface.
165
+ The image includes a health check at `http://localhost:4141/`.
219
166
 
220
167
  ---
221
168
 
222
- ## ⚠️ Important Notices
169
+ ## Authentication flow
223
170
 
224
- > **Reverse-Engineered Proxy**: This tool reverse-engineers GitHub Copilot's API. It's not officially supported by GitHub and may break unexpectedly.
171
+ 1. Run `copilot-api auth` or `copilot-api start` for the first time.
172
+ 2. The proxy displays a device code and opens GitHub in your browser.
173
+ 3. Enter the code on GitHub to authorize.
174
+ 4. The proxy exchanges the device code for an access token.
175
+ 5. The access token is used to obtain a Copilot session token.
176
+ 6. Tokens are persisted to disk and refreshed automatically.
225
177
 
226
- > **Rate Limiting**: Excessive automated use may trigger GitHub's abuse detection. Use responsibly with appropriate rate limiting.
227
-
228
- > **Terms of Service**: Review [GitHub's Acceptable Use Policies](https://docs.github.com/site-policy/acceptable-use-policies/github-acceptable-use-policies) and [Copilot Terms](https://docs.github.com/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot) before use.
178
+ A connectivity monitor runs in the background. When it detects network restoration -- after laptop sleep, VPN reconnect, or Wi-Fi switch -- it triggers an immediate token refresh so the next request does not fail with a stale token.
229
179
 
230
180
  ---
231
181
 
232
- ## 🙏 Attribution & License
233
-
234
- This is a **Node 20+ compatible fork** of the original project by **[Erick Christian](https://github.com/ericc-ch)**.
235
-
236
- **Original Repository**: <https://github.com/ericc-ch/copilot-api>
237
- **Original Package**: `copilot-api` on npm
182
+ ## Notices
238
183
 
239
- **Full credit goes to Erick Christian** for creating this amazing project. This fork exists solely to maintain Node 20+ compatibility and will be discontinued once the original package supports modern Node versions.
184
+ This project relies on reverse-engineered, undocumented GitHub APIs. It is **not officially supported by GitHub** and may break at any time without notice.
240
185
 
241
- ### License
242
-
243
- MIT License - see [LICENSE](LICENSE) file for details.
244
-
245
- ### Support the Original Author
246
-
247
- If this project helps you, consider supporting the original creator:
248
- [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E519XS7W)
186
+ - Use the `--rate-limit` flag to throttle requests and reduce the risk of abuse detection.
187
+ - Review the [GitHub Acceptable Use Policies](https://docs.github.com/en/site-policy/acceptable-use-policies/github-acceptable-use-policies) and [GitHub Copilot Terms](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot) before use.
188
+ - This software is provided as-is with no warranty.
249
189
 
250
190
  ---
251
191
 
252
- ## 🐛 Troubleshooting
253
-
254
- ### Common Issues
255
-
256
- - **Authentication Failed**: Run `copilot-api auth --verbose` to debug
257
- - **Rate Limited**: Use `--rate-limit` and `--wait` flags
258
- - **Node Version**: Ensure Node.js 20+ is installed
259
- - **Port Conflicts**: Change port with `--port 8080`
260
-
261
- ### Debug Information
192
+ ## Attribution
262
193
 
263
- ```bash
264
- # Get detailed diagnostic info
265
- npx copilot-api-node20@latest debug --json
266
- ```
194
+ Original project by **Erick Christian** -- [ericc-ch/copilot-api](https://github.com/ericc-ch/copilot-api).
267
195
 
268
- ### Need Help?
196
+ Erick built the foundation that makes all of this possible: the authentication flow, the API translation layer, the streaming implementation. This fork exists because his work was good enough to use in production -- and production is where the edge cases live.
269
197
 
270
- - Check the [original repository](https://github.com/ericc-ch/copilot-api) for issues and discussions
271
- - Review [Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/overview) for integration help
272
-
273
- ---
198
+ If you find this useful, consider supporting the original author:
274
199
 
275
- <div align="center">
276
-
277
- **Made with ❤️ by the community • Original work by [Erick Christian](https://github.com/ericc-ch)**
278
-
279
- [⭐ Star this repo](https://github.com/johnib/copilot-api) • [🐛 Report issues](https://github.com/johnib/copilot-api/issues) • [📖 Original repo](https://github.com/ericc-ch/copilot-api)
200
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E519XS7W)
280
201
 
281
- </div>
202
+ ## License
282
203
 
204
+ [MIT](LICENSE) -- Copyright (c) 2025 Erick Christian Purwanto
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{_c1 as e,DEFAULT_TIMEOUT_MS as t,_g1 as n,_g4 as r,_g2 as i,_g3 as a,HTTPError as o,PATHS as s,SENSITIVE_HEADERS as c,SeverityNumber as l,approvalCounter as u,approvalWaitHistogram as d,cachedTokensCounter as f,chunksPerRequestHistogram as p,connectivityMonitor as m,_s1 as h,copilotDurationHistogram as g,_s2 as _,emitLog as v,ensurePaths as y,errorsCounter as ee,flattenAttributes as b,_c2 as x,_s4 as te,_s3 as ne,initOtel as re,_s5 as ie,inputTokensCounter as ae,inputTokensPerRequestHistogram as oe,modelMappingCounter as se,modelValidationErrorCounter as ce,outputTokensCounter as le,outputTokensPerRequestHistogram as ue,rateLimitCounter as de,rateLimitWaitHistogram as fe,requestDurationHistogram as pe,requestsCounter as me,shutdownOtel as he,_c3 as ge,state as S,streamChunksCounter as _e,streamDurationHistogram as C,tokenRefreshAttemptCounter as ve,tokenRefreshDurationHistogram as ye,tokenRefreshFailureCounter as be,tracedFetch as w,tracedUndiciRequest as xe,tracer as T,translationDurationHistogram as Se}from"./get-user-DX7ymfsj.js";import{defineCommand as E,runMain as Ce}from"citty";import D from"consola";import O from"node:fs/promises";import we from"node:os";import{SpanKind as k,SpanStatusCode as A,context as Te,trace as Ee}from"@opentelemetry/api";import De from"clipboardy";import j from"node:process";import{serve as Oe}from"srvx";import ke from"tiny-invariant";import{execSync as Ae}from"node:child_process";import{Hono as M}from"hono";import{cors as je}from"hono/cors";import{streamSSE as N}from"hono/streaming";import{events as Me}from"fetch-event-stream";const Ne=async()=>{let e=`${n}/\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/v2/token`,t=S.timeoutMs,r=new AbortController,i=setTimeout(()=>r.abort(),t);try{let{response:t,span:n}=await w({spanName:`\u0067\u0069\u0074\u0068\u0075\u0062 GET /\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/v2/token`,url:e,target:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_token`,headers:ne(S),signal:r.signal});if(!t.ok)throw n.end(),new o(`Failed to get Service token`,t);let i=await t.json();return n.end(),i}finally{clearTimeout(i)}};async function Pe(){let e=new AbortController,t=S.timeoutMs,n=setTimeout(()=>{e.abort()},t);try{let t=await fetch(`${i}/login/device/code`,{method:`POST`,headers:ge(),body:JSON.stringify({client_id:a,scope:r}),signal:e.signal});if(!t.ok)throw new o(`Failed to get device code`,t);return await t.json()}finally{clearTimeout(n)}}const Fe=async()=>{let e=`${h(S)}/models`,t=_(S),n=S.timeoutMs,r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let{response:n,span:i}=await w({spanName:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074 GET /models`,url:e,target:`models`,headers:t,signal:r.signal});if(!n.ok)throw i.end(),new o(`Failed to get models`,n);let a=await n.json();return i.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.models_count`,a.data.length),i.end(),a}finally{clearTimeout(i)}};function Ie(){return`1.111.0-insider`}Ie();const P=e=>new Promise(t=>{setTimeout(t,e)}),Le=e=>e==null;async function Re(){let e=await Fe();S.models=e}const ze=()=>{let e=Ie();S.vsCodeVersion=e,D.info(`Using client version: ${e}`)};async function Be(e){let t=(e.interval+1)*1e3;for(D.debug(`Polling access token with interval of ${t}ms`);;){let n=new AbortController,r=S.timeoutMs,o=setTimeout(()=>{n.abort()},r);try{let r=await fetch(`${i}/login/oauth/access_token`,{method:`POST`,headers:ge(),body:JSON.stringify({client_id:a,device_code:e.device_code,grant_type:`urn:ietf:params:oauth:grant-type:device_code`}),signal:n.signal});if(!r.ok){await P(t),D.error(`Failed to poll access token:`,await r.text());continue}let o=await r.json();D.debug(`Polling access token response:`,o);let{access_token:s}=o;if(s)return s;await P(t)}catch(e){if(e instanceof Error&&e.name===`AbortError`){D.error(`Access token polling timed out`),await P(t);continue}throw e}finally{clearTimeout(o)}}}let F,I=!1,L,R;function Ve(){D.debug(`Cleaning up token management`),F&&=(clearInterval(F),void 0),L&&=(m.off(`online`,L),void 0),R&&=(m.off(`offline`,R),void 0)}const He=()=>O.readFile(s.GITHUB_TOKEN_PATH,`utf8`),Ue=e=>O.writeFile(s.GITHUB_TOKEN_PATH,e),We=async()=>{let{token:e,refresh_in:t}=await Ne();S.copilotToken=e,D.debug(`Service token fetched successfully!`),S.showToken&&D.info(`Service token:`,e);let n=(t-60)*1e3,r=async(e=5,t=1e3,n=`scheduled`)=>{if(I){D.debug(`Refresh already in progress, skipping`);return}return I=!0,T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token.refresh`,async r=>{let i=performance.now();r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.reason`,n),r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.max_retries`,e);try{for(let a=1;a<=e;a++)try{r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.attempt`,a),D.debug(`Refreshing Service token (${n}, attempt ${a}/${e})`);let{token:t}=await Ne();S.copilotToken=t,D.debug(`Service token refreshed successfully`),S.showToken&&D.info(`Refreshed Service token:`,t),r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.success`,!0),ve.add(1,{reason:n,success:`true`}),ye.record(performance.now()-i,{reason:n}),v(l.INFO,`INFO`,`Token refreshed successfully (${n})`,{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.reason":n,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.attempt":a});return}catch(o){let s=a===e;if(D.error(`Failed to refresh Service token (attempt ${a}/${e}):`,o),ve.add(1,{reason:n,success:`false`}),s){D.error(`All refresh attempts failed. May be unavailable until next scheduled refresh.`);let t=o instanceof Error?o:Error(String(o));r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.success`,!1),r.setStatus({code:A.ERROR,message:t.message}),r.recordException(t),be.add(1,{reason:n}),ye.record(performance.now()-i,{reason:n}),v(l.ERROR,`ERROR`,`Token refresh failed after ${e} attempts (${n})`,{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.reason":n,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.attempts":e});return}let c=t*2**(a-1);D.debug(`Retrying token refresh in ${c}ms...`),await new Promise(e=>setTimeout(e,c))}}finally{r.end(),I=!1}})};F=setInterval(()=>{r(5,1e3,`scheduled`).catch(e=>{D.error(`Unexpected error in scheduled token refresh:`,e)})},n),m.start(),L=()=>{D.debug(`Network connectivity restored, attempting immediate token refresh`),r(3,500,`network-restored`).catch(e=>{D.error(`Unexpected error in network-restored token refresh:`,e)})},R=()=>{D.debug(`Network connectivity lost`)},m.on(`online`,L),m.on(`offline`,R)};async function z(e){try{let t=await He();if(t&&!e?.force){S.githubToken=t,S.showToken&&D.info(`Auth token:`,t),await B();return}D.info(`Authentication required`);let n=await Pe();D.debug(`Device code response:`,n),D.info(`Please enter the code "${n.user_code}" in ${n.verification_uri}`);let r=await Be(n);await Ue(r),S.githubToken=r,S.showToken&&D.info(`Auth token:`,r),await B()}catch(e){throw e instanceof o?(D.error(`Failed to get Auth token:`,await e.response.json()),e):(D.error(`Failed to get Auth token:`,e),e)}}async function B(){let e=await te();D.info(`Authenticated as ${e.login}`)}async function Ge(e){e.verbose&&(D.level=5,D.info(`Verbose logging enabled`)),S.showToken=e.showToken,await y(),await z({force:!0}),D.success(`Auth token written to`,s.GITHUB_TOKEN_PATH)}const Ke=E({meta:{name:`auth`,description:`Run authentication flow`},args:{verbose:{alias:`v`,type:`boolean`,default:!1,description:`Enable verbose logging`},"show-token":{type:`boolean`,default:!1,description:`Show token on auth`}},run({args:e}){return Ge({verbose:e.verbose,showToken:e[`show-token`]})}}),V=async()=>{let e=`${n}/\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/user`,t=S.timeoutMs,r=new AbortController,i=setTimeout(()=>r.abort(),t);try{let{response:t,span:n}=await w({spanName:`\u0067\u0069\u0074\u0068\u0075\u0062 GET /\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/user`,url:e,target:`usage`,headers:ne(S),signal:r.signal});if(!t.ok)throw n.end(),new o(`Failed to get usage`,t);let i=await t.json();return n.end(),i}finally{clearTimeout(i)}},qe=E({meta:{name:`check-usage`,description:`Show current usage/quota information`},async run(){await y(),await z();try{let e=await V(),t=e.quota_snapshots.premium_interactions,n=t.entitlement,r=n-t.remaining,i=n>0?r/n*100:0,a=t.percent_remaining;function o(e,t){if(!t)return`${e}: N/A`;let n=t.entitlement,r=n-t.remaining,i=n>0?r/n*100:0,a=t.percent_remaining;return`${e}: ${r}/${n} used (${i.toFixed(1)}% used, ${a.toFixed(1)}% remaining)`}let s=`Premium: ${r}/${n} used (${i.toFixed(1)}% used, ${a.toFixed(1)}% remaining)`,c=o(`Chat`,e.quota_snapshots.chat),l=o(`Completions`,e.quota_snapshots.completions);D.box(`Usage (plan: ${e.\u0063\u006f\u0070\u0069\u006c\u006f\u0074_plan})\nQuota resets: ${e.quota_reset_date}\n\nQuotas:\n ${s}\n ${c}\n ${l}`)}catch(e){D.error(`Failed to fetch usage:`,e),process.exit(1)}}});async function Je(){try{let e=new URL(`../package.json`,import.meta.url).pathname,t=await O.readFile(e),n=JSON.parse(t.toString());return n.version}catch{return`unknown`}}function Ye(){let e=typeof Bun<`u`;return{name:e?`bun`:`node`,version:e?Bun.version:process.version.slice(1),platform:we.platform(),arch:we.arch()}}async function Xe(){try{let e=await O.stat(s.GITHUB_TOKEN_PATH);if(!e.isFile())return!1;let t=await O.readFile(s.GITHUB_TOKEN_PATH,`utf8`);return t.trim().length>0}catch{return!1}}async function Ze(){let[e,t]=await Promise.all([Je(),Xe()]);return{version:e,runtime:Ye(),paths:{APP_DIR:s.APP_DIR,GITHUB_TOKEN_PATH:s.GITHUB_TOKEN_PATH},tokenExists:t}}function Qe(e){D.info(`service debug
2
+ import{_c1 as e,DEFAULT_TIMEOUT_MS as t,_g1 as n,_g4 as r,_g2 as i,_g3 as a,HTTPError as o,PATHS as s,SENSITIVE_HEADERS as c,SeverityNumber as l,approvalCounter as u,approvalWaitHistogram as d,cachedTokensCounter as f,chunksPerRequestHistogram as p,connectivityMonitor as m,_s1 as h,copilotDurationHistogram as g,_s2 as _,emitLog as v,ensurePaths as y,errorsCounter as ee,flattenAttributes as b,_c2 as x,_s4 as te,_s3 as ne,initOtel as re,_s5 as ie,inputTokensCounter as ae,inputTokensPerRequestHistogram as oe,modelMappingCounter as se,modelValidationErrorCounter as ce,outputTokensCounter as le,outputTokensPerRequestHistogram as ue,rateLimitCounter as de,rateLimitWaitHistogram as fe,requestDurationHistogram as pe,requestsCounter as me,shutdownOtel as he,_c3 as ge,state as S,streamChunksCounter as _e,streamDurationHistogram as ve,tokenRefreshAttemptCounter as ye,tokenRefreshDurationHistogram as be,tokenRefreshFailureCounter as xe,tracedFetch as C,tracedUndiciRequest as Se,tracer as w,translationDurationHistogram as Ce}from"./get-user-DX7ymfsj.js";import{defineCommand as T,runMain as we}from"citty";import E from"consola";import D from"node:fs/promises";import Te from"node:os";import{SpanKind as O,SpanStatusCode as k,context as Ee,trace as De}from"@opentelemetry/api";import Oe from"clipboardy";import A from"node:process";import{serve as ke}from"srvx";import Ae from"tiny-invariant";import{execSync as je}from"node:child_process";import{Hono as j}from"hono";import{cors as Me}from"hono/cors";import{streamSSE as M}from"hono/streaming";import{events as Ne}from"fetch-event-stream";import{Tokenizer as Pe,models as Fe}from"ai-tokenizer";import*as Ie from"ai-tokenizer/encoding/\u0063\u006c\u0061\u0075\u0064\u0065";const Le=async()=>{let e=`${n}/\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/v2/token`,t=S.timeoutMs,r=new AbortController,i=setTimeout(()=>r.abort(),t);try{let{response:t,span:n}=await C({spanName:`\u0067\u0069\u0074\u0068\u0075\u0062 GET /\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/v2/token`,url:e,target:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_token`,headers:ne(S),signal:r.signal});if(!t.ok)throw n.end(),new o(`Failed to get Service token`,t);let i=await t.json();return n.end(),i}finally{clearTimeout(i)}};async function Re(){let e=new AbortController,t=S.timeoutMs,n=setTimeout(()=>{e.abort()},t);try{let t=await fetch(`${i}/login/device/code`,{method:`POST`,headers:ge(),body:JSON.stringify({client_id:a,scope:r}),signal:e.signal});if(!t.ok)throw new o(`Failed to get device code`,t);return await t.json()}finally{clearTimeout(n)}}const ze=async()=>{let e=`${h(S)}/models`,t=_(S),n=S.timeoutMs,r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let{response:n,span:i}=await C({spanName:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074 GET /models`,url:e,target:`models`,headers:t,signal:r.signal});if(!n.ok)throw i.end(),new o(`Failed to get models`,n);let a=await n.json();return i.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.models_count`,a.data.length),i.end(),a}finally{clearTimeout(i)}};function Be(){return`1.111.0-insider`}Be();const N=e=>new Promise(t=>{setTimeout(t,e)}),Ve=e=>e==null;async function He(){let e=await ze();S.models=e}const Ue=()=>{let e=Be();S.vsCodeVersion=e,E.info(`Using client version: ${e}`)};async function We(e){let t=(e.interval+1)*1e3;for(E.debug(`Polling access token with interval of ${t}ms`);;){let n=new AbortController,r=S.timeoutMs,o=setTimeout(()=>{n.abort()},r);try{let r=await fetch(`${i}/login/oauth/access_token`,{method:`POST`,headers:ge(),body:JSON.stringify({client_id:a,device_code:e.device_code,grant_type:`urn:ietf:params:oauth:grant-type:device_code`}),signal:n.signal});if(!r.ok){await N(t),E.error(`Failed to poll access token:`,await r.text());continue}let o=await r.json();E.debug(`Polling access token response:`,o);let{access_token:s}=o;if(s)return s;await N(t)}catch(e){if(e instanceof Error&&e.name===`AbortError`){E.error(`Access token polling timed out`),await N(t);continue}throw e}finally{clearTimeout(o)}}}let P,F=!1,I,L;function Ge(){E.debug(`Cleaning up token management`),P&&=(clearInterval(P),void 0),I&&=(m.off(`online`,I),void 0),L&&=(m.off(`offline`,L),void 0)}const Ke=()=>D.readFile(s.GITHUB_TOKEN_PATH,`utf8`),qe=e=>D.writeFile(s.GITHUB_TOKEN_PATH,e),Je=async()=>{let{token:e,refresh_in:t}=await Le();S.copilotToken=e,E.debug(`Service token fetched successfully!`),S.showToken&&E.info(`Service token:`,e);let n=(t-60)*1e3,r=async(e=5,t=1e3,n=`scheduled`)=>{if(F){E.debug(`Refresh already in progress, skipping`);return}return F=!0,w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token.refresh`,async r=>{let i=performance.now();r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.reason`,n),r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.max_retries`,e);try{for(let a=1;a<=e;a++)try{r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.attempt`,a),E.debug(`Refreshing Service token (${n}, attempt ${a}/${e})`);let{token:t}=await Le();S.copilotToken=t,E.debug(`Service token refreshed successfully`),S.showToken&&E.info(`Refreshed Service token:`,t),r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.success`,!0),ye.add(1,{reason:n,success:`true`}),be.record(performance.now()-i,{reason:n}),v(l.INFO,`INFO`,`Token refreshed successfully (${n})`,{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.reason":n,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.attempt":a});return}catch(o){let s=a===e;if(E.error(`Failed to refresh Service token (attempt ${a}/${e}):`,o),ye.add(1,{reason:n,success:`false`}),s){E.error(`All refresh attempts failed. May be unavailable until next scheduled refresh.`);let t=o instanceof Error?o:Error(String(o));r.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.success`,!1),r.setStatus({code:k.ERROR,message:t.message}),r.recordException(t),xe.add(1,{reason:n}),be.record(performance.now()-i,{reason:n}),v(l.ERROR,`ERROR`,`Token refresh failed after ${e} attempts (${n})`,{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.reason":n,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.token_refresh.attempts":e});return}let c=t*2**(a-1);E.debug(`Retrying token refresh in ${c}ms...`),await new Promise(e=>setTimeout(e,c))}}finally{r.end(),F=!1}})};P=setInterval(()=>{r(5,1e3,`scheduled`).catch(e=>{E.error(`Unexpected error in scheduled token refresh:`,e)})},n),m.start(),I=()=>{E.debug(`Network connectivity restored, attempting immediate token refresh`),r(3,500,`network-restored`).catch(e=>{E.error(`Unexpected error in network-restored token refresh:`,e)})},L=()=>{E.debug(`Network connectivity lost`)},m.on(`online`,I),m.on(`offline`,L)};async function R(e){try{let t=await Ke();if(t&&!e?.force){S.githubToken=t,S.showToken&&E.info(`Auth token:`,t),await Ye();return}E.info(`Authentication required`);let n=await Re();E.debug(`Device code response:`,n),E.info(`Please enter the code "${n.user_code}" in ${n.verification_uri}`);let r=await We(n);await qe(r),S.githubToken=r,S.showToken&&E.info(`Auth token:`,r),await Ye()}catch(e){throw e instanceof o?(E.error(`Failed to get Auth token:`,await e.response.json()),e):(E.error(`Failed to get Auth token:`,e),e)}}async function Ye(){let e=await te();E.info(`Authenticated as ${e.login}`)}async function Xe(e){e.verbose&&(E.level=5,E.info(`Verbose logging enabled`)),S.showToken=e.showToken,await y(),await R({force:!0}),E.success(`Auth token written to`,s.GITHUB_TOKEN_PATH)}const Ze=T({meta:{name:`auth`,description:`Run authentication flow`},args:{verbose:{alias:`v`,type:`boolean`,default:!1,description:`Enable verbose logging`},"show-token":{type:`boolean`,default:!1,description:`Show token on auth`}},run({args:e}){return Xe({verbose:e.verbose,showToken:e[`show-token`]})}}),Qe=async()=>{let e=`${n}/\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/user`,t=S.timeoutMs,r=new AbortController,i=setTimeout(()=>r.abort(),t);try{let{response:t,span:n}=await C({spanName:`\u0067\u0069\u0074\u0068\u0075\u0062 GET /\u0063\u006f\u0070\u0069\u006c\u006f\u0074_internal/user`,url:e,target:`usage`,headers:ne(S),signal:r.signal});if(!t.ok)throw n.end(),new o(`Failed to get usage`,t);let i=await t.json();return n.end(),i}finally{clearTimeout(i)}},$e=T({meta:{name:`check-usage`,description:`Show current usage/quota information`},async run(){await y(),await R();try{let e=await Qe(),t=e.quota_snapshots.premium_interactions,n=t.entitlement,r=n-t.remaining,i=n>0?r/n*100:0,a=t.percent_remaining;function o(e,t){if(!t)return`${e}: N/A`;let n=t.entitlement,r=n-t.remaining,i=n>0?r/n*100:0,a=t.percent_remaining;return`${e}: ${r}/${n} used (${i.toFixed(1)}% used, ${a.toFixed(1)}% remaining)`}let s=`Premium: ${r}/${n} used (${i.toFixed(1)}% used, ${a.toFixed(1)}% remaining)`,c=o(`Chat`,e.quota_snapshots.chat),l=o(`Completions`,e.quota_snapshots.completions);E.box(`Usage (plan: ${e.\u0063\u006f\u0070\u0069\u006c\u006f\u0074_plan})\nQuota resets: ${e.quota_reset_date}\n\nQuotas:\n ${s}\n ${c}\n ${l}`)}catch(e){E.error(`Failed to fetch usage:`,e),process.exit(1)}}});async function et(){try{let e=new URL(`../package.json`,import.meta.url).pathname,t=await D.readFile(e),n=JSON.parse(t.toString());return n.version}catch{return`unknown`}}function tt(){let e=typeof Bun<`u`;return{name:e?`bun`:`node`,version:e?Bun.version:process.version.slice(1),platform:Te.platform(),arch:Te.arch()}}async function nt(){try{let e=await D.stat(s.GITHUB_TOKEN_PATH);if(!e.isFile())return!1;let t=await D.readFile(s.GITHUB_TOKEN_PATH,`utf8`);return t.trim().length>0}catch{return!1}}async function rt(){let[e,t]=await Promise.all([et(),nt()]);return{version:e,runtime:tt(),paths:{APP_DIR:s.APP_DIR,GITHUB_TOKEN_PATH:s.GITHUB_TOKEN_PATH},tokenExists:t}}function it(e){E.info(`service debug
3
3
 
4
4
  Version: ${e.version}
5
5
  Runtime: ${e.runtime.name} ${e.runtime.version} (${e.runtime.platform} ${e.runtime.arch})
@@ -8,13 +8,15 @@ Paths:
8
8
  - APP_DIR: ${e.paths.APP_DIR}
9
9
  - \u0047\u0049\u0054\u0048\u0055\u0042_TOKEN_PATH: ${e.paths.\u0047\u0049\u0054\u0048\u0055\u0042_TOKEN_PATH}
10
10
 
11
- Token exists: ${e.tokenExists?`Yes`:`No`}`)}function $e(e){console.log(JSON.stringify(e,null,2))}async function et(e){let t=await Ze();e.json?$e(t):Qe(t)}const tt=E({meta:{name:`debug`,description:`Print debug information about the application`},args:{json:{type:`boolean`,default:!1,description:`Output debug information as JSON`}},run({args:e}){return et({json:e.json})}});function nt(){let{platform:e,ppid:t,env:n}=j;if(e===`win32`){try{let e=`wmic process get ParentProcessId,Name | findstr "${t}"`,n=Ae(e,{stdio:`pipe`}).toString();if(n.toLowerCase().includes(`powershell.exe`))return`powershell`}catch{return`cmd`}return`cmd`}else{let e=n.SHELL;if(e){if(e.endsWith(`zsh`))return`zsh`;if(e.endsWith(`fish`))return`fish`;if(e.endsWith(`bash`))return`bash`}return`sh`}}function rt(e,t=``){let n=nt(),r=Object.entries(e).filter(([,e])=>e!==void 0),i;switch(n){case`powershell`:i=r.map(([e,t])=>`$env:${e} = ${t}`).join(`; `);break;case`cmd`:i=r.map(([e,t])=>`set ${e}=${t}`).join(` & `);break;case`fish`:i=r.map(([e,t])=>`set -gx ${e} ${t}`).join(`; `);break;default:{let e=r.map(([e,t])=>`${e}=${t}`).join(` `);i=r.length>0?`export ${e}`:``;break}}if(i&&t){let e=n===`cmd`?` & `:` && `;return`${i}${e}${t}`}return i||t}function it(){return`req_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}function at(e){return e.includes(`/messages`)?`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`:e.includes(`/chat/completions`)?`\u006f\u0070\u0065\u006e\u0061\u0069`:e.includes(`/embeddings`)?`embeddings`:e.includes(`/models`)?`models`:e.includes(`/usage`)?`usage`:e.includes(`/token`)?`token`:`unknown`}function ot(){return async(t,n)=>{let r=Date.now(),i=it(),a=t.req.method,o=t.req.path,s=at(o);t.set(`requestId`,i),t.header(`x-request-id`,i);let l=T.startSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.handle_request`,{kind:k.SERVER,attributes:{"http.method":a,"http.url":t.req.url,"http.route":o,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.request_id":i,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.endpoint_type":s}});for(let[e,n]of Object.entries(t.req.header())){let t=e.toLowerCase();if(c.has(t))continue;l.setAttribute(`http.request.header.${t}`,n)}let u=Ee.setSpan(Te.active(),l);await Te.with(u,async()=>{e.registerCompletion(i,t,r);try{await n()}catch(e){let t=e instanceof Error?e:Error(String(e));throw l.setStatus({code:A.ERROR,message:t.message}),l.recordException(t),e}});let d=Date.now()-r,p=t.get(`requestData`),m=t.res.status,h=p?.model??`unknown`,g=p?.streaming??!1;if(l.setAttribute(`http.status_code`,m),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model`,h),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.streaming`,g),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.duration_ms`,d),p?.copilotDuration&&l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.\u0063\u006f\u0070\u0069\u006c\u006f\u0074_duration_ms`,p.copilotDuration),p?.tokenUsage){let e=p.tokenUsage;l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.input_tokens`,e.inputTokens),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.output_tokens`,e.outputTokens),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.total_tokens`,e.totalTokens),e.cachedTokens&&l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.cached_tokens`,e.cachedTokens),e.estimatedCost&&l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.estimated_cost`,e.estimatedCost)}t.res.headers.forEach((e,t)=>{let n=t.toLowerCase();c.has(n)||l.setAttribute(`http.response.header.${n}`,e)}),m>=400&&l.setStatus({code:A.ERROR,message:`HTTP ${m}`}),l.end();let _={method:a,path:o,status_code:String(m),model:h,streaming:String(g),endpoint_type:s};if(me.add(1,_),pe.record(d,_),m>=400&&ee.add(1,{method:a,path:o,status_code:String(m),error_type:m>=500?`server_error`:`client_error`}),p?.tokenUsage){let e=p.tokenUsage,t={model:h,endpoint_type:s};e.inputTokens&&(ae.add(e.inputTokens,t),oe.record(e.inputTokens,t)),e.outputTokens&&(le.add(e.outputTokens,t),ue.record(e.outputTokens,t)),e.cachedTokens&&f.add(e.cachedTokens,{model:h})}p?.tokenUsage&&e.executeCompletion(i)}}const st=async()=>T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.await`,async e=>{let t=performance.now();try{let n=await D.prompt(`Accept incoming request?`,{type:`confirm`}),r=performance.now()-t;if(e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.wait_duration_ms`,r),d.record(r),!n)throw e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.result`,`rejected`),u.add(1,{result:`rejected`}),new o(`Request rejected`,Response.json({message:`Request rejected`},{status:403}));e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.result`,`approved`),u.add(1,{result:`approved`})}finally{e.end()}}),ct={input:3e-6,output:15e-6};function H(e){let t=e.prompt_tokens||0,n=e.completion_tokens||0,r=e.total_tokens||t+n,i=t*ct.input+n*ct.output;return{inputTokens:t,outputTokens:n,totalTokens:r,estimatedCost:i,cachedTokens:e.prompt_tokens_details?.cached_tokens,acceptedPredictionTokens:e.completion_tokens_details?.accepted_prediction_tokens,rejectedPredictionTokens:e.completion_tokens_details?.rejected_prediction_tokens}}const lt=[{pattern:/haiku/i,family:`haiku`},{pattern:/sonnet[.-]?4[.-]6/i,family:`sonnet-4.6`},{pattern:/(sonnet-4[.-]5|[.-]?3[.-]5[.-]?sonnet|[.-]?3[.-]7[.-]?sonnet)/i,family:`sonnet-4.5`},{pattern:/sonnet-4(?![.-]5|[.-]6|[.-]1)/i,family:`sonnet-4`},{pattern:/opus[.-]?4[.-]6/i,family:`opus-4.6`},{pattern:/opus[.-]?4[.-]5/i,family:`opus-4.5`},{pattern:/opus/i,family:`opus`}],ut={haiku:`\u0063\u006c\u0061\u0075\u0064\u0065-haiku-4.5`,"sonnet-4.6":`\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4.6`,"sonnet-4.5":`\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4.5`,"sonnet-4":`\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4`,"opus-4.6":`\u0063\u006c\u0061\u0075\u0064\u0065-opus-4.6`,"opus-4.5":`\u0063\u006c\u0061\u0075\u0064\u0065-opus-4.5`,opus:`\u0063\u006c\u0061\u0075\u0064\u0065-opus-4.5`};function dt(e){return e.startsWith(`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063/`)?e.slice(10):e}function ft(e){let t=e.lastIndexOf(`[`),n=e.lastIndexOf(`]`);return t!==-1&&n===e.length-1&&n>t?[e.slice(0,t),e.slice(t+1,n)]:[e,null]}function pt(e){for(let t of lt)if(t.pattern.test(e))return t.family;return null}function mt(e,t,n=null){let r=ut[e];if(!r)return null;if(n){let e=`${r}-${n}`;if(t.includes(e))return e}if(t.includes(r))return r;if(e===`sonnet-4.5`){let e=[`\u0063\u006c\u0061\u0075\u0064\u0065-3.5-sonnet`];for(let r of e){let e=n?`${r}-${n}`:r;if(t.includes(e))return e}}return null}function ht(e,t){let n=dt(e),[r,i]=ft(n);if(t.includes(n))return n;if(i){let e=`${r}-${i}`,n=e.replaceAll(/(\d)-(\d)\b/g,`$1.$2`);if(t.includes(n))return n}let a=pt(r);if(!a)return null;let o=r.replace(/-\d{8}(?::.*)?$/,``),s=i?`-${i}`:``;for(let e of t){let t=e.replace(/-\d{8}(?::.*)?$/,``),n=`${o}${s}`.toLowerCase().replaceAll(/(\d)-(\d)\b/g,`$1.$2`),r=t.toLowerCase().replaceAll(/(\d)-(\d)\b/g,`$1.$2`);if(r===n)return e}return mt(a,t,i)}var U=class extends Error{statusCode;constructor(e,t=400){super(e),this.name=`ModelValidationError`,this.statusCode=t}};function W(e){if(!e||typeof e!=`string`)throw new U(`Model name is required and must be a string`);if(!S.models?.data)throw new U(`Models not available. Please try again later.`,503);let t=S.models.data.map(e=>e.id),n=ht(e,t);if(!n)throw ce.add(1,{requested_model:e}),new U(`Invalid model: '${e}'. Available services: ${t.join(`, `)}`);return n}async function gt(e){if(e.rateLimitSeconds===void 0)return;let t=e.rateLimitSeconds;return T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.check`,async n=>{try{let r=Date.now();if(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.configured_seconds`,t),!e.lastRequestTimestamp){e.lastRequestTimestamp=r,n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`allowed`);return}let i=(r-e.lastRequestTimestamp)/1e3;if(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.elapsed_seconds`,i),i>t){e.lastRequestTimestamp=r,n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`allowed`);return}let a=Math.ceil(t-i);if(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.wait_seconds`,a),!e.rateLimitWait)throw n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`rejected`),de.add(1,{action:`rejected`,source:`local`}),D.warn(`Rate limit exceeded. Need to wait ${a} more seconds.`),new o(`Rate limit exceeded`,Response.json({message:`Rate limit exceeded`},{status:429}));let s=a*1e3;n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`waited`),de.add(1,{action:`waited`,source:`local`}),fe.record(s,{source:`local`}),D.warn(`Rate limit reached. Waiting ${a} seconds before proceeding...`),await P(s),e.lastRequestTimestamp=r,D.info(`Rate limit wait completed, proceeding with request`)}finally{n.end()}})}function _t(e){let t=e,n=String.fromCodePoint(27),r=t.split(n);if(r.length>1){t=r[0];for(let e=1;e<r.length;e++){let i=r[e],a=i.match(/^\[[0-9;]*[a-z]/i);t+=a?i.slice(a[0].length):n+i}}return t.replaceAll(/[\u200B-\u200D\uFEFF]/g,``).replaceAll(/[\u2060-\u2064]/g,``).replaceAll(/[\u206A-\u206F]/g,``).replaceAll(/[\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/g,``).replaceAll(/[\uFFF0-\uFFFF]/g,``).replaceAll(/[\x00-\x08\v\f\x0E-\x1F]/g,``)}function G(e){if(typeof e==`string`)return _t(e);if(Array.isArray(e)){let t=e.map(e=>G(e));return t}if(e&&typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=G(r);return t}return e}const vt=async e=>{if(!S.copilotToken)throw Error(`Service token not found`);let t=G(e),n=t.messages.some(e=>typeof e.content!=`string`&&e.content?.some(e=>e.type===`image_url`)),r=t.messages.some(e=>[`assistant`,`tool`].includes(e.role)),i={..._(S,n),"X-Initiator":r?`agent`:`user`},a=`${h(S)}/chat/completions`,s=S.timeoutMs,c=new AbortController,l=setTimeout(()=>c.abort(),s);try{let{statusCode:e,headers:l,body:u,span:d}=await xe({spanName:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074 POST /chat/completions`,url:a,target:`chat_completions`,headers:i,body:JSON.stringify(t),signal:c.signal,headersTimeout:s,bodyTimeout:s*3,extraAttributes:{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model":t.model,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.streaming":!!t.stream,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.timeout_ms":s,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.has_tools":!!t.tools?.length,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.tool_count":t.tools?.length??0,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.message_count":t.messages.length,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.max_tokens":t.max_tokens??0,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.vision_enabled":n,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.initiator":r?`agent`:`user`}}),f=new Response(u,{status:e,headers:l});if(!f.ok)throw d.end(),new o(`Failed to create chat completions`,f);if(t.stream)return d.end(),Me(f);let p=await f.json();return p.id&&d.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.response.id`,p.id),d.end(),p}finally{clearTimeout(l)}};function yt(e){return T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.validate`,t=>{try{t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.requested`,e.model);let n=W(e.model);return t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.normalized`,n),n===e.model?(t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!1),e):(t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!0),se.add(1,{from_model:e.model,to_model:n}),D.debug(`Normalized model from '${e.model}' to '${n}'`),{...e,model:n})}finally{t.end()}})}async function bt(t){await gt(S);let n=await t.req.json();D.debug(`Request payload:`,JSON.stringify(n).slice(-400));try{n=yt(n)}catch(e){if(e instanceof U)return t.json({error:{message:e.message,type:`invalid_request_error`,code:`invalid_model`}},e.statusCode);throw e}if(t.set(`requestData`,{model:n.model,streaming:!!n.stream}),S.manualApprove&&await st(),Le(n.max_tokens)){let e=S.models?.data.find(e=>e.id===n.model);n={...n,max_tokens:e?.capabilities.limits?.max_output_tokens},D.debug(`Set max_tokens to:`,JSON.stringify(n.max_tokens))}let r=performance.now(),i=await vt(n),a=performance.now()-r;if(g.record(a,{model:n.model,target:`chat_completions`,streaming:String(!!n.stream)}),xt(i)){let e=t.get(`requestData`)||{};return i.usage&&(e.tokenUsage=H(i.usage)),e.copilotDuration=a,t.set(`requestData`,e),D.debug(`Non-streaming response:`,JSON.stringify(i)),t.json(i)}return N(t,async r=>{let o=null,s=0,c=performance.now();for await(let e of i){let i=e;if(e.data&&e.data!==`[DONE]`){s++,_e.add(1,{model:n.model,endpoint_type:`\u006f\u0070\u0065\u006e\u0061\u0069`});try{let n=JSON.parse(e.data);if(n.usage){o=n.usage;let e=t.get(`requestData`)||{};e.tokenUsage=H(o),e.copilotDuration=a,t.set(`requestData`,e)}if(n.usage?.prompt_tokens_details?.cached_tokens!==void 0){let t={...n,usage:{...n.usage,prompt_tokens_details:void 0}};i={...e,data:JSON.stringify(t)}}}catch{}}await r.writeSSE(i)}let l=performance.now()-c,u={model:n.model,endpoint_type:`\u006f\u0070\u0065\u006e\u0061\u0069`};if(C.record(l,u),p.record(s,u),o){let e=t.get(`requestData`)||{};e.tokenUsage||(e.tokenUsage=H(o),e.copilotDuration=a,t.set(`requestData`,e))}let d=t.get(`requestId`);d&&e.executeCompletion(d)})}const xt=e=>Object.hasOwn(e,`choices`),K=new M;K.post(`/`,async e=>{try{return await bt(e)}catch(t){return await x(e,t)}});const St=async e=>{if(!S.copilotToken)throw Error(`Service token not found`);let t=`${h(S)}/embeddings`,n=_(S),r=S.timeoutMs,i=new AbortController,a=setTimeout(()=>i.abort(),r);try{let{response:r,span:a}=await w({spanName:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074 POST /embeddings`,url:t,target:`embeddings`,method:`POST`,headers:n,body:JSON.stringify(e),signal:i.signal,extraAttributes:{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model":e.model,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.input_count":Array.isArray(e.input)?e.input.length:1}});if(!r.ok)throw a.end(),new o(`Failed to create embeddings`,r);let s=await r.json();return a.end(),s}finally{clearTimeout(a)}},q=new M;q.post(`/`,async e=>{try{let t=await e.req.json();try{W(t.model)}catch(t){if(t instanceof U)return e.json({error:{message:t.message,type:`invalid_request_error`,code:`invalid_model`}},t.statusCode);throw t}e.set(`requestData`,{model:t.model});let n=performance.now(),r=await St(t),i=performance.now()-n;g.record(i,{model:t.model,target:`embeddings`,streaming:`false`});let a=e.get(`requestData`)||{};return a.tokenUsage=H(r.usage),a.copilotDuration=i,e.set(`requestData`,a),e.json(r)}catch(t){return await x(e,t)}});function Ct(e){if(e===null)return null;let t={stop:`end_turn`,length:`max_tokens`,tool_calls:`tool_use`,content_filter:`end_turn`};return t[e]}function wt(e){return{model:Tt(e.model),messages:Et(e.messages,e.system),max_tokens:e.max_tokens,stop:e.stop_sequences,stream:e.stream,temperature:e.temperature,top_p:e.top_p,user:e.metadata?.user_id,tools:At(e.tools),tool_choice:jt(e.tool_choice)}}function Tt(e){return e}function Et(e,t){let n=Dt(t),r=e.flatMap(e=>e.role===`user`?Ot(e):kt(e));return[...n,...r]}function J(e){return e.startsWith(`x-\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063-billing-header`)?e.replace(/^x-anthropic-billing-header:[^\n]*\n+/,``):e}function Dt(e){if(!e)return[];if(typeof e==`string`)return[{role:`system`,content:J(e)}];{let t=e.map(e=>e.text).join(`
11
+ Token exists: ${e.tokenExists?`Yes`:`No`}`)}function at(e){console.log(JSON.stringify(e,null,2))}async function ot(e){let t=await rt();e.json?at(t):it(t)}const st=T({meta:{name:`debug`,description:`Print debug information about the application`},args:{json:{type:`boolean`,default:!1,description:`Output debug information as JSON`}},run({args:e}){return ot({json:e.json})}});function ct(){let{platform:e,ppid:t,env:n}=A;if(e===`win32`){try{let e=`wmic process get ParentProcessId,Name | findstr "${t}"`,n=je(e,{stdio:`pipe`}).toString();if(n.toLowerCase().includes(`powershell.exe`))return`powershell`}catch{return`cmd`}return`cmd`}else{let e=n.SHELL;if(e){if(e.endsWith(`zsh`))return`zsh`;if(e.endsWith(`fish`))return`fish`;if(e.endsWith(`bash`))return`bash`}return`sh`}}function lt(e,t=``){let n=ct(),r=Object.entries(e).filter(([,e])=>e!==void 0),i;switch(n){case`powershell`:i=r.map(([e,t])=>`$env:${e} = ${t}`).join(`; `);break;case`cmd`:i=r.map(([e,t])=>`set ${e}=${t}`).join(` & `);break;case`fish`:i=r.map(([e,t])=>`set -gx ${e} ${t}`).join(`; `);break;default:{let e=r.map(([e,t])=>`${e}=${t}`).join(` `);i=r.length>0?`export ${e}`:``;break}}if(i&&t){let e=n===`cmd`?` & `:` && `;return`${i}${e}${t}`}return i||t}function ut(){return`req_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}function dt(e){return e.includes(`/messages`)?`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`:e.includes(`/chat/completions`)?`\u006f\u0070\u0065\u006e\u0061\u0069`:e.includes(`/embeddings`)?`embeddings`:e.includes(`/models`)?`models`:e.includes(`/usage`)?`usage`:e.includes(`/token`)?`token`:`unknown`}function ft(){return async(t,n)=>{let r=Date.now(),i=ut(),a=t.req.method,o=t.req.path,s=dt(o);t.set(`requestId`,i),t.header(`x-request-id`,i);let l=w.startSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.handle_request`,{kind:O.SERVER,attributes:{"http.method":a,"http.url":t.req.url,"http.route":o,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.request_id":i,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.endpoint_type":s}});for(let[e,n]of Object.entries(t.req.header())){let t=e.toLowerCase();if(c.has(t))continue;l.setAttribute(`http.request.header.${t}`,n)}let u=De.setSpan(Ee.active(),l);await Ee.with(u,async()=>{e.registerCompletion(i,t,r);try{await n()}catch(e){let t=e instanceof Error?e:Error(String(e));throw l.setStatus({code:k.ERROR,message:t.message}),l.recordException(t),e}});let d=Date.now()-r,p=t.get(`requestData`),m=t.res.status,h=p?.model??`unknown`,g=p?.streaming??!1;if(l.setAttribute(`http.status_code`,m),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model`,h),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.streaming`,g),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.duration_ms`,d),p?.copilotDuration&&l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.\u0063\u006f\u0070\u0069\u006c\u006f\u0074_duration_ms`,p.copilotDuration),p?.tokenUsage){let e=p.tokenUsage;l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.input_tokens`,e.inputTokens),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.output_tokens`,e.outputTokens),l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.total_tokens`,e.totalTokens),e.cachedTokens&&l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.cached_tokens`,e.cachedTokens),e.estimatedCost&&l.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.estimated_cost`,e.estimatedCost)}t.res.headers.forEach((e,t)=>{let n=t.toLowerCase();c.has(n)||l.setAttribute(`http.response.header.${n}`,e)}),m>=400&&l.setStatus({code:k.ERROR,message:`HTTP ${m}`}),l.end();let _={method:a,path:o,status_code:String(m),model:h,streaming:String(g),endpoint_type:s};if(me.add(1,_),pe.record(d,_),m>=400&&ee.add(1,{method:a,path:o,status_code:String(m),error_type:m>=500?`server_error`:`client_error`}),p?.tokenUsage){let e=p.tokenUsage,t={model:h,endpoint_type:s};e.inputTokens&&(ae.add(e.inputTokens,t),oe.record(e.inputTokens,t)),e.outputTokens&&(le.add(e.outputTokens,t),ue.record(e.outputTokens,t)),e.cachedTokens&&f.add(e.cachedTokens,{model:h})}p?.tokenUsage&&e.executeCompletion(i)}}const pt=async()=>w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.await`,async e=>{let t=performance.now();try{let n=await E.prompt(`Accept incoming request?`,{type:`confirm`}),r=performance.now()-t;if(e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.wait_duration_ms`,r),d.record(r),!n)throw e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.result`,`rejected`),u.add(1,{result:`rejected`}),new o(`Request rejected`,Response.json({message:`Request rejected`},{status:403}));e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.approval.result`,`approved`),u.add(1,{result:`approved`})}finally{e.end()}}),mt={input:3e-6,output:15e-6};function z(e){let t=e.prompt_tokens||0,n=e.completion_tokens||0,r=e.total_tokens||t+n,i=t*mt.input+n*mt.output;return{inputTokens:t,outputTokens:n,totalTokens:r,estimatedCost:i,cachedTokens:e.prompt_tokens_details?.cached_tokens,acceptedPredictionTokens:e.completion_tokens_details?.accepted_prediction_tokens,rejectedPredictionTokens:e.completion_tokens_details?.rejected_prediction_tokens}}const ht=[{pattern:/haiku/i,family:`haiku`},{pattern:/sonnet[.-]?4[.-]6/i,family:`sonnet-4.6`},{pattern:/(sonnet-4[.-]5|[.-]?3[.-]5[.-]?sonnet|[.-]?3[.-]7[.-]?sonnet)/i,family:`sonnet-4.5`},{pattern:/sonnet-4(?![.-]5|[.-]6|[.-]1)/i,family:`sonnet-4`},{pattern:/opus[.-]?4[.-]6/i,family:`opus-4.6`},{pattern:/opus[.-]?4[.-]5/i,family:`opus-4.5`},{pattern:/opus/i,family:`opus`}],gt={haiku:`\u0063\u006c\u0061\u0075\u0064\u0065-haiku-4.5`,"sonnet-4.6":`\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4.6`,"sonnet-4.5":`\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4.5`,"sonnet-4":`\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4`,"opus-4.6":`\u0063\u006c\u0061\u0075\u0064\u0065-opus-4.6`,"opus-4.5":`\u0063\u006c\u0061\u0075\u0064\u0065-opus-4.5`,opus:`\u0063\u006c\u0061\u0075\u0064\u0065-opus-4.5`};function _t(e){return e.startsWith(`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063/`)?e.slice(10):e}function vt(e){let t=e.lastIndexOf(`[`),n=e.lastIndexOf(`]`);return t!==-1&&n===e.length-1&&n>t?[e.slice(0,t),e.slice(t+1,n)]:[e,null]}function yt(e){for(let t of ht)if(t.pattern.test(e))return t.family;return null}function bt(e,t,n=null){let r=gt[e];if(!r)return null;if(n){let e=`${r}-${n}`;if(t.includes(e))return e}if(t.includes(r))return r;if(e===`sonnet-4.5`){let e=[`\u0063\u006c\u0061\u0075\u0064\u0065-3.5-sonnet`];for(let r of e){let e=n?`${r}-${n}`:r;if(t.includes(e))return e}}return null}function xt(e,t){let n=_t(e),[r,i]=vt(n);if(t.includes(n))return n;if(i){let e=`${r}-${i}`,n=e.replaceAll(/(\d)-(\d)\b/g,`$1.$2`);if(t.includes(n))return n}let a=yt(r);if(!a)return null;let o=r.replace(/-\d{8}(?::.*)?$/,``),s=i?`-${i}`:``;for(let e of t){let t=e.replace(/-\d{8}(?::.*)?$/,``),n=`${o}${s}`.toLowerCase().replaceAll(/(\d)-(\d)\b/g,`$1.$2`),r=t.toLowerCase().replaceAll(/(\d)-(\d)\b/g,`$1.$2`);if(r===n)return e}return bt(a,t,i)}var B=class extends Error{statusCode;constructor(e,t=400){super(e),this.name=`ModelValidationError`,this.statusCode=t}};function V(e){if(!e||typeof e!=`string`)throw new B(`Model name is required and must be a string`);if(!S.models?.data)throw new B(`Models not available. Please try again later.`,503);let t=S.models.data.map(e=>e.id),n=xt(e,t);if(!n)throw ce.add(1,{requested_model:e}),new B(`Invalid model: '${e}'. Available services: ${t.join(`, `)}`);return n}async function St(e){if(e.rateLimitSeconds===void 0)return;let t=e.rateLimitSeconds;return w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.check`,async n=>{try{let r=Date.now();if(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.configured_seconds`,t),!e.lastRequestTimestamp){e.lastRequestTimestamp=r,n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`allowed`);return}let i=(r-e.lastRequestTimestamp)/1e3;if(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.elapsed_seconds`,i),i>t){e.lastRequestTimestamp=r,n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`allowed`);return}let a=Math.ceil(t-i);if(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.wait_seconds`,a),!e.rateLimitWait)throw n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`rejected`),de.add(1,{action:`rejected`,source:`local`}),E.warn(`Rate limit exceeded. Need to wait ${a} more seconds.`),new o(`Rate limit exceeded`,Response.json({message:`Rate limit exceeded`},{status:429}));let s=a*1e3;n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.rate_limit.action`,`waited`),de.add(1,{action:`waited`,source:`local`}),fe.record(s,{source:`local`}),E.warn(`Rate limit reached. Waiting ${a} seconds before proceeding...`),await N(s),e.lastRequestTimestamp=r,E.info(`Rate limit wait completed, proceeding with request`)}finally{n.end()}})}function Ct(e){let t=e,n=String.fromCodePoint(27),r=t.split(n);if(r.length>1){t=r[0];for(let e=1;e<r.length;e++){let i=r[e],a=i.match(/^\[[0-9;]*[a-z]/i);t+=a?i.slice(a[0].length):n+i}}return t.replaceAll(/[\u200B-\u200D\uFEFF]/g,``).replaceAll(/[\u2060-\u2064]/g,``).replaceAll(/[\u206A-\u206F]/g,``).replaceAll(/[\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/g,``).replaceAll(/[\uFFF0-\uFFFF]/g,``).replaceAll(/[\x00-\x08\v\f\x0E-\x1F]/g,``)}function H(e){if(typeof e==`string`)return Ct(e);if(Array.isArray(e)){let t=e.map(e=>H(e));return t}if(e&&typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=H(r);return t}return e}const wt=async e=>{if(!S.copilotToken)throw Error(`Service token not found`);let t=H(e),n=t.messages.some(e=>typeof e.content!=`string`&&e.content?.some(e=>e.type===`image_url`)),r=t.messages.some(e=>[`assistant`,`tool`].includes(e.role)),i={..._(S,n),"X-Initiator":r?`agent`:`user`},a=`${h(S)}/chat/completions`,s=S.timeoutMs,c=new AbortController,l=setTimeout(()=>c.abort(),s);try{let{statusCode:e,headers:l,body:u,span:d}=await Se({spanName:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074 POST /chat/completions`,url:a,target:`chat_completions`,headers:i,body:JSON.stringify(t),signal:c.signal,headersTimeout:s,bodyTimeout:s*3,extraAttributes:{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model":t.model,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.streaming":!!t.stream,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.timeout_ms":s,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.has_tools":!!t.tools?.length,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.tool_count":t.tools?.length??0,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.message_count":t.messages.length,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.max_tokens":t.max_tokens??0,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.vision_enabled":n,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.initiator":r?`agent`:`user`}}),f=new Response(u,{status:e,headers:l});if(!f.ok)throw d.end(),new o(`Failed to create chat completions`,f);if(t.stream)return d.end(),Ne(f);let p=await f.json();return p.id&&d.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.response.id`,p.id),d.end(),p}finally{clearTimeout(l)}};function Tt(e){return w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.validate`,t=>{try{t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.requested`,e.model);let n=V(e.model);return t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.normalized`,n),n===e.model?(t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!1),e):(t.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!0),se.add(1,{from_model:e.model,to_model:n}),E.debug(`Normalized model from '${e.model}' to '${n}'`),{...e,model:n})}finally{t.end()}})}async function Et(t){await St(S);let n=await t.req.json();E.debug(`Request payload:`,JSON.stringify(n).slice(-400));try{n=Tt(n)}catch(e){if(e instanceof B)return t.json({error:{message:e.message,type:`invalid_request_error`,code:`invalid_model`}},e.statusCode);throw e}if(t.set(`requestData`,{model:n.model,streaming:!!n.stream}),S.manualApprove&&await pt(),Ve(n.max_tokens)){let e=S.models?.data.find(e=>e.id===n.model);n={...n,max_tokens:e?.capabilities.limits?.max_output_tokens},E.debug(`Set max_tokens to:`,JSON.stringify(n.max_tokens))}let r=performance.now(),i=await wt(n),a=performance.now()-r;if(g.record(a,{model:n.model,target:`chat_completions`,streaming:String(!!n.stream)}),Dt(i)){let e=t.get(`requestData`)||{};return i.usage&&(e.tokenUsage=z(i.usage)),e.copilotDuration=a,t.set(`requestData`,e),E.debug(`Non-streaming response:`,JSON.stringify(i)),t.json(i)}return M(t,async r=>{let o=null,s=0,c=performance.now();for await(let e of i){let i=e;if(e.data&&e.data!==`[DONE]`){s++,_e.add(1,{model:n.model,endpoint_type:`\u006f\u0070\u0065\u006e\u0061\u0069`});try{let n=JSON.parse(e.data);if(n.usage){o=n.usage;let e=t.get(`requestData`)||{};e.tokenUsage=z(o),e.copilotDuration=a,t.set(`requestData`,e)}if(n.usage?.prompt_tokens_details?.cached_tokens!==void 0){let t={...n,usage:{...n.usage,prompt_tokens_details:void 0}};i={...e,data:JSON.stringify(t)}}}catch{}}await r.writeSSE(i)}let l=performance.now()-c,u={model:n.model,endpoint_type:`\u006f\u0070\u0065\u006e\u0061\u0069`};if(ve.record(l,u),p.record(s,u),o){let e=t.get(`requestData`)||{};e.tokenUsage||(e.tokenUsage=z(o),e.copilotDuration=a,t.set(`requestData`,e))}let d=t.get(`requestId`);d&&e.executeCompletion(d)})}const Dt=e=>Object.hasOwn(e,`choices`),U=new j;U.post(`/`,async e=>{try{return await Et(e)}catch(t){return await x(e,t)}});const Ot=async e=>{if(!S.copilotToken)throw Error(`Service token not found`);let t=`${h(S)}/embeddings`,n=_(S),r=S.timeoutMs,i=new AbortController,a=setTimeout(()=>i.abort(),r);try{let{response:r,span:a}=await C({spanName:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074 POST /embeddings`,url:t,target:`embeddings`,method:`POST`,headers:n,body:JSON.stringify(e),signal:i.signal,extraAttributes:{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model":e.model,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.input_count":Array.isArray(e.input)?e.input.length:1}});if(!r.ok)throw a.end(),new o(`Failed to create embeddings`,r);let s=await r.json();return a.end(),s}finally{clearTimeout(a)}},W=new j;W.post(`/`,async e=>{try{let t=await e.req.json();try{V(t.model)}catch(t){if(t instanceof B)return e.json({error:{message:t.message,type:`invalid_request_error`,code:`invalid_model`}},t.statusCode);throw t}e.set(`requestData`,{model:t.model});let n=performance.now(),r=await Ot(t),i=performance.now()-n;g.record(i,{model:t.model,target:`embeddings`,streaming:`false`});let a=e.get(`requestData`)||{};return a.tokenUsage=z(r.usage),a.copilotDuration=i,e.set(`requestData`,a),e.json(r)}catch(t){return await x(e,t)}});const kt=new Pe(Ie),At=Fe[`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063/\u0063\u006c\u0061\u0075\u0064\u0065-sonnet-4`].tokens,G={...At,baseOverhead:4,perTool:27};function K(e){return kt.encode(e).length}async function jt(e){let t;try{t=await e.req.json()}catch{return e.json({error:{type:`invalid_request_error`,message:`Invalid JSON`}},400)}if(!Array.isArray(t.messages))return e.json({error:{type:`invalid_request_error`,message:`messages is required`}},400);let n=G.baseOverhead;if(t.system){let e=typeof t.system==`string`?t.system:t.system.map(e=>e.text).join(`
12
12
 
13
- `);return[{role:`system`,content:J(t)}]}}function Ot(e){let t=[];if(Array.isArray(e.content)){let n=e.content.filter(e=>e.type===`tool_result`),r=e.content.filter(e=>e.type!==`tool_result`);for(let e of n)t.push({role:`tool`,tool_call_id:e.tool_use_id,content:Y(e.content)});r.length>0&&t.push({role:`user`,content:Y(r)})}else t.push({role:`user`,content:Y(e.content)});return t}function kt(e){if(!Array.isArray(e.content))return[{role:`assistant`,content:Y(e.content)}];let t=e.content.filter(e=>e.type===`tool_use`),n=e.content.filter(e=>e.type===`text`),r=e.content.filter(e=>e.type===`thinking`),i=[...n.map(e=>e.text),...r.map(e=>e.thinking)].join(`
13
+ `);n+=G.perMessage+K(e)*G.contentMultiplier}for(let e of t.messages)n+=G.perMessage,n+=K(e.role),typeof e.content==`string`?n+=K(e.content)*G.contentMultiplier:Array.isArray(e.content)&&(n+=Mt(e.content));return t.tools&&t.tools.length>0&&(n+=Nt(t.tools)),e.json({input_tokens:Math.round(n)})}function Mt(e){let t=0;for(let n of e)switch(n.type){case`text`:t+=K(n.text)*G.contentMultiplier;break;case`tool_use`:{let e=n.name+JSON.stringify(n.input);t+=K(e)*G.contentMultiplier;break}case`tool_result`:n.content&&(t+=K(typeof n.content==`string`?n.content:JSON.stringify(n.content))*G.contentMultiplier);break;case`thinking`:t+=K(n.thinking)*G.contentMultiplier;break;case`image`:t+=1600;break}return t}function Nt(e){let t=G.toolsExist;for(let[n,r]of e.entries())n>0&&(t+=G.perTool),t+=K(r.name),r.description&&(t+=G.perDesc+K(r.description)),t+=q(r.input_schema);return t}function q(e){let t=0,n=e.properties;if(!n)return t;let r=Object.entries(n);for(let[e,[n,i]]of r.entries()){if(t+=e===0?G.perFirstProp:G.perAdditionalProp,t+=K(n),i.description&&(t+=G.perPropDesc+K(i.description)),i.enum&&Array.isArray(i.enum)){t+=G.perEnum;for(let e of i.enum)t+=K(String(e))}if(i.type===`object`&&i.properties&&(t+=G.perNestedObject,t+=q(i)),i.type===`array`&&i.items){let e=i.items;e.type===`object`&&e.properties&&(t+=G.perArrayOfObjects,t+=q(e))}}return t}function Pt(e){if(e===null)return null;let t={stop:`end_turn`,length:`max_tokens`,tool_calls:`tool_use`,content_filter:`end_turn`};return t[e]}function Ft(e){return{model:It(e.model),messages:Lt(e.messages,e.system),max_tokens:e.max_tokens,stop:e.stop_sequences,stream:e.stream,temperature:e.temperature,top_p:e.top_p,user:e.metadata?.user_id,tools:Ht(e.tools),tool_choice:Ut(e.tool_choice)}}function It(e){return e}function Lt(e,t){let n=zt(t),r=e.flatMap(e=>e.role===`user`?Bt(e):Vt(e));return[...n,...r]}function Rt(e){return e.startsWith(`x-\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063-billing-header`)?e.replace(/^x-anthropic-billing-header:[^\n]*\n+/,``):e}function zt(e){if(!e)return[];if(typeof e==`string`)return[{role:`system`,content:Rt(e)}];{let t=e.map(e=>e.text).join(`
14
14
 
15
- `);return t.length>0?[{role:`assistant`,content:i||null,tool_calls:t.map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.input)}}))}]:[{role:`assistant`,content:Y(e.content)}]}function Y(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return null;let t=e.some(e=>e.type===`image`);if(!t)return e.filter(e=>e.type===`text`||e.type===`thinking`).map(e=>e.type===`text`?e.text:e.thinking).join(`
15
+ `);return[{role:`system`,content:Rt(t)}]}}function Bt(e){let t=[];if(Array.isArray(e.content)){let n=e.content.filter(e=>e.type===`tool_result`),r=e.content.filter(e=>e.type!==`tool_result`);for(let e of n)t.push({role:`tool`,tool_call_id:e.tool_use_id,content:J(e.content)});r.length>0&&t.push({role:`user`,content:J(r)})}else t.push({role:`user`,content:J(e.content)});return t}function Vt(e){if(!Array.isArray(e.content))return[{role:`assistant`,content:J(e.content)}];let t=e.content.filter(e=>e.type===`tool_use`),n=e.content.filter(e=>e.type===`text`),r=e.content.filter(e=>e.type===`thinking`),i=[...n.map(e=>e.text),...r.map(e=>e.thinking)].join(`
16
16
 
17
- `);let n=[];for(let t of e)switch(t.type){case`text`:n.push({type:`text`,text:t.text});break;case`thinking`:n.push({type:`text`,text:t.thinking});break;case`image`:n.push({type:`image_url`,image_url:{url:`data:${t.source.media_type};base64,${t.source.data}`}});break}return n}function At(e){if(e)return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.input_schema}}))}function jt(e){if(e)switch(e.type){case`auto`:return`auto`;case`any`:return`required`;case`tool`:return e.name?{type:`function`,function:{name:e.name}}:void 0;case`none`:return`none`;default:return}}function Mt(e){let t=[],n=[],r=null;r=e.choices[0]?.finish_reason??r;for(let i of e.choices){let e=Nt(i.message.content),a=Pt(i.message.tool_calls);t.push(...e),n.push(...a),(i.finish_reason===`tool_calls`||r===`stop`)&&(r=i.finish_reason)}return{id:e.id,type:`message`,role:`assistant`,model:e.model,content:[...t,...n],stop_reason:Ct(r),stop_sequence:null,usage:{input_tokens:e.usage?.prompt_tokens??0,output_tokens:e.usage?.completion_tokens??0}}}function Nt(e){return typeof e==`string`?[{type:`text`,text:e}]:Array.isArray(e)?e.filter(e=>e.type===`text`).map(e=>({type:`text`,text:e.text})):[]}function Pt(e){return e?e.map(e=>({type:`tool_use`,id:e.id,name:e.function.name,input:JSON.parse(e.function.arguments)})):[]}function Ft(e){return e.contentBlockOpen?Object.values(e.toolCalls).some(t=>t.anthropicBlockIndex===e.contentBlockIndex):!1}function It(e,t){let n=[];if(e.choices.length===0)return n;let r=e.choices[0],{delta:i}=r;if(t.messageStartSent||=(n.push({type:`message_start`,message:{id:e.id,type:`message`,role:`assistant`,content:[],model:e.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:e.usage?.prompt_tokens??0,output_tokens:0}}}),!0),i.content&&(Ft(t)&&(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),t.contentBlockIndex++,t.contentBlockOpen=!1),t.contentBlockOpen||=(n.push({type:`content_block_start`,index:t.contentBlockIndex,content_block:{type:`text`,text:``}}),!0),n.push({type:`content_block_delta`,index:t.contentBlockIndex,delta:{type:`text_delta`,text:i.content}})),i.tool_calls)for(let e of i.tool_calls){if(e.id&&e.function?.name){t.contentBlockOpen&&=(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),t.contentBlockIndex++,!1);let r=t.contentBlockIndex;t.toolCalls[e.index]={id:e.id,name:e.function.name,anthropicBlockIndex:r},n.push({type:`content_block_start`,index:r,content_block:{type:`tool_use`,id:e.id,name:e.function.name,input:{}}}),t.contentBlockOpen=!0}if(e.function?.arguments){let r=t.toolCalls[e.index];r&&n.push({type:`content_block_delta`,index:r.anthropicBlockIndex,delta:{type:`input_json_delta`,partial_json:e.function.arguments}})}}return r.finish_reason&&(t.contentBlockOpen&&=(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),!1),n.push({type:`message_delta`,delta:{stop_reason:Ct(r.finish_reason),stop_sequence:null},usage:{input_tokens:e.usage?.prompt_tokens??0,output_tokens:e.usage?.completion_tokens??0}},{type:`message_stop`})),n}async function Lt(e,t,n){let r={query:t,max_results:n?.maxResults??5};n?.includeDomains?.length&&(r.include_domains=n.includeDomains),n?.excludeDomains?.length&&(r.exclude_domains=n.excludeDomains),D.debug(`Tavily search request:`,JSON.stringify(r));let i=await fetch(`https://api.tavily.com/search`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e}`},body:JSON.stringify(r)});if(!i.ok){let e=await i.text();throw D.error(`Tavily API error (${i.status}):`,e),Error(`Tavily API error: ${i.status} ${e}`)}let a=await i.json();return D.debug(`Tavily returned ${a.results.length} results`),a.results}function Rt(e){let t=e.tools;if(!t||t.length!==1)return!1;let n=t[0].type;return typeof n==`string`&&n.startsWith(`web_search`)}function zt(e){let t=e.messages[0];if(!t||t.role!==`user`)return null;let n;if(typeof t.content==`string`)n=t.content;else if(Array.isArray(t.content)){let e=t.content.find(e=>e.type===`text`);if(!e)return null;n=e.text}else return null;return n.startsWith(`Perform a web search for the query: `)?n.slice(36).trim():n.trim()||null}function Bt(e){let t=e.tools,n=t?.[0],r=typeof n?.max_uses==`number`?n.max_uses:5;return{maxResults:r,allowedDomains:n?.allowed_domains,blockedDomains:n?.blocked_domains}}function X(){let e=``;for(let t=0;t<24;t++)e+=`abcdefghijklmnopqrstuvwxyz0123456789`[Math.floor(Math.random()*36)];return e}function Vt(e){let{query:t,results:n,model:r,isError:i,errorContent:a}=e,o=`srvtoolu_${X()}`,s=[{type:`text`,text:`I'll search for that.`},{type:`server_tool_use`,id:o,name:`web_search`,input:{query:t}},{type:`web_search_tool_result`,tool_use_id:o,content:i&&a?a:n}];return{id:`msg_tavily_${X()}`,type:`message`,role:`assistant`,model:r,content:s,stop_reason:`end_turn`,stop_sequence:null,usage:{input_tokens:0,output_tokens:0}}}function Ht(e){let{query:t,results:n,model:r,isError:i,errorContent:a}=e,o=`srvtoolu_${X()}`,s=`msg_tavily_${X()}`,c=[];return c.push({type:`message_start`,message:{id:s,type:`message`,role:`assistant`,content:[],model:r,stop_reason:null,stop_sequence:null,usage:{input_tokens:0,output_tokens:0}}},{type:`content_block_start`,index:0,content_block:{type:`text`,text:``}},{type:`content_block_delta`,index:0,delta:{type:`text_delta`,text:`I'll search for that.`}},{type:`content_block_stop`,index:0},{type:`content_block_start`,index:1,content_block:{type:`server_tool_use`,id:o,name:`web_search`,input:{}}},{type:`content_block_delta`,index:1,delta:{type:`input_json_delta`,partial_json:JSON.stringify({query:t})}},{type:`content_block_stop`,index:1},{type:`content_block_start`,index:2,content_block:{type:`web_search_tool_result`,tool_use_id:o,content:i&&a?a:n}},{type:`content_block_stop`,index:2},{type:`message_delta`,delta:{stop_reason:`end_turn`,stop_sequence:null},usage:{output_tokens:0}},{type:`message_stop`}),c}async function Ut(e,t){let n=zt(t);if(!n)return e.json({type:`error`,error:{type:`invalid_request_error`,message:`Could not extract search query from web search request`}},400);let r=Bt(t);D.info(`Web search intercepted: "${n}"`);let i=[],a=!1,o;try{let e=S.tavilyApiKey;if(!e)throw Error(`No Tavily API key configured`);let t=await Lt(e,n,{maxResults:Math.min(r.maxResults,10),includeDomains:r.allowedDomains,excludeDomains:r.blockedDomains});i=t.map(e=>({type:`web_search_result`,url:e.url,title:e.title,encrypted_content:Buffer.from(e.content).toString(`base64`),page_age:null}))}catch(e){D.error(`Tavily search failed:`,e),a=!0,o=[{type:`web_search_tool_result_error`,error_code:`unavailable`}]}let s={query:n,results:i,model:t.model,isError:a,errorContent:o};if(!t.stream)return e.json(Vt(s));let c=Ht(s);return N(e,async e=>{for(let t of c)await e.writeSSE({event:t.type,data:JSON.stringify(t)})})}function Wt(e,t){return T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.validate`,n=>{try{n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.requested`,t.model);let e=W(t.model);return n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.normalized`,e),e===t.model?(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!1),t):(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!0),se.add(1,{from_model:t.model,to_model:e}),D.debug(`Model mapping: '${t.model}' → '${e}'`),{...t,model:e})}catch(t){if(t instanceof U)return e.json({type:`error`,error:{type:`invalid_request_error`,message:t.message}},t.statusCode),null;throw t}finally{n.end()}})}async function Gt(t){let n=await t.req.json();if(Rt(n))return Ut(t,n);await gt(S),D.debug(`\u0041\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063 request payload:`,JSON.stringify(n));let r=t.req.header(`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063-beta`)??``,i=/context-1m/i.test(r);if(i){let e=n.model;n={...n,model:`${n.model}-1m`},D.debug(`Detected context-1m beta flag, rewriting model: '${e}' → '${n.model}'`)}let a=Wt(t,n);if(!a)return;n=a;let o=performance.now(),s=T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translate.\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063_to_\u006f\u0070\u0065\u006e\u0061\u0069`,e=>{try{e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.direction`,`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063_to_\u006f\u0070\u0065\u006e\u0061\u0069`),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.message_count`,n.messages.length),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_tools`,!!n.tools?.length),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_system`,!!n.system),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.context_1m_beta`,i);let t=n.messages.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type===`image`)),r=n.messages.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type===`thinking`));return e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_images`,t),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_thinking`,r),wt(n)}finally{e.end()}});Se.record(performance.now()-o,{direction:`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063_to_\u006f\u0070\u0065\u006e\u0061\u0069`}),D.debug(`Translated \u004f\u0070\u0065\u006e\u0041\u0049 request payload:`,JSON.stringify(s)),t.set(`requestData`,{model:s.model,streaming:!!s.stream});let c=performance.now();S.manualApprove&&await st();let l=await vt(s),u=performance.now()-c;if(g.record(u,{model:s.model,target:`chat_completions`,streaming:String(!!s.stream)}),Kt(l)){let e=t.get(`requestData`)||{};l.usage&&(e.tokenUsage=H(l.usage)),e.copilotDuration=u,t.set(`requestData`,e),D.debug(`Non-streaming response:`,JSON.stringify(l).slice(-400));let n=performance.now(),r=T.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translate.\u006f\u0070\u0065\u006e\u0061\u0069_to_\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`,e=>{try{e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.direction`,`\u006f\u0070\u0065\u006e\u0061\u0069_to_\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`);let t=Mt(l);return e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.content_blocks`,t.content.length),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.stop_reason`,t.stop_reason??`null`),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_tool_use`,t.content.some(e=>e.type===`tool_use`)),t}finally{e.end()}});return Se.record(performance.now()-n,{direction:`\u006f\u0070\u0065\u006e\u0061\u0069_to_\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`}),D.debug(`Translated \u0041\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063 response:`,JSON.stringify(r)),t.json(r)}return D.debug(`Streaming response from service`),N(t,async n=>{let r=null,i=0,a=performance.now(),o={messageStartSent:!1,contentBlockIndex:0,contentBlockOpen:!1,toolCalls:{}};for await(let e of l){if(D.debug(`Raw stream event:`,JSON.stringify(e)),e.data===`[DONE]`)break;if(!e.data)continue;let a=JSON.parse(e.data);if(i++,_e.add(1,{model:s.model,endpoint_type:`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`}),a.usage){r=a.usage;let e=t.get(`requestData`)||{};e.tokenUsage=H(r),e.copilotDuration=u,t.set(`requestData`,e)}let c=It(a,o);for(let e of c)D.debug(`Translated \u0041\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063 event:`,JSON.stringify(e)),await n.writeSSE({event:e.type,data:JSON.stringify(e)})}let c=performance.now()-a,d={model:s.model,endpoint_type:`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`};if(C.record(c,d),p.record(i,d),r){let e=t.get(`requestData`)||{};e.tokenUsage||(e.tokenUsage=H(r),e.copilotDuration=u,t.set(`requestData`,e))}let f=t.get(`requestId`);f&&e.executeCompletion(f)})}const Kt=e=>Object.hasOwn(e,`choices`),qt=new M;qt.post(`/`,async e=>{try{return await Gt(e)}catch(t){return await x(e,t)}});const Z=new M;Z.get(`/`,async e=>{try{S.models||await Re();let t=S.models?.data.map(e=>({id:e.id,object:`model`,type:`model`,created:0,created_at:new Date(0).toISOString(),owned_by:e.vendor,display_name:e.name,context_length:e.capabilities.limits?.max_context_window_tokens}));return e.json({object:`list`,data:t,has_more:!1})}catch(t){return await x(e,t)}});const Jt=new M;Jt.get(`/`,e=>{try{return e.json({token:S.copilotToken})}catch(t){return console.error(`Error fetching token:`,t),e.json({error:`Failed to fetch token`,token:null},500)}});const Yt=new M;Yt.get(`/`,async e=>{try{let t=await V();return e.json(t)}catch(t){return console.error(`Error fetching usage:`,t),e.json({error:`Failed to fetch usage`},500)}});const Q=new M;Q.use(ot()),Q.use(je()),Q.get(`/`,e=>e.text(`Server running`)),Q.route(`/chat/completions`,K),Q.route(`/models`,Z),Q.route(`/embeddings`,q),Q.route(`/usage`,Yt),Q.route(`/token`,Jt),Q.route(`/v1/chat/completions`,K),Q.route(`/v1/models`,Z),Q.route(`/v1/embeddings`,q),Q.route(`/v1/messages`,qt),Q.post(`/v1/messages/count_tokens`,e=>e.json({input_tokens:1}));const Xt=[],$=Date.now();function Zt(){let e=async(e,t=0)=>{D.info(`Gracefully shutting down...`);let n=T.startSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.server.shutdown`,{kind:k.INTERNAL,attributes:{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.shutdown.reason":e,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.shutdown.exit_code":t,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.uptime_seconds":(Date.now()-$)/1e3}});for(let e of Xt)try{await e()}catch(e){D.error(`Error during cleanup:`,e)}n.end(),D.info(`Shutdown complete`),j.exit(t)};j.on(`SIGINT`,()=>e(`SIGINT`)),j.on(`SIGTERM`,()=>e(`SIGTERM`)),j.on(`uncaughtException`,t=>{D.error(`Uncaught exception:`,t),e(`uncaughtException`,1)}),j.on(`unhandledRejection`,(t,n)=>{D.error(`Unhandled promise rejection at:`,n,`reason:`,t),e(`unhandledRejection`,1)})}function Qt(){return`npx \u0063\u006f\u0070\u0069\u006c\u006f\u0074-api start`}function $t(e){let t=[Qt()];return t.push(`-p ${e.port}`),e.verbose&&t.push(`-v`),e.accountType!==`individual`&&t.push(`-a ${e.accountType}`),e.manual&&t.push(`--manual`),e.rateLimit&&t.push(`-r ${e.rateLimit}`),e.rateLimitWait&&t.push(`-w`),e.githubToken&&t.push(`-g ${e.\u0067\u0069\u0074\u0068\u0075\u0062Token}`),e.claudeCode&&t.push(`-c`),e.model&&t.push(`-m ${e.model}`),e.smallModel&&t.push(`-s ${e.smallModel}`),e.timeout&&t.push(`-t ${String(e.timeout)}`),e.showToken&&t.push(`--show-token`),e.disableConnectivityMonitoring&&t.push(`--disable-connectivity-monitoring`),t.join(` `)}async function en(e,t){if(!e.claudeCode)return;ke(S.models,`Models should be loaded by now`);let n,r;if(e.model&&e.smallModel){let t=S.models.data.map(e=>e.id);t.includes(e.model)||(D.error(`Invalid model: ${e.model}`),D.info(`Available services: \n${t.join(`
18
- `)}`),j.exit(1)),t.includes(e.smallModel)||(D.error(`Invalid small model: ${e.smallModel}`),D.info(`Available services: \n${t.join(`
19
- `)}`),j.exit(1)),n=e.model,r=e.smallModel,D.info(`Using service: ${n}`),D.info(`Using small model: ${r}`)}else e.model||e.smallModel?(D.error(`Both --model and --small-model must be specified for model selection`),j.exit(1)):(n=await D.prompt(`Select a model to use`,{type:`select`,options:S.models.data.map(e=>e.id)}),r=await D.prompt(`Select a small model to use`,{type:`select`,options:S.models.data.map(e=>e.id)}));let i=rt({ANTHROPIC_BASE_URL:t,ANTHROPIC_AUTH_TOKEN:`dummy`,ANTHROPIC_MODEL:n,ANTHROPIC_SMALL_FAST_MODEL:r},`\u0063\u006c\u0061\u0075\u0064\u0065`);try{De.writeSync(i),D.success(`Copied command to clipboard!`)}catch{D.warn(`Failed to copy to clipboard. Here is the command:`),D.log(i)}}function tn(e){let{options:t,version:n,runtime:r,githubUser:i}=e,a=T.startSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.server.startup`,{kind:k.INTERNAL,attributes:b({config:{version:n,port:t.port,accountType:t.accountType,verbose:t.verbose,manualApprove:t.manual,rateLimitSeconds:t.rateLimit??0,rateLimitWait:t.rateLimitWait,timeoutMs:t.timeout,showToken:t.showToken,claudeCode:t.claudeCode,disableConnectivityMonitoring:t.disableConnectivityMonitoring,model:t.model,smallModel:t.smallModel,githubTokenSource:t.githubToken?`cli_arg`:`stored`},runtime:r,identity:{githubUser:i.login,machineId:S.machineId,sessionId:S.sessionId,vsCodeVersion:S.vsCodeVersion},connectivity:S.connectivity,modelsCount:S.models?.data.length??0,startupDurationMs:Date.now()-$},`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api`)});if(S.models?.data)for(let e of S.models.data)a.addEvent(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.available`,b(e,`model`));a.end(),v(l.INFO,`INFO`,`Server started`,b({version:n,port:t.port,accountType:t.accountType,githubUser:i.login,modelsCount:S.models?.data.length??0,startupDurationMs:Date.now()-$},`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api`))}async function nn(e){Zt(),Xt.push(()=>{D.debug(`Cleaning up connectivity monitor`),m.stop()},()=>{D.debug(`Cleaning up token management`),Ve()},async()=>{D.debug(`Shutting down OTel SDK`),await he()}),e.verbose&&(D.level=5,D.info(`Verbose logging enabled`)),S.accountType=e.accountType,e.accountType!==`individual`&&D.info(`Using ${e.accountType} plan account`),S.manualApprove=e.manual,S.rateLimitSeconds=e.rateLimit,S.rateLimitWait=e.rateLimitWait,S.showToken=e.showToken,S.timeoutMs=e.timeout,S.connectivity.enabled=!e.disableConnectivityMonitoring,e.tavilyApiKey&&(S.tavilyApiKey=e.tavilyApiKey,D.info(`Web search enabled via Tavily API`)),await y(),ze();let t=await Je(),n=Ye();re(t,$),e.githubToken?(S.githubToken=e.githubToken,D.info(`Using provided Auth token`)):await z();let r;try{let{_s4:e}=await import(`./get-user-C8Q0uEyI.js`);r=await e(),await ie(S,r.login)}catch(e){D.error(`Failed to get user info for machine ID generation:`,e),D.error(`Cannot proceed without user information`),j.exit(1)}await We(),await Re(),tn({options:e,version:t,runtime:n,githubUser:r}),D.info(`Available services:`);for(let e of S.models?.data??[]){let t=e.capabilities.limits?.max_context_window_tokens,n=t?` (${t.toLocaleString()} tokens)`:``;D.info(`- ${e.id}${n}`)}let i=`http://localhost:${e.port}`;if(await en(e,i),e.tavilyApiKey)D.box(`🔍 Web Search: Enabled ✓`);else{let t=$t(e);D.box([`🔍 Web Search: Enable web search by adding a Tavily API key.`,` Get your API key at: https://www.tavily.com`,``,` ${t} --tavily-api-key <your-key>`].join(`
20
- `))}Oe({fetch:Q.fetch,port:e.port})}const rn=E({meta:{name:`start`,description:`Start the API server`},args:{port:{alias:`p`,type:`string`,default:`4141`,description:`Port to listen on`},verbose:{alias:`v`,type:`boolean`,default:!1,description:`Enable verbose logging`},"account-type":{alias:`a`,type:`string`,default:`individual`,description:`Account type (individual, business, enterprise)`},manual:{type:`boolean`,default:!1,description:`Enable manual request approval`},"rate-limit":{alias:`r`,type:`string`,description:`Rate limit in seconds between requests`},wait:{alias:`w`,type:`boolean`,default:!1,description:`Wait instead of error when rate limit is hit. Has no effect if rate limit is not set`},"\u0067\u0069\u0074\u0068\u0075\u0062-token":{alias:`g`,type:`string`,description:"Provide auth token directly (must be generated using the `auth` subcommand)"},"\u0063\u006c\u0061\u0075\u0064\u0065-code":{alias:`c`,type:`boolean`,default:!1,description:`Generate a command to launch with API config`},model:{alias:`m`,type:`string`,description:`Model to use (requires --\u0063\u006c\u0061\u0075\u0064\u0065-code)`},"small-model":{alias:`s`,type:`string`,description:`Small/fast model to use (requires --\u0063\u006c\u0061\u0075\u0064\u0065-code)`},"show-token":{type:`boolean`,default:!1,description:`Show tokens on fetch and refresh`},timeout:{alias:`t`,type:`string`,description:`API timeout in milliseconds (default: 600000)`},"disable-connectivity-monitoring":{type:`boolean`,default:!1,description:`Disable automatic network monitoring for token refresh`},"tavily-api-key":{type:`string`,description:`Tavily API key for web search support (or set TAVILY_API_KEY env var)`}},run({args:e}){let n=e[`rate-limit`],r=n===void 0?void 0:Number.parseInt(n,10),i=e.timeout,a=i===void 0?t:Number.parseInt(i,10);return nn({port:Number.parseInt(e.port,10),verbose:e.verbose,accountType:e[`account-type`],manual:e.manual,rateLimit:r,rateLimitWait:e.wait,githubToken:e[`\u0067\u0069\u0074\u0068\u0075\u0062-token`],claudeCode:e[`\u0063\u006c\u0061\u0075\u0064\u0065-code`],model:e.model,smallModel:e[`small-model`],showToken:e[`show-token`],timeout:a,disableConnectivityMonitoring:e[`disable-connectivity-monitoring`],tavilyApiKey:e[`tavily-api-key`]||j.env.TAVILY_API_KEY})}}),an=E({meta:{name:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074-api`,description:`API proxy server for tool integration.`},subCommands:{auth:Ke,start:rn,"check-usage":qe,debug:tt}});await Ce(an);export{};
17
+ `);return t.length>0?[{role:`assistant`,content:i||null,tool_calls:t.map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.input)}}))}]:[{role:`assistant`,content:J(e.content)}]}function J(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return null;let t=e.some(e=>e.type===`image`);if(!t)return e.filter(e=>e.type===`text`||e.type===`thinking`).map(e=>e.type===`text`?e.text:e.thinking).join(`
18
+
19
+ `);let n=[];for(let t of e)switch(t.type){case`text`:n.push({type:`text`,text:t.text});break;case`thinking`:n.push({type:`text`,text:t.thinking});break;case`image`:n.push({type:`image_url`,image_url:{url:`data:${t.source.media_type};base64,${t.source.data}`}});break}return n}function Ht(e){if(e)return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.input_schema}}))}function Ut(e){if(e)switch(e.type){case`auto`:return`auto`;case`any`:return`required`;case`tool`:return e.name?{type:`function`,function:{name:e.name}}:void 0;case`none`:return`none`;default:return}}function Wt(e){let t=[],n=[],r=null;r=e.choices[0]?.finish_reason??r;for(let i of e.choices){let e=Gt(i.message.content),a=Kt(i.message.tool_calls);t.push(...e),n.push(...a),(i.finish_reason===`tool_calls`||r===`stop`)&&(r=i.finish_reason)}return{id:e.id,type:`message`,role:`assistant`,model:e.model,content:[...t,...n],stop_reason:Pt(r),stop_sequence:null,usage:{input_tokens:e.usage?.prompt_tokens??0,output_tokens:e.usage?.completion_tokens??0}}}function Gt(e){return typeof e==`string`?[{type:`text`,text:e}]:Array.isArray(e)?e.filter(e=>e.type===`text`).map(e=>({type:`text`,text:e.text})):[]}function Kt(e){return e?e.map(e=>({type:`tool_use`,id:e.id,name:e.function.name,input:JSON.parse(e.function.arguments)})):[]}function qt(e){return e.contentBlockOpen?Object.values(e.toolCalls).some(t=>t.anthropicBlockIndex===e.contentBlockIndex):!1}function Jt(e,t){let n=[];if(e.choices.length===0)return n;let r=e.choices[0],{delta:i}=r;if(t.messageStartSent||=(n.push({type:`message_start`,message:{id:e.id,type:`message`,role:`assistant`,content:[],model:e.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:e.usage?.prompt_tokens??0,output_tokens:0}}}),!0),i.content&&(qt(t)&&(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),t.contentBlockIndex++,t.contentBlockOpen=!1),t.contentBlockOpen||=(n.push({type:`content_block_start`,index:t.contentBlockIndex,content_block:{type:`text`,text:``}}),!0),n.push({type:`content_block_delta`,index:t.contentBlockIndex,delta:{type:`text_delta`,text:i.content}})),i.tool_calls)for(let e of i.tool_calls){if(e.id&&e.function?.name){t.contentBlockOpen&&=(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),t.contentBlockIndex++,!1);let r=t.contentBlockIndex;t.toolCalls[e.index]={id:e.id,name:e.function.name,anthropicBlockIndex:r},n.push({type:`content_block_start`,index:r,content_block:{type:`tool_use`,id:e.id,name:e.function.name,input:{}}}),t.contentBlockOpen=!0}if(e.function?.arguments){let r=t.toolCalls[e.index];r&&n.push({type:`content_block_delta`,index:r.anthropicBlockIndex,delta:{type:`input_json_delta`,partial_json:e.function.arguments}})}}return r.finish_reason&&(t.contentBlockOpen&&=(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),!1),n.push({type:`message_delta`,delta:{stop_reason:Pt(r.finish_reason),stop_sequence:null},usage:{input_tokens:e.usage?.prompt_tokens??0,output_tokens:e.usage?.completion_tokens??0}},{type:`message_stop`})),n}async function Yt(e,t,n){let r={query:t,max_results:n?.maxResults??5};n?.includeDomains?.length&&(r.include_domains=n.includeDomains),n?.excludeDomains?.length&&(r.exclude_domains=n.excludeDomains),E.debug(`Tavily search request:`,JSON.stringify(r));let i=await fetch(`https://api.tavily.com/search`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e}`},body:JSON.stringify(r)});if(!i.ok){let e=await i.text();throw E.error(`Tavily API error (${i.status}):`,e),Error(`Tavily API error: ${i.status} ${e}`)}let a=await i.json();return E.debug(`Tavily returned ${a.results.length} results`),a.results}function Xt(e){let t=e.tools;if(!t||t.length!==1)return!1;let n=t[0].type;return typeof n==`string`&&n.startsWith(`web_search`)}function Zt(e){let t=e.messages[0];if(!t||t.role!==`user`)return null;let n;if(typeof t.content==`string`)n=t.content;else if(Array.isArray(t.content)){let e=t.content.find(e=>e.type===`text`);if(!e)return null;n=e.text}else return null;return n.startsWith(`Perform a web search for the query: `)?n.slice(36).trim():n.trim()||null}function Qt(e){let t=e.tools,n=t?.[0],r=typeof n?.max_uses==`number`?n.max_uses:5;return{maxResults:r,allowedDomains:n?.allowed_domains,blockedDomains:n?.blocked_domains}}function Y(){let e=``;for(let t=0;t<24;t++)e+=`abcdefghijklmnopqrstuvwxyz0123456789`[Math.floor(Math.random()*36)];return e}function $t(e){let{query:t,results:n,model:r,isError:i,errorContent:a}=e,o=`srvtoolu_${Y()}`,s=[{type:`text`,text:`I'll search for that.`},{type:`server_tool_use`,id:o,name:`web_search`,input:{query:t}},{type:`web_search_tool_result`,tool_use_id:o,content:i&&a?a:n}];return{id:`msg_tavily_${Y()}`,type:`message`,role:`assistant`,model:r,content:s,stop_reason:`end_turn`,stop_sequence:null,usage:{input_tokens:0,output_tokens:0}}}function en(e){let{query:t,results:n,model:r,isError:i,errorContent:a}=e,o=`srvtoolu_${Y()}`,s=`msg_tavily_${Y()}`,c=[];return c.push({type:`message_start`,message:{id:s,type:`message`,role:`assistant`,content:[],model:r,stop_reason:null,stop_sequence:null,usage:{input_tokens:0,output_tokens:0}}},{type:`content_block_start`,index:0,content_block:{type:`text`,text:``}},{type:`content_block_delta`,index:0,delta:{type:`text_delta`,text:`I'll search for that.`}},{type:`content_block_stop`,index:0},{type:`content_block_start`,index:1,content_block:{type:`server_tool_use`,id:o,name:`web_search`,input:{}}},{type:`content_block_delta`,index:1,delta:{type:`input_json_delta`,partial_json:JSON.stringify({query:t})}},{type:`content_block_stop`,index:1},{type:`content_block_start`,index:2,content_block:{type:`web_search_tool_result`,tool_use_id:o,content:i&&a?a:n}},{type:`content_block_stop`,index:2},{type:`message_delta`,delta:{stop_reason:`end_turn`,stop_sequence:null},usage:{output_tokens:0}},{type:`message_stop`}),c}async function tn(e,t){let n=Zt(t);if(!n)return e.json({type:`error`,error:{type:`invalid_request_error`,message:`Could not extract search query from web search request`}},400);let r=Qt(t);E.info(`Web search intercepted: "${n}"`);let i=[],a=!1,o;try{let e=S.tavilyApiKey;if(!e)throw Error(`No Tavily API key configured`);let t=await Yt(e,n,{maxResults:Math.min(r.maxResults,10),includeDomains:r.allowedDomains,excludeDomains:r.blockedDomains});i=t.map(e=>({type:`web_search_result`,url:e.url,title:e.title,encrypted_content:Buffer.from(e.content).toString(`base64`),page_age:null}))}catch(e){E.error(`Tavily search failed:`,e),a=!0,o=[{type:`web_search_tool_result_error`,error_code:`unavailable`}]}let s={query:n,results:i,model:t.model,isError:a,errorContent:o};if(!t.stream)return e.json($t(s));let c=en(s);return M(e,async e=>{for(let t of c)await e.writeSSE({event:t.type,data:JSON.stringify(t)})})}function nn(e,t){return w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.validate`,n=>{try{n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.requested`,t.model);let e=V(t.model);return n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.normalized`,e),e===t.model?(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!1),t):(n.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.was_mapped`,!0),se.add(1,{from_model:t.model,to_model:e}),E.debug(`Model mapping: '${t.model}' → '${e}'`),{...t,model:e})}catch(t){if(t instanceof B)return e.json({type:`error`,error:{type:`invalid_request_error`,message:t.message}},t.statusCode),null;throw t}finally{n.end()}})}async function rn(t){let n=await t.req.json();if(Xt(n))return tn(t,n);await St(S),E.debug(`\u0041\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063 request payload:`,JSON.stringify(n));let r=t.req.header(`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063-beta`)??``,i=/context-1m/i.test(r);if(i){let e=n.model;n={...n,model:`${n.model}-1m`},E.debug(`Detected context-1m beta flag, rewriting model: '${e}' → '${n.model}'`)}let a=nn(t,n);if(!a)return;n=a;let o=performance.now(),s=w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translate.\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063_to_\u006f\u0070\u0065\u006e\u0061\u0069`,e=>{try{e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.direction`,`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063_to_\u006f\u0070\u0065\u006e\u0061\u0069`),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.message_count`,n.messages.length),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_tools`,!!n.tools?.length),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_system`,!!n.system),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.context_1m_beta`,i);let t=n.messages.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type===`image`)),r=n.messages.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type===`thinking`));return e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_images`,t),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_thinking`,r),Ft(n)}finally{e.end()}});Ce.record(performance.now()-o,{direction:`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063_to_\u006f\u0070\u0065\u006e\u0061\u0069`}),E.debug(`Translated \u004f\u0070\u0065\u006e\u0041\u0049 request payload:`,JSON.stringify(s)),t.set(`requestData`,{model:s.model,streaming:!!s.stream});let c=performance.now();S.manualApprove&&await pt();let l=await wt(s),u=performance.now()-c;if(g.record(u,{model:s.model,target:`chat_completions`,streaming:String(!!s.stream)}),an(l)){let e=t.get(`requestData`)||{};l.usage&&(e.tokenUsage=z(l.usage)),e.copilotDuration=u,t.set(`requestData`,e),E.debug(`Non-streaming response:`,JSON.stringify(l).slice(-400));let n=performance.now(),r=w.startActiveSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translate.\u006f\u0070\u0065\u006e\u0061\u0069_to_\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`,e=>{try{e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.direction`,`\u006f\u0070\u0065\u006e\u0061\u0069_to_\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`);let t=Wt(l);return e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.content_blocks`,t.content.length),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.stop_reason`,t.stop_reason??`null`),e.setAttribute(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.translation.has_tool_use`,t.content.some(e=>e.type===`tool_use`)),t}finally{e.end()}});return Ce.record(performance.now()-n,{direction:`\u006f\u0070\u0065\u006e\u0061\u0069_to_\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`}),E.debug(`Translated \u0041\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063 response:`,JSON.stringify(r)),t.json(r)}return E.debug(`Streaming response from service`),M(t,async n=>{let r=null,i=0,a=performance.now(),o={messageStartSent:!1,contentBlockIndex:0,contentBlockOpen:!1,toolCalls:{}};for await(let e of l){if(E.debug(`Raw stream event:`,JSON.stringify(e)),e.data===`[DONE]`)break;if(!e.data)continue;let a=JSON.parse(e.data);if(i++,_e.add(1,{model:s.model,endpoint_type:`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`}),a.usage){r=a.usage;let e=t.get(`requestData`)||{};e.tokenUsage=z(r),e.copilotDuration=u,t.set(`requestData`,e)}let c=Jt(a,o);for(let e of c)E.debug(`Translated \u0041\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063 event:`,JSON.stringify(e)),await n.writeSSE({event:e.type,data:JSON.stringify(e)})}let c=performance.now()-a,d={model:s.model,endpoint_type:`\u0061\u006e\u0074\u0068\u0072\u006f\u0070\u0069\u0063`};if(ve.record(c,d),p.record(i,d),r){let e=t.get(`requestData`)||{};e.tokenUsage||(e.tokenUsage=z(r),e.copilotDuration=u,t.set(`requestData`,e))}let f=t.get(`requestId`);f&&e.executeCompletion(f)})}const an=e=>Object.hasOwn(e,`choices`),X=new j;X.post(`/`,async e=>{try{return await rn(e)}catch(t){return await x(e,t)}});const Z=new j;Z.get(`/`,async e=>{try{S.models||await He();let t=S.models?.data.map(e=>({id:e.id,object:`model`,type:`model`,created:0,created_at:new Date(0).toISOString(),owned_by:e.vendor,display_name:e.name,context_length:e.capabilities.limits?.max_context_window_tokens}));return e.json({object:`list`,data:t,has_more:!1})}catch(t){return await x(e,t)}});const on=new j;on.get(`/`,e=>{try{return e.json({token:S.copilotToken})}catch(t){return console.error(`Error fetching token:`,t),e.json({error:`Failed to fetch token`,token:null},500)}});const sn=new j;sn.get(`/`,async e=>{try{let t=await Qe();return e.json(t)}catch(t){return console.error(`Error fetching usage:`,t),e.json({error:`Failed to fetch usage`},500)}});const Q=new j;Q.use(ft()),Q.use(Me()),Q.get(`/`,e=>e.text(`Server running`)),Q.route(`/chat/completions`,U),Q.route(`/models`,Z),Q.route(`/embeddings`,W),Q.route(`/usage`,sn),Q.route(`/token`,on),Q.route(`/v1/chat/completions`,U),Q.route(`/v1/models`,Z),Q.route(`/v1/embeddings`,W),Q.route(`/v1/messages`,X),Q.post(`/v1/messages/count_tokens`,jt);const cn=[],$=Date.now();function ln(){let e=async(e,t=0)=>{E.info(`Gracefully shutting down...`);let n=w.startSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.server.shutdown`,{kind:O.INTERNAL,attributes:{"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.shutdown.reason":e,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.shutdown.exit_code":t,"\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.uptime_seconds":(Date.now()-$)/1e3}});for(let e of cn)try{await e()}catch(e){E.error(`Error during cleanup:`,e)}n.end(),E.info(`Shutdown complete`),A.exit(t)};A.on(`SIGINT`,()=>e(`SIGINT`)),A.on(`SIGTERM`,()=>e(`SIGTERM`)),A.on(`uncaughtException`,t=>{E.error(`Uncaught exception:`,t),e(`uncaughtException`,1)}),A.on(`unhandledRejection`,(t,n)=>{E.error(`Unhandled promise rejection at:`,n,`reason:`,t),e(`unhandledRejection`,1)})}function un(){return`npx \u0063\u006f\u0070\u0069\u006c\u006f\u0074-api start`}function dn(e){let t=[un()];return t.push(`-p ${e.port}`),e.verbose&&t.push(`-v`),e.accountType!==`individual`&&t.push(`-a ${e.accountType}`),e.manual&&t.push(`--manual`),e.rateLimit&&t.push(`-r ${e.rateLimit}`),e.rateLimitWait&&t.push(`-w`),e.githubToken&&t.push(`-g ${e.\u0067\u0069\u0074\u0068\u0075\u0062Token}`),e.claudeCode&&t.push(`-c`),e.model&&t.push(`-m ${e.model}`),e.smallModel&&t.push(`-s ${e.smallModel}`),e.timeout&&t.push(`-t ${String(e.timeout)}`),e.showToken&&t.push(`--show-token`),e.disableConnectivityMonitoring&&t.push(`--disable-connectivity-monitoring`),t.join(` `)}async function fn(e,t){if(!e.claudeCode)return;Ae(S.models,`Models should be loaded by now`);let n,r;if(e.model&&e.smallModel){let t=S.models.data.map(e=>e.id);t.includes(e.model)||(E.error(`Invalid model: ${e.model}`),E.info(`Available services: \n${t.join(`
20
+ `)}`),A.exit(1)),t.includes(e.smallModel)||(E.error(`Invalid small model: ${e.smallModel}`),E.info(`Available services: \n${t.join(`
21
+ `)}`),A.exit(1)),n=e.model,r=e.smallModel,E.info(`Using service: ${n}`),E.info(`Using small model: ${r}`)}else e.model||e.smallModel?(E.error(`Both --model and --small-model must be specified for model selection`),A.exit(1)):(n=await E.prompt(`Select a model to use`,{type:`select`,options:S.models.data.map(e=>e.id)}),r=await E.prompt(`Select a small model to use`,{type:`select`,options:S.models.data.map(e=>e.id)}));let i=lt({ANTHROPIC_BASE_URL:t,ANTHROPIC_AUTH_TOKEN:`dummy`,ANTHROPIC_MODEL:n,ANTHROPIC_SMALL_FAST_MODEL:r},`\u0063\u006c\u0061\u0075\u0064\u0065`);try{Oe.writeSync(i),E.success(`Copied command to clipboard!`)}catch{E.warn(`Failed to copy to clipboard. Here is the command:`),E.log(i)}}function pn(e){let{options:t,version:n,runtime:r,githubUser:i}=e,a=w.startSpan(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.server.startup`,{kind:O.INTERNAL,attributes:b({config:{version:n,port:t.port,accountType:t.accountType,verbose:t.verbose,manualApprove:t.manual,rateLimitSeconds:t.rateLimit??0,rateLimitWait:t.rateLimitWait,timeoutMs:t.timeout,showToken:t.showToken,claudeCode:t.claudeCode,disableConnectivityMonitoring:t.disableConnectivityMonitoring,model:t.model,smallModel:t.smallModel,githubTokenSource:t.githubToken?`cli_arg`:`stored`},runtime:r,identity:{githubUser:i.login,machineId:S.machineId,sessionId:S.sessionId,vsCodeVersion:S.vsCodeVersion},connectivity:S.connectivity,modelsCount:S.models?.data.length??0,startupDurationMs:Date.now()-$},`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api`)});if(S.models?.data)for(let e of S.models.data)a.addEvent(`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api.model.available`,b(e,`model`));a.end(),v(l.INFO,`INFO`,`Server started`,b({version:n,port:t.port,accountType:t.accountType,githubUser:i.login,modelsCount:S.models?.data.length??0,startupDurationMs:Date.now()-$},`\u0063\u006f\u0070\u0069\u006c\u006f\u0074_api`))}async function mn(e){ln(),cn.push(()=>{E.debug(`Cleaning up connectivity monitor`),m.stop()},()=>{E.debug(`Cleaning up token management`),Ge()},async()=>{E.debug(`Shutting down OTel SDK`),await he()}),e.verbose&&(E.level=5,E.info(`Verbose logging enabled`)),S.accountType=e.accountType,e.accountType!==`individual`&&E.info(`Using ${e.accountType} plan account`),S.manualApprove=e.manual,S.rateLimitSeconds=e.rateLimit,S.rateLimitWait=e.rateLimitWait,S.showToken=e.showToken,S.timeoutMs=e.timeout,S.connectivity.enabled=!e.disableConnectivityMonitoring,e.tavilyApiKey&&(S.tavilyApiKey=e.tavilyApiKey,E.info(`Web search enabled via Tavily API`)),await y(),Ue();let t=await et(),n=tt();re(t,$),e.githubToken?(S.githubToken=e.githubToken,E.info(`Using provided Auth token`)):await R();let r;try{let{_s4:e}=await import(`./get-user-C8Q0uEyI.js`);r=await e(),await ie(S,r.login)}catch(e){E.error(`Failed to get user info for machine ID generation:`,e),E.error(`Cannot proceed without user information`),A.exit(1)}await Je(),await He(),pn({options:e,version:t,runtime:n,githubUser:r}),E.info(`Available services:`);for(let e of S.models?.data??[]){let t=e.capabilities.limits?.max_context_window_tokens,n=t?` (${t.toLocaleString()} tokens)`:``;E.info(`- ${e.id}${n}`)}let i=`http://localhost:${e.port}`;if(await fn(e,i),e.tavilyApiKey)E.box(`🔍 Web Search: Enabled ✓`);else{let t=dn(e);E.box([`🔍 Web Search: Enable web search by adding a Tavily API key.`,` Get your API key at: https://www.tavily.com`,``,` ${t} --tavily-api-key <your-key>`].join(`
22
+ `))}ke({fetch:Q.fetch,port:e.port})}const hn=T({meta:{name:`start`,description:`Start the API server`},args:{port:{alias:`p`,type:`string`,default:`4141`,description:`Port to listen on`},verbose:{alias:`v`,type:`boolean`,default:!1,description:`Enable verbose logging`},"account-type":{alias:`a`,type:`string`,default:`individual`,description:`Account type (individual, business, enterprise)`},manual:{type:`boolean`,default:!1,description:`Enable manual request approval`},"rate-limit":{alias:`r`,type:`string`,description:`Rate limit in seconds between requests`},wait:{alias:`w`,type:`boolean`,default:!1,description:`Wait instead of error when rate limit is hit. Has no effect if rate limit is not set`},"\u0067\u0069\u0074\u0068\u0075\u0062-token":{alias:`g`,type:`string`,description:"Provide auth token directly (must be generated using the `auth` subcommand)"},"\u0063\u006c\u0061\u0075\u0064\u0065-code":{alias:`c`,type:`boolean`,default:!1,description:`Generate a command to launch with API config`},model:{alias:`m`,type:`string`,description:`Model to use (requires --\u0063\u006c\u0061\u0075\u0064\u0065-code)`},"small-model":{alias:`s`,type:`string`,description:`Small/fast model to use (requires --\u0063\u006c\u0061\u0075\u0064\u0065-code)`},"show-token":{type:`boolean`,default:!1,description:`Show tokens on fetch and refresh`},timeout:{alias:`t`,type:`string`,description:`API timeout in milliseconds (default: 600000)`},"disable-connectivity-monitoring":{type:`boolean`,default:!1,description:`Disable automatic network monitoring for token refresh`},"tavily-api-key":{type:`string`,description:`Tavily API key for web search support (or set TAVILY_API_KEY env var)`}},run({args:e}){let n=e[`rate-limit`],r=n===void 0?void 0:Number.parseInt(n,10),i=e.timeout,a=i===void 0?t:Number.parseInt(i,10);return mn({port:Number.parseInt(e.port,10),verbose:e.verbose,accountType:e[`account-type`],manual:e.manual,rateLimit:r,rateLimitWait:e.wait,githubToken:e[`\u0067\u0069\u0074\u0068\u0075\u0062-token`],claudeCode:e[`\u0063\u006c\u0061\u0075\u0064\u0065-code`],model:e.model,smallModel:e[`small-model`],showToken:e[`show-token`],timeout:a,disableConnectivityMonitoring:e[`disable-connectivity-monitoring`],tavilyApiKey:e[`tavily-api-key`]||A.env.TAVILY_API_KEY})}}),gn=T({meta:{name:`\u0063\u006f\u0070\u0069\u006c\u006f\u0074-api`,description:`API proxy server for tool integration.`},subCommands:{auth:Ze,start:hn,"check-usage":$e,debug:st}});await we(gn);export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "copilot-api-node20",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code! (Node v20+ fork)",
5
5
  "keywords": [
6
6
  "proxy",
@@ -65,6 +65,7 @@
65
65
  "@opentelemetry/sdk-node": "^0.213.0",
66
66
  "@opentelemetry/sdk-trace-base": "^2.6.0",
67
67
  "@opentelemetry/semantic-conventions": "^1.40.0",
68
+ "ai-tokenizer": "^1.0.6",
68
69
  "citty": "^0.1.6",
69
70
  "clipboardy": "^4.0.0",
70
71
  "consola": "^3.4.2",