scalemax 0.1.21 → 0.1.22
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/commands/helper-bot.d.ts +14 -0
- package/dist/commands/helper-bot.js +142 -6
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { loadApiKey } from '../utils/keyStore.js';
|
|
|
3
3
|
import { validateApiKey } from '../utils/api.js';
|
|
4
4
|
export declare const SCALEMAX_HELPER_REFUSAL: string;
|
|
5
5
|
export declare const SCALEMAX_HELPER_SYSTEM_PROMPT: string;
|
|
6
|
+
export declare const SCALEMAX_HELPER_INVALID_PROVIDER_RESPONSE: string;
|
|
6
7
|
export interface HelperBotArgs {
|
|
7
8
|
question?: string;
|
|
8
9
|
model?: string;
|
|
@@ -11,6 +12,10 @@ export interface HelperConnection {
|
|
|
11
12
|
apiKey: string;
|
|
12
13
|
baseUrl: string;
|
|
13
14
|
model: string;
|
|
15
|
+
platform?: NodeJS.Platform;
|
|
16
|
+
providerScope?: 'openai' | 'anthropic' | 'both';
|
|
17
|
+
keyMode?: string;
|
|
18
|
+
availableModels?: string[];
|
|
14
19
|
}
|
|
15
20
|
export type HelperCompletion = (options: ChatCompletionOptions) => Promise<ChatCompletionResult>;
|
|
16
21
|
export interface HelperBotDependencies {
|
|
@@ -22,6 +27,15 @@ export interface HelperBotDependencies {
|
|
|
22
27
|
export declare function parseHelperBotArgs(args: string[]): HelperBotArgs;
|
|
23
28
|
export declare function redactHelperSecrets(value: unknown, activeKey?: string): string;
|
|
24
29
|
export declare function isScaleMaxHelperQuestion(input: string, hasHistory?: boolean): boolean;
|
|
30
|
+
export declare function isProviderIdentityOverride(value: string): boolean;
|
|
31
|
+
export declare function helperRuntimeContext(connection: HelperConnection): string;
|
|
32
|
+
export declare function helperConnectionSummary(connection: HelperConnection): string;
|
|
33
|
+
/**
|
|
34
|
+
* Answer stable configuration questions locally. Besides being faster and free,
|
|
35
|
+
* this keeps provider-owned personas out of the installation path where exact
|
|
36
|
+
* field values matter more than generated prose.
|
|
37
|
+
*/
|
|
38
|
+
export declare function localHelperReply(question: string, connection: HelperConnection): string | undefined;
|
|
25
39
|
export declare function selectHelperModel(models: ModelInfo[], requested?: string): string;
|
|
26
40
|
export declare function requestHelperReply(question: string, history: ChatMessage[], connection: HelperConnection, complete?: HelperCompletion): Promise<string>;
|
|
27
41
|
export declare function helperBotCommand(args?: string[], home?: string, dependencies?: Partial<HelperBotDependencies>): Promise<void>;
|
|
@@ -534,6 +534,26 @@ const CLEARLY_UNRELATED_PATTERN = /\b(?:homework|poem|story|roleplay|translate|t
|
|
|
534
534
|
const SCALEMAX_TOPIC_PATTERN = /\b(?:scalemax|api\s*key|base\s*url|endpoint|provider|model|token|credit|billing|pricing|authentication|configuration|configure|install|update|repair|verify|health\s*check|environment\s*variable|vscode|visual\s+studio\s+code|cursor|codex(?:\s+cli)?|claude(?:\s+code)?|opencode|openclaw|roo\s+code|continue|windsurf|hermes|cherry\s+studio|api\s+code)\b/i;
|
|
535
535
|
const TROUBLESHOOTING_PATTERN = /\b(?:error|failed?|failure|broken|not\s+working|doesn['’]?t\s+work|cannot|can['’]?t|timeout|invalid|unauthorized|forbidden|help)\b/i;
|
|
536
536
|
const GREETING_PATTERN = /^(?:hi|hello|hey|help|what can you do)[!.?\s]*$/i;
|
|
537
|
+
const CLAUDE_DESKTOP_PATTERN = /\bclaude\s+desktop\b/i;
|
|
538
|
+
const CLAUDE_DESKTOP_CONFIGURATION_PATTERN = /\b(?:configur(?:e|ation)|setup|set\s*up|gateway|base\s*url|api\s*key|connect(?:ion)?|third[- ]party|inference|field|install|verify)\b/i;
|
|
539
|
+
const CODEX_CLI_PATTERN = /\bcodex(?:\s+cli)?\b/i;
|
|
540
|
+
const CLIENT_CONFIGURATION_PATTERN = /\b(?:configur(?:e|ation)|setup|set\s*up|base\s*url|api\s*key|connect(?:ion)?|provider|install|repair|verify|update)\b/i;
|
|
541
|
+
const KNOWN_CONTEXT_REASK_PATTERN = /(?:\b(?:need|send|provide|share|tell)\b.{0,100}\b(?:api\s*(?:key|endpoint)|base\s*url|operating\s+system|\bos\b|model\s+(?:name|catalog))\b|YOUR-SCALEMAX-ENDPOINT|your-key)/is;
|
|
542
|
+
const PROVIDER_IDENTITY_OVERRIDE_PATTERNS = [
|
|
543
|
+
/\bkiro\b/i,
|
|
544
|
+
/\b(?:i\s+am|i['’]m)\s+(?:an?\s+)?(?:claude|chatgpt|codex)\b/i,
|
|
545
|
+
/\bas\s+(?:claude|chatgpt|codex)(?:\s+(?:ai|assistant|model))?\s*[,—-]/i,
|
|
546
|
+
/\b(?:i\s+am|i['’]m)\s+(?:an?\s+)?(?:ai[- ]powered\s+)?(?:development\s+environment|ai\s+assistant|assistant|language\s+model)\s+(?:made|built|created|developed)\s+by\s+(?:anthropic|openai)\b/i,
|
|
547
|
+
/\bi\s+(?:was|am)\s+(?:made|built|created|developed)\s+by\s+(?:anthropic|openai)\b/i,
|
|
548
|
+
/\b(?:i\s+am|i['’]m)\s+not\s+(?:the\s+)?(?:official\s+)?scalemax\s+helper\b/i,
|
|
549
|
+
/\bi\s+(?:cannot|can['’]?t|won['’]?t)\s+(?:become|act\s+as|identify\s+as)\s+(?:the\s+)?(?:official\s+)?scalemax\s+helper\b/i,
|
|
550
|
+
/\b(?:not|isn['’]?t)\s+(?:the\s+)?(?:official\s+)?scalemax\s+helper\b/i,
|
|
551
|
+
/\b(?:that|the|your|supplied)\s+(?:system\s+)?prompt\b.{0,120}\b(?:does\s+not|doesn['’]?t|cannot|can['’]?t|won['’]?t)\s+(?:override|change|replace)\b.{0,100}\b(?:identity|instructions?|role)\b/is,
|
|
552
|
+
/\bscalemax\b.{0,100}\b(?:does\s+not|doesn['’]?t)\s+(?:appear\s+to\s+)?(?:exist|be\s+real)\b/is
|
|
553
|
+
];
|
|
554
|
+
export const SCALEMAX_HELPER_INVALID_PROVIDER_RESPONSE = `ScaleMax Helper blocked an invalid provider response because it conflicted with the Helper's required identity.
|
|
555
|
+
|
|
556
|
+
The requested ScaleMax task was not completed or verified. Run \`scalemax models\`, then retry with another available model using \`scalemax helper-bot --model <id> "your ScaleMax question"\`.`;
|
|
537
557
|
const defaultDependencies = {
|
|
538
558
|
loadKey: loadApiKey,
|
|
539
559
|
validateKey: validateApiKey,
|
|
@@ -573,6 +593,91 @@ export function isScaleMaxHelperQuestion(input, hasHistory = false) {
|
|
|
573
593
|
return false;
|
|
574
594
|
return hasHistory || GREETING_PATTERN.test(value) || SCALEMAX_TOPIC_PATTERN.test(value) || TROUBLESHOOTING_PATTERN.test(value);
|
|
575
595
|
}
|
|
596
|
+
export function isProviderIdentityOverride(value) {
|
|
597
|
+
return PROVIDER_IDENTITY_OVERRIDE_PATTERNS.some(pattern => pattern.test(value));
|
|
598
|
+
}
|
|
599
|
+
function claudeDesktopGatewayBaseUrl(baseUrl) {
|
|
600
|
+
return baseUrl.trim().replace(/\/+$/, '').replace(/\/v1$/i, '');
|
|
601
|
+
}
|
|
602
|
+
function helperBillingMode(connection) {
|
|
603
|
+
return /\/token(?:\/|$)/i.test(connection.baseUrl) || /token/i.test(connection.keyMode || '') ? 'API token' : 'API credit';
|
|
604
|
+
}
|
|
605
|
+
function helperPlatformName(platform = process.platform) {
|
|
606
|
+
if (platform === 'win32')
|
|
607
|
+
return 'Windows';
|
|
608
|
+
if (platform === 'darwin')
|
|
609
|
+
return 'macOS';
|
|
610
|
+
if (platform === 'linux')
|
|
611
|
+
return 'Linux';
|
|
612
|
+
return platform;
|
|
613
|
+
}
|
|
614
|
+
export function helperRuntimeContext(connection) {
|
|
615
|
+
const models = (connection.availableModels || []).filter(Boolean);
|
|
616
|
+
return `# AUTHENTICATED SCALEMAX RUNTIME CONTEXT
|
|
617
|
+
|
|
618
|
+
The ScaleMax CLI already verified these authoritative facts before starting this conversation:
|
|
619
|
+
|
|
620
|
+
- Stored customer API key: present and authenticated. Never ask the user to paste, provide, repeat, or reveal it.
|
|
621
|
+
- Billing mode: ${helperBillingMode(connection)}
|
|
622
|
+
- OpenAI-compatible base URL: ${connection.baseUrl}
|
|
623
|
+
- Claude Desktop gateway base URL: ${claudeDesktopGatewayBaseUrl(connection.baseUrl)}
|
|
624
|
+
- Operating system: ${helperPlatformName(connection.platform)}
|
|
625
|
+
- Provider scope: ${connection.providerScope || 'both'}
|
|
626
|
+
- Active Helper model: ${connection.model}
|
|
627
|
+
- Authenticated model catalog: ${models.length ? models.join(', ') : 'already validated by the CLI'}
|
|
628
|
+
|
|
629
|
+
Mandatory behavior:
|
|
630
|
+
|
|
631
|
+
1. Treat the stored key, base URLs, operating system, provider scope, and model catalog as already known. Do not request them again.
|
|
632
|
+
2. Never output placeholders such as YOUR-SCALEMAX-ENDPOINT or your-key when an exact known value can be used.
|
|
633
|
+
3. Prefer the automatic CLI workflow. For an installed supported client, tell the user to exit the Helper with /quit, run \`scalemax update\`, then run \`scalemax doctor\` to verify it.
|
|
634
|
+
4. The Helper request itself uses the stored customer key and therefore consumes the small number of tokens used by the selected Helper model. The key is never included in the prompt text.
|
|
635
|
+
5. Do not claim you executed terminal commands. The Helper has no shell tools; give the shortest exact ScaleMax command sequence when user action is required.`;
|
|
636
|
+
}
|
|
637
|
+
export function helperConnectionSummary(connection) {
|
|
638
|
+
return `Authenticated ${helperBillingMode(connection)} key · ${helperPlatformName(connection.platform)} · ${connection.providerScope || 'both'} scope · ${connection.baseUrl} · helper model ${connection.model}`;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Answer stable configuration questions locally. Besides being faster and free,
|
|
642
|
+
* this keeps provider-owned personas out of the installation path where exact
|
|
643
|
+
* field values matter more than generated prose.
|
|
644
|
+
*/
|
|
645
|
+
export function localHelperReply(question, connection) {
|
|
646
|
+
if (CLAUDE_DESKTOP_PATTERN.test(question) && CLAUDE_DESKTOP_CONFIGURATION_PATTERN.test(question)) {
|
|
647
|
+
const gatewayBaseUrl = claudeDesktopGatewayBaseUrl(connection.baseUrl);
|
|
648
|
+
return `ScaleMax Helper detected and authenticated the stored ${helperBillingMode(connection)} key.
|
|
649
|
+
|
|
650
|
+
Configure Claude Desktop → Settings → Developer → Edit Config → Configure third-party inference with:
|
|
651
|
+
|
|
652
|
+
- Connection: Gateway
|
|
653
|
+
- Gateway base URL: ${gatewayBaseUrl}
|
|
654
|
+
- Gateway API key: use the stored ScaleMax key (do not paste it into chat)
|
|
655
|
+
- Authentication scheme: Bearer
|
|
656
|
+
- Credential kind: Static API key
|
|
657
|
+
- Model discovery: On
|
|
658
|
+
|
|
659
|
+
Select Save Changes, then Apply Changes. Start a new Claude Desktop chat and send a short test message with one discovered model. The key and endpoint are verified; the Claude Desktop GUI is only verified after that test succeeds.`;
|
|
660
|
+
}
|
|
661
|
+
if (CODEX_CLI_PATTERN.test(question) && CLIENT_CONFIGURATION_PATTERN.test(question)) {
|
|
662
|
+
return `ScaleMax Helper already authenticated the stored ${helperBillingMode(connection)} key for ${helperPlatformName(connection.platform)}.
|
|
663
|
+
|
|
664
|
+
You do not need to provide the API key or base URL again. This key uses:
|
|
665
|
+
|
|
666
|
+
- Base URL: ${connection.baseUrl}
|
|
667
|
+
- Provider scope: ${connection.providerScope || 'both'}
|
|
668
|
+
|
|
669
|
+
Exit the Helper with \`/quit\`, then run:
|
|
670
|
+
|
|
671
|
+
\`\`\`powershell
|
|
672
|
+
scalemax update
|
|
673
|
+
scalemax doctor
|
|
674
|
+
codex
|
|
675
|
+
\`\`\`
|
|
676
|
+
|
|
677
|
+
\`scalemax update\` configures detected Codex CLI from the stored key, and \`scalemax doctor\` verifies the resulting ScaleMax connection before Codex starts.`;
|
|
678
|
+
}
|
|
679
|
+
return undefined;
|
|
680
|
+
}
|
|
576
681
|
export function selectHelperModel(models, requested) {
|
|
577
682
|
if (requested) {
|
|
578
683
|
const exact = models.find(model => model.id.toLowerCase() === requested.toLowerCase());
|
|
@@ -580,7 +685,7 @@ export function selectHelperModel(models, requested) {
|
|
|
580
685
|
throw new Error(`Model "${requested}" is not available to this API key. Run \`scalemax models\` to see available models.`);
|
|
581
686
|
return exact.id;
|
|
582
687
|
}
|
|
583
|
-
const preferred = ['gpt-5.6-luna', 'claude-haiku-4-5', 'fable-5', 'gpt-5.6-terra', 'gpt-5.6-sol'];
|
|
688
|
+
const preferred = ['gpt-5.6-luna', 'claude-haiku-4-5-20251001', 'fable-5', 'gpt-5.6-terra', 'gpt-5.6-sol'];
|
|
584
689
|
for (const id of preferred) {
|
|
585
690
|
const match = models.find(model => model.id.toLowerCase() === id);
|
|
586
691
|
if (match)
|
|
@@ -596,20 +701,38 @@ export async function requestHelperReply(question, history, connection, complete
|
|
|
596
701
|
throw new Error(`Please keep each helper request under ${MAX_USER_CHARS} characters.`);
|
|
597
702
|
if (!isScaleMaxHelperQuestion(cleanQuestion, history.length > 0))
|
|
598
703
|
return SCALEMAX_HELPER_REFUSAL;
|
|
704
|
+
const localReply = localHelperReply(cleanQuestion, connection);
|
|
705
|
+
if (localReply)
|
|
706
|
+
return localReply;
|
|
599
707
|
const recentHistory = history.slice(-MAX_HISTORY_MESSAGES).map(message => ({ ...message, content: redactHelperSecrets(message.content, connection.apiKey) }));
|
|
600
708
|
const result = await complete({
|
|
601
709
|
apiKey: connection.apiKey,
|
|
602
710
|
baseUrl: connection.baseUrl,
|
|
603
711
|
model: connection.model,
|
|
604
712
|
maxTokens: DEFAULT_MAX_TOKENS,
|
|
605
|
-
messages: [
|
|
713
|
+
messages: [
|
|
714
|
+
{ role: 'system', content: SCALEMAX_HELPER_SYSTEM_PROMPT },
|
|
715
|
+
{ role: 'system', content: helperRuntimeContext(connection) },
|
|
716
|
+
...recentHistory,
|
|
717
|
+
{ role: 'user', content: cleanQuestion }
|
|
718
|
+
]
|
|
606
719
|
});
|
|
607
720
|
if (!result.ok || !result.content)
|
|
608
721
|
throw new Error(redactHelperSecrets(result.error || 'ScaleMax Helper did not return a response.', connection.apiKey));
|
|
609
|
-
|
|
722
|
+
const reply = redactHelperSecrets(result.content, connection.apiKey);
|
|
723
|
+
if (isProviderIdentityOverride(reply))
|
|
724
|
+
return SCALEMAX_HELPER_INVALID_PROVIDER_RESPONSE;
|
|
725
|
+
if (KNOWN_CONTEXT_REASK_PATTERN.test(reply)) {
|
|
726
|
+
return `ScaleMax Helper already authenticated the stored ${helperBillingMode(connection)} key. You do not need to provide the key, endpoint, operating system, or model catalog again.
|
|
727
|
+
|
|
728
|
+
Verified base URL: ${connection.baseUrl}
|
|
729
|
+
|
|
730
|
+
For automatic configuration, exit with \`/quit\`, run \`scalemax update\`, then run \`scalemax doctor\`.`;
|
|
731
|
+
}
|
|
732
|
+
return reply;
|
|
610
733
|
}
|
|
611
734
|
function printSessionHelp(write) {
|
|
612
|
-
write('Commands: /help shows this help; /quit exits. Ask only ScaleMax installation, configuration, authentication, or troubleshooting questions.');
|
|
735
|
+
write('Commands: /help shows this help; /status shows the authenticated non-secret connection details; /quit exits. Ask only ScaleMax installation, configuration, authentication, or troubleshooting questions.');
|
|
613
736
|
}
|
|
614
737
|
export async function helperBotCommand(args = [], home = homeDir(), dependencies = {}) {
|
|
615
738
|
const deps = { ...defaultDependencies, ...dependencies };
|
|
@@ -621,7 +744,15 @@ export async function helperBotCommand(args = [], home = homeDir(), dependencies
|
|
|
621
744
|
if (!validation.ok || !validation.baseUrl)
|
|
622
745
|
throw new Error(redactHelperSecrets(validation.error || 'Unable to validate the ScaleMax API key.', key));
|
|
623
746
|
const model = selectHelperModel(validation.models, options.model);
|
|
624
|
-
const connection = {
|
|
747
|
+
const connection = {
|
|
748
|
+
apiKey: key,
|
|
749
|
+
baseUrl: validation.baseUrl,
|
|
750
|
+
model,
|
|
751
|
+
platform: process.platform,
|
|
752
|
+
providerScope: validation.key?.provider_scope || 'both',
|
|
753
|
+
keyMode: validation.key?.mode,
|
|
754
|
+
availableModels: validation.models.map(item => item.id)
|
|
755
|
+
};
|
|
625
756
|
if (options.question) {
|
|
626
757
|
deps.write(await requestHelperReply(options.question, [], connection, deps.complete));
|
|
627
758
|
return;
|
|
@@ -629,7 +760,8 @@ export async function helperBotCommand(args = [], home = homeDir(), dependencies
|
|
|
629
760
|
if (!process.stdin.isTTY)
|
|
630
761
|
throw new Error('Interactive helper-bot requires a terminal. Pass a quoted question for non-interactive use.');
|
|
631
762
|
deps.write(chalk.cyan('ScaleMax Helper'));
|
|
632
|
-
deps.write(chalk.dim(
|
|
763
|
+
deps.write(chalk.dim(helperConnectionSummary(connection)));
|
|
764
|
+
deps.write(chalk.dim('The stored customer key is reused for Helper requests; it will not be requested or displayed. Type /help or /quit.'));
|
|
633
765
|
const reader = createInterface({ input: process.stdin, output: process.stdout });
|
|
634
766
|
const history = [];
|
|
635
767
|
try {
|
|
@@ -650,6 +782,10 @@ export async function helperBotCommand(args = [], home = homeDir(), dependencies
|
|
|
650
782
|
printSessionHelp(deps.write);
|
|
651
783
|
continue;
|
|
652
784
|
}
|
|
785
|
+
if (/^\/?status$/i.test(input)) {
|
|
786
|
+
deps.write(helperConnectionSummary(connection));
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
653
789
|
try {
|
|
654
790
|
const reply = await requestHelperReply(input, history, connection, deps.complete);
|
|
655
791
|
deps.write(reply);
|