@johnowennixon/diffdash 1.6.1 → 1.8.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.
- package/README.md +18 -20
- package/dist/package.json +25 -32
- package/dist/src/lib_abort.js +2 -2
- package/dist/src/lib_char_smart.js +4 -0
- package/dist/src/lib_datetime.js +4 -1
- package/dist/src/lib_debug.js +1 -0
- package/dist/src/lib_diffdash_cli.js +5 -5
- package/dist/src/lib_diffdash_config.js +35 -15
- package/dist/src/lib_diffdash_llm.js +8 -14
- package/dist/src/lib_diffdash_sequence.js +18 -18
- package/dist/src/lib_file_io.js +13 -0
- package/dist/src/lib_file_is.js +34 -0
- package/dist/src/lib_git_message_generate.js +12 -12
- package/dist/src/lib_git_message_prompt.js +25 -20
- package/dist/src/lib_git_message_schema.js +3 -3
- package/dist/src/lib_json5.js +4 -0
- package/dist/src/lib_llm_access.js +20 -54
- package/dist/src/{lib_llm_provider.js → lib_llm_api.js} +11 -29
- package/dist/src/lib_llm_chat.js +62 -24
- package/dist/src/lib_llm_config.js +9 -19
- package/dist/src/lib_llm_list.js +11 -9
- package/dist/src/lib_llm_model.js +383 -202
- package/dist/src/lib_llm_results.js +47 -0
- package/dist/src/lib_tell.js +11 -10
- package/dist/src/lib_tui_none.js +15 -0
- package/dist/src/lib_tui_number.js +22 -0
- package/dist/src/lib_tui_quote.js +26 -0
- package/dist/src/lib_tui_table.js +13 -5
- package/package.json +25 -32
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import { LF } from "./lib_char_control.js";
|
|
2
2
|
import { EMPTY } from "./lib_char_empty.js";
|
|
3
|
+
const LF_LF = LF + LF;
|
|
3
4
|
const portion_role = `
|
|
4
5
|
Your role is to generate a Git commit message in conversational English.
|
|
5
6
|
The user does not want Conventional Commits - the summary line must be a normal sentence.
|
|
6
|
-
`.trim() +
|
|
7
|
+
`.trim() + LF_LF;
|
|
7
8
|
const portion_inputs = `
|
|
8
9
|
The user will send you a <diffstat> block, the output of a 'git diff --staged --stat' command.
|
|
9
10
|
The user will send you a <diff> block, the output of a 'git diff --staged' command.
|
|
10
|
-
`.trim() +
|
|
11
|
+
`.trim() + LF_LF;
|
|
11
12
|
const portion_reminders = `
|
|
12
13
|
Some reminders of how diffs work:
|
|
13
14
|
- Lines that start with a single plus sign have been added to the file.
|
|
14
15
|
- Lines that start with a single minus sign have been removed from the file.
|
|
15
16
|
- Lines that start with @@ indicate a jump to a different section of the file - you can not see the code in these gaps.
|
|
16
|
-
`.trim() +
|
|
17
|
+
`.trim() + LF_LF;
|
|
17
18
|
const portion_format_structured = `
|
|
18
19
|
You must output in the following format (this will be forced):
|
|
19
20
|
- summary_line: a single sentence giving a concise summary of the changes.
|
|
20
21
|
- extra_lines: additional sentences giving more information about the changes.
|
|
21
|
-
`.trim() +
|
|
22
|
+
`.trim() + LF_LF;
|
|
22
23
|
const portion_format_unstructured = `
|
|
23
24
|
You must output in the following format - without any preamble or conclusion:
|
|
24
25
|
- First line: a single sentence giving a concise summary of the changes.
|
|
25
26
|
- Second line: completely blank - not even any spaces.
|
|
26
27
|
- Then an unordered list (with a dash prefix) of additional sentences giving more information about the changes.
|
|
27
28
|
- And nothing else.
|
|
28
|
-
`.trim() +
|
|
29
|
-
|
|
29
|
+
`.trim() + LF_LF;
|
|
30
|
+
const portion_format = (has_structured_json) => {
|
|
30
31
|
return has_structured_json ? portion_format_structured : portion_format_unstructured;
|
|
31
|
-
}
|
|
32
|
+
};
|
|
32
33
|
const portion_instructions = `
|
|
33
34
|
Use the imperative mood and present tense.
|
|
34
35
|
Please write in full sentences that start with a capital letter.
|
|
@@ -42,19 +43,23 @@ Don't assume the change is always an improvement - it might be making things wor
|
|
|
42
43
|
The number of additional sentences should depend upon the complexity of the change.
|
|
43
44
|
A simple change needs only two additional sentences scaling up to a complex change with five additional sentences.
|
|
44
45
|
If there are a lot of changes, you will need to summarize even more.
|
|
45
|
-
`.trim() +
|
|
46
|
+
`.trim() + LF_LF;
|
|
47
|
+
const portion_extra = (extra_prompts) => {
|
|
48
|
+
return extra_prompts && extra_prompts.length > 0 ? extra_prompts.map((s) => s.trim).join(LF) + LF_LF : EMPTY;
|
|
49
|
+
};
|
|
46
50
|
const portion_final = `
|
|
47
51
|
Everything you write will be checked for validity and then saved directly to Git - it will not be reviewed by a human.
|
|
48
52
|
Therefore, you must just output the Git message itself without any introductory or concluding sections.
|
|
49
|
-
`.trim() +
|
|
50
|
-
export function git_message_get_system_prompt({ has_structured_json }) {
|
|
53
|
+
`.trim() + LF_LF;
|
|
54
|
+
export function git_message_get_system_prompt({ has_structured_json, inputs, }) {
|
|
51
55
|
let system_prompt = EMPTY;
|
|
52
|
-
system_prompt += portion_role
|
|
53
|
-
system_prompt += portion_inputs
|
|
54
|
-
system_prompt += portion_reminders
|
|
55
|
-
system_prompt += portion_format(has_structured_json)
|
|
56
|
-
system_prompt += portion_instructions
|
|
57
|
-
system_prompt +=
|
|
56
|
+
system_prompt += portion_role;
|
|
57
|
+
system_prompt += portion_inputs;
|
|
58
|
+
system_prompt += portion_reminders;
|
|
59
|
+
system_prompt += portion_format(has_structured_json);
|
|
60
|
+
system_prompt += portion_instructions;
|
|
61
|
+
system_prompt += portion_extra(inputs.extra_prompts);
|
|
62
|
+
system_prompt += portion_final;
|
|
58
63
|
return system_prompt.trim();
|
|
59
64
|
}
|
|
60
65
|
export function git_message_get_user_prompt({ has_structured_json, inputs, max_length, }) {
|
|
@@ -62,11 +67,11 @@ export function git_message_get_user_prompt({ has_structured_json, inputs, max_l
|
|
|
62
67
|
const truncate = diffstat.length + diff.length > max_length;
|
|
63
68
|
const diff_truncated = truncate ? diff.slice(0, max_length - diffstat.length) + LF : diff;
|
|
64
69
|
let user_prompt = EMPTY;
|
|
65
|
-
user_prompt += "<diffstat>" + LF + diffstat + "</diffstat>" +
|
|
66
|
-
user_prompt += "<diff>" + LF + diff_truncated + "</diff>" +
|
|
70
|
+
user_prompt += "<diffstat>" + LF + diffstat + "</diffstat>" + LF_LF;
|
|
71
|
+
user_prompt += "<diff>" + LF + diff_truncated + "</diff>" + LF_LF;
|
|
67
72
|
if (truncate) {
|
|
68
|
-
user_prompt += "Please note: the Diff above has been truncated" +
|
|
73
|
+
user_prompt += "Please note: the Diff above has been truncated" + LF_LF;
|
|
69
74
|
}
|
|
70
|
-
user_prompt += portion_format(has_structured_json)
|
|
75
|
+
user_prompt += portion_format(has_structured_json);
|
|
71
76
|
return user_prompt.trim();
|
|
72
77
|
}
|
|
@@ -7,10 +7,10 @@ export const git_message_schema = z.object({
|
|
|
7
7
|
.array(z.string().describe("Another sentence giving more information about the changes."))
|
|
8
8
|
.describe("More information about the changes."),
|
|
9
9
|
});
|
|
10
|
-
export function git_message_schema_format(
|
|
10
|
+
export function git_message_schema_format(git_message_object) {
|
|
11
11
|
return [
|
|
12
|
-
|
|
12
|
+
git_message_object.summary_line,
|
|
13
13
|
EMPTY, // Empty line
|
|
14
|
-
...
|
|
14
|
+
...git_message_object.extra_lines.map((line) => (line.startsWith("- ") ? line : `- ${line}`)),
|
|
15
15
|
].join(LF);
|
|
16
16
|
}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { abort_with_error } from "./lib_abort.js";
|
|
2
2
|
import { COMMA } from "./lib_char_punctuation.js";
|
|
3
|
+
import { llm_api_get_api_key, llm_api_get_api_key_env } from "./lib_llm_api.js";
|
|
3
4
|
import { llm_model_find_detail } from "./lib_llm_model.js";
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
export function llm_access_available({ llm_model_details, llm_model_name, llm_include, llm_excludes, }) {
|
|
6
|
+
const detail = llm_model_find_detail({ llm_model_details, llm_model_name });
|
|
7
|
+
const { llm_api_code } = detail;
|
|
8
|
+
if (llm_api_get_api_key(llm_api_code) === null) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (llm_include) {
|
|
12
|
+
if (!(llm_model_name.includes(llm_include) || llm_include === llm_api_code)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
6
16
|
if (llm_excludes) {
|
|
7
17
|
const llm_excludes_array = llm_excludes.split(COMMA).map((exclude) => exclude.trim());
|
|
8
18
|
for (const llm_exclude of llm_excludes_array) {
|
|
@@ -11,59 +21,15 @@ export function llm_access_available({ llm_model_details, llm_model_name, llm_ex
|
|
|
11
21
|
}
|
|
12
22
|
}
|
|
13
23
|
}
|
|
14
|
-
|
|
15
|
-
const { llm_provider, llm_model_code_direct, llm_model_code_requesty, llm_model_code_openrouter } = detail;
|
|
16
|
-
if (llm_model_code_direct !== null && llm_provider !== null) {
|
|
17
|
-
if (llm_provider_get_api_key(llm_provider)) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (llm_model_code_openrouter !== null) {
|
|
22
|
-
if (llm_provider_get_api_key("openrouter")) {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (llm_model_code_requesty !== null) {
|
|
27
|
-
if (llm_provider_get_api_key("requesty")) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return false;
|
|
24
|
+
return true;
|
|
32
25
|
}
|
|
33
|
-
export function llm_access_get({ llm_model_details, llm_model_name,
|
|
26
|
+
export function llm_access_get({ llm_model_details, llm_model_name, }) {
|
|
34
27
|
const detail = llm_model_find_detail({ llm_model_details, llm_model_name });
|
|
35
|
-
const {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return { llm_model_code: llm_model_code_direct, llm_provider, llm_api_key };
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (llm_model_code_openrouter !== null) {
|
|
45
|
-
const llm_api_key = llm_provider_get_api_key("openrouter");
|
|
46
|
-
if (llm_api_key) {
|
|
47
|
-
return { llm_model_code: llm_model_code_openrouter, llm_provider: "openrouter", llm_api_key };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (llm_model_code_requesty !== null) {
|
|
51
|
-
const llm_api_key = llm_provider_get_api_key("requesty");
|
|
52
|
-
if (llm_api_key) {
|
|
53
|
-
return { llm_model_code: llm_model_code_requesty, llm_provider: "requesty", llm_api_key };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (llm_model_code_direct !== null && llm_provider !== null) {
|
|
57
|
-
const llm_api_key = llm_provider_get_api_key(llm_provider);
|
|
58
|
-
if (llm_api_key) {
|
|
59
|
-
return { llm_model_code: llm_model_code_direct, llm_provider, llm_api_key };
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const env_openrouter = llm_provider_get_api_key_env("openrouter");
|
|
63
|
-
const env_requesty = llm_provider_get_api_key_env("requesty");
|
|
64
|
-
if (llm_provider !== null) {
|
|
65
|
-
const env_provider = llm_provider_get_api_key_env(llm_provider);
|
|
66
|
-
abort_with_error(`Please set environment variable ${env_provider}, ${env_openrouter} or ${env_requesty}`);
|
|
28
|
+
const { llm_api_code, llm_model_code } = detail;
|
|
29
|
+
const llm_api_key = llm_api_get_api_key(llm_api_code);
|
|
30
|
+
if (!llm_api_key) {
|
|
31
|
+
const env_name = llm_api_get_api_key_env(llm_api_code);
|
|
32
|
+
abort_with_error(`Please set environment variable ${env_name}`);
|
|
67
33
|
}
|
|
68
|
-
|
|
34
|
+
return { llm_model_code, llm_api_code, llm_api_key };
|
|
69
35
|
}
|
|
@@ -3,26 +3,10 @@ import { createDeepSeek } from "@ai-sdk/deepseek";
|
|
|
3
3
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
4
4
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
5
5
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
6
|
-
import { createRequesty } from "@requesty/ai-sdk";
|
|
7
6
|
import { abort_with_error } from "./lib_abort.js";
|
|
8
7
|
import { env_get } from "./lib_env.js";
|
|
9
|
-
export function
|
|
10
|
-
switch (
|
|
11
|
-
case "anthropic":
|
|
12
|
-
case "deepseek":
|
|
13
|
-
case "google":
|
|
14
|
-
case "openai":
|
|
15
|
-
return "direct";
|
|
16
|
-
case "requesty":
|
|
17
|
-
return "via Requesty";
|
|
18
|
-
case "openrouter":
|
|
19
|
-
return "via OpenRouter";
|
|
20
|
-
default:
|
|
21
|
-
abort_with_error("Unknown LLM provider");
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export function llm_provider_get_api_key_env(llm_provider) {
|
|
25
|
-
switch (llm_provider) {
|
|
8
|
+
export function llm_api_get_api_key_env(llm_api_code) {
|
|
9
|
+
switch (llm_api_code) {
|
|
26
10
|
case "anthropic":
|
|
27
11
|
return "ANTHROPIC_API_KEY";
|
|
28
12
|
case "deepseek":
|
|
@@ -31,20 +15,19 @@ export function llm_provider_get_api_key_env(llm_provider) {
|
|
|
31
15
|
return "GEMINI_API_KEY";
|
|
32
16
|
case "openai":
|
|
33
17
|
return "OPENAI_API_KEY";
|
|
34
|
-
case "requesty":
|
|
35
|
-
return "REQUESTY_API_KEY";
|
|
36
18
|
case "openrouter":
|
|
37
19
|
return "OPENROUTER_API_KEY";
|
|
38
20
|
default:
|
|
39
|
-
abort_with_error("Unknown LLM
|
|
21
|
+
abort_with_error("Unknown LLM API");
|
|
40
22
|
}
|
|
41
23
|
}
|
|
42
|
-
export function
|
|
43
|
-
const env =
|
|
24
|
+
export function llm_api_get_api_key(llm_api_code) {
|
|
25
|
+
const env = llm_api_get_api_key_env(llm_api_code);
|
|
44
26
|
return env_get(env);
|
|
45
27
|
}
|
|
46
|
-
|
|
47
|
-
|
|
28
|
+
// eslint-disable-next-line sonarjs/function-return-type
|
|
29
|
+
export function llm_api_get_ai_sdk_language_model({ llm_model_code, llm_api_code, llm_api_key, }) {
|
|
30
|
+
switch (llm_api_code) {
|
|
48
31
|
case "anthropic":
|
|
49
32
|
return createAnthropic({ apiKey: llm_api_key })(llm_model_code);
|
|
50
33
|
case "deepseek":
|
|
@@ -53,11 +36,10 @@ export function llm_provider_get_ai_sdk_language_model({ llm_model_code, llm_pro
|
|
|
53
36
|
return createGoogleGenerativeAI({ apiKey: llm_api_key })(llm_model_code);
|
|
54
37
|
case "openai":
|
|
55
38
|
return createOpenAI({ apiKey: llm_api_key })(llm_model_code);
|
|
56
|
-
case "
|
|
57
|
-
return createRequesty({ apiKey: llm_api_key })(llm_model_code);
|
|
58
|
-
case "openrouter":
|
|
39
|
+
case "openrouter": {
|
|
59
40
|
return createOpenRouter({ apiKey: llm_api_key })(llm_model_code);
|
|
41
|
+
}
|
|
60
42
|
default:
|
|
61
|
-
abort_with_error("Unknown LLM
|
|
43
|
+
abort_with_error("Unknown LLM API");
|
|
62
44
|
}
|
|
63
45
|
}
|
package/dist/src/lib_llm_chat.js
CHANGED
|
@@ -1,66 +1,104 @@
|
|
|
1
|
-
import { generateObject, generateText } from "ai";
|
|
1
|
+
import { generateObject, generateText, stepCountIs } from "ai";
|
|
2
2
|
import { debug_channels, debug_inspect_when } from "./lib_debug.js";
|
|
3
|
+
import { Duration } from "./lib_duration.js";
|
|
3
4
|
import { env_get_empty, env_get_substitute } from "./lib_env.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { error_get_text } from "./lib_error.js";
|
|
6
|
+
import { llm_api_get_ai_sdk_language_model } from "./lib_llm_api.js";
|
|
7
|
+
import { parse_int, parse_int_or_undefined } from "./lib_parse_number.js";
|
|
8
|
+
import { tell_debug } from "./lib_tell.js";
|
|
9
|
+
import { tui_block_string } from "./lib_tui_block.js";
|
|
6
10
|
function llm_chat_get_parameters() {
|
|
7
11
|
return {
|
|
8
|
-
|
|
9
|
-
temperature: parse_float_or_undefined(env_get_substitute("lib_llm_chat_temperature", "0.6")),
|
|
12
|
+
max_output_tokens: parse_int_or_undefined(env_get_empty("lib_llm_chat_max_output_tokens")),
|
|
10
13
|
timeout: parse_int(env_get_substitute("lib_llm_chat_timeout", "60")),
|
|
11
14
|
};
|
|
12
15
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
function llm_chat_debug_prompts({ llm_model_name, system_prompt, user_prompt, }) {
|
|
17
|
+
if (debug_channels.llm_prompts) {
|
|
18
|
+
const teller = tell_debug;
|
|
19
|
+
if (system_prompt) {
|
|
20
|
+
tui_block_string({ teller, title: `LLM system prompt (for ${llm_model_name}):`, content: system_prompt });
|
|
21
|
+
}
|
|
22
|
+
tui_block_string({ teller, title: `LLM user prompt (for ${llm_model_name}):`, content: user_prompt });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function llm_chat_generate_text({ llm_config, system_prompt, user_prompt, tools, max_steps, min_steps, }) {
|
|
26
|
+
const { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key } = llm_config;
|
|
27
|
+
llm_chat_debug_prompts({ system_prompt, user_prompt, llm_model_name });
|
|
28
|
+
const ai_sdk_language_model = llm_api_get_ai_sdk_language_model({
|
|
16
29
|
llm_model_code,
|
|
17
|
-
|
|
30
|
+
llm_api_code,
|
|
18
31
|
llm_api_key,
|
|
19
32
|
});
|
|
20
|
-
const {
|
|
33
|
+
const { recommended_temperature, provider_options } = llm_model_detail;
|
|
34
|
+
const temperature = recommended_temperature;
|
|
35
|
+
const { max_output_tokens, timeout } = llm_chat_get_parameters();
|
|
21
36
|
const llm_inputs = {
|
|
22
37
|
model: ai_sdk_language_model,
|
|
23
38
|
system: system_prompt,
|
|
24
39
|
prompt: user_prompt,
|
|
25
40
|
tools,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
maxTokens: max_tokens,
|
|
41
|
+
stopWhen: max_steps === undefined ? undefined : stepCountIs(max_steps),
|
|
42
|
+
maxOutputTokens: max_output_tokens,
|
|
29
43
|
temperature,
|
|
44
|
+
providerOptions: provider_options,
|
|
30
45
|
abortSignal: AbortSignal.timeout(timeout * 1000),
|
|
31
46
|
};
|
|
32
|
-
debug_inspect_when(debug_channels.llm_inputs, llm_inputs, `
|
|
47
|
+
debug_inspect_when(debug_channels.llm_inputs, llm_inputs, `LLM inputs object (for ${llm_model_name})`);
|
|
33
48
|
// This is liable to throw an error
|
|
34
49
|
const llm_outputs = await generateText(llm_inputs);
|
|
35
|
-
debug_inspect_when(debug_channels.llm_outputs, llm_outputs, `
|
|
50
|
+
debug_inspect_when(debug_channels.llm_outputs, llm_outputs, `LLM outputs object (for ${llm_model_name})`);
|
|
36
51
|
if (min_steps !== undefined && llm_outputs.steps.length < min_steps) {
|
|
37
52
|
throw new Error("Too few steps taken");
|
|
38
53
|
}
|
|
39
54
|
if (max_steps !== undefined && llm_outputs.steps.length === max_steps) {
|
|
40
55
|
throw new Error("Too many steps taken");
|
|
41
56
|
}
|
|
42
|
-
|
|
57
|
+
const { text: generated_text, reasoningText: reasoning_text, totalUsage: total_usage, providerMetadata: provider_metadata, } = llm_outputs;
|
|
58
|
+
return { generated_text, reasoning_text, total_usage, provider_metadata };
|
|
59
|
+
}
|
|
60
|
+
export async function llm_chat_generate_text_result({ llm_config, system_prompt, user_prompt, }) {
|
|
61
|
+
const duration = new Duration();
|
|
62
|
+
duration.start();
|
|
63
|
+
try {
|
|
64
|
+
const outputs = await llm_chat_generate_text({ llm_config, system_prompt, user_prompt });
|
|
65
|
+
duration.stop();
|
|
66
|
+
const seconds = duration.seconds_rounded();
|
|
67
|
+
return { llm_config, seconds, error_text: null, outputs };
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
duration.stop();
|
|
71
|
+
const seconds = duration.seconds_rounded();
|
|
72
|
+
const error_text = error_get_text(error);
|
|
73
|
+
return { llm_config, seconds, error_text, outputs: null };
|
|
74
|
+
}
|
|
43
75
|
}
|
|
44
76
|
export async function llm_chat_generate_object({ llm_config, user_prompt, system_prompt, schema, }) {
|
|
45
|
-
const { llm_model_name,
|
|
46
|
-
|
|
77
|
+
const { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key } = llm_config;
|
|
78
|
+
llm_chat_debug_prompts({ system_prompt, user_prompt, llm_model_name });
|
|
79
|
+
const ai_sdk_language_model = llm_api_get_ai_sdk_language_model({
|
|
47
80
|
llm_model_code,
|
|
48
|
-
|
|
81
|
+
llm_api_code,
|
|
49
82
|
llm_api_key,
|
|
50
83
|
});
|
|
51
|
-
const {
|
|
84
|
+
const { recommended_temperature, provider_options } = llm_model_detail;
|
|
85
|
+
const temperature = recommended_temperature;
|
|
86
|
+
const { max_output_tokens, timeout } = llm_chat_get_parameters();
|
|
52
87
|
const llm_inputs = {
|
|
53
88
|
model: ai_sdk_language_model,
|
|
54
89
|
system: system_prompt,
|
|
55
90
|
prompt: user_prompt,
|
|
91
|
+
output: "object",
|
|
56
92
|
schema,
|
|
57
|
-
|
|
93
|
+
maxOutputTokens: max_output_tokens,
|
|
58
94
|
temperature,
|
|
95
|
+
providerOptions: provider_options,
|
|
59
96
|
abortSignal: AbortSignal.timeout(timeout * 1000),
|
|
60
97
|
};
|
|
61
|
-
debug_inspect_when(debug_channels.llm_inputs, llm_inputs, `
|
|
98
|
+
debug_inspect_when(debug_channels.llm_inputs, llm_inputs, `LLM inputs object (for ${llm_model_name})`);
|
|
62
99
|
// This is liable to throw an error
|
|
63
100
|
const llm_outputs = await generateObject(llm_inputs);
|
|
64
|
-
debug_inspect_when(debug_channels.llm_outputs, llm_outputs, `
|
|
65
|
-
|
|
101
|
+
debug_inspect_when(debug_channels.llm_outputs, llm_outputs, `LLM outputs object (for ${llm_model_name})`);
|
|
102
|
+
const { object: generated_object, usage: total_usage, providerMetadata: provider_metadata } = llm_outputs;
|
|
103
|
+
return { generated_object, total_usage, provider_metadata };
|
|
66
104
|
}
|
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import { llm_access_available, llm_access_get } from "./lib_llm_access.js";
|
|
2
2
|
import { llm_model_find_detail, llm_model_get_choices } from "./lib_llm_model.js";
|
|
3
|
-
|
|
4
|
-
import { tell_info } from "./lib_tell.js";
|
|
5
|
-
export function llm_config_get({ llm_model_details, llm_model_name, llm_router, }) {
|
|
3
|
+
export function llm_config_get({ llm_model_details, llm_model_name, }) {
|
|
6
4
|
const llm_model_detail = llm_model_find_detail({ llm_model_details, llm_model_name });
|
|
7
|
-
const access = llm_access_get({ llm_model_details, llm_model_name
|
|
8
|
-
const { llm_model_code,
|
|
9
|
-
return { llm_model_name, llm_model_detail, llm_model_code,
|
|
10
|
-
}
|
|
11
|
-
export function llm_config_get_all({ llm_model_details,
|
|
12
|
-
const choices = llm_model_get_choices(llm_model_details);
|
|
13
|
-
const available = choices.filter((llm_model_name) => llm_access_available({ llm_model_details, llm_model_name, llm_excludes }));
|
|
14
|
-
return available.map((llm_model_name) => llm_config_get({ llm_model_details, llm_model_name
|
|
15
|
-
}
|
|
16
|
-
export function llm_config_get_model_via(llm_config) {
|
|
17
|
-
const { llm_model_name, llm_provider } = llm_config;
|
|
18
|
-
return `${llm_model_name} (${llm_provider_get_via(llm_provider)})`;
|
|
19
|
-
}
|
|
20
|
-
export function llm_config_show(llm_config) {
|
|
21
|
-
const model_via = llm_config_get_model_via(llm_config);
|
|
22
|
-
tell_info(`Using LLM ${model_via}`);
|
|
5
|
+
const access = llm_access_get({ llm_model_details, llm_model_name });
|
|
6
|
+
const { llm_model_code, llm_api_code, llm_api_key } = access;
|
|
7
|
+
return { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key };
|
|
8
|
+
}
|
|
9
|
+
export function llm_config_get_all({ llm_model_details, llm_include, llm_excludes, }) {
|
|
10
|
+
const choices = llm_model_get_choices({ llm_model_details });
|
|
11
|
+
const available = choices.filter((llm_model_name) => llm_access_available({ llm_model_details, llm_model_name, llm_include, llm_excludes }));
|
|
12
|
+
return available.map((llm_model_name) => llm_config_get({ llm_model_details, llm_model_name }));
|
|
23
13
|
}
|
package/dist/src/lib_llm_list.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { DOLLAR } from "./lib_char_punctuation.js";
|
|
2
2
|
import { stdio_write_stdout_linefeed } from "./lib_stdio_write.js";
|
|
3
3
|
import { tell_info, tell_warning } from "./lib_tell.js";
|
|
4
|
-
import { tui_justify_right } from "./lib_tui_justify.js";
|
|
5
4
|
import { TuiTable } from "./lib_tui_table.js";
|
|
6
5
|
export function llm_list_models({ llm_model_details }) {
|
|
7
|
-
const headings = ["NAME", "CONTEXT", "INPUT", "OUTPUT"];
|
|
8
|
-
const
|
|
6
|
+
const headings = ["NAME", "API", "CONTEXT", "INPUT", "OUTPUT", "REASONING"];
|
|
7
|
+
const alignments = ["left", "left", "right", "right", "right", "left"];
|
|
8
|
+
const table = new TuiTable({ headings, alignments });
|
|
9
9
|
for (const detail of llm_model_details) {
|
|
10
|
-
const { llm_model_name, context_window, cents_input, cents_output } = detail;
|
|
10
|
+
const { llm_model_name, llm_api_code, context_window, cents_input, cents_output, default_reasoning } = detail;
|
|
11
11
|
const tui_name = llm_model_name;
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
12
|
+
const tui_api = llm_api_code;
|
|
13
|
+
const tui_context = context_window.toString();
|
|
14
|
+
const tui_input = DOLLAR + (cents_input / 100).toFixed(2);
|
|
15
|
+
const tui_output = DOLLAR + (cents_output / 100).toFixed(2);
|
|
16
|
+
const tui_reasoning = default_reasoning ? "True" : "False";
|
|
17
|
+
const row = [tui_name, tui_api, tui_context, tui_input, tui_output, tui_reasoning];
|
|
16
18
|
table.push(row);
|
|
17
19
|
}
|
|
18
20
|
stdio_write_stdout_linefeed(table.toString());
|
|
19
21
|
tell_info("Prices are per million tokens.");
|
|
20
|
-
tell_warning("Prices are best effort and are liable to change - always double-check with your LLM provider.");
|
|
22
|
+
tell_warning("Prices are best effort and are liable to change - always double-check with your LLM API provider.");
|
|
21
23
|
}
|