@johnowennixon/diffdash 1.7.0 → 1.9.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 -18
- package/dist/package.json +24 -22
- package/dist/src/lib_datetime.js +4 -1
- package/dist/src/lib_debug.js +1 -0
- package/dist/src/lib_diffdash_cli.js +3 -5
- package/dist/src/lib_diffdash_config.js +6 -15
- package/dist/src/lib_diffdash_llm.js +8 -13
- package/dist/src/lib_diffdash_sequence.js +33 -17
- package/dist/src/lib_git_message_generate.js +19 -19
- package/dist/src/lib_git_message_prompt.js +3 -3
- package/dist/src/lib_git_message_schema.js +3 -3
- package/dist/src/lib_git_simple_staging.js +11 -6
- package/dist/src/lib_llm_access.js +14 -53
- package/dist/src/lib_llm_api.js +2 -36
- package/dist/src/lib_llm_chat.js +26 -19
- package/dist/src/lib_llm_config.js +12 -15
- package/dist/src/lib_llm_list.js +10 -8
- package/dist/src/lib_llm_model.js +369 -241
- package/dist/src/lib_llm_results.js +50 -0
- package/dist/src/lib_llm_tokens.js +6 -3
- package/dist/src/lib_parse_number.js +2 -2
- package/dist/src/lib_tell.js +6 -5
- package/dist/src/lib_tui_confirm.js +25 -0
- package/dist/src/lib_tui_none.js +12 -0
- package/dist/src/lib_tui_number.js +22 -0
- package/dist/src/lib_tui_table.js +14 -6
- package/package.json +24 -22
- package/dist/src/lib_assert_type.js +0 -30
- package/dist/src/lib_tui_readline.js +0 -16
- package/dist/src/lib_type_guard.js +0 -15
|
@@ -3,8 +3,13 @@ import { COMMA } from "./lib_char_punctuation.js";
|
|
|
3
3
|
import { llm_api_get_api_key, llm_api_get_api_key_env } from "./lib_llm_api.js";
|
|
4
4
|
import { llm_model_find_detail } from "./lib_llm_model.js";
|
|
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
|
+
}
|
|
6
11
|
if (llm_include) {
|
|
7
|
-
if (!llm_model_name.includes(llm_include)) {
|
|
12
|
+
if (!(llm_model_name.includes(llm_include) || llm_include === llm_api_code)) {
|
|
8
13
|
return false;
|
|
9
14
|
}
|
|
10
15
|
}
|
|
@@ -16,59 +21,15 @@ export function llm_access_available({ llm_model_details, llm_model_name, llm_in
|
|
|
16
21
|
}
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
|
-
|
|
20
|
-
const { llm_api_code, llm_model_code_direct, llm_model_code_requesty, llm_model_code_openrouter } = detail;
|
|
21
|
-
if (llm_model_code_direct !== null && llm_api_code !== null) {
|
|
22
|
-
if (llm_api_get_api_key(llm_api_code)) {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (llm_model_code_openrouter !== null) {
|
|
27
|
-
if (llm_api_get_api_key("openrouter")) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (llm_model_code_requesty !== null) {
|
|
32
|
-
if (llm_api_get_api_key("requesty")) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
24
|
+
return true;
|
|
37
25
|
}
|
|
38
|
-
export function llm_access_get({ llm_model_details, llm_model_name,
|
|
26
|
+
export function llm_access_get({ llm_model_details, llm_model_name, }) {
|
|
39
27
|
const detail = llm_model_find_detail({ llm_model_details, llm_model_name });
|
|
40
|
-
const { llm_api_code,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return { llm_model_code: llm_model_code_direct, llm_api_code, llm_api_key };
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (llm_model_code_openrouter !== null) {
|
|
50
|
-
const llm_api_key = llm_api_get_api_key("openrouter");
|
|
51
|
-
if (llm_api_key) {
|
|
52
|
-
return { llm_model_code: llm_model_code_openrouter, llm_api_code: "openrouter", llm_api_key };
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (llm_model_code_requesty !== null) {
|
|
56
|
-
const llm_api_key = llm_api_get_api_key("requesty");
|
|
57
|
-
if (llm_api_key) {
|
|
58
|
-
return { llm_model_code: llm_model_code_requesty, llm_api_code: "requesty", llm_api_key };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (llm_model_code_direct !== null && llm_api_code !== null) {
|
|
62
|
-
const llm_api_key = llm_api_get_api_key(llm_api_code);
|
|
63
|
-
if (llm_api_key) {
|
|
64
|
-
return { llm_model_code: llm_model_code_direct, llm_api_code, llm_api_key };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const env_openrouter = llm_api_get_api_key_env("openrouter");
|
|
68
|
-
const env_requesty = llm_api_get_api_key_env("requesty");
|
|
69
|
-
if (llm_api_code !== null) {
|
|
70
|
-
const env_direct = llm_api_get_api_key_env(llm_api_code);
|
|
71
|
-
abort_with_error(`Please set environment variable ${env_direct}, ${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}`);
|
|
72
33
|
}
|
|
73
|
-
|
|
34
|
+
return { llm_model_code, llm_api_code, llm_api_key };
|
|
74
35
|
}
|
package/dist/src/lib_llm_api.js
CHANGED
|
@@ -3,26 +3,8 @@ 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
|
-
import { assert_type_string } from "./lib_assert_type.js";
|
|
9
|
-
import { AT_SIGN } from "./lib_char_punctuation.js";
|
|
10
7
|
import { env_get } from "./lib_env.js";
|
|
11
|
-
export function llm_api_get_via(llm_api_code) {
|
|
12
|
-
switch (llm_api_code) {
|
|
13
|
-
case "anthropic":
|
|
14
|
-
case "deepseek":
|
|
15
|
-
case "google":
|
|
16
|
-
case "openai":
|
|
17
|
-
return "direct";
|
|
18
|
-
case "requesty":
|
|
19
|
-
return "via Requesty";
|
|
20
|
-
case "openrouter":
|
|
21
|
-
return "via OpenRouter";
|
|
22
|
-
default:
|
|
23
|
-
abort_with_error("Unknown LLM API");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
8
|
export function llm_api_get_api_key_env(llm_api_code) {
|
|
27
9
|
switch (llm_api_code) {
|
|
28
10
|
case "anthropic":
|
|
@@ -33,8 +15,6 @@ export function llm_api_get_api_key_env(llm_api_code) {
|
|
|
33
15
|
return "GEMINI_API_KEY";
|
|
34
16
|
case "openai":
|
|
35
17
|
return "OPENAI_API_KEY";
|
|
36
|
-
case "requesty":
|
|
37
|
-
return "REQUESTY_API_KEY";
|
|
38
18
|
case "openrouter":
|
|
39
19
|
return "OPENROUTER_API_KEY";
|
|
40
20
|
default:
|
|
@@ -45,6 +25,7 @@ export function llm_api_get_api_key(llm_api_code) {
|
|
|
45
25
|
const env = llm_api_get_api_key_env(llm_api_code);
|
|
46
26
|
return env_get(env);
|
|
47
27
|
}
|
|
28
|
+
// eslint-disable-next-line sonarjs/function-return-type
|
|
48
29
|
export function llm_api_get_ai_sdk_language_model({ llm_model_code, llm_api_code, llm_api_key, }) {
|
|
49
30
|
switch (llm_api_code) {
|
|
50
31
|
case "anthropic":
|
|
@@ -55,23 +36,8 @@ export function llm_api_get_ai_sdk_language_model({ llm_model_code, llm_api_code
|
|
|
55
36
|
return createGoogleGenerativeAI({ apiKey: llm_api_key })(llm_model_code);
|
|
56
37
|
case "openai":
|
|
57
38
|
return createOpenAI({ apiKey: llm_api_key })(llm_model_code);
|
|
58
|
-
case "requesty":
|
|
59
|
-
return createRequesty({ apiKey: llm_api_key })(llm_model_code);
|
|
60
39
|
case "openrouter": {
|
|
61
|
-
|
|
62
|
-
if (llm_model_code.includes(AT_SIGN)) {
|
|
63
|
-
const splits = llm_model_code.split(AT_SIGN);
|
|
64
|
-
const model_id = assert_type_string(splits[0]);
|
|
65
|
-
const provider = assert_type_string(splits[1]);
|
|
66
|
-
return openrouter(model_id, {
|
|
67
|
-
extraBody: {
|
|
68
|
-
provider: {
|
|
69
|
-
only: [provider],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
return openrouter(llm_model_code);
|
|
40
|
+
return createOpenRouter({ apiKey: llm_api_key })(llm_model_code);
|
|
75
41
|
}
|
|
76
42
|
default:
|
|
77
43
|
abort_with_error("Unknown LLM API");
|
package/dist/src/lib_llm_chat.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
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
3
|
import { Duration } from "./lib_duration.js";
|
|
4
4
|
import { env_get_empty, env_get_substitute } from "./lib_env.js";
|
|
5
5
|
import { error_get_text } from "./lib_error.js";
|
|
6
6
|
import { llm_api_get_ai_sdk_language_model } from "./lib_llm_api.js";
|
|
7
|
-
import {
|
|
7
|
+
import { parse_int, parse_int_or_undefined } from "./lib_parse_number.js";
|
|
8
8
|
import { tell_debug } from "./lib_tell.js";
|
|
9
9
|
import { tui_block_string } from "./lib_tui_block.js";
|
|
10
10
|
function llm_chat_get_parameters() {
|
|
11
11
|
return {
|
|
12
|
-
|
|
13
|
-
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")),
|
|
14
13
|
timeout: parse_int(env_get_substitute("lib_llm_chat_timeout", "60")),
|
|
15
14
|
};
|
|
16
15
|
}
|
|
@@ -23,24 +22,26 @@ function llm_chat_debug_prompts({ llm_model_name, system_prompt, user_prompt, })
|
|
|
23
22
|
tui_block_string({ teller, title: `LLM user prompt (for ${llm_model_name}):`, content: user_prompt });
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
|
-
export async function llm_chat_generate_text({ llm_config,
|
|
27
|
-
const { llm_model_name,
|
|
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;
|
|
28
27
|
llm_chat_debug_prompts({ system_prompt, user_prompt, llm_model_name });
|
|
29
28
|
const ai_sdk_language_model = llm_api_get_ai_sdk_language_model({
|
|
30
29
|
llm_model_code,
|
|
31
30
|
llm_api_code,
|
|
32
31
|
llm_api_key,
|
|
33
32
|
});
|
|
34
|
-
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();
|
|
35
36
|
const llm_inputs = {
|
|
36
37
|
model: ai_sdk_language_model,
|
|
37
38
|
system: system_prompt,
|
|
38
39
|
prompt: user_prompt,
|
|
39
40
|
tools,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
maxTokens: max_tokens,
|
|
41
|
+
stopWhen: max_steps === undefined ? undefined : stepCountIs(max_steps),
|
|
42
|
+
maxOutputTokens: max_output_tokens,
|
|
43
43
|
temperature,
|
|
44
|
+
providerOptions: provider_options,
|
|
44
45
|
abortSignal: AbortSignal.timeout(timeout * 1000),
|
|
45
46
|
};
|
|
46
47
|
debug_inspect_when(debug_channels.llm_inputs, llm_inputs, `LLM inputs object (for ${llm_model_name})`);
|
|
@@ -53,45 +54,51 @@ export async function llm_chat_generate_text({ llm_config, headers, system_promp
|
|
|
53
54
|
if (max_steps !== undefined && llm_outputs.steps.length === max_steps) {
|
|
54
55
|
throw new Error("Too many steps taken");
|
|
55
56
|
}
|
|
56
|
-
|
|
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 };
|
|
57
59
|
}
|
|
58
|
-
export async function
|
|
60
|
+
export async function llm_chat_generate_text_result({ llm_config, system_prompt, user_prompt, }) {
|
|
59
61
|
const duration = new Duration();
|
|
60
62
|
duration.start();
|
|
61
63
|
try {
|
|
62
|
-
const
|
|
64
|
+
const outputs = await llm_chat_generate_text({ llm_config, system_prompt, user_prompt });
|
|
63
65
|
duration.stop();
|
|
64
66
|
const seconds = duration.seconds_rounded();
|
|
65
|
-
return { llm_config, seconds,
|
|
67
|
+
return { llm_config, seconds, error_text: null, outputs };
|
|
66
68
|
}
|
|
67
69
|
catch (error) {
|
|
68
70
|
duration.stop();
|
|
69
71
|
const seconds = duration.seconds_rounded();
|
|
70
72
|
const error_text = error_get_text(error);
|
|
71
|
-
return { llm_config, seconds,
|
|
73
|
+
return { llm_config, seconds, error_text, outputs: null };
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
export async function llm_chat_generate_object({ llm_config, user_prompt, system_prompt, schema, }) {
|
|
75
|
-
const { llm_model_name,
|
|
77
|
+
const { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key } = llm_config;
|
|
76
78
|
llm_chat_debug_prompts({ system_prompt, user_prompt, llm_model_name });
|
|
77
79
|
const ai_sdk_language_model = llm_api_get_ai_sdk_language_model({
|
|
78
80
|
llm_model_code,
|
|
79
81
|
llm_api_code,
|
|
80
82
|
llm_api_key,
|
|
81
83
|
});
|
|
82
|
-
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();
|
|
83
87
|
const llm_inputs = {
|
|
84
88
|
model: ai_sdk_language_model,
|
|
85
89
|
system: system_prompt,
|
|
86
90
|
prompt: user_prompt,
|
|
91
|
+
output: "object",
|
|
87
92
|
schema,
|
|
88
|
-
|
|
93
|
+
maxOutputTokens: max_output_tokens,
|
|
89
94
|
temperature,
|
|
95
|
+
providerOptions: provider_options,
|
|
90
96
|
abortSignal: AbortSignal.timeout(timeout * 1000),
|
|
91
97
|
};
|
|
92
98
|
debug_inspect_when(debug_channels.llm_inputs, llm_inputs, `LLM inputs object (for ${llm_model_name})`);
|
|
93
99
|
// This is liable to throw an error
|
|
94
100
|
const llm_outputs = await generateObject(llm_inputs);
|
|
95
101
|
debug_inspect_when(debug_channels.llm_outputs, llm_outputs, `LLM outputs object (for ${llm_model_name})`);
|
|
96
|
-
|
|
102
|
+
const { object: generated_object, usage: total_usage, providerMetadata: provider_metadata } = llm_outputs;
|
|
103
|
+
return { generated_object, total_usage, provider_metadata };
|
|
97
104
|
}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
|
+
import { env_get } from "./lib_env.js";
|
|
1
2
|
import { llm_access_available, llm_access_get } from "./lib_llm_access.js";
|
|
2
|
-
import { llm_api_get_via } from "./lib_llm_api.js";
|
|
3
3
|
import { llm_model_find_detail, llm_model_get_choices } from "./lib_llm_model.js";
|
|
4
|
-
import {
|
|
5
|
-
export function llm_config_get({ llm_model_details, llm_model_name,
|
|
4
|
+
import { parse_int_or_undefined } from "./lib_parse_number.js";
|
|
5
|
+
export function llm_config_get({ llm_model_details, llm_model_name, }) {
|
|
6
6
|
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
|
|
7
|
+
const access = llm_access_get({ llm_model_details, llm_model_name });
|
|
8
8
|
const { llm_model_code, llm_api_code, llm_api_key } = access;
|
|
9
|
-
|
|
9
|
+
let effective_context_window = llm_model_detail.context_window;
|
|
10
|
+
const env_context_window = parse_int_or_undefined(env_get("LLM_CONFIG_CONTEXT_WINDOW"));
|
|
11
|
+
if (env_context_window !== undefined) {
|
|
12
|
+
effective_context_window = Math.min(effective_context_window, env_context_window);
|
|
13
|
+
}
|
|
14
|
+
return { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key, effective_context_window };
|
|
10
15
|
}
|
|
11
|
-
export function llm_config_get_all({ llm_model_details,
|
|
16
|
+
export function llm_config_get_all({ llm_model_details, llm_include, llm_excludes, }) {
|
|
12
17
|
const choices = llm_model_get_choices({ llm_model_details });
|
|
13
18
|
const available = choices.filter((llm_model_name) => llm_access_available({ llm_model_details, llm_model_name, llm_include, 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_api_code } = llm_config;
|
|
18
|
-
return `${llm_model_name} (${llm_api_get_via(llm_api_code)})`;
|
|
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}`);
|
|
19
|
+
return available.map((llm_model_name) => llm_config_get({ llm_model_details, llm_model_name }));
|
|
23
20
|
}
|
package/dist/src/lib_llm_list.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
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, compact: true });
|
|
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());
|