ado-sync 0.1.55 → 0.1.57
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/README.md +39 -0
- package/dist/__tests__/regressions.test.d.ts +1 -0
- package/dist/__tests__/regressions.test.js +140 -0
- package/dist/__tests__/regressions.test.js.map +1 -0
- package/dist/ai/generate-spec.d.ts +11 -9
- package/dist/ai/generate-spec.js +116 -96
- package/dist/ai/generate-spec.js.map +1 -1
- package/dist/ai/summarizer.d.ts +5 -5
- package/dist/ai/summarizer.js +243 -135
- package/dist/ai/summarizer.js.map +1 -1
- package/dist/azure/test-cases.d.ts +10 -1
- package/dist/azure/test-cases.js +61 -25
- package/dist/azure/test-cases.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.js +7 -2
- package/dist/config.js.map +1 -1
- package/dist/issues/ado-bugs.js +7 -3
- package/dist/issues/ado-bugs.js.map +1 -1
- package/dist/mcp-server.js +51 -27
- package/dist/mcp-server.js.map +1 -1
- package/dist/parsers/javascript.js +2 -1
- package/dist/parsers/javascript.js.map +1 -1
- package/dist/sync/cache.js +3 -1
- package/dist/sync/cache.js.map +1 -1
- package/dist/sync/engine.d.ts +12 -1
- package/dist/sync/engine.js +226 -165
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/publish-results.js +64 -21
- package/dist/sync/publish-results.js.map +1 -1
- package/dist/sync/writeback.js +22 -5
- package/dist/sync/writeback.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/docs/advanced.md +17 -18
- package/docs/cli.md +74 -4
- package/docs/publish-test-results.md +3 -3
- package/mkdocs.yml +39 -0
- package/package.json +23 -14
- package/requirements-docs.txt +4 -0
- package/scripts/build_site.sh +6 -0
package/dist/ai/summarizer.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* dependencies, works fully offline.
|
|
15
15
|
*
|
|
16
16
|
* ollama — local LLM via Ollama REST API (http://localhost:11434).
|
|
17
|
-
* Model suggestion:
|
|
17
|
+
* Model suggestion: gemma-4-e4b-it.
|
|
18
18
|
*
|
|
19
19
|
* openai — OpenAI Chat Completions API (requires API key).
|
|
20
20
|
*
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Usage (engine.ts / CLI):
|
|
24
24
|
* const { title, description, steps } = await summarizeTest(test, localType, {
|
|
25
25
|
* provider: 'local',
|
|
26
|
-
* model: '/path/to/
|
|
26
|
+
* model: '/path/to/gemma-4-e4b-it-Q4_K_M.gguf',
|
|
27
27
|
* });
|
|
28
28
|
* test.title = title;
|
|
29
29
|
* test.description = description;
|
|
@@ -663,6 +663,9 @@ function parseAiResponse(raw, fallbackTitle) {
|
|
|
663
663
|
}
|
|
664
664
|
return { title, description, steps };
|
|
665
665
|
}
|
|
666
|
+
// ─── Shared dynamic import helper ────────────────────────────────────────────
|
|
667
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
668
|
+
const esmImport = new Function('m', 'return import(m)');
|
|
666
669
|
const llamaSessionCache = new Map();
|
|
667
670
|
async function getLlamaSession(modelPath) {
|
|
668
671
|
const cached = llamaSessionCache.get(modelPath);
|
|
@@ -704,82 +707,65 @@ async function localLlamaSummary(code, fallbackTitle, modelPath, contextContent)
|
|
|
704
707
|
}
|
|
705
708
|
}
|
|
706
709
|
async function ollamaSummary(code, fallbackTitle, model, baseUrl, contextContent) {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
throw new Error(`Ollama ${res.status}: ${await res.text()}`);
|
|
715
|
-
const data = await res.json();
|
|
716
|
-
return parseAiResponse(data.response ?? '', fallbackTitle);
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Fetch with automatic retry for transient errors:
|
|
720
|
-
* 503 — model container cold-starting (Hugging Face serverless inference)
|
|
721
|
-
* 429 — rate limit exceeded
|
|
722
|
-
* Retries up to `maxRetries` times with exponential backoff starting at `baseDelayMs`.
|
|
723
|
-
*/
|
|
724
|
-
async function fetchWithRetry(url, init, provider, maxRetries = 3, baseDelayMs = 5_000) {
|
|
725
|
-
let attempt = 0;
|
|
726
|
-
while (true) {
|
|
727
|
-
const res = await fetch(url, init);
|
|
728
|
-
if (res.status === 503 || res.status === 429) {
|
|
729
|
-
if (attempt >= maxRetries)
|
|
730
|
-
return res;
|
|
731
|
-
const retryAfter = res.headers.get('retry-after');
|
|
732
|
-
const delayMs = retryAfter
|
|
733
|
-
? parseInt(retryAfter, 10) * 1_000
|
|
734
|
-
: baseDelayMs * Math.pow(2, attempt);
|
|
735
|
-
const reason = res.status === 503 ? 'model loading' : 'rate limited';
|
|
736
|
-
process.stderr.write(` [ai-summary] ${provider} ${reason} — retrying in ${Math.round(delayMs / 1000)}s (${attempt + 1}/${maxRetries})\n`);
|
|
737
|
-
await new Promise(r => setTimeout(r, delayMs));
|
|
738
|
-
attempt++;
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
|
-
return res;
|
|
710
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
711
|
+
let Ollama;
|
|
712
|
+
try {
|
|
713
|
+
({ Ollama } = await esmImport('ollama'));
|
|
714
|
+
}
|
|
715
|
+
catch {
|
|
716
|
+
throw new Error("'ollama' provider requires the ollama package. Install it with: npm install ollama");
|
|
742
717
|
}
|
|
718
|
+
const client = new Ollama({ host: baseUrl });
|
|
719
|
+
const response = await client.chat({
|
|
720
|
+
model,
|
|
721
|
+
messages: [{ role: 'user', content: buildPrompt(code, contextContent) }],
|
|
722
|
+
});
|
|
723
|
+
return parseAiResponse(response.message?.content ?? '', fallbackTitle);
|
|
743
724
|
}
|
|
744
725
|
async function openaiSummary(code, fallbackTitle, model, apiKey, baseUrl, contextContent) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const
|
|
758
|
-
|
|
726
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
727
|
+
let OpenAI;
|
|
728
|
+
try {
|
|
729
|
+
({ OpenAI } = await esmImport('openai'));
|
|
730
|
+
}
|
|
731
|
+
catch {
|
|
732
|
+
throw new Error("'openai' provider requires the openai package. Install it with: npm install openai");
|
|
733
|
+
}
|
|
734
|
+
const client = new OpenAI({
|
|
735
|
+
apiKey,
|
|
736
|
+
...(baseUrl ? { baseURL: baseUrl.replace(/\/$/, '') } : {}),
|
|
737
|
+
});
|
|
738
|
+
const msg = await client.chat.completions.create({
|
|
739
|
+
model,
|
|
740
|
+
messages: [{ role: 'user', content: buildPrompt(code, contextContent) }],
|
|
741
|
+
temperature: 0,
|
|
742
|
+
max_tokens: 2048,
|
|
743
|
+
});
|
|
744
|
+
return parseAiResponse(msg.choices?.[0]?.message?.content ?? '', fallbackTitle);
|
|
759
745
|
}
|
|
760
746
|
async function anthropicSummary(code, fallbackTitle, model, apiKey, baseUrl, contextContent) {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
return parseAiResponse(
|
|
747
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
748
|
+
let Anthropic;
|
|
749
|
+
try {
|
|
750
|
+
({ default: Anthropic } = await esmImport('@anthropic-ai/sdk'));
|
|
751
|
+
}
|
|
752
|
+
catch {
|
|
753
|
+
throw new Error("'anthropic' provider requires @anthropic-ai/sdk. Install it with: npm install @anthropic-ai/sdk");
|
|
754
|
+
}
|
|
755
|
+
const client = new Anthropic({
|
|
756
|
+
apiKey,
|
|
757
|
+
...(baseUrl ? { baseURL: baseUrl.replace(/\/$/, '') } : {}),
|
|
758
|
+
});
|
|
759
|
+
const msg = await client.messages.create({
|
|
760
|
+
model,
|
|
761
|
+
max_tokens: 2048,
|
|
762
|
+
messages: [{ role: 'user', content: buildPrompt(code, contextContent) }],
|
|
763
|
+
});
|
|
764
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
765
|
+
return parseAiResponse(msg.content[0]?.text ?? '', fallbackTitle);
|
|
780
766
|
}
|
|
781
767
|
async function huggingfaceSummary(code, fallbackTitle, model, apiKey, contextContent) {
|
|
782
|
-
// Hugging Face OpenAI-compatible /v1 endpoint
|
|
768
|
+
// Hugging Face exposes an OpenAI-compatible /v1 endpoint — use the openai SDK with a custom baseURL
|
|
783
769
|
return openaiSummary(code, fallbackTitle, model, apiKey, 'https://api-inference.huggingface.co/v1', contextContent);
|
|
784
770
|
}
|
|
785
771
|
// ─── Bedrock helpers (retry + credential pre-flight) ─────────────────────────
|
|
@@ -863,26 +849,57 @@ async function bedrockSummary(code, fallbackTitle, model, region, contextContent
|
|
|
863
849
|
return parseAiResponse(raw, fallbackTitle);
|
|
864
850
|
}
|
|
865
851
|
async function azureaiSummary(code, fallbackTitle, model, apiKey, baseUrl, contextContent) {
|
|
866
|
-
//
|
|
867
|
-
let
|
|
868
|
-
|
|
869
|
-
|
|
852
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
853
|
+
let AzureOpenAI;
|
|
854
|
+
try {
|
|
855
|
+
({ AzureOpenAI } = await esmImport('openai'));
|
|
870
856
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
857
|
+
catch {
|
|
858
|
+
throw new Error("'azureai' provider requires the openai package. Install it with: npm install openai");
|
|
859
|
+
}
|
|
860
|
+
const client = new AzureOpenAI({
|
|
861
|
+
apiKey,
|
|
862
|
+
endpoint: baseUrl.replace(/\/$/, ''),
|
|
863
|
+
apiVersion: '2024-12-01-preview',
|
|
864
|
+
deployment: model,
|
|
865
|
+
});
|
|
866
|
+
const msg = await client.chat.completions.create({
|
|
867
|
+
model,
|
|
868
|
+
messages: [{ role: 'user', content: buildPrompt(code, contextContent) }],
|
|
869
|
+
temperature: 0,
|
|
870
|
+
max_tokens: 2048,
|
|
871
|
+
});
|
|
872
|
+
return parseAiResponse(msg.choices?.[0]?.message?.content ?? '', fallbackTitle);
|
|
873
|
+
}
|
|
874
|
+
async function githubSummary(code, fallbackTitle, model, apiKey, contextContent) {
|
|
875
|
+
// GitHub Models is OpenAI-compatible — delegate to openaiSummary with GitHub Models endpoint
|
|
876
|
+
return openaiSummary(code, fallbackTitle, model, apiKey, 'https://models.inference.ai.azure.com', contextContent);
|
|
877
|
+
}
|
|
878
|
+
async function azureinferenceSummary(code, fallbackTitle, model, apiKey, endpoint, contextContent) {
|
|
879
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
880
|
+
let ModelClient, AzureKeyCredential;
|
|
881
|
+
try {
|
|
882
|
+
({ default: ModelClient } = await esmImport('@azure-rest/ai-inference'));
|
|
883
|
+
({ AzureKeyCredential } = await esmImport('@azure/core-auth'));
|
|
884
|
+
}
|
|
885
|
+
catch {
|
|
886
|
+
throw new Error("'azureinference' provider requires @azure-rest/ai-inference and @azure/core-auth. " +
|
|
887
|
+
'Install with: npm install @azure-rest/ai-inference @azure/core-auth');
|
|
888
|
+
}
|
|
889
|
+
const client = ModelClient(endpoint.replace(/\/$/, ''), new AzureKeyCredential(apiKey));
|
|
890
|
+
const response = await client.path('/chat/completions').post({
|
|
891
|
+
body: {
|
|
892
|
+
model,
|
|
875
893
|
messages: [{ role: 'user', content: buildPrompt(code, contextContent) }],
|
|
876
894
|
temperature: 0,
|
|
877
895
|
max_tokens: 2048,
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
896
|
+
},
|
|
897
|
+
});
|
|
898
|
+
if (response.status !== '200') {
|
|
899
|
+
throw new Error(`Azure AI Inference ${response.status}: ${JSON.stringify(response.body)}`);
|
|
900
|
+
}
|
|
883
901
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
884
|
-
|
|
885
|
-
return parseAiResponse(data.choices?.[0]?.message?.content ?? '', fallbackTitle);
|
|
902
|
+
return parseAiResponse(response.body.choices?.[0]?.message?.content ?? '', fallbackTitle);
|
|
886
903
|
}
|
|
887
904
|
function resolveEnvVar(value) {
|
|
888
905
|
if (value.startsWith('$'))
|
|
@@ -942,51 +959,86 @@ async function analyzeFailure(testName, errorMessage, stackTrace, opts) {
|
|
|
942
959
|
let raw = '';
|
|
943
960
|
switch (opts.provider) {
|
|
944
961
|
case 'ollama': {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
962
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
963
|
+
let OllamaFA;
|
|
964
|
+
try {
|
|
965
|
+
({ Ollama: OllamaFA } = await esmImport('ollama'));
|
|
966
|
+
}
|
|
967
|
+
catch {
|
|
968
|
+
throw new Error("ollama package not installed");
|
|
969
|
+
}
|
|
970
|
+
const ollamaClient = new OllamaFA({ host: opts.baseUrl ?? 'http://localhost:11434' });
|
|
971
|
+
const ollamaResp = await ollamaClient.chat({
|
|
972
|
+
model: opts.model ?? 'gemma-4-e4b-it',
|
|
973
|
+
messages: [{ role: 'user', content: prompt }],
|
|
974
|
+
});
|
|
975
|
+
raw = ollamaResp.message?.content ?? '';
|
|
954
976
|
break;
|
|
955
977
|
}
|
|
956
978
|
case 'openai': {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
979
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
980
|
+
let OpenAI;
|
|
981
|
+
try {
|
|
982
|
+
({ OpenAI } = await esmImport('openai'));
|
|
983
|
+
}
|
|
984
|
+
catch {
|
|
985
|
+
throw new Error("openai package not installed");
|
|
986
|
+
}
|
|
987
|
+
const openaiClient = new OpenAI({
|
|
988
|
+
apiKey: resolveEnvVar(opts.apiKey ?? ''),
|
|
989
|
+
...(opts.baseUrl ? { baseURL: opts.baseUrl.replace(/\/$/, '') } : {}),
|
|
990
|
+
});
|
|
991
|
+
const openaiMsg = await openaiClient.chat.completions.create({
|
|
992
|
+
model: opts.model ?? 'gpt-4o-mini',
|
|
993
|
+
messages: [{ role: 'user', content: prompt }],
|
|
994
|
+
temperature: 0,
|
|
995
|
+
max_tokens: 256,
|
|
996
|
+
});
|
|
997
|
+
raw = openaiMsg.choices?.[0]?.message?.content ?? '';
|
|
966
998
|
break;
|
|
967
999
|
}
|
|
968
1000
|
case 'anthropic': {
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1001
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1002
|
+
let Anthropic;
|
|
1003
|
+
try {
|
|
1004
|
+
({ default: Anthropic } = await esmImport('@anthropic-ai/sdk'));
|
|
1005
|
+
}
|
|
1006
|
+
catch {
|
|
1007
|
+
throw new Error("@anthropic-ai/sdk package not installed");
|
|
1008
|
+
}
|
|
1009
|
+
const anthropicClient = new Anthropic({
|
|
1010
|
+
apiKey: resolveEnvVar(opts.apiKey ?? ''),
|
|
1011
|
+
...(opts.baseUrl ? { baseURL: opts.baseUrl.replace(/\/$/, '') } : {}),
|
|
1012
|
+
});
|
|
1013
|
+
const anthropicMsg = await anthropicClient.messages.create({
|
|
1014
|
+
model: opts.model ?? 'claude-haiku-4-5-20251001',
|
|
1015
|
+
max_tokens: 1024,
|
|
1016
|
+
messages: [{ role: 'user', content: prompt }],
|
|
1017
|
+
});
|
|
1018
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1019
|
+
raw = anthropicMsg.content[0]?.text ?? '';
|
|
978
1020
|
break;
|
|
979
1021
|
}
|
|
980
1022
|
case 'huggingface': {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
throw new Error(
|
|
989
|
-
|
|
1023
|
+
// Hugging Face OpenAI-compatible endpoint via openai SDK
|
|
1024
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1025
|
+
let OpenAIhf;
|
|
1026
|
+
try {
|
|
1027
|
+
({ OpenAI: OpenAIhf } = await esmImport('openai'));
|
|
1028
|
+
}
|
|
1029
|
+
catch {
|
|
1030
|
+
throw new Error("openai package not installed");
|
|
1031
|
+
}
|
|
1032
|
+
const hfClient = new OpenAIhf({
|
|
1033
|
+
apiKey: resolveEnvVar(opts.apiKey ?? ''),
|
|
1034
|
+
baseURL: 'https://api-inference.huggingface.co/v1',
|
|
1035
|
+
});
|
|
1036
|
+
const hfMsg = await hfClient.chat.completions.create({
|
|
1037
|
+
model: opts.model,
|
|
1038
|
+
messages: [{ role: 'user', content: prompt }],
|
|
1039
|
+
max_tokens: 256,
|
|
1040
|
+
});
|
|
1041
|
+
raw = hfMsg.choices?.[0]?.message?.content ?? '';
|
|
990
1042
|
break;
|
|
991
1043
|
}
|
|
992
1044
|
case 'bedrock': {
|
|
@@ -1014,19 +1066,69 @@ async function analyzeFailure(testName, errorMessage, stackTrace, opts) {
|
|
|
1014
1066
|
case 'azureai': {
|
|
1015
1067
|
if (!opts.baseUrl)
|
|
1016
1068
|
break;
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1069
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1070
|
+
let AzureOpenAI;
|
|
1071
|
+
try {
|
|
1072
|
+
({ AzureOpenAI } = await esmImport('openai'));
|
|
1073
|
+
}
|
|
1074
|
+
catch {
|
|
1075
|
+
throw new Error("openai package not installed");
|
|
1076
|
+
}
|
|
1077
|
+
const azureClient = new AzureOpenAI({
|
|
1078
|
+
apiKey: resolveEnvVar(opts.apiKey ?? ''),
|
|
1079
|
+
endpoint: opts.baseUrl.replace(/\/$/, ''),
|
|
1080
|
+
apiVersion: '2024-12-01-preview',
|
|
1081
|
+
deployment: opts.model ?? 'gpt-4o',
|
|
1082
|
+
});
|
|
1083
|
+
const azureMsg = await azureClient.chat.completions.create({
|
|
1084
|
+
model: opts.model ?? 'gpt-4o',
|
|
1085
|
+
messages: [{ role: 'user', content: prompt }],
|
|
1086
|
+
temperature: 0,
|
|
1087
|
+
max_tokens: 256,
|
|
1088
|
+
});
|
|
1089
|
+
raw = azureMsg.choices?.[0]?.message?.content ?? '';
|
|
1090
|
+
break;
|
|
1091
|
+
}
|
|
1092
|
+
case 'github': {
|
|
1093
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1094
|
+
let OpenAIgh;
|
|
1095
|
+
try {
|
|
1096
|
+
({ OpenAI: OpenAIgh } = await esmImport('openai'));
|
|
1097
|
+
}
|
|
1098
|
+
catch {
|
|
1099
|
+
throw new Error("openai package not installed");
|
|
1100
|
+
}
|
|
1101
|
+
const ghClient = new OpenAIgh({
|
|
1102
|
+
apiKey: resolveEnvVar(opts.apiKey ?? process.env['GITHUB_TOKEN'] ?? ''),
|
|
1103
|
+
baseURL: 'https://models.inference.ai.azure.com',
|
|
1104
|
+
});
|
|
1105
|
+
const ghMsg = await ghClient.chat.completions.create({
|
|
1106
|
+
model: opts.model ?? 'gpt-4o',
|
|
1107
|
+
messages: [{ role: 'user', content: prompt }],
|
|
1108
|
+
temperature: 0,
|
|
1109
|
+
max_tokens: 256,
|
|
1110
|
+
});
|
|
1111
|
+
raw = ghMsg.choices?.[0]?.message?.content ?? '';
|
|
1112
|
+
break;
|
|
1113
|
+
}
|
|
1114
|
+
case 'azureinference': {
|
|
1115
|
+
if (!opts.baseUrl)
|
|
1116
|
+
break;
|
|
1117
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1118
|
+
let ModelClientFA, AzureKeyCredentialFA;
|
|
1119
|
+
try {
|
|
1120
|
+
({ default: ModelClientFA } = await esmImport('@azure-rest/ai-inference'));
|
|
1121
|
+
({ AzureKeyCredential: AzureKeyCredentialFA } = await esmImport('@azure/core-auth'));
|
|
1020
1122
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
raw =
|
|
1123
|
+
catch {
|
|
1124
|
+
throw new Error("@azure-rest/ai-inference package not installed");
|
|
1125
|
+
}
|
|
1126
|
+
const aiClient = ModelClientFA(opts.baseUrl.replace(/\/$/, ''), new AzureKeyCredentialFA(resolveEnvVar(opts.apiKey ?? '')));
|
|
1127
|
+
const aiResp = await aiClient.path('/chat/completions').post({
|
|
1128
|
+
body: { model: opts.model ?? 'gpt-4o', messages: [{ role: 'user', content: prompt }], temperature: 0, max_tokens: 256 },
|
|
1129
|
+
});
|
|
1130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1131
|
+
raw = aiResp.body.choices?.[0]?.message?.content ?? '';
|
|
1030
1132
|
break;
|
|
1031
1133
|
}
|
|
1032
1134
|
default:
|
|
@@ -1072,7 +1174,7 @@ async function summarizeTest(test, localType, opts) {
|
|
|
1072
1174
|
case 'local':
|
|
1073
1175
|
return await localLlamaSummary(body, fallbackTitle, opts.model, ctx);
|
|
1074
1176
|
case 'ollama':
|
|
1075
|
-
return await ollamaSummary(body, fallbackTitle, opts.model ?? '
|
|
1177
|
+
return await ollamaSummary(body, fallbackTitle, opts.model ?? 'gemma-4-e4b-it', opts.baseUrl ?? 'http://localhost:11434', ctx);
|
|
1076
1178
|
case 'openai':
|
|
1077
1179
|
return await openaiSummary(body, fallbackTitle, opts.model ?? 'gpt-4o-mini', resolveEnvVar(opts.apiKey ?? ''), opts.baseUrl ?? 'https://api.openai.com/v1', ctx);
|
|
1078
1180
|
case 'anthropic':
|
|
@@ -1087,6 +1189,12 @@ async function summarizeTest(test, localType, opts) {
|
|
|
1087
1189
|
if (!opts.baseUrl)
|
|
1088
1190
|
throw new Error('azureai provider requires --ai-url <azure-endpoint>');
|
|
1089
1191
|
return await azureaiSummary(body, fallbackTitle, opts.model ?? 'gpt-4o', resolveEnvVar(opts.apiKey ?? ''), opts.baseUrl, ctx);
|
|
1192
|
+
case 'github':
|
|
1193
|
+
return await githubSummary(body, fallbackTitle, opts.model ?? 'gpt-4o', resolveEnvVar(opts.apiKey ?? process.env['GITHUB_TOKEN'] ?? ''), ctx);
|
|
1194
|
+
case 'azureinference':
|
|
1195
|
+
if (!opts.baseUrl)
|
|
1196
|
+
throw new Error('azureinference provider requires --ai-url <endpoint>');
|
|
1197
|
+
return await azureinferenceSummary(body, fallbackTitle, opts.model ?? 'gpt-4o', resolveEnvVar(opts.apiKey ?? ''), opts.baseUrl, ctx);
|
|
1090
1198
|
}
|
|
1091
1199
|
}
|
|
1092
1200
|
catch (err) {
|