kritya 0.8.47-beta → 0.8.49-beta
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/doctor.js +2 -2
- package/dist/config/models.js +49 -0
- package/dist/engine.js +2 -2
- package/dist/headless.js +2 -2
- package/dist/index.js +2 -2
- package/dist/ui/App.js +1 -1
- package/dist/ui/ModelPicker.js +18 -5
- package/dist/ui/useAgent.js +2 -2
- package/package.json +1 -1
package/dist/commands/doctor.js
CHANGED
|
@@ -3,7 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { BUILTIN_PROVIDERS, CONFIG_DIR, CONFIG_FILE, legacyGlobalModel, loadConfig, loadDotEnv, privacyModeFor, resolveProvider, } from "../config/config.js";
|
|
6
|
-
import {
|
|
6
|
+
import { defaultModelFor, contextWindowFor } from "../config/models.js";
|
|
7
7
|
import { retentionDaysFor } from "../config/retention.js";
|
|
8
8
|
import { assertJsonWithinLimits } from "../config/jsonSafety.js";
|
|
9
9
|
import { isGitRepo } from "../agent/worktree.js";
|
|
@@ -144,7 +144,7 @@ function providerSection(config, provider) {
|
|
|
144
144
|
else {
|
|
145
145
|
checks.push(fail(`no API key resolved for provider "${provider.name}"`));
|
|
146
146
|
}
|
|
147
|
-
const model = resolveEffectiveModel(provider.name, [config.providers?.[provider.name]?.model, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID :
|
|
147
|
+
const model = resolveEffectiveModel(provider.name, [config.providers?.[provider.name]?.model, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID : defaultModelFor(provider.name));
|
|
148
148
|
checks.push(ok(`model: ${model} (context ${contextWindowFor(model, config).toLocaleString("en-US")})`));
|
|
149
149
|
// A pinned provider name with no matching entry is a silent misconfiguration:
|
|
150
150
|
// resolveProvider falls back to NVIDIA's URL, so requests go somewhere the
|
package/dist/config/models.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** The provider a `ModelInfo` belongs to, defaulting the historical NVIDIA catalog. */
|
|
2
|
+
export function providerOfModel(m) {
|
|
3
|
+
return m.provider ?? "nvidia";
|
|
4
|
+
}
|
|
1
5
|
/** Fallback context window when neither config nor the registry knows the model. */
|
|
2
6
|
export const DEFAULT_CONTEXT_WINDOW = 120_000;
|
|
3
7
|
/**
|
|
@@ -63,8 +67,53 @@ export const CURATED_MODELS = [
|
|
|
63
67
|
note: "fast + cheap",
|
|
64
68
|
contextWindow: 1_048_576,
|
|
65
69
|
},
|
|
70
|
+
// Groq (https://console.groq.com/docs/models). Context windows verified
|
|
71
|
+
// against the docs table; both are 131,072.
|
|
72
|
+
{
|
|
73
|
+
id: "openai/gpt-oss-120b",
|
|
74
|
+
label: "GPT-OSS 120B",
|
|
75
|
+
provider: "groq",
|
|
76
|
+
note: "default",
|
|
77
|
+
contextWindow: 131_072,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "llama-3.3-70b-versatile",
|
|
81
|
+
label: "Llama 3.3 70B Versatile",
|
|
82
|
+
provider: "groq",
|
|
83
|
+
contextWindow: 131_072,
|
|
84
|
+
},
|
|
66
85
|
];
|
|
86
|
+
/** Models registered for one provider, in registry order. */
|
|
87
|
+
export function modelsForProvider(provider) {
|
|
88
|
+
return CURATED_MODELS.filter((m) => providerOfModel(m) === provider);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The provider a curated model belongs to, or undefined for a model this
|
|
92
|
+
* registry doesn't know (custom models, arbitrary `-m` ids).
|
|
93
|
+
*/
|
|
94
|
+
export function curatedProviderFor(modelId) {
|
|
95
|
+
const m = CURATED_MODELS.find((x) => x.id === modelId);
|
|
96
|
+
return m ? providerOfModel(m) : undefined;
|
|
97
|
+
}
|
|
98
|
+
/** The curated default model for a provider, if it has one. */
|
|
99
|
+
export function defaultModelForProvider(provider) {
|
|
100
|
+
const models = modelsForProvider(provider);
|
|
101
|
+
if (models.length === 0)
|
|
102
|
+
return undefined;
|
|
103
|
+
// Prefer an entry flagged `note: "default"`, else the first registered.
|
|
104
|
+
return (models.find((m) => m.note === "default") ?? models[0]).id;
|
|
105
|
+
}
|
|
67
106
|
export const DEFAULT_MODEL = CURATED_MODELS[0].id;
|
|
107
|
+
/**
|
|
108
|
+
* The default model id for a given provider. Providers with a curated list use
|
|
109
|
+
* their own default, so `-p groq` with no `-m` sends a Groq model id rather
|
|
110
|
+
* than the NVIDIA default (which the Groq API would reject). Providers with no
|
|
111
|
+
* curated models keep the historical behaviour of falling back to the NVIDIA
|
|
112
|
+
* default, since those are callers passing an arbitrary provider/model pair.
|
|
113
|
+
*/
|
|
114
|
+
export function defaultModelFor(provider) {
|
|
115
|
+
return defaultModelForProvider(provider) ?? DEFAULT_MODEL;
|
|
116
|
+
}
|
|
68
117
|
/**
|
|
69
118
|
* Context window for a model. Explicit config.contextWindow always wins; then
|
|
70
119
|
* the curated registry; then the default. Custom models can carry a window via
|
package/dist/engine.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { Agent } from "./agent/loop.js";
|
|
3
3
|
import { CONFIG_DIR, legacyGlobalModel, loadConfig, loadDotEnv, privacyModeFor, resolveProvider, } from "./config/config.js";
|
|
4
|
-
import {
|
|
4
|
+
import { defaultModelFor, contextWindowFor } from "./config/models.js";
|
|
5
5
|
import { PermissionManager } from "./permissions/permissions.js";
|
|
6
6
|
import { loadRules } from "./permissions/rules.js";
|
|
7
7
|
import { ProviderClient } from "./provider/client.js";
|
|
@@ -41,7 +41,7 @@ export async function createEngineSession(dir, opts = {}) {
|
|
|
41
41
|
throw new Error(`No API key found for provider "${provider.name}". Set it via env var, a .env file, or ~/.kritya/config.json.`);
|
|
42
42
|
}
|
|
43
43
|
const providerDefaultModel = config.providers?.[provider.name]?.model;
|
|
44
|
-
let currentModel = resolveEffectiveModel(provider.name, [opts.model, providerDefaultModel, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID :
|
|
44
|
+
let currentModel = resolveEffectiveModel(provider.name, [opts.model, providerDefaultModel, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID : defaultModelFor(provider.name));
|
|
45
45
|
const sampling = {
|
|
46
46
|
temperature: provider.temperature,
|
|
47
47
|
topP: provider.topP,
|
package/dist/headless.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { Agent } from "./agent/loop.js";
|
|
3
3
|
import { KillSwitchError } from "./agent/killSwitch.js";
|
|
4
4
|
import { CONFIG_DIR, legacyGlobalModel, listProviders, loadConfig, loadDotEnv, privacyModeFor, resolveProvider, } from "./config/config.js";
|
|
5
|
-
import {
|
|
5
|
+
import { defaultModelFor, contextWindowFor } from "./config/models.js";
|
|
6
6
|
import { PermissionManager } from "./permissions/permissions.js";
|
|
7
7
|
import { loadRules } from "./permissions/rules.js";
|
|
8
8
|
import { ProviderClient, RetryExhaustedError, friendlyProviderErrorHint, } from "./provider/client.js";
|
|
@@ -125,7 +125,7 @@ export async function runHeadless(args) {
|
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
127
|
const providerDefaultModel = config.providers?.[provider.name]?.model;
|
|
128
|
-
const model = resolveEffectiveModel(provider.name, [args.model, providerDefaultModel, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID :
|
|
128
|
+
const model = resolveEffectiveModel(provider.name, [args.model, providerDefaultModel, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID : defaultModelFor(provider.name));
|
|
129
129
|
const staleModelWarning = staleSwitchyardModelWarning(provider.name, model, args.model);
|
|
130
130
|
if (staleModelWarning)
|
|
131
131
|
process.stderr.write(`${staleModelWarning}\n`);
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { render } from "ink";
|
|
6
6
|
import { Agent } from "./agent/loop.js";
|
|
7
7
|
import { CONFIG_DIR, appendGlobalEnvVar, legacyGlobalModel, loadConfig, loadDotEnv, privacyModeFor, resolveProvider, } from "./config/config.js";
|
|
8
|
-
import {
|
|
8
|
+
import { defaultModelFor, contextWindowFor } from "./config/models.js";
|
|
9
9
|
import { PermissionManager } from "./permissions/permissions.js";
|
|
10
10
|
import { loadRules } from "./permissions/rules.js";
|
|
11
11
|
import { ProviderClient } from "./provider/client.js";
|
|
@@ -404,7 +404,7 @@ async function main() {
|
|
|
404
404
|
}
|
|
405
405
|
const providerDefaultModel = config.providers?.[provider.name]?.model;
|
|
406
406
|
const modelRef = {
|
|
407
|
-
current: resolveEffectiveModel(provider.name, [args.model, providerDefaultModel, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID :
|
|
407
|
+
current: resolveEffectiveModel(provider.name, [args.model, providerDefaultModel, legacyGlobalModel(config, provider.name)], provider.name === "switchyard" ? SWITCHYARD_ROUTE_ID : defaultModelFor(provider.name)),
|
|
408
408
|
};
|
|
409
409
|
const staleModelWarning = staleSwitchyardModelWarning(provider.name, modelRef.current, args.model);
|
|
410
410
|
if (staleModelWarning)
|
package/dist/ui/App.js
CHANGED
|
@@ -721,7 +721,7 @@ export function App({ agent, workspace, modelRef, providerRef, config, resumedCo
|
|
|
721
721
|
}
|
|
722
722
|
addItem({ kind: "user", text: `${text} (queued)` });
|
|
723
723
|
void expandMentions(text).then((t) => agent.queueSteer(t));
|
|
724
|
-
}, placeholder: "steer the agent\u2026 (Enter to queue)" })] })] })), phase === "permission" && permission && (_jsx(PermissionPrompt, { toolName: permission.toolName, summary: permission.summary, diff: permission.diff, warning: permission.warning, onDecision: onPermissionDecision })), phase === "elicitation" && elicitation && (_jsx(ElicitationPrompt, { message: elicitation.message, fields: elicitation.fields, onDecision: onElicitationDecision })), phase === "confirmMode" && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [_jsx(Text, { bold: true, color: "green", children: "Switch to accept-edits mode?" }), _jsx(Text, { children: "File writes and edits will auto-approve without asking." }), _jsx(Text, { dimColor: true, children: "Destructive shell commands (rm -rf, force-push, etc.) always still ask, in every mode." }), _jsx(Text, { dimColor: true, children: "Shift+Tab again moves to dry-run mode; once more back to normal." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [_jsx(Text, { color: "green", children: "Yes (y)" }), " \u00B7 No (n/Esc)"] }) })] })), phase === "confirmBypassMode" && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Switch to auto mode? (sandbox-gated)" }), _jsx(Text, { children: "EVERY tool call will auto-approve, including destructive shell commands (rm -rf, force-push, etc.) \u2014 nothing will ask first." }), _jsx(Text, { dimColor: true, children: "The sandbox \u2014 not a human \u2014 is what contains any damage this mode causes." }), _jsx(Text, { dimColor: true, children: "Shift+Tab again goes back to normal." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [_jsx(Text, { color: "red", children: "Yes (y)" }), " \u00B7 No (n/Esc)"] }) })] })), phase === "model" && (_jsx(ModelPicker, { current: model, customModels: config.customModels ?? [], onSelect: (id) => {
|
|
724
|
+
}, placeholder: "steer the agent\u2026 (Enter to queue)" })] })] })), phase === "permission" && permission && (_jsx(PermissionPrompt, { toolName: permission.toolName, summary: permission.summary, diff: permission.diff, warning: permission.warning, onDecision: onPermissionDecision })), phase === "elicitation" && elicitation && (_jsx(ElicitationPrompt, { message: elicitation.message, fields: elicitation.fields, onDecision: onElicitationDecision })), phase === "confirmMode" && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [_jsx(Text, { bold: true, color: "green", children: "Switch to accept-edits mode?" }), _jsx(Text, { children: "File writes and edits will auto-approve without asking." }), _jsx(Text, { dimColor: true, children: "Destructive shell commands (rm -rf, force-push, etc.) always still ask, in every mode." }), _jsx(Text, { dimColor: true, children: "Shift+Tab again moves to dry-run mode; once more back to normal." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [_jsx(Text, { color: "green", children: "Yes (y)" }), " \u00B7 No (n/Esc)"] }) })] })), phase === "confirmBypassMode" && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Switch to auto mode? (sandbox-gated)" }), _jsx(Text, { children: "EVERY tool call will auto-approve, including destructive shell commands (rm -rf, force-push, etc.) \u2014 nothing will ask first." }), _jsx(Text, { dimColor: true, children: "The sandbox \u2014 not a human \u2014 is what contains any damage this mode causes." }), _jsx(Text, { dimColor: true, children: "Shift+Tab again goes back to normal." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [_jsx(Text, { color: "red", children: "Yes (y)" }), " \u00B7 No (n/Esc)"] }) })] })), phase === "model" && (_jsx(ModelPicker, { current: model, provider: provider, customModels: config.customModels ?? [], onSelect: (id) => {
|
|
725
725
|
setPhase("input");
|
|
726
726
|
setModelEverywhere(id);
|
|
727
727
|
}, onCancel: () => setPhase("input") })), phase === "resume" && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [_jsxs(Text, { bold: true, color: "magenta", children: ["Resume a session", " ", _jsx(Text, { dimColor: true, children: "(type to search \u00B7 Esc for a fresh one \u00B7 -r <name> to skip this)" })] }), resumeFilter ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "filter: " }), resumeFilter] })) : null, _jsx(SelectList, { items: (resumeSessions ?? [])
|
package/dist/ui/ModelPicker.js
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import { CURATED_MODELS } from "../config/models.js";
|
|
3
|
+
import { CURATED_MODELS, providerOfModel } from "../config/models.js";
|
|
4
4
|
import { SelectList } from "./SelectList.js";
|
|
5
|
-
|
|
5
|
+
/** Provider label for a hint, e.g. `groq` — what the user would pass to `-p`. */
|
|
6
|
+
function providerHint(m) {
|
|
7
|
+
return providerOfModel(m);
|
|
8
|
+
}
|
|
9
|
+
export function ModelPicker({ current, provider, customModels, onSelect, onCancel, }) {
|
|
10
|
+
// Show the active provider's models first and unlabelled, then any other
|
|
11
|
+
// providers' under a `provider/` prefix — so a Groq user sees Groq models
|
|
12
|
+
// at the top, and an NVIDIA user still sees the rest without the picker
|
|
13
|
+
// silently hiding them or lying about which provider they belong to.
|
|
14
|
+
const own = CURATED_MODELS.filter((m) => providerOfModel(m) === provider);
|
|
15
|
+
const others = CURATED_MODELS.filter((m) => providerOfModel(m) !== provider);
|
|
16
|
+
// Fall back to the whole list when the active provider has no curated
|
|
17
|
+
// models, so the picker is never empty.
|
|
18
|
+
const listed = own.length > 0 ? [...own, ...others] : CURATED_MODELS;
|
|
6
19
|
const items = [
|
|
7
|
-
...
|
|
20
|
+
...listed.map((m) => ({
|
|
8
21
|
label: m.label + (m.id === current ? " (current)" : ""),
|
|
9
22
|
value: m.id,
|
|
10
|
-
hint: m.
|
|
23
|
+
hint: `${m.id} · ${providerHint(m)}${m.note ? ` · ${m.note}` : ""}`,
|
|
11
24
|
})),
|
|
12
25
|
...customModels.map((m) => ({
|
|
13
26
|
label: (m.label ?? m.id) + (m.id === current ? " (current)" : ""),
|
|
@@ -15,5 +28,5 @@ export function ModelPicker({ current, customModels, onSelect, onCancel, }) {
|
|
|
15
28
|
hint: `${m.id} · custom`,
|
|
16
29
|
})),
|
|
17
30
|
];
|
|
18
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [_jsxs(Text, { bold: true, color: "magenta", children: ["Select model", " ",
|
|
31
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [_jsxs(Text, { bold: true, color: "magenta", children: ["Select model", " ", _jsxs(Text, { dimColor: true, children: ["(Esc to cancel, or /model <id> for any ", provider, " model)"] })] }), _jsx(SelectList, { items: items, onSelect: onSelect, onCancel: onCancel })] }));
|
|
19
32
|
}
|
package/dist/ui/useAgent.js
CHANGED
|
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { gitBranch } from "../git/git.js";
|
|
4
4
|
import { listProviders, resolveProvider, saveConfig, saveProviderModel, } from "../config/config.js";
|
|
5
|
-
import {
|
|
5
|
+
import { defaultModelFor, contextWindowFor, displayModelId } from "../config/models.js";
|
|
6
6
|
import { ProviderClient, RetryExhaustedError, friendlyProviderErrorHint, } from "../provider/client.js";
|
|
7
7
|
import { createSwitchyardClient } from "../provider/switchyardClient.js";
|
|
8
8
|
import { SWITCHYARD_ROUTE_ID, resolveEffectiveModel } from "../provider/switchyardSidecar.js";
|
|
@@ -382,7 +382,7 @@ export function useAgent({ agent, workspace, modelRef, providerRef, config, uiBr
|
|
|
382
382
|
providerDefaultModel,
|
|
383
383
|
name === "switchyard" ? SWITCHYARD_ROUTE_ID : undefined,
|
|
384
384
|
modelRef.current,
|
|
385
|
-
], name === "switchyard" ? SWITCHYARD_ROUTE_ID :
|
|
385
|
+
], name === "switchyard" ? SWITCHYARD_ROUTE_ID : defaultModelFor(name));
|
|
386
386
|
let note = `Switched provider to ${name} — conversation history kept.`;
|
|
387
387
|
if (targetModel !== modelRef.current) {
|
|
388
388
|
setModelEverywhere(targetModel);
|