apteva 0.3.8 → 0.4.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/App.4z8ded67.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/crypto.ts +8 -0
- package/src/providers.ts +19 -0
- package/src/routes/api.ts +103 -1
- package/src/web/components/agents/AgentPanel.tsx +107 -10
- package/src/web/components/agents/CreateAgentModal.tsx +47 -11
- package/src/web/components/settings/SettingsPage.tsx +46 -11
- package/dist/App.mvbdnw89.js +0 -227
|
@@ -40,6 +40,31 @@ export function CreateAgentModal({
|
|
|
40
40
|
}: CreateAgentModalProps) {
|
|
41
41
|
const { projects, currentProjectId } = useProjects();
|
|
42
42
|
const selectedProvider = providers.find(p => p.id === form.provider);
|
|
43
|
+
const [ollamaModels, setOllamaModels] = React.useState<Array<{ value: string; label: string }>>([]);
|
|
44
|
+
const [loadingOllamaModels, setLoadingOllamaModels] = React.useState(false);
|
|
45
|
+
|
|
46
|
+
// Fetch Ollama models when Ollama is selected
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
if (form.provider === "ollama") {
|
|
49
|
+
setLoadingOllamaModels(true);
|
|
50
|
+
fetch("/api/providers/ollama/models")
|
|
51
|
+
.then(res => res.json())
|
|
52
|
+
.then(data => {
|
|
53
|
+
if (data.models && data.models.length > 0) {
|
|
54
|
+
setOllamaModels(data.models.map((m: { value: string; label?: string }) => ({
|
|
55
|
+
value: m.value,
|
|
56
|
+
label: m.label || m.value,
|
|
57
|
+
})));
|
|
58
|
+
// Auto-select first model if none selected
|
|
59
|
+
if (!form.model && data.models.length > 0) {
|
|
60
|
+
onFormChange({ ...form, model: data.models[0].value });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
.catch(() => setOllamaModels([]))
|
|
65
|
+
.finally(() => setLoadingOllamaModels(false));
|
|
66
|
+
}
|
|
67
|
+
}, [form.provider]);
|
|
43
68
|
|
|
44
69
|
const providerOptions = configuredProviders
|
|
45
70
|
.filter(p => p.type === "llm")
|
|
@@ -48,11 +73,14 @@ export function CreateAgentModal({
|
|
|
48
73
|
label: p.name,
|
|
49
74
|
}));
|
|
50
75
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
76
|
+
// Use dynamic Ollama models if available, otherwise use provider's default models
|
|
77
|
+
const modelOptions = form.provider === "ollama" && ollamaModels.length > 0
|
|
78
|
+
? ollamaModels
|
|
79
|
+
: selectedProvider?.models.map(m => ({
|
|
80
|
+
value: m.value,
|
|
81
|
+
label: m.label,
|
|
82
|
+
recommended: m.recommended,
|
|
83
|
+
})) || [];
|
|
56
84
|
|
|
57
85
|
const projectOptions = projects.map(p => ({ value: p.id, label: p.name }));
|
|
58
86
|
|
|
@@ -158,12 +186,20 @@ export function CreateAgentModal({
|
|
|
158
186
|
</FormField>
|
|
159
187
|
|
|
160
188
|
<FormField label="Model">
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
189
|
+
{loadingOllamaModels ? (
|
|
190
|
+
<div className="text-sm text-[#666] py-2">Loading Ollama models...</div>
|
|
191
|
+
) : form.provider === "ollama" && modelOptions.length === 0 ? (
|
|
192
|
+
<div className="text-sm text-yellow-400/80 py-2">
|
|
193
|
+
No models found. Run <code className="bg-[#1a1a1a] px-1 rounded">ollama pull llama3.3</code> to download a model.
|
|
194
|
+
</div>
|
|
195
|
+
) : (
|
|
196
|
+
<Select
|
|
197
|
+
value={form.model}
|
|
198
|
+
options={modelOptions}
|
|
199
|
+
onChange={(value) => onFormChange({ ...form, model: value })}
|
|
200
|
+
placeholder="Select model..."
|
|
201
|
+
/>
|
|
202
|
+
)}
|
|
167
203
|
</FormField>
|
|
168
204
|
|
|
169
205
|
<FormField label="System Prompt">
|
|
@@ -793,6 +793,19 @@ function ProviderKeyCard({
|
|
|
793
793
|
onSave,
|
|
794
794
|
onDelete,
|
|
795
795
|
}: ProviderKeyCardProps) {
|
|
796
|
+
const isOllama = provider.id === "ollama";
|
|
797
|
+
const [ollamaStatus, setOllamaStatus] = React.useState<{ connected: boolean; modelCount?: number } | null>(null);
|
|
798
|
+
|
|
799
|
+
// Check Ollama status when configured
|
|
800
|
+
React.useEffect(() => {
|
|
801
|
+
if (isOllama && provider.hasKey) {
|
|
802
|
+
fetch("/api/providers/ollama/status")
|
|
803
|
+
.then(res => res.json())
|
|
804
|
+
.then(data => setOllamaStatus({ connected: data.connected, modelCount: data.modelCount }))
|
|
805
|
+
.catch(() => setOllamaStatus({ connected: false }));
|
|
806
|
+
}
|
|
807
|
+
}, [isOllama, provider.hasKey]);
|
|
808
|
+
|
|
796
809
|
return (
|
|
797
810
|
<div className={`bg-[#111] border rounded-lg p-4 ${
|
|
798
811
|
provider.hasKey ? 'border-green-500/20' : 'border-[#1a1a1a]'
|
|
@@ -803,13 +816,28 @@ function ProviderKeyCard({
|
|
|
803
816
|
<p className="text-sm text-[#666] truncate">
|
|
804
817
|
{provider.type === "integration"
|
|
805
818
|
? (provider.description || "MCP integration")
|
|
806
|
-
:
|
|
819
|
+
: isOllama
|
|
820
|
+
? "Run models locally"
|
|
821
|
+
: `${provider.models.length} models`}
|
|
807
822
|
</p>
|
|
808
823
|
</div>
|
|
809
824
|
{provider.hasKey ? (
|
|
810
|
-
<span className=
|
|
811
|
-
|
|
812
|
-
|
|
825
|
+
<span className={`text-xs flex items-center gap-1 px-2 py-1 rounded whitespace-nowrap flex-shrink-0 ${
|
|
826
|
+
isOllama && ollamaStatus
|
|
827
|
+
? ollamaStatus.connected
|
|
828
|
+
? "text-green-400 bg-green-500/10"
|
|
829
|
+
: "text-yellow-400 bg-yellow-500/10"
|
|
830
|
+
: "text-green-400 bg-green-500/10"
|
|
831
|
+
}`}>
|
|
832
|
+
{isOllama && ollamaStatus ? (
|
|
833
|
+
ollamaStatus.connected ? (
|
|
834
|
+
<><CheckIcon className="w-3 h-3" />{ollamaStatus.modelCount} models</>
|
|
835
|
+
) : (
|
|
836
|
+
<>Not running</>
|
|
837
|
+
)
|
|
838
|
+
) : (
|
|
839
|
+
<><CheckIcon className="w-3 h-3" />{provider.keyHint}</>
|
|
840
|
+
)}
|
|
813
841
|
</span>
|
|
814
842
|
) : (
|
|
815
843
|
<span className="text-[#666] text-xs bg-[#1a1a1a] px-2 py-1 rounded whitespace-nowrap flex-shrink-0">
|
|
@@ -822,13 +850,20 @@ function ProviderKeyCard({
|
|
|
822
850
|
{isEditing ? (
|
|
823
851
|
<div className="space-y-3">
|
|
824
852
|
<input
|
|
825
|
-
type="password"
|
|
853
|
+
type={isOllama ? "text" : "password"}
|
|
826
854
|
value={apiKey}
|
|
827
855
|
onChange={e => onApiKeyChange(e.target.value)}
|
|
828
|
-
placeholder={
|
|
856
|
+
placeholder={isOllama
|
|
857
|
+
? "http://localhost:11434"
|
|
858
|
+
: provider.hasKey ? "Enter new API key..." : "Enter API key..."}
|
|
829
859
|
autoFocus
|
|
830
860
|
className="w-full bg-[#0a0a0a] border border-[#333] rounded px-3 py-2 focus:outline-none focus:border-[#f97316]"
|
|
831
861
|
/>
|
|
862
|
+
{isOllama && (
|
|
863
|
+
<p className="text-xs text-[#666]">
|
|
864
|
+
Enter your Ollama server URL. Default is http://localhost:11434
|
|
865
|
+
</p>
|
|
866
|
+
)}
|
|
832
867
|
{error && <p className="text-red-400 text-sm">{error}</p>}
|
|
833
868
|
{success && <p className="text-green-400 text-sm">{success}</p>}
|
|
834
869
|
<div className="flex gap-2">
|
|
@@ -843,7 +878,7 @@ function ProviderKeyCard({
|
|
|
843
878
|
disabled={!apiKey || saving}
|
|
844
879
|
className="flex-1 px-3 py-1.5 bg-[#f97316] text-black rounded text-sm font-medium disabled:opacity-50"
|
|
845
880
|
>
|
|
846
|
-
{testing ? "Validating..." : saving ? "Saving..." : "Save"}
|
|
881
|
+
{testing ? "Validating..." : saving ? "Saving..." : isOllama ? "Connect" : "Save"}
|
|
847
882
|
</button>
|
|
848
883
|
</div>
|
|
849
884
|
</div>
|
|
@@ -855,14 +890,14 @@ function ProviderKeyCard({
|
|
|
855
890
|
rel="noopener noreferrer"
|
|
856
891
|
className="text-sm text-[#3b82f6] hover:underline"
|
|
857
892
|
>
|
|
858
|
-
View docs
|
|
893
|
+
{isOllama ? "Download Ollama" : "View docs"}
|
|
859
894
|
</a>
|
|
860
895
|
<div className="flex items-center gap-3">
|
|
861
896
|
<button
|
|
862
897
|
onClick={onStartEdit}
|
|
863
898
|
className="text-sm text-[#888] hover:text-[#e0e0e0]"
|
|
864
899
|
>
|
|
865
|
-
Update key
|
|
900
|
+
{isOllama ? "Change URL" : "Update key"}
|
|
866
901
|
</button>
|
|
867
902
|
<button
|
|
868
903
|
onClick={onDelete}
|
|
@@ -880,13 +915,13 @@ function ProviderKeyCard({
|
|
|
880
915
|
rel="noopener noreferrer"
|
|
881
916
|
className="text-sm text-[#3b82f6] hover:underline"
|
|
882
917
|
>
|
|
883
|
-
Get API key
|
|
918
|
+
{isOllama ? "Download Ollama" : "Get API key"}
|
|
884
919
|
</a>
|
|
885
920
|
<button
|
|
886
921
|
onClick={onStartEdit}
|
|
887
922
|
className="text-sm text-[#f97316] hover:text-[#fb923c]"
|
|
888
923
|
>
|
|
889
|
-
+ Add key
|
|
924
|
+
{isOllama ? "Configure" : "+ Add key"}
|
|
890
925
|
</button>
|
|
891
926
|
</div>
|
|
892
927
|
)}
|