apteva 0.4.41 → 0.4.48
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/ActivityPage.sw9p594m.js +3 -0
- package/dist/ApiDocsPage.90e03bz7.js +4 -0
- package/dist/App.0ws87fpx.js +53 -0
- package/dist/App.3vnrera5.js +4 -0
- package/dist/App.94x6mh7f.js +20 -0
- package/dist/{App.7fb3e7mp.js → App.9sryp183.js} +1 -1
- package/dist/App.d9tny4t0.js +221 -0
- package/dist/App.jhb45d7r.js +8 -0
- package/dist/App.p7jjw1zf.js +4 -0
- package/dist/App.pfbdzrhh.js +4 -0
- package/dist/App.stgng5bx.js +13 -0
- package/dist/App.tm3k7h4b.js +4 -0
- package/dist/App.vkg121c6.js +4 -0
- package/dist/App.wghtdzsk.js +1 -0
- package/dist/App.xf7wsckg.js +4 -0
- package/dist/App.xva0tfzh.js +4 -0
- package/dist/App.ysxy7akk.js +61 -0
- package/dist/App.yzkh4gq2.js +4 -0
- package/dist/ConnectionsPage.q5f9fd37.js +3 -0
- package/dist/McpPage.f3ccrezb.js +3 -0
- package/dist/SettingsPage.3sqx6wm4.js +3 -0
- package/dist/SkillsPage.whxnez67.js +3 -0
- package/dist/TasksPage.zp4jfevw.js +3 -0
- package/dist/TelemetryPage.a9fmxq87.js +3 -0
- package/dist/TestsPage.18krj0d1.js +3 -0
- package/dist/ThreadsPage.nnphgy98.js +3 -0
- package/dist/apteva-kit.css +1 -1
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +11 -10
- package/src/db.ts +61 -13
- package/src/integrations/agentdojo.ts +1 -0
- package/src/mcp-platform.ts +418 -63
- package/src/openapi.ts +96 -0
- package/src/providers.ts +55 -24
- package/src/routes/api/agent-utils.ts +25 -4
- package/src/routes/api/agents.ts +19 -1
- package/src/routes/api/meta-agent.ts +2 -0
- package/src/routes/api/system.ts +90 -1
- package/src/routes/api/telemetry.ts +38 -2
- package/src/routes/share.ts +85 -0
- package/src/server.ts +64 -1
- package/src/web/App.tsx +89 -11
- package/src/web/components/activity/ActivityPage.tsx +14 -14
- package/src/web/components/agents/AgentCard.tsx +19 -17
- package/src/web/components/agents/AgentPanel.tsx +541 -220
- package/src/web/components/agents/AgentsView.tsx +4 -4
- package/src/web/components/agents/CreateAgentModal.tsx +24 -82
- package/src/web/components/api/ApiDocsPage.tsx +66 -66
- package/src/web/components/auth/CreateAccountStep.tsx +16 -16
- package/src/web/components/auth/LoginPage.tsx +10 -10
- package/src/web/components/common/LoadingSpinner.tsx +2 -2
- package/src/web/components/common/Modal.tsx +9 -9
- package/src/web/components/common/Select.tsx +9 -9
- package/src/web/components/connections/ConnectionsPage.tsx +4 -4
- package/src/web/components/connections/IntegrationsTab.tsx +18 -18
- package/src/web/components/connections/OverviewTab.tsx +13 -13
- package/src/web/components/connections/TriggersTab.tsx +99 -99
- package/src/web/components/dashboard/Dashboard.tsx +32 -32
- package/src/web/components/layout/Header.tsx +50 -34
- package/src/web/components/layout/Sidebar.tsx +35 -15
- package/src/web/components/mcp/IntegrationsPanel.tsx +40 -40
- package/src/web/components/mcp/McpPage.tsx +208 -208
- package/src/web/components/meta-agent/MetaAgent.tsx +12 -10
- package/src/web/components/onboarding/OnboardingWizard.tsx +25 -25
- package/src/web/components/settings/SettingsPage.tsx +291 -175
- package/src/web/components/skills/SkillsPage.tsx +88 -88
- package/src/web/components/tasks/TasksPage.tsx +539 -78
- package/src/web/components/telemetry/TelemetryPage.tsx +405 -65
- package/src/web/components/tests/TestsPage.tsx +50 -50
- package/src/web/components/threads/ThreadsPage.tsx +23 -21
- package/src/web/context/ProjectContext.tsx +6 -1
- package/src/web/context/ThemeContext.tsx +90 -0
- package/src/web/context/index.ts +2 -0
- package/src/web/index.html +1 -6
- package/src/web/styles.css +52 -3
- package/src/web/themes.ts +162 -0
- package/src/web/types.ts +0 -4
- package/dist/ActivityPage.7907h64p.js +0 -3
- package/dist/ApiDocsPage.k3jjenpq.js +0 -4
- package/dist/App.01nq20st.js +0 -4
- package/dist/App.1maqvamf.js +0 -4
- package/dist/App.2yjrh32f.js +0 -4
- package/dist/App.3qw8nben.js +0 -20
- package/dist/App.7sy3wq8c.js +0 -4
- package/dist/App.apjrmctz.js +0 -57
- package/dist/App.av6t2yhe.js +0 -4
- package/dist/App.jqj5a094.js +0 -46
- package/dist/App.mc7xf85h.js +0 -4
- package/dist/App.myxqcj9x.js +0 -4
- package/dist/App.nm91r1mp.js +0 -13
- package/dist/App.p02f4ret.js +0 -1
- package/dist/App.qcknavjz.js +0 -221
- package/dist/App.vc7vfhg4.js +0 -4
- package/dist/App.z4s9zkw5.js +0 -4
- package/dist/ConnectionsPage.z1pw5xe2.js +0 -3
- package/dist/McpPage.8vc97z0b.js +0 -3
- package/dist/SettingsPage.p61bz8kd.js +0 -3
- package/dist/SkillsPage.r9x43g3g.js +0 -3
- package/dist/TasksPage.1e0zkye4.js +0 -3
- package/dist/TelemetryPage.p9vbe4gf.js +0 -3
- package/dist/TestsPage.d4xy504e.js +0 -3
- package/dist/ThreadsPage.m016am3x.js +0 -3
package/src/openapi.ts
CHANGED
|
@@ -1006,6 +1006,40 @@ while (true) {
|
|
|
1006
1006
|
},
|
|
1007
1007
|
},
|
|
1008
1008
|
},
|
|
1009
|
+
"/tasks/{agentId}": {
|
|
1010
|
+
post: {
|
|
1011
|
+
tags: ["Tasks"],
|
|
1012
|
+
summary: "Create a task on an agent",
|
|
1013
|
+
description: "Create a new task on a running agent. The agent must have the tasks feature enabled.",
|
|
1014
|
+
parameters: [
|
|
1015
|
+
{ name: "agentId", in: "path", required: true, schema: { type: "string" }, description: "Agent ID to create the task on" },
|
|
1016
|
+
],
|
|
1017
|
+
requestBody: {
|
|
1018
|
+
required: true,
|
|
1019
|
+
content: {
|
|
1020
|
+
"application/json": {
|
|
1021
|
+
schema: {
|
|
1022
|
+
type: "object",
|
|
1023
|
+
properties: {
|
|
1024
|
+
title: { type: "string", description: "Task title" },
|
|
1025
|
+
description: { type: "string", description: "Task description" },
|
|
1026
|
+
type: { type: "string", enum: ["once", "recurring"], default: "once" },
|
|
1027
|
+
priority: { type: "integer", minimum: 1, maximum: 10, default: 5 },
|
|
1028
|
+
execute_at: { type: "string", format: "date-time", description: "Scheduled execution time (for one-time tasks)" },
|
|
1029
|
+
recurrence: { type: "string", description: "Cron expression (for recurring tasks)" },
|
|
1030
|
+
},
|
|
1031
|
+
required: ["title"],
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
1034
|
+
},
|
|
1035
|
+
},
|
|
1036
|
+
responses: {
|
|
1037
|
+
"201": { description: "Task created successfully" },
|
|
1038
|
+
"400": { description: "Agent is not running or invalid input" },
|
|
1039
|
+
"404": { description: "Agent not found" },
|
|
1040
|
+
},
|
|
1041
|
+
},
|
|
1042
|
+
},
|
|
1009
1043
|
"/tasks/{agentId}/{taskId}": {
|
|
1010
1044
|
get: {
|
|
1011
1045
|
tags: ["Tasks"],
|
|
@@ -1033,6 +1067,68 @@ while (true) {
|
|
|
1033
1067
|
"404": { description: "Agent not found" },
|
|
1034
1068
|
},
|
|
1035
1069
|
},
|
|
1070
|
+
put: {
|
|
1071
|
+
tags: ["Tasks"],
|
|
1072
|
+
summary: "Update a task on an agent",
|
|
1073
|
+
description: "Update an existing task on a running agent.",
|
|
1074
|
+
parameters: [
|
|
1075
|
+
{ name: "agentId", in: "path", required: true, schema: { type: "string" }, description: "Agent ID" },
|
|
1076
|
+
{ name: "taskId", in: "path", required: true, schema: { type: "string" }, description: "Task ID to update" },
|
|
1077
|
+
],
|
|
1078
|
+
requestBody: {
|
|
1079
|
+
required: true,
|
|
1080
|
+
content: {
|
|
1081
|
+
"application/json": {
|
|
1082
|
+
schema: {
|
|
1083
|
+
type: "object",
|
|
1084
|
+
properties: {
|
|
1085
|
+
title: { type: "string" },
|
|
1086
|
+
description: { type: "string" },
|
|
1087
|
+
type: { type: "string", enum: ["once", "recurring"] },
|
|
1088
|
+
priority: { type: "integer", minimum: 1, maximum: 10 },
|
|
1089
|
+
execute_at: { type: "string", format: "date-time" },
|
|
1090
|
+
recurrence: { type: "string" },
|
|
1091
|
+
},
|
|
1092
|
+
},
|
|
1093
|
+
},
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
responses: {
|
|
1097
|
+
"200": { description: "Task updated" },
|
|
1098
|
+
"400": { description: "Agent is not running or invalid input" },
|
|
1099
|
+
"404": { description: "Agent or task not found" },
|
|
1100
|
+
},
|
|
1101
|
+
},
|
|
1102
|
+
delete: {
|
|
1103
|
+
tags: ["Tasks"],
|
|
1104
|
+
summary: "Delete a task on an agent",
|
|
1105
|
+
description: "Delete a task from a running agent.",
|
|
1106
|
+
parameters: [
|
|
1107
|
+
{ name: "agentId", in: "path", required: true, schema: { type: "string" }, description: "Agent ID" },
|
|
1108
|
+
{ name: "taskId", in: "path", required: true, schema: { type: "string" }, description: "Task ID to delete" },
|
|
1109
|
+
],
|
|
1110
|
+
responses: {
|
|
1111
|
+
"200": { description: "Task deleted" },
|
|
1112
|
+
"400": { description: "Agent is not running" },
|
|
1113
|
+
"404": { description: "Agent or task not found" },
|
|
1114
|
+
},
|
|
1115
|
+
},
|
|
1116
|
+
},
|
|
1117
|
+
"/tasks/{agentId}/{taskId}/execute": {
|
|
1118
|
+
post: {
|
|
1119
|
+
tags: ["Tasks"],
|
|
1120
|
+
summary: "Execute a task immediately",
|
|
1121
|
+
description: "Immediately execute a task on a running agent, regardless of its schedule.",
|
|
1122
|
+
parameters: [
|
|
1123
|
+
{ name: "agentId", in: "path", required: true, schema: { type: "string" }, description: "Agent ID" },
|
|
1124
|
+
{ name: "taskId", in: "path", required: true, schema: { type: "string" }, description: "Task ID to execute" },
|
|
1125
|
+
],
|
|
1126
|
+
responses: {
|
|
1127
|
+
"200": { description: "Task execution started" },
|
|
1128
|
+
"400": { description: "Agent is not running" },
|
|
1129
|
+
"404": { description: "Agent or task not found" },
|
|
1130
|
+
},
|
|
1131
|
+
},
|
|
1036
1132
|
},
|
|
1037
1133
|
"/mcp/servers": {
|
|
1038
1134
|
get: {
|
package/src/providers.ts
CHANGED
|
@@ -12,9 +12,9 @@ export const PROVIDERS = {
|
|
|
12
12
|
docsUrl: "https://console.anthropic.com/settings/keys",
|
|
13
13
|
testEndpoint: "https://api.anthropic.com/v1/messages",
|
|
14
14
|
models: [
|
|
15
|
-
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", recommended: true },
|
|
16
|
-
{ value: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" },
|
|
17
|
-
{ value: "claude-haiku-4-5", label: "Claude Haiku 4.5 (Fast)" },
|
|
15
|
+
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", recommended: true, input_cost: 3, output_cost: 15, cache_creation_cost: 3.75, cache_read_cost: 0.3 },
|
|
16
|
+
{ value: "claude-sonnet-4-5", label: "Claude Sonnet 4.5", input_cost: 3, output_cost: 15, cache_creation_cost: 3.75, cache_read_cost: 0.3 },
|
|
17
|
+
{ value: "claude-haiku-4-5", label: "Claude Haiku 4.5 (Fast)", input_cost: 0.8, output_cost: 4, cache_creation_cost: 1, cache_read_cost: 0.08 },
|
|
18
18
|
],
|
|
19
19
|
},
|
|
20
20
|
openai: {
|
|
@@ -26,8 +26,8 @@ export const PROVIDERS = {
|
|
|
26
26
|
docsUrl: "https://platform.openai.com/api-keys",
|
|
27
27
|
testEndpoint: "https://api.openai.com/v1/models",
|
|
28
28
|
models: [
|
|
29
|
-
{ value: "gpt-4o", label: "GPT-4o", recommended: true },
|
|
30
|
-
{ value: "gpt-4o-mini", label: "GPT-4o Mini (Fast)" },
|
|
29
|
+
{ value: "gpt-4o", label: "GPT-4o", recommended: true, input_cost: 2.5, output_cost: 10 },
|
|
30
|
+
{ value: "gpt-4o-mini", label: "GPT-4o Mini (Fast)", input_cost: 0.15, output_cost: 0.6 },
|
|
31
31
|
],
|
|
32
32
|
},
|
|
33
33
|
groq: {
|
|
@@ -39,8 +39,8 @@ export const PROVIDERS = {
|
|
|
39
39
|
docsUrl: "https://console.groq.com/keys",
|
|
40
40
|
testEndpoint: "https://api.groq.com/openai/v1/models",
|
|
41
41
|
models: [
|
|
42
|
-
{ value: "llama-3.3-70b-versatile", label: "Llama 3.3 70B", recommended: true },
|
|
43
|
-
{ value: "llama-3.1-8b-instant", label: "Llama 3.1 8B (Fast)" },
|
|
42
|
+
{ value: "llama-3.3-70b-versatile", label: "Llama 3.3 70B", recommended: true, input_cost: 0, output_cost: 0 },
|
|
43
|
+
{ value: "llama-3.1-8b-instant", label: "Llama 3.1 8B (Fast)", input_cost: 0, output_cost: 0 },
|
|
44
44
|
],
|
|
45
45
|
},
|
|
46
46
|
gemini: {
|
|
@@ -52,8 +52,8 @@ export const PROVIDERS = {
|
|
|
52
52
|
docsUrl: "https://aistudio.google.com/app/apikey",
|
|
53
53
|
testEndpoint: "https://generativelanguage.googleapis.com/v1/models",
|
|
54
54
|
models: [
|
|
55
|
-
{ value: "gemini-3-pro-preview", label: "Gemini 3 Pro Preview (Latest)", recommended: true },
|
|
56
|
-
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview (Fast)" },
|
|
55
|
+
{ value: "gemini-3-pro-preview", label: "Gemini 3 Pro Preview (Latest)", recommended: true, input_cost: 2, output_cost: 12 },
|
|
56
|
+
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview (Fast)", input_cost: 0.5, output_cost: 3 },
|
|
57
57
|
],
|
|
58
58
|
},
|
|
59
59
|
xai: {
|
|
@@ -65,8 +65,8 @@ export const PROVIDERS = {
|
|
|
65
65
|
docsUrl: "https://console.x.ai/",
|
|
66
66
|
testEndpoint: "https://api.x.ai/v1/models",
|
|
67
67
|
models: [
|
|
68
|
-
{ value: "grok-2", label: "Grok 2", recommended: true },
|
|
69
|
-
{ value: "grok-2-mini", label: "Grok 2 Mini (Fast)" },
|
|
68
|
+
{ value: "grok-2", label: "Grok 2", recommended: true, input_cost: 2, output_cost: 10 },
|
|
69
|
+
{ value: "grok-2-mini", label: "Grok 2 Mini (Fast)", input_cost: 0.3, output_cost: 1 },
|
|
70
70
|
],
|
|
71
71
|
},
|
|
72
72
|
together: {
|
|
@@ -78,8 +78,8 @@ export const PROVIDERS = {
|
|
|
78
78
|
docsUrl: "https://api.together.xyz/settings/api-keys",
|
|
79
79
|
testEndpoint: "https://api.together.xyz/v1/models",
|
|
80
80
|
models: [
|
|
81
|
-
{ value: "moonshotai/Kimi-K2.5", label: "Kimi K2.5", recommended: true },
|
|
82
|
-
{ value: "moonshotai/Kimi-K2-Thinking", label: "Kimi K2 Thinking (Reasoning)" },
|
|
81
|
+
{ value: "moonshotai/Kimi-K2.5", label: "Kimi K2.5", recommended: true, input_cost: 1, output_cost: 4 },
|
|
82
|
+
{ value: "moonshotai/Kimi-K2-Thinking", label: "Kimi K2 Thinking (Reasoning)", input_cost: 1, output_cost: 4 },
|
|
83
83
|
],
|
|
84
84
|
},
|
|
85
85
|
fireworks: {
|
|
@@ -91,10 +91,10 @@ export const PROVIDERS = {
|
|
|
91
91
|
docsUrl: "https://fireworks.ai/api-keys",
|
|
92
92
|
testEndpoint: "https://api.fireworks.ai/inference/v1/models",
|
|
93
93
|
models: [
|
|
94
|
-
{ value: "accounts/fireworks/models/kimi-k2p5", label: "Kimi K2.5", recommended: true },
|
|
95
|
-
{ value: "accounts/fireworks/models/kimi-k2-thinking", label: "Kimi K2 Thinking (Reasoning)" },
|
|
96
|
-
{ value: "accounts/fireworks/models/minimax-m2p5", label: "MiniMax M2.5" },
|
|
97
|
-
{ value: "accounts/fireworks/models/glm-5", label: "GLM 5" },
|
|
94
|
+
{ value: "accounts/fireworks/models/kimi-k2p5", label: "Kimi K2.5", recommended: true, input_cost: 1, output_cost: 4 },
|
|
95
|
+
{ value: "accounts/fireworks/models/kimi-k2-thinking", label: "Kimi K2 Thinking (Reasoning)", input_cost: 1, output_cost: 4 },
|
|
96
|
+
{ value: "accounts/fireworks/models/minimax-m2p5", label: "MiniMax M2.5", input_cost: 1, output_cost: 4 },
|
|
97
|
+
{ value: "accounts/fireworks/models/glm-5", label: "GLM 5", input_cost: 1, output_cost: 4 },
|
|
98
98
|
],
|
|
99
99
|
},
|
|
100
100
|
moonshot: {
|
|
@@ -106,8 +106,24 @@ export const PROVIDERS = {
|
|
|
106
106
|
docsUrl: "https://platform.moonshot.cn/console/api-keys",
|
|
107
107
|
testEndpoint: "https://api.moonshot.cn/v1/models",
|
|
108
108
|
models: [
|
|
109
|
-
{ value: "moonshot-v1-128k", label: "Kimi 128K", recommended: true },
|
|
110
|
-
{ value: "moonshot-v1-32k", label: "Kimi 32K (Fast)" },
|
|
109
|
+
{ value: "moonshot-v1-128k", label: "Kimi 128K", recommended: true, input_cost: 1, output_cost: 4 },
|
|
110
|
+
{ value: "moonshot-v1-32k", label: "Kimi 32K (Fast)", input_cost: 0.5, output_cost: 2 },
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
venice: {
|
|
114
|
+
id: "venice",
|
|
115
|
+
name: "Venice",
|
|
116
|
+
displayName: "Venice AI",
|
|
117
|
+
type: "llm" as const,
|
|
118
|
+
envVar: "VENICE_API_KEY",
|
|
119
|
+
docsUrl: "https://docs.venice.ai/overview/pricing",
|
|
120
|
+
testEndpoint: "https://api.venice.ai/api/v1/models",
|
|
121
|
+
models: [
|
|
122
|
+
{ value: "llama-3.3-70b", label: "Llama 3.3 70B", recommended: true, input_cost: 0.7, output_cost: 2.8 },
|
|
123
|
+
{ value: "olafangensan-glm-4.7-flash-heretic", label: "GLM 4.7 Flash Heretic", input_cost: 0.14, output_cost: 0.8 },
|
|
124
|
+
{ value: "qwen3-235b-a22b-instruct-2507", label: "Qwen 3 235B Instruct", input_cost: 0.15, output_cost: 0.75 },
|
|
125
|
+
{ value: "deepseek-v3.2", label: "DeepSeek V3.2", input_cost: 0.4, output_cost: 1 },
|
|
126
|
+
{ value: "venice-uncensored", label: "Venice Uncensored 1.1", input_cost: 0.2, output_cost: 0.9 },
|
|
111
127
|
],
|
|
112
128
|
},
|
|
113
129
|
ollama: {
|
|
@@ -122,11 +138,11 @@ export const PROVIDERS = {
|
|
|
122
138
|
defaultBaseUrl: "http://localhost:11434",
|
|
123
139
|
models: [
|
|
124
140
|
// Default models - actual list fetched dynamically from Ollama
|
|
125
|
-
{ value: "llama3.3", label: "Llama 3.3 (70B)", recommended: true },
|
|
126
|
-
{ value: "llama3.2", label: "Llama 3.2 (3B)" },
|
|
127
|
-
{ value: "qwen2.5", label: "Qwen 2.5" },
|
|
128
|
-
{ value: "mistral", label: "Mistral" },
|
|
129
|
-
{ value: "deepseek-r1", label: "DeepSeek R1" },
|
|
141
|
+
{ value: "llama3.3", label: "Llama 3.3 (70B)", recommended: true, input_cost: 0, output_cost: 0 },
|
|
142
|
+
{ value: "llama3.2", label: "Llama 3.2 (3B)", input_cost: 0, output_cost: 0 },
|
|
143
|
+
{ value: "qwen2.5", label: "Qwen 2.5", input_cost: 0, output_cost: 0 },
|
|
144
|
+
{ value: "mistral", label: "Mistral", input_cost: 0, output_cost: 0 },
|
|
145
|
+
{ value: "deepseek-r1", label: "DeepSeek R1", input_cost: 0, output_cost: 0 },
|
|
130
146
|
],
|
|
131
147
|
},
|
|
132
148
|
// Browser Providers
|
|
@@ -217,6 +233,21 @@ export const PROVIDERS = {
|
|
|
217
233
|
|
|
218
234
|
export type ProviderId = keyof typeof PROVIDERS;
|
|
219
235
|
|
|
236
|
+
/** Get cost per 1M tokens for a given provider + model. Returns { input_cost, output_cost, cache_creation_cost, cache_read_cost } in USD. */
|
|
237
|
+
export function getModelCost(provider: string, model: string): { input_cost: number; output_cost: number; cache_creation_cost: number; cache_read_cost: number } {
|
|
238
|
+
const providerDef = PROVIDERS[provider as ProviderId];
|
|
239
|
+
if (!providerDef || !("models" in providerDef)) return { input_cost: 0, output_cost: 0, cache_creation_cost: 0, cache_read_cost: 0 };
|
|
240
|
+
const modelDef = (providerDef.models as ReadonlyArray<{ value: string; input_cost?: number; output_cost?: number; cache_creation_cost?: number; cache_read_cost?: number }>)
|
|
241
|
+
.find(m => m.value === model);
|
|
242
|
+
if (!modelDef) return { input_cost: 0, output_cost: 0, cache_creation_cost: 0, cache_read_cost: 0 };
|
|
243
|
+
return {
|
|
244
|
+
input_cost: modelDef.input_cost ?? 0,
|
|
245
|
+
output_cost: modelDef.output_cost ?? 0,
|
|
246
|
+
cache_creation_cost: modelDef.cache_creation_cost ?? 0,
|
|
247
|
+
cache_read_cost: modelDef.cache_read_cost ?? 0,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
220
251
|
// Provider Keys Management
|
|
221
252
|
export const ProviderKeys = {
|
|
222
253
|
// Save an API key (encrypts before storing)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "bun";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { homedir } from "os";
|
|
4
|
-
import { mkdirSync, existsSync, rmSync } from "fs";
|
|
4
|
+
import { mkdirSync, existsSync, rmSync, writeFileSync, readFileSync } from "fs";
|
|
5
5
|
import { agentProcesses, agentsStarting, getBinaryPathForAgent, getBinaryStatus, BIN_DIR, telemetryBroadcaster, isShuttingDown, type TelemetryEvent } from "../../server";
|
|
6
6
|
import { AgentDB, McpServerDB, SkillDB, SubscriptionDB, TelemetryDB, generateId, getMultiAgentConfig, getOperatorConfig, type Agent, type Project } from "../../db";
|
|
7
7
|
import { ProviderKeys, PROVIDERS, type ProviderId } from "../../providers";
|
|
@@ -337,7 +337,6 @@ export function buildAgentConfig(agent: Agent, providerKey: string) {
|
|
|
337
337
|
const baseUrl = process.env.PUBLIC_URL || `http://localhost:${process.env.PORT || 4280}`;
|
|
338
338
|
return {
|
|
339
339
|
enabled: multiAgentConfig.enabled,
|
|
340
|
-
mode: multiAgentConfig.mode || "worker",
|
|
341
340
|
group: multiAgentConfig.group || agent.project_id || undefined,
|
|
342
341
|
// This agent's reachable URL for peer communication
|
|
343
342
|
url: `http://localhost:${agent.port}`,
|
|
@@ -545,7 +544,9 @@ export async function startAgentProcess(
|
|
|
545
544
|
|
|
546
545
|
// Build environment with provider key and agent API key
|
|
547
546
|
// CONFIG_PATH ensures each agent has its own config file (prevents sharing)
|
|
547
|
+
// Remove stale persisted config — platform is source of truth and pushes fresh config after boot
|
|
548
548
|
const agentConfigPath = join(agentDataDir, "agent-config.json");
|
|
549
|
+
rmSync(agentConfigPath, { force: true });
|
|
549
550
|
const env: Record<string, string> = {
|
|
550
551
|
...process.env as Record<string, string>,
|
|
551
552
|
PORT: String(port),
|
|
@@ -566,8 +567,19 @@ export async function startAgentProcess(
|
|
|
566
567
|
// Get binary path dynamically (allows hot-reload of new binary versions)
|
|
567
568
|
const binaryPath = getBinaryPathForAgent();
|
|
568
569
|
|
|
570
|
+
// Write VERSION file so the binary knows its version (ldflags not set in npm builds)
|
|
571
|
+
try {
|
|
572
|
+
const { dirname } = await import("path");
|
|
573
|
+
const pkgJsonPath = require.resolve("@apteva/agent-linux-x64/package.json");
|
|
574
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
575
|
+
if (pkg.version) {
|
|
576
|
+
writeFileSync(join(agentDataDir, "VERSION"), pkg.version);
|
|
577
|
+
}
|
|
578
|
+
} catch {}
|
|
579
|
+
|
|
569
580
|
const proc = spawn({
|
|
570
581
|
cmd: [binaryPath],
|
|
582
|
+
cwd: agentDataDir,
|
|
571
583
|
env,
|
|
572
584
|
stdout: "ignore",
|
|
573
585
|
stderr: "ignore",
|
|
@@ -645,6 +657,15 @@ export async function startAgentProcess(
|
|
|
645
657
|
}
|
|
646
658
|
}
|
|
647
659
|
|
|
660
|
+
// Strip legacy "mode" field from multi-agent config
|
|
661
|
+
function cleanFeatures(features: Agent["features"]): Agent["features"] {
|
|
662
|
+
if (features.agents && typeof features.agents === "object") {
|
|
663
|
+
const { mode, ...rest } = features.agents as any;
|
|
664
|
+
return { ...features, agents: rest };
|
|
665
|
+
}
|
|
666
|
+
return features;
|
|
667
|
+
}
|
|
668
|
+
|
|
648
669
|
// Transform DB agent to API response format (camelCase for frontend compatibility)
|
|
649
670
|
// Uses batch queries + light MCP loading (no decryption) for performance
|
|
650
671
|
export function toApiAgent(agent: Agent) {
|
|
@@ -688,7 +709,7 @@ export function toApiAgent(agent: Agent) {
|
|
|
688
709
|
systemPrompt: agent.system_prompt,
|
|
689
710
|
status: agent.status,
|
|
690
711
|
port: agent.port,
|
|
691
|
-
features: agent.features,
|
|
712
|
+
features: cleanFeatures(agent.features),
|
|
692
713
|
mcpServers: agent.mcp_servers,
|
|
693
714
|
mcpServerDetails,
|
|
694
715
|
skills: agent.skills,
|
|
@@ -735,7 +756,7 @@ export function toApiAgentsBatch(agents: Agent[]) {
|
|
|
735
756
|
return {
|
|
736
757
|
id: agent.id, name: agent.name, model: agent.model, provider: agent.provider,
|
|
737
758
|
systemPrompt: agent.system_prompt, status: agent.status, port: agent.port,
|
|
738
|
-
features: agent.features, mcpServers: agent.mcp_servers, mcpServerDetails,
|
|
759
|
+
features: cleanFeatures(agent.features), mcpServers: agent.mcp_servers, mcpServerDetails,
|
|
739
760
|
skills: agent.skills, skillDetails, subscriptions, projectId: agent.project_id,
|
|
740
761
|
createdAt: agent.created_at, updatedAt: agent.updated_at,
|
|
741
762
|
};
|
package/src/routes/api/agents.ts
CHANGED
|
@@ -270,6 +270,25 @@ export async function handleAgentRoutes(
|
|
|
270
270
|
});
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
// ==================== SHARE LINK ====================
|
|
274
|
+
|
|
275
|
+
// GET /api/agents/:id/share-token - Get the share token for this agent
|
|
276
|
+
const shareTokenMatch = path.match(/^\/api\/agents\/([^/]+)\/share-token$/);
|
|
277
|
+
if (shareTokenMatch && method === "GET") {
|
|
278
|
+
const agent = AgentDB.findById(shareTokenMatch[1]);
|
|
279
|
+
if (!agent) {
|
|
280
|
+
return json({ error: "Agent not found" }, 404);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const { getShareToken } = await import("../share");
|
|
284
|
+
const token = getShareToken(agent.id);
|
|
285
|
+
if (!token) {
|
|
286
|
+
return json({ error: "Could not generate share token" }, 500);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return json({ token });
|
|
290
|
+
}
|
|
291
|
+
|
|
273
292
|
// ==================== AGENT LIFECYCLE ====================
|
|
274
293
|
|
|
275
294
|
// POST /api/agents/:id/start - Start an agent
|
|
@@ -840,7 +859,6 @@ export async function handleAgentRoutes(
|
|
|
840
859
|
id: a.id,
|
|
841
860
|
name: a.name,
|
|
842
861
|
url: `http://localhost:${a.port}`,
|
|
843
|
-
mode: agentConfig.mode || "worker",
|
|
844
862
|
group: agentConfig.group || a.project_id,
|
|
845
863
|
};
|
|
846
864
|
});
|
package/src/routes/api/system.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { json } from "./helpers";
|
|
2
|
-
import { META_AGENT_ENABLED, fetchFromAgent, startAgentProcess, setAgentStatus } from "./agent-utils";
|
|
2
|
+
import { META_AGENT_ENABLED, fetchFromAgent, agentFetch, startAgentProcess, setAgentStatus } from "./agent-utils";
|
|
3
3
|
import { AgentDB } from "../../db";
|
|
4
4
|
import { ProviderKeys } from "../../providers";
|
|
5
5
|
import { agentProcesses, getBinaryStatus, BIN_DIR } from "../../server";
|
|
@@ -44,6 +44,7 @@ export async function handleSystemRoutes(
|
|
|
44
44
|
return json({
|
|
45
45
|
projects: process.env.PROJECTS_ENABLED === "true",
|
|
46
46
|
metaAgent: process.env.META_AGENT_ENABLED === "true",
|
|
47
|
+
costTracking: process.env.COST_TRACKING_ENABLED !== "false",
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -180,6 +181,94 @@ export async function handleSystemRoutes(
|
|
|
180
181
|
return json({ task: { ...data, agentId: agent.id, agentName: agent.name } });
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
// POST /api/tasks/:agentId/:taskId/execute - Execute a task immediately
|
|
185
|
+
const executeTaskMatch = path.match(/^\/api\/tasks\/([^/]+)\/([^/]+)\/execute$/);
|
|
186
|
+
if (executeTaskMatch && method === "POST") {
|
|
187
|
+
const [, agentId, taskId] = executeTaskMatch;
|
|
188
|
+
const agent = AgentDB.findById(agentId);
|
|
189
|
+
if (!agent) return json({ error: "Agent not found" }, 404);
|
|
190
|
+
if (agent.status !== "running" || !agent.port) return json({ error: "Agent is not running" }, 400);
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const res = await agentFetch(agentId, agent.port, `/tasks/${taskId}/execute`, {
|
|
194
|
+
method: "POST",
|
|
195
|
+
signal: AbortSignal.timeout(5000),
|
|
196
|
+
});
|
|
197
|
+
const data = await res.json();
|
|
198
|
+
if (!res.ok) return json({ error: data.error || `HTTP ${res.status}` }, res.status);
|
|
199
|
+
return json(data);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
return json({ error: `Failed to execute task: ${err}` }, 500);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// POST /api/tasks/:agentId - Create a task on an agent
|
|
206
|
+
const createTaskMatch = path.match(/^\/api\/tasks\/([^/]+)$/);
|
|
207
|
+
if (createTaskMatch && method === "POST") {
|
|
208
|
+
const agentId = createTaskMatch[1];
|
|
209
|
+
const agent = AgentDB.findById(agentId);
|
|
210
|
+
if (!agent) return json({ error: "Agent not found" }, 404);
|
|
211
|
+
if (agent.status !== "running" || !agent.port) return json({ error: "Agent is not running" }, 400);
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const body = await req.json();
|
|
215
|
+
const res = await agentFetch(agentId, agent.port, "/tasks", {
|
|
216
|
+
method: "POST",
|
|
217
|
+
headers: { "Content-Type": "application/json" },
|
|
218
|
+
body: JSON.stringify(body),
|
|
219
|
+
signal: AbortSignal.timeout(5000),
|
|
220
|
+
});
|
|
221
|
+
const data = await res.json();
|
|
222
|
+
if (!res.ok) return json({ error: data.error || `HTTP ${res.status}` }, res.status);
|
|
223
|
+
return json(data, 201);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
return json({ error: `Failed to create task: ${err}` }, 500);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// PUT /api/tasks/:agentId/:taskId - Update a task on an agent
|
|
230
|
+
if (singleTaskMatch && method === "PUT") {
|
|
231
|
+
const [, agentId, taskId] = singleTaskMatch;
|
|
232
|
+
const agent = AgentDB.findById(agentId);
|
|
233
|
+
if (!agent) return json({ error: "Agent not found" }, 404);
|
|
234
|
+
if (agent.status !== "running" || !agent.port) return json({ error: "Agent is not running" }, 400);
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const body = await req.json();
|
|
238
|
+
const res = await agentFetch(agentId, agent.port, `/tasks/${taskId}`, {
|
|
239
|
+
method: "PUT",
|
|
240
|
+
headers: { "Content-Type": "application/json" },
|
|
241
|
+
body: JSON.stringify(body),
|
|
242
|
+
signal: AbortSignal.timeout(5000),
|
|
243
|
+
});
|
|
244
|
+
const data = await res.json();
|
|
245
|
+
if (!res.ok) return json({ error: data.error || `HTTP ${res.status}` }, res.status);
|
|
246
|
+
return json(data);
|
|
247
|
+
} catch (err) {
|
|
248
|
+
return json({ error: `Failed to update task: ${err}` }, 500);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// DELETE /api/tasks/:agentId/:taskId - Delete a task on an agent
|
|
253
|
+
if (singleTaskMatch && method === "DELETE") {
|
|
254
|
+
const [, agentId, taskId] = singleTaskMatch;
|
|
255
|
+
const agent = AgentDB.findById(agentId);
|
|
256
|
+
if (!agent) return json({ error: "Agent not found" }, 404);
|
|
257
|
+
if (agent.status !== "running" || !agent.port) return json({ error: "Agent is not running" }, 400);
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const res = await agentFetch(agentId, agent.port, `/tasks/${taskId}`, {
|
|
261
|
+
method: "DELETE",
|
|
262
|
+
signal: AbortSignal.timeout(5000),
|
|
263
|
+
});
|
|
264
|
+
const data = await res.json();
|
|
265
|
+
if (!res.ok) return json({ error: data.error || `HTTP ${res.status}` }, res.status);
|
|
266
|
+
return json(data);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
return json({ error: `Failed to delete task: ${err}` }, 500);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
183
272
|
// GET /api/dashboard - Get dashboard statistics
|
|
184
273
|
if (path === "/api/dashboard" && method === "GET") {
|
|
185
274
|
const url = new URL(req.url);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { json } from "./helpers";
|
|
2
|
-
import { TelemetryDB } from "../../db";
|
|
2
|
+
import { TelemetryDB, AgentDB } from "../../db";
|
|
3
|
+
import { getModelCost } from "../../providers";
|
|
3
4
|
import { telemetryBroadcaster, type TelemetryEvent } from "../../server";
|
|
4
5
|
|
|
5
6
|
export async function handleTelemetryRoutes(
|
|
@@ -33,8 +34,41 @@ export async function handleTelemetryRoutes(
|
|
|
33
34
|
return json({ error: "agent_id and events are required" }, 400);
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
// Debug: log raw incoming events
|
|
38
|
+
for (const event of body.events) {
|
|
39
|
+
if (event.category === "LLM") {
|
|
40
|
+
console.log(`[telemetry] RAW LLM event from ${body.agent_id}: ${JSON.stringify(event)}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
// Filter out debug events - too noisy
|
|
37
45
|
const filteredEvents = body.events.filter(e => e.level !== "debug");
|
|
46
|
+
|
|
47
|
+
// Compute cost per LLM event if cost tracking is enabled
|
|
48
|
+
const costTrackingEnabled = process.env.COST_TRACKING_ENABLED !== "false";
|
|
49
|
+
if (costTrackingEnabled) {
|
|
50
|
+
const agent = AgentDB.findById(body.agent_id);
|
|
51
|
+
if (agent) {
|
|
52
|
+
const pricing = getModelCost(agent.provider, agent.model);
|
|
53
|
+
for (const event of filteredEvents) {
|
|
54
|
+
if (event.category === "LLM" && event.data) {
|
|
55
|
+
const inputTokens = (event.data.input_tokens as number) || 0;
|
|
56
|
+
const outputTokens = (event.data.output_tokens as number) || 0;
|
|
57
|
+
const cacheCreationTokens = (event.data.cache_creation_tokens as number) || 0;
|
|
58
|
+
const cacheReadTokens = (event.data.cache_read_tokens as number) || 0;
|
|
59
|
+
const reasoningTokens = (event.data.reasoning_tokens as number) || 0;
|
|
60
|
+
(event as any).cost = (
|
|
61
|
+
inputTokens * pricing.input_cost +
|
|
62
|
+
outputTokens * pricing.output_cost +
|
|
63
|
+
cacheCreationTokens * pricing.cache_creation_cost +
|
|
64
|
+
cacheReadTokens * pricing.cache_read_cost +
|
|
65
|
+
reasoningTokens * pricing.output_cost
|
|
66
|
+
) / 1_000_000;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
38
72
|
const inserted = TelemetryDB.insertBatch(body.agent_id, filteredEvents);
|
|
39
73
|
|
|
40
74
|
// Broadcast to SSE clients
|
|
@@ -116,7 +150,7 @@ export async function handleTelemetryRoutes(
|
|
|
116
150
|
project_id: projectIdParam === "null" ? null : projectIdParam || undefined,
|
|
117
151
|
since: url.searchParams.get("since") || undefined,
|
|
118
152
|
until: url.searchParams.get("until") || undefined,
|
|
119
|
-
group_by: (url.searchParams.get("group_by") as "agent" | "day") || undefined,
|
|
153
|
+
group_by: (url.searchParams.get("group_by") as "agent" | "day" | "project") || undefined,
|
|
120
154
|
});
|
|
121
155
|
return json({ usage });
|
|
122
156
|
}
|
|
@@ -129,6 +163,8 @@ export async function handleTelemetryRoutes(
|
|
|
129
163
|
const stats = TelemetryDB.getStats({
|
|
130
164
|
agentId,
|
|
131
165
|
projectId: projectIdParam === "null" ? null : projectIdParam || undefined,
|
|
166
|
+
since: url.searchParams.get("since") || undefined,
|
|
167
|
+
until: url.searchParams.get("until") || undefined,
|
|
132
168
|
});
|
|
133
169
|
return json({ stats });
|
|
134
170
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { AgentDB, type Agent } from "../db";
|
|
3
|
+
import { agentFetch } from "./api/agent-utils";
|
|
4
|
+
|
|
5
|
+
function deriveShareToken(apiKey: string, agentId: string): string {
|
|
6
|
+
return createHash("sha256")
|
|
7
|
+
.update(apiKey + ":" + agentId + ":share")
|
|
8
|
+
.digest("hex")
|
|
9
|
+
.substring(0, 32);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function findAgentByShareToken(token: string): Agent | null {
|
|
13
|
+
const agents = AgentDB.findAll();
|
|
14
|
+
for (const agent of agents) {
|
|
15
|
+
const apiKey = AgentDB.getApiKey(agent.id);
|
|
16
|
+
if (!apiKey) continue;
|
|
17
|
+
if (deriveShareToken(apiKey, agent.id) === token) return agent;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Get the share token for an agent (used by API route for the UI) */
|
|
23
|
+
export function getShareToken(agentId: string): string | null {
|
|
24
|
+
const apiKey = AgentDB.getApiKey(agentId);
|
|
25
|
+
if (!apiKey) return null;
|
|
26
|
+
return deriveShareToken(apiKey, agentId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function handleShareRequest(req: Request, path: string): Promise<Response | null> {
|
|
30
|
+
// Match /share/<32 hex chars> sub-paths for API calls
|
|
31
|
+
const infoMatch = path.match(/^\/share\/([a-f0-9]{32})\/info$/);
|
|
32
|
+
const chatMatch = path.match(/^\/share\/([a-f0-9]{32})\/chat$/);
|
|
33
|
+
|
|
34
|
+
if (!infoMatch && !chatMatch) return null;
|
|
35
|
+
|
|
36
|
+
const token = (infoMatch || chatMatch)![1];
|
|
37
|
+
const agent = findAgentByShareToken(token);
|
|
38
|
+
|
|
39
|
+
// Intentionally vague 404 — don't reveal whether token exists
|
|
40
|
+
if (!agent) {
|
|
41
|
+
return new Response("Not found", { status: 404 });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// GET /share/:token/info — agent info (no secrets)
|
|
45
|
+
if (infoMatch && req.method === "GET") {
|
|
46
|
+
return Response.json({
|
|
47
|
+
name: agent.name,
|
|
48
|
+
status: agent.status,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// POST /share/:token/chat — proxy to agent
|
|
53
|
+
if (chatMatch && req.method === "POST") {
|
|
54
|
+
if (agent.status !== "running" || !agent.port) {
|
|
55
|
+
return Response.json({ error: "Agent is currently offline" }, { status: 503 });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const body = await req.json();
|
|
60
|
+
const response = await agentFetch(agent.id, agent.port, "/chat", {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: { "Content-Type": "application/json" },
|
|
63
|
+
body: JSON.stringify(body),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
const errorText = await response.text();
|
|
68
|
+
return Response.json({ error: `Agent error: ${errorText}` }, { status: response.status });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return new Response(response.body, {
|
|
72
|
+
status: 200,
|
|
73
|
+
headers: {
|
|
74
|
+
"Content-Type": response.headers.get("Content-Type") || "text/event-stream",
|
|
75
|
+
"Cache-Control": "no-cache",
|
|
76
|
+
"Connection": "keep-alive",
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
} catch (err) {
|
|
80
|
+
return Response.json({ error: "Failed to connect to agent" }, { status: 500 });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|