deepagentsdk 0.15.0 → 0.16.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/dist/adapters/elements/index.d.cts +1 -1
- package/dist/adapters/elements/index.d.mts +1 -1
- package/dist/{agent-DHUp_-Fx.d.mts → agent-BwmAQJhR.d.mts} +8 -8
- package/dist/{agent-tfRthBvX.d.cts → agent-DuvtniwH.d.cts} +31 -31
- package/dist/cli/index.cjs +679 -88
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +680 -89
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{file-saver-ZDVH1zHI.cjs → file-saver-BKNL0pg6.cjs} +115 -6
- package/dist/file-saver-BKNL0pg6.cjs.map +1 -0
- package/dist/{file-saver-CQWTIr8z.mjs → file-saver-DoXRgKBv.mjs} +106 -9
- package/dist/file-saver-DoXRgKBv.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -1
- package/dist/file-saver-CQWTIr8z.mjs.map +0 -1
- package/dist/file-saver-ZDVH1zHI.cjs.map +0 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { St as
|
|
3
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { St as DEFAULT_SUMMARIZATION_THRESHOLD, a as LocalSandbox, bt as DEFAULT_KEEP_MESSAGES, c as createDeepAgent, d as estimateMessagesTokens, i as setProvidersConfig, n as getProvidersConfig, r as parseModelString, t as FileSaver, vt as CONTEXT_WINDOW, wt as init_limits, yt as DEFAULT_EVICTION_TOKEN_LIMIT } from "../file-saver-DoXRgKBv.mjs";
|
|
3
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { Box, Text, render, useApp, useInput } from "ink";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { Badge, Spinner, StatusMessage } from "@inkjs/ui";
|
|
7
7
|
|
|
8
8
|
//#region src/cli/hooks/useAgent.ts
|
|
9
|
-
init_limits();
|
|
10
9
|
/**
|
|
11
10
|
* Hook for managing agent streaming and events.
|
|
12
11
|
*/
|
|
12
|
+
init_limits();
|
|
13
13
|
let eventCounter = 0;
|
|
14
14
|
function createEventId() {
|
|
15
15
|
return `event-${++eventCounter}`;
|
|
@@ -533,8 +533,8 @@ function useAgent(options) {
|
|
|
533
533
|
setSummarizationEnabled(enabled);
|
|
534
534
|
const newConfig = enabled ? {
|
|
535
535
|
enabled: true,
|
|
536
|
-
tokenThreshold: options.summarization?.tokenThreshold,
|
|
537
|
-
keepMessages: options.summarization?.keepMessages
|
|
536
|
+
tokenThreshold: options.summarization?.tokenThreshold ?? DEFAULT_SUMMARIZATION_THRESHOLD,
|
|
537
|
+
keepMessages: options.summarization?.keepMessages ?? DEFAULT_KEEP_MESSAGES
|
|
538
538
|
} : void 0;
|
|
539
539
|
setSummarizationConfig(newConfig);
|
|
540
540
|
recreateAgent({ summarization: newConfig });
|
|
@@ -656,6 +656,11 @@ const SLASH_COMMANDS = [
|
|
|
656
656
|
aliases: ["/key", "/api"],
|
|
657
657
|
description: "Manage API keys (interactive)"
|
|
658
658
|
},
|
|
659
|
+
{
|
|
660
|
+
command: "/baseurl",
|
|
661
|
+
aliases: ["/base-url"],
|
|
662
|
+
description: "Configure custom base URLs for providers (interactive)"
|
|
663
|
+
},
|
|
659
664
|
{
|
|
660
665
|
command: "/model",
|
|
661
666
|
aliases: [],
|
|
@@ -1563,7 +1568,7 @@ function isCacheValid(provider) {
|
|
|
1563
1568
|
const entry = modelCache[provider];
|
|
1564
1569
|
if (!entry) return false;
|
|
1565
1570
|
if (Date.now() - entry.timestamp > CACHE_TTL_MS) return false;
|
|
1566
|
-
const currentKeyHash = provider === "anthropic" ? hashApiKey(process.env.ANTHROPIC_API_KEY) : hashApiKey(process.env.OPENAI_API_KEY);
|
|
1571
|
+
const currentKeyHash = provider === "anthropic" ? hashApiKey(process.env.ANTHROPIC_API_KEY) : provider === "openai" ? hashApiKey(process.env.OPENAI_API_KEY) : hashApiKey(process.env.ZHIPU_API_KEY);
|
|
1567
1572
|
return entry.apiKeyHash === currentKeyHash;
|
|
1568
1573
|
}
|
|
1569
1574
|
/**
|
|
@@ -1577,7 +1582,7 @@ function getCachedModels(provider) {
|
|
|
1577
1582
|
* Set cached models for a provider.
|
|
1578
1583
|
*/
|
|
1579
1584
|
function setCachedModels(provider, models) {
|
|
1580
|
-
const apiKeyHash = provider === "anthropic" ? hashApiKey(process.env.ANTHROPIC_API_KEY) : hashApiKey(process.env.OPENAI_API_KEY);
|
|
1585
|
+
const apiKeyHash = provider === "anthropic" ? hashApiKey(process.env.ANTHROPIC_API_KEY) : provider === "openai" ? hashApiKey(process.env.OPENAI_API_KEY) : hashApiKey(process.env.ZHIPU_API_KEY);
|
|
1581
1586
|
modelCache[provider] = {
|
|
1582
1587
|
models,
|
|
1583
1588
|
timestamp: Date.now(),
|
|
@@ -1590,7 +1595,8 @@ function setCachedModels(provider, models) {
|
|
|
1590
1595
|
function detectAvailableProviders() {
|
|
1591
1596
|
return {
|
|
1592
1597
|
anthropic: !!process.env.ANTHROPIC_API_KEY,
|
|
1593
|
-
openai: !!process.env.OPENAI_API_KEY
|
|
1598
|
+
openai: !!process.env.OPENAI_API_KEY,
|
|
1599
|
+
zhipu: !!process.env.ZHIPU_API_KEY
|
|
1594
1600
|
};
|
|
1595
1601
|
}
|
|
1596
1602
|
/**
|
|
@@ -1706,6 +1712,34 @@ function getOpenAIModelDescription(modelId) {
|
|
|
1706
1712
|
return "";
|
|
1707
1713
|
}
|
|
1708
1714
|
/**
|
|
1715
|
+
* Known Zhipu GLM models with descriptions.
|
|
1716
|
+
* Zhipu doesn't have a public models list API, so we use a static list.
|
|
1717
|
+
*/
|
|
1718
|
+
const ZHIPU_MODELS = [{
|
|
1719
|
+
id: "glm-4.7",
|
|
1720
|
+
description: "Most capable GLM models"
|
|
1721
|
+
}];
|
|
1722
|
+
/**
|
|
1723
|
+
* Get available Zhipu models.
|
|
1724
|
+
* Returns a static list of known models since Zhipu doesn't have a models list API.
|
|
1725
|
+
*/
|
|
1726
|
+
async function fetchZhipuModels() {
|
|
1727
|
+
if (!process.env.ZHIPU_API_KEY) return {
|
|
1728
|
+
models: [],
|
|
1729
|
+
error: "No Zhipu API key configured"
|
|
1730
|
+
};
|
|
1731
|
+
const cached = getCachedModels("zhipu");
|
|
1732
|
+
if (cached) return { models: cached };
|
|
1733
|
+
const models = ZHIPU_MODELS.map((model) => ({
|
|
1734
|
+
id: `zhipu/${model.id}`,
|
|
1735
|
+
name: model.id,
|
|
1736
|
+
provider: "zhipu",
|
|
1737
|
+
description: model.description
|
|
1738
|
+
}));
|
|
1739
|
+
setCachedModels("zhipu", models);
|
|
1740
|
+
return { models };
|
|
1741
|
+
}
|
|
1742
|
+
/**
|
|
1709
1743
|
* Get list of available models from all configured providers.
|
|
1710
1744
|
* Only fetches from providers that have API keys configured.
|
|
1711
1745
|
*/
|
|
@@ -1728,6 +1762,13 @@ async function getAvailableModels() {
|
|
|
1728
1762
|
error: result.error
|
|
1729
1763
|
});
|
|
1730
1764
|
}));
|
|
1765
|
+
if (providers.zhipu) promises.push(fetchZhipuModels().then((result) => {
|
|
1766
|
+
allModels.push(...result.models);
|
|
1767
|
+
if (result.error) errors.push({
|
|
1768
|
+
provider: "Zhipu",
|
|
1769
|
+
error: result.error
|
|
1770
|
+
});
|
|
1771
|
+
}));
|
|
1731
1772
|
await Promise.all(promises);
|
|
1732
1773
|
return {
|
|
1733
1774
|
models: allModels,
|
|
@@ -1751,48 +1792,146 @@ async function getModelsByProvider() {
|
|
|
1751
1792
|
//#endregion
|
|
1752
1793
|
//#region src/cli/components/ModelSelection.tsx
|
|
1753
1794
|
/**
|
|
1754
|
-
* Model Selection Panel -
|
|
1795
|
+
* Model Selection Panel - Two-step interactive model selection.
|
|
1796
|
+
* Step 1: Select provider (Anthropic, OpenAI, Zhipu)
|
|
1797
|
+
* Step 2: Select model from that provider
|
|
1755
1798
|
*/
|
|
1756
1799
|
function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
1757
|
-
const
|
|
1758
|
-
const hasAnyKey =
|
|
1800
|
+
const detectedProviders = detectAvailableProviders();
|
|
1801
|
+
const hasAnyKey = detectedProviders.anthropic || detectedProviders.openai || detectedProviders.zhipu;
|
|
1759
1802
|
const [state, setState] = useState({
|
|
1760
1803
|
loading: true,
|
|
1761
1804
|
anthropicModels: [],
|
|
1762
1805
|
openaiModels: [],
|
|
1806
|
+
zhipuModels: [],
|
|
1763
1807
|
errors: []
|
|
1764
1808
|
});
|
|
1765
|
-
const [
|
|
1766
|
-
const
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1809
|
+
const [step, setStep] = useState("select-provider");
|
|
1810
|
+
const [selectedProviderIndex, setSelectedProviderIndex] = useState(0);
|
|
1811
|
+
const [selectedProvider, setSelectedProvider] = useState(null);
|
|
1812
|
+
const [selectedModelIndex, setSelectedModelIndex] = useState(0);
|
|
1813
|
+
const availableProviders = useMemo(() => {
|
|
1814
|
+
const providers = [];
|
|
1815
|
+
if (detectedProviders.anthropic) providers.push({
|
|
1816
|
+
key: "anthropic",
|
|
1817
|
+
name: "Anthropic Claude",
|
|
1818
|
+
description: "Claude models",
|
|
1819
|
+
hasKey: true,
|
|
1820
|
+
modelCount: state.anthropicModels.length
|
|
1821
|
+
});
|
|
1822
|
+
if (detectedProviders.openai) providers.push({
|
|
1823
|
+
key: "openai",
|
|
1824
|
+
name: "OpenAI GPT",
|
|
1825
|
+
description: "GPT models",
|
|
1826
|
+
hasKey: true,
|
|
1827
|
+
modelCount: state.openaiModels.length
|
|
1828
|
+
});
|
|
1829
|
+
if (detectedProviders.zhipu) providers.push({
|
|
1830
|
+
key: "zhipu",
|
|
1831
|
+
name: "Zhipu GLM",
|
|
1832
|
+
description: "GLM models",
|
|
1833
|
+
hasKey: true,
|
|
1834
|
+
modelCount: state.zhipuModels.length
|
|
1835
|
+
});
|
|
1836
|
+
return providers;
|
|
1837
|
+
}, [
|
|
1838
|
+
detectedProviders,
|
|
1839
|
+
state.anthropicModels.length,
|
|
1840
|
+
state.openaiModels.length,
|
|
1841
|
+
state.zhipuModels.length
|
|
1842
|
+
]);
|
|
1843
|
+
const currentProviderModels = useMemo(() => {
|
|
1844
|
+
if (!selectedProvider) return [];
|
|
1845
|
+
switch (selectedProvider) {
|
|
1846
|
+
case "anthropic": return state.anthropicModels;
|
|
1847
|
+
case "openai": return state.openaiModels;
|
|
1848
|
+
case "zhipu": return state.zhipuModels;
|
|
1849
|
+
default: return [];
|
|
1850
|
+
}
|
|
1851
|
+
}, [
|
|
1852
|
+
selectedProvider,
|
|
1853
|
+
state.anthropicModels,
|
|
1854
|
+
state.openaiModels,
|
|
1855
|
+
state.zhipuModels
|
|
1856
|
+
]);
|
|
1857
|
+
const hasInitializedProviderIndex = React.useRef(false);
|
|
1772
1858
|
useEffect(() => {
|
|
1773
|
-
if (
|
|
1774
|
-
const
|
|
1775
|
-
|
|
1859
|
+
if (!hasInitializedProviderIndex.current && currentModel && availableProviders.length > 0) {
|
|
1860
|
+
const providerFromModel = currentModel.split("/")[0];
|
|
1861
|
+
const providerIndex = availableProviders.findIndex((p) => p.key === providerFromModel);
|
|
1862
|
+
if (providerIndex >= 0) {
|
|
1863
|
+
setSelectedProviderIndex(providerIndex);
|
|
1864
|
+
hasInitializedProviderIndex.current = true;
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
}, [currentModel, availableProviders]);
|
|
1868
|
+
const prevStepRef = React.useRef(null);
|
|
1869
|
+
useEffect(() => {
|
|
1870
|
+
if (step === "select-model" && prevStepRef.current !== "select-model" && currentProviderModels.length > 0 && currentModel) {
|
|
1871
|
+
const currentIndex = currentProviderModels.findIndex((m) => isCurrentModel(currentModel, m));
|
|
1872
|
+
if (currentIndex >= 0) setSelectedModelIndex(currentIndex);
|
|
1873
|
+
else setSelectedModelIndex(0);
|
|
1776
1874
|
}
|
|
1777
|
-
|
|
1875
|
+
prevStepRef.current = step;
|
|
1876
|
+
}, [
|
|
1877
|
+
step,
|
|
1878
|
+
currentProviderModels,
|
|
1879
|
+
currentModel
|
|
1880
|
+
]);
|
|
1881
|
+
const stateRef = React.useRef(state);
|
|
1882
|
+
const stepRef = React.useRef(step);
|
|
1883
|
+
const availableProvidersRef = React.useRef(availableProviders);
|
|
1884
|
+
const selectedProviderIndexRef = React.useRef(selectedProviderIndex);
|
|
1885
|
+
const currentProviderModelsRef = React.useRef(currentProviderModels);
|
|
1886
|
+
const selectedModelIndexRef = React.useRef(selectedModelIndex);
|
|
1887
|
+
React.useEffect(() => {
|
|
1888
|
+
stateRef.current = state;
|
|
1889
|
+
stepRef.current = step;
|
|
1890
|
+
availableProvidersRef.current = availableProviders;
|
|
1891
|
+
selectedProviderIndexRef.current = selectedProviderIndex;
|
|
1892
|
+
currentProviderModelsRef.current = currentProviderModels;
|
|
1893
|
+
selectedModelIndexRef.current = selectedModelIndex;
|
|
1894
|
+
});
|
|
1778
1895
|
useInput((input, key) => {
|
|
1779
|
-
if (
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1896
|
+
if (stateRef.current.loading) return;
|
|
1897
|
+
const currentStep = stepRef.current;
|
|
1898
|
+
const providers = availableProvidersRef.current;
|
|
1899
|
+
const providerIndex = selectedProviderIndexRef.current;
|
|
1900
|
+
const models = currentProviderModelsRef.current;
|
|
1901
|
+
const modelIndex = selectedModelIndexRef.current;
|
|
1902
|
+
if (currentStep === "select-provider") {
|
|
1903
|
+
if (key.upArrow) setSelectedProviderIndex((prev) => prev > 0 ? prev - 1 : providers.length - 1);
|
|
1904
|
+
else if (key.downArrow) setSelectedProviderIndex((prev) => prev < providers.length - 1 ? prev + 1 : 0);
|
|
1905
|
+
else if (key.return) {
|
|
1906
|
+
const provider = providers[providerIndex];
|
|
1907
|
+
if (provider && provider.modelCount > 0) {
|
|
1908
|
+
setSelectedProvider(provider.key);
|
|
1909
|
+
setSelectedModelIndex(0);
|
|
1910
|
+
setStep("select-model");
|
|
1911
|
+
}
|
|
1912
|
+
} else if (key.escape) onClose?.();
|
|
1913
|
+
} else if (currentStep === "select-model") {
|
|
1914
|
+
if (key.upArrow) setSelectedModelIndex((prev) => prev > 0 ? prev - 1 : models.length - 1);
|
|
1915
|
+
else if (key.downArrow) setSelectedModelIndex((prev) => prev < models.length - 1 ? prev + 1 : 0);
|
|
1916
|
+
else if (key.return) {
|
|
1917
|
+
const selectedModel = models[modelIndex];
|
|
1918
|
+
if (selectedModel) {
|
|
1919
|
+
onModelSelect?.(selectedModel.id);
|
|
1920
|
+
onClose?.();
|
|
1921
|
+
}
|
|
1922
|
+
} else if (key.escape || key.leftArrow) {
|
|
1923
|
+
setStep("select-provider");
|
|
1924
|
+
setSelectedProvider(null);
|
|
1787
1925
|
}
|
|
1788
|
-
}
|
|
1789
|
-
});
|
|
1926
|
+
}
|
|
1927
|
+
}, { isActive: !state.loading });
|
|
1790
1928
|
useEffect(() => {
|
|
1791
1929
|
if (!hasAnyKey) {
|
|
1792
1930
|
setState({
|
|
1793
1931
|
loading: false,
|
|
1794
1932
|
anthropicModels: [],
|
|
1795
1933
|
openaiModels: [],
|
|
1934
|
+
zhipuModels: [],
|
|
1796
1935
|
errors: []
|
|
1797
1936
|
});
|
|
1798
1937
|
return;
|
|
@@ -1805,6 +1944,7 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1805
1944
|
loading: false,
|
|
1806
1945
|
anthropicModels: result.anthropic || [],
|
|
1807
1946
|
openaiModels: result.openai || [],
|
|
1947
|
+
zhipuModels: result.zhipu || [],
|
|
1808
1948
|
errors: result.errors
|
|
1809
1949
|
});
|
|
1810
1950
|
} catch (error) {
|
|
@@ -1812,6 +1952,7 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1812
1952
|
loading: false,
|
|
1813
1953
|
anthropicModels: [],
|
|
1814
1954
|
openaiModels: [],
|
|
1955
|
+
zhipuModels: [],
|
|
1815
1956
|
errors: [{
|
|
1816
1957
|
provider: "Unknown",
|
|
1817
1958
|
error: String(error)
|
|
@@ -1856,6 +1997,10 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1856
1997
|
/* @__PURE__ */ jsx(Text, {
|
|
1857
1998
|
dimColor: true,
|
|
1858
1999
|
children: " • OpenAI (GPT)"
|
|
2000
|
+
}),
|
|
2001
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2002
|
+
dimColor: true,
|
|
2003
|
+
children: " • Zhipu (GLM)"
|
|
1859
2004
|
})
|
|
1860
2005
|
]
|
|
1861
2006
|
});
|
|
@@ -1876,7 +2021,7 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1876
2021
|
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Spinner, { label: "Fetching models from API..." }) })
|
|
1877
2022
|
]
|
|
1878
2023
|
});
|
|
1879
|
-
if (
|
|
2024
|
+
if (availableProviders.length === 0 || availableProviders.every((p) => p.modelCount === 0)) return /* @__PURE__ */ jsxs(Box, {
|
|
1880
2025
|
flexDirection: "column",
|
|
1881
2026
|
borderStyle: "single",
|
|
1882
2027
|
borderColor: colors.error,
|
|
@@ -1887,7 +2032,7 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1887
2032
|
/* @__PURE__ */ jsxs(Text, {
|
|
1888
2033
|
bold: true,
|
|
1889
2034
|
color: colors.error,
|
|
1890
|
-
children: [emoji.error, "
|
|
2035
|
+
children: [emoji.error, " No Models Available"]
|
|
1891
2036
|
}),
|
|
1892
2037
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1893
2038
|
state.errors.map((err, i) => /* @__PURE__ */ jsxs(Text, {
|
|
@@ -1905,9 +2050,7 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1905
2050
|
})
|
|
1906
2051
|
]
|
|
1907
2052
|
});
|
|
1908
|
-
|
|
1909
|
-
let openaiOffset = state.anthropicModels.length;
|
|
1910
|
-
return /* @__PURE__ */ jsxs(Box, {
|
|
2053
|
+
if (step === "select-provider") return /* @__PURE__ */ jsxs(Box, {
|
|
1911
2054
|
flexDirection: "column",
|
|
1912
2055
|
borderStyle: "single",
|
|
1913
2056
|
borderColor: colors.primary,
|
|
@@ -1918,7 +2061,7 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1918
2061
|
/* @__PURE__ */ jsxs(Text, {
|
|
1919
2062
|
bold: true,
|
|
1920
2063
|
color: colors.info,
|
|
1921
|
-
children: [emoji.model, " Select
|
|
2064
|
+
children: [emoji.model, " Select Provider"]
|
|
1922
2065
|
}),
|
|
1923
2066
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1924
2067
|
state.errors.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [state.errors.map((err, i) => /* @__PURE__ */ jsxs(Text, {
|
|
@@ -1931,42 +2074,53 @@ function ModelSelectionPanel({ currentModel, onModelSelect, onClose }) {
|
|
|
1931
2074
|
err.error
|
|
1932
2075
|
]
|
|
1933
2076
|
}, i)), /* @__PURE__ */ jsx(Box, { height: 1 })] }),
|
|
1934
|
-
|
|
1935
|
-
/* @__PURE__ */ jsx(
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
})
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
model,
|
|
1943
|
-
isSelected: anthropicOffset + index === selectedIndex,
|
|
1944
|
-
isCurrent: isCurrentModel(currentModel, model)
|
|
1945
|
-
}, model.id);
|
|
1946
|
-
}),
|
|
1947
|
-
/* @__PURE__ */ jsx(Box, { height: 1 })
|
|
1948
|
-
] }),
|
|
1949
|
-
state.openaiModels.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1950
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1951
|
-
bold: true,
|
|
1952
|
-
color: colors.primary,
|
|
1953
|
-
children: "OpenAI GPT"
|
|
1954
|
-
}),
|
|
1955
|
-
state.openaiModels.map((model, index) => {
|
|
1956
|
-
return /* @__PURE__ */ jsx(ModelItem, {
|
|
1957
|
-
model,
|
|
1958
|
-
isSelected: openaiOffset + index === selectedIndex,
|
|
1959
|
-
isCurrent: isCurrentModel(currentModel, model)
|
|
1960
|
-
}, model.id);
|
|
1961
|
-
}),
|
|
1962
|
-
/* @__PURE__ */ jsx(Box, { height: 1 })
|
|
1963
|
-
] }),
|
|
2077
|
+
availableProviders.map((provider, index) => {
|
|
2078
|
+
return /* @__PURE__ */ jsx(ProviderItem, {
|
|
2079
|
+
provider,
|
|
2080
|
+
isSelected: index === selectedProviderIndex,
|
|
2081
|
+
isCurrent: currentModel?.startsWith(`${provider.key}/`) ?? false
|
|
2082
|
+
}, provider.key);
|
|
2083
|
+
}),
|
|
2084
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1964
2085
|
/* @__PURE__ */ jsx(Text, {
|
|
1965
2086
|
dimColor: true,
|
|
1966
2087
|
children: "↑/↓ Navigate • Enter Select • Esc Cancel"
|
|
1967
2088
|
})
|
|
1968
2089
|
]
|
|
1969
2090
|
});
|
|
2091
|
+
const selectedProviderInfo = availableProviders.find((p) => p.key === selectedProvider);
|
|
2092
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2093
|
+
flexDirection: "column",
|
|
2094
|
+
borderStyle: "single",
|
|
2095
|
+
borderColor: colors.primary,
|
|
2096
|
+
paddingX: 2,
|
|
2097
|
+
paddingY: 1,
|
|
2098
|
+
marginY: 1,
|
|
2099
|
+
children: [
|
|
2100
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2101
|
+
bold: true,
|
|
2102
|
+
color: colors.info,
|
|
2103
|
+
children: [
|
|
2104
|
+
emoji.model,
|
|
2105
|
+
" Select Model - ",
|
|
2106
|
+
selectedProviderInfo?.name
|
|
2107
|
+
]
|
|
2108
|
+
}),
|
|
2109
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2110
|
+
currentProviderModels.map((model, index) => {
|
|
2111
|
+
return /* @__PURE__ */ jsx(ModelItem, {
|
|
2112
|
+
model,
|
|
2113
|
+
isSelected: index === selectedModelIndex,
|
|
2114
|
+
isCurrent: isCurrentModel(currentModel, model)
|
|
2115
|
+
}, model.id);
|
|
2116
|
+
}),
|
|
2117
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2118
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2119
|
+
dimColor: true,
|
|
2120
|
+
children: "↑/↓ Navigate • Enter Select • ←/Esc Back"
|
|
2121
|
+
})
|
|
2122
|
+
]
|
|
2123
|
+
});
|
|
1970
2124
|
}
|
|
1971
2125
|
/**
|
|
1972
2126
|
* Check if a model matches the current model.
|
|
@@ -1975,6 +2129,50 @@ function isCurrentModel(currentModel, model) {
|
|
|
1975
2129
|
if (!currentModel) return false;
|
|
1976
2130
|
return currentModel === model.id || currentModel === model.name || currentModel === `${model.provider}/${model.name}` || currentModel.startsWith(`${model.provider}/`) && currentModel === model.id;
|
|
1977
2131
|
}
|
|
2132
|
+
function ProviderItem({ provider, isSelected, isCurrent }) {
|
|
2133
|
+
let indicator = " ";
|
|
2134
|
+
let textColor = void 0;
|
|
2135
|
+
let isBold = false;
|
|
2136
|
+
if (isSelected) {
|
|
2137
|
+
indicator = "▸ ";
|
|
2138
|
+
textColor = colors.primary;
|
|
2139
|
+
isBold = true;
|
|
2140
|
+
}
|
|
2141
|
+
if (isCurrent) {
|
|
2142
|
+
indicator = isSelected ? "▸✓" : " ✓";
|
|
2143
|
+
textColor = isSelected ? colors.primary : colors.success;
|
|
2144
|
+
}
|
|
2145
|
+
const hasModels = provider.modelCount > 0;
|
|
2146
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2147
|
+
marginLeft: 1,
|
|
2148
|
+
children: [
|
|
2149
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2150
|
+
color: isSelected ? colors.primary : isCurrent ? colors.success : void 0,
|
|
2151
|
+
children: indicator
|
|
2152
|
+
}),
|
|
2153
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2154
|
+
color: hasModels ? textColor : colors.muted,
|
|
2155
|
+
bold: isBold,
|
|
2156
|
+
children: provider.name
|
|
2157
|
+
}),
|
|
2158
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2159
|
+
dimColor: true,
|
|
2160
|
+
children: [
|
|
2161
|
+
" ",
|
|
2162
|
+
"(",
|
|
2163
|
+
provider.modelCount,
|
|
2164
|
+
" model",
|
|
2165
|
+
provider.modelCount !== 1 ? "s" : "",
|
|
2166
|
+
")"
|
|
2167
|
+
]
|
|
2168
|
+
}),
|
|
2169
|
+
!hasModels && /* @__PURE__ */ jsx(Text, {
|
|
2170
|
+
color: colors.warning,
|
|
2171
|
+
children: " - loading..."
|
|
2172
|
+
})
|
|
2173
|
+
]
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
1978
2176
|
function ModelItem({ model, isSelected, isCurrent }) {
|
|
1979
2177
|
let indicator = " ";
|
|
1980
2178
|
let textColor = void 0;
|
|
@@ -1988,6 +2186,7 @@ function ModelItem({ model, isSelected, isCurrent }) {
|
|
|
1988
2186
|
indicator = isSelected ? "▸✓" : " ✓";
|
|
1989
2187
|
textColor = isSelected ? colors.primary : colors.success;
|
|
1990
2188
|
}
|
|
2189
|
+
const displayName = model.name;
|
|
1991
2190
|
return /* @__PURE__ */ jsxs(Box, {
|
|
1992
2191
|
marginLeft: 1,
|
|
1993
2192
|
children: [
|
|
@@ -1998,7 +2197,7 @@ function ModelItem({ model, isSelected, isCurrent }) {
|
|
|
1998
2197
|
/* @__PURE__ */ jsx(Text, {
|
|
1999
2198
|
color: textColor,
|
|
2000
2199
|
bold: isBold,
|
|
2001
|
-
children:
|
|
2200
|
+
children: displayName
|
|
2002
2201
|
}),
|
|
2003
2202
|
model.description && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
|
|
2004
2203
|
dimColor: true,
|
|
@@ -2024,6 +2223,7 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2024
2223
|
const [error, setError] = useState(null);
|
|
2025
2224
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
2026
2225
|
const openaiKey = process.env.OPENAI_API_KEY;
|
|
2226
|
+
const zhipuKey = process.env.ZHIPU_API_KEY;
|
|
2027
2227
|
const maskKey = (key) => {
|
|
2028
2228
|
if (!key) return null;
|
|
2029
2229
|
if (key.length <= 8) return "•".repeat(key.length);
|
|
@@ -2041,6 +2241,11 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2041
2241
|
setStep("enter-key");
|
|
2042
2242
|
setError(null);
|
|
2043
2243
|
if (openaiKey) setApiKey(openaiKey);
|
|
2244
|
+
} else if (input === "3" || input.toLowerCase() === "z") {
|
|
2245
|
+
setSelectedProvider("zhipu");
|
|
2246
|
+
setStep("enter-key");
|
|
2247
|
+
setError(null);
|
|
2248
|
+
if (zhipuKey) setApiKey(zhipuKey);
|
|
2044
2249
|
} else if (key.escape) onClose?.();
|
|
2045
2250
|
} else if (step === "enter-key") {
|
|
2046
2251
|
if (key.escape) {
|
|
@@ -2053,16 +2258,9 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2053
2258
|
setError("API key cannot be empty");
|
|
2054
2259
|
return;
|
|
2055
2260
|
}
|
|
2056
|
-
if (selectedProvider === "anthropic" && !apiKey.startsWith("sk-ant-")) {
|
|
2057
|
-
setError("Anthropic API keys typically start with 'sk-ant-'");
|
|
2058
|
-
return;
|
|
2059
|
-
}
|
|
2060
|
-
if (selectedProvider === "openai" && !apiKey.startsWith("sk-")) {
|
|
2061
|
-
setError("OpenAI API keys typically start with 'sk-'");
|
|
2062
|
-
return;
|
|
2063
|
-
}
|
|
2064
2261
|
if (selectedProvider === "anthropic") process.env.ANTHROPIC_API_KEY = apiKey.trim();
|
|
2065
2262
|
else if (selectedProvider === "openai") process.env.OPENAI_API_KEY = apiKey.trim();
|
|
2263
|
+
else if (selectedProvider === "zhipu") process.env.ZHIPU_API_KEY = apiKey.trim();
|
|
2066
2264
|
setStep("success");
|
|
2067
2265
|
onKeySaved?.(selectedProvider, apiKey.trim());
|
|
2068
2266
|
setTimeout(() => {
|
|
@@ -2156,6 +2354,30 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2156
2354
|
})
|
|
2157
2355
|
] })
|
|
2158
2356
|
}),
|
|
2357
|
+
/* @__PURE__ */ jsx(Box, {
|
|
2358
|
+
marginLeft: 2,
|
|
2359
|
+
children: zhipuKey ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2360
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2361
|
+
color: colors.success,
|
|
2362
|
+
children: "✓ "
|
|
2363
|
+
}),
|
|
2364
|
+
/* @__PURE__ */ jsx(Text, { children: "Zhipu: " }),
|
|
2365
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2366
|
+
dimColor: true,
|
|
2367
|
+
children: maskKey(zhipuKey)
|
|
2368
|
+
})
|
|
2369
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2370
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2371
|
+
color: colors.warning,
|
|
2372
|
+
children: "✗ "
|
|
2373
|
+
}),
|
|
2374
|
+
/* @__PURE__ */ jsx(Text, { children: "Zhipu: " }),
|
|
2375
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2376
|
+
dimColor: true,
|
|
2377
|
+
children: "not set"
|
|
2378
|
+
})
|
|
2379
|
+
] })
|
|
2380
|
+
}),
|
|
2159
2381
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2160
2382
|
step === "select-provider" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2161
2383
|
/* @__PURE__ */ jsx(Text, {
|
|
@@ -2191,10 +2413,24 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2191
2413
|
})
|
|
2192
2414
|
]
|
|
2193
2415
|
}),
|
|
2416
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
2417
|
+
marginLeft: 2,
|
|
2418
|
+
children: [
|
|
2419
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2420
|
+
color: colors.primary,
|
|
2421
|
+
children: "[3]"
|
|
2422
|
+
}),
|
|
2423
|
+
/* @__PURE__ */ jsx(Text, { children: " Zhipu (GLM)" }),
|
|
2424
|
+
zhipuKey && /* @__PURE__ */ jsx(Text, {
|
|
2425
|
+
dimColor: true,
|
|
2426
|
+
children: " (overwrite)"
|
|
2427
|
+
})
|
|
2428
|
+
]
|
|
2429
|
+
}),
|
|
2194
2430
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2195
2431
|
/* @__PURE__ */ jsx(Text, {
|
|
2196
2432
|
dimColor: true,
|
|
2197
|
-
children: "Press 1 or
|
|
2433
|
+
children: "Press 1, 2, or 3 to select, Esc to close"
|
|
2198
2434
|
})
|
|
2199
2435
|
] }),
|
|
2200
2436
|
step === "enter-key" && selectedProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -2203,10 +2439,10 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2203
2439
|
" ",
|
|
2204
2440
|
/* @__PURE__ */ jsx(Text, {
|
|
2205
2441
|
color: colors.primary,
|
|
2206
|
-
children: selectedProvider === "anthropic" ? "Anthropic" : "OpenAI"
|
|
2442
|
+
children: selectedProvider === "anthropic" ? "Anthropic" : selectedProvider === "openai" ? "OpenAI" : "Zhipu"
|
|
2207
2443
|
}),
|
|
2208
2444
|
" ",
|
|
2209
|
-
"API key
|
|
2445
|
+
"API key",
|
|
2210
2446
|
selectedProvider === "anthropic" && anthropicKey && /* @__PURE__ */ jsxs(Text, {
|
|
2211
2447
|
dimColor: true,
|
|
2212
2448
|
children: [
|
|
@@ -2222,7 +2458,16 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2222
2458
|
maskKey(openaiKey),
|
|
2223
2459
|
")"
|
|
2224
2460
|
]
|
|
2225
|
-
})
|
|
2461
|
+
}),
|
|
2462
|
+
selectedProvider === "zhipu" && zhipuKey && /* @__PURE__ */ jsxs(Text, {
|
|
2463
|
+
dimColor: true,
|
|
2464
|
+
children: [
|
|
2465
|
+
" (current: ",
|
|
2466
|
+
maskKey(zhipuKey),
|
|
2467
|
+
")"
|
|
2468
|
+
]
|
|
2469
|
+
}),
|
|
2470
|
+
":"
|
|
2226
2471
|
] }),
|
|
2227
2472
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2228
2473
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
@@ -2260,7 +2505,270 @@ function ApiKeyInputPanel({ onKeySaved, onClose }) {
|
|
|
2260
2505
|
emoji.completed,
|
|
2261
2506
|
" API key saved for",
|
|
2262
2507
|
" ",
|
|
2263
|
-
selectedProvider === "anthropic" ? "Anthropic" : "OpenAI",
|
|
2508
|
+
selectedProvider === "anthropic" ? "Anthropic" : selectedProvider === "openai" ? "OpenAI" : "Zhipu",
|
|
2509
|
+
"!"
|
|
2510
|
+
]
|
|
2511
|
+
}),
|
|
2512
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2513
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2514
|
+
dimColor: true,
|
|
2515
|
+
children: "Press Enter or Esc to return to menu"
|
|
2516
|
+
})
|
|
2517
|
+
] })
|
|
2518
|
+
]
|
|
2519
|
+
});
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
//#endregion
|
|
2523
|
+
//#region src/cli/components/BaseURLInput.tsx
|
|
2524
|
+
/**
|
|
2525
|
+
* BaseURLInput Component
|
|
2526
|
+
*
|
|
2527
|
+
* Interactive component for setting custom base URLs for AI providers.
|
|
2528
|
+
* Accessed via the /baseurl slash command in the CLI.
|
|
2529
|
+
*/
|
|
2530
|
+
function BaseURLInput({ onSubmit, onCancel }) {
|
|
2531
|
+
const [step, setStep] = useState("select-provider");
|
|
2532
|
+
const [selectedProvider, setSelectedProvider] = useState(null);
|
|
2533
|
+
const [baseURL, setBaseURL] = useState("");
|
|
2534
|
+
const [error, setError] = useState(null);
|
|
2535
|
+
const anthropicBaseURL = process.env.ANTHROPIC_BASE_URL;
|
|
2536
|
+
const openaiBaseURL = process.env.OPENAI_BASE_URL;
|
|
2537
|
+
const zhipuBaseURL = process.env.ZHIPU_BASE_URL;
|
|
2538
|
+
useInput((input, key) => {
|
|
2539
|
+
if (step === "select-provider") {
|
|
2540
|
+
if (input === "1" || input.toLowerCase() === "a") {
|
|
2541
|
+
setSelectedProvider("anthropic");
|
|
2542
|
+
setStep("enter-url");
|
|
2543
|
+
setError(null);
|
|
2544
|
+
if (anthropicBaseURL) setBaseURL(anthropicBaseURL);
|
|
2545
|
+
else setBaseURL("");
|
|
2546
|
+
} else if (input === "2" || input.toLowerCase() === "o") {
|
|
2547
|
+
setSelectedProvider("openai");
|
|
2548
|
+
setStep("enter-url");
|
|
2549
|
+
setError(null);
|
|
2550
|
+
if (openaiBaseURL) setBaseURL(openaiBaseURL);
|
|
2551
|
+
else setBaseURL("");
|
|
2552
|
+
} else if (input === "3" || input.toLowerCase() === "z") {
|
|
2553
|
+
setSelectedProvider("zhipu");
|
|
2554
|
+
setStep("enter-url");
|
|
2555
|
+
setError(null);
|
|
2556
|
+
if (zhipuBaseURL) setBaseURL(zhipuBaseURL);
|
|
2557
|
+
else setBaseURL("");
|
|
2558
|
+
} else if (key.escape) onCancel();
|
|
2559
|
+
} else if (step === "enter-url") {
|
|
2560
|
+
if (key.escape) {
|
|
2561
|
+
setStep("select-provider");
|
|
2562
|
+
setBaseURL("");
|
|
2563
|
+
setSelectedProvider(null);
|
|
2564
|
+
setError(null);
|
|
2565
|
+
} else if (key.return) {
|
|
2566
|
+
if (!baseURL.trim()) {
|
|
2567
|
+
setError("Base URL cannot be empty");
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
try {
|
|
2571
|
+
new URL(baseURL.trim());
|
|
2572
|
+
} catch (err) {
|
|
2573
|
+
setError("Invalid URL format. Example: https://api.anthropic.com/v1");
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
setStep("success");
|
|
2577
|
+
onSubmit(selectedProvider, baseURL.trim());
|
|
2578
|
+
setTimeout(() => {
|
|
2579
|
+
setStep("select-provider");
|
|
2580
|
+
setBaseURL("");
|
|
2581
|
+
setSelectedProvider(null);
|
|
2582
|
+
setError(null);
|
|
2583
|
+
}, 1500);
|
|
2584
|
+
} else if (key.backspace || key.delete) {
|
|
2585
|
+
setBaseURL((prev) => prev.slice(0, -1));
|
|
2586
|
+
setError(null);
|
|
2587
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
2588
|
+
setBaseURL((prev) => prev + input);
|
|
2589
|
+
setError(null);
|
|
2590
|
+
}
|
|
2591
|
+
} else if (step === "success") {
|
|
2592
|
+
if (key.return || key.escape) {
|
|
2593
|
+
setStep("select-provider");
|
|
2594
|
+
setBaseURL("");
|
|
2595
|
+
setSelectedProvider(null);
|
|
2596
|
+
setError(null);
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
});
|
|
2600
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2601
|
+
flexDirection: "column",
|
|
2602
|
+
borderStyle: "single",
|
|
2603
|
+
borderColor: colors.primary,
|
|
2604
|
+
paddingX: 2,
|
|
2605
|
+
paddingY: 1,
|
|
2606
|
+
marginY: 1,
|
|
2607
|
+
children: [
|
|
2608
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2609
|
+
bold: true,
|
|
2610
|
+
color: colors.info,
|
|
2611
|
+
children: "🌐 Base URL Configuration"
|
|
2612
|
+
}),
|
|
2613
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2614
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2615
|
+
bold: true,
|
|
2616
|
+
children: "Current Base URLs:"
|
|
2617
|
+
}),
|
|
2618
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2619
|
+
/* @__PURE__ */ jsx(Box, {
|
|
2620
|
+
marginLeft: 2,
|
|
2621
|
+
children: anthropicBaseURL ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2622
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2623
|
+
color: colors.success,
|
|
2624
|
+
children: "✓ "
|
|
2625
|
+
}),
|
|
2626
|
+
/* @__PURE__ */ jsx(Text, { children: "Anthropic: " }),
|
|
2627
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2628
|
+
dimColor: true,
|
|
2629
|
+
children: anthropicBaseURL
|
|
2630
|
+
})
|
|
2631
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2632
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2633
|
+
dimColor: true,
|
|
2634
|
+
children: "○ "
|
|
2635
|
+
}),
|
|
2636
|
+
/* @__PURE__ */ jsx(Text, { children: "Anthropic: " }),
|
|
2637
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2638
|
+
dimColor: true,
|
|
2639
|
+
children: "default"
|
|
2640
|
+
})
|
|
2641
|
+
] })
|
|
2642
|
+
}),
|
|
2643
|
+
/* @__PURE__ */ jsx(Box, {
|
|
2644
|
+
marginLeft: 2,
|
|
2645
|
+
children: openaiBaseURL ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2646
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2647
|
+
color: colors.success,
|
|
2648
|
+
children: "✓ "
|
|
2649
|
+
}),
|
|
2650
|
+
/* @__PURE__ */ jsx(Text, { children: "OpenAI: " }),
|
|
2651
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2652
|
+
dimColor: true,
|
|
2653
|
+
children: openaiBaseURL
|
|
2654
|
+
})
|
|
2655
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2656
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2657
|
+
dimColor: true,
|
|
2658
|
+
children: "○ "
|
|
2659
|
+
}),
|
|
2660
|
+
/* @__PURE__ */ jsx(Text, { children: "OpenAI: " }),
|
|
2661
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2662
|
+
dimColor: true,
|
|
2663
|
+
children: "default"
|
|
2664
|
+
})
|
|
2665
|
+
] })
|
|
2666
|
+
}),
|
|
2667
|
+
/* @__PURE__ */ jsx(Box, {
|
|
2668
|
+
marginLeft: 2,
|
|
2669
|
+
children: zhipuBaseURL ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2670
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2671
|
+
color: colors.success,
|
|
2672
|
+
children: "✓ "
|
|
2673
|
+
}),
|
|
2674
|
+
/* @__PURE__ */ jsx(Text, { children: "Zhipu: " }),
|
|
2675
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2676
|
+
dimColor: true,
|
|
2677
|
+
children: zhipuBaseURL
|
|
2678
|
+
})
|
|
2679
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2680
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2681
|
+
dimColor: true,
|
|
2682
|
+
children: "○ "
|
|
2683
|
+
}),
|
|
2684
|
+
/* @__PURE__ */ jsx(Text, { children: "Zhipu: " }),
|
|
2685
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2686
|
+
dimColor: true,
|
|
2687
|
+
children: "default"
|
|
2688
|
+
})
|
|
2689
|
+
] })
|
|
2690
|
+
}),
|
|
2691
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2692
|
+
step === "select-provider" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2693
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2694
|
+
bold: true,
|
|
2695
|
+
children: "Set Custom Base URL:"
|
|
2696
|
+
}),
|
|
2697
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2698
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
2699
|
+
marginLeft: 2,
|
|
2700
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
2701
|
+
color: colors.primary,
|
|
2702
|
+
children: "[1]"
|
|
2703
|
+
}), /* @__PURE__ */ jsx(Text, { children: " Anthropic (Claude)" })]
|
|
2704
|
+
}),
|
|
2705
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
2706
|
+
marginLeft: 2,
|
|
2707
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
2708
|
+
color: colors.primary,
|
|
2709
|
+
children: "[2]"
|
|
2710
|
+
}), /* @__PURE__ */ jsx(Text, { children: " OpenAI (GPT)" })]
|
|
2711
|
+
}),
|
|
2712
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
2713
|
+
marginLeft: 2,
|
|
2714
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
2715
|
+
color: colors.primary,
|
|
2716
|
+
children: "[3]"
|
|
2717
|
+
}), /* @__PURE__ */ jsx(Text, { children: " Zhipu (GLM)" })]
|
|
2718
|
+
}),
|
|
2719
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2720
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2721
|
+
dimColor: true,
|
|
2722
|
+
children: "Press 1, 2, or 3 to select, Esc to close"
|
|
2723
|
+
})
|
|
2724
|
+
] }),
|
|
2725
|
+
step === "enter-url" && selectedProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2726
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2727
|
+
"Enter base URL for",
|
|
2728
|
+
" ",
|
|
2729
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2730
|
+
color: colors.primary,
|
|
2731
|
+
children: selectedProvider === "anthropic" ? "Anthropic" : selectedProvider === "openai" ? "OpenAI" : "Zhipu"
|
|
2732
|
+
}),
|
|
2733
|
+
":"
|
|
2734
|
+
] }),
|
|
2735
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2736
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
2737
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2738
|
+
dimColor: true,
|
|
2739
|
+
children: [">", " "]
|
|
2740
|
+
}),
|
|
2741
|
+
/* @__PURE__ */ jsx(Text, { children: baseURL || /* @__PURE__ */ jsx(Text, {
|
|
2742
|
+
dimColor: true,
|
|
2743
|
+
children: "Type URL here..."
|
|
2744
|
+
}) }),
|
|
2745
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2746
|
+
color: colors.primary,
|
|
2747
|
+
children: "█"
|
|
2748
|
+
})
|
|
2749
|
+
] }),
|
|
2750
|
+
error && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Box, { height: 1 }), /* @__PURE__ */ jsxs(Text, {
|
|
2751
|
+
color: colors.error,
|
|
2752
|
+
children: [
|
|
2753
|
+
emoji.warning,
|
|
2754
|
+
" ",
|
|
2755
|
+
error
|
|
2756
|
+
]
|
|
2757
|
+
})] }),
|
|
2758
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
2759
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2760
|
+
dimColor: true,
|
|
2761
|
+
children: "Press Enter to save, Esc to go back"
|
|
2762
|
+
})
|
|
2763
|
+
] }),
|
|
2764
|
+
step === "success" && selectedProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2765
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2766
|
+
color: colors.success,
|
|
2767
|
+
children: [
|
|
2768
|
+
emoji.completed,
|
|
2769
|
+
" Base URL saved for",
|
|
2770
|
+
" ",
|
|
2771
|
+
selectedProvider === "anthropic" ? "Anthropic" : selectedProvider === "openai" ? "OpenAI" : "Zhipu",
|
|
2264
2772
|
"!"
|
|
2265
2773
|
]
|
|
2266
2774
|
}),
|
|
@@ -2352,6 +2860,7 @@ function ToolApproval({ toolName, args, onApprove, onDeny, onApproveAll }) {
|
|
|
2352
2860
|
* Or with options:
|
|
2353
2861
|
* ANTHROPIC_API_KEY=xxx bunx deep-agent-ink --model anthropic/claude-sonnet-4-20250514
|
|
2354
2862
|
*/
|
|
2863
|
+
init_limits();
|
|
2355
2864
|
const DEFAULT_PROMPT_CACHING = true;
|
|
2356
2865
|
const DEFAULT_EVICTION_LIMIT = DEFAULT_EVICTION_TOKEN_LIMIT;
|
|
2357
2866
|
const DEFAULT_SUMMARIZATION = true;
|
|
@@ -2400,7 +2909,13 @@ function parseArgs() {
|
|
|
2400
2909
|
} else if (arg && arg.startsWith("--session=")) {
|
|
2401
2910
|
const sessionVal = arg.split("=")[1];
|
|
2402
2911
|
if (sessionVal) options.session = sessionVal;
|
|
2403
|
-
} else if (arg === "--
|
|
2912
|
+
} else if (arg === "--anthropic-base-url") options.anthropicBaseURL = args[++i];
|
|
2913
|
+
else if (arg === "--openai-base-url") options.openaiBaseURL = args[++i];
|
|
2914
|
+
else if (arg === "--zhipu-base-url") options.zhipuBaseURL = args[++i];
|
|
2915
|
+
else if (arg === "--anthropic-api-key") options.anthropicApiKey = args[++i];
|
|
2916
|
+
else if (arg === "--openai-api-key") options.openaiApiKey = args[++i];
|
|
2917
|
+
else if (arg === "--zhipu-api-key") options.zhipuApiKey = args[++i];
|
|
2918
|
+
else if (arg === "--help" || arg === "-h") {
|
|
2404
2919
|
printHelp();
|
|
2405
2920
|
process.exit(0);
|
|
2406
2921
|
}
|
|
@@ -2443,6 +2958,14 @@ Options:
|
|
|
2443
2958
|
--dir, -d <directory> Working directory for file operations (default: current dir)
|
|
2444
2959
|
--help, -h Show this help
|
|
2445
2960
|
|
|
2961
|
+
Provider Configuration:
|
|
2962
|
+
--anthropic-base-url <url> Custom base URL for Anthropic API
|
|
2963
|
+
--openai-base-url <url> Custom base URL for OpenAI API
|
|
2964
|
+
--zhipu-base-url <url> Custom base URL for Zhipu API
|
|
2965
|
+
--anthropic-api-key <key> Anthropic API key (overrides environment variable)
|
|
2966
|
+
--openai-api-key <key> OpenAI API key (overrides environment variable)
|
|
2967
|
+
--zhipu-api-key <key> Zhipu AI API key (overrides environment variable)
|
|
2968
|
+
|
|
2446
2969
|
Performance & Memory (all enabled by default):
|
|
2447
2970
|
--no-cache Disable prompt caching (enabled by default for Anthropic)
|
|
2448
2971
|
--no-eviction Disable tool result eviction (enabled by default: 20k tokens)
|
|
@@ -2459,12 +2982,16 @@ Runtime Commands:
|
|
|
2459
2982
|
|
|
2460
2983
|
API Keys:
|
|
2461
2984
|
The CLI automatically loads API keys from:
|
|
2462
|
-
1. Environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, TAVILY_API_KEY)
|
|
2985
|
+
1. Environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, ZHIPU_API_KEY, TAVILY_API_KEY)
|
|
2463
2986
|
2. .env or .env.local file in the working directory
|
|
2464
2987
|
|
|
2465
2988
|
Example .env file:
|
|
2466
2989
|
ANTHROPIC_API_KEY=sk-ant-...
|
|
2467
2990
|
OPENAI_API_KEY=sk-...
|
|
2991
|
+
ZHIPU_API_KEY=...
|
|
2992
|
+
ANTHROPIC_BASE_URL=https://custom-endpoint.com/v1
|
|
2993
|
+
OPENAI_BASE_URL=https://custom-openai-endpoint.com/v1
|
|
2994
|
+
ZHIPU_BASE_URL=https://api.z.ai/api/coding/paas/v4
|
|
2468
2995
|
TAVILY_API_KEY=tvly-... # For web_search tool
|
|
2469
2996
|
|
|
2470
2997
|
Examples:
|
|
@@ -2472,14 +2999,20 @@ Examples:
|
|
|
2472
2999
|
bun src/cli-ink/index.tsx --dir ./my-project # loads .env from ./my-project
|
|
2473
3000
|
ANTHROPIC_API_KEY=xxx bun src/cli-ink/index.tsx # env var takes precedence
|
|
2474
3001
|
bun src/cli-ink/index.tsx --model anthropic/claude-sonnet-4-20250514
|
|
3002
|
+
|
|
3003
|
+
# Use Zhipu with custom base URL
|
|
3004
|
+
bun src/cli-ink/index.tsx --model zhipu/glm-4-plus --zhipu-base-url https://api.z.ai/api/coding/paas/v4
|
|
3005
|
+
|
|
3006
|
+
# Use Anthropic with custom API key
|
|
3007
|
+
bun src/cli-ink/index.tsx --model anthropic/claude-3.5-sonnet --anthropic-api-key sk-custom-...
|
|
2475
3008
|
`);
|
|
2476
3009
|
}
|
|
2477
3010
|
function App({ options, backend }) {
|
|
2478
3011
|
const { exit } = useApp();
|
|
2479
3012
|
const summarizationConfig = options.enableSummarization ? {
|
|
2480
3013
|
enabled: true,
|
|
2481
|
-
tokenThreshold: options.summarizationThreshold,
|
|
2482
|
-
keepMessages: options.summarizationKeepMessages
|
|
3014
|
+
tokenThreshold: options.summarizationThreshold ?? DEFAULT_SUMMARIZATION_THRESHOLD,
|
|
3015
|
+
keepMessages: options.summarizationKeepMessages ?? DEFAULT_KEEP_MESSAGES
|
|
2483
3016
|
} : void 0;
|
|
2484
3017
|
const checkpointer = options.session ? new FileSaver({ dir: "./.checkpoints" }) : void 0;
|
|
2485
3018
|
const agent = useAgent({
|
|
@@ -2555,6 +3088,10 @@ function App({ options, backend }) {
|
|
|
2555
3088
|
case "api":
|
|
2556
3089
|
setPanel({ view: "apikey-input" });
|
|
2557
3090
|
break;
|
|
3091
|
+
case "baseurl":
|
|
3092
|
+
case "base-url":
|
|
3093
|
+
setPanel({ view: "baseurl-input" });
|
|
3094
|
+
break;
|
|
2558
3095
|
case "model":
|
|
2559
3096
|
if (args) agent.setModel(args.trim());
|
|
2560
3097
|
else setPanel({ view: "models" });
|
|
@@ -2666,7 +3203,7 @@ function App({ options, backend }) {
|
|
|
2666
3203
|
}
|
|
2667
3204
|
};
|
|
2668
3205
|
const isGenerating = agent.status !== "idle" && agent.status !== "done" && agent.status !== "error";
|
|
2669
|
-
const isInteractivePanel = panel.view === "apikey-input" || panel.view === "models";
|
|
3206
|
+
const isInteractivePanel = panel.view === "apikey-input" || panel.view === "baseurl-input" || panel.view === "models";
|
|
2670
3207
|
return /* @__PURE__ */ jsxs(Box, {
|
|
2671
3208
|
flexDirection: "column",
|
|
2672
3209
|
padding: 1,
|
|
@@ -2686,6 +3223,19 @@ function App({ options, backend }) {
|
|
|
2686
3223
|
onKeySaved: () => {},
|
|
2687
3224
|
onClose: () => setPanel({ view: "none" })
|
|
2688
3225
|
}),
|
|
3226
|
+
panel.view === "baseurl-input" && /* @__PURE__ */ jsx(BaseURLInput, {
|
|
3227
|
+
onSubmit: (provider, baseURL) => {
|
|
3228
|
+
const providerConfig = getProvidersConfig()[provider] || {};
|
|
3229
|
+
setProvidersConfig({ [provider]: {
|
|
3230
|
+
...providerConfig,
|
|
3231
|
+
baseURL
|
|
3232
|
+
} });
|
|
3233
|
+
const envVar = `${provider.toUpperCase()}_BASE_URL`;
|
|
3234
|
+
process.env[envVar] = baseURL;
|
|
3235
|
+
console.log(`\x1b[32m✓\x1b[0m Set ${provider} base URL: ${baseURL}`);
|
|
3236
|
+
},
|
|
3237
|
+
onCancel: () => setPanel({ view: "none" })
|
|
3238
|
+
}),
|
|
2689
3239
|
panel.view === "features" && /* @__PURE__ */ jsx(FeaturesPanel, {
|
|
2690
3240
|
features: agent.features,
|
|
2691
3241
|
options
|
|
@@ -3069,7 +3619,14 @@ function TokensPanel({ tokenCount, messageCount }) {
|
|
|
3069
3619
|
*/
|
|
3070
3620
|
async function loadEnvFile(workDir) {
|
|
3071
3621
|
const envPaths = [`${workDir}/.env`, `${workDir}/.env.local`];
|
|
3072
|
-
const keysToCheck = [
|
|
3622
|
+
const keysToCheck = [
|
|
3623
|
+
"ANTHROPIC_API_KEY",
|
|
3624
|
+
"OPENAI_API_KEY",
|
|
3625
|
+
"ZHIPU_API_KEY",
|
|
3626
|
+
"ANTHROPIC_BASE_URL",
|
|
3627
|
+
"OPENAI_BASE_URL",
|
|
3628
|
+
"ZHIPU_BASE_URL"
|
|
3629
|
+
];
|
|
3073
3630
|
const result = {
|
|
3074
3631
|
loaded: false,
|
|
3075
3632
|
keysFound: []
|
|
@@ -3107,7 +3664,41 @@ async function main() {
|
|
|
3107
3664
|
const workDir = options.workDir || process.cwd();
|
|
3108
3665
|
const envResult = await loadEnvFile(workDir);
|
|
3109
3666
|
if (envResult.loaded && envResult.keysFound.length > 0) console.log(`\x1b[32m✓\x1b[0m Loaded API keys from ${envResult.path}: ${envResult.keysFound.join(", ")}`);
|
|
3110
|
-
if (!process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) console.log(`\x1b[33m⚠\x1b[0m No API keys found. Set ANTHROPIC_API_KEY or
|
|
3667
|
+
if (!process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY && !process.env.ZHIPU_API_KEY) console.log(`\x1b[33m⚠\x1b[0m No API keys found. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or ZHIPU_API_KEY in environment or .env file.`);
|
|
3668
|
+
const providerConfig = {};
|
|
3669
|
+
if (process.env.ANTHROPIC_BASE_URL || process.env.ANTHROPIC_API_KEY) providerConfig.anthropic = {
|
|
3670
|
+
baseURL: process.env.ANTHROPIC_BASE_URL,
|
|
3671
|
+
apiKey: process.env.ANTHROPIC_API_KEY
|
|
3672
|
+
};
|
|
3673
|
+
if (process.env.OPENAI_BASE_URL || process.env.OPENAI_API_KEY) providerConfig.openai = {
|
|
3674
|
+
baseURL: process.env.OPENAI_BASE_URL,
|
|
3675
|
+
apiKey: process.env.OPENAI_API_KEY
|
|
3676
|
+
};
|
|
3677
|
+
if (process.env.ZHIPU_BASE_URL || process.env.ZHIPU_API_KEY) providerConfig.zhipu = {
|
|
3678
|
+
baseURL: process.env.ZHIPU_BASE_URL,
|
|
3679
|
+
apiKey: process.env.ZHIPU_API_KEY
|
|
3680
|
+
};
|
|
3681
|
+
setProvidersConfig(providerConfig);
|
|
3682
|
+
const loadedBaseUrls = Object.entries(providerConfig).filter(([_, config]) => config?.baseURL).map(([provider]) => provider);
|
|
3683
|
+
if (loadedBaseUrls.length > 0) console.log(`\x1b[32m✓\x1b[0m Loaded custom base URLs: ${loadedBaseUrls.join(", ")}`);
|
|
3684
|
+
const cliConfig = {};
|
|
3685
|
+
if (options.anthropicBaseURL || options.anthropicApiKey) cliConfig.anthropic = {
|
|
3686
|
+
baseURL: options.anthropicBaseURL,
|
|
3687
|
+
apiKey: options.anthropicApiKey
|
|
3688
|
+
};
|
|
3689
|
+
if (options.openaiBaseURL || options.openaiApiKey) cliConfig.openai = {
|
|
3690
|
+
baseURL: options.openaiBaseURL,
|
|
3691
|
+
apiKey: options.openaiApiKey
|
|
3692
|
+
};
|
|
3693
|
+
if (options.zhipuBaseURL || options.zhipuApiKey) cliConfig.zhipu = {
|
|
3694
|
+
baseURL: options.zhipuBaseURL,
|
|
3695
|
+
apiKey: options.zhipuApiKey
|
|
3696
|
+
};
|
|
3697
|
+
if (Object.keys(cliConfig).length > 0) {
|
|
3698
|
+
setProvidersConfig(cliConfig);
|
|
3699
|
+
const overriddenProviders = Object.keys(cliConfig).join(", ");
|
|
3700
|
+
console.log(`\x1b[32m✓\x1b[0m Applied CLI overrides for: ${overriddenProviders}`);
|
|
3701
|
+
}
|
|
3111
3702
|
render(/* @__PURE__ */ jsx(App, {
|
|
3112
3703
|
options,
|
|
3113
3704
|
backend: new LocalSandbox({ cwd: workDir })
|