@miller-tech/uap 1.13.6 → 1.13.8

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 (55) hide show
  1. package/README.md +20 -0
  2. package/config/chat_template.jinja +126 -44
  3. package/config/model-profiles/qwen35.json +3 -3
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/benchmarks/token-throughput.d.ts +259 -0
  6. package/dist/benchmarks/token-throughput.d.ts.map +1 -0
  7. package/dist/benchmarks/token-throughput.js +198 -0
  8. package/dist/benchmarks/token-throughput.js.map +1 -0
  9. package/dist/bin/cli.js +12 -0
  10. package/dist/bin/cli.js.map +1 -1
  11. package/dist/bin/llama-server-optimize.js +0 -0
  12. package/dist/bin/policy.js +0 -0
  13. package/dist/cli/dashboard.d.ts.map +1 -1
  14. package/dist/cli/dashboard.js +10 -20
  15. package/dist/cli/dashboard.js.map +1 -1
  16. package/dist/cli/init.d.ts.map +1 -1
  17. package/dist/cli/init.js +5 -0
  18. package/dist/cli/init.js.map +1 -1
  19. package/dist/cli/memory.d.ts.map +1 -1
  20. package/dist/cli/memory.js +9 -18
  21. package/dist/cli/memory.js.map +1 -1
  22. package/dist/cli/worktree.d.ts +4 -1
  23. package/dist/cli/worktree.d.ts.map +1 -1
  24. package/dist/cli/worktree.js +73 -1
  25. package/dist/cli/worktree.js.map +1 -1
  26. package/dist/coordination/adaptive-patterns.d.ts +3 -1
  27. package/dist/coordination/adaptive-patterns.d.ts.map +1 -1
  28. package/dist/coordination/adaptive-patterns.js +31 -3
  29. package/dist/coordination/adaptive-patterns.js.map +1 -1
  30. package/dist/dashboard/data-service.d.ts +44 -0
  31. package/dist/dashboard/data-service.d.ts.map +1 -1
  32. package/dist/dashboard/data-service.js +326 -17
  33. package/dist/dashboard/data-service.js.map +1 -1
  34. package/dist/memory/embeddings.d.ts.map +1 -1
  35. package/dist/memory/embeddings.js +1 -1
  36. package/dist/memory/embeddings.js.map +1 -1
  37. package/dist/models/router.js +1 -1
  38. package/dist/models/router.js.map +1 -1
  39. package/dist/models/types.d.ts +12 -12
  40. package/dist/models/types.js +13 -13
  41. package/dist/models/types.js.map +1 -1
  42. package/dist/policies/schemas/policy.d.ts +13 -13
  43. package/dist/policies/schemas/policy.js +1 -1
  44. package/dist/policies/schemas/policy.js.map +1 -1
  45. package/dist/tasks/coordination.js +1 -1
  46. package/dist/tasks/coordination.js.map +1 -1
  47. package/dist/types/config.d.ts +24 -24
  48. package/package.json +1 -1
  49. package/templates/hooks/session-start.sh +49 -48
  50. package/tools/agents/install-opencode-local.sh.j2 +57 -7
  51. package/tools/agents/opencode_uap_agent.py +63 -1
  52. package/tools/agents/scripts/__pycache__/anthropic_proxy.cpython-313.pyc +0 -0
  53. package/tools/agents/scripts/__pycache__/tool_call_wrapper.cpython-313.pyc +0 -0
  54. package/tools/agents/scripts/anthropic_proxy.py +759 -12
  55. package/tools/agents/scripts/tool_call_wrapper.py +9 -5
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Token Throughput Benchmark for Qwen3.5
3
+ *
4
+ * Measures token generation throughput at different context sizes.
5
+ * Uses actual model inference via the local API endpoint.
6
+ */
7
+ import { z } from 'zod';
8
+ export declare const TokenThroughputConfigSchema: z.ZodObject<{
9
+ endpoint: z.ZodDefault<z.ZodString>;
10
+ model: z.ZodDefault<z.ZodString>;
11
+ contextSizes: z.ZodDefault<z.ZodArray<z.ZodNumber, "many">>;
12
+ warmupRuns: z.ZodDefault<z.ZodNumber>;
13
+ measurementRuns: z.ZodDefault<z.ZodNumber>;
14
+ maxTokens: z.ZodDefault<z.ZodNumber>;
15
+ temperature: z.ZodDefault<z.ZodNumber>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ endpoint: string;
18
+ model: string;
19
+ contextSizes: number[];
20
+ warmupRuns: number;
21
+ measurementRuns: number;
22
+ maxTokens: number;
23
+ temperature: number;
24
+ }, {
25
+ endpoint?: string | undefined;
26
+ model?: string | undefined;
27
+ contextSizes?: number[] | undefined;
28
+ warmupRuns?: number | undefined;
29
+ measurementRuns?: number | undefined;
30
+ maxTokens?: number | undefined;
31
+ temperature?: number | undefined;
32
+ }>;
33
+ export type TokenThroughputConfig = z.infer<typeof TokenThroughputConfigSchema>;
34
+ export declare const TokenThroughputResultSchema: z.ZodObject<{
35
+ contextSize: z.ZodNumber;
36
+ tokensPerSecond: z.ZodNumber;
37
+ totalTimeMs: z.ZodNumber;
38
+ avgLatencyMs: z.ZodNumber;
39
+ runs: z.ZodArray<z.ZodObject<{
40
+ runIndex: z.ZodNumber;
41
+ tokensGenerated: z.ZodNumber;
42
+ latencyMs: z.ZodNumber;
43
+ }, "strip", z.ZodTypeAny, {
44
+ runIndex: number;
45
+ tokensGenerated: number;
46
+ latencyMs: number;
47
+ }, {
48
+ runIndex: number;
49
+ tokensGenerated: number;
50
+ latencyMs: number;
51
+ }>, "many">;
52
+ }, "strip", z.ZodTypeAny, {
53
+ contextSize: number;
54
+ tokensPerSecond: number;
55
+ totalTimeMs: number;
56
+ avgLatencyMs: number;
57
+ runs: {
58
+ runIndex: number;
59
+ tokensGenerated: number;
60
+ latencyMs: number;
61
+ }[];
62
+ }, {
63
+ contextSize: number;
64
+ tokensPerSecond: number;
65
+ totalTimeMs: number;
66
+ avgLatencyMs: number;
67
+ runs: {
68
+ runIndex: number;
69
+ tokensGenerated: number;
70
+ latencyMs: number;
71
+ }[];
72
+ }>;
73
+ export type TokenThroughputResult = z.infer<typeof TokenThroughputResultSchema>;
74
+ export declare const TokenThroughputBenchmarkSchema: z.ZodObject<{
75
+ model: z.ZodString;
76
+ endpoint: z.ZodString;
77
+ timestamp: z.ZodString;
78
+ config: z.ZodObject<{
79
+ endpoint: z.ZodDefault<z.ZodString>;
80
+ model: z.ZodDefault<z.ZodString>;
81
+ contextSizes: z.ZodDefault<z.ZodArray<z.ZodNumber, "many">>;
82
+ warmupRuns: z.ZodDefault<z.ZodNumber>;
83
+ measurementRuns: z.ZodDefault<z.ZodNumber>;
84
+ maxTokens: z.ZodDefault<z.ZodNumber>;
85
+ temperature: z.ZodDefault<z.ZodNumber>;
86
+ }, "strip", z.ZodTypeAny, {
87
+ endpoint: string;
88
+ model: string;
89
+ contextSizes: number[];
90
+ warmupRuns: number;
91
+ measurementRuns: number;
92
+ maxTokens: number;
93
+ temperature: number;
94
+ }, {
95
+ endpoint?: string | undefined;
96
+ model?: string | undefined;
97
+ contextSizes?: number[] | undefined;
98
+ warmupRuns?: number | undefined;
99
+ measurementRuns?: number | undefined;
100
+ maxTokens?: number | undefined;
101
+ temperature?: number | undefined;
102
+ }>;
103
+ results: z.ZodArray<z.ZodObject<{
104
+ contextSize: z.ZodNumber;
105
+ tokensPerSecond: z.ZodNumber;
106
+ totalTimeMs: z.ZodNumber;
107
+ avgLatencyMs: z.ZodNumber;
108
+ runs: z.ZodArray<z.ZodObject<{
109
+ runIndex: z.ZodNumber;
110
+ tokensGenerated: z.ZodNumber;
111
+ latencyMs: z.ZodNumber;
112
+ }, "strip", z.ZodTypeAny, {
113
+ runIndex: number;
114
+ tokensGenerated: number;
115
+ latencyMs: number;
116
+ }, {
117
+ runIndex: number;
118
+ tokensGenerated: number;
119
+ latencyMs: number;
120
+ }>, "many">;
121
+ }, "strip", z.ZodTypeAny, {
122
+ contextSize: number;
123
+ tokensPerSecond: number;
124
+ totalTimeMs: number;
125
+ avgLatencyMs: number;
126
+ runs: {
127
+ runIndex: number;
128
+ tokensGenerated: number;
129
+ latencyMs: number;
130
+ }[];
131
+ }, {
132
+ contextSize: number;
133
+ tokensPerSecond: number;
134
+ totalTimeMs: number;
135
+ avgLatencyMs: number;
136
+ runs: {
137
+ runIndex: number;
138
+ tokensGenerated: number;
139
+ latencyMs: number;
140
+ }[];
141
+ }>, "many">;
142
+ summary: z.ZodObject<{
143
+ avgTokensPerSecond: z.ZodNumber;
144
+ minTokensPerSecond: z.ZodNumber;
145
+ maxTokensPerSecond: z.ZodNumber;
146
+ avgLatencyMs: z.ZodNumber;
147
+ totalRuns: z.ZodNumber;
148
+ totalTokensProcessed: z.ZodNumber;
149
+ }, "strip", z.ZodTypeAny, {
150
+ avgLatencyMs: number;
151
+ avgTokensPerSecond: number;
152
+ minTokensPerSecond: number;
153
+ maxTokensPerSecond: number;
154
+ totalRuns: number;
155
+ totalTokensProcessed: number;
156
+ }, {
157
+ avgLatencyMs: number;
158
+ avgTokensPerSecond: number;
159
+ minTokensPerSecond: number;
160
+ maxTokensPerSecond: number;
161
+ totalRuns: number;
162
+ totalTokensProcessed: number;
163
+ }>;
164
+ }, "strip", z.ZodTypeAny, {
165
+ endpoint: string;
166
+ model: string;
167
+ timestamp: string;
168
+ config: {
169
+ endpoint: string;
170
+ model: string;
171
+ contextSizes: number[];
172
+ warmupRuns: number;
173
+ measurementRuns: number;
174
+ maxTokens: number;
175
+ temperature: number;
176
+ };
177
+ results: {
178
+ contextSize: number;
179
+ tokensPerSecond: number;
180
+ totalTimeMs: number;
181
+ avgLatencyMs: number;
182
+ runs: {
183
+ runIndex: number;
184
+ tokensGenerated: number;
185
+ latencyMs: number;
186
+ }[];
187
+ }[];
188
+ summary: {
189
+ avgLatencyMs: number;
190
+ avgTokensPerSecond: number;
191
+ minTokensPerSecond: number;
192
+ maxTokensPerSecond: number;
193
+ totalRuns: number;
194
+ totalTokensProcessed: number;
195
+ };
196
+ }, {
197
+ endpoint: string;
198
+ model: string;
199
+ timestamp: string;
200
+ config: {
201
+ endpoint?: string | undefined;
202
+ model?: string | undefined;
203
+ contextSizes?: number[] | undefined;
204
+ warmupRuns?: number | undefined;
205
+ measurementRuns?: number | undefined;
206
+ maxTokens?: number | undefined;
207
+ temperature?: number | undefined;
208
+ };
209
+ results: {
210
+ contextSize: number;
211
+ tokensPerSecond: number;
212
+ totalTimeMs: number;
213
+ avgLatencyMs: number;
214
+ runs: {
215
+ runIndex: number;
216
+ tokensGenerated: number;
217
+ latencyMs: number;
218
+ }[];
219
+ }[];
220
+ summary: {
221
+ avgLatencyMs: number;
222
+ avgTokensPerSecond: number;
223
+ minTokensPerSecond: number;
224
+ maxTokensPerSecond: number;
225
+ totalRuns: number;
226
+ totalTokensProcessed: number;
227
+ };
228
+ }>;
229
+ export type TokenThroughputBenchmark = z.infer<typeof TokenThroughputBenchmarkSchema>;
230
+ export interface ChatCompletionRequest {
231
+ model: string;
232
+ messages: Array<{
233
+ role: 'user' | 'assistant' | 'system';
234
+ content: string;
235
+ }>;
236
+ max_tokens?: number;
237
+ temperature?: number;
238
+ }
239
+ export interface ChatCompletionResponse {
240
+ id: string;
241
+ model: string;
242
+ created: number;
243
+ choices: Array<{
244
+ index: number;
245
+ message: {
246
+ role: string;
247
+ content: string;
248
+ };
249
+ finish_reason: string;
250
+ }>;
251
+ usage: {
252
+ prompt_tokens: number;
253
+ completion_tokens: number;
254
+ total_tokens: number;
255
+ };
256
+ }
257
+ export declare function chatCompletion(config: TokenThroughputConfig, messages: ChatCompletionRequest['messages'], options?: Partial<ChatCompletionRequest>): Promise<ChatCompletionResponse>;
258
+ export declare function runTokenThroughputBenchmark(config?: Partial<TokenThroughputConfig>): Promise<TokenThroughputBenchmark>;
259
+ //# sourceMappingURL=token-throughput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-throughput.d.ts","sourceRoot":"","sources":["../../src/benchmarks/token-throughput.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;EAQtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAMhF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAczC,CAAC;AAEH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAMtF,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;QACtC,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;IACH,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,qBAAqB,EAC7B,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,EAC3C,OAAO,GAAE,OAAO,CAAC,qBAAqB,CAAM,GAC3C,OAAO,CAAC,sBAAsB,CAAC,CAqBjC;AAMD,wBAAsB,2BAA2B,CAC/C,MAAM,GAAE,OAAO,CAAC,qBAAqB,CAAM,GAC1C,OAAO,CAAC,wBAAwB,CAAC,CAkGnC"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Token Throughput Benchmark for Qwen3.5
3
+ *
4
+ * Measures token generation throughput at different context sizes.
5
+ * Uses actual model inference via the local API endpoint.
6
+ */
7
+ import { z } from 'zod';
8
+ // ============================================================================
9
+ // Benchmark Configuration
10
+ // ============================================================================
11
+ export const TokenThroughputConfigSchema = z.object({
12
+ endpoint: z.string().default('http://localhost:8080/v1'),
13
+ model: z.string().default('qwen/qwen35-a3b-iq4xs'),
14
+ contextSizes: z.array(z.number()).default([100, 500, 1000, 2000, 4000, 8000, 16000, 32000]),
15
+ warmupRuns: z.number().default(2),
16
+ measurementRuns: z.number().default(5),
17
+ maxTokens: z.number().default(100),
18
+ temperature: z.number().default(0.7),
19
+ });
20
+ // ============================================================================
21
+ // Benchmark Result Types
22
+ // ============================================================================
23
+ export const TokenThroughputResultSchema = z.object({
24
+ contextSize: z.number(),
25
+ tokensPerSecond: z.number(),
26
+ totalTimeMs: z.number(),
27
+ avgLatencyMs: z.number(),
28
+ runs: z.array(z.object({
29
+ runIndex: z.number(),
30
+ tokensGenerated: z.number(),
31
+ latencyMs: z.number(),
32
+ })),
33
+ });
34
+ export const TokenThroughputBenchmarkSchema = z.object({
35
+ model: z.string(),
36
+ endpoint: z.string(),
37
+ timestamp: z.string(),
38
+ config: TokenThroughputConfigSchema,
39
+ results: z.array(TokenThroughputResultSchema),
40
+ summary: z.object({
41
+ avgTokensPerSecond: z.number(),
42
+ minTokensPerSecond: z.number(),
43
+ maxTokensPerSecond: z.number(),
44
+ avgLatencyMs: z.number(),
45
+ totalRuns: z.number(),
46
+ totalTokensProcessed: z.number(),
47
+ }),
48
+ });
49
+ export async function chatCompletion(config, messages, options = {}) {
50
+ const response = await fetch(`${config.endpoint}/chat/completions`, {
51
+ method: 'POST',
52
+ headers: {
53
+ 'Content-Type': 'application/json',
54
+ },
55
+ body: JSON.stringify({
56
+ model: config.model,
57
+ messages,
58
+ max_tokens: options.max_tokens ?? config.maxTokens,
59
+ temperature: options.temperature ?? config.temperature,
60
+ ...options,
61
+ }),
62
+ });
63
+ if (!response.ok) {
64
+ const errorText = await response.text();
65
+ throw new Error(`API request failed: ${response.status} ${errorText}`);
66
+ }
67
+ return response.json();
68
+ }
69
+ // ============================================================================
70
+ // Benchmark Runner
71
+ // ============================================================================
72
+ export async function runTokenThroughputBenchmark(config = {}) {
73
+ const cfg = TokenThroughputConfigSchema.parse(config);
74
+ const results = [];
75
+ for (const contextSize of cfg.contextSizes) {
76
+ console.log(`\nšŸ“Š Testing context size: ${contextSize.toLocaleString()} tokens`);
77
+ // Generate context-appropriate prompt
78
+ const prompt = 'The '.repeat(contextSize);
79
+ const messages = [
80
+ {
81
+ role: 'user',
82
+ content: prompt,
83
+ },
84
+ ];
85
+ const runResults = [];
86
+ // Warmup runs
87
+ for (let i = 0; i < cfg.warmupRuns; i++) {
88
+ const start = Date.now();
89
+ try {
90
+ await chatCompletion(cfg, messages);
91
+ const latencyMs = Date.now() - start;
92
+ runResults.push({ runIndex: i, tokensGenerated: 0, latencyMs });
93
+ }
94
+ catch (error) {
95
+ console.warn(`Warmup run ${i} failed: ${error}`);
96
+ runResults.push({ runIndex: i, tokensGenerated: 0, latencyMs: Date.now() - start });
97
+ }
98
+ }
99
+ // Measurement runs
100
+ for (let i = 0; i < cfg.measurementRuns; i++) {
101
+ const start = Date.now();
102
+ try {
103
+ const response = await chatCompletion(cfg, messages);
104
+ const latencyMs = Date.now() - start;
105
+ const tokensGenerated = response.usage.completion_tokens;
106
+ runResults.push({ runIndex: i, tokensGenerated, latencyMs });
107
+ }
108
+ catch (error) {
109
+ console.warn(`Measurement run ${i} failed: ${error}`);
110
+ runResults.push({ runIndex: i, tokensGenerated: 0, latencyMs: Date.now() - start });
111
+ }
112
+ }
113
+ // Calculate statistics
114
+ const successfulRuns = runResults.filter((r) => r.tokensGenerated > 0);
115
+ const avgLatencyMs = runResults.reduce((sum, r) => sum + r.latencyMs, 0) / runResults.length;
116
+ const totalTimeMs = runResults.reduce((sum, r) => sum + r.latencyMs, 0);
117
+ // Estimate tokens/s based on context size (since completion tokens may be small)
118
+ const avgTokensPerSecond = successfulRuns.length > 0 ?
119
+ (successfulRuns.reduce((sum, r) => sum + r.tokensGenerated, 0) / successfulRuns.length) /
120
+ (avgLatencyMs / 1000) :
121
+ 0;
122
+ results.push({
123
+ contextSize,
124
+ tokensPerSecond: avgTokensPerSecond,
125
+ totalTimeMs,
126
+ avgLatencyMs,
127
+ runs: runResults,
128
+ });
129
+ console.log(` āœ“ Avg: ${avgTokensPerSecond.toFixed(2)} tokens/s | Latency: ${avgLatencyMs.toFixed(0)}ms`);
130
+ }
131
+ // Calculate summary
132
+ const allTokensPerSecond = results.map((r) => r.tokensPerSecond).filter((t) => t > 0);
133
+ const allLatencies = results.map((r) => r.avgLatencyMs);
134
+ return {
135
+ model: cfg.model,
136
+ endpoint: cfg.endpoint,
137
+ timestamp: new Date().toISOString(),
138
+ config: cfg,
139
+ results,
140
+ summary: {
141
+ avgTokensPerSecond: allTokensPerSecond.length > 0
142
+ ? allTokensPerSecond.reduce((a, b) => a + b, 0) / allTokensPerSecond.length
143
+ : 0,
144
+ minTokensPerSecond: allTokensPerSecond.length > 0 ? Math.min(...allTokensPerSecond) : 0,
145
+ maxTokensPerSecond: allTokensPerSecond.length > 0 ? Math.max(...allTokensPerSecond) : 0,
146
+ avgLatencyMs: allLatencies.length > 0 ? allLatencies.reduce((a, b) => a + b, 0) / allLatencies.length : 0,
147
+ totalRuns: cfg.measurementRuns * cfg.contextSizes.length,
148
+ totalTokensProcessed: results.reduce((sum, r) => sum + r.runs.reduce((s, run) => s + run.tokensGenerated, 0), 0),
149
+ },
150
+ };
151
+ }
152
+ // ============================================================================
153
+ // CLI Entry Point
154
+ // ============================================================================
155
+ if (import.meta.url.endsWith(process.argv[1] ?? '')) {
156
+ const config = {
157
+ endpoint: process.env.ENDPOINT || 'http://localhost:8080/v1',
158
+ model: process.env.MODEL || 'qwen/qwen35-a3b-iq4xs',
159
+ contextSizes: process.env.CONTEXT_SIZES
160
+ ? JSON.parse(process.env.CONTEXT_SIZES)
161
+ : [100, 500, 1000, 2000, 4000, 8000, 16000, 32000],
162
+ measurementRuns: parseInt(process.env.MEASUREMENT_RUNS || '5', 10),
163
+ };
164
+ console.log('šŸ”¬ Qwen3.5 Token Throughput Benchmark');
165
+ console.log('='.repeat(60));
166
+ console.log(`Model: ${config.model}`);
167
+ console.log(`Endpoint: ${config.endpoint}`);
168
+ console.log(`Context sizes: ${(config.contextSizes || []).join(', ')}`);
169
+ console.log('='.repeat(60));
170
+ try {
171
+ const benchmark = await runTokenThroughputBenchmark(config);
172
+ console.log('\n' + '='.repeat(60));
173
+ console.log('šŸ“ˆ SUMMARY');
174
+ console.log('='.repeat(60));
175
+ console.log('%-15s %-15s %-15s %-15s', 'Context Size', 'Tokens/s', 'Total Time', 'Avg Latency');
176
+ console.log('-'.repeat(60));
177
+ for (const r of benchmark.results) {
178
+ console.log(`${r.contextSize.toLocaleString().padEnd(15)} ${r.tokensPerSecond.toFixed(2).padEnd(15)} ${r.totalTimeMs}ms`.padEnd(15) +
179
+ `${r.avgLatencyMs.toFixed(0)}ms`);
180
+ }
181
+ console.log('\nšŸ“Š Overall Statistics:');
182
+ console.log(` Avg Tokens/s: ${benchmark.summary.avgTokensPerSecond.toFixed(2)}`);
183
+ console.log(` Min Tokens/s: ${benchmark.summary.minTokensPerSecond.toFixed(2)}`);
184
+ console.log(` Max Tokens/s: ${benchmark.summary.maxTokensPerSecond.toFixed(2)}`);
185
+ console.log(` Avg Latency: ${benchmark.summary.avgLatencyMs.toFixed(0)}ms`);
186
+ console.log(` Total Runs: ${benchmark.summary.totalRuns}`);
187
+ console.log(` Total Tokens: ${benchmark.summary.totalTokensProcessed}`);
188
+ // Save results
189
+ const outputPath = process.env.OUTPUT_FILE || './token_throughput_results.json';
190
+ require('fs').writeFileSync(outputPath, JSON.stringify(benchmark, null, 2));
191
+ console.log(`\nšŸ’¾ Results saved to: ${outputPath}`);
192
+ }
193
+ catch (error) {
194
+ console.error('Benchmark failed:', error);
195
+ process.exit(1);
196
+ }
197
+ }
198
+ //# sourceMappingURL=token-throughput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-throughput.js","sourceRoot":"","sources":["../../src/benchmarks/token-throughput.ts"],"names":[],"mappings":"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"}
package/dist/bin/cli.js CHANGED
@@ -204,6 +204,18 @@ program
204
204
  .option('--strict', 'Exit with code 1 if not in a worktree (for use as a gate)')
205
205
  .action(async (options) => {
206
206
  (await lazy.worktree())('ensure', { strict: options.strict });
207
+ }))
208
+ .addCommand(new Command('prune')
209
+ .description('Prune stale worktrees older than specified days')
210
+ .option('-o, --older-than <days>', 'Only prune worktrees older than N days', '30')
211
+ .option('-f, --force', 'Skip confirmation prompt')
212
+ .option('-n, --dry-run', 'Preview without making changes')
213
+ .action(async (options) => {
214
+ (await lazy.worktree())('prune', {
215
+ olderThan: parseInt(options.olderThan, 10),
216
+ force: options.force ?? false,
217
+ dryRun: options.dryRun ?? false,
218
+ });
207
219
  }));
208
220
  program
209
221
  .command('sync')