@chrysb/alphaclaw 0.6.1 → 0.6.2-beta.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/lib/public/css/agents.css +1 -1
- package/lib/public/css/cron.css +535 -0
- package/lib/public/css/theme.css +72 -0
- package/lib/public/js/app.js +45 -10
- package/lib/public/js/components/action-button.js +26 -20
- package/lib/public/js/components/agents-tab/agent-detail-panel.js +98 -17
- package/lib/public/js/components/agents-tab/agent-tools/index.js +105 -0
- package/lib/public/js/components/agents-tab/agent-tools/tool-catalog.js +289 -0
- package/lib/public/js/components/agents-tab/agent-tools/use-agent-tools.js +128 -0
- package/lib/public/js/components/agents-tab/index.js +4 -0
- package/lib/public/js/components/cron-tab/cron-calendar-helpers.js +385 -0
- package/lib/public/js/components/cron-tab/cron-calendar.js +441 -0
- package/lib/public/js/components/cron-tab/cron-helpers.js +326 -0
- package/lib/public/js/components/cron-tab/cron-job-detail.js +425 -0
- package/lib/public/js/components/cron-tab/cron-job-list.js +305 -0
- package/lib/public/js/components/cron-tab/cron-job-usage.js +70 -0
- package/lib/public/js/components/cron-tab/cron-overview.js +599 -0
- package/lib/public/js/components/cron-tab/cron-runs-trend-card.js +277 -0
- package/lib/public/js/components/cron-tab/index.js +100 -0
- package/lib/public/js/components/cron-tab/use-cron-tab.js +366 -0
- package/lib/public/js/components/doctor/summary-cards.js +5 -11
- package/lib/public/js/components/icons.js +13 -0
- package/lib/public/js/components/pill-tabs.js +33 -0
- package/lib/public/js/components/pop-actions.js +58 -0
- package/lib/public/js/components/routes/agents-route.js +4 -0
- package/lib/public/js/components/routes/cron-route.js +9 -0
- package/lib/public/js/components/routes/index.js +1 -0
- package/lib/public/js/components/segmented-control.js +15 -9
- package/lib/public/js/components/summary-stat-card.js +17 -0
- package/lib/public/js/components/tooltip.js +50 -4
- package/lib/public/js/components/watchdog-tab.js +46 -1
- package/lib/public/js/lib/api.js +94 -0
- package/lib/public/js/lib/app-navigation.js +2 -0
- package/lib/public/js/lib/storage-keys.js +1 -0
- package/lib/public/setup.html +1 -0
- package/lib/server/agents/agents.js +15 -0
- package/lib/server/constants.js +1 -0
- package/lib/server/cost-utils.js +312 -0
- package/lib/server/cron-service.js +461 -0
- package/lib/server/db/usage/index.js +100 -1
- package/lib/server/db/usage/pricing.js +1 -83
- package/lib/server/db/usage/sessions.js +4 -1
- package/lib/server/db/usage/shared.js +2 -1
- package/lib/server/db/usage/summary.js +5 -1
- package/lib/server/onboarding/index.js +39 -5
- package/lib/server/onboarding/openclaw.js +25 -19
- package/lib/server/onboarding/validation.js +28 -0
- package/lib/server/routes/cron.js +148 -0
- package/lib/server.js +13 -0
- package/package.json +1 -1
|
@@ -72,19 +72,21 @@ export const ActionButton = ({
|
|
|
72
72
|
: "opacity-80"
|
|
73
73
|
}`
|
|
74
74
|
: "";
|
|
75
|
-
const spinnerSizeClass =
|
|
75
|
+
const spinnerSizeClass =
|
|
76
|
+
size === "md" || size === "lg" ? "h-4 w-4" : "h-3 w-3";
|
|
76
77
|
const isInlineLoading = loadingMode === "inline";
|
|
77
78
|
const IdleIcon = idleIcon;
|
|
78
|
-
const idleContent =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
const idleContent =
|
|
80
|
+
iconOnly && IdleIcon
|
|
81
|
+
? html`<${IdleIcon} className=${idleIconClassName} />`
|
|
82
|
+
: IdleIcon
|
|
83
|
+
? html`
|
|
84
|
+
<span class="inline-flex items-center gap-1.5 leading-none">
|
|
85
|
+
<${IdleIcon} className=${idleIconClassName} />
|
|
86
|
+
${idleLabel}
|
|
87
|
+
</span>
|
|
88
|
+
`
|
|
89
|
+
: idleLabel;
|
|
88
90
|
const currentLabel = loading && !isInlineLoading ? loadingLabel : idleContent;
|
|
89
91
|
|
|
90
92
|
return html`
|
|
@@ -98,11 +100,15 @@ export const ActionButton = ({
|
|
|
98
100
|
>
|
|
99
101
|
${isInlineLoading
|
|
100
102
|
? html`
|
|
101
|
-
<span
|
|
103
|
+
<span
|
|
104
|
+
class="relative inline-flex items-center justify-center leading-none"
|
|
105
|
+
>
|
|
102
106
|
<span class=${loading ? "invisible" : ""}>${currentLabel}</span>
|
|
103
107
|
${loading
|
|
104
108
|
? html`
|
|
105
|
-
<span
|
|
109
|
+
<span
|
|
110
|
+
class="absolute inset-0 inline-flex items-center justify-center"
|
|
111
|
+
>
|
|
106
112
|
<${LoadingSpinner} className=${spinnerSizeClass} />
|
|
107
113
|
</span>
|
|
108
114
|
`
|
|
@@ -110,13 +116,13 @@ export const ActionButton = ({
|
|
|
110
116
|
</span>
|
|
111
117
|
`
|
|
112
118
|
: loading
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
? html`
|
|
120
|
+
<span class="inline-flex items-center gap-1.5 leading-none">
|
|
121
|
+
<${LoadingSpinner} className=${spinnerSizeClass} />
|
|
122
|
+
${currentLabel}
|
|
123
|
+
</span>
|
|
124
|
+
`
|
|
125
|
+
: currentLabel}
|
|
120
126
|
</button>
|
|
121
127
|
`;
|
|
122
128
|
};
|
|
@@ -1,22 +1,69 @@
|
|
|
1
1
|
import { h } from "https://esm.sh/preact";
|
|
2
|
+
import { useState, useCallback } from "https://esm.sh/preact/hooks";
|
|
2
3
|
import htm from "https://esm.sh/htm";
|
|
3
4
|
import { ActionButton } from "../action-button.js";
|
|
4
5
|
import { Badge } from "../badge.js";
|
|
6
|
+
import { PillTabs } from "../pill-tabs.js";
|
|
7
|
+
import { PopActions } from "../pop-actions.js";
|
|
5
8
|
import { AgentOverview } from "./agent-overview/index.js";
|
|
9
|
+
import { AgentToolsPanel } from "./agent-tools/index.js";
|
|
10
|
+
import { useAgentTools } from "./agent-tools/use-agent-tools.js";
|
|
6
11
|
|
|
7
12
|
const html = htm.bind(h);
|
|
8
13
|
|
|
14
|
+
const kDetailTabs = [
|
|
15
|
+
{ label: "Overview", value: "overview" },
|
|
16
|
+
{ label: "Tools", value: "tools" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const PencilIcon = ({ className = "w-3.5 h-3.5" }) => html`
|
|
20
|
+
<svg
|
|
21
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
+
viewBox="0 0 24 24"
|
|
23
|
+
fill="currentColor"
|
|
24
|
+
class=${className}
|
|
25
|
+
>
|
|
26
|
+
<path
|
|
27
|
+
d="M15.7279 9.57627L14.3137 8.16206L5 17.4758V18.89H6.41421L15.7279 9.57627ZM17.1421 8.16206L18.5563 6.74785L17.1421 5.33363L15.7279 6.74785L17.1421 8.16206ZM7.24264 20.89H3V16.6473L16.435 3.21231C16.8256 2.82179 17.4587 2.82179 17.8492 3.21231L20.6777 6.04074C21.0682 6.43126 21.0682 7.06443 20.6777 7.45495L7.24264 20.89Z"
|
|
28
|
+
/>
|
|
29
|
+
</svg>
|
|
30
|
+
`;
|
|
31
|
+
|
|
9
32
|
export const AgentDetailPanel = ({
|
|
10
33
|
agent = null,
|
|
11
34
|
agents = [],
|
|
35
|
+
activeTab = "overview",
|
|
12
36
|
saving = false,
|
|
13
37
|
onUpdateAgent = async () => {},
|
|
14
38
|
onSetLocation = () => {},
|
|
39
|
+
onSelectTab = () => {},
|
|
15
40
|
onEdit = () => {},
|
|
16
41
|
onDelete = () => {},
|
|
17
42
|
onSetDefault = () => {},
|
|
18
43
|
onOpenWorkspace = () => {},
|
|
19
44
|
}) => {
|
|
45
|
+
const tools = useAgentTools({ agent: agent || {} });
|
|
46
|
+
const [savingTools, setSavingTools] = useState(false);
|
|
47
|
+
|
|
48
|
+
const handleSaveTools = useCallback(async () => {
|
|
49
|
+
if (!agent) return;
|
|
50
|
+
setSavingTools(true);
|
|
51
|
+
try {
|
|
52
|
+
const nextAgent = await onUpdateAgent(
|
|
53
|
+
agent.id,
|
|
54
|
+
{ tools: tools.toolsConfig },
|
|
55
|
+
"Tool access updated",
|
|
56
|
+
);
|
|
57
|
+
tools.markSaved(nextAgent?.tools || tools.toolsConfig);
|
|
58
|
+
} catch {
|
|
59
|
+
// toast handled by parent
|
|
60
|
+
} finally {
|
|
61
|
+
setSavingTools(false);
|
|
62
|
+
}
|
|
63
|
+
}, [agent, tools.toolsConfig, tools.markSaved, onUpdateAgent]);
|
|
64
|
+
|
|
65
|
+
const isSaving = saving || savingTools;
|
|
66
|
+
|
|
20
67
|
if (!agent) {
|
|
21
68
|
return html`
|
|
22
69
|
<div class="agents-detail-panel">
|
|
@@ -32,10 +79,18 @@ export const AgentDetailPanel = ({
|
|
|
32
79
|
<div class="agents-detail-inner">
|
|
33
80
|
<div class="agents-detail-header">
|
|
34
81
|
<div class="min-w-0">
|
|
35
|
-
<div class="flex items-center gap-
|
|
82
|
+
<div class="flex items-center gap-2 min-w-0">
|
|
36
83
|
<span class="agents-detail-header-title">
|
|
37
84
|
${agent.name || agent.id}
|
|
38
85
|
</span>
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
class="text-gray-500 hover:text-gray-300 transition-colors p-0.5 -ml-0.5"
|
|
89
|
+
onclick=${() => onEdit(agent)}
|
|
90
|
+
title="Edit agent name"
|
|
91
|
+
>
|
|
92
|
+
<${PencilIcon} />
|
|
93
|
+
</button>
|
|
39
94
|
${agent.default
|
|
40
95
|
? html`<${Badge} tone="cyan">Default</${Badge}>`
|
|
41
96
|
: null}
|
|
@@ -44,29 +99,55 @@ export const AgentDetailPanel = ({
|
|
|
44
99
|
<span class="font-mono">${agent.id}</span>
|
|
45
100
|
</div>
|
|
46
101
|
</div>
|
|
47
|
-
|
|
102
|
+
<${PopActions} visible=${tools.dirty}>
|
|
48
103
|
<${ActionButton}
|
|
49
|
-
onClick=${
|
|
50
|
-
disabled=${
|
|
104
|
+
onClick=${tools.reset}
|
|
105
|
+
disabled=${isSaving}
|
|
51
106
|
tone="secondary"
|
|
52
107
|
size="sm"
|
|
53
|
-
idleLabel="
|
|
108
|
+
idleLabel="Cancel"
|
|
54
109
|
className="text-xs"
|
|
55
110
|
/>
|
|
56
|
-
|
|
111
|
+
<${ActionButton}
|
|
112
|
+
onClick=${handleSaveTools}
|
|
113
|
+
disabled=${isSaving}
|
|
114
|
+
loading=${isSaving}
|
|
115
|
+
loadingMode="inline"
|
|
116
|
+
tone="primary"
|
|
117
|
+
size="sm"
|
|
118
|
+
idleLabel="Save changes"
|
|
119
|
+
loadingLabel="Saving…"
|
|
120
|
+
className="text-xs"
|
|
121
|
+
/>
|
|
122
|
+
</${PopActions}>
|
|
57
123
|
</div>
|
|
124
|
+
<${PillTabs}
|
|
125
|
+
tabs=${kDetailTabs}
|
|
126
|
+
activeTab=${activeTab}
|
|
127
|
+
onSelectTab=${onSelectTab}
|
|
128
|
+
className="flex items-center gap-2 pt-6"
|
|
129
|
+
/>
|
|
58
130
|
<div class="agents-detail-content">
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
131
|
+
${activeTab === "overview"
|
|
132
|
+
? html`
|
|
133
|
+
<${AgentOverview}
|
|
134
|
+
agent=${agent}
|
|
135
|
+
agents=${agents}
|
|
136
|
+
saving=${saving}
|
|
137
|
+
onUpdateAgent=${onUpdateAgent}
|
|
138
|
+
onSetLocation=${onSetLocation}
|
|
139
|
+
onOpenWorkspace=${onOpenWorkspace}
|
|
140
|
+
onSwitchToModels=${() => onSetLocation("/models")}
|
|
141
|
+
onSetDefault=${onSetDefault}
|
|
142
|
+
onDelete=${onDelete}
|
|
143
|
+
/>
|
|
144
|
+
`
|
|
145
|
+
: html`
|
|
146
|
+
<${AgentToolsPanel}
|
|
147
|
+
agent=${agent}
|
|
148
|
+
tools=${tools}
|
|
149
|
+
/>
|
|
150
|
+
`}
|
|
70
151
|
</div>
|
|
71
152
|
</div>
|
|
72
153
|
</div>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { h } from "https://esm.sh/preact";
|
|
2
|
+
import htm from "https://esm.sh/htm";
|
|
3
|
+
import { ToggleSwitch } from "../../toggle-switch.js";
|
|
4
|
+
import { InfoTooltip } from "../../info-tooltip.js";
|
|
5
|
+
import { SegmentedControl } from "../../segmented-control.js";
|
|
6
|
+
import { kSections, kToolProfiles, kProfileLabels } from "./tool-catalog.js";
|
|
7
|
+
|
|
8
|
+
const html = htm.bind(h);
|
|
9
|
+
|
|
10
|
+
const kProfileDescriptions = {
|
|
11
|
+
minimal: "Only session status — grant specific tools with alsoAllow",
|
|
12
|
+
messaging: "Session access and messaging — ideal for notification agents",
|
|
13
|
+
coding: "File I/O, shell, memory, sessions, cron, and image generation",
|
|
14
|
+
full: "All tools enabled, no restrictions",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const kProfileOptions = kToolProfiles.map((p) => ({
|
|
18
|
+
label: kProfileLabels[p],
|
|
19
|
+
value: p,
|
|
20
|
+
title: kProfileDescriptions[p],
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const ToolRow = ({ tool, onToggle }) => html`
|
|
24
|
+
<div class="flex items-center justify-between gap-3 py-2.5 px-4">
|
|
25
|
+
<div class="min-w-0">
|
|
26
|
+
<div class="text-sm text-gray-200 flex items-center gap-1.5">
|
|
27
|
+
<span>${tool.label}</span>
|
|
28
|
+
${tool.help
|
|
29
|
+
? html`<${InfoTooltip} text=${tool.help} widthClass="w-72" />`
|
|
30
|
+
: null}
|
|
31
|
+
</div>
|
|
32
|
+
<span class="text-xs font-mono text-gray-500">${tool.id}</span>
|
|
33
|
+
</div>
|
|
34
|
+
<${ToggleSwitch}
|
|
35
|
+
checked=${tool.enabled}
|
|
36
|
+
onChange=${(checked) => onToggle(tool.id, checked)}
|
|
37
|
+
label=${null}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const ToolSection = ({ section, toolStates, onToggle }) => {
|
|
43
|
+
const sectionTools = toolStates.filter((t) => t.section === section.id);
|
|
44
|
+
if (!sectionTools.length) return null;
|
|
45
|
+
|
|
46
|
+
return html`
|
|
47
|
+
<div class="bg-surface border border-border rounded-xl overflow-hidden">
|
|
48
|
+
<h3 class="card-label text-xs px-4 pt-3 pb-2">${section.label}</h3>
|
|
49
|
+
<div class="divide-y divide-border">
|
|
50
|
+
${sectionTools.map(
|
|
51
|
+
(tool) =>
|
|
52
|
+
html`<${ToolRow}
|
|
53
|
+
key=${tool.id}
|
|
54
|
+
tool=${tool}
|
|
55
|
+
onToggle=${onToggle}
|
|
56
|
+
/>`,
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
`;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const AgentToolsPanel = ({ agent = {}, tools = {} }) => {
|
|
64
|
+
const { profile, toolStates, setProfile, toggleTool } = tools;
|
|
65
|
+
|
|
66
|
+
const enabledTotal = (toolStates || []).filter((t) => t.enabled).length;
|
|
67
|
+
const totalTools = (toolStates || []).length;
|
|
68
|
+
|
|
69
|
+
return html`
|
|
70
|
+
<div class="space-y-4">
|
|
71
|
+
<div class="bg-surface border border-border rounded-xl p-4 space-y-4">
|
|
72
|
+
<div>
|
|
73
|
+
<div class="flex items-center justify-between mb-3">
|
|
74
|
+
<h3 class="card-label text-xs">Preset</h3>
|
|
75
|
+
<span class="text-xs text-gray-500"
|
|
76
|
+
>${enabledTotal}/${totalTools} tools enabled</span
|
|
77
|
+
>
|
|
78
|
+
</div>
|
|
79
|
+
<${SegmentedControl}
|
|
80
|
+
options=${kProfileOptions}
|
|
81
|
+
value=${profile}
|
|
82
|
+
onChange=${setProfile}
|
|
83
|
+
fullWidth
|
|
84
|
+
className="ac-segmented-control-dark"
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div style="columns: 2; column-gap: 0.75rem;">
|
|
90
|
+
${kSections.map(
|
|
91
|
+
(section) => html`
|
|
92
|
+
<div style="break-inside: avoid; margin-bottom: 0.75rem;">
|
|
93
|
+
<${ToolSection}
|
|
94
|
+
key=${section.id}
|
|
95
|
+
section=${section}
|
|
96
|
+
toolStates=${toolStates || []}
|
|
97
|
+
onToggle=${toggleTool}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
`,
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
`;
|
|
105
|
+
};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static tool catalog mirroring OpenClaw's tool-catalog.ts.
|
|
3
|
+
* Grouped and labeled for the AlphaClaw Setup UI.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const kToolProfiles = ["minimal", "messaging", "coding", "full"];
|
|
7
|
+
|
|
8
|
+
export const kProfileLabels = {
|
|
9
|
+
minimal: "Minimal",
|
|
10
|
+
messaging: "Messaging",
|
|
11
|
+
coding: "Coding",
|
|
12
|
+
full: "Full",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const kTools = [
|
|
16
|
+
{
|
|
17
|
+
id: "read",
|
|
18
|
+
label: "Read files",
|
|
19
|
+
profiles: ["coding"],
|
|
20
|
+
section: "filesystem",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "edit",
|
|
24
|
+
label: "Edit files",
|
|
25
|
+
profiles: ["coding"],
|
|
26
|
+
section: "filesystem",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "write",
|
|
30
|
+
label: "Write files",
|
|
31
|
+
profiles: ["coding"],
|
|
32
|
+
section: "filesystem",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "apply_patch",
|
|
36
|
+
label: "Apply patches",
|
|
37
|
+
help: "Make targeted patch edits, mainly for OpenAI-compatible patch workflows.",
|
|
38
|
+
profiles: ["coding"],
|
|
39
|
+
section: "filesystem",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "exec",
|
|
43
|
+
label: "Run commands",
|
|
44
|
+
help: "Execute shell commands inside the agent environment.",
|
|
45
|
+
profiles: ["coding"],
|
|
46
|
+
section: "execution",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "process",
|
|
50
|
+
label: "Manage processes",
|
|
51
|
+
help: "Inspect and control long-running background processes.",
|
|
52
|
+
profiles: ["coding"],
|
|
53
|
+
section: "execution",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "message",
|
|
57
|
+
label: "Send messages",
|
|
58
|
+
help: "Send outbound messages through configured messaging channels.",
|
|
59
|
+
profiles: ["messaging"],
|
|
60
|
+
section: "communication",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: "tts",
|
|
64
|
+
label: "Text-to-speech",
|
|
65
|
+
help: "Convert text responses into generated speech audio.",
|
|
66
|
+
profiles: [],
|
|
67
|
+
section: "communication",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "browser",
|
|
71
|
+
label: "Control browser",
|
|
72
|
+
help: "Drive a browser for page navigation and interactive web tasks.",
|
|
73
|
+
profiles: [],
|
|
74
|
+
section: "web",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "web_search",
|
|
78
|
+
label: "Search the web",
|
|
79
|
+
help: "Run web searches to discover external information.",
|
|
80
|
+
profiles: [],
|
|
81
|
+
section: "web",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "web_fetch",
|
|
85
|
+
label: "Fetch URLs",
|
|
86
|
+
help: "Fetch and read webpage content from a specific URL.",
|
|
87
|
+
profiles: [],
|
|
88
|
+
section: "web",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "memory_search",
|
|
92
|
+
label: "Semantic search",
|
|
93
|
+
help: "Search memory semantically to find related notes and prior context.",
|
|
94
|
+
profiles: ["coding"],
|
|
95
|
+
section: "memory",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "memory_get",
|
|
99
|
+
label: "Read memories",
|
|
100
|
+
help: "Read stored memory files and saved context entries.",
|
|
101
|
+
profiles: ["coding"],
|
|
102
|
+
section: "memory",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "agents_list",
|
|
106
|
+
label: "List agents",
|
|
107
|
+
help: "List known agent IDs that can be targeted in multi-agent flows.",
|
|
108
|
+
profiles: [],
|
|
109
|
+
section: "multiagent",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "sessions_spawn",
|
|
113
|
+
label: "Spawn sessions",
|
|
114
|
+
help: "Start a new background session/run; this is the base primitive used by sub-agent workflows.",
|
|
115
|
+
profiles: ["coding"],
|
|
116
|
+
section: "multiagent",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "sessions_send",
|
|
120
|
+
label: "Send to session",
|
|
121
|
+
help: "Send messages or tasks into an existing running session.",
|
|
122
|
+
profiles: ["coding", "messaging"],
|
|
123
|
+
section: "multiagent",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "sessions_list",
|
|
127
|
+
label: "List sessions",
|
|
128
|
+
help: "List active or recent sessions available to the agent.",
|
|
129
|
+
profiles: ["coding", "messaging"],
|
|
130
|
+
section: "multiagent",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: "sessions_history",
|
|
134
|
+
label: "Session history",
|
|
135
|
+
help: "Read the transcript and prior exchanges from a session.",
|
|
136
|
+
profiles: ["coding", "messaging"],
|
|
137
|
+
section: "multiagent",
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "session_status",
|
|
141
|
+
label: "Session status",
|
|
142
|
+
help: "Check whether a session is running and inspect runtime health/state.",
|
|
143
|
+
profiles: ["minimal", "coding", "messaging"],
|
|
144
|
+
section: "multiagent",
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: "subagents",
|
|
148
|
+
label: "Sub-agents",
|
|
149
|
+
help: "Launch specialized delegated agents (higher-level orchestration built on session spawning).",
|
|
150
|
+
profiles: ["coding"],
|
|
151
|
+
section: "multiagent",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "cron",
|
|
155
|
+
label: "Scheduled jobs",
|
|
156
|
+
help: "Create and manage scheduled automation jobs.",
|
|
157
|
+
profiles: ["coding"],
|
|
158
|
+
section: "scheduling",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "gateway",
|
|
162
|
+
label: "Gateway control",
|
|
163
|
+
help: "Inspect and control the running Gateway service (status, health, and control actions like restart).",
|
|
164
|
+
profiles: [],
|
|
165
|
+
section: "scheduling",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "image",
|
|
169
|
+
label: "Generate images",
|
|
170
|
+
help: "Generate or analyze images with image-capable model tools.",
|
|
171
|
+
profiles: ["coding"],
|
|
172
|
+
section: "creative",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "canvas",
|
|
176
|
+
label: "Visual canvas",
|
|
177
|
+
help: "Control the Canvas panel (present, navigate, eval, snapshot). Primarily a macOS app capability when a canvas-capable node is connected.",
|
|
178
|
+
profiles: [],
|
|
179
|
+
section: "creative",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: "nodes",
|
|
183
|
+
label: "Node workflows",
|
|
184
|
+
help: "Use paired device/node capabilities (for example canvas, camera, notifications, and system actions).",
|
|
185
|
+
profiles: [],
|
|
186
|
+
section: "creative",
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
export const kSections = [
|
|
191
|
+
{
|
|
192
|
+
id: "filesystem",
|
|
193
|
+
label: "Filesystem",
|
|
194
|
+
description: "Read, edit, and write files",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: "execution",
|
|
198
|
+
label: "Execution",
|
|
199
|
+
description: "Run shell commands and scripts",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "communication",
|
|
203
|
+
label: "Communication",
|
|
204
|
+
description: "Send messages across Telegram, Slack, Discord",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: "web",
|
|
208
|
+
label: "Web & Browser",
|
|
209
|
+
description: "Browse pages, search the web, fetch URLs",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: "memory",
|
|
213
|
+
label: "Memory",
|
|
214
|
+
description:
|
|
215
|
+
"Semantic search and retrieval across the agent's stored knowledge",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: "multiagent",
|
|
219
|
+
label: "Multi-Agent",
|
|
220
|
+
description:
|
|
221
|
+
"List agents, spawn sessions, send messages between agents. Orchestrate sub-agents.",
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: "scheduling",
|
|
225
|
+
label: "Scheduling",
|
|
226
|
+
description: "Create and manage scheduled jobs",
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: "creative",
|
|
230
|
+
label: "Creative",
|
|
231
|
+
description: "Generate images, visual canvas, node-based workflows",
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
export const getToolsForSection = (sectionId) =>
|
|
236
|
+
kTools.filter((t) => t.section === sectionId);
|
|
237
|
+
|
|
238
|
+
export const getAllToolIds = () => kTools.map((t) => t.id);
|
|
239
|
+
|
|
240
|
+
export const getProfileToolIds = (profileId) => {
|
|
241
|
+
if (profileId === "full") return kTools.map((t) => t.id);
|
|
242
|
+
return kTools.filter((t) => t.profiles.includes(profileId)).map((t) => t.id);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Given a profile + alsoAllow + deny, resolve whether each tool is enabled.
|
|
247
|
+
*/
|
|
248
|
+
export const resolveToolStates = ({
|
|
249
|
+
profile = "full",
|
|
250
|
+
alsoAllow = [],
|
|
251
|
+
deny = [],
|
|
252
|
+
}) => {
|
|
253
|
+
const profileTools = new Set(getProfileToolIds(profile));
|
|
254
|
+
const alsoAllowSet = new Set(alsoAllow);
|
|
255
|
+
const denySet = new Set(deny);
|
|
256
|
+
|
|
257
|
+
return kTools.map((tool) => {
|
|
258
|
+
const inProfile = profileTools.has(tool.id);
|
|
259
|
+
const isDenied = denySet.has(tool.id);
|
|
260
|
+
const isAlsoAllowed = alsoAllowSet.has(tool.id);
|
|
261
|
+
const enabled = isDenied ? false : inProfile || isAlsoAllowed;
|
|
262
|
+
|
|
263
|
+
return { ...tool, enabled, inProfile, isDenied, isAlsoAllowed };
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Derive the minimal tools config from the resolved tool states
|
|
269
|
+
* relative to the selected profile.
|
|
270
|
+
*/
|
|
271
|
+
export const deriveToolsConfig = ({ profile, toolStates }) => {
|
|
272
|
+
const profileTools = new Set(getProfileToolIds(profile));
|
|
273
|
+
const alsoAllow = [];
|
|
274
|
+
const deny = [];
|
|
275
|
+
|
|
276
|
+
for (const tool of toolStates) {
|
|
277
|
+
const inProfile = profileTools.has(tool.id);
|
|
278
|
+
if (tool.enabled && !inProfile) {
|
|
279
|
+
alsoAllow.push(tool.id);
|
|
280
|
+
} else if (!tool.enabled && inProfile) {
|
|
281
|
+
deny.push(tool.id);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const config = { profile };
|
|
286
|
+
if (alsoAllow.length) config.alsoAllow = alsoAllow;
|
|
287
|
+
if (deny.length) config.deny = deny;
|
|
288
|
+
return config;
|
|
289
|
+
};
|