@torqon/mcp 0.1.7 → 0.1.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.
- package/dist/cli.js +1 -1
- package/dist/index.js +122 -13
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -264,7 +264,7 @@ async function cmdLogin() {
|
|
|
264
264
|
printLogo();
|
|
265
265
|
// Generate a random one-time state token
|
|
266
266
|
const state = Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
|
|
267
|
-
const WEB_URL = API_URL.includes('localhost') ? 'http://localhost:3002' : 'https://torqon.
|
|
267
|
+
const WEB_URL = API_URL.includes('localhost') ? 'http://localhost:3002' : 'https://torqon.dev';
|
|
268
268
|
const loginUrl = `${WEB_URL}/auth/cli?state=${state}`;
|
|
269
269
|
console.log(` ${B('Opening browser to complete login...')}\n`);
|
|
270
270
|
console.log(` ${Gr('URL:')} ${Cy(loginUrl)}\n`);
|
package/dist/index.js
CHANGED
|
@@ -185,22 +185,131 @@ server.tool('retrieve_context', 'Retrieves relevant facts from Torqon memory for
|
|
|
185
185
|
};
|
|
186
186
|
});
|
|
187
187
|
// ── optimize_context ─────────────────────────────────────────────────────────
|
|
188
|
-
//
|
|
189
|
-
|
|
188
|
+
// Real algorithmic compression — no LLM call, no backend, pure local processing.
|
|
189
|
+
// Extracts structured facts, strips filler, deduplicates, returns dense format.
|
|
190
|
+
function estimateTokens(text) {
|
|
191
|
+
// ~4 chars per token (GPT/Claude average)
|
|
192
|
+
return Math.ceil(text.length / 4);
|
|
193
|
+
}
|
|
194
|
+
function compressText(raw) {
|
|
195
|
+
const lines = raw.split('\n');
|
|
196
|
+
const facts = [];
|
|
197
|
+
const seen = new Set();
|
|
198
|
+
// Filler phrases to strip from lines
|
|
199
|
+
const fillerPatterns = [
|
|
200
|
+
/\bplease note that\b/gi,
|
|
201
|
+
/\bit is (important|worth noting|essential) (to note |that )?/gi,
|
|
202
|
+
/\bas (mentioned|noted|discussed) (above|before|earlier|previously)\b/gi,
|
|
203
|
+
/\bin (this|the) (context|case|situation|scenario)\b/gi,
|
|
204
|
+
/\bbasically\b/gi,
|
|
205
|
+
/\bessentially\b/gi,
|
|
206
|
+
/\bfundamentally\b/gi,
|
|
207
|
+
/\bof course\b/gi,
|
|
208
|
+
/\bneedless to say\b/gi,
|
|
209
|
+
/\bit goes without saying\b/gi,
|
|
210
|
+
/\bfor (all intents and purposes|the most part)\b/gi,
|
|
211
|
+
/\bin order to\b/gi, // → "to"
|
|
212
|
+
/\bdue to the fact that\b/gi, // → "because"
|
|
213
|
+
/\bat this point in time\b/gi, // → "now"
|
|
214
|
+
/\bthe fact that\b/gi,
|
|
215
|
+
/\bwhat this means is\b/gi,
|
|
216
|
+
/\bwhat we (can|need to) (see|do|understand) (is|here)?\b/gi,
|
|
217
|
+
];
|
|
218
|
+
// Verbose phrase replacements
|
|
219
|
+
const replacements = [
|
|
220
|
+
[/in order to/gi, 'to'],
|
|
221
|
+
[/due to the fact that/gi, 'because'],
|
|
222
|
+
[/at this point in time/gi, 'now'],
|
|
223
|
+
[/a large number of/gi, 'many'],
|
|
224
|
+
[/a majority of/gi, 'most'],
|
|
225
|
+
[/is able to/gi, 'can'],
|
|
226
|
+
[/is going to/gi, 'will'],
|
|
227
|
+
[/make sure (to|that)/gi, 'ensure'],
|
|
228
|
+
[/take into account/gi, 'consider'],
|
|
229
|
+
[/with (the )?regard(s)? to/gi, 'regarding'],
|
|
230
|
+
[/in the event that/gi, 'if'],
|
|
231
|
+
[/on a daily basis/gi, 'daily'],
|
|
232
|
+
[/on a weekly basis/gi, 'weekly'],
|
|
233
|
+
[/on a monthly basis/gi, 'monthly'],
|
|
234
|
+
];
|
|
235
|
+
for (const line of lines) {
|
|
236
|
+
let l = line.trim();
|
|
237
|
+
if (!l)
|
|
238
|
+
continue;
|
|
239
|
+
// Skip pure decoration lines
|
|
240
|
+
if (/^[-=*#]{3,}$/.test(l))
|
|
241
|
+
continue;
|
|
242
|
+
// Skip lines that are just whitespace or single chars
|
|
243
|
+
if (l.length < 3)
|
|
244
|
+
continue;
|
|
245
|
+
// Apply replacements
|
|
246
|
+
for (const [pattern, replacement] of replacements) {
|
|
247
|
+
l = l.replace(pattern, replacement);
|
|
248
|
+
}
|
|
249
|
+
// Strip filler phrases
|
|
250
|
+
for (const pattern of fillerPatterns) {
|
|
251
|
+
l = l.replace(pattern, '');
|
|
252
|
+
}
|
|
253
|
+
// Collapse multiple spaces
|
|
254
|
+
l = l.replace(/\s{2,}/g, ' ').trim();
|
|
255
|
+
// Skip if now too short
|
|
256
|
+
if (l.length < 4)
|
|
257
|
+
continue;
|
|
258
|
+
// Deduplication — normalize for comparison
|
|
259
|
+
const normalized = l.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
260
|
+
if (seen.has(normalized))
|
|
261
|
+
continue;
|
|
262
|
+
seen.add(normalized);
|
|
263
|
+
facts.push(l);
|
|
264
|
+
}
|
|
265
|
+
// Group lines under their nearest heading
|
|
266
|
+
const sections = [];
|
|
267
|
+
let currentSection = { heading: '', items: [] };
|
|
268
|
+
for (const fact of facts) {
|
|
269
|
+
// Detect headings: ALL CAPS line, or line ending with colon, or markdown ##
|
|
270
|
+
const isHeading = /^#{1,3}\s/.test(fact) ||
|
|
271
|
+
/^[A-Z][A-Z\s\-_]{4,}:?$/.test(fact) ||
|
|
272
|
+
(fact.endsWith(':') && fact.length < 60 && !fact.includes('.'));
|
|
273
|
+
if (isHeading) {
|
|
274
|
+
if (currentSection.items.length > 0 || currentSection.heading) {
|
|
275
|
+
sections.push(currentSection);
|
|
276
|
+
}
|
|
277
|
+
currentSection = { heading: fact.replace(/^#+\s*/, '').replace(/:$/, ''), items: [] };
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
currentSection.items.push(fact);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (currentSection.items.length > 0 || currentSection.heading) {
|
|
284
|
+
sections.push(currentSection);
|
|
285
|
+
}
|
|
286
|
+
// Render dense output
|
|
287
|
+
const out = [];
|
|
288
|
+
for (const section of sections) {
|
|
289
|
+
if (section.heading) {
|
|
290
|
+
out.push(`[${section.heading.toUpperCase()}]`);
|
|
291
|
+
}
|
|
292
|
+
for (const item of section.items) {
|
|
293
|
+
// Bullet items stay as-is; plain sentences get prefixed with •
|
|
294
|
+
const prefix = item.startsWith('-') || item.startsWith('*') || item.startsWith('•') ? '' : '• ';
|
|
295
|
+
out.push(`${prefix}${item.replace(/^[-*]\s*/, '')}`);
|
|
296
|
+
}
|
|
297
|
+
if (section.items.length > 0)
|
|
298
|
+
out.push('');
|
|
299
|
+
}
|
|
300
|
+
return out.join('\n').trim();
|
|
301
|
+
}
|
|
302
|
+
server.tool('optimize_context', 'Compresses a large document or long prompt into a dense token-efficient format. Strips filler, deduplicates, restructures. Use before feeding large text to reduce tokens.', {
|
|
190
303
|
message: z.string().describe('The raw text to compress'),
|
|
191
304
|
}, async ({ message }) => {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
apiKey: API_KEY,
|
|
199
|
-
}),
|
|
200
|
-
});
|
|
201
|
-
const data = await response.json();
|
|
305
|
+
const inputTokens = estimateTokens(message);
|
|
306
|
+
const compressed = compressText(message);
|
|
307
|
+
const outputTokens = estimateTokens(compressed);
|
|
308
|
+
const saved = inputTokens - outputTokens;
|
|
309
|
+
const pct = Math.round((saved / inputTokens) * 100);
|
|
310
|
+
const header = `[TORQON OPTIMIZED — ${inputTokens} tokens → ${outputTokens} tokens (${pct}% reduction)]\n\n`;
|
|
202
311
|
return {
|
|
203
|
-
content: [{ type: 'text', text:
|
|
312
|
+
content: [{ type: 'text', text: header + compressed }],
|
|
204
313
|
};
|
|
205
314
|
});
|
|
206
315
|
async function main() {
|